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;