synthesizing 'rightof or 'succ

M

Mike Treseler

KJ said:
my reason for using a variable has never been just
because I didn't want some other process in that same entity/
architecture to be able to access it.

I agree with you here.
Scope has little to do with my use of variables.
In fact, I find it very confusing when
both signals and variables are used to store
values for the same process.

I use variables as globals in a single process entity.
Variables allow me to write sequential, procedural code
that is easy for *me* to write, trace and debug.
If that were not true, I would not bother with them.

-- Mike Treseler
 
A

Andy

I agree with you here.
Scope has little to do with my use of variables.
In fact, I find it very confusing when
both signals and variables are used to store
values for the same process.

I use variables as globals in a single process entity.
Variables allow me to write sequential, procedural code
that is easy for *me* to write, trace and debug.
If that were not true, I would not bother with them.

-- Mike Treseler

I use variables for one main reason: they behave like the code reads:
they update immediately. Signals turn sequential code into "pseudo-
sequential" code, and I don't like that. There, I said it.

The fact that they have additional benefits (and deficits) influences
that decision, and along with all "proper design" approaches, should
be implemented with common sense (the practicality doctrine). I tend
to use source level debuggers and self checking features (assertions)
more than waveforms, but that's just the way I do it. I can certainly
see that if you rely on waveforms, and want to see past history,
variables can be a liability.

The downside of using entities for "information hiding" is that they
are an all or nothing solution: once you drop down into another
entity, there is NO shared visibility, unless you go completely global
which widens the scope too much (and many synthesis tools still don't
use anyway).

The best approach to using signals while hiding private things and
accessing shared things, is the block statement. You can declare a
signal local to a block, and it can only be accessed within that
block, but code within that block can still access other signals
outside the block. All the shared signals are declared in one place
(architecture declarative part); all the local/private signals are
declared in their local block's declarative part.

As far as "proper design", a state variable should only be accessed
and/or updated within a single process (actually, within the case
statement that defines the state transitions). To do otherwise makes
maintenance more difficult because the effects of changes to the state
assignments and transitions are not limited to the state machine. On
the other hand, if I have to write an extra screenful of code to avoid
accessing a state variable outside the state machine itself, then the
doctrine of practicality takes precedence (liberal commenting
helps...)

So let me clarify: The use of signals for state variables is not poor
design per se. The use of a signal for a state variable that is
accessible outside the state machine is poor design. Furthermore, the
use of variables for a state machine is not an automatic "proper
design", especially if you have more than one state machine in a given
process (did I mention that block statements can be used inside
processes too?)

Like it or not, there is a lot of benefit in the years of software
development standards that we can take advantage of to improve our
hardware designs. Just remember, somebody (maybe you) will have to
maintain that code some day...

Andy
 
M

Mike Treseler

Andy said:
I use variables for one main reason: they behave like the code reads:
they update immediately. Signals turn sequential code into "pseudo-
sequential" code, and I don't like that. There, I said it.

Glad you did. I have the same problem.
I cannot manually debug (or even read) a complex
piece of vhdl source code that uses signals
to do logic. I have no choice but to run a sim
and look at the waves because tracing
source code by any means is useless.
I tend
to use source level debuggers and self checking features (assertions)
more than waveforms, but that's just the way I do it. I can certainly
see that if you rely on waveforms, and want to see past history,
variables can be a liability.

Yes. Viewing a variable as a waveform
hides all of the assignments between clock ticks.
This is where the bugs are, and they are
best found by tracing code, either manually
or by using the simulator GUI, or by dropping
in assertions.
The downside of using entities for "information hiding" is that they
are an all or nothing solution: once you drop down into another
entity, there is NO shared visibility, unless you go completely global
which widens the scope too much (and many synthesis tools still don't
use anyway).

This is a matter of style, but I think
there is a happy medium.

I like to declare all of the variables
involved in driving a top output group
in one process/entity slice. All of
the wires (port maps) go in the top entity.
I keep variables together using data structures
and associated update procedures.

Yes, it is possible for procedures to
interact, but that can also be used to advantage.
For example, I might want to share an
input register variable between the get_data
procedure and the readback procedure
that packs in a status bit.
The best approach to using signals while hiding private things and
accessing shared things, is the block statement. You can declare a
signal local to a block, and it can only be accessed within that
block, but code within that block can still access other signals
outside the block.

Don't get me started on block statements :)
I would much rather add an instance to my top entity.
Like it or not, there is a lot of benefit in the years of software
development standards that we can take advantage of to improve our
hardware designs.

Yes. Version control (always) and daily builds
for projects with more that one designer.
Just remember, somebody (maybe you) will have to
maintain that code some day...

Amen brother.

And apologies to Neha.
That's what you get for asking an interesting question :)

-- Mike Treseler
 
K

KJ

Andy said:
On Nov 14, 12:31 pm, Mike Treseler <[email protected]> wrote:
I use variables for one main reason: they behave like the code reads:
they update immediately. Signals turn sequential code into "pseudo-
sequential" code, and I don't like that. There, I said it.
OK. Generally I don't like that variables change their meaning (because
they've been assigned to and update immediately) when they are assigned to
in several places in a long hunk-o-code with all kinds of paths through it.
Of course nobody writes such code ;) My bigger gripe is the lack of history
though.
I tend
to use source level debuggers and self checking features (assertions)
more than waveforms, but that's just the way I do it. I can certainly
see that if you rely on waveforms, and want to see past history,
variables can be a liability.
Assertions don't tell you the root cause of what is wrong, just that a
particular bad something has occurred. Many times one can tell simply by
looking at what assertion failed and quickly deduce the root cause of the
problem, but many times it's not so simple to see what incorrect logic led
to the assertion having failed. In any case, the information that one needs
to debug the failed condition lies in the past (i.e. the simulation history
up to that point) not in the future so stepping through code or really
anything other than analysis of the prior state of (possibly) everything in
the design and testbench is required. Signals, variables and log/trace
output files are the evidence that you use for that forensic analysis.
Things that hinder that analysis typically slows down debug. Wave windows
assist in the forensics as a good analytical tool, for investigating the
scene of the crime (i.e. the failed assert). The two are complementary in
that regard.....having said that though, I realize that the beginner will be
debugging using waves alone (until they recognize the value of asserting
darn near everything that they can instead).
The downside of using entities for "information hiding" is that they
are an all or nothing solution: once you drop down into another
entity, there is NO shared visibility, unless you go completely global
which widens the scope too much (and many synthesis tools still don't
use anyway).
I didn't mean to imply that if, after initial design creation, the
realization sets in that some lower level entity has a 'need to know' about
something and that the interface to that entity couldn't simply be changed
to include that new signal and now the previously hidden info is known. No
need to go global.
As far as "proper design", a state variable should only be accessed
and/or updated within a single process (actually, within the case
statement that defines the state transitions). To do otherwise makes
maintenance more difficult because the effects of changes to the state
assignments and transitions are not limited to the state machine.
The downside to that is that the state machine code itself gets bloated and
hard to maintain because you end up with lots of signal assignments
intertwined with the various 'case' and 'if' branches typical of a state
machine. In any case, a state variable is just another signal and is
deserving of no more or less respect than any other signal or variable in
the design. Changes to the code on any signal will have repercussions
downstream, not just changes to state variables.

Maintenance has more to do with readability then it does with dogma about
scoping rules that apply to 'special' signals like state variables that
inexplicitly do not apply to other signals.
So let me clarify: The use of signals for state variables is not poor
design per se. The use of a signal for a state variable that is
accessible outside the state machine is poor design.

