XICS interrupt controller
New unified ICP and ICS XICS compliant interrupt controller. Configurable number of hardware sources. Fixed hardware source number based on hardware line taken. All hardware interrupts are a fixed priority. Level interrupts supported only. Hardwired to 0xc0004000 in SOC (UART is kept at 0xc0002000). Signed-off-by: Michael Neuling <mikey@neuling.org>pull/165/head
parent
e5a30a1358
commit
b4f20c20b9
@ -0,0 +1,207 @@
|
||||
--
|
||||
-- This is a simple XICS compliant interrupt controller. This is a
|
||||
-- Presenter (ICP) and Source (ICS) in a single unit with no routing
|
||||
-- layer.
|
||||
--
|
||||
-- The sources have a fixed IRQ priority set by HW_PRIORITY. The
|
||||
-- source id starts at 16 for int_level_in(0) and go up from
|
||||
-- there (ie int_level_in(1) is source id 17).
|
||||
--
|
||||
-- The presentation layer will pick an interupt that is more
|
||||
-- favourable than the current CPPR and present it via the XISR and
|
||||
-- send an interrpt to the processor (via e_out). This may not be the
|
||||
-- highest priority interrupt currently presented (which is allowed
|
||||
-- via XICS)
|
||||
--
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.common.all;
|
||||
use work.wishbone_types.all;
|
||||
|
||||
entity xics is
|
||||
generic (
|
||||
LEVEL_NUM : positive := 16
|
||||
);
|
||||
port (
|
||||
clk : in std_logic;
|
||||
rst : in std_logic;
|
||||
|
||||
wb_in : in wishbone_master_out;
|
||||
wb_out : out wishbone_slave_out;
|
||||
|
||||
int_level_in : in std_ulogic_vector(LEVEL_NUM - 1 downto 0);
|
||||
|
||||
e_out : out XicsToExecute1Type
|
||||
);
|
||||
end xics;
|
||||
|
||||
architecture behaviour of xics is
|
||||
type reg_internal_t is record
|
||||
xisr : std_ulogic_vector(23 downto 0);
|
||||
cppr : std_ulogic_vector(7 downto 0);
|
||||
pending_priority : std_ulogic_vector(7 downto 0);
|
||||
mfrr : std_ulogic_vector(7 downto 0);
|
||||
mfrr_pending : std_ulogic;
|
||||
irq : std_ulogic;
|
||||
wb_rd_data : wishbone_data_type;
|
||||
wb_ack : std_ulogic;
|
||||
end record;
|
||||
constant reg_internal_init : reg_internal_t :=
|
||||
(wb_ack => '0',
|
||||
mfrr_pending => '0',
|
||||
mfrr => x"00", -- mask everything on reset
|
||||
irq => '0',
|
||||
others => (others => '0'));
|
||||
|
||||
signal r, r_next : reg_internal_t;
|
||||
|
||||
-- hardwire the hardware IRQ priority
|
||||
constant HW_PRIORITY : std_ulogic_vector(7 downto 0) := x"80";
|
||||
|
||||
-- 32 bit offsets for each presentation
|
||||
constant XIRR_POLL : std_ulogic_vector(31 downto 0) := x"00000000";
|
||||
constant XIRR : std_ulogic_vector(31 downto 0) := x"00000004";
|
||||
constant RESV0 : std_ulogic_vector(31 downto 0) := x"00000008";
|
||||
constant MFRR : std_ulogic_vector(31 downto 0) := x"0000000c";
|
||||
|
||||
begin
|
||||
|
||||
regs : process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
r <= r_next;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
wb_out.dat <= r.wb_rd_data;
|
||||
wb_out.ack <= r.wb_ack;
|
||||
wb_out.stall <= '0'; -- never stall wishbone
|
||||
e_out.irq <= r.irq;
|
||||
|
||||
comb : process(all)
|
||||
variable v : reg_internal_t;
|
||||
variable xirr_accept_rd : std_ulogic;
|
||||
variable irq_eoi : std_ulogic;
|
||||
begin
|
||||
v := r;
|
||||
|
||||
v.wb_ack := '0';
|
||||
|
||||
xirr_accept_rd := '0';
|
||||
irq_eoi := '0';
|
||||
|
||||
if wb_in.cyc = '1' and wb_in.stb = '1' then
|
||||
-- wishbone addresses we get are 64 bit alligned, so we
|
||||
-- need to use the sel bits to get 32 bit chunks.
|
||||
v.wb_ack := '1'; -- always ack
|
||||
if wb_in.we = '1' then -- write
|
||||
-- writes to both XIRR are the same
|
||||
if wb_in.adr = XIRR_POLL then
|
||||
report "XICS XIRR_POLL/XIRR write";
|
||||
if wb_in.sel = x"0f" then -- 4 bytes
|
||||
v.cppr := wb_in.dat(31 downto 24);
|
||||
elsif wb_in.sel = x"f0" then -- 4 byte
|
||||
v.cppr := wb_in.dat(63 downto 56);
|
||||
irq_eoi := '1';
|
||||
elsif wb_in.sel = x"01" then -- 1 byte
|
||||
v.cppr := wb_in.dat(7 downto 0);
|
||||
elsif wb_in.sel = x"10" then -- 1 byte
|
||||
v.cppr := wb_in.dat(39 downto 32);
|
||||
end if;
|
||||
|
||||
elsif wb_in.adr = RESV0 then
|
||||
report "XICS MFRR write";
|
||||
if wb_in.sel = x"f0" then -- 4 bytes
|
||||
v.mfrr_pending := '1';
|
||||
v.mfrr := wb_in.dat(63 downto 56);
|
||||
elsif wb_in.sel = x"10" then -- 1 byte
|
||||
v.mfrr_pending := '1';
|
||||
v.mfrr := wb_in.dat(39 downto 32);
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
else -- read
|
||||
v.wb_rd_data := (others => '0');
|
||||
|
||||
if wb_in.adr = XIRR_POLL then
|
||||
report "XICS XIRR_POLL/XIRR read";
|
||||
if wb_in.sel = x"0f" then
|
||||
v.wb_rd_data(23 downto 0) := r.xisr;
|
||||
v.wb_rd_data(31 downto 24) := r.cppr;
|
||||
elsif wb_in.sel = x"f0" then
|
||||
v.wb_rd_data(55 downto 32) := r.xisr;
|
||||
v.wb_rd_data(63 downto 56) := r.cppr;
|
||||
xirr_accept_rd := '1';
|
||||
elsif wb_in.sel = x"01" then
|
||||
v.wb_rd_data(7 downto 0) := r.cppr;
|
||||
elsif wb_in.sel = x"10" then
|
||||
v.wb_rd_data(39 downto 32) := r.cppr;
|
||||
end if;
|
||||
|
||||
elsif wb_in.adr = RESV0 then
|
||||
report "XICS MFRR read";
|
||||
if wb_in.sel = x"f0" then -- 4 bytes
|
||||
v.wb_rd_data(63 downto 56) := r.mfrr;
|
||||
elsif wb_in.sel = x"10" then -- 1 byte
|
||||
v.wb_rd_data( 7 downto 0) := r.mfrr;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- generate interrupt
|
||||
if r.irq = '0' then
|
||||
-- Here we just present any interrupt that's valid and
|
||||
-- below cppr. For ordering, we ignore hardware
|
||||
-- priorities.
|
||||
if unsigned(HW_PRIORITY) < unsigned(r.cppr) then --
|
||||
-- lower HW sources are higher priority
|
||||
for i in LEVEL_NUM - 1 downto 0 loop
|
||||
if int_level_in(i) = '1' then
|
||||
v.irq := '1';
|
||||
v.xisr := std_ulogic_vector(to_unsigned(16 + i, 24));
|
||||
v.pending_priority := HW_PRIORITY; -- hardware HW IRQs
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
-- Do mfrr as a higher priority so mfrr_pending is cleared
|
||||
if unsigned(r.mfrr) < unsigned(r.cppr) then --
|
||||
report "XICS: MFRR INTERRUPT";
|
||||
-- IPI
|
||||
if r.mfrr_pending = '1' then
|
||||
v.irq := '1';
|
||||
v.xisr := x"000002"; -- special XICS MFRR IRQ source number
|
||||
v.pending_priority := r.mfrr;
|
||||
v.mfrr_pending := '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Accept the interrupt
|
||||
if xirr_accept_rd = '1' then
|
||||
report "XICS: ACCEPT" &
|
||||
" cppr:" & to_hstring(r.cppr) &
|
||||
" xisr:" & to_hstring(r.xisr) &
|
||||
" mfrr:" & to_hstring(r.mfrr);
|
||||
v.cppr := r.pending_priority;
|
||||
end if;
|
||||
|
||||
if irq_eoi = '1' then
|
||||
v.irq := '0';
|
||||
end if;
|
||||
|
||||
if rst = '1' then
|
||||
v := reg_internal_init;
|
||||
end if;
|
||||
|
||||
r_next <= v;
|
||||
|
||||
end process;
|
||||
|
||||
end architecture behaviour;
|
Loading…
Reference in New Issue