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
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