Added equihash check for index ordering
This commit is contained in:
parent
39892b7732
commit
73c20415f8
|
@ -23,7 +23,8 @@ module axi_stream_fifo #(
|
|||
parameter SIZE,
|
||||
parameter DAT_BITS,
|
||||
parameter MOD_BITS = $clog2(DAT_BITS/8),
|
||||
parameter CTL_BITS
|
||||
parameter CTL_BITS,
|
||||
parameter USE_BRAM = 0 // If using BRAM there is an extra cycle delay between reads
|
||||
) (
|
||||
input i_clk, i_rst,
|
||||
if_axi_stream.sink i_axi,
|
||||
|
@ -33,26 +34,74 @@ module axi_stream_fifo #(
|
|||
);
|
||||
|
||||
logic [$clog2(SIZE)-1:0] rd_ptr, wr_ptr;
|
||||
localparam RAM_WIDTH = DAT_BITS + CTL_BITS + MOD_BITS + 3;
|
||||
logic [RAM_WIDTH-1:0] data_out;
|
||||
|
||||
logic [SIZE-1:0][DAT_BITS + CTL_BITS + MOD_BITS + 3 -1:0] ram;
|
||||
generate
|
||||
if (USE_BRAM == 0) begin: BRAM_GEN
|
||||
|
||||
logic [SIZE-1:0][DAT_BITS + CTL_BITS + MOD_BITS + 3 -1:0] ram;
|
||||
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_axi.val && i_axi.rdy) begin
|
||||
ram [wr_ptr] <= {i_axi.err, i_axi.eop, i_axi.sop, i_axi.mod, i_axi.ctl, i_axi.dat};
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
data_out = ram [rd_ptr];
|
||||
o_axi.val = ~o_emp;
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
if_ram #(.RAM_WIDTH(RAM_WIDTH), .RAM_DEPTH(SIZE)) bram_if_rd (i_clk, i_rst);
|
||||
if_ram #(.RAM_WIDTH(RAM_WIDTH), .RAM_DEPTH(SIZE)) bram_if_wr (i_clk, i_rst);
|
||||
|
||||
bram #(
|
||||
.RAM_WIDTH ( RAM_WIDTH ),
|
||||
.RAM_DEPTH ( SIZE ),
|
||||
.RAM_PERFORMANCE ( "LOW_LATENCY" )
|
||||
) bram_i (
|
||||
.a ( bram_if_rd ),
|
||||
.b ( bram_if_wr )
|
||||
);
|
||||
|
||||
always_ff @ (posedge i_clk) begin
|
||||
o_axi.val <= 0;
|
||||
if (~o_emp) o_axi.val <= 1;
|
||||
if (o_axi.val && o_axi.rdy) o_axi.val <= 0;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
bram_if_rd.re = 1;
|
||||
bram_if_rd.a = rd_ptr;
|
||||
bram_if_rd.d = 0;
|
||||
bram_if_rd.we = 0;
|
||||
bram_if_rd.en = 1;
|
||||
|
||||
bram_if_wr.re = 0;
|
||||
bram_if_wr.a = wr_ptr;
|
||||
bram_if_wr.d = {i_axi.err, i_axi.eop, i_axi.sop, i_axi.mod, i_axi.ctl, i_axi.dat};
|
||||
bram_if_wr.we = i_axi.val && i_axi.rdy;
|
||||
bram_if_wr.en = 1;
|
||||
|
||||
data_out = bram_if_rd.q;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Control for full and empty, and assigning outputs from the ram
|
||||
always_comb begin
|
||||
i_axi.rdy = ~o_full;
|
||||
o_axi.dat = ram[rd_ptr][0 +: DAT_BITS];
|
||||
o_axi.ctl = ram[rd_ptr][DAT_BITS +: CTL_BITS];
|
||||
o_axi.mod = ram[rd_ptr][CTL_BITS+DAT_BITS +: MOD_BITS];
|
||||
o_axi.sop = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS +: 1];
|
||||
o_axi.eop = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS+1 +: 1];
|
||||
o_axi.err = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS+2 +: 1];
|
||||
o_axi.val = ~o_emp;
|
||||
end
|
||||
|
||||
// Logic for writing and reading from ram without reset
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_axi.val && i_axi.rdy) begin
|
||||
ram [wr_ptr] <= {i_axi.err, i_axi.eop, i_axi.sop, i_axi.mod, i_axi.ctl, i_axi.dat};
|
||||
end
|
||||
o_axi.dat = data_out[0 +: DAT_BITS];
|
||||
o_axi.ctl = data_out[DAT_BITS +: CTL_BITS];
|
||||
o_axi.mod = data_out[CTL_BITS+DAT_BITS +: MOD_BITS];
|
||||
o_axi.sop = data_out[CTL_BITS+DAT_BITS+MOD_BITS +: 1];
|
||||
o_axi.eop = data_out[CTL_BITS+DAT_BITS+MOD_BITS+1 +: 1];
|
||||
o_axi.err = data_out[CTL_BITS+DAT_BITS+MOD_BITS+2 +: 1];
|
||||
|
||||
end
|
||||
|
||||
// Control logic which requires a reset
|
||||
|
|
|
@ -38,6 +38,7 @@ module hash_map #(
|
|||
output logic o_fnd, // Will be high if adding a key and it already exists (old data overwritten)
|
||||
// or for a lookup if key was found.
|
||||
|
||||
// Configuration (overrides other signals)
|
||||
// To clear memory
|
||||
input i_cfg_clr,
|
||||
// When linked list memory is full this will be high
|
||||
|
@ -162,9 +163,6 @@ always_ff @ (posedge i_clk) begin
|
|||
o_rdy <= 0;
|
||||
hash_state <= STATE_LOOPUP_COL;
|
||||
coll_ram_wait[0] <= 1;
|
||||
end else if (i_cfg_clr) begin
|
||||
o_rdy <= 0;
|
||||
hash_state <= STATE_RESET;
|
||||
end
|
||||
end
|
||||
STATE_LOOPUP_COL: begin
|
||||
|
@ -401,6 +399,12 @@ always_ff @ (posedge i_clk) begin
|
|||
end
|
||||
endcase
|
||||
|
||||
// Clear signal overrides others
|
||||
if (i_cfg_clr) begin
|
||||
o_rdy <= 0;
|
||||
hash_state <= STATE_RESET;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -432,7 +436,8 @@ axi_stream_fifo #(
|
|||
.SIZE ( LL_MEM_SIZE ),
|
||||
.DAT_BITS ( $clog2(LL_MEM_SIZE) ),
|
||||
.MOD_BITS ( 1 ),
|
||||
.CTL_BITS ( 1 )
|
||||
.CTL_BITS ( 1 ),
|
||||
.USE_BRAM ( 1 )
|
||||
)
|
||||
free_mem_fifo (
|
||||
.i_clk ( i_clk ),
|
||||
|
|
|
@ -16,6 +16,14 @@ module bram #(
|
|||
if_ram.sink b
|
||||
);
|
||||
|
||||
// Check RAM sizes match the interface
|
||||
initial begin
|
||||
assert ($bits(a.d) == RAM_WIDTH) else $fatal(1, "%m %t ERROR: bram RAM_WIDTH (%d) does not match interface a (%d)", $time, RAM_WIDTH, $bits(a.d));
|
||||
assert ($bits(a.a) == $clog2(RAM_DEPTH)) else $fatal(1, "%m %t ERROR: bram $clog2(RAM_DEPTH) (%d) does not match interface a (%d)", $time, $clog2(RAM_DEPTH), $bits(a.a));
|
||||
assert ($bits(b.d) == RAM_WIDTH) else $fatal(1, "%m %t ERROR: bram RAM_WIDTH (%d) does not match interface b (%d)", $time, RAM_WIDTH, $bits(b.d));
|
||||
assert ($bits(b.a) == $clog2(RAM_DEPTH)) else $fatal(1, "%m %t ERROR: bram $clog2(RAM_DEPTH) (%d) does not match interface b (%d)", $time, $clog2(RAM_DEPTH), $bits(b.a));
|
||||
end
|
||||
|
||||
xilinx_true_dual_port_no_change_2_clock_ram #(
|
||||
.RAM_WIDTH(RAM_WIDTH), // Specify RAM data width
|
||||
.RAM_DEPTH(RAM_DEPTH), // Specify RAM depth (number of entries)
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
This verifies that a input list stream has no duplicates.
|
||||
|
||||
Implemented using a hash table and FIFOs for flow control.
|
||||
|
||||
Input FIFO could be implemented with clock crossing to run at higher frequency.
|
||||
|
||||
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module dup_check # (
|
||||
parameter IN_BITS,
|
||||
parameter LIST_SIZE
|
||||
) (
|
||||
input i_clk, i_rst,
|
||||
|
||||
if_axi_stream.sink i_axi, // One index per clock cycle - start on .sop and finishes on .eop
|
||||
if_axi_stream.source o_axi // Will give a single clock cycle output with dat = 0 (no duplicates) or 1 (duplicates)
|
||||
);
|
||||
|
||||
logic hash_map_out_rdy, hash_map_out_val, hash_map_out_fnd, hash_map_clr, hash_map_full;
|
||||
logic sol_index_fifo_if_emp;
|
||||
if_axi_stream #(.DAT_BITS(IN_BITS), .CTL_BITS(1), .MOD_BITS(1)) sol_index_fifo_if_in(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(IN_BITS), .CTL_BITS(1), .MOD_BITS(1)) sol_index_fifo_if_out(i_clk);
|
||||
|
||||
logic eop_l, fnd_l;
|
||||
|
||||
enum {IDLE = 0,
|
||||
SEARCH = 1,
|
||||
CLEAR = 2} dup_check_state;
|
||||
|
||||
always_comb begin
|
||||
i_axi.rdy = (dup_check_state != CLEAR) && sol_index_fifo_if_in.rdy && ~eop_l;
|
||||
sol_index_fifo_if_out.rdy = hash_map_out_rdy;
|
||||
sol_index_fifo_if_in.dat = i_axi.dat;
|
||||
sol_index_fifo_if_in.eop = 0;
|
||||
sol_index_fifo_if_in.sop = 0;
|
||||
sol_index_fifo_if_in.err = 0;
|
||||
sol_index_fifo_if_in.ctl = 0;
|
||||
sol_index_fifo_if_in.mod = 0;
|
||||
sol_index_fifo_if_in.val = i_axi.val;
|
||||
end
|
||||
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
dup_check_state <= IDLE;
|
||||
hash_map_clr <= 0;
|
||||
eop_l <= 0;
|
||||
fnd_l <= 0;
|
||||
o_axi.reset_source();
|
||||
end else begin
|
||||
eop_l <= eop_l || (i_axi.val && i_axi.rdy && i_axi.eop);
|
||||
fnd_l <= fnd_l || (hash_map_out_val && hash_map_out_fnd);
|
||||
|
||||
o_axi.val <= 0;
|
||||
o_axi.err <= 0;
|
||||
o_axi.sop <= 1;
|
||||
o_axi.eop <= 1;
|
||||
hash_map_clr <= 0;
|
||||
|
||||
case (dup_check_state)
|
||||
IDLE: begin
|
||||
if (~sol_index_fifo_if_emp && hash_map_out_rdy) begin
|
||||
dup_check_state <= SEARCH;
|
||||
end
|
||||
end
|
||||
SEARCH: begin
|
||||
|
||||
if (sol_index_fifo_if_emp && eop_l && o_axi.rdy) begin
|
||||
dup_check_state <= CLEAR;
|
||||
o_axi.val <= 1;
|
||||
o_axi.dat <= fnd_l;
|
||||
hash_map_clr <= 1;
|
||||
end
|
||||
|
||||
end
|
||||
CLEAR: begin
|
||||
eop_l <= 0;
|
||||
fnd_l <= 0;
|
||||
if (hash_map_out_rdy)
|
||||
dup_check_state <= IDLE;
|
||||
end
|
||||
endcase
|
||||
|
||||
if (hash_map_full) begin
|
||||
o_axi.err <= 1;
|
||||
o_axi.val <= 1;
|
||||
hash_map_clr <= 1;
|
||||
dup_check_state <= CLEAR;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
axi_stream_fifo #(
|
||||
.SIZE ( LIST_SIZE ),
|
||||
.DAT_BITS ( IN_BITS ),
|
||||
.MOD_BITS ( 1 ),
|
||||
.CTL_BITS ( 1 ),
|
||||
.USE_BRAM ( 1 )
|
||||
)
|
||||
index_fifo (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
.i_axi ( sol_index_fifo_if_in ),
|
||||
.o_axi ( sol_index_fifo_if_out ),
|
||||
.o_full ( sol_index_fifo_if_full ),
|
||||
.o_emp ( sol_index_fifo_if_emp )
|
||||
);
|
||||
|
||||
// Hash table used to detect duplicate index, fed from FIFO
|
||||
// Could potentially be run at much higher clock
|
||||
hash_map #(
|
||||
.KEY_BITS ( IN_BITS ),
|
||||
.DAT_BITS ( 1 ),
|
||||
.HASH_MEM_SIZE ( 2*LIST_SIZE ),
|
||||
.LL_MEM_SIZE ( LIST_SIZE )
|
||||
)
|
||||
hash_map_i (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
.i_key ( sol_index_fifo_if_out.dat ),
|
||||
.i_val ( sol_index_fifo_if_out.val ),
|
||||
.i_dat ( 1'd1 ),
|
||||
.i_opcode ( 2'd1 ),
|
||||
.o_rdy ( hash_map_out_rdy ),
|
||||
.o_dat (),
|
||||
.o_val ( hash_map_out_val ),
|
||||
.o_fnd ( hash_map_out_fnd ),
|
||||
.i_cfg_clr ( hash_map_clr ),
|
||||
.o_cfg_full ( hash_map_full )
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -28,7 +28,8 @@
|
|||
module zcash_verif_equihash
|
||||
import zcash_verif_pkg::*;
|
||||
#(
|
||||
parameter DAT_BYTS = 8
|
||||
parameter DAT_BYTS = 8,
|
||||
parameter CHECK_UNIQUE_INDEX = 1
|
||||
)(
|
||||
input i_clk, i_rst,
|
||||
|
||||
|
@ -61,13 +62,18 @@ if_ram #(.RAM_WIDTH(EQUIHASH_SOL_BRAM_WIDTH), .RAM_DEPTH(EQUIHASH_SOL_BRAM_DEPTH
|
|||
|
||||
logic [DAT_BITS-1:0] equihash_sol_bram_if_b_l;
|
||||
logic [2*DAT_BITS-1:0] equihash_sol_bram_if_b_l_comb, equihash_sol_bram_if_b_l_comb_flip;
|
||||
logic [SOL_BITS-1:0] equihash_sol_index, hash_map_in_dat;
|
||||
logic [SOL_BITS-1:0] equihash_sol_index;
|
||||
logic [1:0] equihash_sol_bram_read;
|
||||
|
||||
logic hash_map_in_val, hash_map_out_rdy, hash_map_out_val, hash_map_out_fnd, hash_map_clr, hash_map_full;
|
||||
logic sol_index_fifo_if_emp;
|
||||
if_axi_stream #(.DAT_BITS(SOL_BITS), .CTL_BITS(1), .MOD_BITS(1)) sol_index_fifo_if_in(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(SOL_BITS), .CTL_BITS(1), .MOD_BITS(1)) sol_index_fifo_if_out(i_clk);
|
||||
logic dup_chk_done, order_chk_done;
|
||||
|
||||
if_axi_stream #(.DAT_BITS(SOL_BITS), .CTL_BITS(1), .MOD_BITS(1)) dup_check_if_in(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(1), .CTL_BITS(1), .MOD_BITS(1)) dup_check_if_out(i_clk);
|
||||
|
||||
if_axi_stream #(.DAT_BITS(SOL_BITS), .MOD_BITS(1), .CTL_BITS(1)) equihash_order_if(i_clk);
|
||||
logic equihash_order_val, equihash_order_wrong;
|
||||
|
||||
|
||||
|
||||
enum {STATE_WR_IDLE = 0,
|
||||
STATE_WR_DATA = 1,
|
||||
|
@ -106,7 +112,7 @@ always_ff @ (posedge i_clk) begin
|
|||
case (ram_wr_state)
|
||||
// This state we are waiting for an input block
|
||||
STATE_WR_IDLE: begin
|
||||
i_axi.rdy <= hash_map_out_rdy;
|
||||
i_axi.rdy <= (dup_check_if_in.rdy && equihash_order_if.rdy);
|
||||
if (i_axi.val && i_axi.rdy) begin
|
||||
ram_wr_state <= STATE_WR_DATA;
|
||||
equihash_sol_bram_if_a.a <= 0;
|
||||
|
@ -149,6 +155,9 @@ always_ff @ (posedge i_clk) begin
|
|||
equihash_sol_bram_if_b_l <= 0;
|
||||
equihash_gen_in <= 0;
|
||||
equihash_sol_bram_read <= 0;
|
||||
dup_check_if_in.reset_source();
|
||||
equihash_order_if.reset_source();
|
||||
|
||||
ram_rd_state <= STATE_RD_IDLE;
|
||||
end else begin
|
||||
// Defaults
|
||||
|
@ -157,6 +166,10 @@ always_ff @ (posedge i_clk) begin
|
|||
blake2b_in_hash.sop <= 1;
|
||||
blake2b_in_hash.eop <= 1;
|
||||
blake2b_in_hash.val <= 0;
|
||||
|
||||
dup_check_if_in.val <= 0;
|
||||
equihash_order_if.val <= 0;
|
||||
|
||||
equihash_sol_bram_read <= equihash_sol_bram_read << 1;
|
||||
if (equihash_sol_bram_read[0])
|
||||
equihash_sol_bram_if_b_l <= equihash_sol_bram_if_b.q;
|
||||
|
@ -192,6 +205,7 @@ always_ff @ (posedge i_clk) begin
|
|||
equihash_gen_in.index <= (equihash_sol_index)/INDICIES_PER_HASH;
|
||||
blake2b_in_hash.ctl <= (equihash_sol_index) % INDICIES_PER_HASH;
|
||||
|
||||
|
||||
// Stay 2 clocks behind the RAM write
|
||||
if ((equihash_sol_bram_if_a.a*DAT_BYTS + DAT_BYTS) >= (equihash_sol_bram_if_b.a + $bits(cblockheader_t)/DAT_BITS) ||
|
||||
ram_wr_state == STATE_WR_WAIT) begin
|
||||
|
@ -205,6 +219,16 @@ always_ff @ (posedge i_clk) begin
|
|||
blake2b_in_hash.val <= 1;
|
||||
sol_cnt_in <= sol_cnt_in + 1;
|
||||
|
||||
dup_check_if_in.val <= 1;
|
||||
dup_check_if_in.dat <= equihash_sol_index;
|
||||
dup_check_if_in.sop <= (sol_cnt_in == 0);
|
||||
dup_check_if_in.eop <= (sol_cnt_in == SOL_LIST_LEN - 1);
|
||||
|
||||
equihash_order_if.val <= 1;
|
||||
equihash_order_if.dat <= equihash_sol_index;
|
||||
equihash_order_if.sop <= (sol_cnt_in == 0);
|
||||
equihash_order_if.eop <= (sol_cnt_in == SOL_LIST_LEN - 1);
|
||||
|
||||
// If our input is about to shift we need to adjust pointer by DAT_BITS
|
||||
sol_pos <= sol_pos + SOL_BITS - (equihash_sol_bram_read[0] ? DAT_BITS : 0);
|
||||
if (sol_cnt_in == SOL_LIST_LEN - 1)
|
||||
|
@ -228,21 +252,34 @@ always_ff @ (posedge i_clk) begin
|
|||
blake2b_out_hash.rdy <= 0;
|
||||
sol_cnt_out <= 0;
|
||||
chk_state <= STATE_CHK_IDLE;
|
||||
hash_map_clr <= 0;
|
||||
dup_check_if_out.rdy <= 1;
|
||||
dup_chk_done <= 0;
|
||||
order_chk_done <= 0;
|
||||
end else begin
|
||||
// Defaults
|
||||
blake2b_out_hash.rdy <= 1;
|
||||
|
||||
hash_map_clr <= 0;
|
||||
sol_index_fifo_if_in.val <= blake2b_in_hash.val;
|
||||
sol_index_fifo_if_in.dat <= equihash_sol_index;
|
||||
// Monitor for result of duplicate check
|
||||
if (dup_check_if_out.val) begin
|
||||
if (dup_check_if_out.dat[0] || dup_check_if_out.err) begin
|
||||
o_mask.DUPLICATE_FND <= 1;
|
||||
end
|
||||
dup_chk_done <= 1;
|
||||
end
|
||||
|
||||
if ( (hash_map_out_val && hash_map_out_fnd) || hash_map_full )
|
||||
o_mask.DUPLICATE_FND <= 1;
|
||||
// Monitor for result of order check
|
||||
if (equihash_order_val) begin
|
||||
if (equihash_order_wrong) begin
|
||||
o_mask.BAD_IDX_ORDER <= 1;
|
||||
end
|
||||
order_chk_done <= 1;
|
||||
end
|
||||
|
||||
case(chk_state)
|
||||
STATE_CHK_IDLE: begin
|
||||
sol_cnt_out <= 0;
|
||||
dup_chk_done <= 0;
|
||||
order_chk_done <= 0;
|
||||
o_mask_val <= 0;
|
||||
o_mask <= 0;
|
||||
sol_hash_xor <= 0;
|
||||
|
@ -275,11 +312,11 @@ always_ff @ (posedge i_clk) begin
|
|||
|
||||
if (ram_rd_state == STATE_RD_WAIT &&
|
||||
ram_wr_state == STATE_WR_WAIT &&
|
||||
sol_index_fifo_if_emp ) begin
|
||||
dup_chk_done &&
|
||||
order_chk_done ) begin
|
||||
|
||||
o_mask_val <= 1;
|
||||
chk_state <= STATE_CHK_DONE;
|
||||
hash_map_clr <= 1;
|
||||
end
|
||||
end
|
||||
STATE_CHK_DONE: begin
|
||||
|
@ -310,10 +347,6 @@ always_comb begin
|
|||
for (int i = 0; i < SOL_BITS; i++)
|
||||
equihash_sol_index[i] = equihash_sol_bram_if_b_l_comb_flip[sol_pos + SOL_BITS-1-i];
|
||||
|
||||
// Hash map is fed directly from FIFO
|
||||
hash_map_in_val = sol_index_fifo_if_out.val;
|
||||
hash_map_in_dat = sol_index_fifo_if_out.dat;
|
||||
sol_index_fifo_if_out.rdy = hash_map_out_rdy;
|
||||
|
||||
end
|
||||
|
||||
|
@ -352,7 +385,7 @@ blake2b_pipe_top_i (
|
|||
.o_hash ( blake2b_out_hash )
|
||||
);
|
||||
|
||||
// Memory to store the equihash solution as it comes in. We use dual port,
|
||||
// Memory to store the compressed equihash solution as it comes in. We use dual port,
|
||||
// one port for writing and one port for reading
|
||||
bram #(
|
||||
.RAM_WIDTH ( EQUIHASH_SOL_BRAM_WIDTH ),
|
||||
|
@ -363,44 +396,39 @@ bram #(
|
|||
.b ( equihash_sol_bram_if_b )
|
||||
);
|
||||
|
||||
axi_stream_fifo #(
|
||||
.SIZE ( SOL_LIST_LEN ),
|
||||
.DAT_BITS ( SOL_BITS ),
|
||||
.MOD_BITS ( 1 ),
|
||||
.CTL_BITS ( 1 )
|
||||
)
|
||||
sol_index_fifo (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
.i_axi ( sol_index_fifo_if_in ),
|
||||
.o_axi ( sol_index_fifo_if_out ),
|
||||
.o_full (),
|
||||
.o_emp ( sol_index_fifo_if_emp )
|
||||
);
|
||||
|
||||
// Hash table used to detect duplicate index, fed from FIFO
|
||||
// Could potentially be run at much higher clock
|
||||
hash_map #(
|
||||
.KEY_BITS ( SOL_BITS ),
|
||||
.DAT_BITS ( 1 ),
|
||||
.HASH_MEM_SIZE ( 2*SOL_LIST_LEN ),
|
||||
.LL_MEM_SIZE ( SOL_LIST_LEN )
|
||||
)
|
||||
hash_map_i (
|
||||
zcash_verif_equihash_order
|
||||
equihash_order (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
.i_key ( hash_map_in_dat ),
|
||||
.i_val ( hash_map_in_val ),
|
||||
.i_dat ( 1'd1 ),
|
||||
.i_opcode ( 2'd1 ),
|
||||
.o_rdy ( hash_map_out_rdy ),
|
||||
.o_dat (),
|
||||
.o_val ( hash_map_out_val ),
|
||||
.o_fnd ( hash_map_out_fnd ),
|
||||
.i_cfg_clr ( hash_map_clr ),
|
||||
.o_cfg_full ( hash_map_full )
|
||||
|
||||
.i_axi ( equihash_order_if ),
|
||||
.o_order_wrong ( equihash_order_wrong ),
|
||||
.o_val ( equihash_order_val )
|
||||
);
|
||||
|
||||
generate
|
||||
if (CHECK_UNIQUE_INDEX == 1) begin: GEN_INDEX_CHECK
|
||||
dup_check #(
|
||||
.IN_BITS ( SOL_BITS ),
|
||||
.LIST_SIZE ( SOL_LIST_LEN )
|
||||
)
|
||||
dup_check(
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
|
||||
.i_axi ( dup_check_if_in ),
|
||||
.o_axi ( dup_check_if_out )
|
||||
);
|
||||
end else begin
|
||||
always_comb begin
|
||||
dup_check_if_in.rdy = 1;
|
||||
dup_check_if_out.val = 1;
|
||||
dup_check_if_out.eop = 1;
|
||||
dup_check_if_out.sop = 1;
|
||||
dup_check_if_out.dat = 0;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
// Some checks to make sure our data structures are correct:
|
||||
initial begin
|
||||
assert ($bits(equihash_gen_in_t)/8 == 144) else $fatal(1, "%m %t ERROR: equihash_gen_in_t is not 144 bytes in size", $time);
|
||||
|
|
|
@ -99,7 +99,7 @@ endtask
|
|||
|
||||
// Main testbench calls
|
||||
initial begin
|
||||
#200ns;
|
||||
#20us; // Let internal memories reset
|
||||
|
||||
test_block_346();
|
||||
|
||||
|
|
Loading…
Reference in New Issue