----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 12.11.2018 22:51:11
-- Design Name:
-- Module Name: rpu_core_tb - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

library work;
use work.constants.all;

entity rpu_core_tb is
--  Port ( );
end rpu_core_tb;

architecture Behavioral of rpu_core_tb is

    -- The RPU core definition
    COMPONENT core
        PORT(
            I_clk : IN  std_logic;
            I_reset : IN  std_logic;
            I_halt : IN  std_logic;
                  -- External Interrupt interface
            I_int_data: in STD_LOGIC_VECTOR(31 downto 0);
            I_int: in STD_LOGIC;
            O_int_ack: out STD_LOGIC;

            MEM_O_cmd : OUT  std_logic;
            MEM_O_we : OUT  std_logic;

            MEM_O_byteEnable : OUT  std_logic_vector(1 downto 0);
            MEM_O_addr : OUT  std_logic_vector(31 downto 0);
            MEM_O_data : OUT  std_logic_vector(31 downto 0);
            MEM_I_data : IN  std_logic_vector(31 downto 0);

            MEM_I_ready : IN  std_logic;
            MEM_I_dataReady : IN  std_logic

            ;
            O_DBG:out std_logic_vector(63 downto 0)
        );
    END COMPONENT;

      signal  CLK12MHZ :   STD_LOGIC := '0';
          signal  CLKTIME :   STD_LOGIC := '0';
        constant I_CLKTIME_period : time := 8 ns;

        signal cEng_core : std_logic := '0';
    signal I_reset : std_logic := '1';
    signal I_halt : std_logic := '0';
    signal I_int : std_logic := '0';
    signal MEM_I_ready : std_logic := '1';
    signal MEM_I_data : std_logic_vector(31 downto 0) := (others => '0');
    signal MEM_I_dataReady : std_logic := '0';

    signal MEM_O_data_swizzed : std_logic_vector(31 downto 0) := (others => '0');

    signal O_int_ack : std_logic:= '0';
    signal O_int_ack_stable_12mhz : std_logic:= '0';
    signal O_int_ack_stable_12mhz_core : std_logic:= '0';

    signal MEM_O_cmd : std_logic := '0';
    signal MEM_O_we : std_logic := '0';
    signal MEM_O_byteEnable : std_logic_vector(1 downto 0) := (others => '0');
    signal MEM_O_addr : std_logic_vector(31 downto 0) := (others => '0');
    signal MEM_O_data : std_logic_vector(31 downto 0) := (others => '0');

    signal I_int_data:  STD_LOGIC_VECTOR(31 downto 0);
            signal MEM_I_data_raw : std_logic_vector(31 downto 0) := (others => '0');

    -- Clock period definitions
    constant I_clk_period : time := 5 ns;

        signal MEM_readyState: integer := 0;

        -- SOC_CtrState definitions - running off SOC clock domain
        constant SOC_CtlState_Ready : integer :=  0;

        -- IMM SOC control states are immediate 1-cycle latency
        -- i.e. BRAM or explicit IO
        constant SOC_CtlState_IMM_WriteCmdComplete : integer := 9;
        constant SOC_CtlState_IMM_ReadCmdComplete : integer := 6;

    signal IO_LEDS: STD_LOGIC_VECTOR(7 downto 0):= (others => '0');
    signal INT_DATA: std_logic_vector(BWIDTHM1 downto 0):= (others => '0');
    signal IO_DATA: std_logic_vector(BWIDTHM1 downto 0):= (others => '0');
    signal DDR3_DATA: std_logic_vector(BWIDTHM1 downto 0):= (others => '0');

    -- Block ram management
    signal MEM_64KB_ADDR : std_logic_vector(31 downto 0):= (others => '0');
    signal MEM_BANK_ID : std_logic_vector(15 downto 0):= (others => '0');
    signal MEM_ANY_CS : std_logic := '0';
    signal MEM_WE : std_logic := '0';

    signal MEM_CS_BRAM_1 : std_logic := '0';
    signal MEM_CS_BRAM_2 : std_logic := '0';
    signal MEM_CS_BRAM_3 : std_logic := '0';

        signal mI_wea : STD_LOGIC_VECTOR ( 3 downto 0 ):= (others => '0');

    signal MEM_CS_DDR3 : std_logic := '0';

    signal MEM_CS_SYSTEM : std_logic := '0';

    signal MEM_DATA_OUT_BRAM_1: std_logic_vector(BWIDTHM1 downto 0):= (others => '0');
    signal MEM_DATA_OUT_BRAM_2: std_logic_vector(BWIDTHM1 downto 0):= (others => '0');
    signal MEM_DATA_OUT_BRAM_3: std_logic_vector(BWIDTHM1 downto 0):= (others => '0');

        signal    O_DBG: std_logic_vector(63 downto 0);

            constant mmio_addr_mtime_lo: STD_LOGIC_VECTOR( 31 downto 0) := X"4400bff8";
        constant mmio_addr_mtime_hi: STD_LOGIC_VECTOR( 31 downto 0) := X"4400bffc";
        signal gcsr_mtime_lo: STD_LOGIC_VECTOR( 31 downto 0) := (others => '0');
        signal gcsr_mtime_hi: STD_LOGIC_VECTOR( 31 downto 0) := (others => '0');

            signal memcontroller_reset_count: integer := 100000;

        signal count12MHz: std_logic_vector(63 downto 0) := X"0000000000000000";

       constant mmio_addr_mtimecmp0_lo: STD_LOGIC_VECTOR( 31 downto 0) := X"44004000";
       constant mmio_addr_mtimecmp0_hi: STD_LOGIC_VECTOR( 31 downto 0) := X"44004004";
          --       constant mmio_addr_mtimecmp0_lo: STD_LOGIC_VECTOR( 31 downto 0) := X"00000004";
            --     constant mmio_addr_mtimecmp0_hi: STD_LOGIC_VECTOR( 31 downto 0) := X"00000008";
        signal gcsr_timer_initialized : STD_LOGIC:='0';
        signal gcsr_mtimecmp0_lo: STD_LOGIC_VECTOR( 31 downto 0) := X"0000000c";--X"07270E00";--20s 0E4E1C00"; --?10 seconds of 12mhz counter?"; --(others => '0');
        signal gcsr_mtimecmp0_hi: STD_LOGIC_VECTOR( 31 downto 0) := (others => '0');
        signal gcsr_mtimecmp0_stable: STD_LOGIC_VECTOR( 63 downto 0) := (others => '0');

        signal gcsr_mtimecmp0_lo_written: STD_LOGIC := '0';
        signal gcsr_mtimecmp0_hi_written: STD_LOGIC := '0';
        signal gcsr_mtimecmp_irq_reset: STD_LOGIC := '0';
        signal gcsr_mtimecmp_irq_reset_stable: STD_LOGIC := '0';
        signal gcsr_mtimecmp_irq_en: STD_LOGIC := '0';  ----
        signal gcsr_mtimecmp_irq_en_stable: STD_LOGIC := '0'; ------
        signal gcsr_mtimecmp_irq: STD_LOGIC := '0';

        signal gcsr_mtimecmp_irq_served: std_logic := '0';
        signal plic_int : std_logic := '0';

         type rom_type is array (0 to 16384)
               of std_logic_vector(31 downto 0);
       signal ROM2: rom_type :=(others => X"00000000");
                      signal ROM3: rom_type :=(others => X"00000000");
     signal ROM: rom_type:=(
   X"00000097",     --auipc	ra,0x0
     X"14408093",     --addi    ra,ra,324 # 10000230 <_trap_handler>
     X"30509ff3",     --csrrw    t6,mtvec,ra
     X"00002197",     --auipc    gp,0x2
     X"f0818193",     --addi    gp,gp,-248 # 10002000 <test_A1_data>
     X"00002117",     --auipc    sp,0x2
     X"f1010113",     --addi    sp,sp,-240 # 10002010 <begin_signature>
     X"00002097",     --auipc    ra,0x2
     X"f1808093",     --addi    ra,ra,-232 # 10002020 <test_A1_res_exc>
     X"00500293",     --li    t0,5
     X"00600313",     --li    t1,6
     X"0001a203",     --lw    tp,0(gp)
     X"00412023",     --sw    tp,0(sp)
     X"0011a203",     --lw    tp,1(gp)
     X"00412223",     --sw    tp,4(sp)
     X"0021a203",     --lw    tp,2(gp)
     X"00412423",     --sw    tp,8(sp)
     X"0031a203",     --lw    tp,3(gp)
     X"00412623",     --sw    tp,12(sp)
     X"00002197",     --auipc    gp,0x2
     X"ecc18193",     --addi    gp,gp,-308 # 10002004 <test_A2_data>
     X"00002117",     --auipc    sp,0x2
     X"ef810113",     --addi    sp,sp,-264 # 10002038 <test_A2_res>
     X"00002097",     --auipc    ra,0x2
     X"f1008093",     --addi    ra,ra,-240 # 10002058 <test_A2_res_exc>
     X"00500293",     --li    t0,5
     X"00600313",     --li    t1,6
     X"00019203",     --lh    tp,0(gp)
     X"00412023",     --sw    tp,0(sp)
     X"00119203",     --lh    tp,1(gp)
     X"00412223",     --sw    tp,4(sp)
     X"00219203",     --lh    tp,2(gp)
     X"00412423",     --sw    tp,8(sp)
     X"00319203",     --lh    tp,3(gp)
     X"00412623",     --sw    tp,12(sp)
     X"0001d203",     --lhu    tp,0(gp)
     X"00412823",     --sw    tp,16(sp)
     X"0011d203",     --lhu    tp,1(gp)
     X"00412a23",     --sw    tp,20(sp)
     X"0021d203",     --lhu    tp,2(gp)
     X"00412c23",     --sw    tp,24(sp)
     X"0031d203",     --lhu    tp,3(gp)
     X"00412e23",     --sw    tp,28(sp)
     X"00002117",     --auipc    sp,0x2
     X"ee010113",     --addi    sp,sp,-288 # 10002078 <test_B1_res>
     X"00002097",     --auipc    ra,0x2
     X"ee808093",     --addi    ra,ra,-280 # 10002088 <test_B1_res_exc>
     X"00000313",     --li    t1,0
     X"9999a2b7",     --lui    t0,0x9999a
     X"99928293",     --addi    t0,t0,-1639 # 99999999 <_end+0x89997795>
     X"00512023",     --sw    t0,0(sp)
     X"00512223",     --sw    t0,4(sp)
     X"00512423",     --sw    t0,8(sp)
     X"00512623",     --sw    t0,12(sp)
     X"00612023",     --sw    t1,0(sp)
     X"00410113",     --addi    sp,sp,4
     X"006120a3",     --sw    t1,1(sp)
     X"00410113",     --addi    sp,sp,4
     X"00612123",     --sw    t1,2(sp)
     X"00410113",     --addi    sp,sp,4
     X"006121a3",     --sw    t1,3(sp)
     X"00002117",     --auipc    sp,0x2
     X"ec010113",     --addi    sp,sp,-320 # 100020a0 <test_B2_res>
     X"00002097",     --auipc    ra,0x2
     X"ec808093",     --addi    ra,ra,-312 # 100020b0 <test_B2_res_exc>
     X"00000313",     --li    t1,0
     X"9999a2b7",     --lui    t0,0x9999a
     X"99928293",     --addi    t0,t0,-1639 # 99999999 <_end+0x89997795>
     X"00512023",     --sw    t0,0(sp)
     X"00512223",     --sw    t0,4(sp)
     X"00512423",     --sw    t0,8(sp)
     X"00512623",     --sw    t0,12(sp)
     X"00611023",     --sh    t1,0(sp)
     X"00410113",     --addi    sp,sp,4
     X"006110a3",     --sh    t1,1(sp)
     X"00410113",     --addi    sp,sp,4
     X"00611123",     --sh    t1,2(sp)
     X"00410113",     --addi    sp,sp,4
     X"006111a3",     --sh    t1,3(sp)
     X"305f9073",     --csrw    mtvec,t6
     X"02c0006f",     --j    10000258 <test_end>

     X"34102f73",     --csrr    t5,mepc
     X"004f0f13",     --addi    t5,t5,4
     X"341f1073",     --csrw    mepc,t5
     X"34302f73",     --csrr    t5,mtval
     X"003f7f13",     --andi    t5,t5,3
     X"01e0a023",     --sw    t5,0(ra)
     X"34202f73",     --csrr    t5,mcause
     X"01e0a223",     --sw    t5,4(ra)
     X"00808093",     --addi    ra,ra,8
     X"30200073",     --mret

     X"00100193",     --li    gp,1
     X"00002f17",     --auipc    t5,0x2
     X"e64f0f13",     --addi    t5,t5,-412 # 100020c0 <end_signature>
     X"000f2103",     --lw    sp,0(t5)
     X"00412083",     --lw    ra,4(sp)
     X"00812283",     --lw    t0,8(sp)
     X"00c12303",     --lw    t1,12(sp)
     X"01012383",     --lw    t2,16(sp)
     X"01412403",     --lw    s0,20(sp)
     X"01812483",     --lw    s1,24(sp)
     X"01c12503",     --lw    a0,28(sp)
     X"02012583",     --lw    a1,32(sp)
     X"02412603",     --lw    a2,36(sp)
     X"02812683",     --lw    a3,40(sp)
     X"02c12703",     --lw    a4,44(sp)
     X"03012783",     --lw    a5,48(sp)
     X"03412803",     --lw    a6,52(sp)
     X"03812883",     --lw    a7,56(sp)
     X"03c12903",     --lw    s2,60(sp)
     X"04012983",     --lw    s3,64(sp)
     X"04412a03",     --lw    s4,68(sp)
     X"04812a83",     --lw    s5,72(sp)
     X"04c12b03",     --lw    s6,76(sp)
     X"05012b83",     --lw    s7,80(sp)
     X"05412c03",     --lw    s8,84(sp)
     X"05812c83",     --lw    s9,88(sp)
     X"05c12d03",     --lw    s10,92(sp)
     X"06012d83",     --lw    s11,96(sp)
     X"06412e03",     --lw    t3,100(sp)
     X"06812e83",     --lw    t4,104(sp)
     X"06c12f03",     --lw    t5,108(sp)
     X"07012f83",     --lw    t6,112(sp)
     X"08010113",     --addi    sp,sp,128
             X"0000006f", --              j    00 <if>
--  X"00008067",     --ret

     X"00002f17",     --auipc    t5,0x2
     X"de0f0f13",     --addi    t5,t5,-544 # 100020c0 <end_signature>
     X"000f2103",     --lw    sp,0(t5)
     X"00412083",     --lw    ra,4(sp)
     X"00812283",     --lw    t0,8(sp)
     X"00c12303",     --lw    t1,12(sp)
     X"01012383",     --lw    t2,16(sp)
     X"01412403",     --lw    s0,20(sp)
     X"01812483",     --lw    s1,24(sp)
     X"01c12503",     --lw    a0,28(sp)
     X"02012583",     --lw    a1,32(sp)
     X"02412603",     --lw    a2,36(sp)
     X"02812683",     --lw    a3,40(sp)
     X"02c12703",     --lw    a4,44(sp)
     X"03012783",     --lw    a5,48(sp)
     X"03412803",     --lw    a6,52(sp)
     X"03812883",     --lw    a7,56(sp)
     X"03c12903",     --lw    s2,60(sp)
     X"04012983",     --lw    s3,64(sp)
     X"04412a03",     --lw    s4,68(sp)
     X"04812a83",     --lw    s5,72(sp)
     X"04c12b03",     --lw    s6,76(sp)
     X"05012b83",     --lw    s7,80(sp)
     X"05412c03",     --lw    s8,84(sp)
     X"05812c83",     --lw    s9,88(sp)
     X"05c12d03",     --lw    s10,92(sp)
     X"06012d83",     --lw    s11,96(sp)
     X"06412e03",     --lw    t3,100(sp)
     X"06812e83",     --lw    t4,104(sp)
     X"06c12f03",     --lw    t5,108(sp)
     X"07012f83",     --lw    t6,112(sp)
     X"08010113",     --addi    sp,sp,128
            X"0000006f", --              j    00 <if>

  --   X"00008067",     --ret
  --   X"c0001073",     --unimp
--
--     X"00000097",      --auipc    ra,0x0
--     X"20808093",      --addi    ra,ra,520 # 100002f4 <_trap_handler>
--     X"30509ff3",      --csrrw    t6,mtvec,ra
--     X"30127073",      --csrci    misa,4
--     X"00002097",      --auipc    ra,0x2
--     X"f0408093",      --addi    ra,ra,-252 # 10002000 <begin_signature>
--     X"11111137",      --lui    sp,0x11111
--     X"11110113",      --addi    sp,sp,273 # 11111111 <_end+0x110ef0d>
--     X"00a0006f",      --j    10000116 <begin_testcode+0x2a>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"ef808093",      --addi    ra,ra,-264 # 1000200c <test_A2_res>
--     X"22222137",      --lui    sp,0x22222
--     X"22210113",      --addi    sp,sp,546 # 22222222 <_end+0x1222001e>
--     X"00000217",      --auipc    tp,0x0
--     X"01120213",      --addi    tp,tp,17 # 10000135 <begin_testcode+0x49>
--     X"00020067",      --jr    tp # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"0020a023",      --sw    sp,0(ra)
--     X"00408093",      --addi    ra,ra,4
--     X"33333137",      --lui    sp,0x33333
--     X"33310113",      --addi    sp,sp,819 # 33333333 <_end+0x2333112f>
--     X"00000217",      --auipc    tp,0x0
--     X"01020213",      --addi    tp,tp,16 # 10000154 <begin_testcode+0x68>
--     X"00120067",      --jr    1(tp) # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"0020a023",      --sw    sp,0(ra)
--     X"00408093",      --addi    ra,ra,4
--     X"44444137",      --lui    sp,0x44444
--     X"44410113",      --addi    sp,sp,1092 # 44444444 <_end+0x34442240>
--     X"00000217",      --auipc    tp,0x0
--     X"01420213",      --addi    tp,tp,20 # 10000178 <begin_testcode+0x8c>
--     X"ffd20067",      --jr    -3(tp) # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"0020a023",      --sw    sp,0(ra)
--     X"00408093",      --addi    ra,ra,4
--     X"00002097",      --auipc    ra,0x2
--     X"e9c08093",      --addi    ra,ra,-356 # 10002018 <test_A3_res_exc>
--     X"55555137",      --lui    sp,0x55555
--     X"55510113",      --addi    sp,sp,1365 # 55555555 <_end+0x45553351>
--     X"00000217",      --auipc    tp,0x0
--     X"01220213",      --addi    tp,tp,18 # 1000019e <begin_testcode+0xb2>
--     X"00020067",      --jr    tp # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"66666137",      --lui    sp,0x66666
--     X"66610113",      --addi    sp,sp,1638 # 66666666 <_end+0x56664462>
--     X"00000217",      --auipc    tp,0x0
--     X"01320213",      --addi    tp,tp,19 # 100001b7 <begin_testcode+0xcb>
--     X"00020067",      --jr    tp # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"77777137",      --lui    sp,0x77777
--     X"77710113",      --addi    sp,sp,1911 # 77777777 <_end+0x67775573>
--     X"00000217",      --auipc    tp,0x0
--     X"01020213",      --addi    tp,tp,16 # 100001cc <begin_testcode+0xe0>
--     X"00220067",      --jr    2(tp) # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"88889137",      --lui    sp,0x88889
--     X"88810113",      --addi    sp,sp,-1912 # 88888888 <_end+0x78886684>
--     X"00000217",      --auipc    tp,0x0
--     X"01020213",      --addi    tp,tp,16 # 100001e4 <begin_testcode+0xf8>
--     X"00320067",      --jr    3(tp) # 0 <_start-0x10000000>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"e6408093",      --addi    ra,ra,-412 # 10002048 <test_B1_res_exc>
--     X"00500293",      --li    t0,5
--     X"00600313",      --li    t1,6
--     X"00628763",      --beq    t0,t1,10000202 <begin_testcode+0x116>
--     X"9999a137",      --lui    sp,0x9999a
--     X"99910113",      --addi    sp,sp,-1639 # 99999999 <_end+0x89997795>
--     X"00000013",      --nop
--     X"00000013",      --nop
--     X"00528563",      --beq    t0,t0,10000212 <begin_testcode+0x126>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"e4408093",      --addi    ra,ra,-444 # 10002054 <test_B2_res_exc>
--     X"00500293",      --li    t0,5
--     X"00600313",      --li    t1,6
--     X"00529763",      --bne    t0,t0,1000022e <begin_testcode+0x142>
--     X"aaaab137",      --lui    sp,0xaaaab
--     X"aaa10113",      --addi    sp,sp,-1366 # aaaaaaaa <_end+0x9aaa88a6>
--     X"00000013",      --nop
--     X"00000013",      --nop
--     X"00629563",      --bne    t0,t1,1000023e <begin_testcode+0x152>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"e2408093",      --addi    ra,ra,-476 # 10002060 <test_B3_res_exc>
--     X"00500293",      --li    t0,5
--     X"00600313",      --li    t1,6
--     X"00534763",      --blt    t1,t0,1000025a <begin_testcode+0x16e>
--     X"bbbbc137",      --lui    sp,0xbbbbc
--     X"bbb10113",      --addi    sp,sp,-1093 # bbbbbbbb <_end+0xabbb99b7>
--     X"00000013",      --nop
--     X"00000013",      --nop
--     X"0062c563",      --blt    t0,t1,1000026a <begin_testcode+0x17e>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"e0408093",      --addi    ra,ra,-508 # 1000206c <test_B4_res_exc>
--     X"00500293",      --li    t0,5
--     X"00600313",      --li    t1,6
--     X"00536763",      --bltu    t1,t0,10000286 <begin_testcode+0x19a>
--     X"ccccd137",      --lui    sp,0xccccd
--     X"ccc10113",      --addi    sp,sp,-820 # cccccccc <_end+0xbcccaac8>
--     X"00000013",      --nop
--     X"00000013",      --nop
--     X"0062e563",      --bltu    t0,t1,10000296 <begin_testcode+0x1aa>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"de408093",      --addi    ra,ra,-540 # 10002078 <test_B5_res_exc>
--     X"00500293",      --li    t0,5
--     X"00600313",      --li    t1,6
--     X"0062d763",      --bge    t0,t1,100002b2 <begin_testcode+0x1c6>
--     X"dddde137",      --lui    sp,0xdddde
--     X"ddd10113",      --addi    sp,sp,-547 # dddddddd <_end+0xcdddbbd9>
--     X"00000013",      --nop
--     X"00000013",      --nop
--     X"00535563",      --bge    t1,t0,100002c2 <begin_testcode+0x1d6>
--     X"00000113",      --li    sp,0
--     X"00002097",      --auipc    ra,0x2
--     X"dc408093",      --addi    ra,ra,-572 # 10002084 <test_B6_res_exc>
--     X"00500293",      --li    t0,5
--     X"00600313",      --li    t1,6
--     X"0062f763",      --bgeu    t0,t1,100002de <begin_testcode+0x1f2>
--     X"eeeef137",      --lui    sp,0xeeeef
--     X"eee10113",      --addi    sp,sp,-274 # eeeeeeee <_end+0xdeeeccea>
--     X"00000013",      --nop
--     X"00000013",      --nop
--     X"00537563",      --bgeu    t1,t0,100002ee <begin_testcode+0x202>
--     X"00000113",      --li    sp,0
--     X"305f9073",      --csrw    mtvec,t6
--     X"0300006f",      --j    10000320 <test_end>
--
--      --<_trap_handler>:
--     X"34302f73",      --csrr    t5,mtval
--     X"ffef0f13",      --addi    t5,t5,-2
--     X"341f1073",      --csrw    mepc,t5
--     X"34302f73",      --csrr    t5,mtval
--     X"003f7f13",      --andi    t5,t5,3
--     X"01e0a023",      --sw    t5,0(ra)
--     X"34202f73",      --csrr    t5,mcause
--     X"01e0a223",      --sw    t5,4(ra)
--     X"0020a423",      --sw    sp,8(ra)
--     X"00c08093",      --addi    ra,ra,12
--     X"30200073",      --mret
--
--     -- <test_end>:
--     X"00100193",      --li    gp,1
--     X"00100f13", --              	li	t5,1
--     X"00100e93", --                  li    t4,1
--     X"03df0eb3", --                  mul    t4,t5,t4
--

     X"0000006f", --              j    00 <if>

      X"06300513", --      0      	li	a0,99  0
      X"00a00693", --      4          li    a3,10
      X"02d57733", --      8          remu    a4,a0,a3
      X"00f605b3", --      c          add    a1,a2,a5
      X"00178793", --     10           addi    a5,a5,1
      X"02d55533", --     14           divu    a0,a0,a3
      X"03070713", --     18           addi    a4,a4,48

     --X"00812423", --   	sw	s0,8(sp)
    -- X"00112623", --       sw    ra,12(sp)
     --X"00048413", --       mv    s0,s1
     --X"00048793", --       mv    a5,s1
     --X"40960633", --       sub    a2,a2,s1
     X"00a00693", --       li    a3,10
     X"02d57733", --       remu    a4,a0,a3
     X"00f605b3", --       add    a1,a2,a5
     X"00178793", --       addi    a5,a5,1
     X"02d55533", --       divu    a0,a0,a3
     X"03070713", --       addi    a4,a4,48
     X"fee78fa3", --       sb    a4,-1(a5)
     X"fe0514e3", --       bnez    a0,20bbc <put_decimal+0x30>
 -- 00000000 <if>:
     X"0000006f", --              j    00 <if>

       others => X"00000000");

       signal I_hart0_int0_coreclk_stable : STD_LOGIC := '0';
       signal O_hart0_int_ack0_coreclk_stable : STD_LOGIC := '0';
       signal hart0_int_ack0_external : STD_LOGIC := '0';
       signal int_was_inactive: STD_LOGIC := '0';

       signal count12MHz_stable: STD_LOGIC_VECTOR(63 downto 0) := (others => '0');
