mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
xics: Implement destination server field in interrupt source registers
This implements the server field in the XISRs (external interrupt source registers), allowing each interrupt source to be directed to a particular CPU. If the CPU number that is written is out of range, CPU 0 is used. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
3924ed0f49
commit
9bd6b3d175
@ -252,12 +252,14 @@ package common is
|
|||||||
|
|
||||||
-- For now, fixed 16 sources, make this either a parametric
|
-- For now, fixed 16 sources, make this either a parametric
|
||||||
-- package of some sort or an unconstrainted array.
|
-- package of some sort or an unconstrainted array.
|
||||||
|
-- We don't know NCPUS or SRC_NUM here, so make this
|
||||||
|
-- large enough for 4 cpus and 16 interrupt sources for now.
|
||||||
type ics_to_icp_t is record
|
type ics_to_icp_t is record
|
||||||
-- Level interrupts only, ICS just keeps prsenting the
|
-- Level interrupts only, ICS just keeps prsenting the
|
||||||
-- highest priority interrupt. Once handling edge, something
|
-- highest priority interrupt. Once handling edge, something
|
||||||
-- smarter involving handshake & reject support will be needed
|
-- smarter involving handshake & reject support will be needed
|
||||||
src : std_ulogic_vector(3 downto 0);
|
src : std_ulogic_vector(15 downto 0); -- 4 bits each for 4 cpus
|
||||||
pri : std_ulogic_vector(7 downto 0);
|
pri : std_ulogic_vector(31 downto 0); -- 8 bits each for 4 cpus
|
||||||
end record;
|
end record;
|
||||||
|
|
||||||
-- This needs to die...
|
-- This needs to die...
|
||||||
|
|||||||
1
soc.vhdl
1
soc.vhdl
@ -980,6 +980,7 @@ begin
|
|||||||
|
|
||||||
xics_ics: entity work.xics_ics
|
xics_ics: entity work.xics_ics
|
||||||
generic map(
|
generic map(
|
||||||
|
NCPUS => NCPUS,
|
||||||
SRC_NUM => 16,
|
SRC_NUM => 16,
|
||||||
PRIO_BITS => 3
|
PRIO_BITS => 3
|
||||||
)
|
)
|
||||||
|
|||||||
62
xics.vhdl
62
xics.vhdl
@ -181,9 +181,9 @@ begin
|
|||||||
v.icp(i).xisr := x"000000";
|
v.icp(i).xisr := x"000000";
|
||||||
v.icp(i).irq := '0';
|
v.icp(i).irq := '0';
|
||||||
|
|
||||||
if i = 0 and ics_in.pri /= x"ff" then
|
if ics_in.pri(8*i + 7 downto 8*i) /= x"ff" then
|
||||||
v.icp(i).xisr := x"00001" & ics_in.src;
|
v.icp(i).xisr := x"00001" & ics_in.src(4*i + 3 downto 4*i);
|
||||||
pending_priority := ics_in.pri;
|
pending_priority := ics_in.pri(8*i + 7 downto 8*i);
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Check MFRR
|
-- Check MFRR
|
||||||
@ -235,6 +235,7 @@ use work.helpers.all;
|
|||||||
|
|
||||||
entity xics_ics is
|
entity xics_ics is
|
||||||
generic (
|
generic (
|
||||||
|
NCPUS : natural := 1;
|
||||||
SRC_NUM : integer range 1 to 256 := 16;
|
SRC_NUM : integer range 1 to 256 := 16;
|
||||||
PRIO_BITS : integer range 1 to 8 := 3
|
PRIO_BITS : integer range 1 to 8 := 3
|
||||||
);
|
);
|
||||||
@ -253,10 +254,13 @@ end xics_ics;
|
|||||||
architecture rtl of xics_ics is
|
architecture rtl of xics_ics is
|
||||||
|
|
||||||
constant SRC_NUM_BITS : natural := log2(SRC_NUM);
|
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 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
|
type xive_t is record
|
||||||
pri : pri_t;
|
pri : pri_t;
|
||||||
|
server : server_t;
|
||||||
end record;
|
end record;
|
||||||
constant pri_masked : pri_t := (others => '1');
|
constant pri_masked : pri_t := (others => '1');
|
||||||
|
|
||||||
@ -333,6 +337,16 @@ architecture rtl of xics_ics is
|
|||||||
return p(nbits - 1 downto 0);
|
return p(nbits - 1 downto 0);
|
||||||
end function;
|
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
|
-- Register map
|
||||||
-- 0 : Config
|
-- 0 : Config
|
||||||
-- 4 : Debug/diagnostics
|
-- 4 : Debug/diagnostics
|
||||||
@ -391,16 +405,14 @@ begin
|
|||||||
be_out := (others => '0');
|
be_out := (others => '0');
|
||||||
|
|
||||||
if reg_is_xive = '1' then
|
if reg_is_xive = '1' then
|
||||||
be_out := int_level_l(reg_idx) &
|
be_out(31) := int_level_l(reg_idx);
|
||||||
'0' &
|
be_out(29) := int_level_l(reg_idx);
|
||||||
int_level_l(reg_idx) &
|
be_out(8 + SERVER_NUM_BITS - 1 downto 8) := std_ulogic_vector(xives(reg_idx).server);
|
||||||
'0' &
|
be_out(7 downto 0) := prio_unpack(xives(reg_idx).pri);
|
||||||
x"00000" &
|
|
||||||
prio_unpack(xives(reg_idx).pri);
|
|
||||||
elsif reg_is_config = '1' then
|
elsif reg_is_config = '1' then
|
||||||
be_out := get_config;
|
be_out := get_config;
|
||||||
elsif reg_is_debug = '1' then
|
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;
|
end if;
|
||||||
wb_out.dat <= bswap(be_out);
|
wb_out.dat <= bswap(be_out);
|
||||||
wb_out.ack <= wb_valid;
|
wb_out.ack <= wb_valid;
|
||||||
@ -414,17 +426,20 @@ begin
|
|||||||
if rising_edge(clk) then
|
if rising_edge(clk) then
|
||||||
if rst = '1' then
|
if rst = '1' then
|
||||||
for i in 0 to SRC_NUM - 1 loop
|
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;
|
end loop;
|
||||||
elsif wb_valid = '1' and wb_in.we = '1' then
|
elsif wb_valid = '1' and wb_in.we = '1' then
|
||||||
-- Byteswapped input
|
-- Byteswapped input
|
||||||
be_in := bswap(wb_in.dat);
|
be_in := bswap(wb_in.dat);
|
||||||
if reg_is_xive then
|
if reg_is_xive then
|
||||||
-- TODO: When adding support for other bits, make sure to
|
if wb_in.sel(3) = '1' then
|
||||||
-- properly implement wb_in.sel to allow partial writes.
|
|
||||||
xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
|
xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
|
||||||
report "ICS irq " & integer'image(reg_idx) &
|
report "ICS irq " & integer'image(reg_idx) &
|
||||||
" set to:" & to_hstring(be_in(7 downto 0));
|
" 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;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
@ -449,10 +464,14 @@ begin
|
|||||||
variable pending_pri : pri_vector_t;
|
variable pending_pri : pri_vector_t;
|
||||||
variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
|
variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
|
||||||
begin
|
begin
|
||||||
-- Work out the most-favoured (lowest) priority of the pending interrupts
|
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');
|
pending_pri := (others => '0');
|
||||||
for i in 0 to SRC_NUM - 1 loop
|
for i in 0 to SRC_NUM - 1 loop
|
||||||
if int_level_l(i) = '1' then
|
if int_level_l(i) = '1' and to_integer(xives(i).server) = cpu then
|
||||||
pending_pri := pending_pri or prio_decode(xives(i).pri);
|
pending_pri := pending_pri or prio_decode(xives(i).pri);
|
||||||
end if;
|
end if;
|
||||||
end loop;
|
end loop;
|
||||||
@ -461,17 +480,20 @@ begin
|
|||||||
-- Work out which interrupts are pending at that priority
|
-- Work out which interrupts are pending at that priority
|
||||||
pending_at_pri := (others => '0');
|
pending_at_pri := (others => '0');
|
||||||
for i in 0 to SRC_NUM - 1 loop
|
for i in 0 to SRC_NUM - 1 loop
|
||||||
if int_level_l(i) = '1' and xives(i).pri = max_pri then
|
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';
|
pending_at_pri(i) := '1';
|
||||||
end if;
|
end if;
|
||||||
end loop;
|
end loop;
|
||||||
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);
|
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);
|
||||||
|
|
||||||
if max_pri /= pri_masked then
|
if max_pri /= pri_masked then
|
||||||
report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri));
|
report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri)) &
|
||||||
|
" srv=" & integer'image(cpu);
|
||||||
end if;
|
end if;
|
||||||
icp_out_next.src <= max_idx;
|
icp_out_next.src(4*cpu + 3 downto 4*cpu) <= max_idx;
|
||||||
icp_out_next.pri <= prio_unpack(max_pri);
|
icp_out_next.pri(8*cpu + 7 downto 8*cpu) <= prio_unpack(max_pri);
|
||||||
|
end loop;
|
||||||
end process;
|
end process;
|
||||||
|
|
||||||
end architecture rtl;
|
end architecture rtl;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user