OpenCores
URL https://opencores.org/ocsvn/vhld_tb/vhld_tb/trunk

Subversion Repositories vhld_tb

[/] [vhld_tb/] [trunk/] [examples/] [tb_code_snips.vhd] - Rev 23

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
--             Copyright 2011 Ken Campbell
--                        All Rights Reserved
-------------------------------------------------------------------------------
-- $Author: ken $
--
-- $date:  $
--
-- $Id:  $
--
-- $Source:  $
--
-- Description :
--          Code snipets from / for various VHDL Test Bench Facilities.
--
--   Contents:
--     Section 1:  Code from Usage Tips: Interrupts and Waiting.
--     Section 2:  Code from CPU emulation: some starter commands
--     Section 3:  Code for internal test bench implementation
--     Section 4:  Code for Verify commands
--
------------------------------------------------------------------------------
--  Redistribution and use in source and binary forms, with or without
--  modification, in whole or part, are permitted:
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
--###################################################################################
--  Section 1:  Interrupts and Waiting.
architecture bhv of tb_xxx is
--  ...
constant MAX_TIME : integer  :=  60000;
--  ...
 
Read_file : process
--  ...
    define_instruction(inst_list, "WAIT_IRQ", 0);
--  ...
--------------------------------------------------
     elsif (instruction(1 to len) = "WAIT_IRQ") then
        temp_int := 0;                               -- initialize counter
        while(dut_irq /= '1') then              -- while IRQ not asserted
           wait for clk'event and clk = '1';  -- wait for clock cycle
            temp_int := temp_int + 1;         --  add one to clock counter
            assert (temp_int /= MAX_TIME)  -- if count = max time  quit.
              report "Error:  Time out while waiting for IRQ!!"
            severity failure;
        end loop;
 
-------------------------------------------------------------------------------------------
    define_instruction(inst_list, "MAX_WAIT_SET", 1);
--  ...
--------------------------------------------------------
     elsif (instruction(1 to len) = "MAX_WAIT_SET") then
        MAX_TIME  <= par1;                               -- set the max
        wait for 0 ps;
 
architecture bhv of tb_xxx is
--  ...
  signal irq_expect :  boolean := false;
--  ...
Read_file : process
--  ...
    define_instruction(inst_list, "EXPECT_IRQ", 1);
--  ...
--------------------------------------------------------------------------------
     elsif (instruction(1 to len) = "EXPECT_IRQ") then
       if(par1 = 0) then
         irq_expect <= false;
       else
         irq_expect <= true;
       end if;
        wait for 0 ps;
--  ...
  end process Read_file;
 
------------------------
irq_mon:
  process(clk, dut_irq)
  begin
    -- on the falling edge, assume rising edge assertion, one clock wide
    if(clk'event and clk = '0') then
      if(dut_irq = '1') then
        if(irq_expect = true) then
            assert (false)
              report "NOTE:  An expected IRQ occurred."
            severity note;
        else
            assert (false)
              report "ERROR:  An unexpected IRQ occurred."
            severity failure;
        end if;
      end if;
    end if;
end process irq_mon;
--  END  Section 1:
--###################################################################################
 
 
-------------------------------------------------------------------------------------
--###################################################################################
--  Section 2:  CPU Emulation Commands
-- starting from the top of the bhv architecture
architecture bhv of xxx_tb is
  -- create type for cpu array of registers
  --  Type needed for CPU registers, it can be resized if needed
  type cpu_reg_array is array(0 to 7) of std_logic_vector(31 downto 0);
  -- optional constant to help test for zero
  constant zeros   : std_logic_vector(31 downto 0) := (others => '0');
--  ...
--  ...
  --------------------------------------------------------------------------
  Read_file: process
--  ...  variable definitions
  -------------------
  --  CCR def
  --   bit 0   zero, will be set when results are zero
  --   bit 1   equal, will be set when compared values are equal
  --   bit 2   greater than, will be set when source1 is > source2
  --   bit 3   less than, will be set when source1 is < source2
  --   others undefined
    variable v_reg_ccr    : std_logic_vector(7 downto 0);  -- condition code register
    variable v_regs       : cpu_reg_array;                 -- Create variable of cpu regs
    variable v_tmp_bit    : std_logic;                     -- nice place to store a bit temp
    variable v_read_data  : std_logic_vector(31 downto 0);
--  ...
  begin  -- process Read_file
--  ...
    define_instruction(inst_list, "READ_TO_REG", 2);
    define_instruction(inst_list, "REG_TO_VAR", 2);
    define_instruction(inst_list, "MOV", 2);
    define_instruction(inst_list, "MOVI", 2);
    define_instruction(inst_list, "AND", 3);
    define_instruction(inst_list, "ANDI", 3);
    define_instruction(inst_list, "OR", 3);
    define_instruction(inst_list, "NOT", 2);
    define_instruction(inst_list, "XOR", 3);
    define_instruction(inst_list, "SLL", 2);
    define_instruction(inst_list, "SLR", 2);
    define_instruction(inst_list, "CMP", 2);
    define_instruction(inst_list, "BE", 1);
    define_instruction(inst_list, "BZ", 1);
    define_instruction(inst_list, "BB", 4);
 
    ------------------------------------------------------------------------
    -- Read, test, and load the stimulus file
    read_instruction_file(stimulus_file, inst_list, defined_vars, inst_sequ,
                          file_list);
    -- initialize last info
    last_sequ_num  := 0;
    last_sequ_ptr  := inst_sequ;
    -- initialize  registers  -- this is the zering of the registers and CCR
    v_regs           := (others => (others => '0'));
    v_reg_ccr        := (others => '0');
--  ...
--------------------------------------------------------------------------
-- READ_TO_REG
--   Read a addressed location to the local register array
--     par1   address
--     par2   target reg (index)
    elsif(instruction(1 to len) = "READ_TO_REG") then
      v_temp_vec1     :=  std_logic_vector(conv_unsigned(par1, 32));
      STM_ADD   <=  v_temp_vec1;
      STM_DAT   <=  (others => 'Z');
      STM_RWN   <=  '1';
      wait for 1 ps;
      STM_REQ_N  <=  '0';
      wait until STM_ACK_N'event and STM_ACK_N = '0';
      STM_REQ_N  <=  '1';
      STM_ADD   <=  (others => 'Z');
      v_read_data  :=  STM_DAT;
      v_regs(par2)   :=  STM_DAT;
      STM_RWN   <=  '1';
      wait for 1 ps;
 
--------------------------------------------------------------------------
-- REG_TO_VAR
--  Write a register array value to a Variable.
--     par1   target reg (index)
--     par2   Variable to update with value from target reg
    elsif(instruction(1 to len) = "REG_TO_VAR") then
      temp_int  :=  to_uninteger(v_regs(par1));            --<< NEW to_uninteger conversion function
      update_variable(defined_vars, par2, temp_int, valid);
-- the to_uninteger function was added because to add the function through
--   std_developerskit overflowed my PE student simulator.  I am tired of
--   conversion and created my own function, tb_pkg contained.  see additional
--   code at the bottom of this section.  You can replace this with functions
--   you usually use, or use std_developerskit if you are on real tools.
--------------------------------------------------------------------------
-- MOV
--   Move one register contents to another register.  Source contents maintained
--     par1   reg1 index
--     par2   reg2 index
    elsif(instruction(1 to len) = "MOV") then
      v_regs(par2)  :=  v_regs(par1);
 
--------------------------------------------------------------------------
-- MOVI
--   Move value passed to destination register
--     par1   value
--     par2   reg index
    elsif(instruction(1 to len) = "MOVI") then
      v_regs(par2)  :=  std_logic_vector(conv_unsigned(par1, 32));
 
--------------------------------------------------------------------------
-- AND
--   AND two registers and write results to target register
--     par1   reg1 index
--     par2   reg2 index
--     par3   target results reg index
    elsif(instruction(1 to len) = "AND") then
      v_regs(par3)  :=  v_regs(par1) and v_regs(par2);
      if(v_regs(par3) = zeros) then
        v_reg_ccr(0) := '1';
      else
        v_reg_ccr(0) := '0';
      end if;
 
--------------------------------------------------------------------------
-- ANDI
--   AND the passed value with the indexed register and store in register index
--     par1   value
--     par2   reg index
--     par3   target results reg index
    elsif(instruction(1 to len) = "ANDI") then
      v_regs(par3)  :=  std_logic_vector(conv_unsigned(par1, 32)) and v_regs(par2);
      if(v_regs(par3) = zeros) then
        v_reg_ccr(0) := '1';
      else
        v_reg_ccr(0) := '0';
      end if;
 
--------------------------------------------------------------------------
-- OR
--   OR two registers and write results to target register
--     par1   reg1 index
--     par2   reg2 index
--     par3   target results reg index
    elsif(instruction(1 to len) = "OR") then
      v_regs(par3)  :=  v_regs(par1) or v_regs(par2);
      if(v_regs(par3) = zeros) then
        v_reg_ccr(0) := '1';
      else
        v_reg_ccr(0) := '0';
      end if;
 
--------------------------------------------------------------------------
-- XOR
--   XOR two registers and write results to target register
--     par1   reg1 index
--     par2   reg2 index
--     par3   target results reg index
    elsif(instruction(1 to len) = "XOR") then
      v_regs(par3)  :=  v_regs(par1) xor v_regs(par2);
      if(v_regs(par3) = zeros) then
        v_reg_ccr(0) := '1';
      else
        v_reg_ccr(0) := '0';
      end if;
 
--------------------------------------------------------------------------
-- NOT
--   NOT a register and write results to target register
--     par1   reg1 index
--     par2   target results reg index
    elsif(instruction(1 to len) = "NOT") then
      v_regs(par2)  :=  not v_regs(par1);
      if(v_regs(par2) = zeros) then
        v_reg_ccr(0) := '1';
      else
        v_reg_ccr(0) := '0';
      end if;
 
--------------------------------------------------------------------------
-- SLL
--   Shift the register left rotate the upper bits into the lower bits
--     par1   reg1 index
--     par2   bit positions to Left
    elsif(instruction(1 to len) = "SLL") then
      v_temp_vec1  :=  v_regs(par1);
      temp_int  := par2 - 1;
      v_regs(par1) :=  v_temp_vec1(31-par2 downto 0) & v_temp_vec1(31 downto 31 - temp_int);
 
--------------------------------------------------------------------------
-- SLR
--   Shift the register right rotate the lower bits into the upper bits
--     par1   reg1 index
--     par2   bit positions to Right
    elsif(instruction(1 to len) = "SLR") then
      v_temp_vec1  :=  v_regs(par1);
      temp_int  := par2 - 1;
      v_regs(par1) :=  v_temp_vec1(temp_int downto 0) & v_temp_vec1(31 downto par2);
 
--------------------------------------------------------------------------
-- CMP
--   Compare one register against another and set CCR bits, no effect on registers
--     par1   reg1 index source1
--     par2   reg2 index source2
    elsif(instruction(1 to len) = "CMP") then
      v_reg_ccr  :=  (others => '0');
      if(v_regs(par1) = v_regs(par2)) then
        v_reg_ccr(1)  :=  '1';
      elsif(v_regs(par1) > v_regs(par2)) then
        v_reg_ccr(2)  :=  '1';
      elsif(v_regs(par1) < v_regs(par2)) then
        v_reg_ccr(3)  :=  '1';
      end if;
 
      if(v_regs(par1) = zeros) then
        v_reg_ccr(1)  :=  '0';
      end if;
 
--------------------------------------------------------------------------
-- BE
--   Branch if equal
--     par1   jump location
    elsif(instruction(1 to len) = "BE") then
      if(v_reg_ccr(1) = '1') then
        v_line    :=  par1 - 1;
        wh_state  :=  false;
        wh_stack  := (others => 0);
        wh_dpth   := 0;
        wh_ptr    := 0;
        --stack     := (others => 0);
        --stack_ptr := 0;
      end if;
 
--------------------------------------------------------------------------
-- BZ
--   Branch if Zero
--     par1   jump location
    elsif(instruction(1 to len) = "BZ") then
      if(v_reg_ccr(0) = '1') then
        v_line    :=  par1 - 1;
        wh_state  :=  false;
        wh_stack  := (others => 0);
        wh_dpth   := 0;
        wh_ptr    := 0;
        --stack     := (others => 0);
        --stack_ptr := 0;
      end if;
 
--------------------------------------------------------------------------
-- BB
--   Branch if bit in register is set/clear
--     par1   register
--     par2   register bit index
--     par3   compare value : 0/1
--     par4   jump location
    elsif(instruction(1 to len) = "BB") then
      v_temp_vec1  :=  v_regs(par1);
      if(par3 = 0) then
        v_tmp_bit  := '0';
      else
        v_tmp_bit  := '1';
      end if;
      if(v_temp_vec1(par2) = v_tmp_bit) then
        v_line    :=  par4 - 1;
        wh_state  :=  false;
        wh_stack  := (others => 0);
        wh_dpth   := 0;
        wh_ptr    := 0;
        --stack     := (others => 0);
        --stack_ptr := 0;
      end if;
--  ...
  end process Read_file;
end bhv;
--  Stimulus_file commands used for testing.  I used no VERIFY command
--    as I watched the functionality in single stepping through code.
DEFINE_VAR dat x01
EQU_VAR dat x12345678
MASTR_WRITE 3 $dat
READ_TO_REG 3 0
OR 0 1 2
AND 0 2 1
MOV 1 3
XOR 0 1 4
NOT 4 5
SLL 0 1
SLL 1 2
SLL 2 3
SLL 3 4
SLR 0 1
SLR 1 2
SLR 2 3
SLR 3 4
MOVI x87654321 7
 
ANDI 0 0 0
BZ $B1
MOVI x1234678 0
 
B1:
CMP 1 2
BE $B2
MOVI 0 1
 
B2:
BB 0 0 1 $B3
BB 0 0 0 $B3  "Didnt jup as expected
MOVI 0 1
 
B3:
 
FINISH
 
--------------------------------------------------------------------------------
-- tb_pkg function
---   header section
-------------------------------------------------------------------------
--  convert a std_logic_vector to an unsigned integer
    function to_uninteger  ( constant vect     : in std_logic_vector
                         ) return integer;
--  body section
---------------------------------------------------------------------------------------
  function to_uninteger ( constant vect     : in std_logic_vector
                        ) return integer is
    variable result   : integer := 0;
    variable len      : integer := vect'length;
    variable idx      : integer;
    variable tmp_str  : text_field;
    variable file_name: text_line;
  begin
    -- point to start of string
    idx  :=  1;
    -- convert std_logic_vector to text_field
    for i in len - 1 downto 0 loop
      if(vect(i) = '1') then
        tmp_str(idx) := '1';
      elsif(vect(i) = '0') then
        tmp_str(idx) := '0';
      else
        assert(false)
          report LF & "ERROR:  Non 0/1 value found in std_logic_vector passed to to_uninteger function!!" & LF &
                "Returning 0."
        severity note;
        return result;
      end if;
      idx := idx + 1;
    end loop;
    -- call bin txt to int fuction with dummy fn and sequ idx
    result := bin2integer(tmp_str, file_name, idx);
    return result;
 
  end to_uninteger;
 
 
 
--  Section 2:  END
--###################################################################################
 
--
--###################################################################################
-- Section 3: Begin
--   This section presents the code needed to make an internal test bench
--     an optional compile item through the use of VHDL generics and generate
--     statements.
 
-- this is the top enity or at the level where you can assign the
--    en_bfm generic and it makes sense
entity my_top_dut is
  generic (
           g_en_bfm  :  integer :=  0
          );
  port (
     --  top port definitions
       );
end enity my_top_dut;
 
 
architecture struct of my_top_dut is
-- this is the component of an internal block of my_top_dut
component rtl_block
  port (
        reset_n  : in      std_logic;
        clk_in   : in      std_logic;
        -- ...
       );
end component;
-- bhv_block has the same pin out as rtl_block, except for the generic
component bhv_block
  generic (
           stimulus_file: in string
          );
  port (
        reset_n  : in      std_logic;
        clk_in   : in      std_logic;
        -- ...
       );
end component;
--....
begin
  -- if generic is default value, include rtl
  if(g_en_bfm = 0) generate
  begin
    rtl_b1: rtl_block
      port map(
            reset_n  =>  reset_n,
            clk_in   =>  clk,
            -- ...
           );
  end generate;
  -- if generic is set for bhv, include it
  if(g_en_bfm = 1) generate
  begin
    bfm: bhv_block
      generic map(
                  stimulus_file => "stm/stimulus_file.stm"
                 )
      port map(
            reset_n  =>  reset_n,
            clk_in   =>  clk,
            -- ...
           );
  end generate;
-- ...
end struct;
 
--  Section 3 End:
--###################################################################
 
--####################################################################
--  Section 4 Start:
--    This section provides some example VERIFY commands.
  --------------------------------------------------------------------------
  Read_file: process
  --  ...
    variable v_tmp_bit    : std_logic;
    variable v_upb        : integer := 31;  -- upper bounds
    variable v_lob        : integer := 0;  -- lower bounds
    variable v_temp_read  : std_logic_vector(31 downto 0);
  --  ...
    define_instruction(inst_list, "SLICE_SET", 2);
    define_instruction(inst_list, "VERIFY", 1);
    define_instruction(inst_list, "VERIFY_BIT", 2);
    define_instruction(inst_list, "VERIFY_SLICE", 1);
  --  ...
 
 
-----------------------------------------------------------------------------
--  SLICE_SET     set the slice of the data for testing
--     par1       upper bound value  -  must be larger than par2 and less than 32
--     par2       lower bound value
   elsif (instruction(1 to len) = "SLICE_SET") then
     -- test user input.
     assert (par1 < 32 and par1 >= 1)
       report LF & "ERROR:  Par1 in SLICE_SET command input range is out of bounds" & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
     severity failure;
     assert (par2 < 31 and par2 >= 0)
       report LF & "ERROR:  Par2 in SLICE_SET command input range is out of bounds" & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
     severity failure;
     assert (par1 > par2)
       report LF & "ERROR: SLICE_SET command bounds incorrectly defined. Par1 must be greater than Par2." & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
     severity failure;
     -- update variables
     v_upb  :=  par1;
     v_lob  :=  par2;
 
-----------------------------------------------------------------------------
--  VERIFY    test that the data in temp_read is the passed value.
--      par1  value to test against.
   elsif (instruction(1 to len) = "VERIFY") then
     v_temp_vec1     :=  std_logic_vector(conv_unsigned(par1, 32));
 
     assert (v_temp_vec1 = v_temp_read)
       report LF & "ERROR: VERIFY command compare value was not as expected!!" &
         LF & "Got " & (to_hstring(v_temp_read)) &
         LF & "Expected " & (to_hstring(v_temp_vec1)) & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
      severity failure;
 
-----------------------------------------------------------------------------
--  VERIFY_BIT    test that the data bit in temp_read is the passed value.
--      par1  index into 32 bit temp_read
--      par2  bit value
   elsif (instruction(1 to len) = "VERIFY_BIT") then
     assert (par1 >= 0 and par1 < 32)
       report LF & "ERROR: VERIFY_BIT command bit index is out of range. Valid is 0 - 31." & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
     severity failure;
     if(par2 = 0) then
         v_tmp_bit := '0';
     else
         v_tmp_bit := '1';
     end if;
     assert (v_temp_read(par1) = v_tmp_bit)
       report LF & "ERROR: VERIFY_BIT command miss-compare!" & LF &
        "We tested for " & (integer'image(par2)) & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
     severity failure;
 
-----------------------------------------------------------------------------
--  VERIFY_SLICE    test that the data in temp_read is the passed value.
--      par1   value
   elsif (instruction(1 to len) = "VERIFY_SLICE") then
     v_temp_vec1  :=  (others => '0');
     temp_int   :=  v_upb - v_lob + 1;
     v_temp_vec1(v_upb downto v_lob)     :=  std_logic_vector(conv_unsigned(par1, temp_int));
     -- no need to test ranges here
     assert (v_temp_vec1(v_upb downto v_lob) = v_temp_read(v_upb downto v_lob))
       report LF & "ERROR: VERIFY_SLICE Compare Value was not as expected!!" &
         LF & "Got " & (to_hstring(v_temp_read(v_upb downto v_lob))) &
         LF & "Expected " & (to_hstring(v_temp_vec1(v_upb downto v_lob))) & LF &
        "Found on line " & (integer'image(file_line)) & " in file " & file_name
      severity failure;
 
--  END Section 4
--#######################################################################################

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.