How to write testbench file?

  • Follow


Hi, i am using an actel fpga to generate pwm signal. There are these
IP cores in the libero software for you to drage and drop into your
design. I have the following .vhd code and is having a hard time
trying to write the testbench for it..

"library ieee;
use ieee.std_logic_1164.all;

entity FSM_CorePWM is
    GENERIC (PWM_NUM :  integer := 1);
	port (PCLK, PRESET_N, PSEL, PENABLE, PWRITE: in std_logic;
                       DUTY_CYC: in std_logic_vector (2 downto 0);
                       PWM: out std_logic_vector (PWM_NUM downto 1);
                       PRDATA: out std_logic_vector (7 downto 0);
                       INT: out std_logic);
end entity FSM_CorePWM;

architecture HIERARCHICAL of FSM_CorePWM is
    component FSM
        port (PCLK, PRESET_N: in std_logic;
               DUTY_CYC: in std_logic_vector (2 downto 0);
               PADDR: out std_logic_vector (7 downto 0);
               PWDATA: out std_logic_vector (7 downto 0));
    end component;
    component core_pwm
		GENERIC (PWM_NUM :  integer := 8);
                                port (PCLK, PRESET_N, PSEL, PENABLE,
PWRITE: in std_logic;
                                       PADDR: in std_logic_vector(7
downto 0);
                                       PWDATA: in std_logic_vector(7
downto 0);
                                       PWM: out std_logic_vector
(PWM_NUM downto 1);
                                       PRDATA: out std_logic_vector(7
downto 0);
                                       INT: out std_logic);
    end component;
    signal PADDR_TOP: std_logic_vector(7 downto 0);
    signal PWDATA_TOP: std_logic_vector(7 downto 0);
begin
    FSM_TOP: FSM port map
(PCLK=>PCLK,PRESET_N=>PRESET_N,DUTY_CYC=>DUTY_CYC,PADDR=>PADDR_TOP,PWDATA=>PWDATA_TOP);
    COREPWM_TOP: core_pwm
	GENERIC MAP (PWM_NUM =>PWM_NUM)
	port map
(PCLK=>PCLK,PRESET_N=>PRESET_N,PSEL=>PSEL,PENABLE=>PENABLE,PWRITE=>PWRITE,
PADDR=>PADDR_TOP,PWDATA=>PWDATA_TOP,PWM=>PWM,PRDATA=>PRDATA,INT=>INT);
end HIERARCHICAL; "

In the above, component "FSM" is another .vhd code while component
"core_pwm" is the IP core. please help to guide me how to generate the
testbench/stimulus for this.
0
Reply RaulGonz 1/27/2010 6:18:02 AM

Instantiate your unit under test (fsm_corepwm in this case) in a test
bench entity/architecture. Write processes, procedures, etc. in the
architecture as required to drive the UUT inputs to excercise the UUT
(i.e. give the UUT data to work on, command it to do specific
operations, etc.)

Now you have two options. For simple UUTs you can simply gather up all
the UUT inputs and outputs in a waveform viewer and manually determine
whether or not it is working as you expected.

