Variable vs. Signal on indexing

A

ALuPin

Hi newsgroup,

I have the two following approaches in combinational processes:

SIGNAL ls_idx : integer RANGE 0 TO 127;
SIGNAL ls_wlist_copy_cache_q : std_logic_vector(63 DOWNTO 0);
SIGNAL ls_rlist_cache_q : std_logic_vector(63 DOWNTO 0);
SIGNAL ls_ba_checked_wlistc, ls_ba_checked_rlist : std_logic_vector(1
DOWNTO 0);
SIGNAL ls_pos_col_in_cache : std_logic_vector(5 DOWNTO 0);

1. approach:

CHECKCACHES_comb: PROCESS(ls_check_w_wc_r_list, ls_pos_col_in_cache,
ls_wlist_copy_cache_q,
ls_rlist_cache_q, ls_idx)
VARIABLE idx : integer RANGE 0 TO 127;
BEGIN
ls_ba_checked_wlistc <= "00";
ls_ba_checked_rlist <= "00";

IF ls_check_w_wc_r_list='1' THEN
idx := 2 * to_integer(unsigned(ls_pos_col_in_cache)) - 1;

ls_ba_checked_wlistc <= ls_wlist_copy_cache_q(idx DOWNTO idx-1);
ls_ba_checked_rlist <= ls_rlist_cache_q(idx DOWNTO idx-1);
ls_idx <= idx;

END IF;
END PROCESS CHECKCACHES_comb;

2. approach:

CHECKCACHES_comb: PROCESS(ls_check_w_wc_r_list, ls_pos_col_in_cache,
ls_wlist_copy_cache_q,
ls_rlist_cache_q, ls_idx)
BEGIN
ls_ba_checked_wlistc <= "00";
ls_ba_checked_rlist <= "00";
ls_idx <= 0;

IF ls_check_w_wc_r_list='1' THEN
ls_idx <= 2 * to_integer(unsigned(ls_pos_col_in_cache)) - 1;

ls_ba_checked_wlistc <= ls_wlist_copy_cache_q(ls_idx DOWNTO
ls_idx-1);
ls_ba_checked_rlist <= ls_rlist_cache_q(ls_idx DOWNTO ls_idx-1);


END IF;
END PROCESS CHECKCACHES_comb;

When using the second approach I get the following fatal error when
performing functional simulation
(with ModelsimDesigner 6.1f):


# ** Fatal: (vsim-3471) Slice range (0 downto -1) does not belong to
the prefix index range (63 downto 0).


Note that the signal "ls_pos_col_in_cache" NEVER gets "000000" when
"ls_check_w_wc_r_list"
is active.
So where is the difference in both descriptions causing Modelsim to
complain ?

Is it a simulation problem or will the indexing cause problems during
synthesis ?

Thank you for your opinion.

Rgds
Andre
 
J

Jim Lewis

(e-mail address removed) wrote:
Variables get updated immediately so the process sees the new value.
Signals get updated at the beginning of the next delta cycle,
and hence it has a previous value on it. The previous value
at start-up is 0, the left-most value of the constrained type
(since you range it to be 0 t0 127).

Cheers,
Jim
 
A

ALuPin

Hi Jim,
thank you for your response:

Yes, it is clear now for simulation.

But what about synthesis ? When using variables as shown in the first
approach, do I have to define the ELSE condition for the variable ?

CHECKCACHES_comb: PROCESS(ls_check_w_wc_r_list, ls_pos_col_in_cache,
ls_wlist_copy_cache_q,
ls_rlist_cache_q, ls_idx)
VARIABLE idx : integer RANGE 0 TO 127;
BEGIN
ls_ba_checked_wlistc <= "00";
ls_ba_checked_rlist <= "00";
idx := 0; -- ??? necessary


IF ls_check_w_wc_r_list='1' THEN
idx := 2 * to_integer(unsigned(ls_pos_col_in_cache)) - 1;


