Verilog: Simulating Transport Delays on Bidirectional Trista

K

Kevin Neilson

Guest
When I started to write this, I wanted to ask how to model a
bidirectional wire with transport delays but I've come up with a
solution that works for my SDRAM sim so I'll post it here. I've done a
fairly exhaustive search, and have found many instances of others posing
this question, but no other definitive answers. Mr. Bromley, in a
recent post, showed me how to model transport (not inertial) delays on
unidirectional lines. I was initially able to, using two "wires" at the
endpoints and a "reg" in the middle, simulate a tranport delay that
worked in either direction, but the problem I kept encountering was
this: the signal got "reflected" at the receiving end of the path and
retransmitted, bouncing back and forth forever like a photon in a
mirrored box.

The Verilog "tran" primitive is not useful because it never incurs a
delay across its two I/Os.

I finally found a way to prevent the reflections that has the limitation
described below. To model a bidirectional wire, just instantiate the
module below, and the 'a' and 'b' ports correspond to the values at each
end of a bidirectional wire with delay. The delay values are reals so
that they can be changed during the sim; therefore you must 'force' them
using the method described below. The delays can model PCB copper
delays only, or, for RTL sims, can incorporate input/output pad delays,
in which case the delays may be different in each direction. Here is
the model:

/*****************************************************************
* module triwire: bidirectional wire bus model with delay
*
* This module models the two ends of a bidirectional bus with
* transport (not inertial) delays in each direction. The
* bus has a width of WIDTH and the delays are as follows:
* a->b has a delay of Ta_b (in `timescale units)
* b->a has a delay of Tb_a (in `timescale units)
* The two delays will typically be the same. This model
* overcomes the problem of "echoes" at the receiving end of the
* wire by ensuring that data is only transmitted down the wire
* when the received data is Z. That means that there may be
* collisions resulting in X at the local end, but X's are not
* transmitted to the other end, which is a limitation of the
* model. Another compromise made in the interest of simulation
* speed is that the bus is not treated as individual wires, so
* a Z on any single wire may prevent data from being transmitted
* on other wires.
*
* The delays are reals so that they may vary throughout the
* course of a simulation. To change the delay, use the Verilog
* force command. Here is an example instantiation template:
*
real Ta_b=1, Tb_a=1;
always@(Ta_b) force triwire.Ta_b = Ta_b;
always@(Tb_a) force triwire.Tb_a = Tb_a;
triwire #(.WIDTH(WIDTH)) triwire (.a(a),.b(b));

* Kevin Neilson, Xilinx, 2007
*****************************************************************/
module triwire #(parameter WIDTH=8) (inout [WIDTH-1:0] a, b);
real Ta_b=1, Tb_a=1;
reg [WIDTH-1:0] a_dly = 'bz, b_dly = 'bz;
always@(a) a_dly <= #(Ta_b) b_dly==={WIDTH{1'bz}} ? a : 'bz;
always@(b) b_dly <= #(Tb_a) a_dly==={WIDTH{1'bz}} ? b : 'bz;
assign b = a_dly, a = b_dly;
endmodule
 
On Fri, 16 Feb 2007 14:25:13 -0700, Kevin Neilson
<kevin_neilson@removethiscomcast.net> wrote:

When I started to write this, I wanted to ask how to model a
bidirectional wire with transport delays but I've come up with a
solution that works for my SDRAM sim so I'll post it here.[...]
Kevin, your solution is ingenious and maybe does what you want,
but I'm not sure I really understand the application.

The point about "reflections" on a bidi transport model is
interesting, and makes me wonder about digital modelling
of termination.....

Anyways, here's a thought - don't know whether it meets
your needs. It cheats by using weak drivers to get the
transport-delayed value on to the connections at each end.
I'm quite sure it is not totally general, but it's simple and
works for many purposes. At the driving end, you can
see your driving value un-delayed; at the other end, you
see a delayed version of it. Obviously, if both ends are
driven you may see X values. It does indeed "echo"
as you indicate, but the echo will always settle after
only one round trip - until the next drive change, of course.

