Initial import of microwatt
[microwatt.git] / helpers.vhdl
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4
5 library work;
6
7 package helpers is
8 function fls_32 (val: std_ulogic_vector(31 downto 0)) return integer;
9 function ffs_32 (val: std_ulogic_vector(31 downto 0)) return integer;
10
11 function fls_64 (val: std_ulogic_vector(63 downto 0)) return integer;
12 function ffs_64 (val: std_ulogic_vector(63 downto 0)) return integer;
13
14 function popcnt8(val: std_ulogic_vector(7 downto 0)) return std_ulogic_vector;
15 function popcnt32(val: std_ulogic_vector(31 downto 0)) return std_ulogic_vector;
16 function popcnt64(val: std_ulogic_vector(63 downto 0)) return std_ulogic_vector;
17
18 function cmp_one_byte(a, b: std_ulogic_vector(7 downto 0)) return std_ulogic_vector;
19
20 function ppc_signed_compare(a, b: signed(63 downto 0)) return std_ulogic_vector;
21 function ppc_unsigned_compare(a, b: unsigned(63 downto 0)) return std_ulogic_vector;
22
23 function ra_or_zero(ra: std_ulogic_vector(63 downto 0); reg: std_ulogic_vector(4 downto 0)) return std_ulogic_vector;
24
25 function byte_reverse(val: std_ulogic_vector(63 downto 0); size: integer) return std_ulogic_vector;
26
27 function sign_extend(val: std_ulogic_vector(63 downto 0); size: natural) return std_ulogic_vector;
28 end package helpers;
29
30 package body helpers is
31 function fls_32 (val: std_ulogic_vector(31 downto 0)) return integer is
32 variable ret: integer;
33 begin
34 ret := 32;
35 for i in val'range loop
36 if val(i) = '1' then
37 ret := 31 - i;
38 exit;
39 end if;
40 end loop;
41
42 return ret;
43 end;
44
45 function ffs_32 (val: std_ulogic_vector(31 downto 0)) return integer is
46 variable ret: integer;
47 begin
48 ret := 32;
49 for i in val'reverse_range loop
50 if val(i) = '1' then
51 ret := i;
52 exit;
53 end if;
54 end loop;
55
56 return ret;
57 end;
58
59 function fls_64 (val: std_ulogic_vector(63 downto 0)) return integer is
60 variable ret: integer;
61 begin
62 ret := 64;
63 for i in val'range loop
64 if val(i) = '1' then
65 ret := 63 - i;
66 exit;
67 end if;
68 end loop;
69
70 return ret;
71 end;
72
73 function ffs_64 (val: std_ulogic_vector(63 downto 0)) return integer is
74 variable ret: integer;
75 begin
76 ret := 64;
77 for i in val'reverse_range loop
78 if val(i) = '1' then
79 ret := i;
80 exit;
81 end if;
82 end loop;
83
84 return ret;
85 end;
86
87 function popcnt8(val: std_ulogic_vector(7 downto 0)) return std_ulogic_vector is
88 variable ret: unsigned(3 downto 0) := (others => '0');
89 begin
90 for i in val'range loop
91 ret := ret + ("000" & val(i));
92 end loop;
93
94 return std_ulogic_vector(resize(ret, val'length));
95 end;
96
97 function popcnt32(val: std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
98 variable ret: unsigned(5 downto 0) := (others => '0');
99 begin
100 for i in val'range loop
101 ret := ret + ("00000" & val(i));
102 end loop;
103
104 return std_ulogic_vector(resize(ret, val'length));
105 end;
106
107 function popcnt64(val: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
108 variable ret: unsigned(6 downto 0) := (others => '0');
109 begin
110 for i in val'range loop
111 ret := ret + ("000000" & val(i));
112 end loop;
113
114 return std_ulogic_vector(resize(ret, val'length));
115 end;
116
117 function cmp_one_byte(a, b: std_ulogic_vector(7 downto 0)) return std_ulogic_vector is
118 variable ret: std_ulogic_vector(7 downto 0);
119 begin
120 if a = b then
121 ret := x"ff";
122 else
123 ret := x"00";
124 end if;
125
126 return ret;
127 end;
128
129 function ppc_signed_compare(a, b: signed(63 downto 0)) return std_ulogic_vector is
130 variable ret: std_ulogic_vector(3 downto 0);
131 begin
132 if a < b then
133 ret := "1000";
134 elsif a > b then
135 ret := "0100";
136 else
137 ret := "0010";
138 end if;
139
140 return ret;
141 end;
142
143 function ppc_unsigned_compare(a, b: unsigned(63 downto 0)) return std_ulogic_vector is
144 variable ret: std_ulogic_vector(3 downto 0);
145 begin
146 if a < b then
147 ret := "1000";
148 elsif a > b then
149 ret := "0100";
150 else
151 ret := "0010";
152 end if;
153
154 return ret;
155 end;
156
157 function ra_or_zero(ra: std_ulogic_vector(63 downto 0); reg: std_ulogic_vector(4 downto 0)) return std_ulogic_vector is
158 begin
159 if to_integer(unsigned(reg)) = 0 then
160 return x"0000000000000000";
161 else
162 return ra;
163 end if;
164 end;
165
166 function byte_reverse(val: std_ulogic_vector(63 downto 0); size: integer) return std_ulogic_vector is
167 variable ret : std_ulogic_vector(63 downto 0) := (others => '0');
168 begin
169 -- Vivado doesn't support non constant vector slices, so we have to code
170 -- each of these.
171 case_0: case size is
172 when 2 =>
173 for_2 : for k in 0 to 1 loop
174 ret(((8*k)+7) downto (8*k)) := val((8*(1-k)+7) downto (8*(1-k)));
175 end loop;
176 when 4 =>
177 for_4 : for k in 0 to 3 loop
178 ret(((8*k)+7) downto (8*k)) := val((8*(3-k)+7) downto (8*(3-k)));
179 end loop;
180 when 8 =>
181 for_8 : for k in 0 to 7 loop
182 ret(((8*k)+7) downto (8*k)) := val((8*(7-k)+7) downto (8*(7-k)));
183 end loop;
184 when others =>
185 report "bad byte reverse length " & integer'image(size) severity failure;
186 end case;
187
188 return ret;
189 end;
190
191 function sign_extend(val: std_ulogic_vector(63 downto 0); size: natural) return std_ulogic_vector is
192 variable ret : signed(63 downto 0) := (others => '0');
193 variable upper : integer := 0;
194 begin
195 case_0: case size is
196 when 2 =>
197 upper := 15;
198 when 4 =>
199 upper := 31;
200 when 8 =>
201 upper := 63;
202 when others =>
203 report "bad byte reverse length " & integer'image(size) severity failure;
204 end case;
205
206 ret := resize(signed(val(upper downto 0)), 64);
207 return std_ulogic_vector(ret);
208 end;
209 end package body helpers;