LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

ENTITY TEST_CONTROL IS
END TEST_CONTROL;

ARCHITECTURE TB OF TEST_CONTROL IS
  COMPONENT CONTROL
	PORT(RUN: IN STD_LOGIC;
			 RESETN: IN STD_LOGIC;
			 INS: IN STD_LOGIC_VECTOR(0 TO 8); -- TO OR DOWNTO?
			 CNT: IN STD_LOGIC_VECTOR(1 DOWNTO 0);
			 A_IN: OUT STD_LOGIC;
			 CLR: OUT STD_LOGIC;
			 DONE: OUT STD_LOGIC;
			 DIN_OUT: OUT STD_LOGIC;
			 G_IN: OUT STD_LOGIC;
			 G_OUT: OUT STD_LOGIC;
			 IR_IN: OUT STD_LOGIC;
			 R_IN: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
			 R_OUT: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- TO OR DOWNTO?
			 ADDSUB: OUT STD_LOGIC);
  END COMPONENT;

  SIGNAL T_RUN: STD_LOGIC;
  SIGNAL T_RESET: STD_LOGIC;
  SIGNAL T_INS: STD_LOGIC_VECTOR (0 TO 8);
  SIGNAL T_CNT: STD_LOGIC_VECTOR (1 DOWNTO 0);
  SIGNAL T_A_IN: STD_LOGIC;
  SIGNAL T_CLR: STD_LOGIC;
  SIGNAL T_DONE: STD_LOGIC;
  SIGNAL T_DIN_OUT: STD_LOGIC;
  SIGNAL T_G_IN: STD_LOGIC;
  SIGNAL T_G_OUT: STD_LOGIC;
  SIGNAL T_IR_IN: STD_LOGIC;
  SIGNAL T_R_IN: STD_LOGIC_VECTOR (7 DOWNTO 0);
  SIGNAL T_R_OUT: STD_LOGIC_VECTOR (7 DOWNTO 0);
  SIGNAL T_ADDSUB: STD_LOGIC;
  
