In VHDL, I heavily use block statements to manage locals signals.
For example :
signal PrescalerTrig : std_logic := '0';
...
b_prescaler :
block
signal Counter : integer range 0 to 255 := 0;
begin
process (Clk)
begin
if rising_edge(i_Clk) then
PrescalerTrig <= '0';
if Counter = CLK_DIVIDER then
Counter <= 0;
PrescalerTrig <= '1';
else
Counter <= Counter + 1;
end if;
end if;
end process;
end block;
b_tx :
block
signal Counter : integer range 0 to 16 := 0;
begin
process (Clk)
begin
if rising_edge(i_Clk) then
if PrescalerTrig = '1' then
Counter <= Counter + 1;
.
.
.
end if;
end if;
end process;
end block;
Using local signals makes the code much more readable and less prone to errors.
MyHDL isn’t meant to produce maintainable V* code. Of course it helps that the generated code looks nice and readable. IMO the name prefixing produces acceptable traceable names.
The closest you can get is using local variables in MyHDL, it will produce a local variable in VHDL.
The purpose is not to “produce maintainable V* code”.
VHDL ‘block’ statements are useful for readability and limit design errors.
Name prefixing is a solution. A bad solution to my point of view.
The purpose is not to “produce maintainable V code”.*
Then nothing else matters?
You simulate in MyHDL (and possibly cosimulate), convert and use. If you really have to debug at the VHDL level, the generated names are good enough, certainly not bad.
I adopted a naming convention which produces very traceable names: CamelCase for ports and lowercase without underscores for signals and modules/functions, UPPER_CASE for constants.This generates signals like: sync_syncs2_counter_IsZero where you can think of the ‘_’ representing the ‘. as we use in Python.’
There might be some confusion here. My goal is to write better MyHDL code. Nothing to do with VHDL or Verilog.
In my original post, I show a VHDL example where 2 blocks use a counter simply named Counter. This is clear, each Counter is in its own scope.
In MyHDL, when coding such functionality, I have to create 2 signals with different names because they are in the same scope. This is less readable and can lead to errors. You know, ctrl+c and ctrl+v…
For the typical case of a counter use a MyHDL variable. I didn’t have a good example ready; as I re-use a counter object (and the prefixing takes care of the naming).
I then made one up:
def counter(Clk, Q):
CLK_DIVIDER = 256 - 1
prescalertrig = Signal(bool(0))
counter = intbv(0)[8:]
@always_seq(Clk.posedge, reset=None)
def prescaler():
''' Prescaler '''
prescalertrig.next = 0
if counter == CLK_DIVIDER:
counter[:] = 0
prescalertrig.next = 1
else:
counter[:] = counter + 1
counter = intbv(0)[4:] # yes we are re-using the 'name' only, not the 'object'
@always_seq(Clk.posedge, reset=None)
def thecounter():
''' The Counter '''
Q.next = counter
if prescalertrig:
if counter == 15:
counter[:] = 0
else:
counter[:] = counter + 1
return prescaler, thecounter```
producing this VHDL:
```VHDL
signal prescalertrig : std_logic := '0';
begin
-- Prescaler
prescaler : process(Clk) is
variable counter : unsigned(3 downto 0);
begin
if rising_edge(Clk) then
prescalertrig <= '0';
if (counter = 255) then
counter := to_unsigned(0, 4);
prescalertrig <= '1';
else
counter := (counter + 1);
end if;
end if;
end process prescaler;
-- The Counter
thecounter : process(Clk) is
variable counter : unsigned(3 downto 0);
begin
if rising_edge(Clk) then
Q <= counter;
if bool(prescalertrig) then
if (counter = 15) then
counter := to_unsigned(0, 4);
else
counter := (counter + 1);
end if;
end if;
end if;
end process thecounter;
Variables can be a bit tricky in VHDL though, so we may want to read up on this. There probably is an error in the code …
In the same scope, two objects are manipulated using the same name.
In your example, imagine I miss the second instantiation (because it is late and I am tired), every thing will be ok from MyHDL point of view. But the system will not work as expected. Bugs like this are very hard to find because you don’t search for them.
Also, reading this code can lead to misunderstanding if you overlook the second instantiation.
With much more complex code, this is a real problem. From my point of view.
Sure.
I tried to instanciate signals in “process” functions but this gives an error. Not surprising.
Point taken. It is less evident and it may as well not work …
IMO I feel this feature would be too much work, and not worth the effort.
Using distinct names should not pose a real problem.
Second you can re-factor the @always_seq processes into separate functions/classes and MyHDL will take care of the naming. And it will reduce the verbosity of the top function/module, improving the readability.
My goal was not to request a new feature. I just wanted to know if other users have found a smarter way of coding.
I already though about it but I concluded that it would make the code less readable. This is because I though I have to declare the functions in the main function body. But I don’t have to. Declaring the functions outside the main function might be the solution.
I have already completed 3 designs using MyHDL (Target is a Lattice MACHXO2).
Of course I use many modules for various functionalities : I2C slave, IRQ management, registers management, edge detector, GPIO…
Some modules are more complex than others and are formed of “submodules”.
For example, a RS2232 transmitter. This transmitter needs a prescaler to manage the transmission speed and a core transmitter (using prescaler output). I don’t want to create a module for the prescaler and a module for the core transmitter. I want just one module containing all the logic. The prescaler is specific to this module, so is the core transmitter. Defining a function for the prescaler and another one for the core transmitter in the module is ok for me.
As you said, it has the advantage of a simpler, more readable, top module.