ls_ba_checked_wlistc <= ls_wlist_copy_cache_q(idx DOWNTO idx-1);
ls_ba_checked_rlist <= ls_rlist_cache_q(idx DOWNTO idx-1);
ls_idx <= idx;

END IF;
END PROCESS CHECKCACHES_comb;

Rgds
Andre
 
M

Mike Treseler

Yes, it is clear now for simulation.
But what about synthesis ?

If the design simulates ok,
synthesis should be a detail.

The design process is that same
with or without variables.

With reasonable code design rules, the
simulation waveforms at the ports
matches what I see on the bench.

-- Mike Treseler
 
J

Jim Lewis

Mike said:
If the design simulates ok,
synthesis should be a detail.

The design process is that same
with or without variables.
I agree. The functionality will be correct,
however sometimes with variables the synthesis
tool will be a little generous with registers.
For example if a variable is read before it is
written, it may create a register even when
that register is redundant. In the process below
sometimes VAR will create a register eventhough
that register has the same inputs as the Count
register:

VarProc : Process
begin
wait until Clk = '1' ;
VAR := VAR + 1 ;
Count <= VAR ;
end process ;

> But what about synthesis ? When using variables as shown in the first
> approach, do I have to define the ELSE condition for the variable ?
>
> CHECKCACHES_comb: PROCESS(ls_check_w_wc_r_list, ls_pos_col_in_cache,
> ls_wlist_copy_cache_q,
> ls_rlist_cache_q, ls_idx)
> VARIABLE idx : integer RANGE 0 TO 127;
> BEGIN
> ls_ba_checked_wlistc <= "00";
> ls_ba_checked_rlist <= "00";
> idx := 0; -- ??? necessary
>
>
> IF ls_check_w_wc_r_list='1' THEN
> idx := 2 * to_integer(unsigned(ls_pos_col_in_cache)) - 1;
>
>
> ls_ba_checked_wlistc <= ls_wlist_copy_cache_q(idx DOWNTO idx-1);
> ls_ba_checked_rlist <= ls_rlist_cache_q(idx DOWNTO idx-1);
> ls_idx <= idx;
>
> END IF;
> END PROCESS CHECKCACHES_comb;

Good question. First this process does create latches for
ls_ba_checked_wlistc, ls_ba_checked_rlist, and ls_idx.
If it did create a latch for idx, that latch would be redundant
with the latch for ls_idx.

Without an assignment outside of the if condition, it is possible
that it would create a latch for idx - not very logical though,
but remember synthesis tools are algorithmic - not logical.

I would not assign idx to 0 outside the if statement as that
would imply a multiplexer for idx. Instead if I were worried,
I would move the assignment to idx outside of the if statement.

Cheers,
Jim Lewis
SynthWorks
 
M

Mike Treseler

Jim said:
For example if a variable is read before it is
written, it may create a register even when
that register is redundant.

The implication is that using variables
wastes flops, and this simply is not true.

If the register is not intended,
that is a design error like any
other that would be picked up and corrected
during the edit-sim-edit cycle.
Is the wave correct or is it delayed by a tick?

The simulation results are what matters.
Synthesis tools are very efficient with
signals or variables.
In the process below
sometimes VAR will create a register even though
that register has the same inputs as the Count
register:

VarProc : Process
begin
wait until Clk = '1' ;
VAR := VAR + 1 ;
Count <= VAR ;
end process ;

The error here is that the port
assignment is inside a clocked clause.
This infers an output pipeline register.

If I put the port assignment
outside of the clocked clause,
no pipeline register is inferred.

clked : process(clk)
variable cnt_v : count_t;
begin
if rising_edge(clk) then
cnt_v := cnt_v + 1; -- increment on rising edge
end if;
cnt <= cnt_v; -- wire assignment outside of clocked clause
end process clked;

see synthesis results here:
http://home.comcast.net/~mike_treseler/rollover.pdf

