Updates to verfi module

This commit is contained in:
bsdevlin 2019-02-21 06:44:42 -05:00
parent c8f1c9223f
commit 8b853a7159
3 changed files with 151 additions and 109 deletions

View File

@ -15,27 +15,6 @@
# run results please launch the synthesis/implementation runs as needed. # run results please launch the synthesis/implementation runs as needed.
# #
#***************************************************************************************** #*****************************************************************************************
# NOTE: In order to use this script for source control purposes, please make sure that the
# following files are added to the source control system:-
#
# 1. This project restoration tcl script (create_project.tcl) that was generated.
#
# 2. The following source(s) files that were local or imported into the original project.
# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script)
#
# <none>
#
# 3. The following remote source files that were added to the original project:-
#
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/rtl/blake2b_g.sv"
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/rtl/blake2b_pkg.sv"
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/common/src/rtl/common_pkg.sv"
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/common/src/rtl/common_if.sv"
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/rtl/blake2b_top.sv"
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/synth/blake2b_top.xdc"
# "C:/Users/bsdevlin/git/zcash-fpga/ip_cores/blake2b/src/tb/blake2b_top_tb.sv"
#
#*****************************************************************************************
# Set the reference directory for source file relative paths (by default the value is script directory path) # Set the reference directory for source file relative paths (by default the value is script directory path)
set script_path [ file dirname [ file normalize [ info script ] ] ] set script_path [ file dirname [ file normalize [ info script ] ] ]
@ -148,8 +127,6 @@ set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "file_type" -value "SystemVerilog" -objects $file_obj set_property -name "file_type" -value "SystemVerilog" -objects $file_obj
# Set 'sources_1' fileset file properties for local files
# None
# Set 'sources_1' fileset properties # Set 'sources_1' fileset properties
set obj [get_filesets sources_1] set obj [get_filesets sources_1]

View File

@ -6,6 +6,9 @@
3. No duplicates 3. No duplicates
4. Difficulty passes 4. Difficulty passes
Code is split up into 3 main always blocks, one for loading RAM, one for parsing
output and loading the Blake2b block, and the final for running checks.
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -45,11 +48,9 @@ equihash_gen_in_t equihash_gen_in;
logic [N-1:0] sol_hash_xor; logic [N-1:0] sol_hash_xor;
logic [$clog2(SOL_LIST_LEN)-1:0] sol_cnt_out, sol_cnt_in; // This tracks how many solutions we have XORed logic [$clog2(SOL_LIST_LEN)-1:0] sol_cnt_out, sol_cnt_in; // This tracks how many solutions we have XORed
logic [$clog2(DAT_BITS)-1:0] sol_pos; // This tracks the pos in our DAT_BITS RAM output logic [$clog2(DAT_BITS)-1:0] sol_pos; // This tracks the pos in our DAT_BITS RAM output
logic [SOL_BITS-1:0] ram_out;
logic [64*8-1:0] parameters; logic [64*8-1:0] parameters;
logic [7:0] byte_len; logic [7:0] byte_len;
logic all_checks_done; logic [DAT_BITS-1:0] sol_ram_byte_bit_flip;
@ -60,10 +61,19 @@ if_axi_stream #(.DAT_BYTS(EQUIHASH_GEN_BYTS)) blake2b_in_hash(i_clk);
if_ram #(.RAM_WIDTH(DAT_BITS), .RAM_DEPTH(SOL_LIST_BYTS/DAT_BYTS)) equihash_sol_bram_if_a (i_clk, i_rst); if_ram #(.RAM_WIDTH(DAT_BITS), .RAM_DEPTH(SOL_LIST_BYTS/DAT_BYTS)) equihash_sol_bram_if_a (i_clk, i_rst);
if_ram #(.RAM_WIDTH(DAT_BITS), .RAM_DEPTH(SOL_LIST_BYTS/DAT_BYTS)) equihash_sol_bram_if_b (i_clk, i_rst); if_ram #(.RAM_WIDTH(DAT_BITS), .RAM_DEPTH(SOL_LIST_BYTS/DAT_BYTS)) equihash_sol_bram_if_b (i_clk, i_rst);
logic [DAT_BITS-1:0] equihash_sol_bram_if_b_l; logic [DAT_BITS-1:0] equihash_sol_bram_if_b_l;
logic [1:0] equihash_sol_bram_read;
enum {STATE_IDLE = 0, enum {STATE_WR_IDLE = 0,
STATE_DATA_WRITE = 1, STATE_WR_DATA = 1,
STATE_FINISH_WAIT = 2} ram_state; STATE_WR_WAIT = 2} ram_wr_state;
enum {STATE_RD_IDLE = 0,
STATE_RD_DATA = 1,
STATE_RD_WAIT = 2} ram_rd_state;
enum {STATE_CHK_IDLE = 0,
STATE_CHK_DATA = 1,
STATE_CHK_WAIT = 2} chk_state;
// State machine for controlling writing equihash solution into the RAM and registering the header // State machine for controlling writing equihash solution into the RAM and registering the header
always_ff @ (posedge i_clk) begin always_ff @ (posedge i_clk) begin
@ -73,7 +83,7 @@ always_ff @ (posedge i_clk) begin
cblockheader <= 0; cblockheader <= 0;
cblockheader_byts <= 0; cblockheader_byts <= 0;
cblockheader_val <= 0; cblockheader_val <= 0;
ram_state <= STATE_IDLE; ram_wr_state <= STATE_WR_IDLE;
end else begin end else begin
// Defaults // Defaults
equihash_sol_bram_if_a.we <= 1; equihash_sol_bram_if_a.we <= 1;
@ -86,31 +96,31 @@ always_ff @ (posedge i_clk) begin
cblockheader_byts <= cblockheader_byts + DAT_BYTS; cblockheader_byts <= cblockheader_byts + DAT_BYTS;
end end
case (ram_state) case (ram_wr_state)
// This state we are waiting for an input block // This state we are waiting for an input block
STATE_IDLE: begin STATE_WR_IDLE: begin
i_axi.rdy <= 1; i_axi.rdy <= 1;
if (i_axi.val && i_axi.rdy) begin if (i_axi.val && i_axi.rdy) begin
ram_state <= STATE_DATA_WRITE; ram_wr_state <= STATE_WR_DATA;
equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a + 1; equihash_sol_bram_if_a.a <= 0;
end end
end end
// Here we are checking header values as well as populating the RAM // Here we are checking header values as well as populating the RAM
STATE_DATA_WRITE: begin STATE_WR_DATA: begin
if (i_axi.val && i_axi.rdy) begin if (i_axi.val && i_axi.rdy) begin
equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a + 1; equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a + 1;
if (i_axi.eop) begin if (i_axi.eop) begin
i_axi.rdy <= 0; i_axi.rdy <= 0;
ram_state <= STATE_FINISH_WAIT; ram_wr_state <= STATE_WR_WAIT;
end end
end end
end end
// Here we are have finished populating RAM and waiting for all checks to finish // Here we are have finished populating RAM and waiting for all checks to finish
STATE_FINISH_WAIT: begin STATE_WR_WAIT: begin
equihash_sol_bram_if_a.we <= 0; equihash_sol_bram_if_a.we <= 0;
equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a; equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a;
if (all_checks_done) begin if (chk_state == STATE_CHK_WAIT) begin
ram_state <= STATE_IDLE; ram_wr_state <= STATE_WR_IDLE;
i_axi.rdy <= 1; i_axi.rdy <= 1;
cblockheader_val <= 0; cblockheader_val <= 0;
equihash_sol_bram_if_a.a <= 0; equihash_sol_bram_if_a.a <= 0;
@ -120,99 +130,154 @@ always_ff @ (posedge i_clk) begin
end end
end end
// State machine for controlling the hash calculation // State machine for loading the output of RAM into the Blake2b block
// and checking the header values always_ff @ (posedge i_clk) begin
if (i_rst) begin
blake2b_in_hash.reset_source();
equihash_sol_bram_if_b.reset_source();
sol_cnt_in <= 0;
sol_pos <= 0;
equihash_sol_bram_if_b_l <= 0;
equihash_gen_in <= 0;
equihash_sol_bram_read <= 0;
ram_rd_state <= STATE_RD_IDLE;
end else begin
// Defaults
equihash_sol_bram_if_b.re <= 1;
equihash_sol_bram_if_b.en <= 1;
blake2b_in_hash.sop <= 1;
blake2b_in_hash.eop <= 1;
blake2b_in_hash.val <= 0;
equihash_sol_bram_read <= equihash_sol_bram_read << 1;
case(ram_rd_state)
STATE_RD_IDLE: begin
if (~|equihash_sol_bram_read)
equihash_sol_bram_if_b.a <= $bits(cblockheader_t)/DAT_BITS;
sol_pos <= 3*8 + ($bits(cblockheader_t) % DAT_BITS); // Add on 3*8 as this encodes the size of solution
sol_cnt_in <= 0;
blake2b_in_hash.val <= 0;
//First case has special state
if (equihash_sol_bram_if_a.a >= ($bits(cblockheader_t)/8) + (DAT_BYTS*2)) begin
if (~|equihash_sol_bram_read) begin
equihash_sol_bram_if_b_l <= sol_ram_byte_bit_flip;// equihash_sol_bram_if_b.q;
equihash_sol_bram_if_b.a <= equihash_sol_bram_if_b.a + 1;
equihash_sol_bram_read[0] <= 1;
end
if (equihash_sol_bram_read[1])
ram_rd_state <= STATE_RD_DATA;
end
end
STATE_RD_DATA: begin
equihash_gen_in <= 0;
equihash_gen_in.bits <= cblockheader.bits;
equihash_gen_in.my_time <= cblockheader.my_time;
equihash_gen_in.hash_merkle_root <= cblockheader.hash_merkle_root;
equihash_gen_in.hash_prev_block <= cblockheader.hash_prev_block;
equihash_gen_in.version <= cblockheader.version;
equihash_gen_in.nonce <= cblockheader.nonce;
// Load the solution, need to flip it
for (int i = 0; i < SOL_BITS; i++)
if ((sol_pos + SOL_BITS) >= DAT_BITS && (i + sol_pos < DAT_BITS))
equihash_gen_in.index[SOL_BITS-1-i] <= equihash_sol_bram_if_b_l[i + sol_pos];
else
equihash_gen_in.index[SOL_BITS-1-i] <= /*equihash_sol_bram_if_b.q*/sol_ram_byte_bit_flip[(i+sol_pos) % DAT_BITS];
// 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
// Check if we need to load next memory address
if (sol_pos + 2*SOL_BITS >= DAT_BITS && ~|equihash_sol_bram_read) begin
equihash_sol_bram_if_b_l <= sol_ram_byte_bit_flip;
equihash_sol_bram_if_b.a <= equihash_sol_bram_if_b.a + 1;
equihash_sol_bram_read[0] <= 1;
end
// Load input into Blake2b block
blake2b_in_hash.val <= 1;
sol_cnt_in <= sol_cnt_in + 1;
sol_pos <= sol_pos + SOL_BITS;
if (sol_cnt_in == SOL_LIST_LEN - 2)
ram_rd_state <= STATE_RD_WAIT;
end
end
STATE_RD_WAIT: begin
if (chk_state == STATE_CHK_WAIT) begin
ram_rd_state <= STATE_RD_IDLE;
end
end
endcase
end
end
always_ff @ (posedge i_clk) begin always_ff @ (posedge i_clk) begin
if (i_rst) begin if (i_rst) begin
o_mask_val <= 0; o_mask_val <= 0;
o_mask <= 0; o_mask <= 0;
sol_hash_xor <= 0; sol_hash_xor <= 0;
blake2b_in_hash.reset_source();
blake2b_out_hash.rdy <= 0; blake2b_out_hash.rdy <= 0;
equihash_sol_bram_if_b.reset_source();
all_checks_done <= 0;
sol_cnt_in <= 0;
sol_cnt_out <= 0; sol_cnt_out <= 0;
sol_pos <= 0; chk_state <= STATE_CHK_IDLE;
equihash_sol_bram_if_b_l <= 0;
end else begin end else begin
// Defaults // Defaults
equihash_sol_bram_if_b.re <= 1;
equihash_sol_bram_if_b.en <= 1;
blake2b_out_hash.rdy <= 1; blake2b_out_hash.rdy <= 1;
blake2b_in_hash.sop <= 1;
blake2b_in_hash.eop <= 1;
blake2b_in_hash.val <= 0;
if (ram_state == STATE_IDLE) begin case(chk_state)
equihash_sol_bram_if_b.a <= $bits(cblockheader_t)/DAT_BITS; STATE_CHK_IDLE: begin
sol_pos <= $bits(cblockheader_t) % DAT_BITS;
sol_cnt_out <= 0; sol_cnt_out <= 0;
sol_cnt_in <= 0;
blake2b_in_hash.val <= 0;
o_mask_val <= 0; o_mask_val <= 0;
o_mask <= 0; o_mask <= 0;
sol_hash_xor <= 0;
if (ram_rd_state == STATE_RD_DATA)
chk_state <= STATE_CHK_DATA;
end end
STATE_CHK_DATA: begin
if (cblockheader_val) begin
equihash_gen_in.bits <= cblockheader.bits;
equihash_gen_in.my_time <= cblockheader.my_time;
equihash_gen_in.hash_reserved <= 0;
equihash_gen_in.hash_merkle_root <= cblockheader.hash_merkle_root;
equihash_gen_in.hash_prev_block <= cblockheader.hash_prev_block;
equihash_gen_in.version <= cblockheader.version;
equihash_gen_in.nonce <= cblockheader.nonce;
for (int i = 0; i < SOL_BITS; i++)
if (i + sol_pos >= DAT_BITS)
equihash_gen_in.index[i] <= equihash_sol_bram_if_b_l[i + sol_pos - DAT_BITS];
else
equihash_gen_in.index[i] <= equihash_sol_bram_if_b.q[i+sol_pos];
end
// We can start loading the hash block
if((sol_cnt_in < SOL_LIST_LEN - 1) &&
blake2b_in_hash.rdy &&
(equihash_sol_bram_if_a.a >= $bits(cblockheader_t)/8 + DAT_BYTS)) begin
blake2b_in_hash.val <= 1; // TODO control if we take more than one hash per clock
sol_cnt_in <= sol_cnt_in + 1;
sol_pos <= sol_pos + SOL_BITS;
// Calculate if we should increase our read pointer
if (sol_pos + 2*SOL_BITS >= DAT_BITS) begin
equihash_sol_bram_if_b_l <= equihash_sol_bram_if_b.q; // Latch current output as we might need some bits
equihash_sol_bram_if_b.a <= equihash_sol_bram_if_b.a + 1;
end
//TODO here we also need to check the ordering, and duplicates?
end
// When we start getting the hash results, start XORing them // When we start getting the hash results, start XORing them
if (blake2b_out_hash.val) begin if (blake2b_out_hash.val) begin
sol_hash_xor <= hash_solution(sol_hash_xor, blake2b_out_hash.dat); sol_hash_xor <= hash_solution(sol_hash_xor, blake2b_out_hash.dat);
sol_cnt_out <= sol_cnt_out + 1; sol_cnt_out <= sol_cnt_out + 1;
//TODO here we also need to check the ordering, and duplicates?
end end
if (sol_cnt_out == SOL_LIST_LEN - 1) begin if (sol_cnt_out == SOL_LIST_LEN - 1) begin
o_mask.XOR_FAIL <= |sol_hash_xor; o_mask.XOR_FAIL <= |sol_hash_xor;
o_mask_val <= 1; o_mask_val <= 1;
sol_cnt_out <= sol_cnt_out; chk_state <= STATE_CHK_WAIT;
equihash_sol_bram_if_b.a <= 0;
end end
end
STATE_CHK_WAIT: begin
if (ram_rd_state == STATE_RD_IDLE && ram_wr_state == STATE_WR_IDLE)
chk_state <= STATE_CHK_IDLE;
end
endcase
end end
end end
// Constants // Constants
always_comb begin always_comb begin
parameters = {'0, 8'd1, 8'd1, 8'd0, BLAKE2B_DIGEST_BYTS}; parameters = {'0, 8'd1, 8'd1, 8'd0, BLAKE2B_DIGEST_BYTS};
parameters[48*8-1 +: 16*8] = POW_TAG; parameters[48*8-1 +: 16*8] = POW_TAG;
blake2b_in_hash.dat = equihash_gen_in; blake2b_in_hash.dat = equihash_gen_in;
for (int i = 0; i < DAT_BYTS; i++)
sol_ram_byte_bit_flip[i*8 +: 8] = flip_bit_byte(equihash_sol_bram_if_b.q[i*8 +: 8]);
end end
// Function to OR the hash output depending on equihash parameters // Function to OR the hash output depending on equihash parameters
function hash_solution(input [N-1:0] curr, input [N*INDICIES_PER_HASH-1:0] in); function [N-1:0] hash_solution(input [N-1:0] curr, input [N*INDICIES_PER_HASH-1:0] in);
hash_solution = curr;
for (int i = 0; i < INDICIES_PER_HASH; i++) for (int i = 0; i < INDICIES_PER_HASH; i++)
curr = curr ^ in[i*N +: N]; hash_solution = hash_solution ^ in[i*N +: N];
return curr; endfunction
// Function to convert bit order in each byte of the solution list
function [7:0] flip_bit_byte(input [7:0] in);
for (int i = 0; i < 8; i++)
flip_bit_byte[8-1-i] = in[i];
endfunction endfunction
// Instantiate the Blake2b block - use high performance pipelined version // Instantiate the Blake2b block - use high performance pipelined version

View File

@ -89,7 +89,7 @@ begin
start_241 = 1; start_241 = 1;
while(!done_241 && !mask_val) @(posedge clk); while(!done_241 || !mask_val) @(posedge clk);
assert (~(|mask)) else $fatal(1, "%m %t ERROR: test_block_346 mask was non-zero", $time); assert (~(|mask)) else $fatal(1, "%m %t ERROR: test_block_346 mask was non-zero", $time);
assert (~mask.XOR_FAIL) else $fatal(1, "%m %t ERROR: test_block_346 failed XOR mask check", $time); assert (~mask.XOR_FAIL) else $fatal(1, "%m %t ERROR: test_block_346 failed XOR mask check", $time);