summaryrefslogtreecommitdiffstats
path: root/hdl/tb_pic.vhd
blob: 75f385c3278920e28a94578569896de3a9bc3fee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.read_intel_hex_pack.all;

entity tb_pic is
    generic (
    CLK_FREQ  : positive := 50_000_000;   -- 50M, GW5A clock
    BAUD_RATE : positive := 115_200
  );
end entity tb_pic;

architecture behavioural of tb_pic is
  constant T_clk   : time   := 20 ns;  -- 50M
  constant HEX_FILE : string := "build/program.hex";
  constant SIM_CYCLES : integer := 800_000;

  signal clk    : std_logic := '0';
  signal reset  : std_logic := '1';
  signal opcode : std_logic_vector(13 downto 0);

  signal program_counter    : std_logic_vector(12 downto 0);
  signal work_reg           : std_logic_vector(7 downto 0);
  signal status             : std_logic_vector(2 downto 0);
  signal port_a             : std_logic_vector(7 downto 0);
  signal port_b             : std_logic_vector(7 downto 0);

  signal done : boolean := false;

  signal uart_tx : std_logic;
  signal uart_rx : std_logic := '1';  -- idle high (no incoming bytes)

  -- program memory: 1024 x 14-bit
  signal prog_mem : program_array := (others => (others => '0'));

  signal byte_in : std_logic_vector(7 downto 0);
  signal tx_should_send : std_logic;
  
  
begin

  clk <= not clk after T_clk / 2 when not done else unaffected;

  -- drive opcode from program memory using PC
  opcode <= prog_mem(to_integer(unsigned(program_counter)));

  dut : entity work.PIC(rtl)
    generic map (
      CLK_FREQ => 50_000_000   -- 10 MHz, matches T_clk = 100 ns
    )
    port map (
      clk                => clk,
      reset              => reset,
      opcode             => opcode,
      program_counter    => program_counter,
      work_reg           => work_reg,
      status             => status,
      port_a             => port_a,
      port_b             => port_b,
      uart_tx            => uart_tx,
      uart_rx            => uart_rx
    );

  tx_should_send <= '1';
  byte_in <= x"FC";
  
  uart_master: entity work.uart
    generic map (
      CLK_FREQ     => CLK_FREQ,
      BAUD_RATE    => BAUD_RATE,
      CLKS_PER_BIT => CLK_FREQ / BAUD_RATE)
    port map (
      clk            => clk,
      tx_should_send => tx_should_send,
      byte_in        => byte_in,
      tx_done        => open,
      baud_tick      => open,
      uart_tx        => uart_rx,
      uart_rx        => uart_tx,
      rd_en          => '0',
      rx_data        => open,
      rx_empty       => open,
      rx_full        => open);
  
  stimulus : process is
    variable mem : program_array;
  begin
    -- load hex file into program memory
    read_ihex_file(HEX_FILE, mem);
    prog_mem <= mem;

    -- reset pulse
    reset <= '1';
    wait for T_clk * 2;
    reset <= '0';

    -- run for SIM_CYCLES instruction cycles
    for i in 0 to SIM_CYCLES - 1 loop
      wait until rising_edge(clk);
    end loop;

    report "simulation done. port_a=" & integer'image(to_integer(unsigned(port_a)))
      & " port_b=" & integer'image(to_integer(unsigned(port_b)))
      severity note;

    done <= true;
    wait;
  end process stimulus;

end architecture behavioural;