1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-01-13 15:18:09 +00:00
Paul Mackerras 0aa898c7a6 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>
2022-02-21 13:29:51 +11:00

299 lines
10 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
package helpers is
function fls_32 (val: std_ulogic_vector(31 downto 0)) return integer;
function ffs_32 (val: std_ulogic_vector(31 downto 0)) return integer;
function fls_64 (val: std_ulogic_vector(63 downto 0)) return integer;
function ffs_64 (val: std_ulogic_vector(63 downto 0)) return integer;
function popcnt8(val: std_ulogic_vector(7 downto 0)) return std_ulogic_vector;
function popcnt32(val: std_ulogic_vector(31 downto 0)) return std_ulogic_vector;
function popcnt64(val: std_ulogic_vector(63 downto 0)) return std_ulogic_vector;
function cmp_one_byte(a, b: std_ulogic_vector(7 downto 0)) return std_ulogic_vector;
function ppc_signed_compare(a, b: signed(63 downto 0); so: std_ulogic) return std_ulogic_vector;
function ppc_unsigned_compare(a, b: unsigned(63 downto 0); so: std_ulogic) return std_ulogic_vector;
function ra_or_zero(ra: std_ulogic_vector(63 downto 0); reg: std_ulogic_vector(4 downto 0)) return std_ulogic_vector;
function byte_reverse(val: std_ulogic_vector(63 downto 0); size: integer) return std_ulogic_vector;
function sign_extend(val: std_ulogic_vector(63 downto 0); size: natural) return std_ulogic_vector;
function bit_reverse(a: std_ulogic_vector) 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 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
function fls_32 (val: std_ulogic_vector(31 downto 0)) return integer is
variable ret: integer;
begin
ret := 32;
for i in val'range loop
if val(i) = '1' then
ret := 31 - i;
exit;
end if;
end loop;
return ret;
end;
function ffs_32 (val: std_ulogic_vector(31 downto 0)) return integer is
variable ret: integer;
begin
ret := 32;
for i in val'reverse_range loop
if val(i) = '1' then
ret := i;
exit;
end if;
end loop;
return ret;
end;
function fls_64 (val: std_ulogic_vector(63 downto 0)) return integer is
variable ret: integer;
begin
ret := 64;
for i in val'range loop
if val(i) = '1' then
ret := 63 - i;
exit;
end if;
end loop;
return ret;
end;
function ffs_64 (val: std_ulogic_vector(63 downto 0)) return integer is
variable ret: integer;
begin
ret := 64;
for i in val'reverse_range loop
if val(i) = '1' then
ret := i;
exit;
end if;
end loop;
return ret;
end;
function popcnt8(val: std_ulogic_vector(7 downto 0)) return std_ulogic_vector is
variable ret: unsigned(3 downto 0) := (others => '0');
begin
for i in val'range loop
ret := ret + ("000" & val(i));
end loop;
return std_ulogic_vector(resize(ret, val'length));
end;
function popcnt32(val: std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
variable ret: unsigned(5 downto 0) := (others => '0');
begin
for i in val'range loop
ret := ret + ("00000" & val(i));
end loop;
return std_ulogic_vector(resize(ret, val'length));
end;
function popcnt64(val: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
variable ret: unsigned(6 downto 0) := (others => '0');
begin
for i in val'range loop
ret := ret + ("000000" & val(i));
end loop;
return std_ulogic_vector(resize(ret, val'length));
end;
function cmp_one_byte(a, b: std_ulogic_vector(7 downto 0)) return std_ulogic_vector is
variable ret: std_ulogic_vector(7 downto 0);
begin
if a = b then
ret := x"ff";
else
ret := x"00";
end if;
return ret;
end;
function ppc_signed_compare(a, b: signed(63 downto 0); so: std_ulogic) return std_ulogic_vector is
variable ret: std_ulogic_vector(2 downto 0);
begin
if a < b then
ret := "100";
elsif a > b then
ret := "010";
else
ret := "001";
end if;
return ret & so;
end;
function ppc_unsigned_compare(a, b: unsigned(63 downto 0); so: std_ulogic) return std_ulogic_vector is
variable ret: std_ulogic_vector(2 downto 0);
begin
if a < b then
ret := "100";
elsif a > b then
ret := "010";
else
ret := "001";
end if;
return ret & so;
end;
function ra_or_zero(ra: std_ulogic_vector(63 downto 0); reg: std_ulogic_vector(4 downto 0)) return std_ulogic_vector is
begin
if to_integer(unsigned(reg)) = 0 then
return x"0000000000000000";
else
return ra;
end if;
end;
function byte_reverse(val: std_ulogic_vector(63 downto 0); size: integer) return std_ulogic_vector is
variable ret : std_ulogic_vector(63 downto 0) := (others => '0');
begin
-- Vivado doesn't support non constant vector slices, so we have to code
-- each of these.
case_0: case size is
when 2 =>
for_2 : for k in 0 to 1 loop
ret(((8*k)+7) downto (8*k)) := val((8*(1-k)+7) downto (8*(1-k)));
end loop;
when 4 =>
for_4 : for k in 0 to 3 loop
ret(((8*k)+7) downto (8*k)) := val((8*(3-k)+7) downto (8*(3-k)));
end loop;
when 8 =>
for_8 : for k in 0 to 7 loop
ret(((8*k)+7) downto (8*k)) := val((8*(7-k)+7) downto (8*(7-k)));
end loop;
when others =>
report "bad byte reverse length " & integer'image(size) severity failure;
end case;
return ret;
end;
function sign_extend(val: std_ulogic_vector(63 downto 0); size: natural) return std_ulogic_vector is
variable ret : signed(63 downto 0) := (others => '0');
variable upper : integer := 0;
begin
case_0: case size is
when 2 =>
ret := resize(signed(val(15 downto 0)), 64);
when 4 =>
ret := resize(signed(val(31 downto 0)), 64);
when 8 =>
ret := resize(signed(val(63 downto 0)), 64);
when others =>
report "bad byte reverse length " & integer'image(size) severity failure;
end case;
return std_ulogic_vector(ret);
end;
-- Reverse the order of bits in a word
function bit_reverse(a: std_ulogic_vector) return std_ulogic_vector is
variable ret: std_ulogic_vector(a'left downto a'right);
begin
for i in a'right to a'left loop
ret(a'left + a'right - i) := a(i);
end loop;
return ret;
end;
-- If there is only one bit set in a doubleword, return its bit number
-- (counting from the right). Each bit of the result is obtained by
-- ORing together 32 bits of the input:
-- bit 0 = a[1] or a[3] or a[5] or ...
-- bit 1 = a[2] or a[3] or a[6] or a[7] or ...
-- bit 2 = a[4..7] or a[12..15] or ...
-- bit 5 = a[32..63] ORed together
function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
variable ret: std_ulogic_vector(5 downto 0);
variable stride: natural;
variable bit: std_ulogic;
variable k: natural;
begin
stride := 2;
for i in 0 to 5 loop
bit := '0';
for j in 0 to (64 / stride) - 1 loop
k := j * stride;
bit := bit or (or a(k + stride - 1 downto k + (stride / 2)));
end loop;
ret(i) := bit;
stride := stride * 2;
end loop;
return ret;
end;
-- Assuming the input 'v' is a value of the form 1...10...0,
-- the output is the bit number of the rightmost 1 bit in v.
-- If v is zero, the result is zero.
function edgelocation(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector is
variable p: std_ulogic_vector(nbits - 1 downto 0);
variable stride: natural;
variable b: std_ulogic;
variable k: natural;
begin
stride := 2;
for i in 0 to nbits - 1 loop
b := '0';
for j in 0 to (2**nbits / stride) - 1 loop
k := j * stride;
b := b or (v(k + stride - 1) and not v(k + (stride/2) - 1));
end loop;
p(i) := b;
stride := stride * 2;
end loop;
return p;
end function;
-- Count leading zeroes operations
-- Assumes the value passed in is not zero (if it is, zero is returned)
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
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;