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.
#
#*****************************************************************************************
# 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 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 'sources_1' fileset file properties for local files
# None
# Set 'sources_1' fileset properties
set obj [get_filesets sources_1]

View File

@ -6,6 +6,9 @@
3. No duplicates
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
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 [$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 [SOL_BITS-1:0] ram_out;
logic [64*8-1:0] parameters;
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_b (i_clk, i_rst);
logic [DAT_BITS-1:0] equihash_sol_bram_if_b_l;
logic [1:0] equihash_sol_bram_read;
enum {STATE_IDLE = 0,
STATE_DATA_WRITE = 1,
STATE_FINISH_WAIT = 2} ram_state;
enum {STATE_WR_IDLE = 0,
STATE_WR_DATA = 1,
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
always_ff @ (posedge i_clk) begin
@ -73,7 +83,7 @@ always_ff @ (posedge i_clk) begin
cblockheader <= 0;
cblockheader_byts <= 0;
cblockheader_val <= 0;
ram_state <= STATE_IDLE;
ram_wr_state <= STATE_WR_IDLE;
end else begin
// Defaults
equihash_sol_bram_if_a.we <= 1;
@ -86,31 +96,31 @@ always_ff @ (posedge i_clk) begin
cblockheader_byts <= cblockheader_byts + DAT_BYTS;
end
case (ram_state)
case (ram_wr_state)
// This state we are waiting for an input block
STATE_IDLE: begin
STATE_WR_IDLE: begin
i_axi.rdy <= 1;
if (i_axi.val && i_axi.rdy) begin
ram_state <= STATE_DATA_WRITE;
equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a + 1;
ram_wr_state <= STATE_WR_DATA;
equihash_sol_bram_if_a.a <= 0;
end
end
// 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
equihash_sol_bram_if_a.a <= equihash_sol_bram_if_a.a + 1;
if (i_axi.eop) begin
i_axi.rdy <= 0;
ram_state <= STATE_FINISH_WAIT;
ram_wr_state <= STATE_WR_WAIT;
end
end
end
// 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.a <= equihash_sol_bram_if_a.a;
if (all_checks_done) begin
ram_state <= STATE_IDLE;
if (chk_state == STATE_CHK_WAIT) begin
ram_wr_state <= STATE_WR_IDLE;
i_axi.rdy <= 1;
cblockheader_val <= 0;
equihash_sol_bram_if_a.a <= 0;
@ -120,99 +130,154 @@ always_ff @ (posedge i_clk) begin
end
end
// State machine for controlling the hash calculation
// and checking the header values
// State machine for loading the output of RAM into the Blake2b block
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
if (i_rst) begin
o_mask_val <= 0;
o_mask <= 0;
sol_hash_xor <= 0;
blake2b_in_hash.reset_source();
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_pos <= 0;
equihash_sol_bram_if_b_l <= 0;
chk_state <= STATE_CHK_IDLE;
end else begin
// Defaults
equihash_sol_bram_if_b.re <= 1;
equihash_sol_bram_if_b.en <= 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
equihash_sol_bram_if_b.a <= $bits(cblockheader_t)/DAT_BITS;
sol_pos <= $bits(cblockheader_t) % DAT_BITS;
sol_cnt_out <= 0;
sol_cnt_in <= 0;
blake2b_in_hash.val <= 0;
o_mask_val <= 0;
o_mask <= 0;
end
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;
case(chk_state)
STATE_CHK_IDLE: begin
sol_cnt_out <= 0;
o_mask_val <= 0;
o_mask <= 0;
sol_hash_xor <= 0;
if (ram_rd_state == STATE_RD_DATA)
chk_state <= STATE_CHK_DATA;
end
//TODO here we also need to check the ordering, and duplicates?
end
STATE_CHK_DATA: begin
// When we start getting the hash results, start XORing them
if (blake2b_out_hash.val) begin
sol_hash_xor <= hash_solution(sol_hash_xor, blake2b_out_hash.dat);
sol_cnt_out <= sol_cnt_out + 1;
end
if (sol_cnt_out == SOL_LIST_LEN - 1) begin
o_mask.XOR_FAIL <= |sol_hash_xor;
o_mask_val <= 1;
sol_cnt_out <= sol_cnt_out;
equihash_sol_bram_if_b.a <= 0;
end
// When we start getting the hash results, start XORing them
if (blake2b_out_hash.val) begin
sol_hash_xor <= hash_solution(sol_hash_xor, blake2b_out_hash.dat);
sol_cnt_out <= sol_cnt_out + 1;
//TODO here we also need to check the ordering, and duplicates?
end
if (sol_cnt_out == SOL_LIST_LEN - 1) begin
o_mask.XOR_FAIL <= |sol_hash_xor;
o_mask_val <= 1;
chk_state <= STATE_CHK_WAIT;
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
// Constants
always_comb begin
parameters = {'0, 8'd1, 8'd1, 8'd0, BLAKE2B_DIGEST_BYTS};
parameters[48*8-1 +: 16*8] = POW_TAG;
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
// 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++)
curr = curr ^ in[i*N +: N];
return curr;
hash_solution = hash_solution ^ in[i*N +: N];
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
// Instantiate the Blake2b block - use high performance pipelined version

View File

@ -89,7 +89,7 @@ begin
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.XOR_FAIL) else $fatal(1, "%m %t ERROR: test_block_346 failed XOR mask check", $time);