see full design here:
http://home.comcast.net/~mike_treseler/rollover.vhd


-- Mike Treseler
 
A

Andy

Synplicity has always done a good job of optimizing out redundant
flops, so long as they really are redundant (i.e. both have same async
reset, etc.)!

I've found Mike's method of making the port/signal assignment
outside/after the clock clause to be more efficient, since it avoids
creating the redundant flop in the first place. Inside the clock clause
creates a count register with the combinatorial var as input, outside
the clock clause creates a combinatorial count signal from the
registered var. Sixes either way.

Interestingly, when I ran a test with two functionally (on a
clock-clock basis) identical output signals (one inside, one outside
the clock clause), synplicity did figure out that they were both
identical, and optimized one out. This was even when the LHS was an
expression of variables, as in:

if rising_edge(clk) then
vara := vara + 1;
varb := varb + 1;
siga <= vara + varb; -- register of combo values for a,b
end if; -- rising_edge
sigb <= vara + varb; -- combo of registered values for a,b

Andy
 
J

Jim Lewis

Mike,
The implication is that using variables
wastes flops, and this simply is not true.
Touchy are we :)

It only takes one counter case to prove this
statement wrong and I just showed you one.
If the register is not intended,
that is a design error like any
other that would be picked up and corrected
during the edit-sim-edit cycle.
Is the wave correct or is it delayed by a tick?

The wave is correct - only one register in simulation.
Gate and RTL simulation match, yet the synthesis results
have 2 registers. If you look at the synthesis
results, you will see that both registers (VAR and Count)
have the same input - hence the tool did waste registers.
The simulation results are what matters.
Synthesis tools are very efficient with
signals or variables.

With respect to registers, some synthesis tools
seem to be more generous producing registers than
others.
The error here is that the port
assignment is inside a clocked clause.
This infers an output pipeline register.

Nope. No extra pipeline delay.
BTW, this code is 1076.6-1999 and 1076.6-2004
compliant. As are results that produce either
one or two registers (the standard is about producing
results and not optimization).
If I put the port assignment
outside of the clocked clause,
no pipeline register is inferred.

clked : process(clk)
variable cnt_v : count_t;
begin
if rising_edge(clk) then
cnt_v := cnt_v + 1; -- increment on rising edge
end if;
cnt <= cnt_v; -- wire assignment outside of clocked clause
end process clked;

The fact that you can fix the code is not the point.
The point is there is some code (not good code) that
looks fine, but will produce area inefficient results.

Also although you got results, is your code style portable?
In particular, does it work on Synopsys? I know they
did not support it in the past. Also it is not 1076.6-1999
compliant, it may not be 1076.6-2004 compliant either
(it certainly was not intended to be).

Cheers,
Jim

OTOH, so what if variables are inefficient with respect to
registers? Would you notice? Not unless you did not
fit in the chip.
 
M

Mike Treseler

Andy said:
Synplicity has always done a good job of optimizing out redundant
flops, so long as they really are redundant (i.e. both have same async
reset, etc.)!

Quartus and ISE also take out the duplicate flops, post-fit.
However they can show up in the pre-fit RTL view.
I've found Mike's method of making the port/signal assignment
outside/after the clock clause to be more efficient, since it avoids
creating the redundant flop in the first place.

This also gives me a clean RTL schematic
without running a full synthesis.

-- Mike Treseler
 
M

Mike Treseler

Jim said:
It only takes one counter case to prove this
statement wrong and I just showed you one.

The duplicate flops only show up in the RTL view,
not in the tech view. The removal is also
noted in the log file.
The wave is correct - only one register in simulation.
Gate and RTL simulation match, yet the synthesis results
have 2 registers. If you look at the synthesis
results, you will see that both registers (VAR and Count)
have the same input - hence the tool did waste registers.

Yes, sorry, it is a duplication,
not a pipe at the RTL level.
But synthesis removes it, post-fit.
With respect to registers, some synthesis tools
seem to be more generous producing registers than
others.
The fact that you can fix the code is not the point.
The point is there is some code (not good code) that
looks fine, but will produce area inefficient results.

Hmmm. Synplicity, Quartus and ISE get it right,
even for the "not good code".
What synthesis should I use to duplicate
these inefficient results?
Also although you got results, is your code style portable?
In particular, does it work on Synopsys? I know they
did not support it in the past. Also it is not 1076.6-1999
compliant, it may not be 1076.6-2004 compliant either
(it certainly was not intended to be).

I have one email reporting that my reference design produces
an error on an unspecified version of Synopsys, but it involves my use
of procedures, not variables. But without the use
of a license it is impossible for me to narrow it down,
and I have no interest in buying one.
Other than that, the style is portable, as far as I know.
OTOH, so what if variables are inefficient with respect to
registers? Would you notice? Not unless you did not
fit in the chip.

I'm sure I wouldn't notice even if it were true.
But it isn't true for any of the tools that I use,
and I cringe when new users are frightened away
from perfectly useful synthesis concepts like
variable assignments.

-- Mike Treseler
 
J

Jim Lewis

Mike
The duplicate flops only show up in the RTL view,
not in the tech view. The removal is also
noted in the log file.
Good to hear.

I have one email reporting that my reference design produces
an error on an unspecified version of Synopsys, but it involves my use
of procedures, not variables. But without the use
of a license it is impossible for me to narrow it down,
and I have no interest in buying one.
Other than that, the style is portable, as far as I know.

???
I would definitely need to see it working under
Synopsys before I would claim any portability.
I know for a fact that old versions did not
support this.
I'm sure I wouldn't notice even if it were true.
But it isn't true for any of the tools that I use,
and I cringe when new users are frightened away
from perfectly useful synthesis concepts like
variable assignments.

This is where our opinion differs.
There are enough issues with design, verification,
and HDL coding that new users must deal with and
master. As a result, I don't think a new user
needs to bother with variables in an RTL design.

OTOH, as one grows in experience, I don't see any
reason not to start to use variables.

Cheers,
Jim
 
M

Mike Treseler

Jim said:
I would definitely need to see it working under
Synopsys before I would claim any portability.

I made no such claim.
In fact I have always disclaimed Synopsys
on my web page like this:

"Examples have been used successfully on Quartus, ISE, Leonardo,
Synplify, Modelsim, and NC-Sim. Examples are not compatible with
Synopsys tools. Reports for other tools are appreciated."
I know for a fact that old versions did not
support this.

Thanks for the report.
This is where our opinion differs.
There are enough issues with design, verification,
and HDL coding that new users must deal with and
master. As a result, I don't think a new user
needs to bother with variables in an RTL design.

I will agree that we disagree.

-- Mike Treseler
 
A

ALuPin

Hi Mike, hi Jim,

thank you for your opinions. I think in my case it does make sense
to use variables because if I use the second approach (which is fine
for synthesis) I will always get that fatal error when simulating. So
it is somehow
paradox that a construct can be synthesized but not simulated, my
experience
always shows the other way around.

Rgds
Andre
 
A

ALuPin

I have to correct myself:

When using approach one, and defining the else tree for the variable
assignment, the synthesis tool (Synplicity) gives out the
warning that a combinational loop has been found.
I cannot understand that, all cases are defined.

Rgds
Andres
 
J

jandecaluwe

Jim said:
There are enough issues with design, verification,
and HDL coding that new users must deal with and
master. As a result, I don't think a new user
needs to bother with variables in an RTL design.


Certainly a widely held opinion, but that doesn't make it
logical as I hope to show with the following two arguments.