module bidi_delay
#(parameter delay = 1)
(inout L, R);

reg reg_L = 1'bz, reg_R = 1'bz;

// L->R transport delay
always @(L) reg_R <= #delay L;
assign (weak1, weak0) R = reg_R;

// R->L
always @(R) reg_L <= #delay R;
assign (weak1, weak0) L = reg_L;

endmodule

///////////////////////////////////////////

module test_bidi_delay;

parameter delay = 20;

// Random generation of a single bit. If called
// with use_xz=0, bit is 0 or 1. If called with
// use_xz=1, bit is 0/1/x/z.
function random_bit(input use_xz);
case ({$random} % (use_xz? 4: 2))
0: random_bit = 1'b0;
1: random_bit = 1'b1;
2: random_bit = 1'bx;
3: random_bit = 1'bz;
endcase
endfunction

// Create a random value uniformly distributed over
// the range 0..(N*delay)-1
function integer random_time(input integer N);
random_time = {$random} % (delay * N);
endfunction

// Test harness: connections to each end of the
// delaying wire, and regs to drive them
reg drive_L, drive_R;
wire L = drive_L;
wire R = drive_R;

bidi_delay #delay cable (L, R);

// Test stimulus
initial begin

// test 1: drive from L end only
drive_R = 1'bz;
repeat (20)
#(random_time(5)) drive_L = random_bit(0);

// test 2: drive from R end only
drive_L = 1'bz;
#(delay*100)
repeat (20)
#(random_time(5)) drive_R = random_bit(0);

// test 3: random drive from both ends together
fork
repeat(200)
#(random_time(10)) drive_R = random_bit(1);
repeat(200)
#(random_time(10)) drive_L = random_bit(1);
join

end

endmodule
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Jonathan Bromley wrote:
On Fri, 16 Feb 2007 14:25:13 -0700, Kevin Neilson
kevin_neilson@removethiscomcast.net> wrote:

When I started to write this, I wanted to ask how to model a
bidirectional wire with transport delays but I've come up with a
solution that works for my SDRAM sim so I'll post it here.[...]

Kevin, your solution is ingenious and maybe does what you want,
but I'm not sure I really understand the application.

The point about "reflections" on a bidi transport model is
interesting, and makes me wonder about digital modelling
of termination.....

Anyways, here's a thought - don't know whether it meets
your needs. It cheats by using weak drivers to get the
transport-delayed value on to the connections at each end.
I'm quite sure it is not totally general, but it's simple and
works for many purposes. At the driving end, you can
see your driving value un-delayed; at the other end, you
see a delayed version of it. Obviously, if both ends are
driven you may see X values. It does indeed "echo"
as you indicate, but the echo will always settle after
only one round trip - until the next drive change, of course.

Jonathan,
Thanks for this code. I like the idea of using different drive
strengths. Using this method, though, it looks like I still encounter
the same reflection issue sometimes, because if one end is being driven
with a 'z' and a 'weak' at the same time, 'weak' strength overpowers the
'z' strength and sends back a reflection which will bounce indefinitely
as long as both drivers are 'z'. I can see this simulating your code if
I change 'delay' to 100. Then I see the last transition of drive_L get
reflected back and forth until drive_R gets driven with something non-Z.

To suppress these reflections, I can't leave the net at 'z' when it's
not in use, but rather something between 'weak' and 'strong', like
'pull'. I can suppress the reflections if I put pullups on the R and L
nets, because the 'pull' strength is stronger than 'weak', so it
suppresses reflections, but is weaker than 'strong', so it can be
overridden by regular assignments. So this method works better than
mine, because it models the Xs better, but requires the tristate nets to
have pullups or pulldowns. This is sometimes necessary anyway, because
I've noticed that Xilinx gate-level netlists use the 'buf' primitive
to model delays, and 'buf' turns Zs into Xs, requiring me to model the
bidirectional line with pullups lest Xs propagate through the sim.
-Kevin
 

Welcome to EDABoard.com

Sponsor

Back
Top