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