Search:   

VHDL Switch Model 

 
Have you ever tried to model a bidirectional switch in VHDL ? Since drivers in VHDL are unidirectional the task can become quite challenging.

I came up to this challenge when I have to create a testbench where we need to be able to disconnect an EEPROM model from the DUT on the I2C bus. If the I2C bus were unidirectional then the switch can be modeled as a tri-state buffer, where we disable the tri-state (drive output with 'Z') when we want to disconnect the line. Indeed, even in bidirectional case, disconnection can be modeled by driving both switch ends with 'Z'.

However, the problem arises when we need to model the switch behavior when the switch is on. In this case, if the ends are A and B, we need to resolve logic driven on A and B and then drive A and B with the resolved logic. Anyway, when the switch is on, A and B are connected together and must have the same logic, right ? This leads us to write some VHDL like below:


process(A, B)
variable C : std_logic;
begin
C := resolved(A,B);
A <= C;
B <= C;
end process;


However if you try that, you will soon find out that it will not work. This is because at the beginning of simulation, A and B will be an 'U' (undefined) and a combination of 'U' and any other logic will become 'U', so the switch outputs will always be 'U'.

Let's change the code a little:


process
variable t : time;
variable C : std_logic;
begin
wait on A'transaction, B'transaction until t /= now;
t := now;

A <= 'Z';
B <= 'Z';

wait for 0 ns;

C := resolved(A,B);
A <= C;
B <= C;
end process;


Note the modifications :

  1. We wait on transactions instead of events. This allows us to react when A or B is driven even if the result remains the same.
  2. We check if the time has moved forward. Otherwise the next several assignments will create another set of transactions and your simulator will freeze for infinite loop.
  3. When we detect a transaction, we first un-drive our switch output by driving both ends with 'Z'. This is needed so that we can 'see' what is being driven on A and B from external (or else you will always see 'U').
  4. We wait for 0 ns before resolving. This is to create delta time for the un-driving process to take effect.

Ok, we are pretty close now. You can see that the model will work as expected. However, if you cascade two or more switches together, they will again fail. Why ? Because the 'until t /= now' statement !

The comparison of t and now was necessary to prevent infinite loop but it will also prevent logic propagation across more than one switch since all with happen at the same time (within the VHDL delta times).

To workaround this, we just need to wait until the signal propagate through all cascaded switches by repeating the 'wait for 0 ns' twice the number of switches before we try resolving logic at both ends. And we resolve and drive switch ends also as many times as twice the number of switches to enable our resolved logic to propagate through all switches.

Our final model is shown below. This work is based on Ben Cohen and Ralf Hildebrandt's work so credits for them.


----------------------------------------------------------------------------
-- This model is based on
-- http://www.ralf-hildebrandt.de/publicat ... ergate.vhd
-- by Ralf Hildebrandt which is based on
-- http://members.aol.com/vhdlcohen/vhdl/v ... witch1.vhd
-- by Ben Cohen
--
-- http://www.ralf-hildebrandt.de/publicat ... ergate.vhd
-- added multiple transactions capability to the original Ben Cohen model,
-- allowing chaining of switches/transfergates, but for reasons unknown to
-- me removed the logic resolving feature, causing the model behaves
-- incorrectly when both ends are driven by different logics other than
-- high impedance ('Z')
--
-- This model fixed the issue. The entity name changed back to switch1b
--
-- Limitation: switch1 (multi-bit bus model) is not implemented here
-- but should be able to be done pretty easily
--
----------------------------------------------------------------------------
-- Author: Yanto Suryono - yanto.suryono@gmail.com
----------------------------------------------------------------------------
--
-- Below is the original copyright notice
--
----------------------------------------------------------------------------
-- This model is based on
-- http://members.aol.com/vhdlcohen/vhdl/v ... witch1.vhd
-- and therefore the following copyright statement is valid:

----------------------------------------------------------------------------
-- Copyright (c) 1997, Ben Cohen. All rights reserved.
-- This model can be used in conjunction with the Kluwer Academic book
-- "VHDL Coding Styles and Methodologies", ISBN: 0-7923-9598-0
-- "VHDL Amswers to Frequently Asked Questions", Kluwer Academic
-- which discusses guidelines and testbench design issues.
--
-- This source file for the switch model may be used and
-- distributed without restriction provided that this copyright
-- statement is not removed from the file and that any derivative work
-- contains this copyright notice.
----------------------------------------------------------------------------

----------------------------------------------------------------------------
-- Author: Ralf Hildebrandt - Ralf-Hildebrandt@gmx.de
----------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.all;


entity switch1b is
port (
A, B : inout std_logic;
Cab : in std_logic
);
end switch1b;

architecture behavior of switch1b is
constant chain_length : positive := 3; -- number of transfergates in a chain - don't set too high

-------------------------------------------------------------------
-- resolution function
-------------------------------------------------------------------
constant Resolution_Table : Stdlogic_Table := (
-- ---------------------------------------------------------
-- | U X 0 1 Z W L H - | |
-- ---------------------------------------------------------
( 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U' ), -- | U |
( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ), -- | X |
( 'U', 'X', '0', 'X', '0', '0', '0', '0', 'X' ), -- | 0 |
( 'U', 'X', 'X', '1', '1', '1', '1', '1', 'X' ), -- | 1 |
( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', 'X' ), -- | Z |
( 'U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X' ), -- | W |
( 'U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X' ), -- | L |
( 'U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X' ), -- | H |
( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ) -- | - |
);

function Resolved ( S : Std_uLogic_Vector ) return Std_uLogic is
variable Result : Std_uLogic := 'Z'; -- weakest state default
begin
-- the test for a single driver is essential otherwise the
-- loop would return 'X' for a single driver of '-' and that
-- would conflict with the value of a single driver unresolved
-- signal.
if (S'length = 1) then
return S(S'low);
else
for I in S'range Loop
Result := Resolution_Table(Result, S(I));
end loop;
end if;
return Result;
end Resolved;

begin
process
variable last : time;
variable ResolvedValue_v : std_ulogic;
begin
wait on A'transaction, B'transaction, Cab'transaction until last /= now;
last := now;
A <= 'Z'; -- remove driver of transfergate
B <= 'Z'; -- remove driver of transfergate

-- wait until the internal driver removal propagates through the transfer gates chain
-- ports at the end of chain will start interacting with the actual drivers
for N in 1 to chain_length*2 loop
wait for 0 ns;
end loop;

if (Cab = '1') then

-- if the transfergate is enabled, resolve logics at both ends and re-drive
-- the ends with the resolved value (both ends should have same logic)
-- repeat the process until the resolved logic propagates both ways
-- eventually all wires in the chain will have the same resolved value

for N in 1 to chain_length*2 loop
ResolvedValue_v := Resolved((A, B));
A <= ResolvedValue_v;
B <= ResolvedValue_v;
wait for 0 ns;
end loop;
end if;
end process;
end behavior;


[ add comment ] ( 2775 views ) permalink ( 3 / 1607 )