------------------------------------------------------------------------------
-- http://home.comcast.net/~mike_treseler/oe_demo.vhd -- this file
-- http://home.comcast.net/~mike_treseler/oe_demo.pdf -- sim waves
-- Testbench Example for bidirectional port.
-- oe_demo.vhd
-- Updated Wed Nov  2 11:07:46 2005   Mike Treseler
------------------------------------------------------------------------------
---- Modelsim commands
--   1. TEXT ASSERTIONS:
-- vsim -c test_oe_demo -do "run -all; exit"
--   2. DEBUG WAVES
-- vsim test_oe_demo -do "add wave *;add wave /test_oe_demo/simulation/*;run -all"
--  Note: By specifying the process name, you get the variables ^^^^
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
package oe_demo_package is
   procedure print (
      str1 : in string := ""; -- all args are optional
      str2 : in string := "";
      str3 : in string := "";
      str4 : in string := ""      
      );
   -- Shared constants go here:
   subtype  reg is std_logic_vector (7 downto 0);
   constant dummy_reg  : reg        := x"3e";
   constant dummy_dat  : reg        := x"81";
   constant active     : std_ulogic := '1';
   constant clk_period : time       := 40 ns;
   constant rst_period : time       := 2*clk_period;
   constant sim_limit  : time       := 100 us;
end package oe_demo_package;
-------------------------------------------------------------------------------
use std.textio.write;
package body oe_demo_package is
   procedure print (
      str1 : in string := "";
      str2 : in string := "";
      str3 : in string := "";      
      str4 : in string := ""
      )
   is
      constant newline_c : string := (1 => LF);
      constant tab_c     : string := "   ";
      constant message_c : string := newline_c & tab_c
                                     & str1 & str2 & str3 & str4;
   begin
      write(std.textio.output, message_c);
   end procedure print;
end package body oe_demo_package;
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.oe_demo_package.all;
-- Simplified Device Under Test
entity oe_demo is
   port
      ( reset : in    std_ulogic;
        clock : in    std_ulogic;
        data  : inout std_logic_vector (7 downto 0);
        ready : out   std_ulogic;
        oe    : in    std_ulogic );
end oe_demo;
-------------------------------------------------------------------------------
architecture synth of oe_demo is
begin
   bidir : process (clock, reset) is
   begin  -- process bidir
      clked : if reset = active then
         data  <= (others => 'Z');
         ready <= not active;
      elsif rising_edge(clock) then
         enable : if oe = active then
            data  <= dummy_reg;
            ready <= active;
         else
            data  <= (others => 'Z');
            ready <= not active;
         end if enable;
      end if clked;
   end process bidir;
end architecture synth;
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.oe_demo_package.all;
-- Testbench
entity test_oe_demo is
end entity test_oe_demo;
-------------------------------------------------------------------------------
architecture sim of test_oe_demo is
   -- Testbench wires go here
   signal reset_s         : std_ulogic;                     -- [in]
   signal clock_s         : std_ulogic;                     -- [in]
   signal data_s          : std_logic_vector (7 downto 0);  -- [inout]
   signal ready_s         : std_ulogic;                     -- [in]
   signal oe_s            : std_ulogic;                     -- [in]
   signal we_s            : std_ulogic;
   shared variable done_v : boolean := false;
begin
   -- Device under test instance
   oe_demo_1 : entity work.oe_demo
      port map (reset => reset_s,     -- [in]
                clock => clock_s,     -- [in]
                data  => data_s,      -- [inout]
                ready => ready_s,     -- [out]
                oe    => oe_s);       -- [in]
-------------------------------------------------------------------------------
   -- clock and reset generator
   tb_clk : process is
   begin
      done : if now > sim_limit or done_v then
         wait;
      end if done;
      rst : if now < rst_period then
         reset_s <= active;
      else
         reset_s <= not active;
      end if rst;
      clock_s <= not active;
      wait for clk_period/2;
      clock_s <= active;
      wait for clk_period/2;
   end process tb_clk;
-------------------------------------------------------------------------------
   simulation : process (clock_s, reset_s) is
      type     op_t is (idle, get, put);
      type     script_t is array (1 to 9) of op_t;
      constant script : script_t :=
         (1      => idle,
          2      => get,
          3      => idle,
          4      => idle,
          5      => put,
          others => idle);
      variable step   : natural;
      variable op_now : op_t;
   begin  -- process bidir
      clked : if reset_s = active then
         print("reset = ", std_ulogic'image(reset_s),
               "at ", time'image(now));
         step   := 1;
         oe_s   <= not active;
         we_s   <= not active;
         data_s <= (others => 'Z');
         oe_s   <= not active;
      elsif rising_edge(clock_s) then
         done_v :=  step > script'length;
         enable : if not done_v then
            op_now := script(step);
            print("op ", op_t'image(op_now) );
            stim: case op_now is
               when idle =>
                  we_s   <= not active;
                  oe_s   <= not active;
                  data_s <= (reg'range => 'Z');
               when get =>
                  we_s   <= not active;
                  oe_s   <= active;
                  data_s <= (reg'range => 'Z');
               when put =>
                  we_s   <= active;
                  oe_s   <= not active;
                  data_s <= dummy_dat;
               when others =>
                  oe_s   <= not active;
                  data_s <= (reg'range => 'Z');
            end case stim;
-------------------------------------------------------------------------------
            ck_write: if we_s = active then
               print(time'image(now), " Write Verification");
               assert data_s = dummy_dat;
            end if ck_write;

            ck_read: if ready_s = active then
               print(time'image(now), " Read Verification");
               assert data_s = dummy_reg;
               -- assert data_s = dummy_dat; -- uncomment to force error
            end if ck_read;
-------------------------------------------------------------------------------
            step := step + 1; -- step counter
         end if enable;
      end if clked;
   end process simulation;
end architecture sim;
-------------------------------------------------------------------------------