How to write testbench file?

R

RaulGonz

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.
 
A

Andy

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
 
R

RaulGonz

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.
 
R

RaulGonz

Sorry, i mean how can i ADD this fsm_pwmcore to the two
components in testbench format?? Please advise. Thank you.
 
A

Andy

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
 
R

RaulGonz

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..
 
K

KJ

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
 
R

RaulGonz

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?
 
M

Mike Treseler

KJ said:
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
 
A

Andy

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
 
M

Mike Treseler

Andy said:
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
 
K

KJ

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
 
K

KJ

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
 
M

Mike Treseler

KJ said:
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)
 
E

Evan Lavelle

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];
}
}
 
A

Andy

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
 
K

KJ

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
 
A

Andy

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.

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 := (others => '0');
decode(address) := '1';

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

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

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

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

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 => '-')?

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
 
M

Mike Treseler

Andy said:
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
 

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,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top