BEGIN

   I_int <= gcsr_mtimecmp_irq;

process(CLK12MHZ)
begin
 if rising_edge(CLK12MHZ) then
     count12MHz <= std_logic_vector(unsigned(count12MHz) + 1);
 end if;
end process;

process (cEng_core)

 if rising_edge(cEng_core) then
     if gcsr_mtimecmp_irq_en = '1' then
         if count12MHz_stable >= (gcsr_mtimecmp0_hi & gcsr_mtimecmp0_lo) then
             gcsr_mtimecmp_irq <= '1';
             gcsr_mtimecmp_irq_en <= '0';
         end if;
     else
         if gcsr_mtimecmp_irq_reset = '1' then
            gcsr_mtimecmp_irq_en <= '1';
         end if;
         if gcsr_mtimecmp_irq = '1' and O_int_ack = '1' then
            gcsr_mtimecmp_irq <= '0';
         end if;
     end if;
 end if;
end process;

   I_int_data <= EXCEPTION_INT_MACHINE_TIMER;

 	-- The O_we signal can sustain too long. Clamp it to only when O_cmd is active.
    MEM_WE <= MEM_O_cmd and MEM_O_we;

    -- "Local" BRAM banks are 64KB. To address inside we need lower 16b
    MEM_64KB_ADDR <= X"0000" & MEM_O_addr(15 downto 0);
    MEM_BANK_ID <= MEM_O_addr(31 downto 16);

    MEM_CS_BRAM_1 <= '1' when (MEM_BANK_ID = X"0000") else '0'; -- 0x0000ffff bank 64KB
    MEM_CS_BRAM_2 <= '1' when (MEM_BANK_ID = X"0001") else '0'; -- 0x0001ffff bank 64KB
    MEM_CS_BRAM_3 <= '1' when (MEM_BANK_ID = X"0002") else '0'; -- 0x0002ffff bank 64KB

    MEM_CS_DDR3 <= '1' when (MEM_BANK_ID(15 downto 12) = X"1") else '0'; -- 0x1******* ddr3 bank 256MB

    -- if any CS line is active, this is 1
    MEM_ANY_CS <= MEM_CS_BRAM_1 or MEM_CS_BRAM_2 or MEM_CS_BRAM_3;

    -- select the correct data to send to cpu
    MEM_I_data_raw <=
                  MEM_DATA_OUT_BRAM_1 when MEM_CS_BRAM_1 = '1'
                  else MEM_DATA_OUT_BRAM_2 when MEM_CS_BRAM_2 = '1'
                  else MEM_DATA_OUT_BRAM_3 when MEM_CS_BRAM_3 = '1'
                  else X"91a1b1c1";--IO_DATA;

 MEM_DATA_OUT_BRAM_1 <= ROM(to_integer(unsigned( MEM_64KB_ADDR(15 downto 2)and "01" & X"fff" )));--and "00"&X"03F" )));
 MEM_DATA_OUT_BRAM_2 <= ROM2(to_integer(unsigned( MEM_64KB_ADDR(15 downto 2)and "01" & X"fff" )));--and "00"&X"03F" )));
 MEM_DATA_OUT_BRAM_3 <= ROM3(to_integer(unsigned( MEM_64KB_ADDR(15 downto 2)and "01" & X"fff" )));--and "00"&X"03F" )));

   MEM_I_data  <= MEM_I_data_raw;

    cEng_core_clk: process
    begin
            cEng_core <= '0';
            wait for I_clk_period/2;
            cEng_core <= '1';
            wait for I_clk_period/2;
    end process;

