]> git.the-white-hart.net Git - vhdl/commitdiff
Update project
authorrs <>
Thu, 3 Jul 2025 04:57:27 +0000 (23:57 -0500)
committerrs <>
Thu, 3 Jul 2025 04:57:27 +0000 (23:57 -0500)
* Add single stepping back to CPU
* Separate flash and RAM cyc signals
* Add timers
* Fix interrupt bug

libraries/timer/tests/test_timer.vhd [new file with mode: 0644]
libraries/timer/timer.vhd [new file with mode: 0644]
projects/cpu_0/cpu.vhd
projects/cpu_0/nexys2.vhd
projects/cpu_0/tests/test_cpu.vhd

diff --git a/libraries/timer/tests/test_timer.vhd b/libraries/timer/tests/test_timer.vhd
new file mode 100644 (file)
index 0000000..c678538
--- /dev/null
@@ -0,0 +1,90 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_timer is
+end test_timer;
+
+
+architecture behavior of test_timer is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal rst_i: std_logic;
+       signal clk_i: std_logic;
+       signal cyc_i: std_logic;
+       signal stb_i: std_logic;
+       signal we_i:  std_logic;
+       signal ack_o: std_logic;
+       signal adr_i: std_logic_vector(1 downto 0);
+       signal dat_i: std_logic_vector(7 downto 0);
+       signal dat_o: std_logic_vector(7 downto 0);
+       signal zero:  std_logic;
+
+begin
+
+       p_test: process
+       begin
+               -- Initial values
+               cyc_i <= '0';
+               stb_i <= '0';
+               we_i  <= '0';
+               dat_i <= (others => '0');
+
+               -- Reset
+               rst_i <= '1';
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait for CLK_I_PERIOD;
+
+               -- Set a value in the timer and start it
+               dat_i <= x"00";
+               adr_i <= "11";
+               we_i  <= '1';
+               stb_i <= '1';
+               cyc_i <= '1';
+               wait for CLK_I_PERIOD;
+               dat_i <= x"00";
+               adr_i <= "10";
+               wait for CLK_I_PERIOD;
+               dat_i <= x"01";
+               adr_i <= "01";
+               wait for CLK_I_PERIOD;
+               dat_i <= "00001111";
+               adr_i <= "00";
+               wait for CLK_I_PERIOD;
+               cyc_i <= '0';
+               stb_i <= '0';
+               we_i  <= '0';
+
+               -- Done
+               wait;
+       end process;
+
+
+       e_uut: entity work.timer
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+                       cyc_i => cyc_i,
+                       stb_i => stb_i,
+                       we_i  => we_i,
+                       ack_o => ack_o,
+                       adr_i => adr_i,
+                       dat_i => dat_i,
+                       dat_o => dat_o,
+                       zero  => zero
+               );
+
+
+       p_clk: process
+       begin
+               clk_i <= '0';
+               wait for CLK_I_PERIOD/2;
+               clk_i <= '1';
+               wait for CLK_I_PERIOD/2;
+       end process;
+
+end;
diff --git a/libraries/timer/timer.vhd b/libraries/timer/timer.vhd
new file mode 100644 (file)
index 0000000..02ae009
--- /dev/null
@@ -0,0 +1,127 @@
+--------------------------------------------------------------------------------
+-- timer - Wishbone-bus generic timer
+--------------------------------------------------------------------------------
+--
+--    +---+---+---+---+---+---+---+---+
+--    | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+--    +---+---+---+---+---+---+---+---+
+-- 0  |               | Z |IEN|AUT|ENA| CTRL
+--    +---------------+---+---+---+---+
+-- 1  |            COUNT_L            | (TRIGGER)
+--    +-------------------------------+
+-- 2  |            COUNT_M            |
+--    +-------------------------------+
+-- 3  |            COUNT_H            |
+--    +-------------------------------+
+--
+-- CTRL register bits
+-- ENA - Enable counter
+-- AUT - Enable auto-restart
+-- IEN - Interupt enable
+-- Z   - Counter hit zero interrupt (W1C)
+--
+-- COUNT_L/M/H
+-- 24-bit counter value access
+-- Counter value is loaded into registers when COUNT_L is read
+-- Counter value and auto-reload value are captured when COUNT_L is written
+--
+-- Notes:
+-- Counter counts at 1/256th of the clock rate
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_misc.all;
+use ieee.numeric_std.all;
+
+
+entity timer is
+       port (
+               rst_i: in  std_logic;
+               clk_i: in  std_logic;
+
+               cyc_i: in  std_logic;
+               stb_i: in  std_logic;
+               we_i:  in  std_logic;
+               ack_o: out std_logic;
+               adr_i: in  std_logic_vector(1 downto 0);
+               dat_i: in  std_logic_vector(7 downto 0);
+               dat_o: out std_logic_vector(7 downto 0);
+
+               zero:  out std_logic
+       );
+end timer;
+
+
+architecture behavioral of timer is
+
+       signal ena_reg:    std_logic;
+       signal aut_reg:    std_logic;
+       signal ien_reg:    std_logic;
+       signal z_reg:      std_logic;
+       signal count_reg:  std_logic_vector(31 downto 0);
+       signal reload_reg: std_logic_vector(23 downto 0);
+       signal temp_m_reg: std_logic_vector(7 downto 0);
+       signal temp_h_reg: std_logic_vector(7 downto 0);
+
+       signal is_zero:    std_logic;
+
+begin
+
+       process (rst_i, clk_i, cyc_i, stb_i, we_i, adr_i, dat_i,
+                temp_h_reg, temp_m_reg, z_reg, count_reg, reload_reg)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               ena_reg    <= '0';
+                               aut_reg    <= '0';
+                               ien_reg    <= '0';
+                               z_reg      <= '0';
+                               count_reg  <= (others => '0');
+                               reload_reg <= (others => '0');
+                               temp_m_reg <= (others => '0');
+                               temp_h_reg <= (others => '0');
+                       else
+                               if ena_reg = '1' and is_zero = '0' then
+                                       count_reg <= std_logic_vector(unsigned(count_reg) - 1);
+                               elsif is_zero = '1' then
+                                       z_reg <= '1';
+                                       if aut_reg = '1' then
+                                               count_reg <= reload_reg & x"ff";
+                                       end if;
+                               end if;
+
+                               if cyc_i = '1' and stb_i = '1' and we_i = '1' then
+                                       case adr_i is
+                                               when "00"   => ena_reg    <= dat_i(0);
+                                                              aut_reg    <= dat_i(1);
+                                                              ien_reg    <= dat_i(2);
+                                                              z_reg      <= z_reg and (not dat_i(3));  -- W1C
+                                               when "01"   => count_reg  <= temp_h_reg & temp_m_reg & dat_i & x"ff";
+                                                              reload_reg <= temp_h_reg & temp_m_reg & dat_i;
+                                               when "10"   => temp_m_reg <= dat_i;
+                                               when "11"   => temp_h_reg <= dat_i;
+                                               when others => null;
+                                       end case;
+                               elsif cyc_i = '1' and stb_i = '1' and we_i = '0' and adr_i = "01" then
+                                       -- Load temp registers for reading in later cycles
+                                       temp_m_reg <= count_reg(23 downto 16);
+                                       temp_h_reg <= count_reg(31 downto 24);
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+       with adr_i select dat_o <=
+               "0000" & z_reg & ien_reg & aut_reg & ena_reg when "00",
+               count_reg(15 downto 8)                       when "01",
+               temp_m_reg                                   when "10",
+               temp_h_reg                                   when others;
+
+       ack_o <= '1';
+
+       is_zero <= not or_reduce(count_reg(31 downto 8));
+
+       zero <= z_reg and ien_reg;
+
+end behavioral;
index d7dde24156d2d2b0bd98cf14947af1542364d8fb..e8fd785edc7f9a66d86fdc5918c7c26c08475de0 100644 (file)
@@ -52,7 +52,16 @@ entity cpu is
                dat_i: in  std_logic_vector(7 downto 0);
 
                int_i: in  std_logic;
