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