CLKTIME_clk: process
begin
 CLKTIME <= '0';
 wait for I_CLKTIME_period/2;
 CLKTIME <= '1';
 wait for I_CLKTIME_period/2;
end process;

    CLK12MHZ <= CLKTIME;

   core0: core PORT MAP (
          I_clk => cEng_core,
          I_reset => I_reset,
          I_halt => I_halt,
          I_int => I_int,
          O_int_ack => O_int_ack,
          I_int_data => I_int_data,
          MEM_I_ready => MEM_I_ready,
          MEM_O_cmd => MEM_O_cmd,
          MEM_O_we => MEM_O_we,
          MEM_O_byteEnable => MEM_O_byteEnable,
          MEM_O_addr => MEM_O_addr,
          MEM_O_data => MEM_O_data,
          MEM_I_data => MEM_I_data,
          MEM_I_dataReady => MEM_I_dataReady
		  ,
		  O_DBG=>O_DBG
        );

    -- Huge process which handles memory request arbitration at the Soc/Core clock
    MEM_proc: process(cEng_core)
    begin
        if rising_edge(cEng_core) then
            if gcsr_mtimecmp_irq_en = '1' and gcsr_mtimecmp_irq_reset = '1' then
               gcsr_mtimecmp_irq_reset <= '0';
            end if;

            if MEM_readyState = SOC_CtlState_Ready then
                if MEM_O_cmd = '1' then

                    -- system memory maps
                    if MEM_O_addr = X"f0009000" and MEM_O_we = '1' then
                        -- onboard leds
                        IO_LEDS <= "0000" & MEM_O_data( 3 downto 0);
                    end if;
                    if MEM_O_addr = X"f0009000" and MEM_O_we = '0' then
                        -- onboard leds
                        IO_DATA <= X"000000" &  IO_LEDS;
                    end if;

                   if MEM_O_addr = mmio_addr_mtime_lo and MEM_O_we = '0' then
                      IO_DATA <= count12MHz_stable(31 downto 0);
                    end if;

                   if MEM_O_addr = mmio_addr_mtime_hi and MEM_O_we = '0' then
                     IO_DATA <= count12MHz_stable(63 downto 32);
                   end if;

                   if MEM_O_addr = mmio_addr_mtimecmp0_lo and MEM_O_we = '1' then---1
                     gcsr_mtimecmp0_lo <= MEM_O_data;
                     gcsr_mtimecmp0_lo_written <= '1';
                   end if;

                   if MEM_O_addr = mmio_addr_mtimecmp0_hi and MEM_O_we = '1' then---1
                      gcsr_mtimecmp0_hi <= MEM_O_data;
                      if gcsr_mtimecmp0_lo_written = '1' then
                        --gcsr_mtimecmp0_hi_written <= '1';
                        gcsr_mtimecmp_irq_reset <= '1';
                        gcsr_mtimecmp0_lo_written <= '0';
                        --gcsr_mtimecmp0_hi_written <= '0';
                      end if;
                   end if;

                     if MEM_O_addr = mmio_addr_mtimecmp0_lo and MEM_O_we = '0' then
                       IO_DATA <= (gcsr_mtimecmp0_lo);
                     end if;

                     if MEM_O_addr = mmio_addr_mtimecmp0_hi and MEM_O_we = '0' then
                        IO_DATA <= (gcsr_mtimecmp0_hi);
                     end if;

                    MEM_I_ready <= '0';
                    MEM_I_dataReady  <= '0';
                    if MEM_O_we = '1' then
                        -- DDR3 request, or immediate command?

                        MEM_readyState <= SOC_CtlState_IMM_WriteCmdComplete;
                        if (MEM_CS_BRAM_1 = '1') then
                            ROM(to_integer(unsigned( MEM_64KB_ADDR(15 downto 2)))) <= MEM_O_data;
                        end if;
                        if (MEM_CS_BRAM_2 = '1') then
                            ROM2(to_integer(unsigned( MEM_64KB_ADDR(15 downto 2)))) <= MEM_O_data;
                        end if;
                        if (MEM_CS_BRAM_3 = '1') then
                            ROM3(to_integer(unsigned( MEM_64KB_ADDR(15 downto 2)))) <= MEM_O_data;
                        end if;
                    else
                        -- DDR3 request, or immediate command?

                        MEM_readyState <= SOC_CtlState_IMM_ReadCmdComplete;
                    end if;

                end if;
            elsif MEM_readyState >= 1 then

                -- Immediate commands do not cross clock domains and complete immediately
                if MEM_readyState = SOC_CtlState_IMM_ReadCmdComplete then
                    MEM_I_ready <= '1';
                    MEM_I_dataReady <= '1';
                    MEM_readyState <= SOC_CtlState_Ready;

                elsif MEM_readyState = SOC_CtlState_IMM_WriteCmdComplete then
                    MEM_I_ready <= '1';
                    MEM_I_dataReady  <= '0';
                    MEM_readyState <= SOC_CtlState_Ready;

            end if;

        end if;
    end if;
  end process;

     -- Stimulus process
     stim_proc: process
     begin
        -- hold reset state for 100 ns.
        wait for 20 ns;
        memcontroller_reset_count <= 0;

        I_reset <= '0';

        wait;
