--- /dev/null
+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;
--- /dev/null
+--------------------------------------------------------------------------------
+-- 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;
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;
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,
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
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';
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';
-- 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;
-- 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;
pc_sel <= PC_INTVEC;
-- Mask further interruptions
- imask_set <= '1';
+ imask_clr <= '1';
state_next <= S_FETCH;
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);
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);
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;
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
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
-- UART: 0x02004010-0x02004017
e_mapper: entity utility.wb_mapper_a32d8
generic map (
- N => 5
+ N => 8
)
port map (
cyc_i => cyc,
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
);
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,
-- 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,
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;
-- 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,