testbench procedure trouble

T

Toby

Hi, I'm kinda new to this whole testbench thing. I have a procedure in
my testbench that looks something like this:

procedure SMP_READ
(
signal A_P_SMP_DATA_READ: out std_logic_vector(7 downto 0);
) is
begin

A_P_SMP_DATA_READ(7) <= A_SMP_DATA7;
A_P_SMP_DATA_READ(6) <= A_SMP_DATA6;
A_P_SMP_DATA_READ(5) <= A_SMP_DATA5;
A_P_SMP_DATA_READ(4) <= A_SMP_DATA4;
A_P_SMP_DATA_READ(3) <= A_SMP_DATA3;
A_P_SMP_DATA_READ(2) <= A_SMP_DATA2;
A_P_SMP_DATA_READ(1) <= A_SMP_DATA1;
A_P_SMP_DATA_READ(0) <= A_SMP_DATA0;

end SMP_READ;

Where A_SMP_DATA7, A_SMP_DATA6......A_SMP_DATA0 are signals assigned
for the entire testbench (between the component declarations and the
procedure declarations) as follows:

signal A_SMP_DATA0 : STD_LOGIC := 'L';
signal A_SMP_DATA1 : STD_LOGIC := 'L';
signal A_SMP_DATA2 : STD_LOGIC := 'L';
signal A_SMP_DATA3 : STD_LOGIC := 'L';
signal A_SMP_DATA4 : STD_LOGIC := 'L';
signal A_SMP_DATA5 : STD_LOGIC := 'L';
signal A_SMP_DATA6 : STD_LOGIC := 'L';
signal A_SMP_DATA7 : STD_LOGIC := 'L';