--
     end process;

end Behavioral;

begin
if rising_edge(cEng_core) then
    count12MHz_stable <= count12MHz;
end if;
end process;


----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 12.11.2018 22:51:11
-- Design Name:
-- Module Name: rpu_core_tb - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

library work;
use work.constants.all;

    -- The RPU core definition
  component alu_int32_div is
    Port (
        I_clk : in  STD_LOGIC;
        I_exec : in  STD_LOGIC;
        I_dividend : in  STD_LOGIC_VECTOR (XLEN32M1 downto 0);
        I_divisor : in  STD_LOGIC_VECTOR (XLEN32M1 downto 0);
        I_op : in  STD_LOGIC_VECTOR (1 downto 0);
        O_dataResult : out  STD_LOGIC_VECTOR (XLEN32M1 downto 0);
        O_done : out STD_LOGIC;
        O_int : out std_logic
    );
  end component;

   signal I_clk : std_logic := '0';
   signal I_exec : std_logic := '0';
   signal I_dividend : std_logic_vector(31 downto 0) := (others => '0');
   signal I_divisor : std_logic_vector(31 downto 0) := (others => '0');
   signal I_op : std_logic_vector(1 downto 0) := (others => '0');
   signal O_dataResult : std_logic_vector(31 downto 0) := (others => '0');
   signal O_done : std_logic := '0';
   signal O_int : std_logic := '0';

   -- Clock period definitions
   constant I_clk_period : time := 10 ns;
BEGIN

	-- Instantiate the Unit Under Test (UUT)
   uut: alu_int32_div PORT MAP (
          I_clk => I_clk,
          I_exec => I_exec,
          I_dividend => I_dividend,
          I_divisor => I_divisor,
          I_op => I_op,
          O_dataResult => O_dataResult,
          O_done => O_done,
          O_int => O_int
        );

   -- Clock process definitions
   I_clk_process :process
   begin
		I_clk <= '0';
		wait for I_clk_period/2;
		I_clk <= '1';
		wait for I_clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin
      -- hold reset state for 100 ns.
      wait for 100 ns;

      wait for I_clk_period*10;
      -- insert stimulus here

        I_dividend <= X"ffffffff";
		I_divisor <= X"00000000";
		I_op <= ALU_INT32_DIV_OP_DIVU;
		I_exec <= '1';
      wait for I_clk_period;
		I_exec <= '0';

      wait for I_clk_period*500;

              I_dividend <= X"0000000a";
              I_divisor <= X"0000000a";
              I_op <= ALU_INT32_DIV_OP_REMU;
              I_exec <= '1';
            wait for I_clk_period;
              I_exec <= '0';

            wait for I_clk_period*500;

          I_dividend <= X"00001001";
          I_divisor <= X"00000111";
          I_op <= ALU_INT32_DIV_OP_REM;
          I_exec <= '1';
        wait for I_clk_period;
          I_exec <= '0';

       wait for I_clk_period*500;

                    I_dividend <= X"ffff0001";
                    I_divisor <= X"00000111";
                    I_op <= ALU_INT32_DIV_OP_DIV;
                    I_exec <= '1';
                  wait for I_clk_period;
                    I_exec <= '0';

                 wait for I_clk_period*500;

--                                        I_dividend <= X"ffff0001";
--                                        I_divisor <= X"00000111";
--                                        I_op <= ALU_INT32_DIV_OP_DIVU;
--                                        I_exec <= '1';
--                                      wait for I_clk_period;
--                                        I_exec <= '0';
--        wait for I_clk_period*500;

            I_dividend <= X"00011101";
            I_divisor <= X"00000001";
            I_op <= ALU_INT32_DIV_OP_DIV;
            I_exec <= '1';
          wait for I_clk_period;
            I_exec <= '0';

          wait for I_clk_period*500;

            I_dividend <= X"00010001";
            I_divisor <= X"00000111";
            I_op <= ALU_INT32_DIV_OP_DIV;
            I_exec <= '1';
          wait for I_clk_period;
            I_exec <= '0';
      wait;
   end process;

