diff options
| author | Väinö Kauppila <vaino@vke.fi> | 2026-04-19 19:02:42 +0300 |
|---|---|---|
| committer | Väinö Kauppila <vaino@vke.fi> | 2026-04-19 19:02:42 +0300 |
| commit | 46e1210381106707c2df7f07c56023eb6b760763 (patch) | |
| tree | 6740a17199f76e2965a511dafcbc7ffb61ceafeb /hdl/dpram.vhd | |
| parent | eb8643ddbef43547eb7bfe58789a3908926c7258 (diff) | |
| download | vhdl_pic-46e1210381106707c2df7f07c56023eb6b760763.tar.gz vhdl_pic-46e1210381106707c2df7f07c56023eb6b760763.zip | |
BSRAM progmem. fix Makefile memory command that does not work. add interrupts, bank 1, timer0. Timer0 not tested.
Diffstat (limited to 'hdl/dpram.vhd')
| -rw-r--r-- | hdl/dpram.vhd | 128 |
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; |
