summaryrefslogtreecommitdiffstats
path: root/hdl/timer0.vhd
diff options
context:
space:
mode:
authorVäinö Kauppila <vaino@vke.fi>2026-04-19 19:02:42 +0300
committerVäinö Kauppila <vaino@vke.fi>2026-04-19 19:02:42 +0300
commit46e1210381106707c2df7f07c56023eb6b760763 (patch)
tree6740a17199f76e2965a511dafcbc7ffb61ceafeb /hdl/timer0.vhd
parenteb8643ddbef43547eb7bfe58789a3908926c7258 (diff)
downloadvhdl_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/timer0.vhd')
-rw-r--r--hdl/timer0.vhd131
1 files changed, 131 insertions, 0 deletions
diff --git a/hdl/timer0.vhd b/hdl/timer0.vhd
new file mode 100644
index 0000000..c2846dc
--- /dev/null
+++ b/hdl/timer0.vhd
@@ -0,0 +1,131 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity timer0 is
+ generic (
+ CLK_FREQ : positive := 50_000_000
+ );
+ port (
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- External clock pin (used when T0CS='1')
+ t0cki : in std_logic;
+
+ -- OPTION_REG control bits
+ t0cs : in std_logic; -- 0=Fosc/4, 1=T0CKI
+ t0se : in std_logic; -- 0=rising edge, 1=falling edge
+ psa : in std_logic; -- 0=prescaler->Timer0, 1=prescaler->WDT
+ ps : in std_logic_vector(2 downto 0); -- prescaler rate select
+
+ -- TMR0 register interface (mapped at 0x01)
+ tmr0_we : in std_logic;
+ tmr0_in : in std_logic_vector(7 downto 0);
+ tmr0_out : out std_logic_vector(7 downto 0);
+
+ -- Overflow flag: pulses one clock on FFh->00h rollover
+ t0if : out std_logic
+ );
+end entity timer0;
+
+architecture rtl of timer0 is
+
+ pure function ps_rate(sel : std_logic_vector(2 downto 0)) return natural is
+ begin
+ case sel is
+ when "000" => return 2;
+ when "001" => return 4;
+ when "010" => return 8;
+ when "011" => return 16;
+ when "100" => return 32;
+ when "101" => return 64;
+ when "110" => return 128;
+ when others => return 256;
+ end case;
+ end function;
+
+ -- Fosc/4 tick generator (one pulse every 4 clocks)
+ constant FOSC4_DIV : positive := 4;
+ signal fosc4_cnt : natural range 0 to FOSC4_DIV - 1 := 0;
+ signal fosc4_tick : std_logic := '0';
+
+ -- 2FF synchroniser for the post-mux clock input
+ signal sync_ff1 : std_logic := '0';
+ signal sync_ff2 : std_logic := '0';
+ signal sync_prev : std_logic := '0'; -- for edge detection after sync
+ signal sync_tick : std_logic := '0'; -- one-cycle tick on selected edge
+
+ -- Prescaler
+ signal prescaler : unsigned(7 downto 0) := (others => '0');
+ signal ps_tick : std_logic := '0'; -- one-cycle pulse out of prescaler
+
+ -- TMR0 counter
+ signal tmr0 : unsigned(7 downto 0) := (others => '0');
+
+ -- Write inhibit: per datasheet, 2 cycles after a TMR0 write the
+ -- prescaler increment is blocked to avoid a spurious count
+ signal wr_inhibit : natural range 0 to 2 := 0;
+
+begin
+
+ fosc4_timer_proc : process(clk)
+ begin
+ if rising_edge(clk) then
+
+ fosc4_tick <= '0';
+
+ if fosc4_cnt = FOSC4_DIV - 1 then
+ fosc4_tick <= '1';
+ fosc4_cnt <= 0;
+ else
+ fosc4_cnt <= fosc4_cnt + 1;
+ end if;
+ end if;
+ end process fosc4_timer_proc;
+
+ prescaler_proc : process(clk)
+ begin
+ if rising_edge(clk) then
+ ps_tick <= '0';
+
+ if tmr0_we = '1' then
+ prescaler <= (others => '0');
+ elsif fosc4_tick = '1' and psa = '0' then
+ if to_integer(prescaler) + 1 >= ps_rate(ps) then
+ prescaler <= (others => '0');
+ ps_tick <= '1';
+ else
+ prescaler <= prescaler + 1;
+ end if;
+ end if;
+ end if;
+ end process prescaler_proc;
+
+ tmr0_out <= std_logic_vector(tmr0);
+
+ timer0_proc : process(clk)
+ begin
+ if rising_edge(clk) then
+ t0if <= '0';
+
+ -- 2FF sync
+ sync_ff1 <= '1' when (psa = '1' and fosc4_tick = '1') or
+ (psa = '0' and ps_tick = '1') else '0';
+ sync_ff2 <= sync_ff1;
+
+ if reset = '1' then
+ tmr0 <= (others => '0');
+ sync_ff1 <= '0';
+ sync_ff2 <= '0';
+ elsif tmr0_we = '1' then
+ tmr0 <= unsigned(tmr0_in);
+ elsif sync_ff2 = '1' then
+ if tmr0 = x"FF" then
+ t0if <= '1';
+ end if;
+ tmr0 <= tmr0 + 1;
+ end if;
+ end if;
+ end process timer0_proc;
+end architecture rtl;