end Behavioral;

entity alu_int32_div_tb is
--  Port ( );
end alu_int32_div_tb;


--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date:   16:43:32 12/10/2016
-- Design Name:
-- Module Name:   C:/Users/colin/Desktop/riscy/ise/tb_unit_alu_RV32I_01.vhd
-- Project Name:  riscv32_v1
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: alu_RV32I
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test.  Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

use work.constants.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;

ENTITY tb_unit_alu_RV32I_01 IS
END tb_unit_alu_RV32I_01;

ARCHITECTURE behavior OF tb_unit_alu_RV32I_01 IS

    -- Component Declaration for the Unit Under Test (UUT)

    COMPONENT alu_RV32I
    PORT(
         I_clk : IN  std_logic;
         I_en : IN  std_logic;
         I_dataA : IN  std_logic_vector(31 downto 0);
         I_dataB : IN  std_logic_vector(31 downto 0);
         I_dataDwe : IN  std_logic;
         I_aluop : IN  std_logic_vector(4 downto 0);
         I_aluFunc : IN  std_logic_vector(15 downto 0);
         I_PC : IN  std_logic_vector(31 downto 0);
         I_dataIMM : IN  std_logic_vector(31 downto 0);
         O_dataResult : OUT  std_logic_vector(31 downto 0);
         O_branchTarget : OUT  std_logic_vector(31 downto 0);
         O_dataWriteReg : OUT  std_logic;
         O_shouldBranch : OUT  std_logic
        );
    END COMPONENT;

   --Inputs
   signal I_clk : std_logic := '0';
   signal I_en : std_logic := '0';
   signal I_dataA : std_logic_vector(31 downto 0) := (others => '0');
   signal I_dataB : std_logic_vector(31 downto 0) := (others => '0');
   signal I_dataDwe : std_logic := '0';
   signal I_aluop : std_logic_vector(4 downto 0) := (others => '0');
   signal I_aluFunc : std_logic_vector(15 downto 0) := (others => '0');
   signal I_PC : std_logic_vector(31 downto 0) := (others => '0');
   signal I_dataIMM : std_logic_vector(31 downto 0) := (others => '0');

 	--Outputs
   signal O_dataResult : std_logic_vector(31 downto 0);
   signal O_branchTarget : std_logic_vector(31 downto 0);
   signal O_dataWriteReg : std_logic := '0';
   signal O_shouldBranch : std_logic := '0';

   -- Clock period definitions
   constant I_clk_period : time := 10 ns;

BEGIN

	-- Instantiate the Unit Under Test (UUT)
   uut: alu_RV32I PORT MAP (
          I_clk => I_clk,
          I_en => I_en,
          I_dataA => I_dataA,
          I_dataB => I_dataB,
          I_dataDwe => I_dataDwe,
          I_aluop => I_aluop,
          I_aluFunc => I_aluFunc,
          I_PC => I_PC,
          I_dataIMM => I_dataIMM,
          O_dataResult => O_dataResult,
          O_branchTarget => O_branchTarget,
          O_dataWriteReg => O_dataWriteReg,
          O_shouldBranch => O_shouldBranch
        );

   -- Clock process definitions
   I_clk_process :process
   begin
		I_clk <= '0';
		wait for I_clk_period/2;
		I_clk <= '1';
		wait for I_clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin
      -- hold reset state for 100 ns.
      wait for 100 ns;

      wait for I_clk_period*10;
      -- insert stimulus here

      I_dataA <= X"00001000";
		I_dataB <= X"01A01001";
		I_aluOp <= OPCODE_OP;
		I_aluFunc <= "000000" & F7_OP_ADD & F3_OP_ADD;
		I_dataImm <= X"00000000";
		I_PC <= X"A0000000";
		I_dataDwe <= '1';
		I_en <= '1';


--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date:   22:43:26 12/08/2016
-- Design Name:
-- Module Name:   C:/Users/colin/Desktop/riscy/ise/tb_unit_decoder_RV32_01.vhd
-- Project Name:  riscv32_v1
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: decoder_RV32
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test.  Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;

ENTITY tb_unit_decoder_RV32_01 IS
END tb_unit_decoder_RV32_01;

ARCHITECTURE behavior OF tb_unit_decoder_RV32_01 IS

    -- Component Declaration for the Unit Under Test (UUT)

    COMPONENT decoder_RV32
    PORT(
         I_clk : IN  std_logic;
         I_en : IN  std_logic;
         I_dataInst : IN  std_logic_vector(31 downto 0);
         O_selRS1 : OUT  std_logic_vector(4 downto 0);
         O_selRS2 : OUT  std_logic_vector(4 downto 0);
         O_selD : OUT  std_logic_vector(4 downto 0);
         O_dataIMM : OUT  std_logic_vector(31 downto 0);
         O_regDwe : OUT  std_logic;
         O_aluOp : OUT  std_logic_vector(6 downto 0);
         O_aluFunc : OUT  std_logic_vector(15 downto 0);  -- ALU function
			O_memOp : out STD_LOGIC_VECTOR(4 downto 0)
        );
    END COMPONENT;

   --Inputs
   signal I_clk : std_logic := '0';
   signal I_en : std_logic := '0';
   signal I_dataInst : std_logic_vector(31 downto 0) := (others => '0');

 	--Outputs
   signal O_selRS1 : std_logic_vector(4 downto 0);
   signal O_selRS2 : std_logic_vector(4 downto 0);
   signal O_selD : std_logic_vector(4 downto 0);
   signal O_dataIMM : std_logic_vector(31 downto 0);
   signal O_regDwe : std_logic;
   signal O_aluOp : std_logic_vector(6 downto 0);
   signal O_aluFunc : std_logic_vector(15 downto 0);
	signal O_memOp : STD_LOGIC_VECTOR(4 downto 0);

   -- Clock period definitions
   constant I_clk_period : time := 10 ns;

BEGIN

	-- Instantiate the Unit Under Test (UUT)
   uut: decoder_RV32 PORT MAP (
          I_clk => I_clk,
          I_en => I_en,
          I_dataInst => I_dataInst,
          O_selRS1 => O_selRS1,
          O_selRS2 => O_selRS2,
          O_selD => O_selD,
          O_dataIMM => O_dataIMM,
          O_regDwe => O_regDwe,
          O_aluOp => O_aluOp,
          O_aluFunc => O_aluFunc,
			 O_memOp => O_memOp
        );

   -- Clock process definitions
   I_clk_process :process

   begin
		I_clk <= '0';
		wait for I_clk_period/2;
		I_clk <= '1';
		wait for I_clk_period/2;


----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: ALU unit for 32-bit integer division ops
--
----------------------------------------------------------------------------------
-- Copyright 2020  Colin Riley
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.all;
library work;
use work.constants.all;

entity alu_int32_div is
    port (
        I_clk : in STD_LOGIC;
        I_exec : in STD_LOGIC;
        I_dividend : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
        I_divisor : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
        I_op : in STD_LOGIC_VECTOR (1 downto 0);
        O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
        O_done : out STD_LOGIC;
        O_int : out std_logic
    );
end alu_int32_div;

