mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-13 15:18:09 +00:00
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>
299 lines
10 KiB
VHDL
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;
|