-               vec_i: in  std_logic_vector(7 downto 0)
+               vec_i: in  std_logic_vector(7 downto 0);
+
+               -- Debugging
+               halt_i: in  std_logic;
+               step_i: in  std_logic;
+               pc_o:   out std_logic_vector(31 downto 0);
+               ins_o:  out std_logic_vector(7 downto 0);
+               t_o:    out std_logic_vector(31 downto 0);
+               n_o:    out std_logic_vector(31 downto 0);
+               r_o:    out std_logic_vector(31 downto 0)
        );
 end cpu;
 
@@ -60,6 +69,7 @@ end cpu;
 architecture behavioral of cpu is
 
        type state_t is (
+               S_WAIT,  S_FETCH2,
                S_RESET, S_FETCH, S_MEMORY,
                S_IMM8,  S_IMM32_0, S_IMM32_1, S_IMM32_2, S_IMM32_3,
                S_LD8,   S_LD32_0,  S_LD32_1,  S_LD32_2,  S_LD32_3,
@@ -155,6 +165,13 @@ architecture behavioral of cpu is
 
 begin
 
+       -- Debugging signals
+       pc_o  <= pc_reg;
+       ins_o <= ins_reg;
+       t_o   <= s_t_reg;
+       n_o   <= s_n_reg;
+       r_o   <= r_tos_reg;
+
        -- Control state machine
        process (rst_i, clk_i, state_next)
        begin
@@ -167,7 +184,7 @@ begin
                end if;
        end process;
 
-       process (state_reg, ack_i, ins_decode, int_i, ins_pc_sel, imask_reg)
+       process (state_reg, ack_i, ins_decode, int_i, ins_pc_sel, imask_reg, step_i, halt_i)
        begin
                state_next <= state_reg;
                cyc_o      <= '0';
@@ -195,6 +212,16 @@ begin
 
                case state_reg is
                        when S_FETCH =>
+                               if halt_i = '0' then
+                                       state_next <= S_FETCH2;
+                               elsif step_i = '0' then
+                                       state_next <= S_WAIT;
+                               end if;
+                       when S_WAIT =>
+                               if step_i = '1' then
+                                       state_next <= S_FETCH2;
+                               end if;
+                       when S_FETCH2 =>
                                adr_sel <= ADR_PC;
                                cyc_o   <= '1';
                                stb_o   <= '1';
@@ -212,7 +239,7 @@ begin
                                -- in the S_EXEC state, which would otherwise be necessary to make
                                -- sure we don't enter an interrupt after a "mask-int" instruction
                                -- and then return with interrupts unmasked into a critical section
-                               imask_set <= ins_decode.imask_set;
+                               imask_clr <= ins_decode.imask_clr;
 
                                case ins_decode.mem_op is
                                        when MEM_IMM8  => state_next <= S_IMM8;
@@ -414,10 +441,10 @@ begin
                                -- The flag will be cleared in the next clock cycle, so the next
                                -- instruction is guaranteed to be executed if an interrupt is
                                -- pending, useful for clearing the interrupt flag and then returning
-                               imask_clr <= ins_decode.imask_clr;
+                               imask_set <= ins_decode.imask_set;
 
                                -- Check for interrupts during the execute step so we don't have any in-progress memory operations to cancel
-                               if int_i = '1' and imask_reg = '0' then
+                               if int_i = '1' and imask_reg = '1' then
                                        state_next <= S_INT;
                                else
                                        state_next <= S_FETCH;
@@ -441,7 +468,7 @@ begin
                                pc_sel     <= PC_INTVEC;
 
                                -- Mask further interruptions
-                               imask_set  <= '1';
+                               imask_clr  <= '1';
 
                                state_next <= S_FETCH;
 
index eb581be9d3d3eed26ab4680926076234fef2a2c6..4e44ee857e8c6bfe468a5efc984c1a0361f46365 100644 (file)
@@ -78,7 +78,8 @@ architecture behavioral of nexys2 is
        signal dat_mosi:          std_logic_vector(7 downto 0);
        signal dat_miso:          std_logic_vector(7 downto 0);
 
-       signal mem_cyc:           std_logic;
+       signal fls_cyc:           std_logic;
+       signal ram_cyc:           std_logic;
        signal mem_ack:           std_logic;
        signal mem_miso:          std_logic_vector(7 downto 0);
 
@@ -98,6 +99,14 @@ architecture behavioral of nexys2 is
        signal uart_ack:          std_logic;
        signal uart_miso:         std_logic_vector(7 downto 0);
 
+       signal timer0_cyc:        std_logic;
+       signal timer0_ack:        std_logic;
+       signal timer0_miso:       std_logic_vector(7 downto 0);
+
+       signal timer1_cyc:        std_logic;
+       signal timer1_ack:        std_logic;
+       signal timer1_miso:       std_logic_vector(7 downto 0);
+
        -- Interrupt signals
        signal host_flags:        std_logic_vector(7 downto 0);
 
@@ -121,6 +130,9 @@ architecture behavioral of nexys2 is
        signal uart_err_parity:   std_logic;
        signal uart_err_overflow: std_logic;
 
+       signal timer0_zero:       std_logic;
+       signal timer1_zero:       std_logic;
+
        -- Memory physical interface, routed through host controller
        signal d_MemOE:           std_logic;
        signal d_MemWR:           std_logic;
@@ -143,6 +155,16 @@ architecture behavioral of nexys2 is
        signal int_vec:           std_logic_vector(7 downto 0);
        signal ints:              std_logic_vector(15 downto 0);
 
+       -- Debug signals
+       signal deb_wait: std_logic;
+       signal deb_pc:   std_logic_vector(31 downto 0);
+       signal deb_ins:  std_logic_vector(7 downto 0);
+       signal deb_t:    std_logic_vector(31 downto 0);
+       signal deb_n:    std_logic_vector(31 downto 0);
+       signal deb_r:    std_logic_vector(31 downto 0);
+       signal debug_i:  std_logic_vector(63 downto 0);
+       signal debug_o:  std_logic_vector(63 downto 0);
+
 begin
 
        e_cpu: entity work.cpu
@@ -159,9 +181,23 @@ begin
                        dat_i => dat_miso,
 
                        int_i => int_cpu,
-                       vec_i => int_vec
+                       vec_i => int_vec,
+
+                       halt_i => sw(7),
+                       step_i => deb_wait,
+                       pc_o  => deb_pc,
+                       ins_o => deb_ins,
+                       t_o   => deb_t,
+                       n_o   => deb_n,
+                       r_o   => deb_r
                );
 
