-- $Source: /evtfs/home/tres/vhdl/ref_design/RCS/test_uart.vhd,v $
-- $Revision: 1.37 $  $Date: 2006/08/10 17:32:40 $
-------------------------------------------------------------------------------
-- Synchronous Procedural Coding Style for Simulation  Example: test_uart
-- Tue Feb  8 13:49:01 2005           Mike Treseler
-------------------------------------------------------------------------------
-- This source file will be maintained for a while at
--   http://home.comcast.net/~mike_treseler/test_uart.vhd
-- This vhdl code example is a simulation testbench for the design entity:
--   http://home.comcast.net/~mike_treseler/uart.vhd
-------------------------------------------------------------------------------
-- This vhdl code example demonstrates a synchronous testbench coding
-- style using small, well-named procedure declarations to support the
-- main process shown as a comment below:
-------------------------------------------------------------------------------
--   constant reps : natural := 16;
--   begin  -- process main
--      init;
--      for i in 1 to reps loop
--         timed_cycle;
--      end loop;
--      for i in 1 to reps loop
--         handshake_cycle;
--      end loop;
--      coda;
--   end process main;
-------------------------------------------------------------------------------
-- This testbench contains an instance process named DUT, a fixed
-- stimulus process named TB_CLK and a MAIN process to provide
-- stimulus and verification procedures. Start reading from the end of
-- this file for a "top-down" view of the testbench. All functions and
-- procedures are intended to be short enough that their purpose is
-- obvious but long enough to be useful and nameable. Procedures
-- access testbench object directly, without parameters in most cases.
-------------------------------------------------------------------------------
-- Modelsim commands:
-- run assertions only:                vsim -c test_uart -do "run -all; exit"
-- force an error 116: vsim -Gwire_g=random -c test_uart -do "run -all; exit"
-- force an error 0: vsim -Gwire_g=stuck_hi -c test_uart -do "run -all; exit"
-- change template: vsim -Gtemplate_g=s_rst -c test_uart -do "run -all; exit"
-- slow baud:           vsim -Gtb_tics_g=42 -c test_uart -do "run -all; exit"
-- run with waves:               vsim test_uart -do uart.do
-- verify strobe calibration:    vsim -Gtb_tics_g=42 test_uart
--                          then "do uart.do" from modelsim prompt
-------------------------------------------------------------------------------
--# http://home.comcast.net/~mike_treseler/uart.do
-- set this uart
-- set mydesign $this
-- set mytb test_$this
-- echo Assuming [pwd] is the right directory.
-- vdel -all ;# clean last compilation
-- vlib work
-- vmap work work
-- vcom $mydesign.vhd $mytb.vhd
-- restart -f ;# so I can use this same script to rerun
-- radix hex; ;# Make bus values easy to read
-- add wave *                 ;# Signals
-- add wave /$mytb/main/*     ;# Test variables
-- add wave /$mytb/dut/main/* ;# UUT  variables
-- run -all;
-- # Make wave window readable
-- WaveRestoreCursors {{Cursor 1} {194 ns} 0}
-- configure wave -namecolwidth 277
-- WaveRestoreZoom {178 ns} {281 ns}
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.uart_pkg.all; -- see top of uart.vhd: flag_t, t_rdy_c, r_rdy_c,r_err_c
-------------------------------------------------------------------------------
entity test_uart is
   generic (tb_tics_g : natural := 3;
            tb_char_g : natural := 8;  -- generic type
            verbose_g : boolean := true;
            template_g: template_t := v_rst;            
            wire_g    : wire_t := loopback);
                     -- wire_t (loopback, stuck_hi, stuck_low, random);   
end entity test_uart;
-------------------------------------------------------------------------------
architecture sim of test_uart is
   
   -- signals and other declarations visible to all processes go here:
   constant msb : natural := tb_char_g -1;
   subtype  char_t is unsigned(msb downto 0);  -- generic type, usually 8 bits
   subtype  byte_t is unsigned(7 downto 0);    -- static type,   always 8 bits   
   constant zero_c : char_t := (others => '0');
   constant seed_c      : char_t  := "100001" + zero_c;  -- works for any width
   constant exit_loop_c : natural := 1000;   -- used on init and wait_for_rx
   constant clk_cy      : time    := 10 ns;  -- used on tb_clk and timed_cycle
-------------------------------------------------------------------------------
   -- instance wires
   signal address_s     : std_ulogic;                     -- [in]
   signal writeData_s   : std_logic_vector(msb downto 0); -- [in]
   signal write_stb_s   : std_ulogic;                     -- [in]
   signal readData_s    : std_logic_vector(msb downto 0); -- [out] by uut
   signal read_stb_s    : std_ulogic;                     -- [in]
   signal serialIn_s    : std_ulogic;                     -- [in]  by main
   signal serialOut_s   : std_ulogic;                     -- [out] by uut
-------------------------------------------------------------------------------
   -- testbench wires:
   signal done_s        : boolean;           -- stops all processes
   signal clk_s         : std_ulogic;        -- sim clock
   signal rst_s         : std_ulogic;        -- sim reset
   signal random_byte_s : char_t := seed_c;  -- sorta random byte every tic
   signal ref_count_s   : natural:= 0;       -- new count every tic   

-------------------------------------------------------------------------------
begin  -- architecture sim
   dut : entity work.uart
     generic map (char_len_g    => tb_char_g, -- for vsim command line overload
                  tic_per_bit_g => tb_tics_g)
      port map (
         clock     => clk_s,        -- [in] -- by tb_clk
         reset     => rst_s,        -- [in] -- by tb_clk
         address   => address_s,    -- [in] -- by main
         writeData => writeData_s,  -- [in] -- by main
         write_stb => write_stb_s,  -- [in] -- by main
         readData  => readData_s,   -- [out]-- by uut
         read_stb  => read_stb_s,   -- [in] -- by main
         serialIn  => serialIn_s,   -- [in] -- by main,loopback destination
         serialOut => serialOut_s   -- [out]-- by uut, loopback source
         );
-------------------------------------------------------------------------------
   tb_clk : process is  -- clock, reset, and full clock rate procedures
-------------------------------------------------------------------------------
      constant rst_time            : time   := 10*clk_cy;
      constant mask_c              : char_t := "111" + zero_c;
      variable serialIn_v          : std_ulogic;  -- loopback variable      
-------------------------------------------------------------------------------
      function randomize (arg_byte : char_t)
         return char_t is
         variable result_v : char_t;
      begin
         result_v := arg_byte;                    -- here it is
         result_v := shift_left(result_v, 1);     -- shift it
         if (result_v(result_v'left)) = '1' then  -- maybe invert mask bits
            result_v := result_v xor mask_c;
         end if;
         return result_v;
      end function randomize;
-------------------------------------------------------------------------------
      impure function loopback_mux (wire_arg : wire_t)
         return std_ulogic is
         variable ret_v : std_ulogic;         
      -- Purpose: Select serialIn from the serial output (loopback) or
      -- use error values to verify that this testbench handles errors
      -- cleanly. The loopback mux was a separate process before rev
      -- 1.28, but is now combined with the tb_clk fixed_stim procedure.
      begin 
         case wire_arg is                                 -- First Reading
            when loopback  => ret_v := serialOut_s;       --  36
            when stuck_low => ret_v := '0';               --   0
            when stuck_hi  => ret_v := '1';               --   0
            when random    => ret_v := random_byte_s(0);  -- 116
            when others    => ret_v := serialOut_s;       -- none
            -- others won't elaborate, out of wire_t range 0 to 3.
         end case;
         return ret_v;
      end function loopback_mux;
-------------------------------------------------------------------------------
      procedure fixed_stim is
      begin
         random_byte_s <= randomize(random_byte_s);
         ref_count_s   <= ref_count_s+1;
         serialIn_s    <= loopback_mux(wire_g);          
      end procedure fixed_stim;
-------------------------------------------------------------------------------
   begin  -- process tb_clk
      clk_s <= '0';
      if now < rst_time then
         rst_s <= '1';             -- rst once with clk running
      else
         rst_s <= '0';             -- then low forever
      end if;
      if done_s then wait; end if; -- Stop clock
      wait for clk_cy/2;           -- clock low
      clk_s <= '1';
      fixed_stim;                  -- auxiliary output from tb_clk process
      wait for clk_cy/2;           -- clock high
   end process tb_clk;
-------------------------------------------------------------------------------
   main : process is                -- synchronized using procedure "tic" below
-------------------------------------------------------------------------------
      variable step_v   : natural;      -- verification step
      variable expect_v : char_t;       -- expected value
      variable match_v  : boolean;      -- this match
      variable pass_v   : boolean;      -- all match so far
-------------------------------------------------------------------------------
      procedure tic is
      begin
         wait until rising_edge(clk_s);
      end procedure tic;
-------------------------------------------------------------------------------
      procedure set_bit (signal arg_s : inout std_ulogic) is
      begin-- skip tic if already set
         if arg_s /= '1' then
            arg_s <= '1';
            tic;
         end if;
      end procedure set_bit;
-------------------------------------------------------------------------------
      procedure clr_bit (signal arg_s : inout std_ulogic) is
      begin  -- skip tic if already clear
         if arg_s /= '0' then
            arg_s <= '0';
            tic;
         end if;
      end procedure clr_bit;
-------------------------------------------------------------------------------
      procedure toggle (signal arg_s : inout std_ulogic) is
      begin
         clr_bit(arg_s); -- costs no time if already low
         set_bit(arg_s);
         clr_bit(arg_s);
      end procedure toggle;
-------------------------------------------------------------------------------
      procedure results is
      begin
         if pass_v then
            report "___ALL PASS___";
         else
            report "____FAILED_____";
         end if;
      end procedure results;
-------------------------------------------------------------------------------
      procedure coda is
      begin
         results;
         done_s <= true;
         tic;
         wait;
      end procedure coda;
-------------------------------------------------------------------------------
      procedure die is
      begin
         pass_v := false;
         coda;
      end procedure die;
-------------------------------------------------------------------------------
      procedure nop is
      begin
         address_s   <= '0';
         read_stb_s  <= '0';
         writedata_s <= (others => '0');
         write_stb_s <= '0';
         tic;
      end procedure nop;      
-------------------------------------------------------------------------------
      constant fixed_tics_c  : natural := 3 * (tb_char_g + 4) * tb_tics_g;
                               -- fixed delay adjusted for baud rate
      constant fixed_delay_c : time := fixed_tics_c * clk_cy;            
      procedure init is
         variable width_v : natural;
      begin
         width_v  := 0;
         step_v   := 0;
         pass_v   := true;
         expect_v := (others => '0');
         nop;
         ck_rst : for i in 1 to exit_loop_c loop
            if i = exit_loop_c then
               report "Gave up waiting for reset" severity error;
               die;
            end if;
            if rst_s = '1' then         -- wait for end of reset
               tic;
               width_v := width_v + 1;
            elsif width_v > 0 then      -- reset done
               report "Saw reset rise and fall OK";
               report "Using fixed_delay_c = " & time'image(fixed_delay_c)
                    & " That's " & natural'image(fixed_tics_c) & " ticks.";
               exit ck_rst;
            end if;
         end loop ck_rst;
      end procedure init;
-------------------------------------------------------------------------------
      procedure verify is
         type     string_p is access string;
         variable string_v : string_p;
      begin
         string_v := new string'(integer'image(to_integer(expect_v)));
         report "___Step " & integer'image(step_v);
         match_v  := expect_v = unsigned(readData_s);  -- expected value?
         pass_v   := pass_v and match_v;               -- all ok so far?
         step_v   := step_v + 1;
         ck : if match_v then
            boring : if verbose_g then
               report "____________ saw " & string_v.all & " as expected";
            end if boring;
         else
            report "_____________Expected byte is   " & string_v.all;
            report "_____________Actual bus data is "
               & integer'image(to_integer(unsigned(readData_s)))
               severity error;
            report "________________________________________WIRE STATE IS "
               & wire_t'image(wire_g);
            die;
         end if ck;
      end procedure verify;
-------------------------------------------------------------------------------
      procedure read_data is
      begin
         clr_bit(address_s);
         toggle(read_stb_s);
         verify;               -- data is valid now for one clock period
      end procedure read_data;
-------------------------------------------------------------------------------     
      subtype  flag_t is natural range char_t'range;
--   +----------------------------------------+
--   |    Table 1 UART Memory Map             |
--   +------+-----+-----+----------+----------+
--   |Name  |Add  |R/W  |Data      |Comment   |
--   +------+-----+-----+----------+----------+
--   |TXQ   |0    |W    |7_downto_0| Transmit |
--   |      |     |     |          | Data     |
--   +------+-----+-----+----------+----------+
--   |RXQ   |0    |R    |7_downto 0| Receive  |
--   |      |     |     |          | Data     |
--   +------+-----+-----+----------+----------+
--   |StatQ |1    |R    |2->TxReady| Status   |
--   |      |     |     |1->RxError| Data     |
--   |      |     |     |0->RxReady|          |
--   +------+-----+-----+----------+----------+

-- note: valid_handshake_c has been replaced with named readData_s
-- bits in rev 1.36
-------------------------------------------------------------------------------      
      procedure read_status is -- see package uart_pkg top of uart.vhd
      begin
         set_bit(address_s);
         toggle(read_stb_s);
         good_stop_bit:assert readData_s(r_err_c) = '0' 
            report "_____________Stop Bit Failure" severity error;
         -- don't die until next verify
      end procedure read_status;
-------------------------------------------------------------------------------
      procedure wait_for_rx is
      begin  -- example of handshake delay;
         handshake : for i in 1 to exit_loop_c loop
            read_status;
            if readdata_s(r_rdy_c) = '1' and readdata_s(r_err_c) = '0'
            then
               -- report "rx arbitration tics = "&integer'image(i);  -- 16             
               exit handshake;
            elsif i = exit_loop_c then
               report "wait_for_rx:  Tired of waiting. Handshake error."
                  severity error;
               die;
            end if;
         end loop handshake;
      end procedure wait_for_rx;
 -------------------------------------------------------------------------------
      procedure wait_for_tx is
      begin  -- example of handshake delay;
         handshake : for i in 1 to exit_loop_c loop
            read_status;
            if readdata_s(t_rdy_c) = '1' then
               -- report "tx arbitration tics = "&integer'image(i); -- 1
               exit handshake;
            elsif i = exit_loop_c then
               report "wait_for_tx: Tired of waiting. Handshake error."
                  severity error;
               die;
            end if;
         end loop handshake;
      end procedure wait_for_tx;     
-------------------------------------------------------------------------------     
       procedure write_data is
      begin
         expect_v    := random_byte_s;
         address_s   <= '0';
         writedata_s <= std_logic_vector(expect_v);
         tic;
         toggle(write_stb_s);
      end procedure write_data;
-------------------------------------------------------------------------------
      procedure timed_cycle is
      begin  -- example of waiting instead of handshaking
         write_data;
         wait for fixed_delay_c;  -- example of wasting time between cycles         
---------wait for 10*clk_cy; -- example of reading too soon, reads 4 for 36
         tic;                  -- synchronize delay
         read_status;          -- check stop bit
         read_data;
      end procedure timed_cycle;
-------------------------------------------------------------------------------
      procedure handshake_cycle is
      begin  -- example of handshaking loopback data
         wait_for_tx;
         write_data;
         wait_for_rx;
         read_data;
      end procedure handshake_cycle;
-------------------------------------------------------------------------------
      constant reps : natural := 8;
   begin  -- process main: Top level loop invokes top procedures.
      init;
      for i in 1 to reps loop
         timed_cycle;         
      end loop;
      for i in 1 to reps loop
         handshake_cycle;
      end loop;      
      coda;
   end process main;  -- that's it

end architecture sim;


<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>