Or you can write more processes, procedures, etc. to examine the UUT
inputs and outputs, to determine if they are functioning as expected.
This is called a self checking test bench. This method is more work to
create, but is easier to use, especially by someone else who may not
be as familiar with your design as you are (that someone else could be
yourself after you've left the project for a while). Sometimes the
verification uses a separate reference model of what the UUT is
supposed to do, and the outputs of the UUT and reference model are
compared to determine whether the UUT works. Remember, this reference
model does not need to be synthesizable, so you can use lots of tricks
in vhdl that are not available in synthesis, like waiting on arbitrary
signals, inserting time delays, etc.  Also, your checking code can use
assertion statements to report failures (easy), or you can log
failures to a separate text file for later review (harder, but can be
more elaborate). I usually write self checking testbenches with
assertion statements to report failures, and it works well for me.

Hope this helps,

Andy
0
Reply Andy 1/27/2010 5:02:24 PM


hi Andy,

i wrote the following testbench for "fsm_pwmcore.vhd"

"library ieee;
use ieee.std_logic_1164.all;

entity TB_FSM is
end TB_FSM;

architecture behv of TB_FSM is

component FSM_CorePWM is
GENERIC (PWM_NUM : integer := 8);
port (PCLK, PRESET_N, PSEL, PENABLE, PWRITE: in std_logic;
          DUTY_CYC: in std_logic_vector (2 downto 0);
          PWM: out std_logic_vector (8 downto 1);
          PRDATA: out std_logic_vector (8 downto 1);
          INT: out std_logic);
end component;

signal TB_PCLK: std_logic;
signal TB_PRESET_N: std_logic;
signal TB_PSEL: std_logic;
signal TB_PENABLE: std_logic;
signal TB_PWRITE: std_logic;
signal TB_DUTY_CYC: std_logic_vector (2 downto 0);
signal TB_PWM: std_logic_vector (8 downto 1);
signal TB_PRDATA: std_logic_vector (8 downto 1);
signal TB_INT: std_logic;

begin

	unit: FSM_CorePWM --GENERIC map (PWM_NUM)
			  port map (TB_PCLK, TB_PRESET_N, TB_PSEL, TB_PENABLE, TB_PWRITE,
TB_DUTY_CYC, TB_PWM, TB_PRDATA, TB_INT);

process
  begin

  TB_PSEL <= '1';
  TB_PENABLE <= '1';
  TB_PWRITE <= '1';
	TB_PCLK <= '0';
	wait for 5 ns;
	TB_PCLK <= '1';
	wait for 5 ns;

  end process;
end behv; "

now the problem is this fsm_pwmcore consist of two components which
are the corepwm and fsm. How can i like this fsm_pwmcore to the two
components in testbench format?? Please advise. Thank you.

0
Reply RaulGonz 1/28/2010 6:26:58 AM

Sorry, i mean how can i ADD this fsm_pwmcore to the two
components in testbench format?? Please advise. Thank you.
0
Reply RaulGonz 1/28/2010 6:29:42 AM

On Jan 28, 12:29=A0am, RaulGonz <raull...@hotmail.com> wrote:
> Sorry, i mean how can i ADD this fsm_pwmcore to the two
> components in testbench format?? Please advise. Thank you.

I'm not sure I understand your question, but when you instantiate the
FSM_CorePWM in your testbench, that brings in the lower two modules
instantiated within it. You are testing both of those modules together
within FSM_CorePWM, through the FSM_CorePWM external interface.

BTW, you can avoid component declarations, configurations, default
binding, etc. by directly instantiating the entity (and optionally
specifying the architecture):

unit: entity work.FSM_CorePWM(HIERARCHICAL) --GENERIC map (PWM_NUM)
                          port map (TB_PCLK, TB_PRESET_N, TB_PSEL,
TB_PENABLE, TB_PWRITE,
TB_DUTY_CYC, TB_PWM, TB_PRDATA, TB_INT);

You can do this for any entity/architecture for which you have the
source code. You cannot do this for primitives, or cores for which you
do not have vhdl source. For instance, if you do not have the vhdl
source for the FSM and core_pwm modules, you must use component
declarations and instantiations like you have done.

Andy
0
Reply Andy 1/28/2010 4:55:35 PM

Hi Andy, you are correct. FSM_CorePWM is my top level design file and
it calls on two lower modules instantiated with it. Now, do i have to
create a testbench for each of the two lower modules in order to
simulate the design as a whole?

This is because in the actel libero IDE software project manager, i
was told that i can set FSM_CorePWM as the root and the modelsim
simulation can actually be initiated from the libero project manager.
That brings me to my question... do i have to write individual
testbench for the two lower modules and then link them up to the top
level design file (FSM_CorePWM) before i initiated modelsim from
libero?

Or from what i understand from your reply, i can just write what i
want to do with what components/entity (be it the FSM_CorePWM, FSM or
the corePWM IP) in just a single testbench file?

Please advise. Thank you so much..

Andy wrote:
> On Jan 28, 12:29=A0am, RaulGonz <raull...@hotmail.com> wrote:
> > Sorry, i mean how can i ADD this fsm_pwmcore to the two
> > components in testbench format?? Please advise. Thank you.
>
> I'm not sure I understand your question, but when you instantiate the
> FSM_CorePWM in your testbench, that brings in the lower two modules
> instantiated within it. You are testing both of those modules together
> within FSM_CorePWM, through the FSM_CorePWM external interface.
>
> BTW, you can avoid component declarations, configurations, default
> binding, etc. by directly instantiating the entity (and optionally
> specifying the architecture):
>
> unit: entity work.FSM_CorePWM(HIERARCHICAL) --GENERIC map (PWM_NUM)
>                           port map (TB_PCLK, TB_PRESET_N, TB_PSEL,
> TB_PENABLE, TB_PWRITE,
> TB_DUTY_CYC, TB_PWM, TB_PRDATA, TB_INT);
>
> You can do this for any entity/architecture for which you have the
> source code. You cannot do this for primitives, or cores for which you
> do not have vhdl source. For instance, if you do not have the vhdl
> source for the FSM and core_pwm modules, you must use component
> declarations and instantiations like you have done.
>
> Andy
0
Reply RaulGonz 1/29/2010 1:38:34 AM

On Jan 28, 8:38=A0pm, RaulGonz <raull...@hotmail.com> wrote:
> Now, do i have to
> create a testbench for each of the two lower modules in order to
> simulate the design as a whole?

No.

KJ
0
Reply KJ 1/29/2010 3:27:55 AM

> I usually write self checking testbenches with
> assertion statements to report failures, and it works well for me.
>

Another approach is to write a self checking design.  All of that non-
synthesizable stuff can be included right in the architecture with the
design itself...safely surrounded by
-- synthesis translate_off
-- synthesis translate_on

Then the testbench itself only generate stimulus.  The nice thing here
is that if you make a change to a widget but don't run the testbench
for widget, jumping right to the top level testbench instead you've
still got the same checking code running for you in that environment.

Alternatively, you can view this as checking code for the widget
regardless of the test environment since it will always run.  When you
can do this, you've probably got a more robust checker since it is
will not be dependent on any anomolies, coverage holes or other corner
cutting that might be implicitly there in the traditional testbench
approach that generates stimulus and verifies response.

Testing in more environments is always better from a design
verification standpoint, putting the checking logic right in the
design allows you to test in any environment that the widget will ever
get used.

KJ
0
Reply KJ 1/29/2010 3:43:37 AM

hi KJ,

Do u mean that i can just create a testbench and then include whatever
components/signals, in the two lower modules, to this sole testbench?

KJ wrote:
> On Jan 28, 8:38=A0pm, RaulGonz <raull...@hotmail.com> wrote:
> > Now, do i have to
> > create a testbench for each of the two lower modules in order to
> > simulate the design as a whole?
>
> No.
>
> KJ
0
Reply RaulGonz 1/29/2010 6:02:38 AM

KJ wrote:

> Another approach is to write a self checking design.  All of that non-
> synthesizable stuff can be included right in the architecture with the
> design itself...safely surrounded by
> -- synthesis translate_off
> -- synthesis translate_on

I can even include simulation libraries in
my synthesis code the same way.
This is also a quick way to add some visibility
for debugging a variable deep in the design.

      -- Mike Treseler
0
Reply Mike 1/29/2010 7:07:11 PM

So, is this what they mean by "Design For Test"? ;^)