+       deb_wait <= debug_i(0);
+       with debug_i(2 downto 1) select debug_o <=
+               x"000000" & deb_ins & deb_pc when "00",
+               deb_n & deb_t                when "01",
+               x"00000000" & deb_r          when others;
+
        int_vec(7 downto 4) <= (others => '0');
        ints(0) <= '0';
        e_int: entity work.int_ctrl
@@ -183,7 +219,7 @@ begin
        -- UART:  0x02004010-0x02004017
        e_mapper: entity utility.wb_mapper_a32d8
                generic map (
-                       N => 5
+                       N => 8
                )
                port map (
                        cyc_i    => cyc,
@@ -191,35 +227,50 @@ begin
                        adr_i    => adr,
                        dat_o    => dat_miso,
 
-                       mask(0)  => "00000010000000000000000000000000",
-                       mask(1)  => "00000010000000000100000000000000",
-                       mask(2)  => "00000010000000000100000000011000",
+                       mask(0)  => "00000011000000000000000000000000",
+                       mask(1)  => "00000011000000000000000000000000",
+                       mask(2)  => "00000010000000000100000000000000",
                        mask(3)  => "00000010000000000100000000011000",
                        mask(4)  => "00000010000000000100000000011000",
+                       mask(5)  => "00000010000000000100000000011000",
+                       mask(6)  => "00000010000000000100000000011100",
+                       mask(7)  => "00000010000000000100000000011100",
 
                        match(0) => "00000000000000000000000000000000",
-                       match(1) => "00000010000000000000000000000000",
-                       match(2) => "00000010000000000100000000000000",
-                       match(3) => "00000010000000000100000000001000",
-                       match(4) => "00000010000000000100000000010000",
-
-                       cyc_o(0) => mem_cyc,
-                       cyc_o(1) => tile_cyc,
-                       cyc_o(2) => host_cyc,
-                       cyc_o(3) => ps2_cyc,
-                       cyc_o(4) => uart_cyc,
+                       match(1) => "00000001000000000000000000000000",
+                       match(2) => "00000010000000000000000000000000",
+                       match(3) => "00000010000000000100000000000000",
+                       match(4) => "00000010000000000100000000001000",
+                       match(5) => "00000010000000000100000000010000",
+                       match(6) => "00000010000000000100000000011000",
+                       match(7) => "00000010000000000100000000011100",
+
+                       cyc_o(0) => fls_cyc,
+                       cyc_o(1) => ram_cyc,
+                       cyc_o(2) => tile_cyc,
+                       cyc_o(3) => host_cyc,
+                       cyc_o(4) => ps2_cyc,
+                       cyc_o(5) => uart_cyc,
+                       cyc_o(6) => timer0_cyc,
+                       cyc_o(7) => timer1_cyc,
 
                        ack_i(0) => mem_ack,
-                       ack_i(1) => tile_ack,
-                       ack_i(2) => host_ack,
-                       ack_i(3) => ps2_ack,
-                       ack_i(4) => uart_ack,
+                       ack_i(1) => mem_ack,
+                       ack_i(2) => tile_ack,
+                       ack_i(3) => host_ack,
+                       ack_i(4) => ps2_ack,
+                       ack_i(5) => uart_ack,
+                       ack_i(6) => timer0_ack,
+                       ack_i(7) => timer1_ack,
 
                        dat_i(0) => mem_miso,
-                       dat_i(1) => tile_miso,
-                       dat_i(2) => host_miso,
-                       dat_i(3) => ps2_miso,
-                       dat_i(4) => uart_miso
+                       dat_i(1) => mem_miso,
+                       dat_i(2) => tile_miso,
+                       dat_i(3) => host_miso,
+                       dat_i(4) => ps2_miso,
+                       dat_i(5) => uart_miso,
+                       dat_i(6) => timer0_miso,
+                       dat_i(7) => timer1_miso
                );
 
 
