xics: Rework the irq_gen process

At present, the loop in the irq_gen process generates a chain of
comparators and other logic to work out the source number and priority
of the most-favoured (lowest priority number) pending interrupt.
This replaces that chain with (1) logic to generate an array of bits,
one per priority, indicating whether any interrupt is pending at that
priority, (2) a priority encoder to select the most favoured priority
with an interrupt pending, (3) logic to generate an array of bits, one
per source, indicating whether an interrupt is pending at the priority
calculated in step 2, and (4) a priority encoder to work out the
lowest numbered source that has an interrupt pending at the selected
priority.  This reduces LUT utilization.

The priority encoder function implemented here uses the optimized
count-leading-zeroes logic from helpers.vhdl.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/348/head
Paul Mackerras 3 years ago
parent 1720a0584a
commit 0aa898c7a6

@ -30,6 +30,7 @@ package helpers is
function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector; function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector;
function edgelocation(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector; function edgelocation(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector;
function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector; function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector;
function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector;
end package helpers; end package helpers;


package body helpers is package body helpers is
@ -270,22 +271,28 @@ package body helpers is
return p; return p;
end function; end function;


-- Count leading zeroes operation -- Count leading zeroes operations
-- Assumes the value passed in is not zero (if it is, zero is returned) -- Assumes the value passed in is not zero (if it is, zero is returned)
function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector is function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
variable rev: std_ulogic_vector(val'left downto val'right);
variable sum: std_ulogic_vector(val'left downto val'right); variable sum: std_ulogic_vector(val'left downto val'right);
variable onehot: std_ulogic_vector(val'left downto val'right); variable onehot: std_ulogic_vector(val'left downto val'right);
variable edge: std_ulogic_vector(val'left downto val'right); variable edge: std_ulogic_vector(val'left downto val'right);
variable bn, bn_e, bn_o: std_ulogic_vector(5 downto 0); variable bn, bn_e, bn_o: std_ulogic_vector(5 downto 0);
begin begin
rev := bit_reverse(val); sum := std_ulogic_vector(- signed(val));
sum := std_ulogic_vector(- signed(rev)); onehot := sum and val;
onehot := sum and rev; edge := sum or val;
edge := sum or rev;
bn_e := edgelocation(std_ulogic_vector(resize(signed(edge), 64)), 6); bn_e := edgelocation(std_ulogic_vector(resize(signed(edge), 64)), 6);
bn_o := bit_number(std_ulogic_vector(resize(unsigned(onehot), 64))); bn_o := bit_number(std_ulogic_vector(resize(unsigned(onehot), 64)));
bn := bn_e(5 downto 2) & bn_o(1 downto 0); bn := bn_e(5 downto 2) & bn_o(1 downto 0);
return bn; return bn;
end; end;

function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
variable rev: std_ulogic_vector(val'left downto val'right);
begin
rev := bit_reverse(val);
return count_right_zeroes(rev);
end;

end package body helpers; end package body helpers;

@ -54,9 +54,6 @@ architecture behaviour of xics_icp is


signal r, r_next : reg_internal_t; signal r, r_next : reg_internal_t;


-- hardwire the hardware IRQ priority
constant HW_PRIORITY : std_ulogic_vector(7 downto 0) := x"80";

-- 8 bit offsets for each presentation -- 8 bit offsets for each presentation
constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00"; constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00";
constant XIRR : std_ulogic_vector(7 downto 0) := x"04"; constant XIRR : std_ulogic_vector(7 downto 0) := x"04";
@ -207,12 +204,14 @@ use ieee.numeric_std.all;


library work; library work;
use work.common.all; use work.common.all;
use work.utils.all;
use work.wishbone_types.all; use work.wishbone_types.all;
use work.helpers.all;


entity xics_ics is entity xics_ics is
generic ( generic (
SRC_NUM : integer range 1 to 256 := 16; SRC_NUM : integer range 1 to 256 := 16;
PRIO_BITS : integer range 1 to 8 := 8 PRIO_BITS : integer range 1 to 8 := 3
); );
port ( port (
clk : in std_logic; clk : in std_logic;
@ -228,12 +227,16 @@ end xics_ics;


architecture rtl of xics_ics is architecture rtl of xics_ics is


constant SRC_NUM_BITS : natural := log2(SRC_NUM);

subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0); subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0);
type xive_t is record type xive_t is record
pri : pri_t; pri : pri_t;
end record; end record;
constant pri_masked : pri_t := (others => '1'); constant pri_masked : pri_t := (others => '1');


subtype pri_vector_t is std_ulogic_vector(2**PRIO_BITS - 1 downto 0);

type xive_array_t is array(0 to SRC_NUM-1) of xive_t; type xive_array_t is array(0 to SRC_NUM-1) of xive_t;
signal xives : xive_array_t; signal xives : xive_array_t;


@ -262,8 +265,15 @@ architecture rtl of xics_ics is
end function; end function;


function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is
variable masked : std_ulogic_vector(7 downto 0);
begin begin
masked := x"00";
masked(PRIO_BITS - 1 downto 0) := (others => '1');
if pri8 >= masked then
return pri_masked;
else
return pri8(PRIO_BITS-1 downto 0); return pri8(PRIO_BITS-1 downto 0);
end if;
end function; end function;


function prio_unpack(pri: pri_t) return std_ulogic_vector is function prio_unpack(pri: pri_t) return std_ulogic_vector is
@ -278,6 +288,25 @@ architecture rtl of xics_ics is
return r; return r;
end function; end function;


function prio_decode(pri: pri_t) return pri_vector_t is
variable v: pri_vector_t;
begin
v := (others => '0');
v(to_integer(unsigned(pri))) := '1';
return v;
end function;

-- Assumes nbits <= 6; v is 2^nbits wide
function priority_encoder(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector is
variable h: std_ulogic_vector(2**nbits - 1 downto 0);
variable p: std_ulogic_vector(5 downto 0);
begin
-- Set the lowest-priority (highest-numbered) bit
h := v;
h(2**nbits - 1) := '1';
p := count_right_zeroes(h);
return p(nbits - 1 downto 0);
end function;


-- Register map -- Register map
-- 0 : Config -- 0 : Config
@ -391,35 +420,33 @@ begin
end process; end process;


irq_gen: process(all) irq_gen: process(all)
variable max_idx : integer range 0 to SRC_NUM-1; variable max_idx : std_ulogic_vector(SRC_NUM_BITS - 1 downto 0);
variable max_pri : pri_t; variable max_pri : pri_t;

variable pending_pri : pri_vector_t;
-- A more favored than b ? variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
function a_mf_b(a: pri_t; b: pri_t) return boolean is
variable a_i : unsigned(PRIO_BITS-1 downto 0);
variable b_i : unsigned(PRIO_BITS-1 downto 0);
begin begin
a_i := unsigned(a); -- Work out the most-favoured (lowest) priority of the pending interrupts
b_i := unsigned(b); pending_pri := (others => '0');
report "a_mf_b a=" & to_hstring(a) &
" b=" & to_hstring(b) &
" r=" & boolean'image(a < b);
return a_i < b_i;
end function;
begin
-- XXX FIXME: Use a tree
max_pri := pri_masked;
max_idx := 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 a_mf_b(xives(i).pri, max_pri) then if int_level_l(i) = '1' then
max_pri := xives(i).pri; pending_pri := pending_pri or prio_decode(xives(i).pri);
max_idx := i;
end if; end if;
end loop; 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 then
pending_at_pri(i) := '1';
end if;
end loop;
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(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));
end if; end if;
icp_out_next.src <= std_ulogic_vector(to_unsigned(max_idx, 4)); icp_out_next.src <= max_idx;
icp_out_next.pri <= prio_unpack(max_pri); icp_out_next.pri <= prio_unpack(max_pri);
end process; end process;



Loading…
Cancel
Save