|
|
|
@ -25,6 +25,9 @@ use work.common.all;
|
|
|
|
|
use work.wishbone_types.all;
|
|
|
|
|
|
|
|
|
|
entity xics_icp is
|
|
|
|
|
generic (
|
|
|
|
|
NCPUS : natural := 1
|
|
|
|
|
);
|
|
|
|
|
port (
|
|
|
|
|
clk : in std_logic;
|
|
|
|
|
rst : in std_logic;
|
|
|
|
@ -33,32 +36,41 @@ entity xics_icp is
|
|
|
|
|
wb_out : out wb_io_slave_out;
|
|
|
|
|
|
|
|
|
|
ics_in : in ics_to_icp_t;
|
|
|
|
|
core_irq_out : out std_ulogic
|
|
|
|
|
core_irq_out : out std_ulogic_vector(NCPUS-1 downto 0)
|
|
|
|
|
);
|
|
|
|
|
end xics_icp;
|
|
|
|
|
|
|
|
|
|
architecture behaviour of xics_icp is
|
|
|
|
|
type reg_internal_t is record
|
|
|
|
|
type xics_presentation_t is record
|
|
|
|
|
xisr : std_ulogic_vector(23 downto 0);
|
|
|
|
|
cppr : std_ulogic_vector(7 downto 0);
|
|
|
|
|
mfrr : std_ulogic_vector(7 downto 0);
|
|
|
|
|
irq : std_ulogic;
|
|
|
|
|
end record;
|
|
|
|
|
constant xics_presentation_t_init : xics_presentation_t :=
|
|
|
|
|
(mfrr => x"ff", -- mask everything on reset
|
|
|
|
|
irq => '0',
|
|
|
|
|
others => (others => '0'));
|
|
|
|
|
subtype cpu_index_t is natural range 0 to NCPUS-1;
|
|
|
|
|
type xicp_array_t is array(cpu_index_t) of xics_presentation_t;
|
|
|
|
|
|
|
|
|
|
type reg_internal_t is record
|
|
|
|
|
icp : xicp_array_t;
|
|
|
|
|
wb_rd_data : std_ulogic_vector(31 downto 0);
|
|
|
|
|
wb_ack : std_ulogic;
|
|
|
|
|
end record;
|
|
|
|
|
constant reg_internal_init : reg_internal_t :=
|
|
|
|
|
(wb_ack => '0',
|
|
|
|
|
mfrr => x"ff", -- mask everything on reset
|
|
|
|
|
irq => '0',
|
|
|
|
|
others => (others => '0'));
|
|
|
|
|
wb_rd_data => (others => '0'),
|
|
|
|
|
icp => (others => xics_presentation_t_init));
|
|
|
|
|
|
|
|
|
|
signal r, r_next : reg_internal_t;
|
|
|
|
|
|
|
|
|
|
-- 8 bit offsets for each presentation
|
|
|
|
|
constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00";
|
|
|
|
|
constant XIRR : std_ulogic_vector(7 downto 0) := x"04";
|
|
|
|
|
constant RESV0 : std_ulogic_vector(7 downto 0) := x"08";
|
|
|
|
|
constant MFRR : std_ulogic_vector(7 downto 0) := x"0c";
|
|
|
|
|
-- 4 bit offsets for each presentation register
|
|
|
|
|
constant XIRR_POLL : std_ulogic_vector(3 downto 0) := x"0";
|
|
|
|
|
constant XIRR : std_ulogic_vector(3 downto 0) := x"4";
|
|
|
|
|
constant RESV0 : std_ulogic_vector(3 downto 0) := x"8";
|
|
|
|
|
constant MFRR : std_ulogic_vector(3 downto 0) := x"c";
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
@ -68,7 +80,9 @@ begin
|
|
|
|
|
r <= r_next;
|
|
|
|
|
|
|
|
|
|
-- We delay core_irq_out by a cycle to help with timing
|
|
|
|
|
core_irq_out <= r.irq;
|
|
|
|
|
for i in 0 to NCPUS-1 loop
|
|
|
|
|
core_irq_out(i) <= r.icp(i).irq;
|
|
|
|
|
end loop;
|
|
|
|
|
end if;
|
|
|
|
|
end process;
|
|
|
|
|
|
|
|
|
@ -99,94 +113,105 @@ begin
|
|
|
|
|
|
|
|
|
|
v.wb_ack := '0';
|
|
|
|
|
|
|
|
|
|
xirr_accept_rd := '0';
|
|
|
|
|
|
|
|
|
|
be_in := bswap(wb_in.dat);
|
|
|
|
|
be_out := (others => '0');
|
|
|
|
|
|
|
|
|
|
if wb_in.cyc = '1' and wb_in.stb = '1' then
|
|
|
|
|
v.wb_ack := '1'; -- always ack
|
|
|
|
|
if wb_in.we = '1' then -- write
|
|
|
|
|
-- writes to both XIRR are the same
|
|
|
|
|
case wb_in.adr(5 downto 0) & "00" is
|
|
|
|
|
when XIRR_POLL =>
|
|
|
|
|
report "ICP XIRR_POLL write";
|
|
|
|
|
v.cppr := be_in(31 downto 24);
|
|
|
|
|
when XIRR =>
|
|
|
|
|
v.cppr := be_in(31 downto 24);
|
|
|
|
|
if wb_in.sel = x"f" then -- 4 byte
|
|
|
|
|
report "ICP XIRR write word (EOI) :" & to_hstring(be_in);
|
|
|
|
|
elsif wb_in.sel = x"1" then -- 1 byte
|
|
|
|
|
report "ICP XIRR write byte (CPPR):" & to_hstring(be_in(31 downto 24));
|
|
|
|
|
else
|
|
|
|
|
report "ICP XIRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
|
|
|
|
|
end if;
|
|
|
|
|
when MFRR =>
|
|
|
|
|
v.mfrr := be_in(31 downto 24);
|
|
|
|
|
if wb_in.sel = x"f" then -- 4 bytes
|
|
|
|
|
report "ICP MFRR write word:" & to_hstring(be_in);
|
|
|
|
|
elsif wb_in.sel = x"1" then -- 1 byte
|
|
|
|
|
report "ICP MFRR write byte:" & to_hstring(be_in(31 downto 24));
|
|
|
|
|
else
|
|
|
|
|
report "ICP MFRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
|
|
|
|
|
end if;
|
|
|
|
|
when others =>
|
|
|
|
|
end case;
|
|
|
|
|
|
|
|
|
|
else -- read
|
|
|
|
|
|
|
|
|
|
case wb_in.adr(5 downto 0) & "00" is
|
|
|
|
|
when XIRR_POLL =>
|
|
|
|
|
report "ICP XIRR_POLL read";
|
|
|
|
|
be_out := r.cppr & r.xisr;
|
|
|
|
|
when XIRR =>
|
|
|
|
|
report "ICP XIRR read";
|
|
|
|
|
be_out := r.cppr & r.xisr;
|
|
|
|
|
if wb_in.sel = x"f" then
|
|
|
|
|
xirr_accept_rd := '1';
|
|
|
|
|
end if;
|
|
|
|
|
when MFRR =>
|
|
|
|
|
report "ICP MFRR read";
|
|
|
|
|
be_out(31 downto 24) := r.mfrr;
|
|
|
|
|
when others =>
|
|
|
|
|
end case;
|
|
|
|
|
end if;
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
|
|
pending_priority := x"ff";
|
|
|
|
|
v.xisr := x"000000";
|
|
|
|
|
v.irq := '0';
|
|
|
|
|
for i in cpu_index_t loop
|
|
|
|
|
xirr_accept_rd := '0';
|
|
|
|
|
|
|
|
|
|
if wb_in.cyc = '1' and wb_in.stb = '1' and
|
|
|
|
|
to_integer(unsigned(wb_in.adr(5 downto 2))) = i then
|
|
|
|
|
if wb_in.we = '1' then -- write
|
|
|
|
|
-- writes to both XIRR are the same
|
|
|
|
|
case wb_in.adr(1 downto 0) & "00" is
|
|
|
|
|
when XIRR_POLL =>
|
|
|
|
|
report "ICP XIRR_POLL write";
|
|
|
|
|
v.icp(i).cppr := be_in(31 downto 24);
|
|
|
|
|
when XIRR =>
|
|
|
|
|
v.icp(i).cppr := be_in(31 downto 24);
|
|
|
|
|
if wb_in.sel = x"f" then -- 4 byte
|
|
|
|
|
report "ICP " & natural'image(i) & " XIRR write word (EOI) :" &
|
|
|
|
|
to_hstring(be_in);
|
|
|
|
|
elsif wb_in.sel = x"1" then -- 1 byte
|
|
|
|
|
report "ICP " & natural'image(i) & " XIRR write byte (CPPR):" &
|
|
|
|
|
to_hstring(be_in(31 downto 24));
|
|
|
|
|
else
|
|
|
|
|
report "ICP " & natural'image(i) & " XIRR UNSUPPORTED write ! sel=" &
|
|
|
|
|
to_hstring(wb_in.sel);
|
|
|
|
|
end if;
|
|
|
|
|
when MFRR =>
|
|
|
|
|
v.icp(i).mfrr := be_in(31 downto 24);
|
|
|
|
|
if wb_in.sel = x"f" then -- 4 bytes
|
|
|
|
|
report "ICP " & natural'image(i) & " MFRR write word:" &
|
|
|
|
|
to_hstring(be_in);
|
|
|
|
|
elsif wb_in.sel = x"1" then -- 1 byte
|
|
|
|
|
report "ICP " & natural'image(i) & " MFRR write byte:" &
|
|
|
|
|
to_hstring(be_in(31 downto 24));
|
|
|
|
|
else
|
|
|
|
|
report "ICP " & natural'image(i) & " MFRR UNSUPPORTED write ! sel=" &
|
|
|
|
|
to_hstring(wb_in.sel);
|
|
|
|
|
end if;
|
|
|
|
|
when others =>
|
|
|
|
|
end case;
|
|
|
|
|
|
|
|
|
|
else -- read
|
|
|
|
|
|
|
|
|
|
case wb_in.adr(1 downto 0) & "00" is
|
|
|
|
|
when XIRR_POLL =>
|
|
|
|
|
report "ICP XIRR_POLL read";
|
|
|
|
|
be_out := r.icp(i).cppr & r.icp(i).xisr;
|
|
|
|
|
when XIRR =>
|
|
|
|
|
report "ICP XIRR read";
|
|
|
|
|
be_out := r.icp(i).cppr & r.icp(i).xisr;
|
|
|
|
|
if wb_in.sel = x"f" then
|
|
|
|
|
xirr_accept_rd := '1';
|
|
|
|
|
end if;
|
|
|
|
|
when MFRR =>
|
|
|
|
|
report "ICP MFRR read";
|
|
|
|
|
be_out(31 downto 24) := r.icp(i).mfrr;
|
|
|
|
|
when others =>
|
|
|
|
|
end case;
|
|
|
|
|
end if;
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
|
|
if ics_in.pri /= x"ff" then
|
|
|
|
|
v.xisr := x"00001" & ics_in.src;
|
|
|
|
|
pending_priority := ics_in.pri;
|
|
|
|
|
end if;
|
|
|
|
|
pending_priority := x"ff";
|
|
|
|
|
v.icp(i).xisr := x"000000";
|
|
|
|
|
v.icp(i).irq := '0';
|
|
|
|
|
|
|
|
|
|
-- Check MFRR
|
|
|
|
|
if unsigned(r.mfrr) < unsigned(pending_priority) then --
|
|
|
|
|
v.xisr := x"000002"; -- special XICS MFRR IRQ source number
|
|
|
|
|
pending_priority := r.mfrr;
|
|
|
|
|
end if;
|
|
|
|
|
if ics_in.pri(8*i + 7 downto 8*i) /= x"ff" then
|
|
|
|
|
v.icp(i).xisr := x"00001" & ics_in.src(4*i + 3 downto 4*i);
|
|
|
|
|
pending_priority := ics_in.pri(8*i + 7 downto 8*i);
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
|
|
-- Accept the interrupt
|
|
|
|
|
if xirr_accept_rd = '1' then
|
|
|
|
|
report "XICS: ICP ACCEPT" &
|
|
|
|
|
" cppr:" & to_hstring(r.cppr) &
|
|
|
|
|
" xisr:" & to_hstring(r.xisr) &
|
|
|
|
|
" mfrr:" & to_hstring(r.mfrr);
|
|
|
|
|
v.cppr := pending_priority;
|
|
|
|
|
end if;
|
|
|
|
|
-- Check MFRR
|
|
|
|
|
if unsigned(r.icp(i).mfrr) < unsigned(pending_priority) then --
|
|
|
|
|
v.icp(i).xisr := x"000002"; -- special XICS MFRR IRQ source number
|
|
|
|
|
pending_priority := r.icp(i).mfrr;
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
|
|
-- Accept the interrupt
|
|
|
|
|
if xirr_accept_rd = '1' then
|
|
|
|
|
report "XICS " & natural'image(i) & ": ICP ACCEPT" &
|
|
|
|
|
" cppr:" & to_hstring(r.icp(i).cppr) &
|
|
|
|
|
" xisr:" & to_hstring(r.icp(i).xisr) &
|
|
|
|
|
" mfrr:" & to_hstring(r.icp(i).mfrr);
|
|
|
|
|
v.icp(i).cppr := pending_priority;
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
|
|
v.wb_rd_data := bswap(be_out);
|
|
|
|
|
v.wb_rd_data := bswap(be_out);
|
|
|
|
|
|
|
|
|
|
if unsigned(pending_priority) < unsigned(v.cppr) then
|
|
|
|
|
if r.irq = '0' then
|
|
|
|
|
report "IRQ set";
|
|
|
|
|
if unsigned(pending_priority) < unsigned(v.icp(i).cppr) then
|
|
|
|
|
if r.icp(i).irq = '0' then
|
|
|
|
|
report "CPU " & natural'image(i) & " IRQ set";
|
|
|
|
|
end if;
|
|
|
|
|
v.icp(i).irq := '1';
|
|
|
|
|
elsif r.icp(i).irq = '1' then
|
|
|
|
|
report "CPU " & natural'image(i) & " IRQ clr";
|
|
|
|
|
end if;
|
|
|
|
|
v.irq := '1';
|
|
|
|
|
elsif r.irq = '1' then
|
|
|
|
|
report "IRQ clr";
|
|
|
|
|
end if;
|
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
|
|
if rst = '1' then
|
|
|
|
|
v := reg_internal_init;
|
|
|
|
@ -210,6 +235,7 @@ use work.helpers.all;
|
|
|
|
|
|
|
|
|
|
entity xics_ics is
|
|
|
|
|
generic (
|
|
|
|
|
NCPUS : natural := 1;
|
|
|
|
|
SRC_NUM : integer range 1 to 256 := 16;
|
|
|
|
|
PRIO_BITS : integer range 1 to 8 := 3
|
|
|
|
|
);
|
|
|
|
@ -228,10 +254,13 @@ end xics_ics;
|
|
|
|
|
architecture rtl of xics_ics is
|
|
|
|
|
|
|
|
|
|
constant SRC_NUM_BITS : natural := log2(SRC_NUM);
|
|
|
|
|
constant SERVER_NUM_BITS : natural := 2;
|
|
|
|
|
|
|
|
|
|
subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0);
|
|
|
|
|
subtype server_t is unsigned(SERVER_NUM_BITS-1 downto 0);
|
|
|
|
|
type xive_t is record
|
|
|
|
|
pri : pri_t;
|
|
|
|
|
server : server_t;
|
|
|
|
|
end record;
|
|
|
|
|
constant pri_masked : pri_t := (others => '1');
|
|
|
|
|
|
|
|
|
@ -308,6 +337,16 @@ architecture rtl of xics_ics is
|
|
|
|
|
return p(nbits - 1 downto 0);
|
|
|
|
|
end function;
|
|
|
|
|
|
|
|
|
|
function server_check(serv_in: std_ulogic_vector(7 downto 0)) return unsigned is
|
|
|
|
|
variable srv : server_t;
|
|
|
|
|
begin
|
|
|
|
|
srv := to_unsigned(0, SERVER_NUM_BITS);
|
|
|
|
|
if to_integer(unsigned(serv_in)) < NCPUS then
|
|
|
|
|
srv := unsigned(serv_in(SERVER_NUM_BITS - 1 downto 0));
|
|
|
|
|
end if;
|
|
|
|
|
return srv;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
-- Register map
|
|
|
|
|
-- 0 : Config
|
|
|
|
|
-- 4 : Debug/diagnostics
|
|
|
|
@ -366,16 +405,14 @@ begin
|
|
|
|
|
be_out := (others => '0');
|
|
|
|
|
|
|
|
|
|
if reg_is_xive = '1' then
|
|
|
|
|
be_out := int_level_l(reg_idx) &
|
|
|
|
|
'0' &
|
|
|
|
|
int_level_l(reg_idx) &
|
|
|
|
|
'0' &
|
|
|
|
|
x"00000" &
|
|
|
|
|
prio_unpack(xives(reg_idx).pri);
|
|
|
|
|
be_out(31) := int_level_l(reg_idx);
|
|
|
|
|
be_out(29) := int_level_l(reg_idx);
|
|
|
|
|
be_out(8 + SERVER_NUM_BITS - 1 downto 8) := std_ulogic_vector(xives(reg_idx).server);
|
|
|
|
|
be_out(7 downto 0) := prio_unpack(xives(reg_idx).pri);
|
|
|
|
|
elsif reg_is_config = '1' then
|
|
|
|
|
be_out := get_config;
|
|
|
|
|
elsif reg_is_debug = '1' then
|
|
|
|
|
be_out := x"00000" & icp_out_next.src & icp_out_next.pri;
|
|
|
|
|
be_out := icp_out_next.src & icp_out_next.pri(15 downto 0);
|
|
|
|
|
end if;
|
|
|
|
|
wb_out.dat <= bswap(be_out);
|
|
|
|
|
wb_out.ack <= wb_valid;
|
|
|
|
@ -389,17 +426,20 @@ begin
|
|
|
|
|
if rising_edge(clk) then
|
|
|
|
|
if rst = '1' then
|
|
|
|
|
for i in 0 to SRC_NUM - 1 loop
|
|
|
|
|
xives(i) <= (pri => pri_masked);
|
|
|
|
|
xives(i) <= (pri => pri_masked, server => to_unsigned(0, SERVER_NUM_BITS));
|
|
|
|
|
end loop;
|
|
|
|
|
elsif wb_valid = '1' and wb_in.we = '1' then
|
|
|
|
|
-- Byteswapped input
|
|
|
|
|
be_in := bswap(wb_in.dat);
|
|
|
|
|
if reg_is_xive then
|
|
|
|
|
-- TODO: When adding support for other bits, make sure to
|
|
|
|
|
-- properly implement wb_in.sel to allow partial writes.
|
|
|
|
|
xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
|
|
|
|
|
report "ICS irq " & integer'image(reg_idx) &
|
|
|
|
|
" set to:" & to_hstring(be_in(7 downto 0));
|
|
|
|
|
if wb_in.sel(3) = '1' then
|
|
|
|
|
xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
|
|
|
|
|
report "ICS irq " & integer'image(reg_idx) &
|
|
|
|
|
" set to pri:" & to_hstring(be_in(7 downto 0));
|
|
|
|
|
end if;
|
|
|
|
|
if wb_in.sel(2) = '1' then
|
|
|
|
|
xives(reg_idx).server <= server_check(be_in(15 downto 8));
|
|
|
|
|
end if;
|
|
|
|
|
end if;
|
|
|
|
|
end if;
|
|
|
|
|
end if;
|
|
|
|
@ -424,29 +464,36 @@ begin
|
|
|
|
|
variable pending_pri : pri_vector_t;
|
|
|
|
|
variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
|
|
|
|
|
begin
|
|
|
|
|
-- Work out the most-favoured (lowest) priority of the pending interrupts
|
|
|
|
|
pending_pri := (others => '0');
|
|
|
|
|
for i in 0 to SRC_NUM - 1 loop
|
|
|
|
|
if int_level_l(i) = '1' then
|
|
|
|
|
pending_pri := pending_pri or prio_decode(xives(i).pri);
|
|
|
|
|
end if;
|
|
|
|
|
end loop;
|
|
|
|
|
max_pri := priority_encoder(pending_pri, PRIO_BITS);
|
|
|
|
|
icp_out_next.src <= (others => '0');
|
|
|
|
|
icp_out_next.pri <= (others => '0');
|
|
|
|
|
for cpu in 0 to NCPUS-1 loop
|
|
|
|
|
-- Work out the most-favoured (lowest) priority of the interrupts
|
|
|
|
|
-- that are pending and directed to this cpu
|
|
|
|
|
pending_pri := (others => '0');
|
|
|
|
|
for i in 0 to SRC_NUM - 1 loop
|
|
|
|
|
if int_level_l(i) = '1' and to_integer(xives(i).server) = cpu then
|
|
|
|
|
pending_pri := pending_pri or prio_decode(xives(i).pri);
|
|
|
|
|
end if;
|
|
|
|
|
end loop;
|
|
|
|
|
max_pri := priority_encoder(pending_pri, PRIO_BITS);
|
|
|
|
|
|
|
|
|
|
-- Work out which interrupts are pending at that priority
|
|
|
|
|
pending_at_pri := (others => '0');
|
|
|
|
|
for i in 0 to SRC_NUM - 1 loop
|
|
|
|
|
if int_level_l(i) = '1' and xives(i).pri = max_pri and
|
|
|
|
|
to_integer(xives(i).server) = cpu then
|
|
|
|
|
pending_at_pri(i) := '1';
|
|
|
|
|
end if;
|
|
|
|
|
end loop;
|
|
|
|
|
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);
|
|
|
|
|
|
|
|
|
|
-- Work out which interrupts are pending at that priority
|
|
|
|
|
pending_at_pri := (others => '0');
|
|
|
|
|
for i in 0 to SRC_NUM - 1 loop
|
|
|
|
|
if int_level_l(i) = '1' and xives(i).pri = max_pri then
|
|
|
|
|
pending_at_pri(i) := '1';
|
|
|
|
|
if max_pri /= pri_masked then
|
|
|
|
|
report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri)) &
|
|
|
|
|
" srv=" & integer'image(cpu);
|
|
|
|
|
end if;
|
|
|
|
|
icp_out_next.src(4*cpu + 3 downto 4*cpu) <= max_idx;
|
|
|
|
|
icp_out_next.pri(8*cpu + 7 downto 8*cpu) <= prio_unpack(max_pri);
|
|
|
|
|
end loop;
|
|
|
|
|
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);
|
|
|
|
|
|
|
|
|
|
if max_pri /= pri_masked then
|
|
|
|
|
report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri));
|
|
|
|
|
end if;
|
|
|
|
|
icp_out_next.src <= max_idx;
|
|
|
|
|
icp_out_next.pri <= prio_unpack(max_pri);
|
|
|
|
|
end process;
|
|
|
|
|
|
|
|
|
|
end architecture rtl;
|
|
|
|
|