architecture Behavioral of alu_int32_div is
    signal s_done : std_logic := '0';
    signal s_int : std_logic := '0';
    signal s_op : std_logic_vector(1 downto 0) := (others => '0');
    signal s_result : std_logic_vector(XLEN32M1 downto 0) := (others => '0');
    signal s_outsign : std_logic := '0';
    signal s_ur : unsigned(XLEN32M1 downto 0) := (others => '0');

    signal s_i : integer := 0;
    signal s_N : unsigned(XLEN32M1 downto 0) := (others => '0');
    signal s_D : unsigned(XLEN32M1 downto 0) := (others => '0');
    signal s_R : unsigned(XLEN32M1 downto 0) := (others => '0');
    signal s_Q : unsigned(XLEN32M1 downto 0) := (others => '0');

    process (I_clk)
    begin
        if rising_edge(I_clk) then
            if s_state = STATE_IDLE then
                s_done <= '0';
                if I_exec = '1' then
                    s_op <= I_op;
                    s_done <= '0';

                    if (I_divisor = X"00000000") then
                        s_state <= STATE_COMPLETE;
                        s_Q <= X"ffffffff";

                        if I_dividend(31) = '1' then
                            s_R <= unsigned(-signed(I_dividend));
                        else
                            s_R <= unsigned(I_dividend);
                        end if;

                        if (I_op = ALU_INT32_DIV_OP_DIV) or (I_op = ALU_INT32_DIV_OP_DIVU) then
                            s_outsign <= '0';
                        else
                            s_outsign <= I_dividend(31);
                        end if;

                    elsif (I_divisor = X"00000001") and (I_op = ALU_INT32_DIV_OP_DIV) then
                        s_state <= STATE_COMPLETE;
                        s_R <= X"00000000";
                        if I_dividend(31) = '1' then
                            s_Q <= unsigned(-signed(I_dividend));
                        else
                            s_Q <= unsigned(I_dividend);
                        end if;
                        s_outsign <= I_dividend(31);

                    else
                        if I_op(ALU_INT32_DIV_OP_UNSIGNED_BIT) = '1' then
                            s_state <= STATE_INFLIGHTU;
                            s_N <= unsigned(I_dividend);
                            s_D <= unsigned(I_divisor);
                            s_ur <= X"00000000";
                            s_Q <= X"00000000";
                            s_R <= X"00000000";

                            s_i <= 31;
                            s_outsign <= '0';
                        else
                            s_state <= STATE_INFLIGHTU;

                            if (I_op = ALU_INT32_DIV_OP_DIV) then
                                s_outsign <= I_dividend(31) xor I_divisor(31);
                            else
                                s_outsign <= I_dividend(31);
                            end if;

                            if I_dividend(31) = '1' then
                                s_N <= unsigned(-signed(I_dividend));
                            else
                                s_N <= unsigned(I_dividend);
                            end if;

                            if I_divisor(31) = '1' then
                                s_D <= unsigned(-signed(I_divisor));
                            else
                                s_D <= unsigned(I_divisor);
                            end if;

                            s_ur <= X"00000000";

                            s_Q <= X"00000000";
                            s_R <= X"00000000";

                            s_i <= 31;

                        end if;
                    end if;
                end if;

            elsif s_state = STATE_INFLIGHTU then
                -- binary integer long division loop
                if (s_R(30 downto 0) & s_N(s_i)) >= s_D then
                    s_R <= (s_R(30 downto 0) & s_N(s_i)) - s_D;
                    s_Q(s_i) <= '1';
                else
                    s_R <= s_R(30 downto 0) & s_N(s_i);
                end if;

                if s_i = 0 then
                    s_state <= STATE_COMPLETE;
                else
                    s_i <= s_i - 1;
                end if;

            elsif s_state = STATE_COMPLETE then

                if (s_op = ALU_INT32_DIV_OP_DIV) or (s_op = ALU_INT32_DIV_OP_DIVU) then
                    if (s_outsign = '1') then
                        s_result <= std_logic_vector(-signed(std_logic_vector(s_Q)));
                    else
                        s_result <= std_logic_vector(s_Q);
                    end if;
                else
                    if (s_outsign = '1') then
                        s_result <= std_logic_vector(-signed(std_logic_vector(s_R)));
                    else
                        s_result <= std_logic_vector(s_R);
                    end if;
                end if;

                s_done <= '1';
                s_state <= STATE_IDLE;
            end if;
        end if;
    end process;

    O_dataResult <= s_result;
    O_done <= s_done;
    O_int <= s_int;
end Behavioral;

    constant STATE_IDLE : integer := 0;
    constant STATE_INFLIGHTU : integer := 1;
    constant STATE_COMPLETE : integer := 2;


----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: Constants for instruction forms, opcodes, conditional flags, etc.
--
----------------------------------------------------------------------------------
-- Copyright 2016 Colin Riley
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;

package constants is

constant XLEN: integer := 32;
constant XLENM1: integer := XLEN - 1;

constant XLEN32: integer:= 32;
constant XLEN32M1: integer:= XLEN32 -1;

constant BWIDTH: integer:= 32;
constant BWIDTHM1: integer:= BWIDTH -1;

constant ADDR_RESET:    std_logic_vector(XLEN32M1 downto 0) :=  X"00000000";
constant ADDR_INTVEC:   std_logic_vector(XLEN32M1 downto 0) :=  X"00000100";

-- PC unit opcodes
constant PCU_OP_NOP: std_logic_vector(1 downto 0):= "00";
constant PCU_OP_INC: std_logic_vector(1 downto 0):= "01";
constant PCU_OP_ASSIGN: std_logic_vector(1 downto 0):= "10";
constant PCU_OP_RESET: std_logic_vector(1 downto 0):= "11";

-- Instruction Form Offsets
constant OPCODE_START: integer := 6;
constant OPCODE_END: integer := 0;
constant OPCODE_END_2: integer := 2;

constant RD_START: integer := 11;
constant RD_END: integer := 7;

constant FUNCT3_START: integer := 14;
constant FUNCT3_END: integer := 12;

constant R1_START: integer := 19;
constant R1_END: integer := 15;

constant R2_START: integer := 24;
constant R2_END: integer := 20;

constant FUNCT7_START: integer := 31;
constant FUNCT7_END: integer := 25;

constant IMM_I_START: integer := 31;
constant IMM_I_END: integer := 20;

constant IMM_U_START: integer := 31;
constant IMM_U_END: integer := 12;

constant IMM_S_A_START: integer := 31;
constant IMM_S_A_END: integer := 25;

constant IMM_S_B_START: integer := 11;
constant IMM_S_B_END: integer := 7;

-- Opcodes
constant OPCODE_LOAD: std_logic_vector(4 downto 0) := "00000";
constant OPCODE_STORE: std_logic_vector(4 downto 0) := "01000";
constant OPCODE_MADD: std_logic_vector(4 downto 0) := "10000";
constant OPCODE_BRANCH: std_logic_vector(4 downto 0) := "11000";
constant OPCODE_JALR: std_logic_vector(4 downto 0) := "11001";
constant OPCODE_JAL: std_logic_vector(4 downto 0) := "11011";
constant OPCODE_SYSTEM: std_logic_vector(4 downto 0) := "11100";
constant OPCODE_OP: std_logic_vector(4 downto 0) := "01100";
constant OPCODE_OPIMM: std_logic_vector(4 downto 0) := "00100";
constant OPCODE_MISCMEM: std_logic_vector(4 downto 0) := "00011";
constant OPCODE_AUIPC: std_logic_vector(4 downto 0) := "00101";
constant OPCODE_LUI: std_logic_vector(4 downto 0) := "01101";

-- Flags
constant F3_BRANCH_BEQ: std_logic_vector(2 downto 0) := "000";
constant F3_BRANCH_BNE: std_logic_vector(2 downto 0) := "001";
constant F3_BRANCH_BLT: std_logic_vector(2 downto 0) := "100";
constant F3_BRANCH_BGE: std_logic_vector(2 downto 0) := "101";
constant F3_BRANCH_BLTU: std_logic_vector(2 downto 0) := "110";
constant F3_BRANCH_BGEU: std_logic_vector(2 downto 0) := "111";

constant F3_JALR: std_logic_vector(2 downto 0) := "000";

constant F3_LOAD_LB: std_logic_vector(2 downto 0) := "000";
constant F3_LOAD_LH: std_logic_vector(2 downto 0) := "001";
constant F3_LOAD_LW: std_logic_vector(2 downto 0) := "010";
constant F3_LOAD_LBU: std_logic_vector(2 downto 0) := "100";
constant F3_LOAD_LHU: std_logic_vector(2 downto 0) := "101";

constant F2_MEM_LS_SIZE_B: std_logic_vector(1 downto 0) := "00";
constant F2_MEM_LS_SIZE_H: std_logic_vector(1 downto 0) := "01";
constant F2_MEM_LS_SIZE_W: std_logic_vector(1 downto 0) := "10";

constant F3_STORE_SB: std_logic_vector(2 downto 0) := "000";
constant F3_STORE_SH: std_logic_vector(2 downto 0) := "001";
constant F3_STORE_SW: std_logic_vector(2 downto 0) := "010";

constant F3_OPIMM_ADDI: std_logic_vector(2 downto 0) := "000";
constant F3_OPIMM_SLTI: std_logic_vector(2 downto 0) := "010";
constant F3_OPIMM_SLTIU: std_logic_vector(2 downto 0) := "011";
constant F3_OPIMM_XORI: std_logic_vector(2 downto 0) := "100";
constant F3_OPIMM_ORI: std_logic_vector(2 downto 0) := "110";
constant F3_OPIMM_ANDI: std_logic_vector(2 downto 0) := "111";

constant F3_OPIMM_SLLI: std_logic_vector(2 downto 0) := "001";
constant F7_OPIMM_SLLI: std_logic_vector(6 downto 0) := "0000000";
constant F3_OPIMM_SRLI: std_logic_vector(2 downto 0) := "101";
constant F7_OPIMM_SRLI: std_logic_vector(6 downto 0) := "0000000";
constant F3_OPIMM_SRAI: std_logic_vector(2 downto 0) := "101";
constant F7_OPIMM_SRAI: std_logic_vector(6 downto 0) := "0100000";

constant F3_OP_ADD: std_logic_vector(2 downto 0) := "000";
constant F7_OP_ADD: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SUB: std_logic_vector(2 downto 0) := "000";
constant F7_OP_SUB: std_logic_vector(6 downto 0) := "0100000";
constant F3_OP_SLL: std_logic_vector(2 downto 0) := "001";
constant F7_OP_SLL: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SLT: std_logic_vector(2 downto 0) := "010";
constant F7_OP_SLT: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SLTU: std_logic_vector(2 downto 0) := "011";
constant F7_OP_SLTU: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_XOR: std_logic_vector(2 downto 0) := "100";
constant F7_OP_XOR: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SRL: std_logic_vector(2 downto 0) := "101";
constant F7_OP_SRL: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SRA: std_logic_vector(2 downto 0) := "101";
constant F7_OP_SRA: std_logic_vector(6 downto 0) := "0100000";
constant F3_OP_OR: std_logic_vector(2 downto 0) := "110";
constant F7_OP_OR: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_AND: std_logic_vector(2 downto 0) := "111";
constant F7_OP_AND: std_logic_vector(6 downto 0) := "0000000";

-- RV32M Extension
constant F7_OP_M_EXT: std_logic_vector(6 downto 0) := "0000001";
constant F3_OP_M_MUL: std_logic_vector(2 downto 0) := "000";
constant F3_OP_M_MULH: std_logic_vector(2 downto 0) := "001";
constant F3_OP_M_MULHSU: std_logic_vector(2 downto 0) := "010";
constant F3_OP_M_MULHU: std_logic_vector(2 downto 0) := "011";
constant F3_OP_M_DIV: std_logic_vector(2 downto 0) := "100";
constant F3_OP_M_DIVU: std_logic_vector(2 downto 0) := "101";
constant F3_OP_M_REM: std_logic_vector(2 downto 0) := "110";
constant F3_OP_M_REMU: std_logic_vector(2 downto 0) := "111";

