Sunday, August 14, 2011

Half-duplex: Better than Zero-Ohm

I once had to simulate the long board delays and discovered very soon that it is not easy in VHDL to connect two Z-state capable drivers with a delay line. The literature confirms this. And, the famous Ben Cohen model is proposed to achieve the simulation goal. Nevertheless, look how nicely it works.

In the code,

 
process begin
c <= '1'; wait for 3 ns;
c <= '0'; wait for 3 ns;
c <= '1'; wait for 3 ns;
end process;
a <= c;
ZOI: entity ZeroOhm port map(a, b);
we have driver A and I would expected that B follows its waveform after a delay. Let's see the simulation diagram.



What's that? Instead of 101, I see something terrible on B surrounding 0 value.

I sincerely confess, I do not understand what is the advantage of this model. I just see that instead of delay, it introduces Z-states every driver transition. These gaps corrupt the beautiful picture and completely destroy the signal when driver period comes close to the transport delay. That is, in the cases of larger delay it becomes more important to take into simulation but worse it is corrupted by the transport model. Corrupting instead of propagation is not what we need.

Ben tried to deliver every transaction to another end, which seems impossible due to feedbacks. He used the gaps of silence to break them. Unfortunately, this also invalidates the model.

But, if you think a little, there is no need to simulate the feedbacks. Normally, there is no more than one active driver per line. Neither reflections nor other drivers are allowed to issue their signal values into the line until it stops. At this moment, user introduces Z-gaps himself, to prevent congestion. Feedbacks are not possible. Thus, switch should not spoil the signal introducing 3-state transition periods.

Exploiting this usage of 3-state drivers, though defeats the strong-weak congestion resolution between the communicating parties, at least, does not destroy the normal signal.



The effect is more dramatic when you simulate 4.5 ns board delays for DDR transfers with half of the period = 2.5 ns. Bens's model delivers nothing:



Here is the code

entity Z_SWITCH is
generic (LAG: time := 1 ns);
port (
A, B: inout std_logic := 'Z' -- must be Z-separated or A takes precedence
);
end entity;

architecture WAIT_FOR_Z of Z_SWITCH is
procedure P(constant NAME: string; signal X: in std_logic; variable X_TIMEOUT: in time;
signal Y: out std_logic; variable Y_TIMEOUT: inout time) is
begin
if now > X_TIMEOUT and X /= 'Z' then
L1: loop
Y <= transport X after LAG;
Y_TIMEOUT := now + LAG;
if X = 'Z' then
exit L1;
end if;
wait on X;
end loop;
end if;

end procedure;

begin

process
variable A_TO, B_TO: time := - 10 ns; -- signal will propagate up to this time, do not loop it back.
begin
wait on A, B;
P("A->B", A, A_TO, B, B_TO); -- until A iz not Z
P("B->A", B, B_TO, A, A_TO); -- until B is not Z
end process;

end architecture;


Z-switch Bus and TB
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Z_SWITCH_TB is
end entity;

architecture TB of Z_SWITCH_TB is
constant PERIOD: time := 5 ns;
constant LAG: time := 4.5 ns;
procedure DDR_DRIVE(signal S: out std_logic) is begin
for I in 1 to 2 loop
S <= '0'; wait for PERIOD/2;
S <= '1'; wait for PERIOD/2;
end loop;
S <= 'Z'; wait for 1.3 * PERIOD;
end procedure;
procedure SEQUENCE(signal A,B: inout std_logic) is begin
DDR_DRIVE(A);
DDR_DRIVE(B);
DDR_DRIVE(A);
wait;
end procedure;
begin

NO_CONN: block
signal A, B: std_logic := 'Z';
begin
process begin SEQUENCE(A, B); end process;
end block;

Z_SWITCH: block
signal A, B: std_logic := 'Z';
begin
DUT: entity Z_SWITCH generic map (LAG) port map(A, B);
process begin SEQUENCE(A, B); end process;
end block;

ZERO_OHM: block
signal A, B: std_logic := 'Z';
begin
DUT: entity ZeroOhm generic map (LAG, LAG) port map(A, B);
process begin SEQUENCE(A, B); end process;
end block;

end architecture;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Z_BUS is
generic (LAG: time := 1 ns);
port (
A, B: inout std_logic_vector
);
end entity;
architecture ARCH of Z_BUS is
begin
BUS_COMMUTATOR: for I in A'range generate
SWITCH: entity Z_SWITCH generic map(LAG) port map(A(I), B(I));
end generate;
end architecture;

No comments: