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 # (
parameter DAT_BYTS = 8,
parameter DAT_BYTS = 64,
parameter DAT_BITS = DAT_BYTS*8,
parameter CTL_BYTS = 1,
parameter CTL_BITS = CTL_BYTS*8,

View File

@ -18,7 +18,7 @@
*/
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
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 DAT_BITS,
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
) (
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(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
localparam EQUIHASH_SOL_BRAM_DEPTH = 1 + SOL_LIST_BYTS/DAT_BYTS;
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 [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(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)
// This state we are waiting for an input block
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
ram_wr_state <= STATE_WR_DATA;
equihash_sol_bram_if_a.a <= 0;
@ -254,6 +257,8 @@ always_ff @ (posedge i_clk) begin
dup_check_if_out.rdy <= 1;
dup_chk_done <= 0;
order_chk_done <= 0;
xor_check_done <= 0;
diff_chk_done <= 0;
end else begin
// Defaults
blake2b_out_hash.rdy <= 1;
@ -266,6 +271,12 @@ always_ff @ (posedge i_clk) begin
dup_chk_done <= 1;
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
if (equihash_order_val) begin
if (equihash_order_wrong) begin
@ -278,6 +289,7 @@ always_ff @ (posedge i_clk) begin
STATE_CHK_IDLE: begin
sol_cnt_out <= 0;
dup_chk_done <= 0;
diff_chk_done <= 0;
order_chk_done <= 0;
o_mask_val <= 0;
o_mask <= 0;
@ -308,11 +320,14 @@ always_ff @ (posedge i_clk) begin
end
STATE_CHK_WAIT: begin
o_mask.XOR_NON_ZERO <= |sol_hash_xor;
xor_check_done <= 1;
if (ram_rd_state == STATE_RD_WAIT &&
ram_wr_state == STATE_WR_WAIT &&
dup_chk_done &&
order_chk_done ) begin
order_chk_done &&
diff_chk_done &&
xor_check_done ) begin
o_mask_val <= 1;
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;
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
localparam [EQUIHASH_GEN_BYTS*8-1:0] EQUIHASH_GEN_BYTS_BM = {
{32-SOL_BITS-$clog2(INDICIES_PER_HASH){1'b0}},

View File

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

View File

@ -25,43 +25,44 @@ import common_pkg::*;
logic clk, rst;
equihash_bm_t mask;
logic mask_val;
logic start_241 = 0;
logic done_241;
logic start_241_error = 0;
logic done_241_error;
logic start_346 = 0;
logic done_346;
logic start_346_error = 0;
logic done_346_error;
parameter DAT_BYTS = 8;
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_241(clk);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_241_error(clk);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_346(clk);
if_axi_stream #(.DAT_BYTS(DAT_BYTS)) header_346_error(clk);
// Need one for each test so we can multiplex the input
always_comb begin
header_241.rdy = 0;
header_241_error.rdy = 0;
header_346.rdy = 0;
header_346_error.rdy = 0;
header.val = 0;
if (start_241) begin
header_241.rdy = header.rdy;
header.val = header_241.val;
header.sop = header_241.sop;
header.eop = header_241.eop;
header.ctl = header_241.ctl;
header.mod = header_241.mod;
header.err = header_241.err;
header.dat = header_241.dat;
if (start_346) begin
header_346.rdy = header.rdy;
header.val = header_346.val;
header.sop = header_346.sop;
header.eop = header_346.eop;
header.ctl = header_346.ctl;
header.mod = header_346.mod;
header.err = header_346.err;
header.dat = header_346.dat;
end
if (start_241_error) begin
header_241_error.rdy = header.rdy;
header.val = header_241_error.val;
header.sop = header_241_error.sop;
header.eop = header_241_error.eop;
header.ctl = header_241_error.ctl;
header.mod = header_241_error.mod;
header.err = header_241_error.err;
header.dat = header_241_error.dat;
if (start_346_error) begin
header_346_error.rdy = header.rdy;
header.val = header_346_error.val;
header.sop = header_346_error.sop;
header.eop = header_346_error.eop;
header.ctl = header_346_error.ctl;
header.mod = header_346_error.mod;
header.err = header_346_error.err;
header.dat = header_346_error.dat;
end
end
@ -81,13 +82,13 @@ file_to_axi #(
.DAT_BYTS ( DAT_BYTS ),
.FP ( 0 )
)
file_to_axi_block241 (
file_to_axi_block346 (
.i_file ({my_file_path_s, "/../data/block_346.bin"}),
.i_clk ( clk ),
.i_rst ( rst ),
.i_start ( start_241 ),
.o_done ( done_241 ),
.o_axi ( header_241 )
.i_start ( start_346 ),
.o_done ( done_346 ),
.o_axi ( header_346 )
);
file_to_axi #(
@ -95,13 +96,13 @@ file_to_axi #(
.DAT_BYTS ( DAT_BYTS ),
.FP ( 0 )
)
file_to_axi_block241_error (
file_to_axi_block346_error (
.i_file ({my_file_path_s, "/../data/block_346_errors.bin"}),
.i_clk ( clk ),
.i_rst ( rst ),
.i_start ( start_241_error ),
.o_done ( done_241_error ),
.o_axi ( header_241_error )
.i_start ( start_346_error ),
.o_done ( done_346_error ),
.o_axi ( header_346_error )
);
zcash_verif_equihash
@ -117,9 +118,9 @@ DUT (
task test_block_346();
begin
$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);
$display("test_block_346 PASSED");
@ -131,9 +132,9 @@ endtask
task test_block_346_error();
begin
$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);
$display("test_block_346_error PASSED");