Seriously, there is nothing like embedding self-checking code in the
design itself, to provide guidance for future reviewers/maintainers
about the functionality required of the design.

I've long advocated a system where we could embed assertion
statements, perhaps with standardized functions that verify things
like mutual exclusivity of inputs, etc., such that a synthesis tool
could use the information to optimize the implementation. In
simulation, the assertion would verify that the inputs were indeed
mutually exclusive, thus checking the external interface to that
module.

For instance, if I had a function that could take an unconstrained
array of boolean and return false if more than one element were true,
I could write an assertion that called it:

Assert std_mutex(read_enable & write_enable));

Then if I had code that looked like:

if read_enable then
....
elsif write_enable then
....
end if;

then the synthesis tool could recognize that the priority implied by
the if-elsif statement was not needed and could be optimized out of
the implementaion.

We'd get better verification, with better synthesis in the bargain.

Andy
0
Reply Andy 1/29/2010 8:11:43 PM

Andy wrote:

> For instance, if I had a function that could take an unconstrained
> array of boolean and return false if more than one element were true,
> I could write an assertion that called it:
> 
> Assert std_mutex(read_enable & write_enable));
> 
> Then if I had code that looked like:
> 
> if read_enable then
> ...
> elsif write_enable then
> ...
> end if;
> 
> then the synthesis tool could recognize that the priority implied by
> the if-elsif statement was not needed and could be optimized out of
> the implementaion.
> 
> We'd get better verification, with better synthesis in the bargain.