-- bit 0 of the OP definitions denote unsigned ops; same as above
constant ALU_INT32_DIV_OP_UNSIGNED_BIT: integer := 0;
constant ALU_INT32_DIV_OP_DIV: std_logic_vector(1 downto 0) := "00";
constant ALU_INT32_DIV_OP_DIVU: std_logic_vector(1 downto 0) := "01";
constant ALU_INT32_DIV_OP_REM: std_logic_vector(1 downto 0) := "10";
constant ALU_INT32_DIV_OP_REMU: std_logic_vector(1 downto 0) := "11";

constant F3_MISCMEM_FENCE: std_logic_vector(2 downto 0) := "000";
constant F3_MISCMEM_FENCEI: std_logic_vector(2 downto 0) := "001";

constant F3_SYSTEM_ECALL: std_logic_vector(2 downto 0) := "000";
constant IMM_I_SYSTEM_ECALL: std_logic_vector(11 downto 0) := "000000000000";
constant F3_SYSTEM_EBREAK: std_logic_vector(2 downto 0) := "000";
constant IMM_I_SYSTEM_EBREAK: std_logic_vector(11 downto 0) := "000000000001";
constant F3_SYSTEM_CSRRW: std_logic_vector(2 downto 0) := "001";
constant F3_SYSTEM_CSRRS: std_logic_vector(2 downto 0) := "010";
constant F3_SYSTEM_CSRRC: std_logic_vector(2 downto 0) := "011";
constant F3_SYSTEM_CSRRWI: std_logic_vector(2 downto 0) := "101";
constant F3_SYSTEM_CSRRSI: std_logic_vector(2 downto 0) := "110";
constant F3_SYSTEM_CSRRCI: std_logic_vector(2 downto 0) := "111";

constant F3_PRIVOP: std_logic_vector(2 downto 0) := "000";

constant F7_PRIVOP_URET: std_logic_vector(6 downto 0)       := "0000000";
constant F7_PRIVOP_SRET_WFI: std_logic_vector(6 downto 0)   := "0001000";
constant F7_PRIVOP_MRET: std_logic_vector(6 downto 0)       := "0011000";
constant F7_PRIVOP_SFENCE_VMA: std_logic_vector(6 downto 0) := "0001001";

constant RD_PRIVOP: std_logic_vector(4 downto 0) := "00000";

constant R2_PRIV_RET: std_logic_vector(4 downto 0) := "00010";
constant R2_PRIV_WFI: std_logic_vector(4 downto 0) := "00101";

constant EXCEPTION_INT_USER_SOFTWARE:       std_logic_vector(XLEN32M1 downto 0):=  X"80000000";
constant EXCEPTION_INT_SUPERVISOR_SOFTWARE: std_logic_vector(XLEN32M1 downto 0):=  X"80000001";
--constant EXCEPTION_INT_RESERVED:          std_logic_vector(XLEN32M1 downto 0):=  X"80000002";
constant EXCEPTION_INT_MACHINE_SOFTWARE:    std_logic_vector(XLEN32M1 downto 0):=  X"80000003";
constant EXCEPTION_INT_USER_TIMER:          std_logic_vector(XLEN32M1 downto 0):=  X"80000004";
constant EXCEPTION_INT_SUPERVISOR_TIMER:    std_logic_vector(XLEN32M1 downto 0):=  X"80000005";
--constant EXCEPTION_INT_RESERVED:          std_logic_vector(XLEN32M1 downto 0):=  X"80000006";
constant EXCEPTION_INT_MACHINE_TIMER:       std_logic_vector(XLEN32M1 downto 0):=  X"80000007";
constant EXCEPTION_INT_USER_EXTERNAL:       std_logic_vector(XLEN32M1 downto 0):=  X"80000008";
constant EXCEPTION_INT_SUPERVISOR_EXTERNAL: std_logic_vector(XLEN32M1 downto 0):=  X"80000009";
--constant EXCEPTION_INT_RESERVED:          std_logic_vector(XLEN32M1 downto 0):=  X"8000000a";
constant EXCEPTION_INT_MACHINE_EXTERNAL:    std_logic_vector(XLEN32M1 downto 0):=  X"8000000b";

constant EXCEPTION_INSTRUCTION_ADDR_MISALIGNED: std_logic_vector(XLEN32M1 downto 0):=  X"00000000";
constant EXCEPTION_INSTRUCTION_ACCESS_FAULT:    std_logic_vector(XLEN32M1 downto 0):=  X"00000001";
constant EXCEPTION_INSTRUCTION_ILLEGAL:         std_logic_vector(XLEN32M1 downto 0):=  X"00000002";
constant EXCEPTION_BREAKPOINT:                  std_logic_vector(XLEN32M1 downto 0):=  X"00000003";
constant EXCEPTION_LOAD_ADDRESS_MISALIGNED:     std_logic_vector(XLEN32M1 downto 0):=  X"00000004";
constant EXCEPTION_LOAD_ACCESS_FAULT:           std_logic_vector(XLEN32M1 downto 0):=  X"00000005";
constant EXCEPTION_STORE_AMO_ADDRESS_MISALIGNED:std_logic_vector(XLEN32M1 downto 0):=  X"00000006";
constant EXCEPTION_STORE_AMO_ACCESS_FAULT:      std_logic_vector(XLEN32M1 downto 0):=  X"00000007";
constant EXCEPTION_ENVIRONMENT_CALL_FROM_UMODE: std_logic_vector(XLEN32M1 downto 0):=  X"00000008";
constant EXCEPTION_ENVIRONMENT_CALL_FROM_SMODE: std_logic_vector(XLEN32M1 downto 0):=  X"00000009";
--constant EXCEPTION_RESERVED:                  std_logic_vector(XLEN32M1 downto 0):=  X"0000000a";
constant EXCEPTION_ENVIRONMENT_CALL_FROM_MMODE: std_logic_vector(XLEN32M1 downto 0):=  X"0000000b";
constant EXCEPTION_INSTRUCTION_PAGE_FAULT:      std_logic_vector(XLEN32M1 downto 0):=  X"0000000c";
constant EXCEPTION_LOAD_PAGE_FAULT:             std_logic_vector(XLEN32M1 downto 0):=  X"0000000d";
--constant EXCEPTION_RESERVED:                  std_logic_vector(XLEN32M1 downto 0):=  X"0000000e";

constant CSR_ADDR_PRIVILEGE_BIT_START:  integer := 9;
constant CSR_ADDR_PRIVILEGE_BIT_END:    integer := 8;
constant CSR_ADDR_PRIVILEGE_USER:       std_logic_vector(1 downto 0):= "00";
constant CSR_ADDR_PRIVILEGE_SUPERVISOR: std_logic_vector(1 downto 0):= "01";
constant CSR_ADDR_PRIVILEGE_RESERVED:   std_logic_vector(1 downto 0):= "10";
constant CSR_ADDR_PRIVILEGE_MACHINE:    std_logic_vector(1 downto 0):= "11";

constant CSR_ADDR_ACCESS_BIT_START: integer := 11;
constant CSR_ADDR_ACCESS_BIT_END:   integer := 10;
constant CSR_ADDR_ACCESS_READONLY:  std_logic_vector(1 downto 0):= "11";

-- CSR Opcodes:
-- 0 - CSR Written
-- 1 - CSR Read
-- 2..3 0 operation
--    01 - read or write whole XLEN
--    10 - Set bits
--    11 - clear bits
-- 4 - immediate or register

constant CSR_OP_BITS_READ: integer := 0;
constant CSR_OP_BITS_WRITTEN: integer := 1;
constant CSR_OP_BITS_OPA: integer := 2;
constant CSR_OP_BITS_OPB: integer := 3;
constant CSR_OP_BITS_IMM: integer := 4;

constant CSR_MAINOP_WR: std_logic_vector(1 downto 0) := "01";
constant CSR_MAINOP_SET: std_logic_vector(1 downto 0) := "10";
constant CSR_MAINOP_CLEAR: std_logic_vector(1 downto 0) := "11";

constant CSR_OP_WR: std_logic_vector(4 downto 0) := "00100";
constant CSR_OP_W:  std_logic_vector(4 downto 0) := "00101";
constant CSR_OP_R:  std_logic_vector(4 downto 0) := "00110";

constant CSR_OP_SET_WR: std_logic_vector(4 downto 0) := "01000";
constant CSR_OP_SET_W:  std_logic_vector(4 downto 0) := "01001";
constant CSR_OP_SET_R:  std_logic_vector(4 downto 0) := "01010";

constant CSR_OP_CLEAR_WR: std_logic_vector(4 downto 0) := "01100";
constant CSR_OP_CLEAR_W:  std_logic_vector(4 downto 0) := "01101";
constant CSR_OP_CLEAR_R:  std_logic_vector(4 downto 0) := "01110";

constant CSR_OP_IMM_WR: std_logic_vector(4 downto 0) := "10100";
constant CSR_OP_IMM_W:  std_logic_vector(4 downto 0) := "10101";
constant CSR_OP_IMM_R:  std_logic_vector(4 downto 0) := "10110";

constant CSR_OP_IMM_SET_WR: std_logic_vector(4 downto 0) := "11000";
constant CSR_OP_IMM_SET_W:  std_logic_vector(4 downto 0) := "11001";
constant CSR_OP_IMM_SET_R:  std_logic_vector(4 downto 0) := "11010";

