diff --git a/zcash_fpga/src/rtl/control/control_top.sv b/zcash_fpga/src/rtl/control/control_top.sv index 8ef3a72..61731a6 100644 --- a/zcash_fpga/src/rtl/control/control_top.sv +++ b/zcash_fpga/src/rtl/control/control_top.sv @@ -50,7 +50,6 @@ localparam MAX_BYT_MSG = 256; // Max bytes in a reply message // and one for everything else. This is so we can process these messages even if we are // running something else. - if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS), .CTL_BYTS(1)) rx_int_if (i_clk_core); if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS), .CTL_BYTS(1)) rx_int0_if (i_clk_core); if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS), .CTL_BYTS(1)) rx_int1_if (i_clk_core); @@ -69,23 +68,23 @@ typedef enum {TYP0_IDLE = 0, typ0_msg_state_t typ0_msg_state; -enum {TYP1_IDLE = 0, +typedef enum {TYP1_IDLE = 0, TYP1_VERIFY_EQUIHASH = 1, - TYP1_IGNORE = 2} typ1_msg_state; + TYP1_SEND_IGNORE = 2, + TYP1_IGNORE = 3} typ1_msg_state_t; +typ1_msg_state_t typ1_msg_state; + header_t header, header0, header1, header0_l, header1_l; -//fpga_status_rpl_t fpga_status_rpl; -//fpga_reset_rpl_t fpga_reset_rpl; -//fpga_ignore_rpl_t fpga0_ignore_rpl; -verify_equihash_rpl_t verify_equihash_rpl; +logic verify_equihash_rpl_val; logic [7:0] reset_cnt; logic [$clog2(MAX_BYT_MSG) -1:0] typ0_wrd_cnt, typ1_wrd_cnt; -logic [MAX_BYT_MSG*8 -1:0] typ0_msg; +logic [MAX_BYT_MSG*8 -1:0] typ0_msg, typ1_msg; logic [63:0] equihash_index; -logic equihash_index_val, rx_typ1_if_rdy, verify_equihash_rpl_val; +logic equihash_index_val, rx_typ1_if_rdy; logic sop_l; -logic eop_typ0_l; +logic eop_typ0_l, eop_typ1_l; fpga_state_t fpga_state; always_comb begin @@ -104,9 +103,6 @@ always_ff @ (posedge i_clk_core) begin typ0_msg_state <= TYP0_IDLE; header0_l <= 0; tx_arb_in_if[0].reset_source(); - // fpga_status_rpl <= 0; - // fpga_reset_rpl <= 0; -/// fpga0_ignore_rpl <= 0; typ0_wrd_cnt <= 0; o_usr_rst <= 0; reset_cnt <= 0; @@ -116,11 +112,7 @@ always_ff @ (posedge i_clk_core) begin rx_typ0_if.rdy <= 1; case (typ0_msg_state) - TYP0_IDLE: begin - //fpga_status_rpl <= get_fpga_status_rpl(BUILD_HOST, BUILD_DATE, fpga_state); - //fpga_reset_rpl <= get_fpga_reset_rpl(); - //fpga0_ignore_rpl <= get_fpga_ignore_rpl(header0); - + TYP0_IDLE: begin if (rx_typ0_if.val && rx_typ0_if.rdy) begin header0_l <= header0; rx_typ0_if.rdy <= 0; @@ -139,6 +131,7 @@ always_ff @ (posedge i_clk_core) begin end default: begin typ0_msg <= get_fpga_ignore_rpl(header0); + typ0_wrd_cnt <= $bits(fpga_ignore_rpl_t)/8; eop_typ0_l <= rx_typ0_if.eop; typ0_msg_state <= TYP0_SEND_IGNORE; end @@ -146,23 +139,7 @@ always_ff @ (posedge i_clk_core) begin end end TYP0_SEND_STATUS: begin - /* - rx_typ0_if.rdy <= 0; - if (~tx_arb_in_if[0].val || (tx_arb_in_if[0].rdy && tx_arb_in_if[0].val)) begin - tx_arb_in_if[0].dat <= fpga_status_rpl; - tx_arb_in_if[0].val <= 1; - tx_arb_in_if[0].sop <= typ0_wrd_cnt == $bits(fpga_status_rpl_t)/8; - tx_arb_in_if[0].eop <= typ0_wrd_cnt <= CORE_DAT_BYTS; - tx_arb_in_if[0].mod <= typ0_wrd_cnt < CORE_DAT_BYTS ? typ0_wrd_cnt : 0; - typ0_wrd_cnt <= (typ0_wrd_cnt > CORE_DAT_BYTS) ? (typ0_wrd_cnt - CORE_DAT_BYTS) : 0; - fpga_status_rpl <= fpga_status_rpl >> CORE_DAT_BITS; - if (typ0_wrd_cnt == 0) begin - tx_arb_in_if[0].val <= 0; - typ0_msg_state <= TYP0_IDLE; - end - end - */ - send_typ0_message($bits(fpga_status_rpl_t)/8, typ0_msg, typ0_wrd_cnt); + send_typ0_message($bits(fpga_status_rpl_t)/8); end TYP0_RESET_FPGA: begin rx_typ0_if.rdy <= 0; @@ -172,40 +149,11 @@ always_ff @ (posedge i_clk_core) begin reset_cnt <= reset_cnt - 1; if (~o_usr_rst) begin - send_typ0_message($bits(fpga_reset_rpl_t)/8, typ0_msg, typ0_wrd_cnt); - /* - if (~tx_arb_in_if[0].val || (tx_arb_in_if[0].rdy && tx_arb_in_if[0].val)) begin - tx_arb_in_if[0].dat <= fpga_reset_rpl; - tx_arb_in_if[0].val <= 1; - tx_arb_in_if[0].sop <= typ0_wrd_cnt == $bits(fpga_reset_rpl_t)/8; - tx_arb_in_if[0].eop <= typ0_wrd_cnt <= CORE_DAT_BYTS; - tx_arb_in_if[0].mod <= typ0_wrd_cnt < CORE_DAT_BYTS ? typ0_wrd_cnt : 0; - typ0_wrd_cnt <= (typ0_wrd_cnt > CORE_DAT_BYTS) ? (typ0_wrd_cnt - CORE_DAT_BYTS) : 0; - fpga_reset_rpl <= fpga_reset_rpl >> CORE_DAT_BITS; - if (typ0_wrd_cnt == 0) begin - tx_arb_in_if[0].val <= 0; - typ0_msg_state <= TYP0_IDLE; - end - end*/ + send_typ0_message($bits(fpga_reset_rpl_t)/8); end end TYP0_SEND_IGNORE: begin - send_typ0_message($bits(fpga0_ignore_rpl_t)/8, typ0_msg, typ0_wrd_cnt, eop_typ0_l ? TYP0_IDLE :TYP0_IGNORE); - /* - rx_typ0_if.rdy <= 0; - if (~tx_arb_in_if[0].val || (tx_arb_in_if[0].rdy && tx_arb_in_if[0].val)) begin - tx_arb_in_if[0].dat <= fpga_ignore_rpl; - tx_arb_in_if[0].val <= 1; - tx_arb_in_if[0].sop <= typ0_wrd_cnt == $bits(fpga0_ignore_rpl_t)/8; - tx_arb_in_if[0].eop <= typ0_wrd_cnt <= CORE_DAT_BYTS; - tx_arb_in_if[0].mod <= typ0_wrd_cnt < CORE_DAT_BYTS ? typ0_wrd_cnt : 0; - typ0_wrd_cnt <= (typ0_wrd_cnt > CORE_DAT_BYTS) ? (typ0_wrd_cnt - CORE_DAT_BYTS) : 0; - fpga_ignore_rpl <= fpga_ignore_rpl >> CORE_DAT_BITS; - if (typ0_wrd_cnt == 0) begin - tx_arb_in_if[0].val <= 0; - typ0_msg_state <= eop_typ0_l ? TYP0_IDLE :TYP0_IGNORE; - end - end*/ + send_typ0_message($bits(fpga_ignore_rpl_t)/8, eop_typ0_l ? TYP0_IDLE : TYP0_IGNORE); end TYP0_IGNORE: begin rx_typ0_if.rdy <= 1; @@ -217,17 +165,18 @@ always_ff @ (posedge i_clk_core) begin end // Task to help build reply messages. Assume no message will be more than MAX_BYT_MSG bytes -task automatic send_typ0_message(input logic [$clog2(MAX_BYT_MSG)-1:0] msg_size, ref logic [MAX_BYT_MSG*8-1:0] msg, ref logic [$clog2(MAX_BYT_MSG)-1:0] byt_cnt, input typ0_msg_state_t nxt_state = TYP0_IDLE); +task send_typ0_message(input logic [$clog2(MAX_BYT_MSG)-1:0] msg_size, + input typ0_msg_state_t nxt_state = TYP0_IDLE); rx_typ0_if.rdy <= 0; if (~tx_arb_in_if[0].val || (tx_arb_in_if[0].rdy && tx_arb_in_if[0].val)) begin - tx_arb_in_if[0].dat <= msg; + tx_arb_in_if[0].dat <= typ0_msg; tx_arb_in_if[0].val <= 1; - tx_arb_in_if[0].sop <= byt_cnt == msg_size; - tx_arb_in_if[0].eop <= byt_cnt <= CORE_DAT_BYTS; - tx_arb_in_if[0].mod <= byt_cnt < CORE_DAT_BYTS ? byt_cnt : 0; - byt_cnt <= (byt_cnt > CORE_DAT_BYTS) ? (byt_cnt - CORE_DAT_BYTS) : 0; - msg <= msg >> CORE_DAT_BITS; - if (byt_cnt == 0) begin + tx_arb_in_if[0].sop <= typ0_wrd_cnt == msg_size; + tx_arb_in_if[0].eop <= typ0_wrd_cnt <= CORE_DAT_BYTS; + tx_arb_in_if[0].mod <= typ0_wrd_cnt < CORE_DAT_BYTS ? typ0_wrd_cnt : 0; + typ0_wrd_cnt <= (typ0_wrd_cnt > CORE_DAT_BYTS) ? (typ0_wrd_cnt - CORE_DAT_BYTS) : 0; + typ0_msg <= typ0_msg >> CORE_DAT_BITS; + if (typ0_wrd_cnt == 0) begin tx_arb_in_if[0].val <= 0; typ0_msg_state <= nxt_state; end @@ -249,12 +198,13 @@ always_ff @ (posedge i_clk_core) begin header1_l <= 0; tx_arb_in_if[1].reset_source(); o_equihash_axi.reset_source(); - verify_equihash_rpl <= 0; typ1_wrd_cnt <= 0; equihash_index <= 0; verify_equihash_rpl_val <= 0; equihash_index_val <= 0; - sop_l <= 0; + sop_l <= 0; + eop_typ1_l <= 0; + typ1_msg <= 0; end else begin // TODO add IGNORE type here case (typ1_msg_state) @@ -272,9 +222,12 @@ always_ff @ (posedge i_clk_core) begin typ1_wrd_cnt <= $bits(verify_equihash_rpl_t)/8; typ1_msg_state <= TYP1_VERIFY_EQUIHASH; end - default: - if (~rx_typ1_if.eop) - typ1_msg_state <= TYP1_IGNORE; + default: begin + typ1_msg <= get_fpga_ignore_rpl(header1); + typ1_wrd_cnt <= $bits(fpga_ignore_rpl_t)/8; + eop_typ1_l <= rx_typ1_if.eop; + typ1_msg_state <= TYP1_SEND_IGNORE; + end endcase end end @@ -302,27 +255,18 @@ always_ff @ (posedge i_clk_core) begin // Wait for reply with result if (i_equihash_mask_val && ~verify_equihash_rpl_val) begin - verify_equihash_rpl <= get_verify_equihash_rpl(i_equihash_mask, equihash_index); + typ1_msg <= get_verify_equihash_rpl(i_equihash_mask, equihash_index); verify_equihash_rpl_val <= 1; end // Send result if (verify_equihash_rpl_val) begin - if (~tx_arb_in_if[1].val || (tx_arb_in_if[1].rdy && tx_arb_in_if[1].val)) begin - tx_arb_in_if[1].dat <= verify_equihash_rpl; - tx_arb_in_if[1].val <= 1; - tx_arb_in_if[1].sop <= typ1_wrd_cnt == $bits(verify_equihash_rpl_t)/8; - tx_arb_in_if[1].eop <= typ1_wrd_cnt <= CORE_DAT_BYTS; - tx_arb_in_if[1].mod <= typ1_wrd_cnt < CORE_DAT_BYTS ? typ1_wrd_cnt : 0; - typ1_wrd_cnt <= (typ1_wrd_cnt > CORE_DAT_BYTS) ? (typ1_wrd_cnt - CORE_DAT_BYTS) : 0; - verify_equihash_rpl <= verify_equihash_rpl >> CORE_DAT_BITS; - if (typ1_wrd_cnt == 0) begin - tx_arb_in_if[1].val <= 0; - typ1_msg_state <= TYP1_IDLE; - end - end + send_typ1_message($bits(verify_equihash_rpl_t)/8); end end + TYP1_SEND_IGNORE: begin + send_typ1_message($bits(fpga_ignore_rpl_t)/8, eop_typ1_l ? TYP1_IDLE : TYP1_IGNORE); + end TYP1_IGNORE: begin rx_typ1_if_rdy <= 1; if (rx_typ1_if.rdy && rx_typ1_if.eop && rx_typ1_if.val) @@ -332,6 +276,25 @@ always_ff @ (posedge i_clk_core) begin end end +// Task to help build reply messages. Assume no message will be more than MAX_BYT_MSG bytes +task send_typ1_message(input logic [$clog2(MAX_BYT_MSG)-1:0] msg_size, + input typ1_msg_state_t nxt_state = TYP1_IDLE); + rx_typ1_if.rdy <= 0; + if (~tx_arb_in_if[1].val || (tx_arb_in_if[1].rdy && tx_arb_in_if[1].val)) begin + tx_arb_in_if[1].dat <= typ1_msg; + tx_arb_in_if[1].val <= 1; + tx_arb_in_if[1].sop <= typ1_wrd_cnt == msg_size; + tx_arb_in_if[1].eop <= typ1_wrd_cnt <= CORE_DAT_BYTS; + tx_arb_in_if[1].mod <= typ1_wrd_cnt < CORE_DAT_BYTS ? typ1_wrd_cnt : 0; + typ1_wrd_cnt <= (typ1_wrd_cnt > CORE_DAT_BYTS) ? (typ1_wrd_cnt - CORE_DAT_BYTS) : 0; + typ1_msg <= typ1_msg >> CORE_DAT_BITS; + if (typ1_wrd_cnt == 0) begin + tx_arb_in_if[1].val <= 0; + typ1_msg_state <= nxt_state; + end + end +endtask + // Logic to mux the packet depending on its command type logic msg_type, msg_type_l; always_comb begin diff --git a/zcash_fpga/src/rtl/secp256k1/secp256k1_mod.sv b/zcash_fpga/src/rtl/secp256k1/secp256k1_mod.sv index 135029b..76d15e9 100644 --- a/zcash_fpga/src/rtl/secp256k1/secp256k1_mod.sv +++ b/zcash_fpga/src/rtl/secp256k1/secp256k1_mod.sv @@ -35,7 +35,8 @@ module secp256k1_mod ( // output output logic [255:0] o_dat, input i_rdy, - output logic o_val + output logic o_val, + output logic o_err // Will go high if after 1 reduction we are still >= p ); import secp256k1_pkg::*; @@ -55,9 +56,11 @@ always_ff @ (posedge i_clk) begin state <= IDLE; o_val <= 0; o_rdy <= 0; + o_err <= 0; end else begin o_rdy <= 0; o_dat <= a_ >= p_eq ? (a_ - p_eq) : a_; + case(state) IDLE: begin o_rdy <= 1; @@ -76,10 +79,12 @@ always_ff @ (posedge i_clk) begin end S2: begin o_val <= 1; + o_err <= a_ >= 2* p_eq; if (o_val && i_rdy) begin state <=IDLE; o_rdy <= 1; o_val <= 0; + o_err <= 0; end end endcase diff --git a/zcash_fpga/src/rtl/top/zcash_fpga_pkg.sv b/zcash_fpga/src/rtl/top/zcash_fpga_pkg.sv index 5b2f0e0..41d466e 100644 --- a/zcash_fpga/src/rtl/top/zcash_fpga_pkg.sv +++ b/zcash_fpga/src/rtl/top/zcash_fpga_pkg.sv @@ -95,6 +95,7 @@ package zcash_fpga_pkg; function fpga_ignore_rpl_t get_fpga_ignore_rpl(header_t hdr); get_fpga_ignore_rpl.hdr = '{cmd:FPGA_IGNORE_RPL, len:$bits(fpga_ignore_rpl_t)/8}; + get_fpga_ignore_rpl.ignore_hdr = hdr; endfunction function fpga_status_rpl_t get_fpga_status_rpl(input [63:0] build_host, build_date, fpga_state_t fpga_state); diff --git a/zcash_fpga/src/rtl/top/zcash_fpga_top.sv b/zcash_fpga/src/rtl/top/zcash_fpga_top.sv index 795672c..925b25d 100644 --- a/zcash_fpga/src/rtl/top/zcash_fpga_top.sv +++ b/zcash_fpga/src/rtl/top/zcash_fpga_top.sv @@ -38,8 +38,6 @@ module zcash_fpga_top logic rst_core0, rst_core1, rst_if, usr_rst, usr_rst_r; -logic rst_200, rst_300; - if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS)) equihash_axi(i_clk_core0); equihash_bm_t equihash_mask; @@ -101,7 +99,7 @@ equihash_verif_top #( ) equihash_verif_top ( .i_clk ( i_clk_core0 ), - .i_rst ( core_rst ), + .i_rst ( rst_core0 ), .i_clk_300 ( i_clk_core1 ), // Faster clock .i_rst_300 ( rst_core1 ), .i_axi ( equihash_axi ), diff --git a/zcash_fpga/src/tb/secp256k1_mod_tb.sv b/zcash_fpga/src/tb/secp256k1_mod_tb.sv index 0dac1d0..f95e88d 100644 --- a/zcash_fpga/src/tb/secp256k1_mod_tb.sv +++ b/zcash_fpga/src/tb/secp256k1_mod_tb.sv @@ -40,11 +40,15 @@ end always_comb begin out_if.sop = 1; out_if.eop = 1; - out_if.err = 0; out_if.ctl = 0; out_if.mod = 0; end +// Check for errors +always_ff @ (posedge clk) + if (out_if.val && out_if.err) + $error(1, "%m %t ERROR: output .err asserted", $time); + secp256k1_mod secp256k1_mod ( .i_clk( clk ), @@ -53,6 +57,7 @@ secp256k1_mod secp256k1_mod .i_val( in_if.val ), .o_rdy( in_if.rdy ), .o_dat( out_if.dat ), + .o_err( out_if.err ), .i_rdy( out_if.rdy ), .o_val( out_if.val ) ); @@ -77,19 +82,19 @@ endtask; task test_loop(); begin integer signed get_len, i, max; - logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, in_dat, get_dat; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] in_dat, get_dat; + logic [256:0] expected; $display("Running test_loop..."); in_dat = 1 << 433; expected = 256'd822752465816620949324161418291805943222876982255305228346720256; i = 0; - max = 10000; - repeat (max) begin - - in_dat = in_dat*2; - expected = expected*2; - while (expected >= p_eq) - expected = expected - p_eq; - + max = 1000; + while (i < max) begin + + in_dat = random_vector(512); + in_dat = in_dat % (p_eq*p_eq); + expected = in_dat % p_eq; + fork in_if.put_stream(in_dat, 512/8); out_if.get_stream(get_dat, get_len); @@ -109,8 +114,10 @@ initial begin out_if.rdy = 0; in_if.val = 0; #(40*CLK_PERIOD); + test0(); - test_loop(); + test_loop(); // This one is a bit slower since we compute the expected result + #1us $finish(); end endmodule \ No newline at end of file diff --git a/zcash_fpga/src/tb/zcash_fpga_top_tb.sv b/zcash_fpga/src/tb/zcash_fpga_top_tb.sv index 13f6c4f..7afcee8 100644 --- a/zcash_fpga/src/tb/zcash_fpga_top_tb.sv +++ b/zcash_fpga/src/tb/zcash_fpga_top_tb.sv @@ -112,10 +112,10 @@ zcash_fpga_top #( ) DUT( // Clocks and resets - .i_clk_200 ( clk_200 ), - .i_rst_200 ( rst_200 ), - .i_clk_300 ( clk_300 ), - .i_rst_300 ( rst_300 ), + .i_clk_core0 ( clk_200 ), + .i_rst_core0 ( rst_200 ), + .i_clk_core1 ( clk_300 ), + .i_rst_core1 ( rst_300 ), .i_clk_if ( clk_if ), .i_rst_if ( rst_if ), .rx_if ( tx_if ), @@ -188,14 +188,43 @@ begin end endtask +// This task sends a malformed message and checks it gets ignored +task test_ignored_message(); +begin + header_t header; + fpga_ignore_rpl_t fpga_ignore_rpl; + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + logic fail = 0; + $display("Running test_ignored_message..."); + + // Some header value that is invalid + header = {$bits(header_t){1'b1}}; + header.cmd[8 +: 8] = 0; + fork + tx_if.put_stream(header, $bits(header)/8); + rx_if.get_stream(get_dat, get_len); + join + + fpga_ignore_rpl = get_dat; + + fail |= get_len != $bits(fpga_ignore_rpl_t)/8; + fail |= fpga_ignore_rpl.hdr.cmd != FPGA_IGNORE_RPL; + fail |= fpga_ignore_rpl.hdr.len != $bits(fpga_ignore_rpl_t)/8; + assert (~fail) else $fatal(1, "%m %t ERROR: test_ignored_message rply was wrong:\n%p", $time, fpga_ignore_rpl); + + $display("test_ignored_message PASSED"); + +end +endtask // Main testbench calls initial begin rx_if.rdy = 0; #20us; // Let internal memories reset - test_block_346_equihash(); test_ignored_message(); + test_block_346_equihash(); #1us $finish();