Updates to top control, secp256k1 core.

This commit is contained in:
bsdevlin 2019-03-17 00:31:12 -04:00
parent 051f3e68b5
commit 571bfb2dc0
13 changed files with 748 additions and 50 deletions

View File

@ -0,0 +1,315 @@
//**************************************************************************
//************* BittWare Incorporated *************
//************* 45 S. Main Street, Concord, NH 03301 *************
//**************************************************************************
// LEGAL NOTICE:
// Copyright (c) 2018 BittWare, Inc.
// The user is hereby granted a non-exclusive license to use and or
// modify this code provided that it runs on BittWare hardware.
// Usage of this code on non-BittWare hardware without the express
// written permission of BittWare is strictly prohibited.
//
// E-mail: support@bittware.com Tel: 603-226-0404
//**************************************************************************
//# Created by: Jeff Sanders
//# Date: 20 Jun 2018
///
//**************************************************************************
// pcie_base: Default PCIe-based design incorporating the following functionality:
// - PCIe Gen3x16 interface w/integrated PCIe-to-AXI4 conversion (within IPI subsystem)
// - SPI controller (within IPI subsystem)
// - I2C controller (within IPI subsystem)
// - 16550-compatible UART (within IPI subsystem)
// - STARTUPE3 primitive configured to allow writes to QSPI flash
//
// PCIe address map: (BAR0, 32-bit)
// 0x0000: CSR (0x0=Version(rd);LED[2:0](wr), 0x4=UAR timestamp(rd), 0x8=CSR(rd/wr))
// 0x1100: SPI core
// 0x2200: I2C Core
// 0x3300: UART Core
// 0x4000: 4KB scratchpad BRAM
//
//**************************************************************************
`timescale 1ps/1ps
`define DEV_SEL_HI_BIT 11
`define DEV_SEL_LO_BIT 8
`define VERSION_REG 32'h00600000
module bittware_xupvvh_top (
led_pins,
pcie_7x_mgt_rxn,
pcie_7x_mgt_rxp,
pcie_7x_mgt_txn,
pcie_7x_mgt_txp,
prog_b5_p,
prog_b5_n,
avr_rxd,
avr_txd,
usb_rxd,
usb_txd,
i2c_sda,
i2c_scl,
FPGA_I2C_MASTER_L,
QSFP_CTL_EN,
SAS_CTL_EN,
sys_clkp,
sys_clkn,
sys_reset_l);
//####### Misc. Board-specific #######
output [3:0]led_pins; // On-board LEDs 0-3
output FPGA_I2C_MASTER_L; // Drive high to allow BMC to control QSFPs
output QSFP_CTL_EN; // Drive high for normal operation
output SAS_CTL_EN; // Drive high for normal operation
//####### PCIe Interface #######
input [15:0]pcie_7x_mgt_rxn;
input [15:0]pcie_7x_mgt_rxp;
output [15:0]pcie_7x_mgt_txn;
output [15:0]pcie_7x_mgt_txp;
//####### I2C and UART I/F's #######
input avr_txd; // Tx UART data from the AVR
output avr_rxd; // Rx UART data to the AVR
inout i2c_sda; // I2C biderectional data
inout i2c_scl; // I2C clock
input usb_uart_txd; // Tx UART data from the USB
output logic usb_uart_rxd; // Rx UART data to the USB
//####### Clocks & Reset #######
input sys_clkp; // PCIe reference clock
input sys_clkn;
input prog_b5_p;
input prog_b5_n;
input sys_reset_l; // PCIe PERSTN
wire [3:0] spi_in;
wire [3:0] spi_out;
wire [3:0] spi_tri;
wire spi_sel;
wire spi_clk_o;
wire spi_clk_t;
reg spi_cs_l;
reg [31:0] clk_cnt;
reg [3:0] led_q;
wire [3:0] memtest_ok;
reg led_test_reg;
reg [3:0] qsfp_rst_reg;
reg [3:0] qsfp_lp_reg;
reg [3:0] qsfp_sel_oh;
reg [3:0] qsfp_i2c_ctri_vec;
reg [3:0] qsfp_i2c_dtri_vec;
reg [3:0] qsfp_i2c_cin_vec;
reg [3:0] qsfp_i2c_din_vec;
wire [31:0] CSR_awaddr;
wire [31:0] CSR_wdata;
wire [31:0] CSR_araddr;
reg [31:0] CSR_rdata;
reg CSR_rvalid;
reg CSR_awready;
reg CSR_arready;
reg CSR_wready;
reg CSR_bvalid;
wire CSR_wdecode;
wire CSR_rdecode;
wire csr_ren;
wire csr_wen;
wire sys_clk;
wire sys_clk_gt;
wire [31:0] UAR_DATA;
IBUFDS_GTE4 refclk_ibuf (.O(sys_clk_gt), .ODIV2(sys_clk), .I(sys_clkp), .CEB(1'b0), .IB(sys_clkn));
// STARTUPE3 block: Allows FPGA logic connections to dedicated config. pins
// From the UltraScale Configuration Guide:
// FCSBO: FPGA logic signal to external FCS_B configuration pin. FCSBO allows user
// control of FCS_B pin for Flash access.
// USRCCLKO (User CCLK input). USRCCLKO is an input from the FPGA logic. USERCCLKO drives a custom,
// FPGA-generated clock frequency onto the external FPGA CCLK pin. This is useful for
// post-configuration access of external SPI flash devices.
// STARTUPE3: STARTUP Block
// UltraScale
// Xilinx HDL Libraries Guide, version 2014.4
STARTUPE3 #(
.PROG_USR("FALSE") // Activate program event security feature. Requires encrypted bitstreams.
)
STARTUPE3_inst (
.CFGCLK(), // 1-bit output: Configuration main clock output
.CFGMCLK(), // 1-bit output: Configuration internal oscillator clock output
.DI(spi_in), // 4-bit output: Allow receiving on the D input pin
.EOS(), // 1-bit output: Active-High output signal indicating the End Of Startup
.PREQ(), // 1-bit output: PROGRAM request to fabric output
.DO({3'b000,spi_mosi}),// 4-bit input: Allows control of the D pin output
.DTS(4'b1110), // 4-bit input: Allows tristate of the D pin
.FCSBO(spi_cs_l), // 1-bit input: Contols the FCS_B pin for flash access
.FCSBTS(1'b0), // 1-bit input: Tristate the FCS_B pin
.GSR(), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port)
.GTS(1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name)
.KEYCLEARB(), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM)
.PACK(), // 1-bit input: PROGRAM acknowledge input
.USRCCLKO(spi_sck_o), // 1-bit input: User CCLK input
.USRCCLKTS(1'b0), // 1-bit input: User CCLK 3-state enable input
.USRDONEO(1'b1), // 1-bit input: User DONE pin output control
.USRDONETS(1'b1) // 1-bit input: User DONE 3-state enable output
);
//
// PCIe IPI subsystem instantiation
//
pcie2axilite_sub pcie2axilite_sub_i(
.sys_clk(sys_clk),
.sys_clk_gt(sys_clk_gt),
.clk_100_clk_p(prog_b5_p),
.clk_100_clk_n(prog_b5_n),
.sys_reset_l(sys_reset_l),
.pcie_7x_mgt_rxn(pcie_7x_mgt_rxn),
.pcie_7x_mgt_rxp(pcie_7x_mgt_rxp),
.pcie_7x_mgt_txn(pcie_7x_mgt_txn),
.pcie_7x_mgt_txp(pcie_7x_mgt_txp),
.axi_aclk(axi_clk),
.user_link_up(rst_l),
.m00_axi_0_araddr(CSR_araddr),
.m00_axi_0_arprot(CSR_arprot),
.m00_axi_0_arready(CSR_arready),
.m00_axi_0_arvalid(CSR_arvalid),
.m00_axi_0_awaddr(CSR_awaddr),
.m00_axi_0_awprot(CSR_awprot),
.m00_axi_0_awready(CSR_awready),
.m00_axi_0_awvalid(CSR_awvalid),
.m00_axi_0_bready(CSR_bready),
.m00_axi_0_bresp(1'b0),
.m00_axi_0_bvalid(CSR_bvalid),
.m00_axi_0_rdata(CSR_rdata),
.m00_axi_0_rready(CSR_rready),
.m00_axi_0_rresp(1'b0),
.m00_axi_0_rvalid(CSR_rvalid),
.m00_axi_0_wdata(CSR_wdata),
.m00_axi_0_wready(CSR_wready),
.m00_axi_0_wstrb(CSR_wstrb),
.m00_axi_0_wvalid(CSR_wvalid),
.uart_0_baudoutn(),
.uart_0_ctsn(1'b0),
.uart_0_dcdn(1'b0),
.uart_0_ddis(),
.uart_0_dsrn(1'b0),
.uart_0_dtrn(),
.uart_0_out1n(),
.uart_0_out2n(),
.uart_0_ri(1'b0),
.uart_0_rtsn(),
.uart_0_rxd(avr_txd),
.uart_0_rxrdyn(),
.uart_0_txd(avr_rxd),
.uart_0_txrdyn(),
.iic_0_scl_i(i2c_cin),
.iic_0_scl_o(i2c_cout),
.iic_0_scl_t(i2c_ctri),
.iic_0_sda_i(i2c_din),
.iic_0_sda_o(i2c_dout),
.iic_0_sda_t(i2c_dtri),
.spi_0_io0_o(spi_io0_o),
.spi_0_io1_i(spi_io1_i),
.spi_0_sck_o(spi_sck_o),
.spi_0_ss_o(spi_ss_o_0),
.spi_0_ss_t(spi_ss_t)
);
assign spi_mosi = spi_io0_o;
assign spi_io1_i = spi_miso;
always@(posedge axi_clk) begin
if (spi_ss_t == 0)
spi_cs_l <= spi_ss_o_0;
else
spi_cs_l <= 1'b1;
end
//***************************************************************************
// Buffers for I2C Tri-State I/O
//***************************************************************************
IOBUF IOBUF_i2c_clk_inst (
.O(i2c_cin),
.I(i2c_cout),
.IO(i2c_scl),
.T(i2c_ctri)
);
IOBUF IOBUF_i2c_data_inst (
.O(i2c_din),
.I(i2c_dout),
.IO(i2c_sda),
.T(i2c_dtri)
);
USR_ACCESSE2 USR_ACCESSE2_inst (
.CFGCLK(), // 1-bit output: Configuration Clock
.DATA(UAR_DATA), // 32-bit output: Configuration Data reflecting the contents of the AXSS register
.DATAVALID() // 1-bit output: Active High Data Valid
);
// decode CSR Transaction
assign CSR_wdecode = (CSR_awaddr[`DEV_SEL_HI_BIT:`DEV_SEL_LO_BIT] == 0) | (CSR_awaddr[`DEV_SEL_HI_BIT:`DEV_SEL_LO_BIT] > 3); // Decode 0x0 and out-of-range to CSR
assign CSR_rdecode = (CSR_araddr[`DEV_SEL_HI_BIT:`DEV_SEL_LO_BIT] == 0) | (CSR_araddr[`DEV_SEL_HI_BIT:`DEV_SEL_LO_BIT] > 3); // Decode 0x0 and out-of-range to CSR
assign csr_wen = CSR_awready & CSR_wdecode;
assign csr_ren = CSR_arready & CSR_rdecode;
always@(posedge axi_clk or negedge(rst_l)) begin
if (rst_l == 1'b0) begin
CSR_awready <= 1'b0;
CSR_arready <= 1'b0;
clk_cnt <= 0;
led_q <= 0;
led_test_reg <= 1'b0;
qsfp_rst_reg <= 'h0;
qsfp_lp_reg <= 'h0;
qsfp_sel_oh <= 4'h0;
end
else begin
clk_cnt <= clk_cnt + 1;
led_q[3] <= clk_cnt[25];
CSR_awready <= CSR_awvalid;
CSR_arready <= CSR_arvalid;
if (csr_wen & CSR_wvalid) begin
CSR_wready <= CSR_wvalid & ~(CSR_awvalid);
if (CSR_awaddr[`DEV_SEL_LO_BIT-1]) begin
qsfp_rst_reg <= CSR_wdata[19:16]; // AXI Write to addr 0x80 Config Reg, R/W
qsfp_lp_reg <= CSR_wdata[15:12];
qsfp_sel_oh <= CSR_wdata[11:8];
led_test_reg <= CSR_wdata[7];
led_q[2:0] <= CSR_wdata[6:4];
end
CSR_bvalid <= 1;
end
else if (csr_ren & CSR_rready) begin
CSR_rvalid <= CSR_rready & ~(CSR_arvalid);
// AXI Read: 0x80 reads config reg, 0x0 reads VERSION REG, 0x4 reads UAR. 0x0 and 0x4 are READ ONLY
CSR_rdata <= CSR_araddr[`DEV_SEL_LO_BIT-1] ? {12'h0,
qsfp_rst_reg,
qsfp_lp_reg,
qsfp_sel_oh,
led_test_reg,
led_q[2:0],
4'b0000} : CSR_araddr[3] ? 32'h0 : (CSR_araddr[2] ? UAR_DATA : `VERSION_REG);
end
else begin
CSR_rvalid <= 0;
CSR_wready <= 0;
end
end
end
assign spi_miso = spi_in[1];
assign led_pins = ~led_q;
assign FPGA_I2C_MASTER_L = 1'b1; // Change to 1'b0 to allow FPGA control of QSFP I2C bus
assign QSFP_CTL_EN = 1'b1;
assign SAS_CTL_EN = 1'b1;
// User logic
endmodule

View File

@ -0,0 +1,30 @@
# Find all the cdc_fifos and synchronizers set constraints for the cross clock domains.
#
# Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
set synchronizer_instance [get_cells -hierarchical -filter { ORIG_REF_NAME =~ "synchronizer" || REF_NAME =~ "synchronizer" } ]
foreach child $synchronizer_instance {
set name [get_property NAME $child]
set cells [get_cells -hierarchical -filter "NAME =~ $name/* "]
set clock [get_clocks -of_objects [get_pins -filter { NAME =~ "*dat_reg[1]*C" } -of_objects $cells]]
set clock_period [get_property PERIOD $clock]
set_bus_skew -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects $cells] -to [get_pins -filter { NAME =~ "*dat_reg[1]*D" } -of_objects $cells] [expr $clock_period/2]
set_max_delay -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects $cells] -to [get_pins -filter { NAME =~ "*dat_reg[1]*D" } -of_objects $cells] -datapath_only [expr $clock_period/2]
}

View File

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

View File

@ -18,7 +18,6 @@
set cdc_fifo_instance [get_cells -hierarchical -filter { ORIG_REF_NAME =~ "cdc_fifo" || REF_NAME =~ "cdc_fifo" } ]
foreach child $cdc_fifo_instance {
set using_bram [get_property USE_BRAM [get_cells $child]]
set name [get_property NAME $child]
set wr_ptr_cells [get_cells -hierarchical -filter "NAME =~ $name/synchronizer_wr_ptr/* "]

View File

@ -26,7 +26,7 @@ module control_top
parameter [63:0] BUILD_HOST = "test",
parameter [63:0] BUILD_DATE = "20180311"
)(
input i_clk_core, i_rst_core,
input i_clk_core, i_rst_core, i_rst_core_perm, // _perm reset is not effected by o_usr_rst
input i_clk_if, i_rst_if,
// User is able to reset custom logic on FPGA
output logic o_usr_rst,
@ -43,6 +43,8 @@ module control_top
localparam IN_DAT_BITS = IN_DAT_BYTS*8;
localparam CORE_DAT_BITS = CORE_DAT_BYTS*8;
localparam MAX_BYT_MSG = 256; // Max bytes in a reply message
// When a command comes in it is put through a clock crossing, and then stored in a command
// FIFO to be processed. There are two FIFOS - one for processing status / reset commands (msg_type == 0),
// and one for everything else. This is so we can process these messages even if we are
@ -59,24 +61,31 @@ if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS), .CTL_BYTS(1)) rx_typ1_if (i_clk_core);
if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS), .CTL_BYTS(1)) tx_arb_in_if [2] (i_clk_core);
if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS), .CTL_BYTS(1)) tx_int_if (i_clk_core);
enum {TYP0_IDLE = 0,
typedef enum {TYP0_IDLE = 0,
TYP0_SEND_STATUS = 1,
TYP0_RESET_FPGA = 2,
TYP0_IGNORE = 3} typ0_msg_state;
TYP0_SEND_IGNORE = 3,
TYP0_IGNORE = 4} typ0_msg_state_t;
typ0_msg_state_t typ0_msg_state;
enum {TYP1_IDLE = 0,
TYP1_VERIFY_EQUIHASH = 1,
TYP1_IGNORE = 2} 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_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 [7:0] typ0_wrd_cnt, typ1_wrd_cnt, reset_cnt;
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 [63:0] equihash_index;
logic equihash_index_val, rx_typ1_if_rdy, verify_equihash_rpl_val;
logic sop_l;
logic eop_typ0_l;
fpga_state_t fpga_state;
always_comb begin
@ -90,45 +99,54 @@ end
// Logic for processing msg_type == 0 messages
always_ff @ (posedge i_clk_core) begin
if (i_rst_core) begin
if (i_rst_core_perm ) begin
rx_typ0_if.rdy <= 0;
typ0_msg_state <= TYP0_IDLE;
header0_l <= 0;
tx_arb_in_if[0].reset_source();
fpga_status_rpl <= 0;
fpga_reset_rpl <= 0;
// fpga_status_rpl <= 0;
// fpga_reset_rpl <= 0;
/// fpga0_ignore_rpl <= 0;
typ0_wrd_cnt <= 0;
o_usr_rst <= 0;
reset_cnt <= 0;
eop_typ0_l <= 0;
typ0_msg <= 0;
end else 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();
//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);
if (rx_typ0_if.val && rx_typ0_if.rdy) begin
header0_l <= header0;
rx_typ0_if.rdy <= 0;
case(header0.cmd)
RESET_FPGA: begin
typ0_msg <= get_fpga_reset_rpl();
typ0_wrd_cnt <= $bits(fpga_reset_rpl_t)/8;
typ0_msg_state <= TYP0_RESET_FPGA;
o_usr_rst <= 1;
reset_cnt <= -1;
end
FPGA_STATUS: begin
typ0_msg <= get_fpga_status_rpl(BUILD_HOST, BUILD_DATE, fpga_state);
typ0_wrd_cnt <= $bits(fpga_status_rpl_t)/8;
typ0_msg_state <= TYP0_SEND_STATUS;
end
default:
if (~rx_typ0_if.eop)
typ0_msg_state <= TYP0_IGNORE;
default: begin
typ0_msg <= get_fpga_ignore_rpl(header0);
eop_typ0_l <= rx_typ0_if.eop;
typ0_msg_state <= TYP0_SEND_IGNORE;
end
endcase
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;
@ -143,6 +161,8 @@ always_ff @ (posedge i_clk_core) begin
typ0_msg_state <= TYP0_IDLE;
end
end
*/
send_typ0_message($bits(fpga_status_rpl_t)/8, typ0_msg, typ0_wrd_cnt);
end
TYP0_RESET_FPGA: begin
rx_typ0_if.rdy <= 0;
@ -152,6 +172,8 @@ 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;
@ -164,10 +186,27 @@ always_ff @ (posedge i_clk_core) begin
tx_arb_in_if[0].val <= 0;
typ0_msg_state <= TYP0_IDLE;
end
end
end*/
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*/
end
TYP0_IGNORE: begin
rx_typ0_if.rdy <= 1;
if (rx_typ0_if.rdy && rx_typ0_if.eop && rx_typ0_if.val)
@ -177,6 +216,24 @@ 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 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);
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].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].val <= 0;
typ0_msg_state <= nxt_state;
end
end
endtask
always_comb begin
case(typ1_msg_state)
TYP1_IDLE: rx_typ1_if.rdy = rx_typ1_if_rdy;
@ -199,6 +256,7 @@ always_ff @ (posedge i_clk_core) begin
equihash_index_val <= 0;
sop_l <= 0;
end else begin
// TODO add IGNORE type here
case (typ1_msg_state)
TYP1_IDLE: begin
rx_typ1_if_rdy <= 1;
@ -303,7 +361,7 @@ always_comb begin
end
always_ff @ (posedge i_clk_core) begin
if (i_rst_core || o_usr_rst) begin
if (i_rst_core ) begin
msg_type_l <= 0;
end else begin
if (rx_int_if.val && rx_int_if.rdy) begin
@ -321,7 +379,7 @@ axi_stream_fifo #(
)
cmd_fifo0 (
.i_clk ( i_clk_core ),
.i_rst ( i_rst_core || o_usr_rst ),
.i_rst ( i_rst_core ),
.i_axi ( rx_int0_if ),
.o_axi ( rx_typ0_if )
);
@ -332,7 +390,7 @@ axi_stream_fifo #(
)
cmd_fifo1 (
.i_clk ( i_clk_core ),
.i_rst ( i_rst_core || o_usr_rst ),
.i_rst ( i_rst_core ),
.i_axi ( rx_int1_if ),
.o_axi ( rx_typ1_if )
);
@ -346,9 +404,9 @@ width_change_cdc_fifo #(
)
cdc_fifo_rx (
.i_clk_a ( i_clk_if ),
.i_rst_a ( i_rst_if || o_usr_rst ),
.i_rst_a ( i_rst_if ),
.i_clk_b ( i_clk_core ),
.i_rst_b ( i_rst_core || o_usr_rst ),
.i_rst_b ( i_rst_core ),
.i_axi_a ( rx_if ),
.o_axi_b ( rx_int_if )
);
@ -361,7 +419,7 @@ packet_arb # (
)
packet_arb_tx (
.i_clk ( i_clk_core ),
.i_rst ( i_rst_core || o_usr_rst ),
.i_rst ( i_rst_core ),
.i_axi ( tx_arb_in_if ),
.o_axi ( tx_int_if )
@ -377,9 +435,9 @@ width_change_cdc_fifo #(
)
cdc_fifo_tx (
.i_clk_a ( i_clk_core ),
.i_rst_a ( i_rst_core || o_usr_rst ),
.i_rst_a ( i_rst_core ),
.i_clk_b ( i_clk_if ),
.i_rst_b ( i_rst_if || o_usr_rst ),
.i_rst_b ( i_rst_if ),
.i_axi_a ( tx_int_if ),
.o_axi_b ( tx_if )
);

View File

@ -0,0 +1,89 @@
/*
This performs modular reduction using Algorithm 2.4 from
D. Hankerson, A. Menezes, S. Vanstone, Guide to Elliptic Curve Cryptography
but with data width 256, for the prime field used in secp256k1
p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
Implemented with 2 stages of 8x 256b adds and one final optional
subtract in the case we are >= p.
returns o_dat = i_dat % p, where i_dat < p^2
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
module secp256k1_mod (
input i_clk, i_rst,
// Input value
input [256*2-1:0] i_dat,
input i_val,
output logic o_rdy,
// output
output logic [255:0] o_dat,
input i_rdy,
output logic o_val
);
import secp256k1_pkg::*;
logic [256*2-1:0] b, a, a_;
always_comb begin
a_ = (a << 32) + (a << 9) + (a << 8) + (a << 7) + (a << 6) + (a << 4) + a + b;
end
enum {IDLE, S1, S2} state;
always_ff @ (posedge i_clk) begin
if (i_rst) begin
a <= 0;
b <= 0;
state <= IDLE;
o_val <= 0;
o_rdy <= 0;
end else begin
o_rdy <= 0;
o_dat <= a_ >= p_eq ? (a_ - p_eq) : a_;
case(state)
IDLE: begin
o_rdy <= 1;
o_val <= 0;
if (i_val && o_rdy) begin
a <= i_dat[511:256];
b <= i_dat[255:0];
o_rdy <= 0;
state <= S1;
end
end
S1: begin
a <= a_[511:256];
b <= a_[255:0];
state <= S2;
end
S2: begin
o_val <= 1;
if (o_val && i_rdy) begin
state <=IDLE;
o_rdy <= 1;
o_val <= 0;
end
end
endcase
end
end
endmodule

View File

@ -0,0 +1,33 @@
/*
Package for the secp256k1 core
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package secp256k1_pkg;
// TODO might have to flip these
parameter [255:0] p = 256'hFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFC2F;
parameter [255:0] a = 256'h0;
parameter [255:0] b = 256'h7;
parameter [255:0] Gx = 256'h79BE667E_F9DCBBAC_55A06295_CE870B07_029BFCDB_2DCE28D9_59F2815B_16F81798;
parameter [255:0] Gy = 256'h483ADA77_26A3C465_5DA4FBFC_0E1108A8_FD17B448_A6855419_9C47D08F_FB10D4B8;
parameter [255:0] n = 256'hFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_BAAEDCE6_AF48A03B_BFD25E8C_D0364141;
parameter [255:0] h = 256'h1;
parameter [255:0] p_eq = (1 << 256) - (1 << 32) - (1 << 9) - (1 << 8) - (1 << 7) - (1 << 6) - (1 << 4) - 1;
endpackage

View File

@ -0,0 +1,10 @@
module secp256k1_top ();
// inversion
// multiplication
// addition
endmodule

View File

@ -21,9 +21,13 @@ package zcash_fpga_pkg;
import equihash_pkg::equihash_bm_t;
import equihash_pkg::cblockheader_sol_t;
import equihash_pkg::N;
import equihash_pkg::K;
parameter FPGA_VERSION = 32'h0;
localparam [63:0] FPGA_CMD_CAP = 64'h0;
localparam [63:0] FPGA_CMD_CAP = {{62'd0},
(equihash_pkg::N == 144 && equihash_pkg::K == 5), // N = 144, K = 5 for VERIFY_EQUIHASH command
(equihash_pkg::N == 200 && equihash_pkg::K == 9)}; // N = 200, K = 9 for VERIFY_EQUIHASH command
// These are all the command types the FPGA supports
// Reply messages from the FPGA to host all have the last
@ -36,6 +40,7 @@ package zcash_fpga_pkg;
// Replies from the FPGA
RESET_FPGA_RPL = 'h80_00_00_00,
FPGA_STATUS_RPL = 'h80_00_00_01,
FPGA_IGNORE_RPL = 'h80_00_00_02,
VERIFY_EQUIHASH_RPL = 'h80_00_01_00
} command_t;
@ -50,6 +55,11 @@ package zcash_fpga_pkg;
header_t hdr;
} fpga_reset_rpl_t;
typedef struct packed {
header_t hdr;
logic [63:0] ignore_hdr;
} fpga_ignore_rpl_t;
// These are registers we use for debug
typedef struct packed {
logic [3:0] padding;
@ -82,6 +92,10 @@ package zcash_fpga_pkg;
function fpga_reset_rpl_t get_fpga_reset_rpl();
get_fpga_reset_rpl.hdr = '{cmd:RESET_FPGA_RPL, len:$bits(fpga_reset_rpl_t)/8};
endfunction
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};
endfunction
function fpga_status_rpl_t get_fpga_status_rpl(input [63:0] build_host, build_date, fpga_state_t fpga_state);
get_fpga_status_rpl.cmd_cap = FPGA_CMD_CAP;

View File

@ -27,37 +27,65 @@ module zcash_fpga_top
parameter CORE_DAT_BYTS = 8 // Only tested at 8 byte data width
)(
// Clocks and resets
input i_clk_200, i_rst_200,
input i_clk_300, i_rst_300,
input i_clk_if, i_rst_if,
input i_clk_core0, i_rst_core0, // Core 0 is the main clock
input i_clk_core1, i_rst_core1, // Core 1 is used on logic with faster clock
input i_clk_if, i_rst_if, // Command interface clock (e.g. UART / PCIe)
// Interface input and output
// UART
// Command interface input and output
if_axi_stream.sink rx_if,
if_axi_stream.source tx_if
);
logic usr_rst, core_clk, core_rst;
if_axi_stream #(.DAT_BYTS(CORE_DAT_BYTS)) equihash_axi(core_clk);
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;
logic equihash_mask_val;
always_comb begin
core_clk = i_clk_200;
core_rst = i_rst_200;
always_ff @ (posedge i_clk_core0) begin
usr_rst_r <= usr_rst;
rst_core0 <= i_rst_core0 || usr_rst_r;
end
// Synchronize resets
(* DONT_TOUCH = "yes" *)
synchronizer #(
.DAT_BITS ( 1 ),
.NUM_CLKS ( 3 )
)
core_rst1_sync (
.i_clk_a ( i_clk_core0 ),
.i_clk_b ( i_clk_core1 ),
.i_dat_a ( usr_rst_r || i_rst_core1 ),
.o_dat_b ( rst_core1 )
);
(* DONT_TOUCH = "yes" *)
synchronizer #(
.DAT_BITS ( 1 ),
.NUM_CLKS ( 3 )
)
if_rst_sync (
.i_clk_a ( i_clk_core0 ),
.i_clk_b ( i_clk_if ),
.i_dat_a ( usr_rst_r || i_rst_if ),
.o_dat_b ( rst_if )
);
// This block takes in the interface signals and interfaces with other blocks
control_top #(
.CORE_DAT_BYTS ( CORE_DAT_BYTS ),
.IN_DAT_BYTS ( IF_DAT_BYTS )
)
control_top (
.i_clk_core ( core_clk ),
.i_rst_core ( core_rst ),
.i_clk_core ( i_clk_core0 ),
.i_rst_core ( rst_core0 ),
.i_rst_core_perm ( i_rst_core0 ),
.i_clk_if ( i_clk_if ),
.i_rst_if ( i_rst_if ),
.i_rst_if ( rst_if ),
.o_usr_rst ( usr_rst ),
.rx_if ( rx_if ),
.tx_if ( tx_if ),
@ -72,12 +100,10 @@ equihash_verif_top #(
.DAT_BYTS( CORE_DAT_BYTS )
)
equihash_verif_top (
.i_clk ( core_clk ),
.i_rst ( core_rst || usr_rst ),
.i_clk_300 ( i_clk_300 ),
.i_rst_300 ( i_rst_300 || usr_rst ), // Faster clock
.i_clk ( i_clk_core0 ),
.i_rst ( core_rst ),
.i_clk_300 ( i_clk_core1 ), // Faster clock
.i_rst_300 ( rst_core1 ),
.i_axi ( equihash_axi ),
.o_mask ( equihash_mask ),
.o_mask_val ( equihash_mask_val )

View File

@ -0,0 +1,116 @@
/*
Copyright (C) 2019 Benjamin Devlin and Zcash Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
`timescale 1ps/1ps
module secp256k1_mod_tb ();
import common_pkg::*;
import secp256k1_pkg::*;
localparam CLK_PERIOD = 100;
logic clk, rst;
if_axi_stream #(.DAT_BYTS(512/8)) in_if(clk);
if_axi_stream #(.DAT_BYTS(256/8)) out_if(clk);
initial begin
rst = 0;
repeat(2) #(20*CLK_PERIOD) rst = ~rst;
end
initial begin
clk = 0;
forever #CLK_PERIOD clk = ~clk;
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
secp256k1_mod secp256k1_mod
(
.i_clk( clk ),
.i_rst( rst ),
.i_dat( in_if.dat ),
.i_val( in_if.val ),
.o_rdy( in_if.rdy ),
.o_dat( out_if.dat ),
.i_rdy( out_if.rdy ),
.o_val( out_if.val )
);
task test0();
begin
integer signed get_len;
logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, in_dat, get_dat;
$display("Running test0...");
in_dat = 1 << 433;
expected = 256'd822752465816620949324161418291805943222876982255305228346720256;
fork
in_if.put_stream(in_dat, 512/8);
out_if.get_stream(get_dat, get_len);
join
common_pkg::compare_and_print(get_dat, expected);
$display("test0 PASSED");
end
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;
$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;
fork
in_if.put_stream(in_dat, 512/8);
out_if.get_stream(get_dat, get_len);
join
common_pkg::compare_and_print(get_dat, expected);
$display("test_loop PASSED loop %d/%d", i, max);
i = i + 1;
end
$display("test_loop PASSED");
end
endtask;
initial begin
out_if.rdy = 0;
in_if.val = 0;
#(40*CLK_PERIOD);
test0();
test_loop();
#1us $finish();
end
endmodule

View File

@ -195,6 +195,7 @@ initial begin
#20us; // Let internal memories reset
test_block_346_equihash();
test_ignored_message();
#1us $finish();

View File

@ -1,7 +1,10 @@
create_clock -period 5.000 -name i_clk_200 -waveform {0.000 2.500} [get_ports -filter { NAME =~ "*i_clk_200*" && DIRECTION == "IN" }]
create_clock -period 3.333 -name i_clk_300 -waveform {0.000 1.666} [get_ports -filter { NAME =~ "i_clk_300" && DIRECTION == "IN" }]
create_clock -period 3.000 -name i_clk_core1 -waveform {0.000 1.500} [get_ports -filter { NAME =~ "i_clk_core1" && DIRECTION == "IN" }]
create_clock -period 5.000 -name i_clk_core0 -waveform {0.000 2.500} [get_ports -filter { NAME =~ "i_clk_core0" && DIRECTION == "IN" }]
create_clock -period 10.000 -name i_clk_if -waveform {0.000 5.000} [get_ports -filter { NAME =~ "i_clk_if" && DIRECTION == "IN" }]
#Just for when we are synth a test block
create_clock -period 5.000 -name i_clk -waveform {0.000 2.500} [get_ports -filter { NAME =~ "i_clk" && DIRECTION == "IN" }]
set_bus_skew -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects [get_cells -hierarchical -filter {NAME =~ control_top/cdc_fifo_rx/cdc_fifo/synchronizer_wr_ptr/* }]] -to [get_pins -filter { NAME =~ "*dat_reg[1]*D" } -of_objects [get_cells -hierarchical -filter {NAME =~ control_top/cdc_fifo_rx/cdc_fifo/synchronizer_wr_ptr/* }]] 2.500
set_max_delay -datapath_only -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects [get_cells -hierarchical -filter {NAME =~ control_top/cdc_fifo_rx/cdc_fifo/synchronizer_wr_ptr/* }]] -to [get_pins -filter { NAME =~ "*dat_reg[1]*D" } -of_objects [get_cells -hierarchical -filter {NAME =~ control_top/cdc_fifo_rx/cdc_fifo/synchronizer_wr_ptr/* }]] 2.500
set_bus_skew -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects [get_cells -hierarchical -filter {NAME =~ control_top/cdc_fifo_rx/cdc_fifo/synchronizer_rd_ptr/* }]] -to [get_pins -filter { NAME =~ "*dat_reg[1]*D" } -of_objects [get_cells -hierarchical -filter {NAME =~ control_top/cdc_fifo_rx/cdc_fifo/synchronizer_rd_ptr/* }]] 5.000
@ -48,5 +51,9 @@ set_bus_skew -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects [g
set_max_delay -datapath_only -from [get_pins -filter { NAME =~ "*dat_reg[0]*C" } -of_objects [get_cells -hierarchical -filter {NAME =~ equihash_verif_top/dup_check_fifo_out/synchronizer_rd_ptr/* }]] -to [get_pins -filter { NAME =~ "*dat_reg[1]*D" } -of_objects [get_cells -hierarchical -filter {NAME =~ equihash_verif_top/dup_check_fifo_out/synchronizer_rd_ptr/* }]] 1.667
set_bus_skew -from [get_pins -filter { NAME =~ "*ram*C" } -of_objects [get_cells -hierarchical -filter {NAME =~ equihash_verif_top/dup_check_fifo_out/* }]] -to [get_pins -filter { NAME =~ "*o_dat_b*D" } -of_objects [get_cells -hierarchical -filter {NAME =~ equihash_verif_top/dup_check_fifo_out/* }]] 1.667
set_max_delay -datapath_only -from [get_pins -filter { NAME =~ "*ram*C" } -of_objects [get_cells -hierarchical -filter {NAME =~ equihash_verif_top/dup_check_fifo_out/* }]] -to [get_pins -filter { NAME =~ "*o_dat_b*D" } -of_objects [get_cells -hierarchical -filter {NAME =~ equihash_verif_top/dup_check_fifo_out/* }]] 1.667
set_multicycle_path -hold -from [get_pins control_top/o_usr_rst_reg/C] 5
set_multicycle_path -setup -from [get_pins control_top/o_usr_rst_reg/C] 5
set_false_path -from [get_pins {core_rst1_sync/dat_reg[0][0]/C}] -to [get_pins {core_rst1_sync/dat_reg[2][0]_srl2/D}]
set_false_path -from [get_pins {if_rst_sync/dat_reg[0][0]/C}] -to [get_pins {if_rst_sync/dat_reg[2][0]_srl2/D}]