I could collect statistics in a self-checking simulation,
but I don't follow how I could prove the proposition
except for a constant array.

       -- Mike Treseler
0
Reply Mike 1/29/2010 11:02:40 PM

On Jan 29, 3:11=A0pm, Andy <jonesa...@comcast.net> wrote:
>
> I've long advocated a system where we could embed assertion
> statements, perhaps with standardized functions that verify things
> like mutual exclusivity of inputs, etc., such that a synthesis tool
> could use the information to optimize the implementation.

And if the assertion statements logically contradict the logic in some
fashion, which path should the synthesis tool follow?

- If the synthesis tool followed the path of the written code, it
would be doing what it does today...which is to ignore all but
statically verifiable assertions for the purposes of generating logic
and simply report those assertion failures and stop (at best...some
tools don't do that).

- If it followed the path of the assertions, then what makes the line
of assertion code more likely to be correct than the code for the
logic?  I don't think I'm alone in that every line of code I write is
a potential to initially be wrong and need fixing.  This is true
whether the line of code is logic for the design or an assertion to
check that design.

Kevin Jennings
0
Reply KJ 1/30/2010 3:27:32 AM

On Jan 29, 2:07=A0pm, Mike Treseler <mtrese...@gmail.com> wrote:
> This is also a quick way to add some visibility
> for debugging a variable deep in the design.
>

That's why I keep tellin' ya...use some concurrent assignments and
signals for a change and cut back on those variables ;)

Kevin Jennings
0
Reply KJ 1/30/2010 3:29:16 AM

KJ wrote:
> On Jan 29, 2:07 pm, Mike Treseler <mtrese...@gmail.com> wrote:
>> This is also a quick way to add some visibility
>> for debugging a variable deep in the design.
>>
> 
> That's why I keep tellin' ya...use some concurrent assignments and
> signals for a change and cut back on those variables ;)

  Touch�.
  I should have said, "register" ;)

     -- Mike Treseler
        (still likes that "printf" debugging)
0
Reply Mike 1/30/2010 5:43:09 AM

Kevin and Andy are correct, of course, but there is a much simpler way
to write a testbench. I don't know anything about your design but
let's assume, for the sake of argument, that:

1 - PRESET_N is an active-low reset
2 - PWM is the output waveform
3 - PWM is split into 8 slots
4 - DUTY_CYC is the count of 0 slots
5 - (8-DUTY_CYCLE) is the count of high slots

In this case, the Maia code below tests your design. It applies all 3
combinations of DUTY_CYCLE to your DUT, and then checks the low and
high periods. It runs for 72 cycles and reports any failures in your
code.

disclaimer #1: I work for Maia EDA. You can currently get a free
compiler at www.maia-eda.net; it creates a testbench, and you'll need
a simulator to run the testbench.

disclaimer #2: The current version produces only Verilog output.
You'll need a dual-language simulator if your DUT is in VHDL (the
compiler driver automates all of this).

-Evan