First, for essential skills such as verification, you need to
learn about variables. You'll need them immediately, for
example to write a for loop or a function. At the same time,
we know that variables are useful and work fine with RTL
design also. So why should we prevent users from using them
in RTL design, while they'll need them for verification
anyway? That seems arbitrary and artificial. Surely it
complicates matters more than it simplifies them.

Secondly, consider trying to explain variable versus signal
semantics to a junior software engineer. What will be the most
difficult? Obviously, variables are the easy stuff. In contrast,
signals are complex objects with pretty complicated semantics,
requiring a considerable amount of learning. Still, many
hardware designers have a tendency to label signals as
"basic" and variables as "advanced". It should really be the
other way around. Odd, isn'it?

Jan
 
J

Jonathan Bromley

hardware designers have a tendency to label signals as
"basic" and variables as "advanced". It should really be the
other way around. Odd, isn'it?

Yes; but then, many things about simulation and synthesis
are odd.

For example: it's odd that, in a discrete-event simulator,
all the simulator's time is spent processing activity that
occurs in zero simulated time; the passage of simulated
time costs the simulator essentially nothing (merely
replacing the current value of NOW with the value
at which the next event occurs).

Given the usual RTL paradigm, the relationship between
VHDL signals and the hardware they represent can be
explained rather easily. The relationship between VHDL
variables and the hardware they represent (or don't!)
is much subtler.

It's difficult to get hardware folk to think in terms of
functionality, when they (quite properly) need to
spend much of their working lives worrying about
structure and timing.

I have huge sympathy for the position held by Mike
Treseler and others - that you should use variables
in fairly complicated synchronous processes to describe
the functionality you want, and let the synthesis tool
fuss about the structure - but that position works
only for people who have enough insight to be able
to envisage what hardware structures they're describing,
without actually laying-out the gates and flops. For
beginners, and traditional paper-and-pencil designers,
it's tough.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(e-mail address removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
J

Jim Lewis

Jan,
Certainly a widely held opinion, but that doesn't make it
logical as I hope to show with the following two arguments.

First, for essential skills such as verification, you need to
learn about variables. You'll need them immediately, for
example to write a for loop or a function. At the same time,
we know that variables are useful and work fine with RTL
design also. So why should we prevent users from using them
in RTL design, while they'll need them for verification
anyway? That seems arbitrary and artificial. Surely it
complicates matters more than it simplifies them.

Note I state my guideline as a "recommendation" and not a rule.

Recommendation:
Avoid using variables for RTL design on your first couple of projects.

This way those who already have FPGA design skills or are
sharp would feel free to violate it.
Secondly, consider trying to explain variable versus signal
semantics to a junior software engineer. What will be the most
difficult? Obviously, variables are the easy stuff. In contrast,
signals are complex objects with pretty complicated semantics,
requiring a considerable amount of learning. Still, many
hardware designers have a tendency to label signals as
"basic" and variables as "advanced". It should really be the
other way around. Odd, isn'it?

To some degree, I agree. Especially for verification.
Here are my notes for RTL creation:

RTL behavior in a clocked process:
Signal assignment: Always implies* a register
Variable assignment:
Implies a register if variable read before written.
Alternately implies a register if variable has a life time.
Implies combinational logic when always written before read.

*Registers are created for all implied registers unless there
is a redundancy that can be merged with another register.


RTL behavior in a combinational process:
Signal assignment:
Must get a value for every hardware execution of the
process or it will create a latch.
Recommendation: do not read a value that is written in the same
process, otherwise, signal must be on sensitivity list and process
must iterate.

Variable assignment:
Implies combinational logic when always written before read.
If read before written then error
Must get a value for every hardware execution of the
process or it will create a latch.

For design creation there are alot of details that must
be managed. As you pare this down to RTL creation,
you must master signals, but for most applications you
don't need to use variables - hence you
don't need to learn the additional hardware implications.

Cheers,
Jim
 
M

Mike Treseler

Jonathan said:
... that position works
only for people who have enough insight to be able
to envisage what hardware structures they're describing,
without actually laying-out the gates and flops. For
beginners, and traditional paper-and-pencil designers,
it's tough.

There are two tracks I use when an intern
or engineer new to FPGA design asks for
help getting started.

1. For the circuit board designer with no
software or simulation experience, the starting
point is simple design examples and an RTL viewer.
This shows the connection between
source code view and the gates'n'flops. Simple
designs can be validated on the bench with
trial-and-error synthesis.
Simulation of the validated code is a long final chapter.

2. For the computer engineer, simulation is
a more natural starting point. Here the connection
to make is between source code and functional waveforms.
I start with code template examples, testbenches
and a simulator. Designs can be validated
using trial-and-error simulation and debugged by tracing code.
Synthesis of the validated code is the final chapter.

-- Mike Treseler
 
A

Andy

When I first started flirting with variables in VHDL synthesis,
understanding how they mapped to hardware took some time. OTOH, when I
first started coding VHDL at all, understanding the non-sequential
nature of signal assignment statements in sequential code took a while
too. If I had a buck for every time a newbie asked me why their
signal's value wasn't getting updated when it was clearly assigned
before being read, I'd be a wealthy man! With variables, a read before
a write in a clocked process creates a register, period. How hard is
that? For a

And don't get me started about stuff that Synopsys does not support in
VHDL synthesis... ram/rom inferencing, direct entity instantiation
(sorta, but broken in places), implementation of mod and / in
numeric_std, and on, and on...! I should qualify the above with the
fact that I haven't used Synopsys synthesis tools in a few years, but
everyone else was supporting this stuff when I left them.

If signal assignments to expressions of variables after the clocked
clause are not addressed in the "synthesis standard" and yet the
majority of synthesis tools support it, then they should be addressed,
lest the standard become hopelessly irrelevant. The most recent update
to the standard is a step in the right direction, namely away from
templates and toward synthesis of behavior, but it still has a ways to
go. I believe this is one place where the demands of the marketplace,
and thus the feature sets of the tools are outstripping the ability of
standardization efforts to keep up.

Also, not the variables themselves, but _references_ to them imply
storage or not (and thus register or not); the same variable name may
represent a combinatorial value in one reference, and a register value
in another. And the difference can even be dynamically controlled (e.g.
a prior write may be conditional). The point is the synthesis tool will
use a register or not (or a mux between the two) to implement the coded
behavior.

Andy
 
J

Jim Lewis

Andy,
If signal assignments to expressions of variables after the clocked
clause are not addressed in the "synthesis standard" and yet the
majority of synthesis tools support it, then they should be addressed,
lest the standard become hopelessly irrelevant. The most recent update
to the standard is a step in the right direction, namely away from
templates and toward synthesis of behavior, but it still has a ways to
go. I believe this is one place where the demands of the marketplace,
and thus the feature sets of the tools are outstripping the ability of
standardization efforts to keep up.

Sure. You and Mike ready to take it up? These things
take volunteers. The 2004 revision needs to be re-anlayzed
with this in mind to see if it is missing or if it is there
and I missed seeing it. There is also some need for adding
more attributes and perhaps renaming fsm_complete (particularly
if no-one has implemented it) to fsm_safe (as that is what it
does).

By the way, I am still waiting for vendors to support multiple
clocked FIFOs and registers. I know that Xilinx at one time
supported a coding style that uses VHDL-93 shared variables,
however, as of VHDL-2000/2002, shared variables must be a
protected type.

Also, not the variables themselves, but _references_ to them imply
storage or not (and thus register or not); the same variable name may
represent a combinatorial value in one reference, and a register value
in another.
Obvious to the quick and the sharp. Subtle to new users
who are overwhelmed by other pieces of the design and
design flow.

And the difference can even be dynamically controlled (e.g.
a prior write may be conditional).
Exciting :). Sometimes registered, sometimes combo logic.

Cheers,
Jim
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top