Changing the value of a generic during simulation time

B

Bert Böhne

Hi,

I have a component with a 64-bit bus interface. Through a generic it
can be chosen if this bus is used with the full 64 bit depth or 32 bit
depth. When 32 bit depth is chosen, the other remaining 32 bits are
constant driven low so synthesis will optimize them away.
In my testbench I want to simulate both bit depths. Is it possible to
drive the values of the generic from my stimuli file? So, that I won't
have to recompile?

Thx,

Bird
 
P

Paul Uiterlinden

Alan said:
You can add a generic to your testbench to set the generic in the
component.

Then launch your simulator and set the generic from the simulator (e.g.
-g in Modelsim/Aldec).

You can declare a constant in your testbench and initialize it to a
value in a file, e.g.

constant width : positive := fnreadval("mystimfile");

where fnreadval is an impure function which loads the constant from the
file.

This will be called during elaboration, so in theory it is even safe to
put the value in your stimulus file (i.e. read the first line of the
stimulus file to set the constant, then read the rest of the file during
runtime). Possibly that's not a good idea (sharing a file) though it
should work.

You can use proprietary tool features - for instance Modelsim has a tcl
command "change" which allows you to modify the value of constants, as
long as they have the correct access specified.

Using proprietary tool features (such as the -g option or the Tcl "change"
command) of course have the disadvantage of being, well, uhm, proprietary.

Besides that, you need more or less fancy scripts to set the options or
execute the commands. These all need maintenance and proper storage in some
repository.

All this means that changing simulator will mean changing all these scripts.

I prefer doing these things in VHDL. That way you are as independent from
the tools as possible.

Setting a generic in VHDL is only possible when instantiating something. So
a toplevel generic can only be set in a tool dependent way.

From that the only conclusion is that the testbench needs to be
instantiated, if you want to set testbench generics in VHDL, and not via
some tool dependent way.

The method that I have developed is to instantiate the testbench in one or
more testcases. So there is one generic (pun intended?) testbench, and a
bunch of dedicated testcases, each targeted on verifying certain (sets of)
requirements.

Communication with the testbench does not go through a port map of the
testbench. That would be too difficult to maintain. Instead, a testbench
package contains signal declarations, which are made visible both in the
testbench and testcase. Hence, the testbench doe not have any ports, only
generics.

The generic(s) of the testbench could be set in the instantiation of the
testbench in the testcase. However, it can also be postponed one level
higher to the configuration of the testcase. That way you can even have
multiple configurations of one testcase, setting different values for
testbench generics. This saves copying the whole testcase just for another
generic value of the testbench. Remember: copy-n-paste is evil!

So, putting all this together results in something like this (a simplified
expample):


ENTITY dut IS
GENERIC
(
bus_width : positive
);
PORT
(
i : IN bit
);
END ENTITY dut;


ARCHITECTURE str OF dut IS
BEGIN
p: PROCESS (i) IS
BEGIN
REPORT "i=" & bit'IMAGE(i);
REPORT "bus_width=" & positive'IMAGE(bus_width);
END PROCESS p;
END ARCHITECTURE str;


PACKAGE dut_pkg IS
COMPONENT dut IS
GENERIC
(
bus_width : positive
);
PORT
(
i : IN bit
);
END COMPONENT dut;
END PACKAGE dut_pkg;


PACKAGE tb_pkg IS
SIGNAL b : bit;

COMPONENT tb IS
END COMPONENT tb;
END PACKAGE tb_pkg;


ENTITY tb IS
GENERIC
(
bus_width : positive
);
END ENTITY tb;


USE work.tb_pkg.ALL;
USE work.dut_pkg.ALL;

ARCHITECTURE behav OF tb IS
BEGIN
dut_i: dut
GENERIC MAP
(
bus_width => bus_width
)
PORT MAP
(
i => b
);
END ARCHITECTURE behav;


CONFIGURATION tb_cfg OF tb IS
FOR behav
FOR dut_i: dut
USE ENTITY work.dut(str);
END FOR;
END FOR;
END CONFIGURATION tb_cfg;


ENTITY tc IS
END ENTITY tc;


USE work.tb_pkg.ALL;

ARCHITECTURE test1 OF tc IS
BEGIN
tb_i: tb;

do_sim: PROCESS IS
BEGIN
b <= '0';
WAIT FOR 1 ns;
b <= '1';

WAIT;
END PROCESS do_sim;
END ARCHITECTURE test1;


CONFIGURATION tc_test1_cfg_1 OF tc IS
FOR test1
FOR tb_i: tb
USE CONFIGURATION work.tb_cfg
GENERIC MAP
(
bus_width => 16
);
END FOR;
END FOR;
END CONFIGURATION tc_test1_cfg_1;


CONFIGURATION tc_test1_cfg_2 OF tc IS
FOR test1
FOR tb_i: tb
USE CONFIGURATION work.tb_cfg
GENERIC MAP
(
bus_width => 32
);
END FOR;
END FOR;
END CONFIGURATION tc_test1_cfg_2;


Now you can run the two variants of the testcase test1, just by loading the
appropriate configuration. For ModelSim or Aldec, running the two testcases
is done by:

vsim -quiet -c -do 'run -a; quit' tc_test1_cfg_1
vsim -quiet -c -do 'run -a; quit' tc_test1_cfg_2

Usually, the testbench contains instantiation of all kinds of models
(transactors, bus functional models) needed for the functional verification
of the dut. These models are controlled from the testcases (through the
signals from tb_pkg).

No script needed, save one generic run script, which only gets the name of
the toplevel configuration.
 

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,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top