Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Macro/Function in VHDL testbench ?

1,542 views
Skip to first unread message

ted...@zapta.com

unread,
Jul 4, 2002, 8:24:05 PM7/4/02
to
Hello,

My VHDL test bench looks like:

...

DATA <= "0000001";
wait 1us;
CLK <= '1';
wait 1us;
CLK <= '0';
wait 1us;

'''

Is there a way to write a macro or function such that the above code
can be invoked with something like:

CYCLE("00000001");
CYCLE("00000001");

I am new to VHDL so please be specific in your answer (e.g., where the
macro/function should be defined, its syntax, etc).

Thanks for your help,

Tal

Vhdlcohen2

unread,
Jul 4, 2002, 11:57:49 PM7/4/02
to

This is an excellent example on how NOT to write a testbench:
1. Clock is intemixed with data, and may appear at same delta time as data,
with no setup time. Data is not triggered from clock edge.
2. Code is hard to read and debug.

A. Try using a separate clock, and have your data trigger as a result of the
clock edge.
B. Use transaction based modeling, as demonstrated in my latest books (see my
site)
C. Consider automatic verification with special models.
Ben
----------------------------------------------------------------------------
Ben Cohen Publisher, Trainer, Consultant (310) 721-4830
http://www.vhdlcohen.com/ vhdl...@aol.com
Author of following textbooks:
* Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn
0-9705394-2-8
* Component Design by Example ", 2001 isbn 0-9705394-0-1
* VHDL Coding Styles and Methodologies, 2nd Edition, 1999 isbn 0-7923-8474-1
* VHDL Answers to Frequently Asked Questions, 2nd Edition, isbn 0-7923-8115
------------------------------------------------------------------------------

ted...@zapta.com

unread,
Jul 5, 2002, 2:18:25 AM7/5/02
to
Ben, your answer is way above my head ;-)

Can you refer me to an example for the 'right' way to do that ?

I am sure this is a pretty generic scenario.

Thanks,

Tal

Francisco Camarero

unread,
Jul 5, 2002, 4:11:24 AM7/5/02
to


Although I agree with Cohen, I understand that newcomers need to start
with easier structures: Example:

process
procedure ClkIn(constant x : std_logic) is
begin
DataInxD <= x ;
wait for 50 ns;
ClkxC <= '1';
wait for 45 ns;
ClkxC <= '0';
wait for 5 ns;
end procedure;
begin
wait for 50 ns;
ResetxRB <= '1';
ClkIn('0');
ClkIn('0');
ClkIn('0');
ClkIn('1');
ClkIn('0');
ClkIn('0');
ClkIn('0');
ClkIn('0');
ClkIn('0');
ClkIn('0');
wait; -- for ever
end process;


--
Francisco Camarero
Technologynos...@gmx.ch

Ralf Hildebrandt

unread,
Jul 5, 2002, 3:27:18 AM7/5/02
to
Hi ..uuhmm "ted...@zapta.com"


> Ben, your answer is way above my head ;-)

I will try to explain it my way ...

> >> DATA <= "0000001";
> >> wait 1us;
> >> CLK <= '1';
> >> wait 1us;
> >> CLK <= '0';
> >> wait 1us;

> >1. Clock is intemixed with data, and may appear at same delta time as data,
> >with no setup time. Data is not triggered from clock edge.

CLK and DATA are mixed together. CLK does not really "clock", but
changes it's value 2 times.


> >2. Code is hard to read and debug.

If you delete a line (because of some different tests) and this is a
wait-statement - your CLK will be "damaged".
The code is hard to read.

> >A. Try using a separate clock, and have your data trigger as a result of the
> >clock edge.

Just write an extra clock generator. Write a procedure that produces a
CLK-signal that runs infinite.

If you have a free running clock, you can trigger the data with "if
rising_edge(CLK)". Just use counters to detect a specific clock-edge.


Ralf

Stefan Doll

unread,
Jul 5, 2002, 5:04:58 AM7/5/02
to
Hi Tal,

> Can you refer me to an example for the 'right' way to do that ?

I'll just use this as an opportunity to push my website. ;-)

Go here:
http://www.stefanVHDL.com

then click on "Generating Clock and Reset Stimulus" for an example.

Cheers

Stefan


--
Stefan Doll, München, Germany
http://www.stefanVHDL.com

ted...@zapta.com

unread,
Jul 5, 2002, 11:59:00 AM7/5/02
to
Thanks, this is exactly what I looked for!

Now I need to do some learning to figure out why it is so bad ;-)

Tal

ted...@zapta.com

unread,
Jul 5, 2002, 12:19:03 PM7/5/02
to

Thanks. Very informative site.

Tal

VhdlCohen

unread,
Jul 7, 2002, 11:20:43 PM7/7/02
to
>Now I need to do some learning to figure out why it is so bad ;-)
>
>Tal
The whole concept of transaction based TB modeling is to first define the
transactions to be asserted onto the BFMs, as per the verification plan (See my
book Component Design by Example). Examples of transactions would be things
like WRITE, READ, DMA, INTERRUPT, IO_SETUP, etc. The implementation of those
transactions can be in procedures or in a component model (Which I call
server). Below is an example of a simple WRITE transaction implemented as a
procedure, and a call to a sequence of transactions (implemented in the
process, but could also be implemented in a component called client).
This creates code that is more maintainable. There is more to the whole story
than what is mentioned here (see my references at my site).

library ieee;
use ieee.std_logic_1164.all;
entity TBe is
port (
A : out std_logic_vector(7 downto 0);
enb : out std_logic;
clk : inout std_logic := '1'); -- Need to read back
end entity TBe;

architecture Beh of TBe is
-- transactions
-- WRITE
-- purpose: Defines the write transaction to xmt data
procedure WRITE (
constant delay : in time; -- 1st delay
constant data : in std_logic_vector; -- data to send
signal enb : out std_logic; -- enable
signal clk : in std_logic; -- clock
signal DataBus : out std_logic_vector -- data bus
) is
variable data_v :
std_logic_vector(data'length -1 downto 0) := data;
variable DataBus_v :
std_logic_vector(DataBus'length-1 downto 0);

begin -- procedure WRITE
if data'length /= DataBus'length then
report "error in bus and data widths" severity error;
else
wait until clk = '1';
DataBus_v := data_v;
DataBus <= DataBus_v after delay;
enb <= '1' after delay;
wait until clk = '1';
DataBus_v := (others => 'Z');
DataBus <= DataBus_v after delay;
enb <= '0'after delay;
end if;
end procedure WRITE;

begin -- architecture Beh
clk <= not clk after 50 ns;

Activation_Transactions : process is
begin -- process Activation_Transactions
-- wait for 10 cycles
for I in 1 to 10 loop
wait until clk = '1';
end loop; -- I
-- Do a write data = "11110000"
WRITE (
delay => 10 ns, --
data => "11110000", -- data to send
enb => enb,
clk => clk,
DataBus => A);

-- DO READ transaction
-- Procedure not implementated yet
-- READ (
-- delay => 10 ns, --
-- enb => enb,
-- clk => clk,
-- DataBus => A);

-- DO another WRITE

WRITE (
delay => 10 ns, --
data => "00000000", -- data to send
enb => enb,
clk => clk,
DataBus => A);


end process Activation_Transactions;
end architecture Beh;

TED

unread,
Jul 8, 2002, 11:18:11 AM7/8/02
to
Hi Ben,

Thanks for the example and the pointers. If I understand your point,
you assume that the simulated system has several concurant activities
that interact with each other (e.g. a CPU interacting with memory). In
this case, having a non linear concurrent modeling seems like the
natural way to go.

However, in our case, things are much simpler. The unit under test
receives external commands in the form of op code and clock and
changes it state accordingly. Its state is exposed externally via
output pins (many of them) but it has no input pins except for the
command/clock signals mentioned above. Further more, the unit does not
have any 'life' of itself nor it uses any free running clock or other
internal timing mechanism and all it does is changing it state on each
command/clock signal.

In this case, I don't see the need for writing concurrent testing
model and the sequential stream of commands seems to fulfill our need.
Given that, using a single cmd(opcode) procedure greatly simplified
our code.

Am I missing something ?

Tal

0 new messages