// -------------------------------------
// Maia testbench code:
DUT {
   module FSM_CorePWM(
      input PCLK, PRESET_N, PSEL, PENABLE, PWRITE,
      input [2:0] DUTY_CYC,
      output PWM, INT,
      output [7:0] PRDATA);
   [PRESET_N, PCLK, DUTY_CYC] -> [PWM];
   create_clock PCLK;
}

main() {
   int3 dcycle;
   int  i,j;

   for all dcycle {              // all 8 values: 0->7
      [0, .C, .X] -> [0];        // reset
      for(i=0; i<dcycle; i++)
         [1, .C, dcycle] -> [0];
      for(j=0; j<8-dcycle; j++)
         [1, .C, dcycle] -> [1];
   }
}

0
Reply Evan 2/1/2010 11:14:45 AM

Does it really make a difference whether the assertion (or any other
kind of verification code) is located in the design module or in the
testbench? Is it any less likely to be correct because you put it in a
place where synthesis could take advantage of it? And if it is
incorrect, but synthesis could not take advantage of it, does not the
same assertion still have to be fixed?

Perhaps we simply give the synthesis tool the ability to do the
following:

By writing "assert one_hot(inputs);"

We are saying that any f(inputs) is "don't care" iff one_hot(inputs)
is false?

Conditions could also be put on/around the assertion or its expression
to limit the scope to e.g. rising edges of the clock, when not in
reset, etc., either by including those conditions in the assertion
expression, or by the location and therefore conditional execution of
the assertion statement itself.

I see your point WRT design behavior in off-nominal cases, but that is
just as big an issue everytime we enable synthesis optimizations for
one-hot state machines, etc.

Andy
0
Reply Andy 2/1/2010 5:56:26 PM

On Feb 1, 12:56=A0pm, Andy <jonesa...@comcast.net> wrote:
> Does it really make a difference whether the assertion (or any other
> kind of verification code) is located in the design module or in the
> testbench?

See my post from Jan 28 in this thread for an advantage that one may
gain by putting the verification in the design rather than the
testbench.

> Is it any less likely to be correct because you put it in a
> place where synthesis could take advantage of it?

Nope, nor did I suggest that it would.

> And if it is
> incorrect, but synthesis could not take advantage of it, does not the
> same assertion still have to be fixed?

Only if the incorrect assertion can be found, can it be fixed.

A simulation that runs to completion without failing an assert, no
matter how well thought out, does not imply that all of those
assertions are actually correct and match the logic under every
condition.  To prove that they do match, one would have to use a
formal logic checker of some sort, not a simulator.

But none of that has to do with the point that I was making.  My point
was along the lines of which path should be followed by a synthesis
tool if it used non-static assertions to guide how it formed the logic
and there was a logical difference between what was asserted and what
the written code actually said.

Kevin Jennings
0
Reply KJ 2/2/2010 4:53:44 AM

On Feb 1, 10:53=A0pm, KJ <kkjenni...@sbcglobal.net> wrote:
> But none of that has to do with the point that I was making. =A0My point
> was along the lines of which path should be followed by a synthesis
> tool if it used non-static assertions to guide how it formed the logic
> and there was a logical difference between what was asserted and what
> the written code actually said.

Sorry, I misinterpreted your point.

But since you clarified it...

I think the (synthesis-aware) assertions would have to be implemented
like a subsequent conditional assignment of "don't care", and that way
their interference with the otherwise coded logic is controlled and
(somewhat) predictable.

Not all assertions are explicitly coded; some are built-in.

For example, if I have a decoder as follows:

variable address : natural range 0 to 15;
variable decode : std_logic_vector(7 downto 0);
....
decode :=3D (others =3D> '0');
decode(address) :=3D '1';

What should the synthesis tool do if address is outside of
decode'range?

1. Should (or can) decode remain (others =3D> '0')?

2. Should (or can) decode be (address mod 8 =3D> '1', others =3D> '0')?

3. Should (or can) decode be (others =3D> '-')?

My opinion is that any of these options (and probably others) is
perfectly acceptable, but the #3 is a more accurate option, which
would be typically optimized to #2.

Is this example any different than manually adding an assertion that
address is between 0 and 7 inclusive? And would not the #3 option be
the same as a subsequent conditional assignment to (others =3D> '-')?

