summaryrefslogtreecommitdiffstats
path: root/hdl/dpram.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'hdl/dpram.vhd')
-rw-r--r--hdl/dpram.vhd128
1 files changed, 108 insertions, 20 deletions
diff --git a/hdl/dpram.vhd b/hdl/dpram.vhd
index 44d7adf..92b57f2 100644
--- a/hdl/dpram.vhd
+++ b/hdl/dpram.vhd
@@ -2,23 +2,27 @@ 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):
+-- Data memory with UART and 1-Wire memory-mapped registers.
+-- Addresses 0x70-0x72 are UART (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
+-- Addresses 0x73-0x75 are 1-Wire:
+-- 0x73 OW_DATA write: tx_byte to send; read: rx_byte received
+-- 0x74 OW_CMD write: bits[1:0]=op (00=reset,01=write,10=read), any write pulses start
+-- 0x75 OW_STATUS read: "000000" & presence & busy
entity dpram is
- generic (DEPTH : positive := 128);
+ generic (DEPTH : positive := 256);
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);
+ addr : in std_logic_vector(7 downto 0);
q : out std_logic_vector(7 downto 0);
- q_status : out std_logic_vector(2 downto 0);
+ q_status : out std_logic_vector(7 downto 0);
port_a : out std_logic_vector(7 downto 0);
port_b : out std_logic_vector(7 downto 0);
@@ -31,7 +35,29 @@ entity dpram is
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
+ uart_rx_full : in std_logic;
+
+ -- 1-Wire interface
+ ow_tx_byte : out std_logic_vector(7 downto 0) := (others => '0');
+ ow_op : out std_logic_vector(1 downto 0) := "00";
+ ow_start : out std_logic := '0';
+ ow_rx_byte : in std_logic_vector(7 downto 0);
+ ow_presence : in std_logic;
+ ow_busy : in std_logic;
+
+ -- Timer0 interface
+ tmr0_val : in std_logic_vector(7 downto 0); -- current TMR0 value
+ tmr0_we : out std_logic := '0'; -- CPU writing TMR0
+ tmr0_in : out std_logic_vector(7 downto 0) := (others => '0');
+
+ -- OPTION_REG (bank 1, 0x81) — read by timer0
+ option_reg : out std_logic_vector(7 downto 0);
+
+ -- Interrupt control (INTCON at 0x0B)
+ t0if_set : in std_logic; -- timer0 overflow: sets INTCON.T0IF (bit 2)
+ gie_clear : in std_logic; -- interrupt ack: clears INTCON.GIE (bit 7)
+ gie_set : in std_logic; -- RETFIE: sets INTCON.GIE (bit 7)
+ irq_pending : out std_logic -- GIE & T0IE & T0IF
);
end entity dpram;
@@ -42,10 +68,13 @@ architecture rtl of dpram is
signal mem : mem_t := (others => (others => '0'));
signal uart_tx_pending : std_logic := '0';
+ signal ow_start_i : std_logic := '0';
+ signal ow_op_i : std_logic_vector(1 downto 0) := "00";
+ signal ow_tx_byte_i : std_logic_vector(7 downto 0) := (others => '0');
begin
- -- STATUS output is combinatorial
- q_status <= mem(16#03#)(2 downto 0);
+ -- STATUS output is combinatorial (full 8-bit register)
+ q_status <= mem(16#03#);
port_a <= mem(16#05#);
port_b <= mem(16#06#);
@@ -53,11 +82,21 @@ begin
-- tx_send is high while a transmission is in progress
uart_tx_send <= uart_tx_pending;
+ ow_start <= ow_start_i;
+ ow_op <= ow_op_i;
+ ow_tx_byte <= ow_tx_byte_i;
+
+ option_reg <= mem(16#81#);
+ irq_pending <= mem(16#0B#)(7) and mem(16#0B#)(5) and mem(16#0B#)(2);
+
+ tmr0_we <= '1' when we = '1' and addr = "00000001" else '0';
+ tmr0_in <= d;
+
-- 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
+ if we = '1' and addr = "01110000" then -- 0x70 UART_TX
uart_tx_byte <= d;
uart_tx_pending <= '1';
elsif uart_tx_done = '1' then
@@ -66,18 +105,48 @@ begin
end if;
end process tx_ctrl;
+ ow_ctrl : process(clk)
+ begin
+ if rising_edge(clk) then
+ ow_start_i <= '0';
+ if we = '1' then
+ if addr = "01110011" then -- 0x73 OW_DATA
+ ow_tx_byte_i <= d;
+ elsif addr = "01110100" then -- 0x74 OW_CMD
+ ow_op_i <= d(1 downto 0);
+ ow_start_i <= '1';
+ end if;
+ end if;
+ end if;
+ end process ow_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 addr = "00000000" or
+ addr = "10000000" then -- 0x00/0x80 INDF: indirect via FSR
+ q <= mem(to_integer(unsigned(mem(16#04#))));
+ elsif addr = "00000001" then -- 0x01 TMR0 (bank 0, read from timer0)
+ q <= tmr0_val;
+ elsif addr = "00001011" or
+ addr = "10001011" then -- 0x0B/0x8B INTCON (mirrored)
+ q <= mem(16#0B#);
+ elsif addr = "01110001" then -- 0x71 UART_RX
+ q <= uart_rx_byte;
if uart_rx_empty = '0' then
- uart_rx_rd_en <= '1'; -- advance FIFO pointer
+ uart_rx_rd_en <= '1';
end if;
- elsif addr = "1110010" then -- 0x72 UART_STATUS
+ elsif addr = "01110010" then -- 0x72 UART_STATUS
q <= "00000" & uart_rx_full & uart_rx_empty & uart_tx_pending;
+ elsif addr = "01110011" then -- 0x73 OW_DATA
+ q <= ow_rx_byte;
+ elsif addr = "01110101" then -- 0x75 OW_STATUS
+ q <= "000000" & ow_presence & ow_busy;
+ elsif addr = "00000011" or
+ addr = "10000011" then -- 0x03/0x83 STATUS (mirrored)
+ q <= mem(16#03#);
else
q <= mem(to_integer(unsigned(addr)));
end if;
@@ -89,21 +158,40 @@ begin
begin
if rising_edge(clk) then
if we_status = '1' then
- mem(16#03#) <= d_status;
+ -- only Z/DC/C (bits 2:0) come from ALU; preserve RP0, TO, PD etc.
+ mem(16#03#) <= mem(16#03#)(7 downto 3) & d_status(2 downto 0);
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
+ if addr = "00000000" or
+ addr = "10000000" then -- 0x00/0x80 INDF: indirect via FSR
mem(16#03#) <= d_status;
+ mem(to_integer(unsigned(mem(16#04#)))) <= d;
+ elsif addr = "00000001" then -- 0x01 TMR0: routed to timer0, not RAM
+ mem(16#03#) <= mem(16#03#)(7 downto 3) & d_status(2 downto 0);
+ elsif addr = "00001011" or
+ addr = "10001011" then -- 0x0B/0x8B INTCON (mirrored): direct write
+ mem(16#0B#) <= d;
+ elsif addr = "00000011" or
+ addr = "10000011" then -- 0x03/0x83 STATUS (mirrored): direct write
+ mem(16#03#) <= d;
+ elsif addr = "01110000" or -- 0x70 UART_TX
+ addr = "01110001" or -- 0x71 UART_RX (read-only)
+ addr = "01110010" or -- 0x72 UART_STATUS (read-only)
+ addr = "01110011" or -- 0x73 OW_DATA
+ addr = "01110100" or -- 0x74 OW_CMD
+ addr = "01110101" then -- 0x75 OW_STATUS (read-only)
+ -- peripheral-mapped addresses: don't write to RAM
+ mem(16#03#) <= mem(16#03#)(7 downto 3) & d_status(2 downto 0);
else
mem(16#03#) <= d_status;
mem(to_integer(unsigned(addr))) <= d;
end if;
end if;
+
+ -- Hardware INTCON modifications (last = highest priority)
+ if t0if_set = '1' then mem(16#0B#)(2) <= '1'; end if;
+ if gie_clear = '1' then mem(16#0B#)(7) <= '0'; end if;
+ if gie_set = '1' then mem(16#0B#)(7) <= '1'; end if;
end if;
end process write;