OpenCores
URL https://opencores.org/ocsvn/iota_pow_vhdl/iota_pow_vhdl/trunk

Subversion Repositories iota_pow_vhdl

[/] [iota_pow_vhdl/] [trunk/] [vhdl_altera_de1/] [curl.vhd] - Blame information for rev 7

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 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 2 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 2 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 2 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 2 microengin
 
26
library ieee;
27 4 microengin
 
28 2 microengin
use ieee.std_logic_1164.all;
29
use ieee.numeric_std.all;
30
use work.index_table.all;
31 5 microengin
 
32 2 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 4 microengin
                PARALLEL : integer := 5;
40 2 microengin
                INTERN_NONCE_LENGTH : integer   := 32;
41 4 microengin
                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 2 microengin
        );
45
 
46
        port
47
        (
48
                clk : in std_logic;
49 4 microengin
                clk_slow : in std_logic;
50 2 microengin
                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
                overflow : out std_logic;
56
                running : out std_logic;
57
                found : out std_logic
58
        );
59
 
60
end curl;
61
 
62
architecture behv of curl is
63
 
64
subtype state_vector_type is std_logic_vector(PARALLEL-1 downto 0);
65 4 microengin
subtype mid_state_vector_type is std_logic_vector(DATA_WIDTH-1 downto 0);
66 5 microengin
subtype min_weight_magnitude_type is std_logic_vector(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
67 4 microengin
 
68 2 microengin
type curl_state_array is array(integer range <>) of state_vector_type;
69 4 microengin
type mid_state_array is array(integer range <>) of mid_state_vector_type;
70 5 microengin
type min_weight_magnitude_array is array(integer range<>) of min_weight_magnitude_type;
71 2 microengin
 
72
signal curl_state_low : curl_state_array(STATE_LENGTH-1 downto 0);
73
signal curl_state_high : curl_state_array(STATE_LENGTH-1 downto 0);
74
 
75 4 microengin
-- mid state data in 9bit packed format
76
signal curl_mid_state_low : mid_state_array((STATE_LENGTH/9)-1 downto 0);
77
signal curl_mid_state_high : mid_state_array((STATE_LENGTH/9)-1 downto 0);
78 2 microengin
 
79
signal flag_running : std_logic := '0';
80
signal flag_overflow : std_logic := '0';
81
signal flag_found : std_logic := '0';
82
signal flag_start : std_logic := '0';
83
 
84 4 microengin
signal binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
85
signal mask : state_vector_type;
86 5 microengin
signal min_weight_magnitude : min_weight_magnitude_type;
87 4 microengin
 
88 5 microengin
function expand(b : std_logic)
89
        return state_vector_type is
90 2 microengin
begin
91 5 microengin
        if b = '1' then
92
                return (others => '1');
93
        else
94
                return (others => '0');
95
        end if;
96
end expand;
97
 
98
begin
99 2 microengin
        overflow <= flag_overflow;
100
        running <= flag_running;
101
        found <= flag_found;
102 4 microengin
 
103
        process (clk_slow)
104
        -- because it looks prettier
105 2 microengin
                variable spi_cmd : std_logic_vector(5 downto 0);
106 5 microengin
                variable addrptr : unsigned(7 downto 0) := x"00";
107 2 microengin
        begin
108 4 microengin
                if rising_edge(clk_slow) then
109 2 microengin
                        if reset='1' then
110 4 microengin
                                min_weight_magnitude <= (others => '0');
111 2 microengin
                                flag_start <= '0';
112 5 microengin
                                spi_data_tx <= (others => '0');
113
--                              curl_mid_state_low <= (others => (others => '0'));
114
--                              curl_mid_state_high <= (others => (others => '0'));
115
                                addrptr := x"00";
116 2 microengin
                        else
117 4 microengin
                                flag_start <= '0';
118
-- new spi data received
119 2 microengin
                                if spi_data_rxen = '1' then
120
                                        spi_cmd := spi_data_rx(31 downto 26);
121
                                        case spi_cmd is
122 5 microengin
                                                when "000000" => -- nop (mainly for reading back data)
123 2 microengin
                                                when "100001" => -- start / stop
124 5 microengin
                                                        flag_start <= spi_data_rx(0);
125 4 microengin
                                                when "100101" =>        -- write to wr address
126 5 microengin
                                                        addrptr := unsigned(spi_data_rx(7 downto 0));
127 2 microengin
                                                when "100010" =>        -- write to mid state
128 5 microengin
                                                        if (addrptr <= (STATE_LENGTH/9)-1) then
129
                                                                curl_mid_state_low(to_integer(addrptr)) <= spi_data_rx(DATA_WIDTH-1 downto 0);
130
                                                                curl_mid_state_high(to_integer(addrptr)) <= spi_data_rx(DATA_WIDTH+8 downto DATA_WIDTH);
131
                                                        end if;
132
                                                        spi_data_tx <= spi_data_rx;
133
                                                        addrptr := addrptr + 1;
134 2 microengin
                                                when "100100" =>
135 4 microengin
                                                        min_weight_magnitude <= spi_data_rx(BITS_MIN_WEIGHT_MAGINUTE_MAX-1 downto 0);
136 2 microengin
 
137
                                                when "000001" =>        -- read flags
138 5 microengin
                                                        spi_data_tx(2 downto 0) <= flag_overflow & flag_found & flag_running;
139
 
140
-- for debugging onle ... read back curl_state
141 2 microengin
--                                              when "000010" =>
142
--                                                      spi_addr := spi_data_rx(25 downto 16);
143
--                                                      spi_data_tx(0+PARALLEL-1 downto 0) <= curl_state_low(to_integer(unsigned(spi_addr)));
144
--                                                      spi_data_tx(8+PARALLEL-1 downto 8) <= curl_state_high(to_integer(unsigned(spi_addr)));
145 5 microengin
 
146
-- for debugging only ... read back mid_state
147
--                                              when "000111" =>
148
--                                                      if (addrptr <= (STATE_LENGTH/9)-1) then
149
--                                                              spi_data_tx(DATA_WIDTH-1 downto 0) <= curl_mid_state_low(to_integer(addrptr));
150
--                                                              spi_data_tx(DATA_WIDTH+8 downto DATA_WIDTH) <= curl_mid_state_high(to_integer(addrptr));
151
--                                                      else
152
--                                                              spi_data_tx <= (others => '0');
153
--                                                      end if;
154
--                                                      addrptr := addrptr + 1; -- dual-used for debugging purposes 
155 2 microengin
                                                when "000011" => -- read nonce
156
                                                        spi_data_tx(INTERN_NONCE_LENGTH-1 downto 0) <= std_logic_vector(binary_nonce);
157
                                                when "000100" => -- read mask
158
                                                        spi_data_tx(PARALLEL-1 downto 0) <= mask;
159
                                                when "010101" => -- loop back read test inverted bits
160
                                                        spi_data_tx <= not spi_data_rx;
161 5 microengin
                                                when "000110" => -- read back parallel-level
162
                                                        spi_data_tx(3 downto 0) <= std_logic_vector(to_unsigned(PARALLEL, 4));
163 2 microengin
                                                when others =>
164
                                                        spi_data_tx <= (others => '1');
165 4 microengin
                                        end case;
166 2 microengin
                                end if;
167 4 microengin
                        end if;
168
                end if;
169
        end process;
170
 
171 5 microengin
 
172
 
173 4 microengin
        process (clk)
174
                variable        state : integer range 0 to 31 := 0;
175
                variable round : integer range 0 to 127 := 0;
176
 
177
                variable imask : state_vector_type;
178
 
179 5 microengin
                variable i_min_weight_magnitude : min_weight_magnitude_type;
180
                variable tmp_weight_magnitude : min_weight_magnitude_array(0 to PARALLEL-1);
181
                variable i_binary_nonce : unsigned(INTERN_NONCE_LENGTH-1 downto 0);
182 4 microengin
 
183
                -- temporary registers get optimized away
184
                variable alpha : curl_state_array(STATE_LENGTH-1 downto 0);
185
                variable beta : curl_state_array(STATE_LENGTH-1 downto 0);
186
                variable gamma : curl_state_array(STATE_LENGTH-1 downto 0);
187
                variable delta : curl_state_array(STATE_LENGTH-1 downto 0);
188
 
189
                variable tmp_index : integer range 0 to 1023;
190 5 microengin
                variable tmp_highest_bit : integer range 0 to 31;
191 4 microengin
        begin
192
                if rising_edge(clk) then
193
                        if reset='1' then
194
                                state := 0;
195 5 microengin
                                round := 0;
196 4 microengin
                                flag_found <= '0';
197
                                flag_running <= '0';
198
                                flag_overflow <= '0';
199
                                binary_nonce <= (others => '0');
200 5 microengin
                                mask <= (others => '0');
201
--                              curl_state_low <= (others => (others => '0'));
202
--                              curl_state_high <= (others => (others => '0'));
203
--                              tmp_weight_magnitude := (others => (others => '0'));
204
                                i_binary_nonce := (others => '0');
205
                                imask := (others => '0');
206
                                i_min_weight_magnitude := (others => '0');
207
                                alpha := (others => (others => '0'));
208
                                beta := (others => (others => '0'));
209
                                gamma := (others => (others => '0'));
210
                                delta := (others => (others => '0'));
211
                                tmp_index := 0;
212 4 microengin
                        else
213 2 microengin
                                case state is
214
                                        when 0 =>
215 5 microengin
                                                mask <= imask;
216
                                                binary_nonce <= i_binary_nonce;
217 2 microengin
                                                flag_running <= '0';
218
                                                if flag_start = '1' then
219 5 microengin
                                                        i_binary_nonce := x"00000000";
220 4 microengin
                                                        i_min_weight_magnitude := min_weight_magnitude;
221 2 microengin
                                                        state := 1;
222
                                                end if;
223
                                                -- nop until start from spi
224
                                        when 1 =>
225
                                                flag_found <= '0';
226
                                                flag_running <= '1';
227
                                                flag_overflow <= '0';
228
                                                state := 8;
229 4 microengin
                                        when 8 =>       -- copy mid state and insert nonce
230 2 microengin
 
231 4 microengin
                                                -- copy and fully expand mid-state to curl-state
232
                                                for I in 0 to (STATE_LENGTH/DATA_WIDTH)-1 loop
233
                                                        for J in 0 to DATA_WIDTH-1 loop
234
                                                                tmp_index := I*DATA_WIDTH+J;
235 5 microengin
                                                                if  tmp_index < NONCE_OFFSET or tmp_index > NONCE_OFFSET + NONCE_LENGTH - 1 then
236
                                                                        curl_state_low(tmp_index) <= expand(curl_mid_state_low(I)(J));
237
                                                                        curl_state_high(tmp_index) <= expand(curl_mid_state_high(I)(J));
238 4 microengin
                                                                end if;
239
                                                        end loop;
240
                                                end loop;
241
 
242 5 microengin
                                                -- fill all ... synthesizer is smart enough to optimize away what is not needed
243
                                                for I in NONCE_OFFSET to NONCE_OFFSET + NONCE_LENGTH - 1 loop
244
                                                        curl_state_low(I) <= expand('1');
245
                                                        curl_state_high(I) <= expand('1');
246
                                                end loop;
247
 
248
                                                -- calculate log2(x) by determining the place of highest set bit
249
                                                -- this is calculated on constants, so no logic needed
250
                                                tmp_highest_bit := 0;
251
                                                for I in 0 to 31 loop    -- 32 is enough ...^^
252
                                                        if to_unsigned(PARALLEL-1, 32)(I) = '1' then
253
                                                                tmp_highest_bit := I;
254
                                                        end if;
255
                                                end loop;
256
 
257
--                                              -- generate bitmuster in first trit-arrays of nonce depending on PARALLEL setting
258
                                                -- this is calculated on constants, so no logic needed
259
                                                for I in 0 to PARALLEL-1 loop
260
                                                        for J in 0 to tmp_highest_bit loop
261
                                                                curl_state_low(NONCE_OFFSET+J)(I) <= to_unsigned(I, tmp_highest_bit+1)(J);
262
                                                                curl_state_high(NONCE_OFFSET+J)(I) <= not to_unsigned(I, tmp_highest_bit+1)(J);
263 4 microengin
                                                        end loop;
264
                                                end loop;
265
 
266 5 microengin
                                                -- insert and convert binary nonce to ternary nonce
267
                                                -- It's a fake ternary nonce but integer-values are strictly monotonously rising 
268 4 microengin
                                                -- with integer values of binary nonce.
269
                                                -- Doesn't bring the exact same result like reference implementation with real
270 5 microengin
                                                -- ternary adder - but it doesn't matter and it is way faster.
271
                                                -- conveniently put nonce counter at the end of nonce
272
                                                for I in 0 to INTERN_NONCE_LENGTH-1 loop
273
                                                        curl_state_low(NONCE_OFFSET + NONCE_LENGTH - INTERN_NONCE_LENGTH + I) <= expand(i_binary_nonce(I));
274
                                                        curl_state_high(NONCE_OFFSET + NONCE_LENGTH - INTERN_NONCE_LENGTH + I) <= not expand(i_binary_nonce(I));
275 4 microengin
                                                end loop;
276
 
277
                                                -- initialize round-counter
278
                                                round := NUMBER_OF_ROUNDS;
279
 
280 2 microengin
                                                state := 10;
281 4 microengin
                                        when 10 =>      -- do the curl hash round without any copying needed
282 5 microengin
                                                if round = 1 then
283
                                                        state := 16;
284
                                                end if;
285 2 microengin
                                                for I in 0 to STATE_LENGTH-1 loop
286
                                                        alpha(I) := curl_state_low(index_table(I));
287
                                                        beta(I) := curl_state_high(index_table(I));
288
                                                        gamma(I) := curl_state_high(index_table(I+1));
289
 
290
                                                        delta(I) := (alpha(I) or (not gamma(I))) and (curl_state_low(index_table(I+1)) xor beta(I));
291
 
292
                                                        curl_state_low(I) <= not delta(I);
293
                                                        curl_state_high(I) <= (alpha(I) xor gamma(I)) or delta(I);
294
                                                end loop;
295
                                                round := round - 1;
296
                                        when 16 =>  -- find out which solution - if any
297 5 microengin
                                                imask := (others => '0');
298
 
299
                                                -- transform "vertical" trits to "horizontal" bits
300
                                                -- and compare with min weight magnitude mask
301 4 microengin
                                                for I in 0 to PARALLEL-1 loop
302 5 microengin
                                                        tmp_weight_magnitude(I) := (others => '0');
303 4 microengin
                                                        for J in 0 to BITS_MIN_WEIGHT_MAGINUTE_MAX-1 loop
304 5 microengin
                                                                tmp_weight_magnitude(I)(J) := curl_state_low(HASH_LENGTH - 1 - J)(I) and curl_state_high(HASH_LENGTH - 1 - J)(I);
305 4 microengin
                                                        end loop;
306 5 microengin
                                                        tmp_weight_magnitude(I) := tmp_weight_magnitude(I) and i_min_weight_magnitude; -- only consider used bits
307
                                                        if tmp_weight_magnitude(I) = i_min_weight_magnitude then
308
                                                                imask(I) := '1';
309
                                                        end if;
310 2 microengin
                                                end loop;
311 5 microengin
                                                state := 17;
312
                                        when 17 =>
313
                                                if unsigned(imask) /= 0 then
314
                                                        state := 30;
315
                                                elsif i_binary_nonce = x"ffffffff" then
316
                                                        state := 31;
317 2 microengin
                                                else
318 5 microengin
                                                        i_binary_nonce := i_binary_nonce + 1;
319
                                                        state := 8;
320 2 microengin
                                                end if;
321
                                        when 30 =>
322
                                                flag_found <= '1';
323
                                                state := 0;
324 5 microengin
                                        when 31 =>
325
                                                flag_overflow <= '1';
326
                                                state := 0;
327 2 microengin
                                        when others =>
328
                                                state := 0;
329
                                end case;
330
                        end if;
331
                end if;
332
        end process;
333
end behv;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.