By using the assertion, you are not telling the synthesis tool that
the implementation has to do something else, you are merely giving it
permission to do something else, especially if it is more efficient.

The same thing happens when an integer counter under/over-flows in
synthesis. The implementation will simply roll over, probably because
that is the most efficient thing to do.

Andy
0
Reply Andy 2/2/2010 4:29:37 PM

Andy wrote:

> Not all assertions are explicitly coded; some are built-in.
> For example, if I have a decoder as follows:
> variable address : natural range 0 to 15;
> variable decode : std_logic_vector(7 downto 0);
> ...
> decode := (others => '0');  
> decode(address) := '1';     
> 
> What should the synthesis tool do if address is outside of
> decode'range?

I guess I like the vhdl rules as is.

I will assume this 'decode' is a vector:
  decode := (others => '0');

And this 'decode' is an f(vector) returns std_ulogic:
  decode(address) := '1';

If the decode vector is constrained,
I would expect a synthesis error.
If the decode vector is not constrained,
I am not following my design rules.


    -- Mike Treseler
0
Reply Mike 2/2/2010 5:51:33 PM

Per the stated variable declarations, decode is slv, decode(address)
is address'th bit of the decode vector.

The index of decode is constrained by the variable definition, (7
downto 0), and it will not give you an error in simulation until and
unless decode is indexed beyond its range. Therefore the behavior of
decode in that case is undefined by the language. What behavior should
the synthesis tool implement? The synthesis tool cannot perform run-
time bounds checking, and it cannot assume that just because address
CAN exceed the index range of decode, that it WILL exceed the range.

For example, if I have the following assignment to a natural variable
count:

count := count - 1;

The synthesis tool cannot (and does not!) assume that count - 1 might
be less than zero and therefore stop with an error. The only "safe"
assumption for the synthesis tool is that because you wrote the
description, you don't care about the behavior under situations in
which it will not simulate.

Note the original behavior of decode(address) := '1' is quite differen
from the following:

for i in decode'range loop
  if address = i then
    decode(i) := '1';
  end if;
end loop;

In this case, the MSB of address must be '0' for the index comparison
to be true, and therefore the implementation will do likewise, with
the end result that decode remains (others => '0') when address is
outside of 7 downto 0.

Andy
0
Reply Andy 2/2/2010 6:43:15 PM

Andy wrote:

> Per the stated variable declarations, decode is slv, decode(address)
> is address'th bit of the decode vector.

Sorry I missed that.

> For example, if I have the following assignment to a natural variable
> count:
> count := count - 1;
> The synthesis tool cannot (and does not!) assume that count - 1 might
> be less than zero and therefore stop with an error.

I hear what you're saying.
I guess I would be inclined to constrain the count range
to what is needed for the math,
even if that were integer range -1 to +255.
Synthesis won't generate a carry register if I convert
to natural range or unsigned at the output port assignment.

      -- Mike Treseler

0
Reply Mike 2/2/2010 8:25:23 PM

Mike,

That's exactly what the synthesizer does for both the counter and the
decoder: the most efficient mechanism to create the 3 bit decoder or
the 8 bit counter is to simply truncate the bits. Neither is
prescribed by the LRM, but that is the accepted synthesis practice,
since the LRM behavior from a hardware point of view is undefined
under the circumstances.

All I'm suggesting is that we could manually create other situations
where the LRM behavior, from a hardware point of view, is undefined,
by using assertion statements to say "This cannot happen, so you can
do whatever you want here."

Andy
0
Reply Andy 2/2/2010 9:36:05 PM

On Feb 2, 4:36=A0pm, Andy <jonesa...@comcast.net> wrote:
> Mike,
>
> That's exactly what the synthesizer does for both the counter and the
> decoder: the most efficient mechanism to create the 3 bit decoder or
> the 8 bit counter is to simply truncate the bits. Neither is
> prescribed by the LRM, but that is the accepted synthesis practice,
> since the LRM behavior from a hardware point of view is undefined
> under the circumstances.
>
> All I'm suggesting is that we could manually create other situations
> where the LRM behavior, from a hardware point of view, is undefined,
> by using assertion statements to say "This cannot happen, so you can
> do whatever you want here."
>

