You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
10 KiB
300 lines
10 KiB
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 is_X(reg) then |
|
return x"XXXXXXXXXXXXXXXX"; |
|
elsif 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;
|
|
|