The problem is, A_P_SMP_DATA_READ(7..0) is not getting the values
assigned to it in the procedure. I can set a breakpoint (Aldec
Active-HDL) near the end of the procedure, and I run the cursor over
the A_P_SMP_DATA_READ(#) and the A_SMP_DATA#, and they just arent
equal. How can that even be? If I say A_P_SMP_DATA_READ(7) <=
A_SMP_DATA7; then shouldn't those two things be equal? Any ideas
would be greatly appreciated.
 
M

Mike Treseler

Toby said:
Hi, I'm kinda new to this whole testbench thing. I have a procedure in .. . .
The problem is, A_P_SMP_DATA_READ(7..0) is not getting the values
assigned to it in the procedure.

consider adding a synchronous wait to your procedure:

procedure tic is
begin
wait until rising_edge(tb_clk_s);
end procedure tic;

procedure SMP_READ is
begin
A_P_SMP_DATA_READ(7) <= A_SMP_DATA7;
A_P_SMP_DATA_READ(6) <= A_SMP_DATA6;
A_P_SMP_DATA_READ(5) <= A_SMP_DATA5;
A_P_SMP_DATA_READ(4) <= A_SMP_DATA4;
A_P_SMP_DATA_READ(3) <= A_SMP_DATA3;
A_P_SMP_DATA_READ(2) <= A_SMP_DATA2;
A_P_SMP_DATA_READ(1) <= A_SMP_DATA1;
A_P_SMP_DATA_READ(0) <= A_SMP_DATA0;
tic; -- wait after assignments to see changes
end SMP_READ;

-- Mike Treseler
 
T

Toby

I tried to add the tic thing, but it didnt seem to help. The procedure
posted earlier was simplified a bit. Here is the complete procedure
(including the tic call):

procedure SMP_READ
-- Timing taken from 'C50 datasheet
(constant A_SPACE: in character;
constant A_P_SMP_ADDR_TEMP: in std_logic_vector(2 downto 0);
signal A_TURBO: in std_logic;
signal A_SMP_RD_L, A_SMP_IS_L, A_SMP_DS_L, A_SMP_PS_L: out std_logic;
signal A_P_SMP_DATA_READ: out std_logic_vector(15 downto 0);
signal A_P_SMP_ADDR: out std_logic_vector(2 downto 0);
signal A_UPCLKOUT: in std_logic
) is
begin
A_P_SMP_ADDR <= A_P_SMP_ADDR_TEMP;
if(A_SPACE = 'I') then
A_SMP_IS_L <= '0';
elsif(A_SPACE = 'D') then
A_SMP_DS_L <= '0';
elsif(A_SPACE = 'P') then
A_SMP_PS_L <= '0';
end if;
-- tsu(AV-RDL)
if(A_TURBO = '0') then --turbo mode
wait for 10 ns;
else --slow mode
wait for 20 ns;
end if;
A_SMP_RD_L <= '0';
-- tw(RDL)
if(A_TURBO = '0') then --turbo mode
wait for 58 ns;
else --slow mode
wait for 88 ns;
end if;
A_P_SMP_DATA_READ(15) <= A_SMP_DATA15;
A_P_SMP_DATA_READ(14) <= A_SMP_DATA14;
A_P_SMP_DATA_READ(13) <= A_SMP_DATA13;
A_P_SMP_DATA_READ(12) <= A_SMP_DATA12;
A_P_SMP_DATA_READ(11) <= A_SMP_DATA11;
A_P_SMP_DATA_READ(10) <= A_SMP_DATA10;
A_P_SMP_DATA_READ(9) <= A_SMP_DATA9;
A_P_SMP_DATA_READ(8) <= A_SMP_DATA8;
A_P_SMP_DATA_READ(7) <= A_SMP_DATA7;
A_P_SMP_DATA_READ(6) <= A_SMP_DATA6;
A_P_SMP_DATA_READ(5) <= A_SMP_DATA5;
A_P_SMP_DATA_READ(4) <= A_SMP_DATA4;
A_P_SMP_DATA_READ(3) <= A_SMP_DATA3;
A_P_SMP_DATA_READ(2) <= A_SMP_DATA2;
A_P_SMP_DATA_READ(1) <= A_SMP_DATA1;
A_P_SMP_DATA_READ(0) <= A_SMP_DATA0;
--tw(RDL) continued
wait for 1 ns;
A_SMP_RD_L <= 'H';
if(A_SPACE = 'I') then
A_SMP_IS_L <= 'H';
elsif(A_SPACE = 'D') then
A_SMP_DS_L <= 'H';
elsif(A_SPACE = 'P') then
A_SMP_PS_L <= 'H';
end if;
A_P_SMP_ADDR <= "LLL";

tic(A_UPCLKOUT);

end SMP_READ;


As you can see, there are lots of IF and WAIT statements in there too.
I'm wondering if there is some rule or something I have broken about
using WAIT and IF statements? Is that procedure even normal looking,
or is there a better way of doing what I am trying to do? (I am trying
to have a procedure that simulates all the signals and associated
timing from a microprocessor read cycle). Thank you thank you to
anyone who has any suggestions!
 
M

Mike Treseler

Toby said:
I tried to add the tic thing, but it didnt seem to help. The procedure
posted earlier was simplified a bit. Here is the complete procedure
(including the tic call):

Yikes. Consider a synchronous testbench
using tic;tic;tic; instead of wait for 30ns;

Do you have a clock and reset process working
out through to the uut in and out signals?
Get this working first.

Do you have some base process wrapped around
the procedure declarations run the show?


-- Mike Treseler

___________________
main : process is
<declarations>
constant reps : natural := 16;
begin -- process main
init;
for i in 1 to reps loop
timed_cycle;
end loop;
for i in 1 to reps loop
handshake_cycle;
end loop;
coda;
end process main;
end architecture sim;
 
T

Toby

Hi Mike,

a synchronous testbench using tic; tic; tic, huh? Holy crap! I never
thought of that! Thank you. I do quite a bit of VHDL, and I
definitely understand the importance of synchronizing stuff, I just
never thought to do it in a testbench. Is there anything wrong with
doing tic = 1ps, and doing for loops like a thousand times? Because I
have some stuff that has to be fractions of a nanosecond, and some
stuff the is tens or hundreds of nanoseconds. And I want everything in
my testbench to use the same tic process, right? Tic should be a
process, not a procedure, right?

I do have a clock and reset working throughout the uut.

I dont understand your last comment about having a process wrapped
around the procedure declarations. A procedure can go in a process? I
didnt know that. You dont mean I need a single process for the whole
testbench, do you? I've got a lot of stuff going on in this testbench,
and a lot of it can happen at the same time (i.e. completely seperate
logic in the uut). So I think I need seperate processes for that.
Well, as you can see, any general type of advice about testbenches
would be very helpful.

Anyway, thank you so much! I will work on using that tic clock.

-Toby
 
T

Toby

Hi Mike,

a synchronous testbench using tic; tic; tic, huh? Holy crap! I never
thought of that! Thank you. I do quite a bit of VHDL, and I
definitely understand the importance of synchronizing stuff, I just
never thought to do it in a testbench. Is there anything wrong with
doing tic = 1ps, and doing for loops like a thousand times? Because I
have some stuff that has to be fractions of a nanosecond, and some
stuff the is tens or hundreds of nanoseconds. And I want everything in
my testbench to use the same tic process, right? Tic should be a
process, not a procedure, right?

I do have a clock and reset working throughout the uut.

I dont understand your last comment about having a process wrapped
around the procedure declarations. A procedure can go in a process? I
didnt know that. You dont mean I need a single process for the whole
testbench, do you? I've got a lot of stuff going on in this testbench,
and a lot of it can happen at the same time (i.e. completely seperate
logic in the uut). So I think I need seperate processes for that.
Well, as you can see, any general type of advice about testbenches
would be very helpful.

Anyway, thank you so much! I will work on using that tic clock.

-Toby
 
M

Mike Treseler

Toby said:
a synchronous testbench using tic; tic; tic, huh? Holy crap! I never
thought of that! Thank you. I do quite a bit of VHDL, and I
definitely understand the importance of synchronizing stuff, I just
never thought to do it in a testbench. Is there anything wrong with
doing tic = 1ps, and doing for loops like a thousand times? Because I
have some stuff that has to be fractions of a nanosecond, and some
stuff the is tens or hundreds of nanoseconds. And I want everything in
my testbench to use the same tic process, right? Tic should be a
process, not a procedure, right?

No the other way around.

I use one clock/reset generator process (see tb_clk below)
and one main process. The main process is constructed
out of procedure calls. The lowest level procedure
(i.e. the top declaration) is tic, which waits for
one system clock period. The other procedures
call tic once, at the end, or not at all.
All of the procedure calls, other than tic;
execute in zero simulation time, so no, I don't
need a 1 ps clock period. The clock is strictly
for synchronization of uut stimulus and verification.
I do have a clock and reset working throughout the uut.

That's a good start.
I dont understand your last comment about having a process wrapped
around the procedure declarations. A procedure can go in a process?

The procedure *code* (declaration) for "do_this"
is placed before the BEGIN of the
main process *and* before any other.
procedures that call "do_this"

The procedure *call* "do_this;"
must be placed either in a
process or procedure after the BEGIN.
I didnt know that. You dont mean I need a single process for the whole
testbench, do you?

I use at least two, tb_clk and main. In my last posting
I showed the main process calls of a real testbench.
All of the details are in the procedures that I cut out
I've got a lot of stuff going on in this testbench,
and a lot of it can happen at the same time (i.e. completely seperate
logic in the uut). So I think I need seperate processes for that.

Yes sometimes you do.
Anyway, thank you so much! I will work on using that tic clock.

You are welcome. Good luck

-- Mike Treseler


--____________________________________________
tb_clk : process is
constant clk_cy : time := 10 ns;
constant rst_time : time := 100 ns;
begin
clk_s <= '0';
if now < rst_time then
rst_s <= '1'; -- rst once with clk running

else
rst_s <= '0'; -- then low forever
end if;
wait for clk_cy/2; -- clk rising
clk_s <= '1';
wait for clk_cy/2; -- clk falling
if done_s then
wait; -- Stop clock
end if;
end process tb_clk;
-------------------------------------------------------------------------------
 
P

Paul Uiterlinden

Mike said:
--____________________________________________
tb_clk : process is
constant clk_cy : time := 10 ns;
constant rst_time : time := 100 ns;
begin
clk_s <= '0';
if now < rst_time then
rst_s <= '1'; -- rst once with clk running
else
rst_s <= '0'; -- then low forever
end if;
wait for clk_cy/2; -- clk rising
clk_s <= '1';
wait for clk_cy/2; -- clk falling
if done_s then
wait; -- Stop clock
end if;
end process tb_clk;
-------------------------------------------------------------------------------

I would not combine the generation of the clock and reset:

CONSTANT clk_cy : delay_length := 10 ns;
CONSTANT rst_time : rst_time := 10*clk_cy;

SIGNAL clk_s : std_ulogic := '0';
SIGNAL rst_s : std_ulogic;
SIGNAL done_s : boolean;

clk_gen: clk_s <= '0' WHEN done_s ELSE NOT clk_s AFTER clk_cy/2;
rst_gen: rst_s <= '1', '0' AFTER rst_time;

Nice and short, just two lines. No needless evaluation of "now <
rst_time". Surely it would make not much of a difference in simulation
time, but I find my version better readable. Of course, this is a
personal thing.

The initial value of clk_s really is needed, or otherwise the clock
always would be 'X'. Also note that by chosing '0' as initial value (in
contrast to '1'), rst_s changes value at the falling edge of the clock
(as in your example).

Paul.
 
T

Toby

Can somebody either post, or tell me EXACTLY where to find a nice, BIG,
COMPLETE, good, testbench example with all this stuff you guys are
talking about? Several examples would be even better, but all this
stuff you guys are showing me is just pieces, and I'm having a little
trouble seeing the overall picture of a good testbench design. Thanks!

-Toby
 
M

Mike Treseler

Toby said:
Can somebody either post, or tell me EXACTLY where to find a nice, BIG,
COMPLETE, good, testbench example with all this stuff you guys are
talking about? Several examples would be even better, but all this
stuff you guys are showing me is just pieces, and I'm having a little
trouble seeing the overall picture of a good testbench design. Thanks!

My comments are incomplete, but here you go:

http://home.comcast.net/~mike_treseler/

-- Mike Treseler
 
P

Peter Hermansson

Mike Treseler said:
My comments are incomplete, but here you go:

http://home.comcast.net/~mike_treseler/

-- Mike Treseler

Hi,

A very interesting example. There are a lot of things that are
unfamiliar to me even if I have used VHDL for some years. Could you
please explain the "init_out_variables" procedure that executes on
every clock edge? Whats its purpose? Would it be possible for you
(dont want to waste your time...) to explain more from basic, the
structure of this example?

Regards, Peter
 
T

Toby

Yes that is a very interesting example. It has completely changed the
way I write testbenches, and I suspect it will also change the way I
write my VHDL design files. Thank you Mike! Does anyone else have any
COMPLETE testbench examples they can show me? I just love examples!
Thanks again Mike, your the best!

-Toby
 
M

Mike Treseler

it prevents double output registers.
I will fill in the info files next week.

-- 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,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top