1 |
4 |
microengin |
-- IOTA Pearl Diver VHDL Port
|
2 |
|
|
--
|
3 |
7 |
microengin |
-- 2018 by Thomas Pototschnig <microengineer18@gmail.com,
|
4 |
|
|
-- http://microengineer.eu
|
5 |
|
|
-- discord: pmaxuw#8292
|
6 |
4 |
microengin |
--
|
7 |
7 |
microengin |
-- Permission is hereby granted, free of charge, to any person obtaining
|
8 |
|
|
-- a copy of this software and associated documentation files (the
|
9 |
|
|
-- "Software"), to deal in the Software without restriction, including
|
10 |
|
|
-- without limitation the rights to use, copy, modify, merge, publish,
|
11 |
|
|
-- distribute, sublicense, and/or sell copies of the Software, and to
|
12 |
|
|
-- permit persons to whom the Software is furnished to do so, subject to
|
13 |
|
|
-- the following conditions:
|
14 |
4 |
microengin |
--
|
15 |
7 |
microengin |
-- The above copyright notice and this permission notice shall be
|
16 |
|
|
-- included in all copies or substantial portions of the Software.
|
17 |
4 |
microengin |
--
|
18 |
7 |
microengin |
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19 |
|
|
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20 |
|
|
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21 |
|
|
-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22 |
|
|
-- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23 |
|
|
-- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24 |
|
|
-- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR
|
25 |
4 |
microengin |
|
26 |
|
|
library ieee;
|
27 |
5 |
microengin |
|
28 |
4 |
microengin |
use ieee.std_logic_1164.all;
|
29 |
|
|
use ieee.numeric_std.all;
|
30 |
|
|
use work.index_table.all;
|
31 |
5 |
microengin |
|
32 |
4 |
microengin |
entity curl is
|
33 |
|
|
generic
|
34 |
|
|
(
|
35 |
|
|
HASH_LENGTH : integer := 243;
|
36 |
|
|
STATE_LENGTH : integer := 729; -- 3 * HASH_LENGTH;
|
37 |
|
|
NONCE_LENGTH : integer := 81; -- HASH_LENGTH / 3;
|
38 |
|
|
NUMBER_OF_ROUNDS : integer := 81;
|
39 |
|
|
PARALLEL : integer := 7;
|
40 |
|
|
INTERN_NONCE_LENGTH : integer := 32;
|
41 |
|
|
BITS_MIN_WEIGHT_MAGINUTE_MAX : integer := 26;
|
42 |
5 |
microengin |
DATA_WIDTH : integer := 9;
|
43 |
|
|
NONCE_OFFSET : integer := 162 -- we hope it nevery changes
|
44 |
4 |
microengin |
);
|
45 |
|
|
|
46 |
|
|
port
|
47 |
|
|
(
|
48 |
|
|
clk : in std_logic;
|
49 |
|
|
clk_slow : in std_logic;
|
50 |
|
|
reset : in std_logic;
|
51 |
|
|
|
52 |
|
|
spi_data_rx : in std_logic_vector(31 downto 0);
|
53 |
|
|
spi_data_tx : out std_logic_vector(31 downto 0);
|
54 |
|
|
spi_data_rxen : in std_logic;
|
55 |
7 |
microengin |
spi_data_strobe : out std_logic;
|
56 |
4 |
microengin |
overflow : out std_logic;
|
57 |
|
|
running : out std_logic;
|
58 |
|
|
found : out std_logic
|
59 |
|
|
);
|
60 |
|
|
|
61 |
|
|
end curl;
|
62 |
|
|
|
63 |
|
|
architecture behv of curl is
|
64 |
|
|
|
65 |
|
|
subtype state_vector_type is std_logic_vector(PARALLEL-1 downto 0);
|
66 |
|
|
subtype mid_state_vector_type is std_logic_vector(DATA_WIDTH-1 downto 0);
|
67 |
5 |
microengin |
subtype min_weight_magnitude_type is std_logic_vector(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
|
68 |
4 |
microengin |
|
69 |
|
|
type curl_state_array is array(integer range <>) of state_vector_type;
|
70 |
|
|
type mid_state_array is array(integer range <>) of mid_state_vector_type;
|
71 |
5 |
microengin |
type min_weight_magnitude_array is array(integer range<>) of min_weight_magnitude_type;
|
72 |
4 |
microengin |
|
73 |
|
|
signal curl_state_low : curl_state_array(STATE_LENGTH-1 downto 0);
|
74 |
|
|
signal curl_state_high : curl_state_array(STATE_LENGTH-1 downto 0);
|
75 |
|
|
|
76 |
7 |
microengin |
signal data_low : mid_state_array((HASH_LENGTH/DATA_WIDTH)-1 downto 0);
|
77 |
|
|
signal data_high : mid_state_array((HASH_LENGTH/DATA_WIDTH)-1 downto 0);
|
78 |
4 |
microengin |
|
79 |
7 |
microengin |
|
80 |
|
|
signal curl_mid_state_low : std_logic_vector(STATE_LENGTH-1 downto 0);
|
81 |
|
|
signal curl_mid_state_high : std_logic_vector(STATE_LENGTH-1 downto 0);
|
82 |
|
|
|
83 |
4 |
microengin |
signal flag_running : std_logic := '0';
|
84 |
|
|
signal flag_overflow : std_logic := '0';
|
85 |
|
|
signal flag_found : std_logic := '0';
|
86 |
|
|
signal flag_start : std_logic := '0';
|
87 |
|
|
|
88 |
7 |
microengin |
signal flag_curl_finished : std_logic := '0';
|
89 |
|
|
|
90 |
|
|
type binary_nonce_array is array(integer range<>) of unsigned(INTERN_NONCE_LENGTH-1 downto 0);
|
91 |
|
|
|
92 |
|
|
|
93 |
4 |
microengin |
signal binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
|
94 |
|
|
signal mask : state_vector_type;
|
95 |
5 |
microengin |
signal min_weight_magnitude : min_weight_magnitude_type;
|
96 |
4 |
microengin |
|
97 |
7 |
microengin |
signal i_binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
|
98 |
|
|
signal tmp_weight_magnitude : min_weight_magnitude_array(0 to PARALLEL-1);
|
99 |
|
|
|
100 |
|
|
signal flag_curl_reset : std_logic;
|
101 |
|
|
signal flag_curl_write : std_logic;
|
102 |
|
|
signal flag_curl_do_curl : std_logic;
|
103 |
|
|
|
104 |
|
|
signal imask : state_vector_type;
|
105 |
|
|
|
106 |
|
|
|
107 |
|
|
|
108 |
5 |
microengin |
function expand(b : std_logic)
|
109 |
|
|
return state_vector_type is
|
110 |
4 |
microengin |
begin
|
111 |
5 |
microengin |
if b = '1' then
|
112 |
|
|
return (others => '1');
|
113 |
|
|
else
|
114 |
|
|
return (others => '0');
|
115 |
|
|
end if;
|
116 |
|
|
end expand;
|
117 |
7 |
microengin |
|
118 |
|
|
|
119 |
5 |
microengin |
begin
|
120 |
4 |
microengin |
overflow <= flag_overflow;
|
121 |
|
|
running <= flag_running;
|
122 |
|
|
found <= flag_found;
|
123 |
|
|
|
124 |
|
|
process (clk_slow)
|
125 |
|
|
-- because it looks prettier
|
126 |
|
|
variable spi_cmd : std_logic_vector(5 downto 0);
|
127 |
5 |
microengin |
variable addrptr : unsigned(7 downto 0) := x"00";
|
128 |
4 |
microengin |
begin
|
129 |
|
|
if rising_edge(clk_slow) then
|
130 |
|
|
if reset='1' then
|
131 |
|
|
min_weight_magnitude <= (others => '0');
|
132 |
|
|
flag_start <= '0';
|
133 |
5 |
microengin |
spi_data_tx <= (others => '0');
|
134 |
|
|
addrptr := x"00";
|
135 |
4 |
microengin |
else
|
136 |
|
|
flag_start <= '0';
|
137 |
7 |
microengin |
flag_curl_reset <= '0';
|
138 |
|
|
flag_curl_write <= '0';
|
139 |
|
|
flag_curl_do_curl <= '0';
|
140 |
|
|
spi_data_strobe <= '0';
|
141 |
|
|
|
142 |
4 |
microengin |
-- new spi data received
|
143 |
|
|
if spi_data_rxen = '1' then
|
144 |
|
|
spi_cmd := spi_data_rx(31 downto 26);
|
145 |
|
|
case spi_cmd is
|
146 |
5 |
microengin |
when "000000" => -- nop (mainly for reading back data)
|
147 |
7 |
microengin |
when "100000" => -- start / stop
|
148 |
5 |
microengin |
flag_start <= spi_data_rx(0);
|
149 |
7 |
microengin |
flag_curl_reset <= spi_data_rx(1);
|
150 |
|
|
flag_curl_write <= spi_data_rx(2);
|
151 |
|
|
flag_curl_do_curl <= spi_data_rx(3);
|
152 |
|
|
when "010000" => -- write to wr address
|
153 |
|
|
addrptr := (others => '0'); --unsigned(spi_data_rx(7 downto 0));
|
154 |
|
|
when "001000" => -- write to data buffer
|
155 |
|
|
if (addrptr <= (HASH_LENGTH/DATA_WIDTH)-1) then
|
156 |
|
|
data_low(to_integer(addrptr)) <= spi_data_rx(DATA_WIDTH-1 downto 0);
|
157 |
|
|
data_high(to_integer(addrptr)) <= spi_data_rx(DATA_WIDTH+8 downto DATA_WIDTH);
|
158 |
5 |
microengin |
end if;
|
159 |
|
|
addrptr := addrptr + 1;
|
160 |
7 |
microengin |
when "000100" =>
|
161 |
4 |
microengin |
min_weight_magnitude <= spi_data_rx(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
|
162 |
7 |
microengin |
when "000010" => -- read flags
|
163 |
|
|
spi_data_tx(3 downto 0) <= flag_curl_finished & flag_overflow & flag_found & flag_running;
|
164 |
|
|
spi_data_tx(7 downto 4) <= std_logic_vector(to_unsigned(PARALLEL, 4));
|
165 |
|
|
spi_data_tx(8+(PARALLEL-1) downto 8) <= mask;
|
166 |
|
|
spi_data_strobe <= '1';
|
167 |
|
|
when "000001" => -- read nonce
|
168 |
4 |
microengin |
spi_data_tx(INTERN_NONCE_LENGTH-1 downto 0) <= std_logic_vector(binary_nonce);
|
169 |
7 |
microengin |
spi_data_strobe <= '1';
|
170 |
4 |
microengin |
when others =>
|
171 |
7 |
microengin |
end case;
|
172 |
4 |
microengin |
end if;
|
173 |
|
|
end if;
|
174 |
|
|
end if;
|
175 |
|
|
end process;
|
176 |
|
|
|
177 |
7 |
microengin |
process (clk_slow)
|
178 |
|
|
variable state : integer range 0 to 7 := 0;
|
179 |
|
|
variable round : integer range 0 to 127 := 0;
|
180 |
|
|
variable tmp_index : integer range 0 to 1023;
|
181 |
|
|
|
182 |
|
|
variable alpha : std_logic_vector(STATE_LENGTH-1 downto 0);
|
183 |
|
|
variable beta : std_logic_vector(STATE_LENGTH-1 downto 0);
|
184 |
|
|
variable gamma : std_logic_vector(STATE_LENGTH-1 downto 0);
|
185 |
|
|
variable delta : std_logic_vector(STATE_LENGTH-1 downto 0);
|
186 |
|
|
|
187 |
|
|
begin
|
188 |
|
|
if rising_edge(clk_slow) then
|
189 |
|
|
if reset='1' then
|
190 |
|
|
state := 0;
|
191 |
|
|
else
|
192 |
|
|
case state is
|
193 |
|
|
when 0 =>
|
194 |
|
|
round := NUMBER_OF_ROUNDS;
|
195 |
|
|
flag_curl_finished <= '1';
|
196 |
5 |
microengin |
|
197 |
7 |
microengin |
if flag_curl_write = '1' then
|
198 |
|
|
for I in 0 to (HASH_LENGTH/DATA_WIDTH)-1 loop
|
199 |
|
|
for J in 0 to DATA_WIDTH-1 loop
|
200 |
|
|
tmp_index := I*DATA_WIDTH+J;
|
201 |
|
|
curl_mid_state_low(tmp_index) <= data_low(I)(J);
|
202 |
|
|
curl_mid_state_high(tmp_index) <= data_high(I)(J);
|
203 |
|
|
end loop;
|
204 |
|
|
end loop;
|
205 |
|
|
elsif flag_curl_reset='1' then
|
206 |
|
|
curl_mid_state_low <= (others => '1');
|
207 |
|
|
curl_mid_state_high <= (others => '1');
|
208 |
|
|
end if;
|
209 |
|
|
|
210 |
|
|
if flag_curl_do_curl = '1' then
|
211 |
|
|
round := NUMBER_OF_ROUNDS;
|
212 |
|
|
flag_curl_finished <= '0';
|
213 |
|
|
state := 1;
|
214 |
|
|
end if;
|
215 |
|
|
when 1 => -- do the curl hash round without any copying needed
|
216 |
|
|
if round = 1 then
|
217 |
|
|
state := 0;
|
218 |
|
|
end if;
|
219 |
|
|
for I in 0 to STATE_LENGTH-1 loop
|
220 |
|
|
alpha(I) := curl_mid_state_low(index_table(I));
|
221 |
|
|
beta(I) := curl_mid_state_high(index_table(I));
|
222 |
|
|
gamma(I) := curl_mid_state_high(index_table(I+1));
|
223 |
|
|
|
224 |
|
|
delta(I) := (alpha(I) or (not gamma(I))) and (curl_mid_state_low(index_table(I+1)) xor beta(I));
|
225 |
|
|
|
226 |
|
|
curl_mid_state_low(I) <= not delta(I);
|
227 |
|
|
curl_mid_state_high(I) <= (alpha(I) xor gamma(I)) or delta(I);
|
228 |
|
|
end loop;
|
229 |
|
|
round := round - 1;
|
230 |
|
|
when others =>
|
231 |
|
|
state := 0;
|
232 |
|
|
end case;
|
233 |
|
|
end if;
|
234 |
|
|
end if;
|
235 |
|
|
end process;
|
236 |
5 |
microengin |
|
237 |
4 |
microengin |
process (clk)
|
238 |
7 |
microengin |
variable state : integer range 0 to 63 := 0;
|
239 |
4 |
microengin |
variable round : integer range 0 to 127 := 0;
|
240 |
|
|
|
241 |
|
|
|
242 |
5 |
microengin |
variable i_min_weight_magnitude : min_weight_magnitude_type;
|
243 |
4 |
microengin |
|
244 |
|
|
-- temporary registers get optimized away
|
245 |
|
|
variable alpha : curl_state_array(STATE_LENGTH-1 downto 0);
|
246 |
|
|
variable beta : curl_state_array(STATE_LENGTH-1 downto 0);
|
247 |
|
|
variable gamma : curl_state_array(STATE_LENGTH-1 downto 0);
|
248 |
|
|
variable delta : curl_state_array(STATE_LENGTH-1 downto 0);
|
249 |
7 |
microengin |
|
250 |
5 |
microengin |
variable tmp_highest_bit : integer range 0 to 31;
|
251 |
4 |
microengin |
begin
|
252 |
|
|
if rising_edge(clk) then
|
253 |
|
|
if reset='1' then
|
254 |
|
|
state := 0;
|
255 |
5 |
microengin |
round := 0;
|
256 |
4 |
microengin |
flag_found <= '0';
|
257 |
|
|
flag_running <= '0';
|
258 |
|
|
flag_overflow <= '0';
|
259 |
|
|
binary_nonce <= (others => '0');
|
260 |
5 |
microengin |
mask <= (others => '0');
|
261 |
|
|
-- curl_state_low <= (others => (others => '0'));
|
262 |
|
|
-- curl_state_high <= (others => (others => '0'));
|
263 |
|
|
-- tmp_weight_magnitude := (others => (others => '0'));
|
264 |
7 |
microengin |
i_binary_nonce <= (others => '0');
|
265 |
|
|
imask <= (others => '0');
|
266 |
|
|
-- i_min_weight_magnitude := (others => '0');
|
267 |
|
|
-- alpha := (others => (others => '0'));
|
268 |
|
|
-- beta := (others => (others => '0'));
|
269 |
|
|
-- gamma := (others => (others => '0'));
|
270 |
|
|
-- delta := (others => (others => '0'));
|
271 |
|
|
-- tmp_index := 0;
|
272 |
|
|
tmp_weight_magnitude <= (others => (others => '0'));
|
273 |
4 |
microengin |
else
|
274 |
|
|
case state is
|
275 |
|
|
when 0 =>
|
276 |
|
|
flag_running <= '0';
|
277 |
7 |
microengin |
when others =>
|
278 |
|
|
flag_running <= '1';
|
279 |
|
|
end case;
|
280 |
|
|
|
281 |
|
|
case state is
|
282 |
|
|
when 0 =>
|
283 |
|
|
-- flag_running <= '0';
|
284 |
4 |
microengin |
if flag_start = '1' then
|
285 |
7 |
microengin |
i_binary_nonce <= x"00000000";
|
286 |
|
|
-- flag_running <= '1';
|
287 |
4 |
microengin |
state := 1;
|
288 |
|
|
end if;
|
289 |
7 |
microengin |
|
290 |
|
|
-- do PoW
|
291 |
|
|
when 1 => -- copy mid state and insert nonce
|
292 |
|
|
i_min_weight_magnitude := min_weight_magnitude;
|
293 |
4 |
microengin |
flag_found <= '0';
|
294 |
|
|
flag_overflow <= '0';
|
295 |
7 |
microengin |
binary_nonce <= i_binary_nonce;
|
296 |
|
|
-- pipelining
|
297 |
|
|
i_binary_nonce <= i_binary_nonce + 1;
|
298 |
|
|
|
299 |
|
|
-- -- copy and fully expand mid-state to curl-state
|
300 |
|
|
for I in 0 to STATE_LENGTH-1 loop
|
301 |
|
|
if I < NONCE_OFFSET or I > NONCE_OFFSET + NONCE_LENGTH - 1 then
|
302 |
|
|
curl_state_low(I) <= expand(curl_mid_state_low(I));
|
303 |
|
|
curl_state_high(I) <= expand(curl_mid_state_high(I));
|
304 |
|
|
end if;
|
305 |
|
|
end loop;
|
306 |
|
|
|
307 |
|
|
-- for I in 0 to NONCE_OFFSET-1 loop
|
308 |
|
|
-- curl_state_low(I) <= expand(curl_mid_state_low(I));
|
309 |
|
|
-- curl_state_high(I) <= expand(curl_mid_state_high(I));
|
310 |
|
|
-- end loop;
|
311 |
|
|
--
|
312 |
|
|
-- for I in NONCE_OFFSET + NONCE_LENGTH to STATE_LENGTH-1 loop
|
313 |
|
|
-- curl_state_low(I) <= expand(curl_mid_state_low(I));
|
314 |
|
|
-- curl_state_high(I) <= expand(curl_mid_state_high(I));
|
315 |
|
|
-- end loop;
|
316 |
4 |
microengin |
|
317 |
|
|
|
318 |
5 |
microengin |
-- fill all ... synthesizer is smart enough to optimize away what is not needed
|
319 |
|
|
for I in NONCE_OFFSET to NONCE_OFFSET + NONCE_LENGTH - 1 loop
|
320 |
|
|
curl_state_low(I) <= expand('1');
|
321 |
|
|
curl_state_high(I) <= expand('1');
|
322 |
|
|
end loop;
|
323 |
|
|
|
324 |
|
|
-- calculate log2(x) by determining the place of highest set bit
|
325 |
|
|
-- this is calculated on constants, so no logic needed
|
326 |
|
|
tmp_highest_bit := 0;
|
327 |
|
|
for I in 0 to 31 loop -- 32 is enough ...^^
|
328 |
|
|
if to_unsigned(PARALLEL-1, 32)(I) = '1' then
|
329 |
|
|
tmp_highest_bit := I;
|
330 |
|
|
end if;
|
331 |
|
|
end loop;
|
332 |
|
|
|
333 |
|
|
-- -- generate bitmuster in first trit-arrays of nonce depending on PARALLEL setting
|
334 |
|
|
-- this is calculated on constants, so no logic needed
|
335 |
|
|
for I in 0 to PARALLEL-1 loop
|
336 |
|
|
for J in 0 to tmp_highest_bit loop
|
337 |
|
|
curl_state_low(NONCE_OFFSET+J)(I) <= to_unsigned(I, tmp_highest_bit+1)(J);
|
338 |
|
|
curl_state_high(NONCE_OFFSET+J)(I) <= not to_unsigned(I, tmp_highest_bit+1)(J);
|
339 |
4 |
microengin |
end loop;
|
340 |
|
|
end loop;
|
341 |
|
|
|
342 |
5 |
microengin |
-- insert and convert binary nonce to ternary nonce
|
343 |
|
|
-- It's a fake ternary nonce but integer-values are strictly monotonously rising
|
344 |
4 |
microengin |
-- with integer values of binary nonce.
|
345 |
|
|
-- Doesn't bring the exact same result like reference implementation with real
|
346 |
5 |
microengin |
-- ternary adder - but it doesn't matter and it is way faster.
|
347 |
|
|
-- conveniently put nonce counter at the end of nonce
|
348 |
|
|
for I in 0 to INTERN_NONCE_LENGTH-1 loop
|
349 |
|
|
curl_state_low(NONCE_OFFSET + NONCE_LENGTH - INTERN_NONCE_LENGTH + I) <= expand(i_binary_nonce(I));
|
350 |
|
|
curl_state_high(NONCE_OFFSET + NONCE_LENGTH - INTERN_NONCE_LENGTH + I) <= not expand(i_binary_nonce(I));
|
351 |
4 |
microengin |
end loop;
|
352 |
|
|
|
353 |
|
|
-- initialize round-counter
|
354 |
|
|
round := NUMBER_OF_ROUNDS;
|
355 |
7 |
microengin |
if i_binary_nonce = x"ffffffff" then
|
356 |
|
|
flag_overflow <= '1';
|
357 |
|
|
state := 0;
|
358 |
|
|
else
|
359 |
|
|
state := 2;
|
360 |
|
|
end if;
|
361 |
|
|
when 2 => -- do the curl hash round without any copying needed
|
362 |
5 |
microengin |
if round = 1 then
|
363 |
7 |
microengin |
state := 3;
|
364 |
5 |
microengin |
end if;
|
365 |
4 |
microengin |
for I in 0 to STATE_LENGTH-1 loop
|
366 |
|
|
alpha(I) := curl_state_low(index_table(I));
|
367 |
|
|
beta(I) := curl_state_high(index_table(I));
|
368 |
|
|
gamma(I) := curl_state_high(index_table(I+1));
|
369 |
|
|
|
370 |
|
|
delta(I) := (alpha(I) or (not gamma(I))) and (curl_state_low(index_table(I+1)) xor beta(I));
|
371 |
|
|
|
372 |
|
|
curl_state_low(I) <= not delta(I);
|
373 |
|
|
curl_state_high(I) <= (alpha(I) xor gamma(I)) or delta(I);
|
374 |
|
|
end loop;
|
375 |
|
|
round := round - 1;
|
376 |
7 |
microengin |
when 3 => -- find out which solution - if any
|
377 |
5 |
microengin |
|
378 |
|
|
-- transform "vertical" trits to "horizontal" bits
|
379 |
|
|
-- and compare with min weight magnitude mask
|
380 |
4 |
microengin |
for I in 0 to PARALLEL-1 loop
|
381 |
|
|
for J in 0 to BITS_MIN_WEIGHT_MAGINUTE_MAX-1 loop
|
382 |
7 |
microengin |
tmp_weight_magnitude(I)(J) <= curl_state_low(HASH_LENGTH - 1 - J)(I) and curl_state_high(HASH_LENGTH - 1 - J)(I) and i_min_weight_magnitude(J);
|
383 |
4 |
microengin |
end loop;
|
384 |
7 |
microengin |
end loop;
|
385 |
|
|
|
386 |
|
|
-- pipelining
|
387 |
|
|
imask <= (others => '0');
|
388 |
|
|
for I in 0 to PARALLEL-1 loop
|
389 |
5 |
microengin |
if tmp_weight_magnitude(I) = i_min_weight_magnitude then
|
390 |
7 |
microengin |
imask(I) <= '1';
|
391 |
5 |
microengin |
end if;
|
392 |
4 |
microengin |
end loop;
|
393 |
7 |
microengin |
|
394 |
|
|
-- pipelining
|
395 |
|
|
if unsigned(imask) = 0 then
|
396 |
|
|
state :=1;
|
397 |
4 |
microengin |
else
|
398 |
7 |
microengin |
flag_found <= '1';
|
399 |
|
|
mask <= imask;
|
400 |
|
|
state :=0;
|
401 |
4 |
microengin |
end if;
|
402 |
|
|
when others =>
|
403 |
|
|
state := 0;
|
404 |
|
|
end case;
|
405 |
|
|
end if;
|
406 |
|
|
end if;
|
407 |
|
|
end process;
|
408 |
|
|
end behv;
|