Line 2... |
Line 2... |
-- # << NEORV32 - External Interrupt Controller (XIRQ) >> #
|
-- # << NEORV32 - External Interrupt Controller (XIRQ) >> #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # Simple interrupt controller for platform (processor-external) interrupts. Up to 32 channels #
|
-- # Simple interrupt controller for platform (processor-external) interrupts. Up to 32 channels #
|
-- # are supported that get (optionally) prioritized into a single CPU interrupt. #
|
-- # are supported that get (optionally) prioritized into a single CPU interrupt. #
|
-- # #
|
-- # #
|
-- # The actual trigger configuration has to be done before synthesis using the XIRQ_TRIGGER_TYPE #
|
-- # The actual trigger configuration has to be done BEFORE synthesis using the XIRQ_TRIGGER_TYPE #
|
-- # and XIRQ_TRIGGER_POLARITY generics. These allow to configure channel-independent low-level, #
|
-- # and XIRQ_TRIGGER_POLARITY generics. These allow to configure channel-independent low-level, #
|
-- # high-level, falling-edge and rising-edge triggers. #
|
-- # high-level, falling-edge and rising-edge triggers. #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # BSD 3-Clause License #
|
-- # BSD 3-Clause License #
|
-- # #
|
-- # #
|
Line 75... |
Line 75... |
constant lo_abb_c : natural := index_size_f(xirq_size_c); -- low address boundary bit
|
constant lo_abb_c : natural := index_size_f(xirq_size_c); -- low address boundary bit
|
|
|
-- access control --
|
-- access control --
|
signal acc_en : std_ulogic; -- module access enable
|
signal acc_en : std_ulogic; -- module access enable
|
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
|
signal wren : std_ulogic; -- word write enable
|
|
signal rden : std_ulogic; -- read enable
|
|
|
-- control registers --
|
-- control registers --
|
signal irq_enable : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: interrupt enable
|
signal irq_enable : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: interrupt enable
|
signal clr_pending : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: clear pending IRQs
|
signal clr_pending : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- r/w: clear pending IRQs
|
signal irq_src : std_ulogic_vector(4 downto 0); -- r/w: source IRQ, ACK on any write
|
signal irq_src : std_ulogic_vector(4 downto 0); -- r/w: source IRQ, ACK on any write
|
Line 95... |
Line 97... |
-- interrupt source --
|
-- interrupt source --
|
signal irq_src_nxt : std_ulogic_vector(4 downto 0);
|
signal irq_src_nxt : std_ulogic_vector(4 downto 0);
|
|
|
-- arbiter --
|
-- arbiter --
|
signal irq_run : std_ulogic;
|
signal irq_run : std_ulogic;
|
signal host_ack : std_ulogic;
|
|
|
|
begin
|
begin
|
|
|
-- Sanity Checks --------------------------------------------------------------------------
|
-- Sanity Checks --------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 108... |
Line 109... |
|
|
-- Access Control -------------------------------------------------------------------------
|
-- Access Control -------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = xirq_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = xirq_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
addr <= xirq_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
addr <= xirq_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
|
wren <= acc_en and wren_i;
|
|
rden <= acc_en and rden_i;
|
|
|
|
|
-- Read/Write Access ----------------------------------------------------------------------
|
-- Read/Write Access ----------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
rw_access: process(clk_i)
|
rw_access: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
-- bus handshake --
|
-- bus handshake --
|
ack_o <= acc_en and (rden_i or wren_i);
|
ack_o <= rden or wren;
|
|
|
-- write access --
|
-- write access --
|
host_ack <= '0';
|
|
clr_pending <= (others => '1');
|
clr_pending <= (others => '1');
|
if ((acc_en and wren_i) = '1') then
|
if (wren = '1') then
|
-- channel-enable --
|
-- channel-enable --
|
if (addr = xirq_enable_addr_c) then
|
if (addr = xirq_enable_addr_c) then
|
irq_enable <= data_i(XIRQ_NUM_CH-1 downto 0);
|
irq_enable <= data_i(XIRQ_NUM_CH-1 downto 0);
|
end if;
|
end if;
|
-- clear pending IRQs --
|
-- clear pending IRQs --
|
if (addr = xirq_pending_addr_c) then
|
if (addr = xirq_pending_addr_c) then
|
clr_pending <= data_i(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
|
clr_pending <= data_i(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
|
end if;
|
end if;
|
-- acknowledge IRQ --
|
|
if (addr = xirq_source_addr_c) then -- write _any_ value to ACK
|
|
host_ack <= '1';
|
|
end if;
|
|
end if;
|
end if;
|
|
|
-- read access --
|
-- read access --
|
data_o <= (others => '0');
|
data_o <= (others => '0');
|
if ((acc_en and rden_i) = '1') then
|
if (rden = '1') then
|
case addr is
|
case addr is
|
when xirq_enable_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
|
when xirq_enable_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
|
when xirq_pending_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_buf; -- pending IRQs
|
when xirq_pending_addr_c => data_o(XIRQ_NUM_CH-1 downto 0) <= irq_buf; -- pending IRQs
|
when xirq_source_addr_c => data_o(4 downto 0) <= irq_src; -- source IRQ
|
when xirq_source_addr_c => data_o(4 downto 0) <= irq_src; -- source IRQ
|
when others => NULL;
|
when others => NULL;
|
Line 216... |
Line 214... |
if (irq_fire = '1') then
|
if (irq_fire = '1') then
|
irq_run <= '1';
|
irq_run <= '1';
|
irq_src <= irq_src_nxt;
|
irq_src <= irq_src_nxt;
|
end if;
|
end if;
|
else -- active IRQ, wait for CPU to acknowledge
|
else -- active IRQ, wait for CPU to acknowledge
|
if (host_ack = '1') then
|
if (wren = '1') and (addr = xirq_source_addr_c) then -- write _any_ value to acknowledge
|
irq_run <= '0';
|
irq_run <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process irq_arbiter;
|
end process irq_arbiter;
|