


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*(1k)+7) downto (8*(1k)));




end loop;




when 4 =>




for_4 : for k in 0 to 3 loop




ret(((8*k)+7) downto (8*k)) := val((8*(3k)+7) downto (8*(3k)));




end loop;




when 8 =>




for_8 : for k in 0 to 7 loop




ret(((8*k)+7) downto (8*k)) := val((8*(7k)+7) downto (8*(7k)));




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;
