Update for difficulty check

This commit is contained in:
bsdevlin 2019-02-28 18:32:48 -05:00
parent e8b6d4b19c
commit 2251338f1d
6 changed files with 158 additions and 83 deletions

View File

@ -20,7 +20,7 @@
*/ */
interface if_axi_stream # ( interface if_axi_stream # (
parameter DAT_BYTS = 8, parameter DAT_BYTS = 64,
parameter DAT_BITS = DAT_BYTS*8, parameter DAT_BITS = DAT_BYTS*8,
parameter CTL_BYTS = 1, parameter CTL_BYTS = 1,
parameter CTL_BITS = CTL_BYTS*8, parameter CTL_BITS = CTL_BYTS*8,

View File

@ -18,7 +18,7 @@
*/ */
package common_pkg; package common_pkg;
parameter MAX_SIM_BYTS = 1024; // In simulation tasks how big is the logic register for putting / getting data parameter MAX_SIM_BYTS = 2048; // In simulation tasks how big is the logic register for putting / getting data
// Compare bytes and print if they do not match // Compare bytes and print if they do not match
task compare_and_print(input logic [MAX_SIM_BYTS*8-1:0] data, expected); task compare_and_print(input logic [MAX_SIM_BYTS*8-1:0] data, expected);

View File

@ -23,7 +23,7 @@ module axi_stream_fifo #(
parameter SIZE, parameter SIZE,
parameter DAT_BITS, parameter DAT_BITS,
parameter MOD_BITS = $clog2(DAT_BITS/8), parameter MOD_BITS = $clog2(DAT_BITS/8),
parameter CTL_BITS, parameter CTL_BITS = 8,
parameter USE_BRAM = 0 // If using BRAM there is an extra cycle delay between reads parameter USE_BRAM = 0 // If using BRAM there is an extra cycle delay between reads
) ( ) (
input i_clk, i_rst, input i_clk, i_rst,

View File

@ -54,6 +54,8 @@ logic [64*8-1:0] parameters;
if_axi_stream #(.DAT_BYTS(BLAKE2B_DIGEST_BYTS), .CTL_BYTS($clog2(INDICIES_PER_HASH))) blake2b_out_hash(i_clk); if_axi_stream #(.DAT_BYTS(BLAKE2B_DIGEST_BYTS), .CTL_BYTS($clog2(INDICIES_PER_HASH))) blake2b_out_hash(i_clk);
if_axi_stream #(.DAT_BYTS(EQUIHASH_GEN_BYTS), .CTL_BYTS($clog2(INDICIES_PER_HASH))) blake2b_in_hash(i_clk); if_axi_stream #(.DAT_BYTS(EQUIHASH_GEN_BYTS), .CTL_BYTS($clog2(INDICIES_PER_HASH))) blake2b_in_hash(i_clk);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) difficulty_if_in(i_clk);
// We write the block into a port as it comes in and then read from the b port // We write the block into a port as it comes in and then read from the b port
localparam EQUIHASH_SOL_BRAM_DEPTH = 1 + SOL_LIST_BYTS/DAT_BYTS; localparam EQUIHASH_SOL_BRAM_DEPTH = 1 + SOL_LIST_BYTS/DAT_BYTS;
localparam EQUIHASH_SOL_BRAM_WIDTH = DAT_BITS; localparam EQUIHASH_SOL_BRAM_WIDTH = DAT_BITS;
@ -65,7 +67,8 @@ logic [2*DAT_BITS-1:0] equihash_sol_bram_if_b_l_comb, equihash_sol_bram_if_b_l_c
logic [SOL_BITS-1:0] equihash_sol_index; logic [SOL_BITS-1:0] equihash_sol_index;
logic [1:0] equihash_sol_bram_read; logic [1:0] equihash_sol_bram_read;
logic dup_chk_done, order_chk_done; logic dup_chk_done, order_chk_done, diff_chk_done, xor_check_done;
logic difficulty_fail, difficulty_fail_val;
if_axi_stream #(.DAT_BITS(SOL_BITS), .CTL_BITS(1), .MOD_BITS(1)) dup_check_if_in(i_clk); 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(1), .CTL_BITS(1), .MOD_BITS(1)) dup_check_if_out(i_clk);
@ -112,7 +115,7 @@ always_ff @ (posedge i_clk) begin
case (ram_wr_state) case (ram_wr_state)
// This state we are waiting for an input block // This state we are waiting for an input block
STATE_WR_IDLE: begin STATE_WR_IDLE: begin
i_axi.rdy <= (dup_check_if_in.rdy && equihash_order_if.rdy); i_axi.rdy <= (dup_check_if_in.rdy && equihash_order_if.rdy && difficulty_if_in.rdy);
if (i_axi.val && i_axi.rdy) begin if (i_axi.val && i_axi.rdy) begin
ram_wr_state <= STATE_WR_DATA; ram_wr_state <= STATE_WR_DATA;
equihash_sol_bram_if_a.a <= 0; equihash_sol_bram_if_a.a <= 0;
@ -254,6 +257,8 @@ always_ff @ (posedge i_clk) begin
dup_check_if_out.rdy <= 1; dup_check_if_out.rdy <= 1;
dup_chk_done <= 0; dup_chk_done <= 0;
order_chk_done <= 0; order_chk_done <= 0;
xor_check_done <= 0;
diff_chk_done <= 0;
end else begin end else begin
// Defaults // Defaults
blake2b_out_hash.rdy <= 1; blake2b_out_hash.rdy <= 1;
@ -266,6 +271,12 @@ always_ff @ (posedge i_clk) begin
dup_chk_done <= 1; dup_chk_done <= 1;
end end
// Monitor for output of difficulty check
if (difficulty_fail_val) begin
o_mask.DIFFICULTY_FAIL <= difficulty_fail;
diff_chk_done <= 1;
end
// Monitor for result of order check // Monitor for result of order check
if (equihash_order_val) begin if (equihash_order_val) begin
if (equihash_order_wrong) begin if (equihash_order_wrong) begin
@ -278,6 +289,7 @@ always_ff @ (posedge i_clk) begin
STATE_CHK_IDLE: begin STATE_CHK_IDLE: begin
sol_cnt_out <= 0; sol_cnt_out <= 0;
dup_chk_done <= 0; dup_chk_done <= 0;
diff_chk_done <= 0;
order_chk_done <= 0; order_chk_done <= 0;
o_mask_val <= 0; o_mask_val <= 0;
o_mask <= 0; o_mask <= 0;
@ -308,11 +320,14 @@ always_ff @ (posedge i_clk) begin
end end
STATE_CHK_WAIT: begin STATE_CHK_WAIT: begin
o_mask.XOR_NON_ZERO <= |sol_hash_xor; o_mask.XOR_NON_ZERO <= |sol_hash_xor;
xor_check_done <= 1;
if (ram_rd_state == STATE_RD_WAIT && if (ram_rd_state == STATE_RD_WAIT &&
ram_wr_state == STATE_WR_WAIT && ram_wr_state == STATE_WR_WAIT &&
dup_chk_done && dup_chk_done &&
order_chk_done ) begin order_chk_done &&
diff_chk_done &&
xor_check_done ) begin
o_mask_val <= 1; o_mask_val <= 1;
chk_state <= STATE_CHK_DONE; chk_state <= STATE_CHK_DONE;
@ -363,6 +378,30 @@ function bit bad_order_check(input logic [N-1:0] in, input int cnt);
return bad_order_check; return bad_order_check;
endfunction endfunction
// The difficulty check block - takes a copy of the header as it is streamed in
always_comb begin
difficulty_if_in.val = difficulty_if_in.rdy && i_axi.val && i_axi.rdy;
difficulty_if_in.dat = i_axi.dat;
difficulty_if_in.sop = i_axi.sop;
difficulty_if_in.eop = i_axi.eop;
difficulty_if_in.mod = i_axi.mod;
difficulty_if_in.err = 0;
difficulty_if_in.ctl = 0;
end
zcash_verif_equihash_difficulty #(
.DAT_BYTS ( DAT_BYTS )
)
zcash_verif_equihash_difficulty (
.i_clk ( i_clk ),
.i_rst ( i_rst ),
.i_axi ( difficulty_if_in ),
.i_bits ( cblockheader.bits ),
.o_difficulty_fail ( difficulty_fail ),
.o_val ( difficulty_fail_val )
);
// Instantiate the Blake2b block - use high performance pipelined version // Instantiate the Blake2b block - use high performance pipelined version
localparam [EQUIHASH_GEN_BYTS*8-1:0] EQUIHASH_GEN_BYTS_BM = { localparam [EQUIHASH_GEN_BYTS*8-1:0] EQUIHASH_GEN_BYTS_BM = {
{32-SOL_BITS-$clog2(INDICIES_PER_HASH){1'b0}}, {32-SOL_BITS-$clog2(INDICIES_PER_HASH){1'b0}},

View File

@ -26,24 +26,26 @@
module zcash_verif_equihash_difficulty module zcash_verif_equihash_difficulty
import zcash_verif_pkg::*; import zcash_verif_pkg::*;
#( #(
parameter DAT_BYTS = 8, parameter DAT_BYTS = 8
)( )(
input i_clk, i_rst, input i_clk, i_rst,
if_axi_stream.sink i_axi, if_axi_stream.sink i_axi,
input logic [31:0] i_difficulty, // Must be valid on .sop && .val input logic [31:0] i_bits,
output logic o_difficulty_fail, output logic o_difficulty_fail,
output logic o_val output logic o_val
); );
localparam HEADER_BYTS = $bits(cblockheader_sol_t)/8;
localparam DAT_BITS = DAT_BYTS*8;
logic [$clog2($bits(cblockheader_sol_t)/8)-1:0] byt_cnt; logic [$clog2($bits(cblockheader_sol_t)/8)-1:0] byt_cnt;
logic o_fifo_full, o_fifo_emp; logic o_fifo_full, o_fifo_emp, bits_err;
logic [31:0] difficulty; logic [255:0] nbits_converted;
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) o_fifo(clk); if_axi_stream #(.DAT_BYTS(DAT_BYTS)) o_fifo(i_clk);
if_axi_stream #(.DAT_BYTS(64)) i_block(clk); if_axi_stream #(.DAT_BYTS(64)) i_block(i_clk);
if_axi_stream #(.DAT_BYTS(32)) o_hash(clk); if_axi_stream #(.DAT_BYTS(32)) o_hash(i_clk);
enum {IDLE = 0, enum {IDLE = 0,
SHA256_0 = 1, SHA256_0 = 1,
@ -58,49 +60,61 @@ always_ff @ (posedge i_clk) begin
i_block.reset_source(); i_block.reset_source();
o_hash.rdy <= 0; o_hash.rdy <= 0;
o_fifo.rdy <= 0; o_fifo.rdy <= 0;
difficulty <= 0;
state <= IDLE; state <= IDLE;
nbits_converted <= 0;
bits_err <= 0;
end else begin end else begin
o_val <= 0; o_val <= 0;
o_hash.rdy <= 1; o_hash.rdy <= 1;
nbits_converted <= set_compact(i_bits);
bits_err <= check_err(i_bits);
case(state) case(state)
IDLE: begin IDLE: begin
i_block.reset_source(); i_block.reset_source();
o_fifo.rdy <= 0; o_fifo.rdy <= 0;
byt_cnt <= 0; byt_cnt <= 0;
if (i_axi.rdy && i_axi.val && i_axi.sop) begin if (i_axi.rdy && i_axi.val && i_axi.sop) begin
difficulty <= i_difficulty;
state <= SHA256_0; state <= SHA256_0;
o_fifo.rdy <= 1; o_fifo.rdy <= 1;
end end
end end
// Convert data to 512 bit wide // Convert data to 512 bit wide
// Takes around 26 passes as header is 1619 bytes
SHA256_0: begin SHA256_0: begin
o_fifo.rdy <= 0;
if (o_fifo.rdy && o_fifo.val) begin if (~i_block.val || (i_block.val && i_block.rdy)) begin
i_block.val <= 0; i_block.val <= 0;
byt_cnt <= byt_cnt + DAT_BYTS;
i_block.dat[byt_cnt +: DAT_BYTS] <= o_fifo.dat;
end
if (((byt_cnt + DAT_BYTS) % 64 == 0) ||
(byt_cnt + DAT_BYTS) == $bits(cblockheader_sol_t)/8) begin
i_block.val <= 1;
i_block.sop <= (byt_cnt + DAT_BYTS)/64 == 1;
i_block.eop <= 0;
i_block.mod <= (byt_cnt + DAT_BYTS);
o_fifo.rdy <= i_block.rdy;
if ((byt_cnt + DAT_BYTS) == $bits(cblockheader_sol_t)/8) begin
i_block.eop <= 1;
state <= SHA256_1;
end
end else begin
o_fifo.rdy <= 1; o_fifo.rdy <= 1;
if (i_block.val && i_block.rdy)
i_block.dat <= 0;
if (o_fifo.rdy && o_fifo.val) begin
byt_cnt <= byt_cnt + DAT_BYTS;
i_block.dat[(byt_cnt % 64) *8 +: DAT_BITS] <= o_fifo.dat;
if (((byt_cnt + DAT_BYTS) % 64 == 0) ||
(byt_cnt + DAT_BYTS) >= $bits(cblockheader_sol_t)/8) begin
i_block.val <= 1;
o_fifo.rdy <= 0;
i_block.sop <= (byt_cnt + DAT_BYTS)/64 == 1;
i_block.eop <= 0;
i_block.mod <= 0;
if ((byt_cnt + DAT_BYTS) >= $bits(cblockheader_sol_t)/8) begin
i_block.eop <= 1;
i_block.mod <= $bits(cblockheader_sol_t)/8;
state <= SHA256_1;
end
end
end
end end
end end
// Only single pass
SHA256_1: begin SHA256_1: begin
o_fifo.rdy <= 1; // We might have data we don't care about (transactions)
if (i_block.val && i_block.rdy) begin if (i_block.val && i_block.rdy) begin
i_block.val <= 0; i_block.val <= 0;
end end
@ -112,19 +126,20 @@ always_ff @ (posedge i_clk) begin
i_block.eop <= 1; i_block.eop <= 1;
i_block.mod <= 32; i_block.mod <= 32;
state <= FINISHED; state <= FINISHED;
end end
end end
FINISHED: begin FINISHED: begin
o_fifo.rdy <= 1; // We might have data we don't care about (transactions)
if (i_block.val && i_block.rdy) begin if (i_block.val && i_block.rdy) begin
i_block.val <= 0; i_block.val <= 0;
end end
if (o_hash.val && o_hash.rdy) begin if (o_hash.val && o_hash.rdy) begin
o_difficulty_fail <= check_difficulty(o_hash.dat, difficulty); o_difficulty_fail <= bits_err || (o_hash.dat > nbits_converted);
o_val <= 1; o_val <= 1;
state <= IDLE; state <= IDLE;
end end
end end
endcase endcase
@ -143,18 +158,38 @@ end
// Function to check if difficulty passes - bits is the number of 0s we // Function to check if difficulty passes - bits is the number of 0s we
// need // need
// TODO target function function [255:0] set_compact(input logic [31:0] ncompact);
function check_difficulty(input logic [255:0] hash, logic [31:0] bits); logic [31:0] nsize, nword;
check_difficulty = 0; nsize = ncompact >> 24;
for (int i = 0; i < 64; i++) nword = ncompact;
if (i > bits && hash[(64-1-i)*8 +: 8] != 0)
check_difficulty = 1; if (nsize <= 3) begin
set_compact = nword >> 8 * (3 - nsize);
end else begin
set_compact = nword << 8 * (nsize - 3);
end
endfunction endfunction
function check_err(input logic [31:0] ncompact);
logic [31:0] nsize, nword;
nsize = ncompact >> 24;
nword = ncompact;
check_err = 0;
// For sanity checking we set o_err and fail the check
if (ncompact == 0 ||
(nword != 0 && ncompact[3*8]) ||
(nword != 0 && (nsize > 34 || (nword > 8'hff && nsize > 33) || (nword > 16'hffff && nsize > 32)))) begin
check_err = 1;
end
endfunction
// FIFO for storing input stream // FIFO for storing input stream
axi_stream_fifo #( axi_stream_fifo #(
.SIZE ( ($bits(cblockheader_sol_t)/8)/DAT_BYTS ), .SIZE ( ($bits(cblockheader_sol_t)/8)/DAT_BYTS ),
.DAT_BITS ( DAT_BYTS/8 ), .DAT_BITS ( DAT_BYTS*8 ),
.USE_BRAM ( 1 ) .USE_BRAM ( 1 )
) )
axi_stream_fifo ( axi_stream_fifo (
@ -169,7 +204,7 @@ axi_stream_fifo (
// SHA256 block // SHA256 block
sha256_top sha256_top ( sha256_top sha256_top (
.i_clk ( i_clk ), .i_clk ( i_clk ),
.i_rst ( i_rst ), .i_rst ( i_rst ),
.i_block ( i_block ), .i_block ( i_block ),
.o_hash ( o_hash ) .o_hash ( o_hash )
); );

View File

@ -25,43 +25,44 @@ import common_pkg::*;
logic clk, rst; logic clk, rst;
equihash_bm_t mask; equihash_bm_t mask;
logic mask_val; logic mask_val;
logic start_241 = 0; logic start_346 = 0;
logic done_241; logic done_346;
logic start_241_error = 0; logic start_346_error = 0;
logic done_241_error; logic done_346_error;
parameter DAT_BYTS = 8; parameter DAT_BYTS = 8;
string my_file_path_s = get_file_dir(`__FILE__); string my_file_path_s = get_file_dir(`__FILE__);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header(clk); if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header(clk);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_241(clk); if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_346(clk);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_241_error(clk); if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_346_error(clk);
// Need one for each test so we can multiplex the input // Need one for each test so we can multiplex the input
always_comb begin always_comb begin
header_241.rdy = 0; header_346.rdy = 0;
header_241_error.rdy = 0; header_346_error.rdy = 0;
header.val = 0;
if (start_241) begin if (start_346) begin
header_241.rdy = header.rdy; header_346.rdy = header.rdy;
header.val = header_241.val; header.val = header_346.val;
header.sop = header_241.sop; header.sop = header_346.sop;
header.eop = header_241.eop; header.eop = header_346.eop;
header.ctl = header_241.ctl; header.ctl = header_346.ctl;
header.mod = header_241.mod; header.mod = header_346.mod;
header.err = header_241.err; header.err = header_346.err;
header.dat = header_241.dat; header.dat = header_346.dat;
end end
if (start_241_error) begin if (start_346_error) begin
header_241_error.rdy = header.rdy; header_346_error.rdy = header.rdy;
header.val = header_241_error.val; header.val = header_346_error.val;
header.sop = header_241_error.sop; header.sop = header_346_error.sop;
header.eop = header_241_error.eop; header.eop = header_346_error.eop;
header.ctl = header_241_error.ctl; header.ctl = header_346_error.ctl;
header.mod = header_241_error.mod; header.mod = header_346_error.mod;
header.err = header_241_error.err; header.err = header_346_error.err;
header.dat = header_241_error.dat; header.dat = header_346_error.dat;
end end
end end
@ -81,13 +82,13 @@ file_to_axi #(
.DAT_BYTS ( DAT_BYTS ), .DAT_BYTS ( DAT_BYTS ),
.FP ( 0 ) .FP ( 0 )
) )
file_to_axi_block241 ( file_to_axi_block346 (
.i_file ({my_file_path_s, "/../data/block_346.bin"}), .i_file ({my_file_path_s, "/../data/block_346.bin"}),
.i_clk ( clk ), .i_clk ( clk ),
.i_rst ( rst ), .i_rst ( rst ),
.i_start ( start_241 ), .i_start ( start_346 ),
.o_done ( done_241 ), .o_done ( done_346 ),
.o_axi ( header_241 ) .o_axi ( header_346 )
); );
file_to_axi #( file_to_axi #(
@ -95,13 +96,13 @@ file_to_axi #(
.DAT_BYTS ( DAT_BYTS ), .DAT_BYTS ( DAT_BYTS ),
.FP ( 0 ) .FP ( 0 )
) )
file_to_axi_block241_error ( file_to_axi_block346_error (
.i_file ({my_file_path_s, "/../data/block_346_errors.bin"}), .i_file ({my_file_path_s, "/../data/block_346_errors.bin"}),
.i_clk ( clk ), .i_clk ( clk ),
.i_rst ( rst ), .i_rst ( rst ),
.i_start ( start_241_error ), .i_start ( start_346_error ),
.o_done ( done_241_error ), .o_done ( done_346_error ),
.o_axi ( header_241_error ) .o_axi ( header_346_error )
); );
zcash_verif_equihash zcash_verif_equihash
@ -117,9 +118,9 @@ DUT (
task test_block_346(); task test_block_346();
begin begin
$display("Running test_block_346..."); $display("Running test_block_346...");
start_241 = 1; start_346 = 1;
while(!done_241 || !mask_val) @(posedge clk); while(!done_346 || !mask_val) @(posedge clk);
assert (~(|mask)) else $fatal(1, "%m %t ERROR: test_block_346 mask was non-zero:\n%p", $time, mask); assert (~(|mask)) else $fatal(1, "%m %t ERROR: test_block_346 mask was non-zero:\n%p", $time, mask);
$display("test_block_346 PASSED"); $display("test_block_346 PASSED");
@ -131,9 +132,9 @@ endtask
task test_block_346_error(); task test_block_346_error();
begin begin
$display("Running test_block_346_error..."); $display("Running test_block_346_error...");
start_241_error = 1; start_346_error = 1;
while(!done_241_error || !mask_val) @(posedge clk); while(!done_346_error || !mask_val) @(posedge clk);
assert (&mask) else $fatal(1, "%m %t ERROR: test_block_346_error mask was zero but should of failed:\n%p", $time, mask); assert (&mask) else $fatal(1, "%m %t ERROR: test_block_346_error mask was zero but should of failed:\n%p", $time, mask);
$display("test_block_346_error PASSED"); $display("test_block_346_error PASSED");