summaryrefslogtreecommitdiffstats
path: root/PIC/dpram.vhd
blob: 44d7adf6b67ae15fb3126b77c8ea6a9262374fb3 (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;

-- Data memory with UART memory-mapped registers.
-- Addresses 0x70-0x72 are used (unimplemented in real PIC16F84A, no header conflict):
--   0x70  UART_TX     write: send byte (held until tx_done)
--   0x71  UART_RX     read:  current FIFO head (FWFT), pulses rd_en to pop
--   0x72  UART_STATUS read:  "00000" & rx_full & rx_empty & tx_busy

entity dpram is
  generic (DEPTH : positive := 128);
  port (
    clk      : in  std_logic;
    we       : in  std_logic;
    re       : in  std_logic;
    d        : in  std_logic_vector(7 downto 0);
    d_status : in  std_logic_vector(7 downto 0);
    addr     : in  std_logic_vector(6 downto 0);
    q        : out std_logic_vector(7 downto 0);
    q_status : out std_logic_vector(2 downto 0);

    port_a    : out std_logic_vector(7 downto 0);
    port_b    : out std_logic_vector(7 downto 0);
    we_status : in  std_logic;

    -- UART interface
    uart_tx_byte  : out std_logic_vector(7 downto 0) := (others => '0');
    uart_tx_send  : out std_logic                    := '0';
    uart_tx_done  : in  std_logic;
    uart_rx_byte  : in  std_logic_vector(7 downto 0);
    uart_rx_rd_en : out std_logic                    := '0';
    uart_rx_empty : in  std_logic;
    uart_rx_full  : in  std_logic
  );
end entity dpram;

architecture rtl of dpram is
  type mem_t is
    array (0 to DEPTH - 1)
    of std_logic_vector(7 downto 0);

  signal mem             : mem_t     := (others => (others => '0'));
  signal uart_tx_pending : std_logic := '0';

begin
  -- STATUS output is combinatorial
  q_status <= mem(16#03#)(2 downto 0);

  port_a <= mem(16#05#);
  port_b <= mem(16#06#);

  -- tx_send is high while a transmission is in progress
  uart_tx_send <= uart_tx_pending;

  -- SR: set when CPU writes to 0x08, clear when UART asserts tx_done
  tx_ctrl : process(clk)
  begin
    if rising_edge(clk) then
      if we = '1' and addr = "1110000" then   -- 0x70 UART_TX
        uart_tx_byte    <= d;
        uart_tx_pending <= '1';
      elsif uart_tx_done = '1' then
        uart_tx_pending <= '0';
      end if;
    end if;
  end process tx_ctrl;

  read : process(clk)
  begin
    if rising_edge(clk) then
      uart_rx_rd_en <= '0';   -- default: no pop
      if re = '1' then
        if addr = "1110001" then              -- 0x71 UART_RX
          q <= uart_rx_byte;                  -- FWFT head, valid combinatorially
          if uart_rx_empty = '0' then
            uart_rx_rd_en <= '1';             -- advance FIFO pointer
          end if;
        elsif addr = "1110010" then           -- 0x72 UART_STATUS
          q <= "00000" & uart_rx_full & uart_rx_empty & uart_tx_pending;
        else
          q <= mem(to_integer(unsigned(addr)));
        end if;
      end if;
    end if;
  end process read;

  write : process(clk)
  begin
    if rising_edge(clk) then
      if we_status = '1' then
        mem(16#03#) <= d_status;
      end if;
      if we = '1' then
        if addr = "0000011" then              -- 0x03 STATUS: direct write
          mem(16#03#) <= d;
        elsif addr = "1110000" or            -- 0x70 UART_TX
              addr = "1110001" or            -- 0x71 UART_RX (read-only but handled gracefully)
              addr = "1110010" then          -- 0x72 UART_STATUS (read-only)
          -- UART-mapped addresses: don't write to RAM; still update STATUS
          mem(16#03#) <= d_status;
        else
          mem(16#03#) <= d_status;
          mem(to_integer(unsigned(addr))) <= d;
        end if;
      end if;
    end if;
  end process write;

end architecture rtl;