A multiple screen long state machine filled with signal assignments in the
various branches of the state machine code is a much poorer design (in my
opinion), since it requires paging back and forth to understand the various
reasons why something can be set or reset. I'd much rather have a 1000 line
file where the logic defining any given signal can be viewed and understood
within a single screen than having to wade through that same file searching
for all the possible places that the signal might get assigned.
Like it or not, there is a lot of benefit in the years of software
development standards that we can take advantage of to improve our
hardware designs. Just remember, somebody (maybe you) will have to
maintain that code some day...
Words of wisdom

KJ
 
D

Dave

OK. Generally I don't like that variables change their meaning (because
they've been assigned to and update immediately) when they are assigned to
in several places in a long hunk-o-code with all kinds of paths through it.
Of course nobody writes such code ;) My bigger gripe is the lack of history
though.


Assertions don't tell you the root cause of what is wrong, just that a
particular bad something has occurred. Many times one can tell simply by
looking at what assertion failed and quickly deduce the root cause of the
problem, but many times it's not so simple to see what incorrect logic led
to the assertion having failed. In any case, the information that one needs
to debug the failed condition lies in the past (i.e. the simulation history
up to that point) not in the future so stepping through code or really
anything other than analysis of the prior state of (possibly) everything in
the design and testbench is required. Signals, variables and log/trace
output files are the evidence that you use for that forensic analysis.
Things that hinder that analysis typically slows down debug. Wave windows
assist in the forensics as a good analytical tool, for investigating the
scene of the crime (i.e. the failed assert). The two are complementary in
that regard.....having said that though, I realize that the beginner will be
debugging using waves alone (until they recognize the value of asserting
darn near everything that they can instead).




I didn't mean to imply that if, after initial design creation, the
realization sets in that some lower level entity has a 'need to know' about
something and that the interface to that entity couldn't simply be changed
to include that new signal and now the previously hidden info is known. No
need to go global.


The downside to that is that the state machine code itself gets bloated and
hard to maintain because you end up with lots of signal assignments
intertwined with the various 'case' and 'if' branches typical of a state
machine. In any case, a state variable is just another signal and is
deserving of no more or less respect than any other signal or variable in
the design. Changes to the code on any signal will have repercussions
downstream, not just changes to state variables.

Maintenance has more to do with readability then it does with dogma about
scoping rules that apply to 'special' signals like state variables that
inexplicitly do not apply to other signals.




A multiple screen long state machine filled with signal assignments in the
various branches of the state machine code is a much poorer design (in my
opinion), since it requires paging back and forth to understand the various
reasons why something can be set or reset. I'd much rather have a 1000 line
file where the logic defining any given signal can be viewed and understood
within a single screen than having to wade through that same file searching
for all the possible places that the signal might get assigned.




Words of wisdom

KJ

Does anyone know if there is a reason that declaring signals local to
a process is not allowed? I've always used signals for registers and
variables only for temporary values or to make code more readable, so
I'm used to thinking that way. However, I do like the data-hiding of
variables, and the fact that I don't have to scroll to the top of the
architecture to see their definitions. I realize blocks could give the
same effect, but why not just allow signals local to a process?
 
K

KJ

KJ
Does anyone know if there is a reason that declaring signals local to
a process is not allowed? I've always used signals for registers and
variables only for temporary values or to make code more readable, so
I'm used to thinking that way. However, I do like the data-hiding of
variables, and the fact that I don't have to scroll to the top of the
architecture to see their definitions. I realize blocks could give the
same effect, but why not just allow signals local to a process?

Probably the same reason that someone decided that 'if' and 'case'
statements can only be in a process and not as concurrent statements.

KJ
 
A

Andy

Does anyone know if there is a reason that declaring signals local to
a process is not allowed? I've always used signals for registers and
variables only for temporary values or to make code more readable, so
I'm used to thinking that way. However, I do like the data-hiding of
variables, and the fact that I don't have to scroll to the top of the
architecture to see their definitions. I realize blocks could give the
same effect, but why not just allow signals local to a process?

