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>
fpu-constant
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 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;

@ -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;


Loading…
Cancel
Save