Variable semantics


#1

I am new to FPGA/HDL in general.

While writing code, I often find myself having to repeat code. As a long time programmer I don’t like having to do this.

For example, say I have a sequential block, and it has an internal signal and an external signal.
I want these two signals to be in sync with each other, so they are updated to a “new” value at the same time. An example of this is a block which uses an accumulator to compute a box filter.

At each clock I do something like

accumulator.next = accumulator + data_in - oldest_value
output.next = (accumulator + data_in - oldest_value) // number_samples

In other words, the output is always equal to the accumulator divided by another number.

Is the preferred way to put the output.next into a combinatorial block, rather than a sequential block? I would still like for the output to be registered at the clock edge, and I am not sure if a combinatorial block would allow that.

Are there also other timing implications if the output signal is moved to a combinatorial block?

Is there a way to put the repeated code into some kind of symbolic variable so it can be used, i.e.

temp.next = accumulator + data_in - oldest_value
accumulator.next = temp
output.next = temp // number_samples

?

Another example:
I have a counter which I want to usually count up by 1 on every clock. But sometimes I want to set it back to zero, or subtract some value from it.
The control logic (if statements) are fairly complex, and so I have to manually go through all branches of all my if statements and check that every branch updates the value of the counter.

eg

# This example is contrived - in my real code there is 
# no simple boolean simplification
if condA:
    if condB:
        counter.next = counter + 1
    else:
        counter.next = 0
else:
    if condC:
        counter.next = counter - value
    else:
        counter.next = counter + 1

Is there some way to again use a temporary ‘variable’ to store the next value, or am I thinking too procedurally here?

Eg, is something like this possible:

temp = counter + 1
if condA:
    if not condB:
        temp = 0
else:
    if condC:
        temp = counter - value

counter.next = temp

In other words, is there an easy way to have a default action (increment the counter) which gets applied, unless one of the other new values is applied?

Is there any good user manual / tutorial / documentation where I can learn about how to structure my code to avoid repeating myself and also searching for missing logic branches when updating my counter etc?

Thanks :slight_smile:


#2

Hi,

When coming from pure software world, there are new concepts to learn.
MyHDL documentation is written for hardware guys knowing a HDL language like VHDL or verilog.
You first have to acquire a good knowledge on some HDL principles that are different from standard software principles.

With hardware languages, the concept of variables is different from what it is in standard software.
There is also the concept of signals. Signals can be seen as a representation of a “physical object”.
In HDL languages, signals and variables behave differently. See here for a VHDL example : http://www.gmvhdl.com/signals.htm

In MyHdl, the beauty of the syntax makes things clear : my_signal.next = something means that the “next” value my_signal will be something. The next value is applied when the function is exited. This means that when you assign more than one value to my_signal.next, only the last one is used.

So, your last excerpt of code can be written :

counter.next = counter + 1
if condA:
    if not condB:
        counter.next = 0
else:
    if condC:
        counter.next = counter - value

At the opposite, when a variable is assigned to a new value, the new value is active immediately.
This way, the following is correct when temp is a variable:

temp.next = accumulator + data_in - oldest_value
accumulator.next = temp
output.next = temp // number_samples

All the above is correct when used in a clocked function. In non clocked functions, things may be different.


#3

Thanks for the reply, that’s all very useful information!

At the risk of being daft, you said

At the opposite, when a variable is assigned to a new value, the new value is active immediately.
This way, the following is correct when temp is a variable

What do you mean “when temp is a variable”?

If I initialise temp as temp = Signal(intbv(0)[len(accumulator):]), then assigning to temp.next will delay that value change into the next clock change, and so it won’t appear at the output until the clock edge after that (if I understand correctly - if this is not the case, then why not? why do some assignments to Signal.next take effect immediately and some do not?) - or, is there some type other than Signal which I should use to initialise temp?


#4

There is a vocabulary problem here : In HDL, there are variables and signals. The term “variable” has not the same signification as in standard software. A variable sees its new assignments effective immediately. A signal sees its new assignments effective at the the clock edge.

In MyHDL, a python variable can be a “signal” or a “variable” a la VHDL.
Defining temp as a “variable” : temp = intbv(0)[len(accumulator):]
Defining temp as a “signal” : temp = Signal(intbv(0)[len(accumulator):])

In the following, the behaviour is not the same depending on the type of temp :

temp.next = accumulator + data_in - oldest_value
accumulator.next = temp
output.next = temp // number_samples

If you want to do the same thing than

accumulator.next = accumulator + data_in - oldest_value
output.next = accumulator + data_in - oldest_value

then temp must be a “variable”.
If temp is a signal, you create a new hardware resource for temp and accumulator and output signals are delayed by one clock.


#5

Thank you! That I could use intbv not attached to a signal was the missing piece of crucial knowledge for me. I didn’t realise intbv (and I assume related types) had a next attribute. I will go back and re-read the documentation again, maybe some more things will be clear now that I realise this :slight_smile:


#6

Oups, I made a mistake.
When assigning a new value to a “variable”, one must use the following syntaxes :
temp[:] = new_value
temp += 1

Please look at MyHDL examples : http://myhdl.org/docs/examples
This example http://myhdl.org/docs/examples/sinecomp/ intensively uses “variables”


#7

Thanks again!

I vaguely remember Jan saying somewhere how important variables were to him, so I have been searching the internet for “variable semantics” (which is also the name of this topic). I guess I failed to go back and look at that example. This is going to be very helpful!

I think it needs to be made much clearer in the reference/docs, because I spent a long time looking there and couldn’t find this information. I will check soon to see if I can contribute that.


#8

I have written a cheat sheet. You can get it here : https://bitbucket.org/nico-dev/myhdl_cheat_sheet/src/
I’ll add snippets of code latter, including “variables” use.