That may be such situations...but so far the examples you suggest
clearly do not demonstrate that point (1), (2).

Of course, one can never prove there is no such situation where
synthesis might actually be helped in some fashion by looking at
assertions, but until one can actually demonstrate the existance of
any such situation and it's practical usefulness, it's probably hard
to generate much momentum to get such a change into any tool.  Maybe
they could use them to essentially do some formal logic checking under
the hood as an added bonus, but that's not synthesis.

KJ

--------
(1) The example of assertion of a mutex "Assert std_mutex(read_enable
& write_enable));" is already correctly handled.  The if/elsif...endif
statement for things that are mutually exclusive does not result in
priority encoding.  If the logic that is coded does not actually
support the assertion, we have the situation where the assertion is
incorrect or the design has a problem.  Which path is actually wrong
cannot be discerned by the synthesis tool, so choosing what is
specified by the logic (as they all do today) is just as appropriate
as choosing any other path.

(2) For the example of "decode(address) where address is outside of
decode'range" you already pointed out that the synthesis tool is
already doing the proper thing today anyway.  The reason it does this
is not because of any grand intelligence, but simply because after
implementing the specified logic it noted that the high order bit of
address had no logic that ever used that bit so it was
discarded...most likely with a warning to the user to that effect to
boot.
0
Reply KJ 2/6/2010 2:32:18 AM

On Feb 5, 8:32=A0pm, KJ <kkjenni...@sbcglobal.net> wrote:
>
> That may be such situations...but so far the examples you suggest
> clearly do not demonstrate that point (1), (2).
>
> Of course, one can never prove there is no such situation where
> synthesis might actually be helped in some fashion by looking at
> assertions, but until one can actually demonstrate the existance of
> any such situation and it's practical usefulness, it's probably hard
> to generate much momentum to get such a change into any tool. =A0Maybe
> they could use them to essentially do some formal logic checking under
> the hood as an added bonus, but that's not synthesis.
>
> KJ
>
> --------
> (1) The example of assertion of a mutex "Assert std_mutex(read_enable
> & write_enable));" is already correctly handled. =A0The if/elsif...endif
> statement for things that are mutually exclusive does not result in
> priority encoding. =A0If the logic that is coded does not actually
> support the assertion, we have the situation where the assertion is
> incorrect or the design has a problem. =A0Which path is actually wrong
> cannot be discerned by the synthesis tool, so choosing what is
> specified by the logic (as they all do today) is just as appropriate
> as choosing any other path.
>

There are many cases where external inputs are known by the user
(specified) to be mutually exclusive, but it is not known or provable
by/to the synthesis tool. For instance, if I have an external
interface or black-box IP that generates a set of input bits for me
which are specified as mutually exclusive, there is no way to let the
synthesis tool know that those bits are mutually exclusive and can be
treated as such, unless I explicitly code the logic as such.

As has previously been discussed in other threads on this subject, one
can manually code the and-or logic of a non-priority encoder/mux, or
one can implement tri-state bus logic that will be implemented as a
non-priority encoder/mux, but there are not any "behavioral" ways to
make that happen.

I still don't see where there can be a difference between the logic
"from the code" and the logic "from the assertion". The assertion is
part of the code, and the code, as a whole, has a function, and that
function is what should be implemented.

> (2) For the example of "decode(address) where address is outside of
> decode'range" you already pointed out that the synthesis tool is
> already doing the proper thing today anyway.  The reason it does this
> is not because of any grand intelligence, but simply because after
> implementing the specified logic it noted that the high order bit of
> address had no logic that ever used that bit so it was
> discarded...most likely with a warning to the user to that effect to
> boot.

Actually, given the example I used:

decode :=3D (others =3D> '0');
decode(address) :=3D '1';

