Skip to content

Commit 0aa898c

Browse files
committed
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>
1 parent 1720a05 commit 0aa898c

2 files changed

Lines changed: 69 additions & 35 deletions

File tree

helpers.vhdl

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ package helpers is
3030
function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector;
3131
function edgelocation(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector;
3232
function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector;
33+
function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector;
3334
end package helpers;
3435

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

273-
-- Count leading zeroes operation
274+
-- Count leading zeroes operations
274275
-- Assumes the value passed in is not zero (if it is, zero is returned)
275-
function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
276-
variable rev: std_ulogic_vector(val'left downto val'right);
276+
function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
277277
variable sum: std_ulogic_vector(val'left downto val'right);
278278
variable onehot: std_ulogic_vector(val'left downto val'right);
279279
variable edge: std_ulogic_vector(val'left downto val'right);
280280
variable bn, bn_e, bn_o: std_ulogic_vector(5 downto 0);
281281
begin
282-
rev := bit_reverse(val);
283-
sum := std_ulogic_vector(- signed(rev));
284-
onehot := sum and rev;
285-
edge := sum or rev;
282+
sum := std_ulogic_vector(- signed(val));
283+
onehot := sum and val;
284+
edge := sum or val;
286285
bn_e := edgelocation(std_ulogic_vector(resize(signed(edge), 64)), 6);
287286
bn_o := bit_number(std_ulogic_vector(resize(unsigned(onehot), 64)));
288287
bn := bn_e(5 downto 2) & bn_o(1 downto 0);
289288
return bn;
290289
end;
290+
291+
function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
292+
variable rev: std_ulogic_vector(val'left downto val'right);
293+
begin
294+
rev := bit_reverse(val);
295+
return count_right_zeroes(rev);
296+
end;
297+
291298
end package body helpers;

xics.vhdl

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ architecture behaviour of xics_icp is
5454

5555
signal r, r_next : reg_internal_t;
5656

57-
-- hardwire the hardware IRQ priority
58-
constant HW_PRIORITY : std_ulogic_vector(7 downto 0) := x"80";
59-
6057
-- 8 bit offsets for each presentation
6158
constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00";
6259
constant XIRR : std_ulogic_vector(7 downto 0) := x"04";
@@ -207,12 +204,14 @@ use ieee.numeric_std.all;
207204

208205
library work;
209206
use work.common.all;
207+
use work.utils.all;
210208
use work.wishbone_types.all;
209+
use work.helpers.all;
211210

212211
entity xics_ics is
213212
generic (
214213
SRC_NUM : integer range 1 to 256 := 16;
215-
PRIO_BITS : integer range 1 to 8 := 8
214+
PRIO_BITS : integer range 1 to 8 := 3
216215
);
217216
port (
218217
clk : in std_logic;
@@ -228,12 +227,16 @@ end xics_ics;
228227

229228
architecture rtl of xics_ics is
230229

230+
constant SRC_NUM_BITS : natural := log2(SRC_NUM);
231+
231232
subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0);
232233
type xive_t is record
233234
pri : pri_t;
234235
end record;
235236
constant pri_masked : pri_t := (others => '1');
236237

238+
subtype pri_vector_t is std_ulogic_vector(2**PRIO_BITS - 1 downto 0);
239+
237240
type xive_array_t is array(0 to SRC_NUM-1) of xive_t;
238241
signal xives : xive_array_t;
239242

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

264267
function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is
268+
variable masked : std_ulogic_vector(7 downto 0);
265269
begin
266-
return pri8(PRIO_BITS-1 downto 0);
270+
masked := x"00";
271+
masked(PRIO_BITS - 1 downto 0) := (others => '1');
272+
if pri8 >= masked then
273+
return pri_masked;
274+
else
275+
return pri8(PRIO_BITS-1 downto 0);
276+
end if;
267277
end function;
268278

269279
function prio_unpack(pri: pri_t) return std_ulogic_vector is
@@ -276,8 +286,27 @@ architecture rtl of xics_ics is
276286
r(PRIO_BITS-1 downto 0) := pri;
277287
end if;
278288
return r;
279-
end function;
289+
end function;
280290

291+
function prio_decode(pri: pri_t) return pri_vector_t is
292+
variable v: pri_vector_t;
293+
begin
294+
v := (others => '0');
295+
v(to_integer(unsigned(pri))) := '1';
296+
return v;
297+
end function;
298+
299+
-- Assumes nbits <= 6; v is 2^nbits wide
300+
function priority_encoder(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector is
301+
variable h: std_ulogic_vector(2**nbits - 1 downto 0);
302+
variable p: std_ulogic_vector(5 downto 0);
303+
begin
304+
-- Set the lowest-priority (highest-numbered) bit
305+
h := v;
306+
h(2**nbits - 1) := '1';
307+
p := count_right_zeroes(h);
308+
return p(nbits - 1 downto 0);
309+
end function;
281310

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

393422
irq_gen: process(all)
394-
variable max_idx : integer range 0 to SRC_NUM-1;
423+
variable max_idx : std_ulogic_vector(SRC_NUM_BITS - 1 downto 0);
395424
variable max_pri : pri_t;
396-
397-
-- A more favored than b ?
398-
function a_mf_b(a: pri_t; b: pri_t) return boolean is
399-
variable a_i : unsigned(PRIO_BITS-1 downto 0);
400-
variable b_i : unsigned(PRIO_BITS-1 downto 0);
401-
begin
402-
a_i := unsigned(a);
403-
b_i := unsigned(b);
404-
report "a_mf_b a=" & to_hstring(a) &
405-
" b=" & to_hstring(b) &
406-
" r=" & boolean'image(a < b);
407-
return a_i < b_i;
408-
end function;
425+
variable pending_pri : pri_vector_t;
426+
variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
409427
begin
410-
-- XXX FIXME: Use a tree
411-
max_pri := pri_masked;
412-
max_idx := 0;
428+
-- Work out the most-favoured (lowest) priority of the pending interrupts
429+
pending_pri := (others => '0');
413430
for i in 0 to SRC_NUM - 1 loop
414-
if int_level_l(i) = '1' and a_mf_b(xives(i).pri, max_pri) then
415-
max_pri := xives(i).pri;
416-
max_idx := i;
431+
if int_level_l(i) = '1' then
432+
pending_pri := pending_pri or prio_decode(xives(i).pri);
417433
end if;
418434
end loop;
435+
max_pri := priority_encoder(pending_pri, PRIO_BITS);
436+
437+
-- Work out which interrupts are pending at that priority
438+
pending_at_pri := (others => '0');
439+
for i in 0 to SRC_NUM - 1 loop
440+
if int_level_l(i) = '1' and xives(i).pri = max_pri then
441+
pending_at_pri(i) := '1';
442+
end if;
443+
end loop;
444+
max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);
445+
419446
if max_pri /= pri_masked then
420-
report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(prio_unpack(max_pri));
447+
report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri));
421448
end if;
422-
icp_out_next.src <= std_ulogic_vector(to_unsigned(max_idx, 4));
449+
icp_out_next.src <= max_idx;
423450
icp_out_next.pri <= prio_unpack(max_pri);
424451
end process;
425452

0 commit comments

Comments
 (0)