BEGIN
  U_CONTROL: CONTROL PORT MAP (T_RUN, T_RESET, T_INS, T_CNT, T_A_IN, T_CLR, T_DONE, T_DIN_OUT, T_G_IN, T_G_OUT, T_IR_IN, T_R_IN, T_R_OUT, T_ADDSUB);
  PROCESS
    VARIABLE ERR_CNT: INTEGER := 0;
  BEGIN
    
  -- SETUP
    T_RUN <= '1';
    T_RESET <= '0';
    T_CNT <= "00";
   
  --CASE 1: A MV INSTRUCTION
  -- MOVE CONTENTS OF R7 TO R4
    T_INS <= "000100111";  
    WAIT FOR 1 NS;
    T_CNT <= "01";
    WAIT FOR 1 NS;
    ASSERT (T_R_OUT(7)='1') REPORT "ERROR1A!" SEVERITY ERROR;
    IF (T_R_OUT(7)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_R_IN(4)='1') REPORT "ERROR1B!" SEVERITY ERROR;
    IF (T_R_IN(4)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_DONE='1') REPORT "ERROR1C!" SEVERITY ERROR;
    IF (T_DONE/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    WAIT FOR 10 NS;
    
  --CASE 2: A MVI INSTRUCTION
  -- MOVE THE NUMBER 3 TO R3
    T_CNT <= "00";
    T_INS <= "001011---";  
    WAIT FOR 1 NS;
    T_CNT <= "01";
    WAIT FOR 1 NS;
    ASSERT (T_R_IN(3)='1') REPORT "ERROR2A!" SEVERITY ERROR;
    IF (T_R_IN(3)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    WAIT FOR 1 NS;
    T_CNT <= "10";
    WAIT FOR 1 NS;
    ASSERT (T_DIN_OUT='1') REPORT "ERROR2B!" SEVERITY ERROR;
    IF (T_DIN_OUT/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_DONE='1') REPORT "ERROR2B!" SEVERITY ERROR;
    IF (T_DONE/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;    
    WAIT FOR 10 NS;
    
--CASE 3: AN ADD INSTRUCTION
  -- ADD REGISTER 1 TO REGISTER ONE
    T_CNT <= "00";
    T_INS <= "010001001";
    WAIT FOR 1 NS;
    T_CNT <= "01";
    WAIT FOR 1 NS;
    ASSERT (T_R_OUT(1)='1') REPORT "ERROR3A!" SEVERITY ERROR;
    IF (T_R_OUT(1)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_A_IN='1') REPORT "ERROR3B!" SEVERITY ERROR;
    IF (T_A_IN/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    WAIT FOR 1 NS;
    T_CNT <= "10";
    WAIT FOR 1 NS;
    ASSERT (T_R_OUT(1)='1') REPORT "ERROR3C!" SEVERITY ERROR;
    IF (T_R_OUT(1)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_ADDSUB='0') REPORT "ERROR3D!" SEVERITY ERROR;
    IF (T_ADDSUB/='0') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
     ASSERT (T_G_IN='1') REPORT "ERROR3E!" SEVERITY ERROR;
    IF (T_G_IN/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF; 
    T_CNT <= "11";
    WAIT FOR 1 NS;
    ASSERT (T_R_IN(1)='1') REPORT "ERROR3F!" SEVERITY ERROR;
    IF (T_R_IN(1)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_DONE='1') REPORT "ERROR3G!" SEVERITY ERROR;
    IF (T_DONE/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
     ASSERT (T_G_OUT='1') REPORT "ERROR3H!" SEVERITY ERROR;
    IF (T_G_OUT/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF; 
    WAIT FOR 10 NS;
    
  --CASE 4: A SUB INSTRUCTION
  -- SUB REGISTER 7 FROM REGISTER 3
    T_CNT <= "00";
    T_INS <= "011111011";
    WAIT FOR 1 NS;
    T_CNT <= "01";
    WAIT FOR 1 NS;
    ASSERT (T_R_OUT(7)='1') REPORT "ERROR4A!" SEVERITY ERROR;
    IF (T_R_OUT(7)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_A_IN='1') REPORT "ERROR4B!" SEVERITY ERROR;
    IF (T_A_IN/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    WAIT FOR 1 NS;
    T_CNT <= "10";
    WAIT FOR 1 NS;
    ASSERT (T_R_OUT(3)='1') REPORT "ERROR4C!" SEVERITY ERROR;
    IF (T_R_OUT(3)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    -- IN THE TABLE ADDSUB IS ASSERTED 0 HERE, OUR LOGIC FLIPS THIS.
    ASSERT (T_ADDSUB='1') REPORT "ERROR3D!" SEVERITY ERROR;
    IF (T_ADDSUB/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
     ASSERT (T_G_IN='1') REPORT "ERROR4E!" SEVERITY ERROR;
    IF (T_G_IN/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF; 
    T_CNT <= "11";
    WAIT FOR 1 NS;
    ASSERT (T_R_IN(7)='1') REPORT "ERROR4F!" SEVERITY ERROR;
    IF (T_R_IN(7)/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    ASSERT (T_DONE='1') REPORT "ERROR4G!" SEVERITY ERROR;
    IF (T_DONE/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
     ASSERT (T_G_OUT='1') REPORT "ERROR4H!" SEVERITY ERROR;
    IF (T_G_OUT/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF; 
    WAIT FOR 10 NS;
    
  --CASE 5: A TEST OF RESETN
  -- TRY TO DO A WHOLE BUNCH OF STUFF. IF THEY DO IT, SOMETHING WENT WRONG.
    T_CNT <= "00";
    WAIT FOR 1 NS;
    T_CNT <= "01";
    T_INS <= "011111011";
    T_RESET <= '1';  
    WAIT FOR 1 NS;
    -- LOOP THROUGH ALL REGISTERS TO MAKE SURE 0
    FOR J IN 0 TO 7 LOOP
      ASSERT (T_R_OUT(J)='0') REPORT "ERROR5A!" SEVERITY ERROR;
      IF (T_R_OUT(J)/='0') THEN
        ERR_CNT := ERR_CNT + 1;
      END IF;
    END LOOP;
    FOR A IN 0 TO 7 LOOP
      ASSERT (T_R_IN(A)='0') REPORT "ERROR5B!" SEVERITY ERROR;
      IF (T_R_IN(A)/='0') THEN
        ERR_CNT := ERR_CNT + 1;
      END IF;
    END LOOP;
    ASSERT (T_DONE='0') REPORT "ERROR5C!" SEVERITY ERROR;
    IF (T_DONE/='0') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    WAIT FOR 10 NS;

  --CASE 6: TEST RUN
  -- DO THINGS.............
    T_CNT <= "00";
    T_RUN <= '0';
    T_RESET <= '0';
    WAIT FOR 1 NS;
    T_CNT <= "01";
    WAIT FOR 1 NS;
    ASSERT (T_CLR='1') REPORT "ERROR6A!" SEVERITY ERROR;
    IF (T_CLR/='1') THEN
      ERR_CNT := ERR_CNT + 1;
    END IF;
    WAIT FOR 10 NS;

    -- CHECK ERROR COUNT
    IF ERR_CNT=0 THEN
      ASSERT FALSE
      REPORT "TESTBENCH OF CONTROL COMPLETED SUCCESSFULLY!" SEVERITY NOTE;
    ELSE
      ASSERT FALSE
      REPORT "SOMETHING WRONG. :(" SEVERITY ERROR;
    END IF;
    WAIT;
  END PROCESS;
END TB;