One could just as logically assume that an address that is outside of
decode'range would not result in any decode bits being set, because
the entire address, as specified in the code, does not match the index
of any bit that can be set. In other words, the synthesis tool would
implement a 4 to 16 decoder, then optimize away the upper 8 outputs.
That would NOT optimize away the 4th address bit.

Exactly where/how are you inferring from this example that the MSB is
not needed and can be discarded? What exactly is "the specified
logic"?

Note the example could be (but was not!) written in a different manner
to explicitly exclude the address MSB:

decode(address mod decode'length) :=3D '1';

And it could be re-written as previously shown with a loop that
compares the address to each legal index, which explicitly includes
the MSB.

The only way a synthesis tool could conclude that the MSB is not
needed in the original example is because if the MSB were set, it
would be non-functional VHDL. Therefore, it could assume the MSB must
be zero, and with that assumption, the MSB is not needed.

Andy

0
Reply Andy 2/8/2010 4:25:30 PM

>
> There are many cases where external inputs are known by the user
> (specified) to be mutually exclusive, but it is not known or provable
> by/to the synthesis tool.

I don't think they're that numerous, but your mileage may vary from
mine.  In any case, from a design perspective, it is dicey to to rely
on promises that can be broken...that's my view.

> For instance, if I have an external
> interface or black-box IP that generates a set of input bits for me
> which are specified as mutually exclusive, there is no way to let the
> synthesis tool know that those bits are mutually exclusive and can be
> treated as such, unless I explicitly code the logic as such.
>

The code that generates the signals must code them correctly...not the
code that uses it.  If it turns out that the generating code does
generate mutually exclusive logic, then the code that uses it will
take advantage of it because the logic will not overlap (per Boolean
logic 101, nothing more).

>
> I still don't see where there can be a difference between the logic
> "from the code" and the logic "from the assertion". The assertion is
> part of the code, and the code, as a whole, has a function, and that
> function is what should be implemented.
>

We'll have to disagree on that then

> > (2) For the example of "decode(address) where address is outside of
> > decode'range" you already pointed out that the synthesis tool is
> > already doing the proper thing today anyway. =A0The reason it does this
> > is not because of any grand intelligence, but simply because after
> > implementing the specified logic it noted that the high order bit of
> > address had no logic that ever used that bit so it was
> > discarded...most likely with a warning to the user to that effect to
> > boot.
>
> Actually, given the example I used:
>
> decode :=3D (others =3D> '0');
> decode(address) :=3D '1';
>
> One could just as logically assume that an address that is outside of
> decode'range would not result in any decode bits being set, because
> the entire address, as specified in the code, does not match the index
> of any bit that can be set. In other words, the synthesis tool would
> implement a 4 to 16 decoder, then optimize away the upper 8 outputs.
> That would NOT optimize away the 4th address bit.
>
> Exactly where/how are you inferring from this example that the MSB is
> not needed and can be discarded? What exactly is "the specified
> logic"?
>

Decode is specified as 8 bits ranging from 0 to 7 for addressing.
Only three bits are needed (bits 2 thru 0).  The generated logic for
address 3 will not be needed since it won't hook up to anything.
Don't believe me?  Believe Quartus then (1).


>
> The only way a synthesis tool could conclude that the MSB is not
> needed in the original example is because if the MSB were set, it
> would be non-functional VHDL. Therefore, it could assume the MSB must
> be zero, and with that assumption, the MSB is not needed.
>

Nope, it rightly noted that bit 3 of address was not needed.

KJ

(1)  The code below produces the following warning...

Warning: Design contains 1 input pin(s) that do not drive logic
	Warning (15610): No output dependent on input pin "address[3]"

entity foo is port(
  address: in natural range 0 to 15;
  decode:  out std_logic_vector(7 downto 0));
end foo;

architecture rtl of foo is
begin
process(address)
begin
  decode <=3D (others =3D> '0');
  decode(address) <=3D '1';
end process;
end rtl;
0
Reply KJ 2/10/2010 1:09:23 PM

25 Replies
1218 Views

(page loaded in 0.388 seconds)

Similiar Articles:


















7/20/2012 5:50:01 AM


Reply: