LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE STD.TEXTIO.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;



-- The following VHDL code is a testbench for the VHDL design
-- described in the QEX magazine article "Modern Digital Design 
-- for the Radio Amateur".

-- Written by John Wiseman - KE3QG.
-- Last Updated - June 1997.

-- This is based on a testbench program originally written
-- by Topdown Design Solutions of Nashua NH, and it works quite
-- well for this purpose.




ENTITY qex_tb is

END qex_tb;



ARCHITECTURE dds_interface_test1 OF qex_tb IS  

  -- Constants are defined here.  The file_name must be the file
  -- containing the test vectors.  Clk_period is the desired period
  -- for the main input clock (1.0 MHz. in this design).  It is
  -- desirable to use continue_time so that a long simulation will
  -- cleanly stop on its own if left unattended.  

  CONSTANT file_name:            STRING := "stim_dds_interface.txt";
  CONSTANT clk_period:           TIME := 1000 ns;
  CONSTANT clk_start:            TIME := 1000 ns;
  CONSTANT continue_time:        TIME := 30000 ms;
  SIGNAL Done:                   BOOLEAN := FALSE;
  
  -- These are the port names for the design that is to 
  -- be tested with this testbench.

  COMPONENT qex
    PORT(Clock:                  IN  BIT;
         Reset:                  IN  BIT;
         Fine_Tuning:            IN  BIT;
         Up:                     IN  BIT;
         Down:                   IN  BIT;
         DDS_Strobe:             OUT BIT_VECTOR (0 TO 3);
         Timer_Output:           OUT BIT;
         DDS_Data_Out:           OUT UNSIGNED (7 DOWNTO 0);
         Serial_Data_Output:     OUT STD_LOGIC;
         Serial_Clock_Output:    OUT BIT;
         CS_Output:              OUT BIT
         );
  END COMPONENT;
  
  -- New signals must be defined that can be bound to the
  -- ports of the design to be tested.  A simple solution 
  -- is to just place a new character (such as A...) before
  -- the original port names.

  SIGNAL A_Clock:                BIT;
  SIGNAL A_Reset:                BIT;
  SIGNAL A_Fine_Tuning:          BIT;
  SIGNAL A_Up:                   BIT;
  SIGNAL A_Down:                 BIT;
  SIGNAL A_DDS_Strobe:           BIT_VECTOR (0 TO 3);
  SIGNAL A_Timer_Output:         BIT;
  SIGNAL A_DDS_Data_Out:         UNSIGNED (7 DOWNTO 0);
  SIGNAL A_Serial_Data_Output:   STD_LOGIC;
  SIGNAL A_Serial_Clock_Output:  BIT;
  SIGNAL A_CS_Output:            BIT;



BEGIN

  -- Here is the new port map for the simulation.
  -- These are the I/O names that are displayed in
  -- the simulation waveform output window.

  u1:qex
     PORT MAP(A_Clock,
              A_Reset,
              A_Fine_Tuning,
              A_Up,
              A_Down,
              A_DDS_Strobe,
              A_Timer_Output,
              A_DDS_Data_Out,
              A_Serial_Data_Output,
              A_Serial_Clock_Output,
              A_CS_Output
             );



  stimulator:
  PROCESS
  
  -- This process reads 6 parameters from the external
  -- stim_file (stim_dds_interface.txt).  It first reads
  -- the line to see if it contains anything.  If so,
  -- then the time, reset, up, down, and tune information
  -- will be read and assigned to variables, which will
  -- in turn be assigned to input signals.

    FILE stim_file:text IS IN file_name; 
    VARIABLE l:             LINE;
    VARIABLE time_var:      TIME;
    VARIABLE reset_var:     BIT;
    VARIABLE up_var:        BIT;
    VARIABLE down_var:      BIT;
    VARIABLE tune_var:      BIT;
 
  BEGIN
  
  -- If there is information on the file line, then read
  -- in the time, reset, up, down, and fine tuning values
  -- and assign them to the appropriate variables.
  
  -- Then assign these variables to the appropriate input
  -- signals as the stimuli for the simulation.

    WHILE NOT ENDFILE(stim_file) LOOP
      READLINE(stim_file,l);
      IF l'LENGTH > 0 THEN
        READ(l,time_var);
        READ(l,reset_var);
        READ(l,up_var);
        READ(l,down_var);
        READ(l,tune_var);
        WAIT FOR time_var - now;
        A_Reset <= reset_var;
        A_up <= up_var;
        A_down <= down_var;
        A_fine_tuning <= tune_var;
      END IF;
    END LOOP;
    ASSERT FALSE REPORT "This is the end of the stimulation file."
        SEVERITY note;
    done <= true;
    WAIT;
  END PROCESS stimulator;



  clock:
  PROCESS
  
  -- This process generates the clock for the testbench program.

    VARIABLE done_time : time;

  BEGIN

    A_clock <= '0';
    WAIT FOR clk_start;
    WHILE NOT DONE LOOP
      A_clock <= '1';
      WAIT FOR clk_period/2;
      A_clock <= '0';
      WAIT FOR clk_period/2;
    END LOOP;
    done_time := now+continue_time;
    WHILE now < done_time LOOP
      A_clock <= '1';
      WAIT FOR clk_period/2;
      A_clock <= '0';
      WAIT FOR clk_period/2;
    END LOOP;
    WAIT;
  END PROCESS clock;
  
  

END dds_interface_test1;



-- Given here is an example stimulation file, or
-- test vector file.  This one is quite simple, and
-- consists of (from the left column) time, reset,
-- up, down, and fine tuning controls.

-- These values come from the file "stim_dds_interface.txt".

--   0  ns       1  1  1  0
--   5  ms       1  1  1  0
-- 400  ms       1  1  0  0
-- 600  ms       1  1  0  0
-- 700  ms       1  1  0  0
-- 800  ms       1  1  0  1
-- 1400 ms       1  0  1  1
-- 5000 ms       1  1  1  1