I've often wondered that myself... I don't think there is a good
reason for it, and it would probably simplify some optimizations on
signals that aren't read outside the same process where they are
written during simulation (avoiding a lot of the signal overhead). But
I'm pretty sure a lot of simulators already take advantage of that
when they find it; this would just make it easier to identify such
situations (in addition to the human readability & information hiding
benefits)

Do you prefer using signals for registers because it is easier to
recognize a register from a combinatorial value? I quit trying to
focus on that, and instead focus on the cycle-cycle behavior, and let
the registers fall where they may. If I need to add/subtract a
register in a signal path, I add/subtract a behavioral delay (i.e.
a[nother] loop through the process). Often that can be accomplished by
simply re-ordering statements, without adding anything to the code.
With synthesis retiming, the exact placement of registers in source
code is becoming less important anyway (not totally unimportant yet!)

Andy
 
A

Andy

KJ




Probably the same reason that someone decided that 'if' and 'case'
statements can only be in a process and not as concurrent statements.

KJ

I'm not sure what you mean: we already have "with ... select..." and a
<= b when condition1 else c... These forms give you the capability to
use those types of control structures while ensuring that only one
signal is assigned (kind of the point of a concurrent ASSIGNMENT
statement).

I think at least the "when condition else..." form was added to
sequential statements in the last release.

Andy
 
D

Dave

Does anyone know if there is a reason that declaring signals local to
a process is not allowed? I've always used signals for registers and
variables only for temporary values or to make code more readable, so
I'm used to thinking that way. However, I do like the data-hiding of
variables, and the fact that I don't have to scroll to the top of the
architecture to see their definitions. I realize blocks could give the
same effect, but why not just allow signals local to a process?

I've often wondered that myself... I don't think there is a good
reason for it, and it would probably simplify some optimizations on
signals that aren't read outside the same process where they are
written during simulation (avoiding a lot of the signal overhead). But
I'm pretty sure a lot of simulators already take advantage of that
when they find it; this would just make it easier to identify such
situations (in addition to the human readability & information hiding
benefits)

Do you prefer using signals for registers because it is easier to
recognize a register from a combinatorial value? I quit trying to
focus on that, and instead focus on the cycle-cycle behavior, and let
the registers fall where they may. If I need to add/subtract a
register in a signal path, I add/subtract a behavioral delay (i.e.
a[nother] loop through the process). Often that can be accomplished by
simply re-ordering statements, without adding anything to the code.
With synthesis retiming, the exact placement of registers in source
code is becoming less important anyway (not totally unimportant yet!)

Andy

I guess it's mostly habit. Once you learn to write a certain way for a
while, it gets hard to change. Since I've started reading these
forums, I've seen people use variables a lot more than I expected, so
I'm thinking about using variables more - it's quite a different way
to think, at least to me. Do you guys know of any good books that
really show what variables can do in synthesizable code?
 
K

KJ

I'm not sure what you mean: we already have "with ... select..." and a
<= b when condition1 else c... These forms give you the capability to
use those types of control structures while ensuring that only one
signal is assigned (kind of the point of a concurrent ASSIGNMENT
statement).

And the reason for having two different ways to do the same thing
is????

It's not the case of giving the user a choice or a preference for one
form or the other, if you're in a process and you need 'case' or 'if'
functionality you use one form, outside of a process you use the
other, get it wrong and you get an error. 'with...select' gives you
nothing that 'case' couldn't provide; similarly 'when...else' gives
you nothing that 'if...else' couldn't. The operative word there is
"couldn't", I realize it "doesn't" but see no reason why it
"couldn't".

KJ
 
A

Andy

I've often wondered that myself... I don't think there is a good
reason for it, and it would probably simplify some optimizations on
signals that aren't read outside the same process where they are
written during simulation (avoiding a lot of the signal overhead). But
I'm pretty sure a lot of simulators already take advantage of that
when they find it; this would just make it easier to identify such
situations (in addition to the human readability & information hiding
benefits)
Do you prefer using signals for registers because it is easier to
recognize a register from a combinatorial value? I quit trying to
focus on that, and instead focus on the cycle-cycle behavior, and let
the registers fall where they may. If I need to add/subtract a
register in a signal path, I add/subtract a behavioral delay (i.e.
a[nother] loop through the process). Often that can be accomplished by
simply re-ordering statements, without adding anything to the code.
With synthesis retiming, the exact placement of registers in source
code is becoming less important anyway (not totally unimportant yet!)

I guess it's mostly habit. Once you learn to write a certain way for a
while, it gets hard to change. Since I've started reading these
forums, I've seen people use variables a lot more than I expected, so
I'm thinking about using variables more - it's quite a different way
to think, at least to me. Do you guys know of any good books that
really show what variables can do in synthesizable code?

No books, but a couple of basic principles:

Look at how synthesis really infers storage (registers or latches):
whenever the execution of the code requires remembering a previous
value in time, storage is implied. In signals, that's easy since
because of postponed updates, every reference to a signal in a clocked
process is from a previous time (one or more clock cycles in the
past). With variables, the same inference principles apply, and boil
down to the fact that a reference to a variable in a clocked process
after it has been updated in that cycle requires no "memory" and thus
no storage or register. Conversely, a reference to a variable that has
NOT already been written in that clock cycle does require memory and
therefore implies storage with a register.

Since a variable can be referenced before and/or after it has been
updated in a given clock cycle, a variable REFERENCE can represent a
registered and/or a combinatorial value. It is important to note that
the variable itself does not represent either register or
combinatorial data, EACH REFERENCE to it does. Also, if the prior
update is conditional (within an if statement, etc.) then any
subsequent reference to the variable is also referring to the
multiplexer structure implied by the conditional if statement. So, it
is possible to have a variable reference that in some clock cycles is
a register (i.e. it was not updated earlier in that clock cycle), and
in other clock cycles is combinatorial: a multiplexer is implied to
select, during each clock cycle, the combinatorial or registered
value.

The bottom line is: the synthesis tool will create a circuit that
behaves the way the circuit simulates. If it needs a register to make
that happen, it will use a register.


Andy
 
E

Eric Smith

Andy said:
I use variables for one main reason: they behave like the code reads:
they update immediately. Signals turn sequential code into "pseudo-
sequential" code, and I don't like that. There, I said it.

I use signals for one main reason: they work they way the hardware
actually works. The FPGA (or ASIC) doesn't execute assignments sequentially,
unless you build logic to do that. I find that designing HDL models that
work similarly to how the hardware actually works tends to result in my
spending less time debugging.

I'm not religious about it, though. I use variables when it helps to
express what I'm trying to accomplish. For instance, if I need to write
a parity generator/checker, I'll probably write a function with a
for loop and a variable holding the result being computed by the loop.

If some people find that using variables where I would use signals helps
them be more productive, I'm not going to argue with them, though I might
grumble if I ever have to maintain their code.
The fact that they have additional benefits (and deficits) influences
that decision, and along with all "proper design" approaches, should
be implemented with common sense (the practicality doctrine).
Yes.

So let me clarify: The use of signals for state variables is not poor
design per se. The use of a signal for a state variable that is
accessible outside the state machine is poor design.

IMNSHO, the state variable should never be visible outside the state
machine, unless it is specifically an output of the machine, in which
case it should be exported as a signal (even if it is implemented as
a variable inside the state machine).
Furthermore, the
use of variables for a state machine is not an automatic "proper
design", especially if you have more than one state machine in a given
process

I normally try to avoid putting multiple state machines in one process.
Unless they're fairly trivial, I don't usually even put them in the
same entity.

Eric
 
M

Martin Thompson