@@ -229,11 +280,12 @@ begin
                        clk_i       => d_clk,
 
                        -- Internal access
-                       cyc_i       => mem_cyc,
+                       fls_cyc_i   => fls_cyc,
+                       ram_cyc_i   => ram_cyc,
                        stb_i       => stb,
                        we_i        => we,
                        ack_o       => mem_ack,
-                       adr_i       => adr(24 downto 0),
+                       adr_i       => adr(23 downto 0),
                        dat_i       => dat_mosi,
                        dat_o       => mem_miso,
 
@@ -291,8 +343,8 @@ begin
                        -- Signals to the internal device
                        d_rst_o      => d_rst,
                        d_flags_o    => host_flags,
-                       debug_i      => (others => '0'),
-                       debug_o      => open,
+                       debug_i      => debug_o,
+                       debug_o      => debug_i,
 
                        -- Internal access to control registers
                        d_cyc_i      => host_cyc,
@@ -428,4 +480,36 @@ begin
                        rx           => RsRx
                );
 
+
+       ints(4) <= timer0_zero;
+       e_timer0: entity timer.timer
+               port map (
+                       rst_i => d_rst,
+                       clk_i => d_clk,
+                       cyc_i => timer0_cyc,
+                       stb_i => stb,
+                       we_i  => we,
+                       ack_o => timer0_ack,
+                       adr_i => adr(1 downto 0),
+                       dat_i => dat_mosi,
+                       dat_o => timer0_miso,
+                       zero  => timer0_zero
+               );
+
+
+       ints(5) <= timer1_zero;
+       e_timer1: entity timer.timer
+               port map (
+                       rst_i => d_rst,
+                       clk_i => d_clk,
+                       cyc_i => timer1_cyc,
+                       stb_i => stb,
+                       we_i  => we,
+                       ack_o => timer1_ack,
+                       adr_i => adr(1 downto 0),
+                       dat_i => dat_mosi,
+                       dat_o => timer1_miso,
+                       zero  => timer1_zero
+               );
+
 end behavioral;
index 183cc3f99104c0df12f1b560f4350a68c3c82607..a8fc2c71ff5af84c1b5bc42d9d0d9081953c90db 100644 (file)
@@ -65,8 +65,12 @@ begin
                        -- INIT => x"0a100000000c05000000000000000000015a0b00000000000000000000000000"
 
                        -- Test conditional branch and interrupts
-                       -- 0x00: jz 0x10 #0xa5 ;    0x10: jmp 0x10
-                       INIT => x"0d1000000001a50b00000000000000000c100000000000000000000000000000"
+                       -- 0x00: jz 0x10 #0xa5 ien ;    0x10: ien jmp 0x11
+                       -- INIT => x"0d1000000001a5190b00000000000000190c1100000000000000000000000000"
+
+                       -- Test jumptable
+                       -- 0x00: #0x03 dup + dup + #0x00000010 + @32 >r ;
+                       INIT => x"01031610161002100000001004080b0011111111222222223333333344444444"
                )
                port map (
                        rst_i => rst_i,