From 0aa898c7a6975732f21481487ae44fa7cd5d3503 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 19 Oct 2021 15:13:31 +1100 Subject: [PATCH] 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 --- helpers.vhdl | 21 ++++++++----- xics.vhdl | 83 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/helpers.vhdl b/helpers.vhdl index 654c113..bb69927 100644 --- a/helpers.vhdl +++ b/helpers.vhdl @@ -30,6 +30,7 @@ package helpers is 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 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; package body helpers is @@ -270,22 +271,28 @@ package body helpers is return p; end function; - -- Count leading zeroes operation + -- Count leading zeroes operations -- 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 - variable rev: std_ulogic_vector(val'left downto val'right); + function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector is variable sum: 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 bn, bn_e, bn_o: std_ulogic_vector(5 downto 0); begin - rev := bit_reverse(val); - sum := std_ulogic_vector(- signed(rev)); - onehot := sum and rev; - edge := sum or rev; + sum := std_ulogic_vector(- signed(val)); + onehot := sum and val; + edge := sum or val; bn_e := edgelocation(std_ulogic_vector(resize(signed(edge), 64)), 6); bn_o := bit_number(std_ulogic_vector(resize(unsigned(onehot), 64))); bn := bn_e(5 downto 2) & bn_o(1 downto 0); return bn; 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; diff --git a/xics.vhdl b/xics.vhdl index 0e3a1da..6daa5d4 100644 --- a/xics.vhdl +++ b/xics.vhdl @@ -54,9 +54,6 @@ architecture behaviour of xics_icp is 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 constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00"; constant XIRR : std_ulogic_vector(7 downto 0) := x"04"; @@ -207,12 +204,14 @@ use ieee.numeric_std.all; library work; use work.common.all; +use work.utils.all; use work.wishbone_types.all; +use work.helpers.all; entity xics_ics is generic ( 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 ( clk : in std_logic; @@ -228,12 +227,16 @@ end xics_ics; 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); type xive_t is record pri : pri_t; end record; 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; signal xives : xive_array_t; @@ -262,8 +265,15 @@ architecture rtl of xics_ics is end function; function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is + variable masked : std_ulogic_vector(7 downto 0); begin - return pri8(PRIO_BITS-1 downto 0); + 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); + end if; end function; function prio_unpack(pri: pri_t) return std_ulogic_vector is @@ -276,8 +286,27 @@ architecture rtl of xics_ics is r(PRIO_BITS-1 downto 0) := pri; end if; 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 -- 0 : Config @@ -391,35 +420,33 @@ begin end process; 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; - - -- A more favored than b ? - 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 - a_i := unsigned(a); - b_i := unsigned(b); - report "a_mf_b a=" & to_hstring(a) & - " b=" & to_hstring(b) & - " r=" & boolean'image(a < b); - return a_i < b_i; - end function; + variable pending_pri : pri_vector_t; + variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0); begin - -- XXX FIXME: Use a tree - max_pri := pri_masked; - max_idx := 0; + -- 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' and a_mf_b(xives(i).pri, max_pri) then - max_pri := xives(i).pri; - max_idx := i; + 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); + + -- 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 - 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; - 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); end process;