ignore /abc.history
[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); so: std_ulogic) return std_ulogic_vector;
21 function ppc_unsigned_compare(a, b: unsigned(63 downto 0); so: std_ulogic) 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
29 function bit_reverse(a: std_ulogic_vector) return std_ulogic_vector;
30 function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector;
31 function edgelocation(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector;
32 function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector;
33 function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector;
34 end package helpers;
35
36 package body helpers is
37 function fls_32 (val: std_ulogic_vector(31 downto 0)) return integer is
38 variable ret: integer;
39 begin
40 ret := 32;
41 for i in val'range loop
42 if val(i) = '1' then
43 ret := 31 - i;
44 exit;
45 end if;
46 end loop;
47
48 return ret;
49 end;
50
51 function ffs_32 (val: std_ulogic_vector(31 downto 0)) return integer is
52 variable ret: integer;
53 begin
54 ret := 32;
55 for i in val'reverse_range loop
56 if val(i) = '1' then
57 ret := i;
58 exit;
59 end if;
60 end loop;
61
62 return ret;
63 end;
64
65 function fls_64 (val: std_ulogic_vector(63 downto 0)) return integer is
66 variable ret: integer;
67 begin
68 ret := 64;
69 for i in val'range loop
70 if val(i) = '1' then
71 ret := 63 - i;
72 exit;
73 end if;
74 end loop;
75
76 return ret;
77 end;
78
79 function ffs_64 (val: std_ulogic_vector(63 downto 0)) return integer is
80 variable ret: integer;
81 begin
82 ret := 64;
83 for i in val'reverse_range loop
84 if val(i) = '1' then
85 ret := i;
86 exit;
87 end if;
88 end loop;
89
90 return ret;
91 end;
92
93 function popcnt8(val: std_ulogic_vector(7 downto 0)) return std_ulogic_vector is
94 variable ret: unsigned(3 downto 0) := (others => '0');
95 begin
96 for i in val'range loop
97 ret := ret + ("000" & val(i));
98 end loop;
99
100 return std_ulogic_vector(resize(ret, val'length));
101 end;
102
103 function popcnt32(val: std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
104 variable ret: unsigned(5 downto 0) := (others => '0');
105 begin
106 for i in val'range loop
107 ret := ret + ("00000" & val(i));
108 end loop;
109
110 return std_ulogic_vector(resize(ret, val'length));
111 end;
112
113 function popcnt64(val: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
114 variable ret: unsigned(6 downto 0) := (others => '0');
115 begin
116 for i in val'range loop
117 ret := ret + ("000000" & val(i));
118 end loop;
119
120 return std_ulogic_vector(resize(ret, val'length));
121 end;
122
123 function cmp_one_byte(a, b: std_ulogic_vector(7 downto 0)) return std_ulogic_vector is
124 variable ret: std_ulogic_vector(7 downto 0);
125 begin
126 if a = b then
127 ret := x"ff";
128 else
129 ret := x"00";
130 end if;
131
132 return ret;
133 end;
134
135 function ppc_signed_compare(a, b: signed(63 downto 0); so: std_ulogic) return std_ulogic_vector is
136 variable ret: std_ulogic_vector(2 downto 0);
137 begin
138 if a < b then
139 ret := "100";
140 elsif a > b then
141 ret := "010";
142 else
143 ret := "001";
144 end if;
145
146 return ret & so;
147 end;
148
149 function ppc_unsigned_compare(a, b: unsigned(63 downto 0); so: std_ulogic) return std_ulogic_vector is
150 variable ret: std_ulogic_vector(2 downto 0);
151 begin
152 if a < b then
153 ret := "100";
154 elsif a > b then
155 ret := "010";
156 else
157 ret := "001";
158 end if;
159
160 return ret & so;
161 end;
162
163 function ra_or_zero(ra: std_ulogic_vector(63 downto 0); reg: std_ulogic_vector(4 downto 0)) return std_ulogic_vector is
164 begin
165 if is_X(reg) then
166 return x"XXXXXXXXXXXXXXXX";
167 elsif to_integer(unsigned(reg)) = 0 then
168 return x"0000000000000000";
169 else
170 return ra;
171 end if;
172 end;
173
174 function byte_reverse(val: std_ulogic_vector(63 downto 0); size: integer) return std_ulogic_vector is
175 variable ret : std_ulogic_vector(63 downto 0) := (others => '0');
176 begin
177 -- Vivado doesn't support non constant vector slices, so we have to code
178 -- each of these.
179 case_0: case size is
180 when 2 =>
181 for_2 : for k in 0 to 1 loop
182 ret(((8*k)+7) downto (8*k)) := val((8*(1-k)+7) downto (8*(1-k)));
183 end loop;
184 when 4 =>
185 for_4 : for k in 0 to 3 loop
186 ret(((8*k)+7) downto (8*k)) := val((8*(3-k)+7) downto (8*(3-k)));
187 end loop;
188 when 8 =>
189 for_8 : for k in 0 to 7 loop
190 ret(((8*k)+7) downto (8*k)) := val((8*(7-k)+7) downto (8*(7-k)));
191 end loop;
192 when others =>
193 report "bad byte reverse length " & integer'image(size) severity failure;
194 end case;
195
196 return ret;
197 end;
198
199 function sign_extend(val: std_ulogic_vector(63 downto 0); size: natural) return std_ulogic_vector is
200 variable ret : signed(63 downto 0) := (others => '0');
201 variable upper : integer := 0;
202 begin
203 case_0: case size is
204 when 2 =>
205 ret := resize(signed(val(15 downto 0)), 64);
206 when 4 =>
207 ret := resize(signed(val(31 downto 0)), 64);
208 when 8 =>
209 ret := resize(signed(val(63 downto 0)), 64);
210 when others =>
211 report "bad byte reverse length " & integer'image(size) severity failure;
212 end case;
213
214 return std_ulogic_vector(ret);
215
216 end;
217
218 -- Reverse the order of bits in a word
219 function bit_reverse(a: std_ulogic_vector) return std_ulogic_vector is
220 variable ret: std_ulogic_vector(a'left downto a'right);
221 begin
222 for i in a'right to a'left loop
223 ret(a'left + a'right - i) := a(i);
224 end loop;
225 return ret;
226 end;
227
228 -- If there is only one bit set in a doubleword, return its bit number
229 -- (counting from the right). Each bit of the result is obtained by
230 -- ORing together 32 bits of the input:
231 -- bit 0 = a[1] or a[3] or a[5] or ...
232 -- bit 1 = a[2] or a[3] or a[6] or a[7] or ...
233 -- bit 2 = a[4..7] or a[12..15] or ...
234 -- bit 5 = a[32..63] ORed together
235 function bit_number(a: std_ulogic_vector(63 downto 0)) return std_ulogic_vector is
236 variable ret: std_ulogic_vector(5 downto 0);
237 variable stride: natural;
238 variable bit: std_ulogic;
239 variable k: natural;
240 begin
241 stride := 2;
242 for i in 0 to 5 loop
243 bit := '0';
244 for j in 0 to (64 / stride) - 1 loop
245 k := j * stride;
246 bit := bit or (or a(k + stride - 1 downto k + (stride / 2)));
247 end loop;
248 ret(i) := bit;
249 stride := stride * 2;
250 end loop;
251 return ret;
252 end;
253
254 -- Assuming the input 'v' is a value of the form 1...10...0,
255 -- the output is the bit number of the rightmost 1 bit in v.
256 -- If v is zero, the result is zero.
257 function edgelocation(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector is
258 variable p: std_ulogic_vector(nbits - 1 downto 0);
259 variable stride: natural;
260 variable b: std_ulogic;
261 variable k: natural;
262 begin
263 stride := 2;
264 for i in 0 to nbits - 1 loop
265 b := '0';
266 for j in 0 to (2**nbits / stride) - 1 loop
267 k := j * stride;
268 b := b or (v(k + stride - 1) and not v(k + (stride/2) - 1));
269 end loop;
270 p(i) := b;
271 stride := stride * 2;
272 end loop;
273 return p;
274 end function;
275
276 -- Count leading zeroes operations
277 -- Assumes the value passed in is not zero (if it is, zero is returned)
278 function count_right_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
279 variable sum: std_ulogic_vector(val'left downto val'right);
280 variable onehot: std_ulogic_vector(val'left downto val'right);
281 variable edge: std_ulogic_vector(val'left downto val'right);
282 variable bn, bn_e, bn_o: std_ulogic_vector(5 downto 0);
283 begin
284 sum := std_ulogic_vector(- signed(val));
285 onehot := sum and val;
286 edge := sum or val;
287 bn_e := edgelocation(std_ulogic_vector(resize(signed(edge), 64)), 6);
288 bn_o := bit_number(std_ulogic_vector(resize(unsigned(onehot), 64)));
289 bn := bn_e(5 downto 2) & bn_o(1 downto 0);
290 return bn;
291 end;
292
293 function count_left_zeroes(val: std_ulogic_vector) return std_ulogic_vector is
294 variable rev: std_ulogic_vector(val'left downto val'right);
295 begin
296 rev := bit_reverse(val);
297 return count_right_zeroes(rev);
298 end;
299
300 end package body helpers;