library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity test_rom is
  generic
  (
    addressWidth : in positive := 16;
    busWidth : in positive := 16
  );
  port
  (
    address : in std_logic_vector(addressWidth - 1 downto 0);
    dataOut : out std_logic_vector(busWidth - 1 downto 0)
  );
end test_rom;

architecture Behavioral of test_rom is
  constant alignment: positive := busWidth / 8;

---  type romtype is array(0 to 14) of std_logic_vector(15 downto 0);
---  signal romdata: romtype := (
---x"e180",
---x"e200",
---x"e301",
---x"e4ff",
---x"2210",
---x"3223",
---x"ed08",
---x"ea00",
---x"eb00",
---x"3aa3",
---x"fefe",
---x"3bb3",
---x"c0b4",
---x"fef8",
---x"ee08"
---);

  type romtype is array(0 to 10) of std_logic_vector(15 downto 0);
  signal romdata: romtype := (
    x"0000", -- NOP
    x"e02a", -- SET r0, 42
    x"e125", -- SET r1, 37
    x"2010", -- STORE r0, [r1]
    x"1210", -- LOAD r2, [r1]
    x"3322", -- ADD r3, r2, r2
    x"2310", -- STORE r3, [r1]
    x"c020", -- CMP r0, r2
    x"de04", -- BEQ pc, 4
    x"0000", -- NOP
    x"ee00"  -- SET pc, 0
  );
begin

  process(address) is
    variable index: natural;
  begin
    index := to_integer(unsigned(address)) / alignment;
    dataOut <= romdata(index);
  end process;

end Behavioral;

---

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

entity cpu_test is
end cpu_test;

architecture rtl of cpu_test is

  component clock is port(clk: out std_logic);
  end component;

  component cpu is port(
                         clk: in std_logic;
                         rst: in std_logic;

                         code_data: in std_logic_vector(15 downto 0);
                         code_addr: out std_logic_vector(15 downto 0);

                         mem_in: in std_logic_vector(15 downto 0);
                         mem_out: out std_logic_vector(15 downto 0);
                         mem_addr: out std_logic_vector(15 downto 0);
                         mem_write: out std_logic
                       );
  end component;

  component test_rom is port (
                               address : in std_logic_vector(15 downto 0);
                               dataOut : out std_logic_vector(15 downto 0)
                             );
  end component;

  signal clk, rst, mem_write: std_logic;
  signal rom_data, rom_addr, mem_in, mem_out, mem_addr: std_logic_vector(15 downto 0);

begin
  heartbeat: clock port map(clk);
  dut: cpu port map(clk, rst, rom_data, rom_addr, mem_in, mem_out, mem_addr, mem_write);
  rom: test_rom port map(rom_addr, rom_data);

  process
  begin
    rst <= '1';

    wait for 1 ns;
    assert(rom_addr=x"0000") report "Fail rst" severity error;

    rst <= '0';

    wait for 10 ns;
    assert(rom_addr=x"0002") report "Fail PC advance @00" severity error;

    wait for 20 ns;
    assert(rom_addr=x"0006") report "Fail PC @06" severity error;
    assert(mem_write='1') report "Fail set mem_write to 1" severity error;
    assert(mem_addr=x"0025") report "Fail set mem_addr to 0x25" severity error;
    assert(mem_out=x"002a") report "Fail set mem_out to 42" severity error;

    wait for 10 ns;
    assert(rom_addr=x"0008") report "Fail PC @08" severity error;
    assert(mem_write='0') report "Fail set mem_write to 0" severity error;
    assert(mem_addr=x"0025") report "Fail set mem_addr to 0x25" severity error;
    mem_in <= x"002a";

    wait for 20 ns;
    assert(rom_addr=x"000c") report "Fail PC @0c" severity error;
    assert(mem_write='1') report "Fail set mem_write to 1" severity error;
    assert(mem_addr=x"0025") report "Fail set mem_addr to 0x25" severity error;
    assert(mem_out=x"0054") report "Fail set mem_out to 84" severity error;

    wait for 30 ns;
    assert(rom_addr=x"0014") report "Fail to branch" severity error;

    wait for 10 ns;
    assert(rom_addr=x"0000") report "Fail to jump" severity error;

    assert false report "Test done." severity note;
    wait;
  end process;
end rtl;