constant CSR_OP_IMM_CLEAR_WR: std_logic_vector(4 downto 0) := "11100";
constant CSR_OP_IMM_CLEAR_W:  std_logic_vector(4 downto 0) := "11101";
constant CSR_OP_IMM_CLEAR_R:  std_logic_vector(4 downto 0) := "11110";

end constants;

package body constants is

end constants;

constant EXCEPTION_STORE_AMO_PAGE_FAULT:        std_logic_vector(XLEN32M1 downto 0):=  X"0000000f";


----------------------------------------------------------------------------------
-- Project Name: RPU
-- Description: control unit
--
----------------------------------------------------------------------------------
-- Copyright 2016,2018,2019,2020 Colin Riley
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;

library work;
use work.constants.all;

entity control_unit is
    port (
        I_clk : in STD_LOGIC;
        I_reset : in STD_LOGIC;
        I_halt : in STD_LOGIC;
        I_aluop : in STD_LOGIC_VECTOR (6 downto 0);

        -- interrupts
        I_int_enabled : in std_logic;
        I_int : in STD_LOGIC;
        O_int_ack : out STD_LOGIC;
        I_int_mem_data : in STD_LOGIC_VECTOR(XLENM1 downto 0);
        O_idata : out STD_LOGIC_VECTOR(XLENM1 downto 0);
        O_set_idata : out STD_LOGIC;
        O_set_ipc : out STD_LOGIC;
        O_set_irpc : out STD_LOGIC;
        O_instTick : out STD_LOGIC;
        -- mem controller state and control
        I_misalignment : in STD_LOGIC;
        I_ready : in STD_LOGIC;
        O_execute : out STD_LOGIC;
        I_dataReady : in STD_LOGIC;

        -- alu stall input
        I_aluWait : in STD_LOGIC;
        I_aluMultiCy : in STD_LOGIC;
        O_state : out STD_LOGIC_VECTOR (6 downto 0)
    );
end control_unit;

architecture Behavioral of control_unit is
    signal s_state : STD_LOGIC_VECTOR(6 downto 0) := "0000001";

    signal mem_ready : std_logic;
    signal mem_execute : std_logic := '0';
    signal mem_dataReady : std_logic;

    signal mem_cycles : integer := 0;

    signal next_s_state : STD_LOGIC_VECTOR(6 downto 0) := "0000001";

    signal interrupt_state : STD_LOGIC_VECTOR(2 downto 0) := "000";
    signal interrupt_ack : STD_LOGIC := '0';
    signal interrupt_was_inactive : STD_LOGIC := '1';
    signal set_idata : STD_LOGIC := '0';
    signal set_ipc : STD_LOGIC := '0';
    signal instTick : STD_LOGIC := '0';
    signal s_hasWaited : STD_LOGIC := '0';

    signal s_check_alignint : integer := 0;
begin

    O_execute <= mem_execute;
    mem_ready <= I_ready;
    mem_dataReady <= I_dataReady;
    O_int_ack <= interrupt_ack;
    O_set_idata <= set_idata;
    O_set_irpc <= set_idata;
    O_set_ipc <= set_ipc;
    O_instTick <= instTick;

    process (I_clk)
    begin
        if rising_edge(I_clk) and I_halt = '0' then

            if I_reset = '1' then
                s_state <= "0000001";
                next_s_state <= "0000001";
                mem_cycles <= 0;
                mem_execute <= '0';
                interrupt_was_inactive <= '1';
                interrupt_ack <= '0';
                interrupt_state <= "000";
                set_ipc <= '0';
                O_idata <= X"00000000";
                set_idata <= '0';
                instTick <= '0';
            else
                case s_state is
                    ---------------------------
                    -- FETCH
                    when "0000001" => -- fetch

                        if s_check_alignint /= 0 then
                            -- If we've seen an alignment hint we need to stall here for s_check_alignint
                            -- cycles, checking for an interrupt each time. When it's 0 we give up.
                            if I_int_enabled = '1' and interrupt_was_inactive = '1' and I_int = '1' then
                                interrupt_ack <= '1';

                            else
                                s_check_alignint <= s_check_alignint - 1;
                            end if;
                        else

                            if I_int = '0' then
                                interrupt_was_inactive <= '1';
                            end if;
                            instTick <= '0';
                            if mem_cycles = 0 and mem_ready = '1' then
                                mem_execute <= '1';
                                mem_cycles <= 1;

                            elsif mem_cycles = 1 then
                                mem_execute <= '0';
                                mem_cycles <= 2;

                            elsif mem_cycles = 2 then
                                mem_execute <= '0';
                                if mem_dataReady = '1' then
                                    mem_cycles <= 0;
                                    s_state <= "0000010";
                                end if;
                            end if;

                        end if;

                    ---------------------------
                    -- DECODE
                    when "0000010" => --- decode
                        if I_int = '0' then
                            interrupt_was_inactive <= '1';
                        end if;
                        s_hasWaited <= '0';
                        s_state <= "0001000"; --E "0000100"; --R

                    ---------------------------
                    -- EXECUTE
                    when "0001000" => -- execute
                        if I_int = '0' then
                            interrupt_was_inactive <= '1';
                        end if;
                        --MEM/WB
                        -- if it's not a memory alu op, goto writeback
                        if (I_aluop(6 downto 2) = OPCODE_LOAD or
                            I_aluop(6 downto 2) = OPCODE_STORE) then
                            s_state <= "0010000"; -- MEM

                            --  -- mem load short cut
                            --  ISSUE - this fails to take into account the type of request, sizing, address correctly
                            --          and therefore needs removed for compliance to pass.
                            --  if I_misalignment = '0' and mem_cycles = 0 and mem_ready = '1' then
                            --      mem_execute <= '1';
                            --      mem_cycles <= 1;
                            --  end if;

                        else
                            if I_aluWait = '0' then
                                if I_aluMultiCy = '1' then
                                    if s_hasWaited = '1' then
                                        s_state <= "0100000"; -- WB
                                    end if;
                                else
                                    s_state <= "0100000"; -- WB
                                end if;
                                s_hasWaited <= '1';
                            end if;
                        end if;

                    ---------------------------
                    -- MEMORY
                    when "0010000" => -- mem
                        if I_int = '0' then
                            interrupt_was_inactive <= '1';
                        end if;

                        -- alignment traps here are tricky.
                        -- if we see the misalignment hint, wait 6 cycles and then test interrupt stall.
                        -- if no interrupt we need to re-run the stage.

                        if I_misalignment = '1' and s_check_alignint = 0 then
                            s_check_alignint <= 6;
                        elsif s_check_alignint > 0 then
                            if I_int_enabled = '1' and interrupt_was_inactive = '1' and I_int = '1' then
                                interrupt_ack <= '1';
                                interrupt_was_inactive <= '0';
                                interrupt_state <= "001";
                                next_s_state <= "0000001"; --F
                                s_state <= "1000000"; --F
                                s_check_alignint <= 0;
                            else
                                s_check_alignint <= s_check_alignint - 1;
                            end if;

                        else
                            if mem_cycles = 0 and mem_ready = '1' then

                                mem_execute <= '1';
                                mem_cycles <= 1;

                            elsif mem_cycles = 1 then
                                mem_execute <= '0';
                                -- if it's a write, go through
                                if I_aluop(6 downto 2) = OPCODE_STORE then
                                    mem_cycles <= 0;
                                    s_state <= "0100000"; -- WB
                                elsif mem_dataReady = '1' then
                                    -- if read, wait for data
                                    mem_cycles <= 0;
                                    s_state <= "0100000"; -- WB
                                end if;
                            end if;
                        end if;

                    ---------------------------
                    -- WRITEBACK
                    when "0100000" => -- writeback
                        -- check interrupt?
                        if I_int_enabled = '1' and interrupt_was_inactive = '1' and I_int = '1' then
                            interrupt_ack <= '1';
                            interrupt_was_inactive <= '0';
                            interrupt_state <= "001";
                            next_s_state <= "0000001"; --F
                            s_state <= "1000000"; --F
                        else
                            if I_int = '0' then
                                interrupt_was_inactive <= '1';
                            end if;
                            if I_misalignment = '1' and s_check_alignint = 0 then
                                s_check_alignint <= 3;
                            end if;

                            -- misalign interrupts take a while to propagate
                            -- this signal short cuts to ensure we can catch any misalignments before fetch.

                            s_state <= "0000001"; --F

                            -- if the mem system is ready, shortcut the fetch
                            -- at this point, the next PC/Branch should be set.
                            -- need to ensure the sizing is correct.
                            if I_misalignment = '0' and mem_cycles = 0 and mem_ready = '1' then -- shortcut
                                mem_execute <= '1'; -- shortcut
                                mem_cycles <= 2;    -- shortcut
                            end if;                 -- shortcut

                        end if;
                        instTick <= '1';
                    when "1000000" => --  stalls
                        if I_int = '0' then
                            interrupt_was_inactive <= '1';
                        end if;
                        instTick <= '0';
                        -- interrupt stall
                        if interrupt_state = "001" then
                            -- give a cycle of latency
                            -- set PC to interrupt vector.

                            set_ipc <= '1';
                            interrupt_state <= "101";

                        elsif interrupt_state = "101" then
                            set_ipc <= '0';
                            interrupt_ack <= '0';
                            interrupt_state <= "111";
                        elsif interrupt_state = "111" then
                            interrupt_state <= "000";
                            s_state <= "0000001"; --F
                        end if;
                    when "1001000" =>
                        -- alu 1 cycle stall
                        s_state <= "0100000"; -- WB
                    when others =>
                        s_state <= "0000001";
                end case;
            end if;
        end if;
    end process;

    O_state <= s_state;
end Behavioral;