From: Anders Nordstrom (Anders.Nordstrom.andersn@nt.com)
Date: Wed Nov 11 1998 - 14:11:23 PST
BAD MSG:
Dear BTF Members,
ontent-Length: 36887
X-Lines: 1081
X-Status: $$$$
X-UID: 0000000727
Status: RO
The Behavioural Task Force will meet before and after the regular 1364 WG meeting on
Monday November 16.
The BTF meeting will be at the same place as the 1364 WG meeting (TBD by Maq).
The meeting will start at 9:00 am, break for the 1364 WG meeting and continue
afterwards until 4:00 pm
<p>Agenda
-----
1) BE78 - Review enclosed proposal
2) B08 - Combinatorial Sensitivity list, review new proposal from Stefen.
3) BE01 - Identifier errata. Cliff to send out proposal.
4) BE40 and BE49 Errata. Cliff to send out proposals.
5) Discuss ANSI port declarations. See email from Mike McNamara on Oct 28.
6) Continue discussion on configurations.
7) Discuss Bottom testing loop B28. See enclosed proposals.
<p>Regards,
Anders Nordstrom
<p><p><x-html><HTML>
<HEAD>
<TITLE> BE78 </TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<BR>
<HR SIZE=5 NOSHADE>
<H2> BE78 - Errata in Syntax 14-5 </H2>
<TABLE BORDER COLS=2 WIDTH="75%" >
<TR><TD>
Section: </TD><TD> 14.2.2 page 181
</TD></TR><TR><TD>
Date Submitted: </TD><TD> 981102
</TD></TR><TR><TD>
Requestor: </TD><TD> Mike McNamara (mac@surefirev.com)
</TD></TR><TR><TD>
Status: </TD><TD> Proposal
</TD></TR><TR><TD>
Analyzed by: </TD><TD> Mike McNamara
</TD></TR>
</TABLE>
<H3> Details </H3>
Syntax 14-5 (page 181, in section 14.2.2 of 1364-1995) defines the
<PRE>
file_output_task_names ::=
$fdisplay | $fdisplayb | $fdisplayh | fdisplayf
| $fwrite | $fwriteb | $fwriteh | fwritef
| $fstrobe | $fstrobeb | $fstrobeh | fstrobef
| $fmonitor | $fmonitorb | $fmonitorh | fmonitorf
</PRE>
I believe the $xxxxxf versions should be $xxxxo
This error is in 1364-1995, as well as the current draft.
In XL 1.1a the table was:
<PRE>
file_output_task_names ::=
$fdisplay | $fdisplayb | $fdisplayh | fdisplayo
| $fwrite | $fwriteb | $fwriteh | fwriteo
| $fstrobe | $fstrobeb | $fstrobeh | fstrobeo
| $fmonitor | $fmonitorb | $fmonitorh | fmonitoro
</PRE>
<p><H3> Proposal </H3>
Change Syntax 14-5 on page 181 from:
<PRE>
file_output_task_names ::=
$fdisplay | $fdisplayb | $fdisplayh | fdisplayf
| $fwrite | $fwriteb | $fwriteh | fwritef
| $fstrobe | $fstrobeb | $fstrobeh | fstrobef
| $fmonitor | $fmonitorb | $fmonitorh | fmonitorf
</PRE>
to:
<PRE>
file_output_task_names ::=
$fdisplay | $fdisplayb | $fdisplayh | fdisplayo
| $fwrite | $fwriteb | $fwriteh | fwriteo
| $fstrobe | $fstrobeb | $fstrobeh | fstrobeo
| $fmonitor | $fmonitorb | $fmonitorh | fmonitoro
</PRE>
<HR SIZE=5 NOSHADE>
</BODY>
</HTML>
</x-html><x-html><HTML>
<HEAD>
<TITLE> B28 </TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<BR>
<HR SIZE=5 NOSHADE>
<H2> B28 - Bottom Testing Loop </H2>
<TABLE BORDER COLS=2 WIDTH="75%" >
<TR><TD>
Section: </TD><TD> TBD
</TD></TR><TR><TD>
Date Submitted: </TD><TD> 980317
</TD></TR><TR><TD>
Requestor: </TD><TD> Mark Arnold
</TD></TR><TR><TD>
Status: </TD><TD> Submitted
</TD></TR><TR><TD>
Analyzed by: </TD><TD> TBD
</TD></TR><TR><TD>
Synthesizable: </TD><TD> Yes
</TD></TR>
</TABLE>
<H3> Details </H3>
Dr. Mark Arnold of the University of Wyoming made an enhancement request
shortly after the Verilog conference. My apologies to Dr. Arnold, I am just
now wading through all of my e-mail that I did not get to in the past eight
weeks.
<p>
Dr. Arnold has submitted a request for a "bottom testing loop" in Verilog.
I am not a big fan of the proposal but I was wondering if there is a member
of the committee that is enthusiastic about the proposal that would also be
willing to champion the cause of this enhancement?
Perhaps Dr. Arnold could add a few more comments in favor of his proposal
that might help justify its inclusion. What I remember of Dr. Arnold's
proposal was that this construct would make it easier to do implicit FSM
modeling, an FSM coding style that I personally highly discourage.
Dr. Arnold has also reminded me that I need to make errata proposals to
start to clean up the scheduling semantics in Verilog. I will make these
proposals in a separate e-mail.
Regards - Cliff Cummings
<PRE>
Return-Path: <real-cliffc@europa.com>
Date: Tue, 17 Mar 1998 20:57:48 -0700
From: Mark Arnold <marnold@strawberry.uwyo.edu>
To: cliffc@europa.com
</PRE>
Thank you for taking the time to talk about my request for a bottom
testing loop in Verilog. I would like the behavioral task force to
consider this request for inclusion in the 1998 version of Verilog.
I have also listed items that you and Elliot were discussing, which
seem to me to be valuable improvements to IEEE 1364:
1. Bottom testing loop
Most languages provide this construct, such as do .. while in C.
I intend for this construct to be synthesizable. As described in my
paper, it would be very helpful to a designer using the implicit style.
Bottom testing loops are common in FSMs and in assembly language, and
so it is hard to explain the absence of this construct in a hardware
description language.
The existing Verilog language provides no easy way to implement such
a loop. The common approach of using disable in synthesis does not work
with all simulators (see #2).
A possible syntax is:
<PRE>
repeat
<statement>
while (<expression>)
</PRE>
which I think can be added to existing Verilog parsers with little
effort.
Beyond the implicit style, the repeat...while is useful in its own right.
I understand consideration is being given to greater file I/O
features. The repeat ... while could be helpful there. Also, even
if a designer does not use implicit style to implement the design under
test, the repeat...while would be convenient in the testbench when the design
implements an algorithm originally written in C or assembly language using
a bottom testing loop.
2. Clarify interaction of <= with disable
<= and disable are synthesizable. It would be nice if the way <=
and disable interact in simulation agrees with synthesis.
In any case, I have seen different results from different simulators.
Some simulators do some really strange things.
3. Clarify interaction of [] and <=
<PRE>
For example, does this complement foo[0]?
i = 0;
i <= i + 1;
foo[i] <= ~foo[i];
Or does it put ~foo[0] into foo[1]?
</PRE>
4. Clarify the scheduling distinction between
<PRE>
module top ...
reg d;
always @(posedge clk)
d = ...
endmodule
</PRE>
and
<PRE>
module top ...
wire d;
newmodule m(d,clk, ...);
endmodule
module newmodule(d,clk, ...);
output d;
input clk;
reg d;
always @(posedge clk)
d = ...
endmodule
</PRE>
I realize it is late in the game to get these requests now, but I was
confused by the OVI web page as to how to submit such requests.
--Mark
<HR SIZE=5 NOSHADE>
</BODY>
</HTML>
</x-html>Date: Sun, 25 Oct 1998 21:57:07 -0700 (MST)
From: Mark G Arnold <marnold@UWYO.EDU>
Subject: Re: Bottom testing loop in Verilog HDL
To: "Nordstrom, Anders (A.) [EXCHANGE:SKY:1V29:NT]" <andersn@americasm01.nt.com>
Message-id: <199810260457.VAA21216@asuwlink.uwyo.edu>
X-Mozilla-Status: 9011
Thank you for the opportunity to describe the usage of my proposed
bottom testing loop construct in Verilog input/output and testbenches.
To illustrate, I have appended four Verilog files at the end of this
ASCII message:
A. Reading LF terminated strings from a file
B. Interactive I/O with data validation
C. Testbench for a machine with a data request signal
D. Testbench with transport delay and protocol conversion
There are many possible syntaxes for the proposed bottom testing loop.
The one on the right is what I used for my IVC '98 paper and in my proposal to
the behavioral task force, but the one on the left can be simulated with macros
in the current version of Verilog for the purpose of this message:
`dowhile ( <cond> ) or repeat
`begin begin
<body> <body>
end end
while ( <cond> );
<p>The above differ only by whether the condition is located textually above or below
the <body>. Although the semantics of the two are intended to be identical,
I feel the original proposal (repeat ... while) is superior:
a) It is intuitive (like the corresponding do..while in C/C++/Java)
because <cond> is listed at the bottom, exactly at the point where it
would be tested the first time.
b) It adds no new reserved words to the language.
Other choices exist, such as Pascal's repeat ... until which negates
<cond>, but the repeat ... while syntax seems the best match to its usage.
The purpose of this message is not to advocate any particular syntax, but
rather to show the need for the bottom testing semantics in Verilog.
There are four ways to emulate a bottom testing loop in the current
Verilog standard:
1. duplication of code
<body>
while ( <cond> )
begin
<body>
end
2. flag variable (used by the `dowhile and `begin macros)
reg f;
...
f=1;
while (f| ( <cond> ))
begin
f=0;
<body>
end
3. disable inside forever
begin : <label>
forever
begin
<body>
if (~cond) disable <label>;
end
end
4. Ad hoc code to force <cond> to be true prior to loop
<code to make condition true>
while (<cond>)
begin
<body>
end
All of these techniques have drawbacks:
1. Duplication of code becomes unwieldy. For example, naive duplication
makes the code for reading terminated strings from a file twice as long as
in the bottom test version given at the end of this message (Example A):
line = -1;
line = line+1;
length[line] = -1;
length[line] = length[line]+1;
text_file.getc(string[{line,length[line]}]);
while (string[{line,length[line]}] != `END_OF_LINE
& string[{line,length[line]}] != `END_OF_FILE)
begin
length[line] = length[line]+1;
text_file.getc(string[{line,length[line]}]);
end
while (string[{line,length[line]}]!=`END_OF_FILE)
begin
line = line+1;
length[line] = -1;
length[line] = length[line]+1;
text_file.getc(string[{line,length[line]}]);
while (string[{line,length[line]}] != `END_OF_LINE
& string[{line,length[line]}] != `END_OF_FILE)
begin
length[line] = length[line]+1;
text_file.getc(string[{line,length[line]}]);
end
end
Admittedly, this code could be simplified (for example, line=0; instead
of the first two lines of code), but the problem remains that nested bottom
testing loops unwind to fairly complicated duplication of while loops.
It takes more while loop constructs to accomplish the same operation
that can be accomplished using fewer bottom testing loop constructs.
2. The flag variable approach requires declaration of the flag. Also, <cond>
is at the top, which is unnatural for a bottom testing loop. (The
reason <cond> is at the top of the loop for the `dowhile and `begin macros
is that this technique is the only one suitable for macros.)
3. The forever/disable approach is the most natural (<cond> at bottom, no duplication
or ad hoc code), but it may have undesired semantics when time or event related
code (such as non-blocking assignment, @, #, or ->) occur in <body>. This prevents
forever/disable from being used in many testbench situations. For example, the
correct output from the transport delay testbench (Example D) should be:
before $time= 0 data=xx lastbyte=x
bottom $time= 50 data=01 lastbyte=0
$time= 50 data=01
bottom $time= 150 data=02 lastbyte=0
$time= 150 data=02
bottom $time= 250 data=03 lastbyte=1
after $time= 250 data=03 lastbyte=1
$time= 250 data=03
$time= 350 data=ff
received terminator
If one attempts to use the forever/disable approach:
begin : lab
forever
begin
wait (strobe_producer===0);
strobe_consumer <= #`TRANSPORT_DELAY 0;
wait (strobe_producer===1);
strobe_consumer <= #`TRANSPORT_DELAY 1;
data_consumer <= #`TRANSPORT_DELAY data_producer;
$strobe("bottom $time=%d data=%x lastbyte=%b",$time,data_consumer,lastbyte);
if (lastbyte) disable lab;
end
end
many simulators will interpret that the disable should undo the non-blocking
assignment, and on such simulators, this code will malfunction:
before $time= 0 data=xx lastbyte=x
bottom $time= 50 data=01 lastbyte=0
$time= 50 data=01
bottom $time= 150 data=02 lastbyte=0
$time= 150 data=02
bottom $time= 250 data=02 lastbyte=1
after $time= 250 data=02 lastbyte=1
$time= 350 data=ff
received terminator
Rather than transmitting the correct message (01 02 03 ff), the forever/disable
testbench transmits an incorrect message (01 02 02 ff).
4. Ad hoc code is specific to the application, and is more likely to develop bugs if
supposedly unrelated code is changed. Often, it is not possible to use the ad
hoc approach due to indexing or time problems. For instance, the testbench
in example C is required to work with a machine that sends a request signal,
which is not valid at the time of entry into the loop. The testbench designer does
not have the authority to alter the nature of the signal provided by the
machine_under_test, and thus he is forced to ignore the value (1'bx) of
request upon entry to the loop. No ad hoc code is possible because the code
that generates request is inside the machine_under_test.
The main point here is not to describe the limitations of the current Verilog
standard any further, but to illustrate why the bottom testing loop is sufficiently
useful for I/O and testbenches to be included in the new standard. Here are
four examples where the bottom testing loop is useful:
A. Reading LF terminated strings from a file
This type of problem arises in two contexts: When a Verilog simulation
is reading text data from the host computer's physical disk, or when
one codesigns hardware and software, and the testbench emulates the
I/O transactions of the software. Since the current version of Verilog
is limited in its file input capabilities, example A is more like
simulated I/O for codesign, but the getc method of the file module
could just as easily be using the system tasks for Verilog I/O that
will be added to the new standard.
The pseudo-code for this approach is:
`dowhile (character is not a terminator)
`begin
...
text_file.getc(character);
end
The bottom testing loop is natural for this application because
the character variable is not defined before the first call
to getc, but that call should naturally be inside the loop.
This example is further complicated by several issues:
1. The file has both `END_OF_LINE and `END_OF_FILE terminators
2. Nested bottom testing loops are needed (the inner
one for processing characters within a line, and the outer
one for processing each line.)
3. The characters are to be put in an array, thus the value
of the index at the point where the condition evaluates is critical.
It is invalid to evaluate the condition prior to the first
iteration because the index will not be meaningful.
4. The length of each line is to be recorded in a second array.
B. Interactive I/O with data validation
This could occur in the two contexts of example A:
new system tasks (or PLI calls) for interactive
I/O during a simulation, or hardware/software codesign. Example
B simulates I/O with a getcecho routine.
Example B performs at least one iteration of some desired computation.
The user is queried whether he wishes another iteration
to be performed. The valid answers are "y" and "n". Any other
response causes the user to be prompted again. The iterations continue
until the user enters "n".
As with example A, it is not known whether the loop should continue
until after the first call to the task, thus the test of the result of
that call should occur at the bottom of the loop.
C. Testbench for a machine with a data request signal
This testbench supplies vectors (in the vect array) at the $times indicated
by the delay array. The machine_under_test (which cannot be changed by the testbench
designer) causes request to be true when it wants an additional byte
of data. In this particular example the machine_under_test chooses to
ask for another byte based on whether the data sent from the testbench
is a terminator byte. Since that byte is not defined by the testbench
until entry into the loop, request is 1'bx at the time the loop is entered.
Only after the testbench has sent the first data byte does the machine
output a well-defined request signal (1 or 0).
The following illustrates how the bottom testing loop
reacts properly when the terminator(8'h67) is present in
the test vectors:
before $time= 0 data=xx request=x
$time= 0 request=x
$time= 0 data=xx
$time= 10 data=12
$time= 12 request=1
bottom $time= 13 data=12 request=1
$time= 33 data=34
bottom $time= 36 data=34 request=1
$time= 46 data=56
bottom $time= 49 data=56 request=1
$time= 59 data=67
$time= 61 request=0
bottom $time= 62 data=67 request=0
after $time= 62 data=67 request=0
The following illustrates how using a while loop by itself
causes the testbench to malfunction:
before $time= 0 data=xx request=x
after $time= 0 data=xx request=x
$time= 0 request=x
$time= 0 data=xx
D. Testbench with transport delay and protocol conversion
This example has two modules being tested by the testbench: the
producer and the consumer. The testbench needs to model
two things: the transport delay of sending data from the
producer to the consumer, and the protocol difference between
what the producer creates and what the consumer demands.
The protocol that the producer uses in this example is a separate
lastbyte signal to indicate the termination of the message.
On the other hand, the consumer wants a terminator byte of
8'hff.
This testbench receives data from the producer and introduces
transport delay using non-blocking assignment.
Also, the testbench translates from the lastbyte protocol
signal to the delimiter protocol.
In summary, there are many applications that could benefit from a bottom testing
construct to make the coding of loops in Verilog more convenient and concise.
Although all of my example applications have a common similarity (initiating
an action inside a loop and then using the reaction to decide whether to continue),
the fact that the applications come from such a variety of contexts argues that many
designers will benefit from the inclusion of a bottom testing construct in
the new Verilog standard.
--Mark Arnold
Verilog code examples
//========Example A. Reading LF terminated strings from a file======================
// Example to show how a bottom testing loop is useful for reading
// terminated strings from files
<p>// Macro to emulate bottom testing loop
`define dowhile f=1; while (f||(
`define begin )) begin f=0;
<p><p>// Unix-like terminators:
`define END_OF_LINE 10
`define END_OF_FILE 3
<p>// Module to emulate a text file
module file;
integer p;
reg [7:0] a[100:0];
initial
begin
p=0;
a[0]= "f";
a[1]= "i";
a[2]= "r";
a[3]= "s";
a[4]= "t";
a[5]= " ";
a[6]= "l";
a[7]= "i";
a[8]= "n";
a[9]= "e";
a[10]=`END_OF_LINE;
a[11]=`END_OF_LINE;
a[12]="s";
a[13]="e";
a[14]="c";
a[15]="o";
a[16]="n";
a[17]="d";
a[18]=" ";
a[19]="n";
a[20]="o";
a[21]="n";
a[22]=" ";
a[23]="e";
a[24]="m";
a[25]="p";
a[26]="t";
a[27]="y";
a[28]=" ";
a[29]="l";
a[30]="i";
a[31]="n";
a[32]="e";
a[33]=`END_OF_FILE;
end
task getc;
output ch;
reg [7:0] ch;
begin
ch = a[p];
p = p+1;
if (ch==`END_OF_FILE)
p = 0;
end
endtask
endmodule
<p>// The following reads lines delimited by `END_OF_LINE from an emulated text
// file into the string array. The file itself is delimited by `END_OF_FILE,
// which also acts like end of line. The string array is arranged in row major
// order as 8 lines of at most 32 characters each. The actual number of characters
// on each line is given by the length array. Because of the number of bits
// declared in variables such as line and col, string[{line,col}] emulates 2D
// access to the character at the given coordinate.
//
// The bottom test loops in the following are useful because without the
// bottom test construct, the looping conditions would evaluate to 'bx
// prior to the first iteration. This would happen because string is
// uninitialized and line is set to an inappropriate value (-1) for indexing
<p>module test;
file text_file(); //emulate text file
reg [2:0] k,line; // line number in range 0..7
reg [4:0] col; // column position in range 0..31
reg [7:0] string[255:0]; // 8 lines of 32 ASCII (8 bit) chars each
reg [4:0] length[7:0]; // length of string on each line in range 0..31
reg f; //for bottom test loop
initial
begin
line = -1;
`dowhile (string[{line,length[line]}]!=`END_OF_FILE)
`begin
line = line+1;
length[line] = -1;
`dowhile (string[{line,length[line]}] != `END_OF_LINE
& string[{line,length[line]}] != `END_OF_FILE)
`begin
length[line] = length[line]+1;
text_file.getc(string[{line,length[line]}]);
end
end
for (k=0; k<=line; k=k+1)
begin
$write("%d ",length[k]);
for (col=0; col<length[k]; col=col+1)
$write("%c",string[{k,col}]);
$display(" ");
end
end
endmodule
<p>//========Example B. Interactive I/O with data validation===========================
// Example to show use of bottom testing loop in interactive I/O
// Macros to emulate a bottom testing loop
`define dowhile f=1; while (f||(
`define begin )) begin f=0;
<p><p>// Module to emulate interactive input
module file;
integer p;
reg [7:0] a[100:0];
initial
begin
p=0;
a[0]="u"; //invalid
a[1]="i"; //invalid
a[2]="y"; //yes, do a second
a[3]="y"; //yes, do a third
a[4]="o"; //invalid
a[5]="y"; //yes, do a fourth
a[6]="9"; //invalid
a[7]="n"; //no, stop the process
end
//method to get char w/o echo
task getc;
output ch;
reg [7:0] ch;
begin
ch = a[p];
p = p+1;
if (ch==0)
p = 0;
end
endtask
<p> //method to get char with echo (as is typ. in interactive dialog)
task getcecho;
output ch;
reg [7:0] ch;
begin
getc(ch);
$display("%c",ch);
end
endtask
endmodule
<p>// module that performs some iterative process (in this case, simply
// incrementing i) interactively, i.e., the user (simulated by the
// console instance of the file module) determines how many iterations
// occur by the answer to the "Do you want to continue" questions.
module interactive;
reg [7:0] continue;
file console();
reg f;
integer i;
initial
begin
i = 1;
`dowhile ( continue == "y" )
`begin
$display("iteration %d",i);
i = i + 1;
`dowhile ( (continue!="y")&(continue!="n") )
`begin
$write("Do you want to continue (y/n)? ");
console.getcecho(continue);
end
end
end
endmodule
<p>//========Example C. Testbench for a machine with a data request signal=============
// Example to illustrate need for bottom testing loop
// in Verilog for testbenchs
// For the purposes of this limited example,
// the bottom testing loop can be emulated by
// the following two macros:
`define dowhile f=1; while (f||(
`define begin )) begin f=0;
<p>// The following is the delay for the machine_under_test
// to respond with the next data request
`define RESPOND_DELAY 3
<p>// The following is the maximum number of test vectors
// to be used
`define MAX_VECT 5
// This module emulates a machine to be tested.
// It consumes data until a terminator byte (not
// known to the testbench, but which is the constant 8'h67
// in this example) is received by the machine under test.
// To signal whether the machine desires an additional
// byte, the machine outputs the request signal.
// In the fabricated hardware, the request signal would
// be generated by a comparison of 8'h67 against
// the data bus. Thus request is not valid before the
// testbench drives the data bus with the first vector.
module machine_under_test(request,data);
output request;
input data;
wire request;
wire [7:0] data;
assign #2 request=data!=8'h67;
always @(request)
$strobe(" $time=%d request=%b",$time,request);
always @(data)
$strobe(" $time=%d data=%h",$time,data);
endmodule
<p>// The testbench drives the data bus with new test
// vectors from the vect array at the times indicated by
// the delay array. The testbench is then to wait for
// an additional `RESPOND_DELAY before testing whether
// machine_under_test requests another byte
// The testbench must stop when the machine under
// test no longer requests data, even if not all of
// the vectors in vect have been consumed.
module testbench;
reg [7:0] vect[0:`MAX_VECT-1];
integer delay[0:`MAX_VECT-1];
reg [7:0] data;
reg f; //for bottom test
integer i;
machine_under_test m(request, data);
initial
begin
vect[0]=8'h12; delay[0]=10;
vect[1]=8'h34; delay[1]=20;
vect[2]=8'h56; delay[2]=10;
vect[3]=8'h68; delay[3]=10;
vect[4]=8'h89; delay[4]=30;
i = 0;
$strobe("before $time=%d data=%h request=%b",$time,data,request);
`dowhile (request & i<`MAX_VECT)
`begin
data <= #(delay[i]) vect[i];
#(delay[i]+`RESPOND_DELAY);
i = i + 1;
$strobe("bottom $time=%d data=%x request=%b",$time,data,request);
end
$strobe("after $time=%d data=%h request=%b",$time,data,request);
end
endmodule
<p>//========Example D. Testbench with transport delay and protocol conversion=========
// The following is the delay for
// a non-blocking assignment that models a delay line
// Using zero will illustrate the problems with the
// forever/disable implementation of the bottom testing loop
// most easily, but other values for the delay suffer
// similar problems on many simulators
`define TRANSPORT_DELAY 0
<p>// This module emulates a machine that consumes data
// It expects a terminator byte of 8'hff
module consumer(strobe,data);
input strobe,data;
wire [7:0] data;
always @(posedge strobe)
$strobe(" $time=%d data=%h",$time,data);
initial
begin
wait(data==8'hff);
#1 $display("received terminator");
end
endmodule
<p>// This module emulates a machine that produces data.
// Valid data is indicated by the rising edge of the strobe.
// The final byte of the packet is indicated by lastbyte.
// For the purpose of this example, the message is simply
// the three bytes 1 2 and 3 repeated over and over:
// _ _ ___ ___ ___ ___ ___ ___ ___
// dataout /x\/0\/ 1 \/ 2 \/ 3 \/ 1 \/ 2 \/ 3 \/ 1 \ ...
// \_/\_/\___/\___/\___/\___/\___/\___/\___/
// __ ___ ___
// lastbyte x |_____________| |__________| |_____ ...
// __ _ _ _ _ _ _ _
// strobe x |___| |__| |__| |__| |__| |__| |__| |__ ...
// 0 25 50 150 250 350 450 550 650
//
// Note that the output of the machine is not defined
// during the first 25 units of $time. dataout has
// an irrelevant value of 0 prior to the first strobe
// to simplify this module.
module producer(strobe,dataout,lastbyte);
output strobe,dataout,lastbyte;
reg strobe;
reg [7:0] dataout;
assign lastbyte = dataout == 3;
initial #25
begin
strobe <= 0;
dataout <= 0;
end
always #50
begin
if (~lastbyte)
dataout <= dataout + 1;
else
dataout <= 1;
strobe <= 1;
#50 strobe <= 0;
end
endmodule
//
// This testbench receives data from the producer and introduces
// transport delay using non-blocking assignment.
// Also, the testbench translates from the separate lastbyte
// signal to a delimiter byte of 8'hff. This testbench is supposed to
// transmit only the first message. Later repetitions of the same
// message will be ignored.
//
// +--------+ strobe_producer +-------+ strobe_consumer +--------+
// | |----------------->| test- |----------------->| |
// |producer| data_producer | bench | data_consumer |consumer|
// | |--------------/-->| |--------------/-->| |
// | | lastbyte 8 | | 8 +--------+
// | |----------------->| |
// +--------+ +-------+
//
// undelayed delayed
// packet delimited by packet delimited by 8'hff
// separate lastbyte signal
//
// The bottom test loop is necessary because the lastbyte signal
// is not defined at $time 0
// __ ____ ____
// lastbyte x |_____________| |_________| |____ ...
//
// _ _ ___ ___ ___ ___ ___ ___ ___
// data_producer /x\/0\/ 1 \/ 2 \/ 3 \/ 1 \/ 2 \/ 3 \/ 1 \ ...
// \_/\_/\___/\___/\___/\___/\___/\___/\___/
// __ _ _ _ _ _ _ _
// strobe_producer x |___| |__| |__| |__| |__| |__| |__| |__ ...
//
// ______ ___ ___ ___ _________________
// data_consumer / x \/ 1 \/ 2 \/ 3 \/ ff
// \______/\___/\___/\___/\_________________
// ____ _ _ _ _
// strobe_consumer x |___| |__| |__| |__| |_______________
//
module testbench;
reg f; //for bottom test loop
reg [7:0] data_consumer;
reg strobe_consumer;
wire [7:0] data_producer;
wire strobe_producer;
wire lastbyte;
producer p(strobe_producer, data_producer,lastbyte);
consumer c(strobe_consumer, data_consumer);
initial
begin
$strobe("before $time=%d data=%h lastbyte=%b",$time,data_consumer,lastbyte);
`dowhile (~lastbyte)
`begin
wait (strobe_producer===0);
strobe_consumer <= #`TRANSPORT_DELAY 0;
wait (strobe_producer===1);
strobe_consumer <= #`TRANSPORT_DELAY 1;
data_consumer <= #`TRANSPORT_DELAY data_producer;
$strobe("bottom $time=%d data=%x lastbyte=%b",$time,data_consumer,lastbyte);
end
/*
begin : lab
forever
begin
wait (strobe_producer===0);
strobe_consumer <= #`TRANSPORT_DELAY 0;
wait (strobe_producer===1);
strobe_consumer <= #`TRANSPORT_DELAY 1;
data_consumer <= #`TRANSPORT_DELAY data_producer;
$strobe("bottom $time=%d data=%x lastbyte=%b",$time,data_consumer,lastbyte);
if (lastbyte) disable lab;
end
end
*/
$strobe("after $time=%d data=%h lastbyte=%b",$time,data_consumer,lastbyte);
#50 strobe_consumer <= #`TRANSPORT_DELAY 0;
#50 strobe_consumer <= #`TRANSPORT_DELAY 1;
data_consumer <= #`TRANSPORT_DELAY 8'hff;
#50 strobe_consumer <= #`TRANSPORT_DELAY 0;
$finish;
end
endmodule
<p>Date: Sun, 08 Nov 1998 00:19:11 -0700 (MST)
From: Mark G Arnold <marnold@UWYO.EDU>
To: "Nordstrom, Anders (A.) [EXCHANGE:SKY:1V29:NT]" <andersn@americasm01.nt.com>,
marnold@uwyo.edu
Message-id: <199811080719.AAA05660@asuwlink.uwyo.edu>
X-Mozilla-Status: 8001
In my earlier discussion of the advantages of the bottom testing
loop for testbenches, I forgot to include one of the most obvious uses:
enumerating all possible bit patterns. One of the most common test strategies
for busses of small size is to have the testbench go through all possible
well-defined values. For a bus of n bits, this means 2 raised to the n
distinct binary values need to be driven on the bus. For example, consider
generating these values for a two bit wide b:
reg [1:0] b;
It would be tempting to use:
for (b=0; b<=3; b=b+1)
however this will fail to exit because the 3+1 is truncated to be 2'b00,
and hence b is never >3.
Another attractive but incorrect solution is:
for (b=0; b!=0; b=b+1)
which fails because the loop is never entered.
The only solution to this problem in the current Verilog
standard is to define a wider variable (such as integer) that can
hold the terminating value (4 in this example). This integer variable
must be assigned to b each time through the loop.
Because the bottom testing loop only tests after the variable has incremented
the first time, the bottom testing loop solves this problem more elegantly.
The terminating value is one less than in the top testing loop, thus the
terminating value can be represented in the same number of bits as b.
The following file illustrates the proposed usage compared to the current
standard. As in my earlier message, I use the `dowhile `begin syntax only
because it works as a macro.
Again, thanks for the opportunity to describe the advantages of the
bottom testing loop.
--Mark Arnold
//Another example to show the advantage of a bottom test loop:
// enumerating all possible bit patterns in a reg of a given size
`define dowhile f=1; while (f||(
`define begin )) begin f=0;
<p>module top;
reg [1:0] b;
integer ib;
reg f;
initial
begin
#100 b=0;
`dowhile(b!=3)
`begin
#200 b = b+1;
end
for (ib=0; ib<=3; ib = ib+1)
begin
#200 b=ib;
end
#200 $finish;
end
always #200
$display("b= %b $time=%d",b,$time);
endmodule
This archive was generated by hypermail 2.1.4
: Mon Jul 08 2002 - 12:53:01 PDT
and
sponsored by Boyd Technology, Inc.