Eric Smith said:
If some people find that using variables where I would use signals helps
them be more productive, I'm not going to argue with them, though I might
grumble if I ever have to maintain their code.

:)

Something I've often wondered:

I always find (and I guess that goes for most engineers) that when I
pick up someone else's code (software, HDL, whatever), or even
sometimes my own code from years past, I find myself sucking air
through my teeth and thinking "Oooh, I wouldn't have done it like
that"...

Do you reckon civil engineers do that every time they drive across
someone else's bridge :) ?

Cheers,
Martin
 
M

Mike Treseler

Eric said:
I use signals for one main reason: they work they way the hardware
actually works. The FPGA (or ASIC) doesn't execute assignments sequentially,
unless you build logic to do that.

The hardware is a set of gates/luts and flops
that can be wired up however I like.
I can't say how this actually works, until I do wire it up.

To do this, I could:
1. Do it myself:
Make a schematic or netlist of these primitive elements.
2. Trust the vendor:
Exploit vendor specific libraries or core generators
to create larger blocks to wire together.
3. Synthesis with explicit wires:
Use HDL process/always blocks that allow me to make
abstract units of counters, shifters etc.
and wire those together instead of primitives.
4. Synthesis without explicit wires:
Use an HDL process as above,
but also exploit the use of process variables
to write C-like sequential descriptions of how
registers are to be updated without explicitly
describing any wires.

Only strategy 1 covers the way the hardware actually works.
All else involves abstraction and trust.
If some people find that using variables where I would use signals helps
them be more productive, I'm not going to argue with them, though I might
grumble if I ever have to maintain their code.

When I maintain code that doesn't match
my current style, I put wrapper around the working part
and add the changes in as a separate entity.
As Martin notes, sometimes all this code is
my own :)

-- Mike Treseler
 
M

Mike Treseler

Dave said:
I guess it's mostly habit. Once you learn to write a certain way for a
while, it gets hard to change. Since I've started reading these
forums, I've seen people use variables a lot more than I expected, so
I'm thinking about using variables more - it's quite a different way
to think, at least to me. Do you guys know of any good books that
really show what variables can do in synthesizable code?

Anyone interested could write such a book
based on the postings in this newsgroup over
the last few years. But it would have to
be for love, not money.

Or just convince yourself
by picking an interesting example
and working it through your own tools.

-- Mike Treseler
 
A

Andy

Do you reckon civil engineers do that every time they drive across
someone else's bridge :) ?

Cheers,
Martin

I'm REALLY glad I'm not a civil engineer :^) Life would be too
painful... At least most of my everyday consumer encounters
sufficiently hide the electronics to allow me to pass through life
blissfully ignorant... At least until I'm sitting at a stoplight that
is clearly not up to the task of properly regulating the flow of
traffic. If they can field stoplight cameras that actually work really
well, you'd think they could come up with a more intelligent control
scheme for the stoplight itself.

Andy
 
A

Andy

The hardware is a set of gates/luts and flops
that can be wired up however I like.
I can't say how this actually works, until I do wire it up.

To do this, I could:
1. Do it myself:
Make a schematic or netlist of these primitive elements.
2. Trust the vendor:
Exploit vendor specific libraries or core generators
to create larger blocks to wire together.
3. Synthesis with explicit wires:
Use HDL process/always blocks that allow me to make
abstract units of counters, shifters etc.
and wire those together instead of primitives.
4. Synthesis without explicit wires:
Use an HDL process as above,
but also exploit the use of process variables
to write C-like sequential descriptions of how
registers are to be updated without explicitly
describing any wires.

Only strategy 1 covers the way the hardware actually works.
All else involves abstraction and trust.

I might add that Strategy #4 makes even more sense if you use the
synthesis retiming optimizations. Why worry about register placements
among the logic in your description if your synthesis tool is going to
rearrange them anyway? Focus on functional behavior, throughput and
latency, then let the synthesis tool do the rest, whenever possible.

Andy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top