concurrent assertion statement and delta races

A

Allan Herriman

Hi,

I occasionally come across a situation in which I have an architecture
with many if-generate constructs to select different options for some
design. Exactly one of the if-generates must evaluate to true and be
"generated".

In a big design I like to test this by having an unresolved signal
(initialised to false) that is set to true inside each of the if-
generates. I then need to use an assertion to check that the signal is
indeed true, indicating that exactly one of the if-generates is active.

I know I could do this in VHDL-2008 using if-else generate, but I'm using
tools from Xilinx :( so I am restricted to using 20th century versions
of VHDL.


This has been working fine for me for years, but I just realised today
that my assertions hadn't actually been checking anything. (Which is
fine, 'cause my code never has bugs...)


I'm looking for pointers on the best way to express my assertion in VHDL
'93 or '01.
Alternatively, I'm looking for any other ways to test this aspect of my
design without using a signal.



E.g.

-- The remainder of this post is in VHDL
-- and can be compiled and simulated.

entity foo is
end entity foo;

architecture bar of foo is

signal sig : boolean := FALSE;

begin

sig <= TRUE; -- (inside an if-generate)
-- comment out previous line to test assertions


-- need to assert that sig is TRUE here

attempt_1 : assert sig
report "sig is false #1"
severity note;

-- attempt_1 fails
-- it indicates that sig is always FALSE,
-- regardless of its actual value, due to the
-- attempt_1 equivalent process running before
-- the delta in which sig gets its value


attempt_2 : assert sig or now = 0 ns
report "sig is false #2"
severity note;

-- attempt_2 fails
-- it indicates that sig is always TRUE,
-- regardless of its actual value
-- because the equivalent process runs when now = 0 ns
-- then does a wait on sig, which never has an event.


attempt_3 : postponed assert sig
report "sig is false #3"
severity note;

-- attempt_3 fails as well.
-- Postponed is meant to fix the delta race
-- we had with attempt_1, but it doesn't,
-- indicating that sig is always FALSE
-- regardless of its actual value.
-- (In which case, what is the point of having
-- postponed assert as part of the language? I must
-- be missing something here.)


attempt_5 : process
begin
wait for 0 ns;
assert sig
report "sig is false #5"
severity note;
wait;
end process attempt_5;

-- attempt_5 works correctly, but is really ugly


end architecture bar;

-- Regards,
-- Allan
 
T

Tricky

Hi,



I occasionally come across a situation in which I have an architecture

with many if-generate constructs to select different options for some

design. Exactly one of the if-generates must evaluate to true and be

"generated".



In a big design I like to test this by having an unresolved signal

(initialised to false) that is set to true inside each of the if-

generates. I then need to use an assertion to check that the signal is

indeed true, indicating that exactly one of the if-generates is active.



I know I could do this in VHDL-2008 using if-else generate, but I'm using

tools from Xilinx :( so I am restricted to using 20th century versions

of VHDL.





This has been working fine for me for years, but I just realised today

that my assertions hadn't actually been checking anything. (Which is

fine, 'cause my code never has bugs...)





I'm looking for pointers on the best way to express my assertion in VHDL

'93 or '01.

Alternatively, I'm looking for any other ways to test this aspect of my

design without using a signal.







E.g.



-- The remainder of this post is in VHDL

-- and can be compiled and simulated.



entity foo is

end entity foo;



architecture bar of foo is



signal sig : boolean := FALSE;



begin



sig <= TRUE; -- (inside an if-generate)

-- comment out previous line to test assertions





-- need to assert that sig is TRUE here



attempt_1 : assert sig

report "sig is false #1"

severity note;



-- attempt_1 fails

-- it indicates that sig is always FALSE,

-- regardless of its actual value, due to the

-- attempt_1 equivalent process running before

-- the delta in which sig gets its value





attempt_2 : assert sig or now = 0 ns

report "sig is false #2"

severity note;



-- attempt_2 fails

-- it indicates that sig is always TRUE,

-- regardless of its actual value

-- because the equivalent process runs when now = 0 ns

-- then does a wait on sig, which never has an event.





attempt_3 : postponed assert sig

report "sig is false #3"

severity note;



-- attempt_3 fails as well.

-- Postponed is meant to fix the delta race

-- we had with attempt_1, but it doesn't,

-- indicating that sig is always FALSE

-- regardless of its actual value.

-- (In which case, what is the point of having

-- postponed assert as part of the language? I must

-- be missing something here.)





attempt_5 : process

begin

wait for 0 ns;

assert sig

report "sig is false #5"

severity note;

wait;

end process attempt_5;



-- attempt_5 works correctly, but is really ugly





end architecture bar;



-- Regards,

-- Allan

I wouldnt use a signal at all - I would just XOR all of the conditions together, or have a single assert based on the different conditions:

assert (a xor b xor c)
report "Only ONE of A or B or C may be set"
severity failure;

But you may be bummed in the end by how the tool actually handle's asserts.IIRC, a few years ago some people did a test with asserts forcing a synthesisor to stop. The only one that actually stopped was Quartus, with Synplify giving just a warning (and carrying on), and others not doing anything atall (Cannot remember the ISE result).

Another problem with the signal approach is that even if it is non-resolved, some compilers may simply just remove the net unless it drives an output.
 
R

Rob Gaddi

I wouldnt use a signal at all - I would just XOR all of the conditions together, or have a single assert based on the different conditions:

assert (a xor b xor c)
report "Only ONE of A or B or C may be set"
severity failure;

But you may be bummed in the end by how the tool actually handle's asserts. IIRC, a few years ago some people did a test with asserts forcing a synthesisor to stop. The only one that actually stopped was Quartus, with Synplify giving just a warning (and carrying on), and others not doing anything at all (Cannot remember the ISE result).

Another problem with the signal approach is that even if it is non-resolved, some compilers may simply just remove the net unless it drives an output.

Integers and addition, not bits and XORs. Otherwise 3=1.
 
A

Allan Herriman

I wouldnt use a signal at all - I would just XOR all of the conditions
together, or have a single assert based on the different conditions:

assert (a xor b xor c)
report "Only ONE of A or B or C may be set"
severity failure;


Quite apart from the bug with xor, that doesn't work for me at a
practical level. The conditions are complicated and there are a lot of
them. Copying and pasting them to two places in the code (the if-
generate and the assert) may introduce errors and makes maintenance
harder. Creating constants for the conditions (to avoid the copy and
paste) makes the code messy.

But you may be bummed in the end by how the tool actually handle's
asserts. IIRC, a few years ago some people did a test with asserts
forcing a synthesisor to stop. The only one that actually stopped was
Quartus, with Synplify giving just a warning (and carrying on), and
others not doing anything at all (Cannot remember the ISE result).

Another problem with the signal approach is that even if it is
non-resolved, some compilers may simply just remove the net unless it
drives an output.

I'm only interested in the simulation behaviour. I run the regression
tests in the simulator. What happens in synthesis doesn't matter to me
for the purposes of this thread.
I'm using Modemsim 10.1d (the latest version).

Regards,
Allan
 
H

HT-Lab

On 11/02/2013 21:35, Allan Herriman wrote:
...
I'm only interested in the simulation behaviour. I run the regression
tests in the simulator. What happens in synthesis doesn't matter to me
for the purposes of this thread.
I'm using Modemsim 10.1d (the latest version).
^^^^^^^^^^^^^^^^^
Not since yesterday :)

10.2 has more suppulent VHDL2008 support and DE users get access to the
FLI (C/C++ interface for VHDL users),

Hans
www.ht-lab.com
 
A

Allan Herriman

Quite apart from the bug with xor, that doesn't work for me at a
practical level. The conditions are complicated and there are a lot of
them. Copying and pasting them to two places in the code (the if-
generate and the assert) may introduce errors and makes maintenance
harder. Creating constants for the conditions (to avoid the copy and
paste) makes the code messy.



I'm only interested in the simulation behaviour. I run the regression
tests in the simulator. What happens in synthesis doesn't matter to me
for the purposes of this thread.
I'm using Modemsim 10.1d (the latest version).

Regards,
Allan


I should clarify:

I'm using Modelsim for simulation. All my testing happens in Modelsim.
The assertions only need to run correctly in Modelsim.

The code is synthesisable, targetting a number of different tools. The
Xilinx tools are the worst case, meaning I can't use VHDL 2008.
I don't care whether the assertions are handled by the synth tools, as
long as it still compiles.

Regards,
Allan
 
T

Tricky

If you're only interested in simulation, how about the use of a shared variable?

shared varaible n_insts : integer := 0;

impure function add_inst return boolean is
begin
n_insts := n_insts + 1;

assert (n_insts <= 1)
report "Too many instances"
severity failure;

return true;
end function;


And then in each generate statement, just have the folowing constant declaration:

constant A_CONST : boolean := add_inst;

This will then count up the number of instances right at the start of the vsim, so you dont even need to run it. Each activated generate will add 1 tothe n_insts variable and bomb out when it goes above 1. This way you nevereven need to know what the generics are, or do you care. current code justneeds the constants adding.
 
A

Allan Herriman

If you're only interested in simulation, how about the use of a shared
variable?

shared varaible n_insts : integer := 0;

impure function add_inst return boolean is begin
n_insts := n_insts + 1;

assert (n_insts <= 1)
report "Too many instances"
severity failure;

return true;
end function;


And then in each generate statement, just have the folowing constant
declaration:

constant A_CONST : boolean := add_inst;

This will then count up the number of instances right at the start of
the vsim, so you dont even need to run it. Each activated generate will
add 1 to the n_insts variable and bomb out when it goes above 1. This
way you never even need to know what the generics are, or do you care.
current code just needs the constants adding.


That's an interesting solution to the problem and I thank you for your
efforts.

However, even though the assertions only need to work in simulation, the
code still needs to be synthesisable and portable over a number of
tools. I believe this rules out the use of shared variables.

The basic problem with shared variables is that one version of VHDL
supports shared variables but not protected types. A different version
of VHDL also supports shared variables, but requires that they be
protected types. Both versions of the language are currently in use.

Regards,
Allan
 
A

Andy

If you're only interested in simulation, how about the use of a shared variable? shared varaible n_insts : integer := 0; impure function add_inst return boolean is begin n_insts := n_insts + 1; assert (n_insts <= 1) report "Too many instances" severity failure; return true; end function; Andthen in each generate statement, just have the folowing constant declaration: constant A_CONST : boolean := add_inst; This will then count up the number of instances right at the start of the vsim, so you dont even need torun it. Each activated generate will add 1 to the n_insts variable and bomb out when it goes above 1. This way you never even need to know what the generics are, or do you care. current code just needs the constants adding.

Right idea, wrong implementation. Since 2002 (?) shared variables must be of a protected type. The functions/procedures (methods) defined in the protected type are guaranteed to execute atomically (one call must complete before another call can start). Otherwise, a compliant simulator could execute two or more of your unprotected initializations at the same time (differentthreads/cores), and one or more of them could see the same current value (e.g. 0), and set the new value to 1. This would lead you to believe that only one generate statement was enabled, when in fact more than one had been enabled.

This is really a good application of a shared protected variable, and it iseasy to implement, to sort of get your feet wet. Warning: once you learn how to do this, you'll find lots of other places where it makes sense to use!

Define a protected type with a local (protected) integer, and within the type, define a method serialize() that increments the protected variable and returns the updated value.

You could just call the serialize in an assertion and make sure the updatedvalue is 2 (1 + this), or define another method, value(), that simply returns the current count without incrementing it.

Then declare a shared variable of the protected type, and call its serialize() method in your constant initialization (use an integer constant) in each generate's declarative region.

This is also handy because it makes the unique serial number avaialble to each generate. This can be useful for lots of other things that require a unique value. Just remember that the order in which the various calls to serialize() are executed is not defined, so it can change from simulator to simulator on the same code, or within the same simulator with seemingly unrelated changes to the code.

Andy
 
A

Andy

You can use synthesis directives (meta-comments) to turn off translation of problematic code in synthesis. Look in the synthesis user- or reference-guide to determine what those meta-comments are for your tool.

The simulator ignores the meta-comments, and compiles/executes the code, but the synthesis tool ignores the code.

Andy
 
A

Allan Herriman

You can use synthesis directives (meta-comments) to turn off translation
of problematic code in synthesis. Look in the synthesis user- or
reference-guide to determine what those meta-comments are for your tool.

The simulator ignores the meta-comments, and compiles/executes the code,
but the synthesis tool ignores the code.

Andy


-- synthesis translate_off

(code not to be synthesised here)

-- synthesis translate_on
 
T

Tricky

Right idea, wrong implementation. Since 2002 (?) shared variables must beof a protected type. The functions/procedures (methods) defined in the protected type are guaranteed to execute atomically (one call must complete before another call can start). Otherwise, a compliant simulator could execute two or more of your unprotected initializations at the same time (different threads/cores), and one or more of them could see the same current value(e.g. 0), and set the new value to 1. This would lead you to believe that only one generate statement was enabled, when in fact more than one had been enabled.



This is really a good application of a shared protected variable, and it is easy to implement, to sort of get your feet wet. Warning: once you learnhow to do this, you'll find lots of other places where it makes sense to use!



Define a protected type with a local (protected) integer, and within the type, define a method serialize() that increments the protected variable and returns the updated value.



You could just call the serialize in an assertion and make sure the updated value is 2 (1 + this), or define another method, value(), that simply returns the current count without incrementing it.



Then declare a shared variable of the protected type, and call its serialize() method in your constant initialization (use an integer constant) in each generate's declarative region.



This is also handy because it makes the unique serial number avaialble toeach generate. This can be useful for lots of other things that require a unique value. Just remember that the order in which the various calls to serialize() are executed is not defined, so it can change from simulator to simulator on the same code, or within the same simulator with seemingly unrelated changes to the code.



Andy

I was going to suggest protected types (I love them) but for this instance I thought it a bit ott, but didnt think about your points.
 
T

Tricky

And just to add - protected types were introduced in 2002. And yes, by the LRM shared variables must be a protected type. But the default stance for modelsim is to only throw a warning for this and technically not be LRM compliant. There is an enforcement switch on the compiler to make it an error instead.

Going back to Andy's point about unique IDs - this method is only "guaranteed" in simulation. Quartus (I havent tried other synthesis tools) will throw an error saying a Constant must be constant if you use the shared variable method above, and it doesnt even accept the keyword "Protected".
 
V

valtih1978

-- Postponed
-- indicating that sig is always FALSE
-- regardless of its actual value.

This is curious. Is it a bug in tools or expected behavior of postponed?
IMO, regardless assignment is considered a process in the body of
architecture or its submodule, postponed must be fired only after all
delta cycles have finished and driving signals updated.
 
A

Allan Herriman

This is curious. Is it a bug in tools or expected behavior of postponed?
IMO, regardless assignment is considered a process in the body of
architecture or its submodule, postponed must be fired only after all
delta cycles have finished and driving signals updated.


I think the problem is that the equivalent process must run at the start
of simulation as well as whenever there's an event on the signal.

Postponed can help with the ordering of things when there's an event, but
it can't do anything about the first time the process runs at the start
of simulation, and that's when the assertion fails.

Regards,
Allan
 
V

valtih1978

Postponed can help with the ordering of things when there's an event, but
it can't do anything about the first time the process runs at the start
of simulation, and that's when the assertion fails.

The spec treats both cases: postponed are executed once all normal
processes catched in the wait during simulation start, at time 0 and,
secondly, prior to time advance (you call it event case). So, if you
have a single assignment

process begin
singleton <= generate_x_value;
wait;
end process;

Since this process generates an event and postponed processes start
after it suspends in the wait, for both of these reasons your postponed
assertion

assert postponed check(singleton)

must work as postponed.

Postponed assertion has only one flaw because start case is treated
specifically. Executing postponed once all processes started, as opposed
to time advance event, creates situation that there are delta frames to
be executed, yet, specification forces your postponed to run once
simulation starts. This requires an ugly workaround,
http://computer-programming-forum.com/42-vhdl/3edcb21668330593.htm
HardLook at that workaround and note that your workaround is not that
ugly. I would live with your workaround. Yet, IMO, no workarounds are
needed in your case since postponed must do its job. That is why I am
asking.
 
A

Allan Herriman

I would live with your workaround. Yet, IMO, no workarounds are
needed in your case since postponed must do its job. That is why I am
asking.


I guess it must be a tool bug if what you say is true.
I really don't know - I've been using VHDL since the mid '90s and that's
the first time I've ever used postponed, so I can't claim to have any
experience in this area.


Regards,
Allan
 

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,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top