diff --git a/.project b/.project new file mode 100644 index 0000000..0ef5a74 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + zcash-fpga + + + + + + + + diff --git a/README.md b/README.md index 742d741..ccaefea 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,22 @@ # zcash-fpga -Repo for ZCash FPGA projects code and documents + +Repo for Zcash FPGA projects code and documents. + +## Overview + +These have been designed targetted for Xilinx boards (US+) and therefore contain Xilinx-specific IP. + +## zcash_verif + +This is the top level for the Zcash verification FPGA board. It targets both Xilinx Virtex UltraScale+ FPGA VCU118 Evaluation Kit, and Amazon EC2 F1 Instances. + +Architecture document is [here]() + +## ip_cores + +These contain custom IP cores used in the projects in this repo. + +* blake2b - A simple implementation of blake2b and a pipline-unrolled version for high performance. +* common - Packages and interfaces that are shared. +* fifo - Fifo implementations +* parsing - Blocks for parsing/processing streams, as well as testbench files. \ No newline at end of file diff --git a/equihash-verifi/README.md b/equihash-verifi/README.md deleted file mode 100644 index 8b13789..0000000 --- a/equihash-verifi/README.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ip_cores/blake2b/scripts/create_project.tcl b/ip_cores/blake2b/scripts/create_project.tcl new file mode 100644 index 0000000..691742a --- /dev/null +++ b/ip_cores/blake2b/scripts/create_project.tcl @@ -0,0 +1,519 @@ +#***************************************************************************************** +# Vivado (TM) v2018.3 (64-bit) +# +# create_project.tcl: Tcl script for re-creating project 'blake2b' +# +# Generated by Vivado on Wed Feb 13 16:57:58 -0500 2019 +# IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# 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) +# +# +# +# 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 ] ] ] +puts $script_path +set origin_dir $script_path + +# Set the project name +set _xil_proj_name_ "blake2b" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "create_project.tcl" + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Set the directory path for the original project from where this script was exported +set orig_proj_dir "[file normalize "$origin_dir/../proj"]" + +# Create project +create_project ${_xil_proj_name_} $origin_dir/../proj/ -part xcvu9p-flga2104-2L-e + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Set project properties +set obj [current_project] +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "dsa.accelerator_binary_content" -value "bitstream" -objects $obj +set_property -name "dsa.accelerator_binary_format" -value "xclbin2" -objects $obj +set_property -name "dsa.description" -value "Vivado generated DSA" -objects $obj +set_property -name "dsa.dr_bd_base_address" -value "0" -objects $obj +set_property -name "dsa.emu_dir" -value "emu" -objects $obj +set_property -name "dsa.flash_interface_type" -value "bpix16" -objects $obj +set_property -name "dsa.flash_offset_address" -value "0" -objects $obj +set_property -name "dsa.flash_size" -value "1024" -objects $obj +set_property -name "dsa.host_architecture" -value "x86_64" -objects $obj +set_property -name "dsa.host_interface" -value "pcie" -objects $obj +set_property -name "dsa.num_compute_units" -value "60" -objects $obj +set_property -name "dsa.platform_state" -value "pre_synth" -objects $obj +set_property -name "dsa.vendor" -value "xilinx" -objects $obj +set_property -name "dsa.version" -value "0.0" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "part" -value "xcvu9p-flga2104-2L-e" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "Mixed" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + [file normalize "${origin_dir}/../src/rtl/blake2b_g.sv"] \ + [file normalize "${origin_dir}/../src/rtl/blake2b_pkg.sv"] \ + [file normalize "${origin_dir}/../../common/src/rtl/common_pkg.sv"] \ + [file normalize "${origin_dir}/../../common/src/rtl/common_if.sv"] \ + [file normalize "${origin_dir}/../src/rtl/blake2b_top.sv"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sources_1' fileset file properties for remote files +set file "$origin_dir/../src/rtl/blake2b_g.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../src/rtl/blake2b_pkg.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../../common/src/rtl/common_pkg.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../../common/src/rtl/common_if.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + +set file "$origin_dir/../src/rtl/blake2b_top.sv" +set file [file normalize $file] +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] +set_property -name "top" -value "blake2b_top" -objects $obj + +# Create 'constrs_1' fileset (if not found) +if {[string equal [get_filesets -quiet constrs_1] ""]} { + create_fileset -constrset constrs_1 +} + +# Set 'constrs_1' fileset object +set obj [get_filesets constrs_1] + +# Add/Import constrs file and set constrs file properties +set file "[file normalize "$origin_dir/../synth/blake2b_top.xdc"]" +set file_added [add_files -norecurse -fileset $obj [list $file]] +set file "$origin_dir/../synth/blake2b_top.xdc" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] +set_property -name "file_type" -value "XDC" -objects $file_obj + +# Set 'constrs_1' fileset properties +set obj [get_filesets constrs_1] +set_property -name "target_part" -value "xcvu9p-flga2104-2L-e" -objects $obj + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +set files [list \ + [file normalize "${origin_dir}/../src/tb/blake2b_top_tb.sv"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sim_1' fileset file properties for remote files +set file "$origin_dir/../src/tb/blake2b_top_tb.sv" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]] +set_property -name "file_type" -value "SystemVerilog" -objects $file_obj + + +# Set 'sim_1' fileset file properties for local files +# None + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "top" -value "blake2b_top_tb" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +# Set 'utils_1' fileset object +set obj [get_filesets utils_1] +# Empty (no sources present) + +# Set 'utils_1' fileset properties +set obj [get_filesets utils_1] + +# Create 'synth_1' run (if not found) +if {[string equal [get_runs -quiet synth_1] ""]} { + create_run -name synth_1 -part xcvu9p-flga2104-2L-e -flow {Vivado Synthesis 2018} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 +} else { + set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] + set_property flow "Vivado Synthesis 2018" [get_runs synth_1] +} +set obj [get_runs synth_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Synthesis Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'synth_1_synth_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { + create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 +} +set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] +if { $obj != "" } { +set_property -name "display_name" -value "synth_1_synth_report_utilization_0" -objects $obj + +} +set obj [get_runs synth_1] +set_property -name "part" -value "xcvu9p-flga2104-2L-e" -objects $obj +set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj + +# set the current synth run +current_run -synthesis [get_runs synth_1] + +# Create 'impl_1' run (if not found) +if {[string equal [get_runs -quiet impl_1] ""]} { + create_run -name impl_1 -part xcvu9p-flga2104-2L-e -flow {Vivado Implementation 2018} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 +} else { + set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] + set_property flow "Vivado Implementation 2018" [get_runs impl_1] +} +set obj [get_runs impl_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Implementation Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'impl_1_init_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_init_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_opt_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { + create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_opt_report_drc_0" -objects $obj + +} +# Create 'impl_1_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_power_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_place_report_io_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { + create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_place_report_io_0" -objects $obj + +} +# Create 'impl_1_place_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { + create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_place_report_utilization_0" -objects $obj + +} +# Create 'impl_1_place_report_control_sets_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { + create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_place_report_control_sets_0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_1' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_place_report_incremental_reuse_1" -objects $obj + +} +# Create 'impl_1_place_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_place_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_post_place_power_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "display_name" -value "impl_1_phys_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_route_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { + create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_drc_0" -objects $obj + +} +# Create 'impl_1_route_report_methodology_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { + create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_methodology_0" -objects $obj + +} +# Create 'impl_1_route_report_power_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { + create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_power_0" -objects $obj + +} +# Create 'impl_1_route_report_route_status_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { + create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_route_status_0" -objects $obj + +} +# Create 'impl_1_route_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_route_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_incremental_reuse_0" -objects $obj + +} +# Create 'impl_1_route_report_clock_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { + create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_clock_utilization_0" -objects $obj + +} +# Create 'impl_1_route_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_route_report_bus_skew_0" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_timing_summary_0" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] +if { $obj != "" } { +set_property -name "display_name" -value "impl_1_post_route_phys_opt_report_bus_skew_0" -objects $obj + +} +set obj [get_runs impl_1] +set_property -name "part" -value "xcvu9p-flga2104-2L-e" -objects $obj +set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj +set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj +set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj + +# set the current impl run +current_run -implementation [get_runs impl_1] + +puts "INFO: Project created:${_xil_proj_name_}" +set obj [get_dashboards default_dashboard] + +# Create 'drc_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] ""]} { +create_dashboard_gadget -name {drc_1} -type drc +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "drc_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj + +# Create 'methodology_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] ""]} { +create_dashboard_gadget -name {methodology_1} -type methodology +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "methodology_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj + +# Create 'power_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] ""]} { +create_dashboard_gadget -name {power_1} -type power +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "power_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj + +# Create 'timing_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] ""]} { +create_dashboard_gadget -name {timing_1} -type timing +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "timing_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj + +# Create 'utilization_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] ""]} { +create_dashboard_gadget -name {utilization_1} -type utilization +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_1" ] ] +set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj +set_property -name "run.step" -value "synth_design" -objects $obj +set_property -name "run.type" -value "synthesis" -objects $obj + +# Create 'utilization_2' gadget (if not found) +if {[string equal [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] ""]} { +create_dashboard_gadget -name {utilization_2} -type utilization +} +set obj [get_dashboard_gadgets -of_objects [get_dashboards default_dashboard] [ list "utilization_2" ] ] +set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj + +move_dashboard_gadget -name {utilization_1} -row 0 -col 0 +move_dashboard_gadget -name {power_1} -row 1 -col 0 +move_dashboard_gadget -name {drc_1} -row 2 -col 0 +move_dashboard_gadget -name {timing_1} -row 0 -col 1 +move_dashboard_gadget -name {utilization_2} -row 1 -col 1 +move_dashboard_gadget -name {methodology_1} -row 2 -col 1 +# Set current dashboard to 'default_dashboard' +current_dashboard default_dashboard diff --git a/ip_cores/blake2b/src/rtl/blake2b_g.sv b/ip_cores/blake2b/src/rtl/blake2b_g.sv new file mode 100644 index 0000000..e6bb2c6 --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2b_g.sv @@ -0,0 +1,78 @@ +/* + The BLAKE2b g function. + + 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 . +*/ + + +module blake2b_g +#( + parameter PIPELINES = 1 // Do we want to optionally add pipeline stages +) +( + input i_clk, + input [63:0] i_a, i_b, i_c, i_d, i_m0, i_m1, + output logic [63:0] o_a, o_b, o_c, o_d +); + +logic [63:0] a0, b0, c0, d0, a1, b1, c1, d1, b2, d2, b3, d3; +logic [PIPELINES:0][64*4-1:0] pipeline; + +// Logic used to implement G function +always_comb begin + a0 = i_a + i_b + i_m0; + d0 = i_d ^ a0; + d1 = {d0[0 +: 32], d0[32 +: 32]}; + c0 = i_c + d1; + b0 = i_b ^ c0; + b1 = {b0[0 +: 24], b0[24 +: 40]}; + a1 = a0 + b1 + i_m1; + d2 = d1 ^ a1; + d3 = {d2[0 +: 16], d2[16 +: 48]}; + c1 = c0 + d3; + b2 = b1 ^ c1; + b3 = {b2[0 +: 63], b2[63]}; +end + +// Final output assignment +always_comb begin + o_a = pipeline[PIPELINES][0*64 +: 64]; + o_b = pipeline[PIPELINES][1*64 +: 64]; + o_c = pipeline[PIPELINES][2*64 +: 64]; + o_d = pipeline[PIPELINES][3*64 +: 64]; +end + +// Optional pipelines +generate begin: PIPE_GEN + genvar gv_p; + always_comb begin + pipeline[0][0*64 +: 64] = a1; + pipeline[0][1*64 +: 64] = b3; + pipeline[0][2*64 +: 64] = c1; + pipeline[0][3*64 +: 64] = d3; + end + for (gv_p = 0; gv_p < PIPELINES; gv_p++) begin: PIPE_LOOP_GEN + always_ff @ (posedge i_clk) begin + pipeline[gv_p + 1][0*64 +: 64] <= pipeline[gv_p][0*64 +: 64]; + pipeline[gv_p + 1][1*64 +: 64] <= pipeline[gv_p][1*64 +: 64]; + pipeline[gv_p + 1][2*64 +: 64] <= pipeline[gv_p][2*64 +: 64]; + pipeline[gv_p + 1][3*64 +: 64] <= pipeline[gv_p][3*64 +: 64]; + end + end +end +endgenerate + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv new file mode 100644 index 0000000..47b6af6 --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2b_pipe_top.sv @@ -0,0 +1,257 @@ +/* + This is a pipeline unrolled implementation of Blake2b (from RFC-7693) + In order to get maximum throughput, the entire message block is required on the first clock cycle, + so all hashes are single clock with .sop and .eop high. + + You can optionally unroll the entire pipeline but this will use a large number of resources. + If you only unroll one pass, you need to interleave the hashes to get the best performance. + So the first part of input message comes on first clock cycle, and the next part comes 26 clocks later. + + Does not support using keys. + + Futher optimization to save area is fixing part of input message constant for + all hashes (just have nonce as input that changes and place this in i_block.ctl). + + 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 . +*/ + +module blake2b_pipe_top + import blake2b_pkg::*; +#( + // Do we fully unroll the pipeline (lot of resources) or just un-roll one pass + parameter FULLY_UNROLL = 0, + // If we fully unfold the pipeline, the message byte length is hard-coded + parameter MSG_LEN = 3, + parameter CTL_BITS = 8 +) +( + input i_clk, i_rst, + + input [7:0] i_byte_len, // Length of the input message + input [64*8-1:0] i_parameters, // Input parameters used in the inital state. + + if_axi_stream.sink i_block, // Input block with valid and ready signals for flow control + if_axi_stream.source o_hash // Output digest with valid and ready signals for flow control +); + + +localparam NUM_ROUNDS = 12; +localparam NUM_PASSES = 1 + MSG_LEN/128; +localparam NUM_PIPE = 2 + NUM_PASSES*(NUM_ROUNDS*2) + 2*NUM_PASSES - 1; + +logic [NUM_PIPE-1:0][15:0][63:0] v; +logic [NUM_PIPE-1:0][7:0][63:0] h; +logic [NUM_PIPE-1:0][15:0][63:0] msg; +logic [NUM_PIPE-1:0][CTL_BITS-1:0] ctl; +logic [NUM_PIPE-1:0] eop_l, sop_l, valid; + +generate + genvar g0, g1, g2, g3; + + // Since this is a single pipeline flow we pause if output is not ready + // Simplier than dealing with valid bubbles in the pipeline + always_comb i_block.rdy = o_hash.rdy; + + // Assign the output from the final pipeline stage + always_comb begin + o_hash.val = valid[NUM_PIPE-1]; + o_hash.ctl = ctl[NUM_PIPE-1]; + o_hash.sop = 1; + o_hash.eop = 1; + o_hash.dat = h[NUM_PIPE-1]; + end + + // First stage has special logic + always_ff @ (posedge i_clk) begin + if (i_rst) begin + h[0] <= 0; + v[0] <= 0; + msg[0] <= i_block.dat; + ctl[0] <= i_block.ctl; + v[0] <= 0; + h[0] <= 0; + valid[0] <= 0; + valid[1] <= 0; + end else begin + if (i_block.rdy) begin + // First stage + h[0] <= i_parameters ^ blake2b_pkg::IV; + v[0] <= 0; + msg[0] <= i_block.dat; + ctl[0] <= i_block.ctl; + valid[0] <= i_block.val; + end + if (o_hash.rdy) begin + // Second stage + h[1] <= h[0]; + init_local_work_vector_pipe(1, NUM_PASSES == 1); // initializes v[1] + msg[1] <= msg[0]; + ctl[1] <= ctl[0]; + valid[1] <= valid[0]; + end + end + end + + + for (g0 = 0; g0 < NUM_PASSES; g0++) begin: GEN_PASS + + localparam LAST_BLOCK = (g0 == NUM_PASSES -1); + localparam SR_MSG_BYTS = LAST_BLOCK ? MSG_LEN % 128 : 128; + localparam PIPE_G0 = 2 + NUM_ROUNDS*2 + g0*(NUM_ROUNDS*2 + 2); + + // Each pass after 0 has a shift register for storing that part of the message + if_axi_stream #(.DAT_BYTS(SR_MSG_BYTS)) msg_in(clk); + if_axi_stream #(.DAT_BYTS(SR_MSG_BYTS)) msg_out(clk); + + // At the end of each round are two pipeline stages for updating + // the local state + always_ff @ (posedge i_clk) begin + if (i_rst) begin + valid[PIPE_G0] <= 0; + valid[PIPE_G0+1] <= 0; + end else begin + if (o_hash.rdy) begin + valid[PIPE_G0] <= valid[PIPE_G0-1]; + valid[PIPE_G0+1] <= valid[PIPE_G0]; + end + end + end + + always_ff @ (posedge i_clk) begin + msg_out.rdy <= 0; + // First stage + // Some pipelines not used in this stage + msg[PIPE_G0] <= 0; + ctl[PIPE_G0] <= 0; + v[PIPE_G0] <= 1; + if (o_hash.rdy) begin + for (int i = 0; i < 8; i++) + h[PIPE_G0][i] <= h[PIPE_G0-1][i] ^ v[PIPE_G0-1][i] ^ v[PIPE_G0-1][i+8]; + end + // Second stage + if (o_hash.rdy) begin + h[PIPE_G0+1] <= h[PIPE_G0]; + init_local_work_vector_pipe(PIPE_G0+2, LAST_BLOCK); + // Need to pull msg and ctl from the shift register if we have more than one pass + // and we fully unrolled. Otherwise next input will be on input. Assert the control + // matches. + msg_out.rdy <= 1; + if (g0 > 0) begin + msg[PIPE_G0+1] <= msg_out.dat; + ctl[PIPE_G0+1] <= msg_out.ctl; + end else begin + msg[PIPE_G0+1] <= 0; + ctl[PIPE_G0+1] <= 0; + end + end + + end + + if (g0 > 0 && FULLY_UNROLL != 0) begin: GEN_MSG_FIFO + + always_ff @ (posedge i_clk) begin + if (msg_in.val && msg_in.rdy) begin + msg_in.dat <= i_block.dat[128*8*g0 :+ 128*8]; + msg_in.sop <= 0; + msg_in.eop <= 0; + msg_in.err <= 0; + msg_in.ctl <= i_block.ctl; + msg_in.mod <= LAST_BLOCK ? i_block.mod : 0; + end + end + + always_comb begin + if (g0 == 0) i_block.rdy = msg_in.rdy; + msg_in.val = i_block.val; + end + + axi_stream_fifo #( + .A_BITS ( $clog2(NUM_ROUNDS + 2) ), + .DAT_BITS ( 128*8 ), + .CTL_BITS ( CTL_BITS ) + ) + message_fifo ( + .i_clk ( i_clk ), + .i_rst ( i_rst ), + .i_axi ( msg_in ), + .o_axi ( msg_out ) + ); + + end + + for (g1 = 0; g1 < NUM_ROUNDS; g1++) begin: GEN_ROUND + for (g2 = 0; g2 < 2; g2++) begin: GEN_G_FUNC + + // Each pipeline stage has 4 G function blocks in parallel + localparam PIPE_G2 = 2 + g0*(2 + NUM_ROUNDS*2) + g1*2 + g2; + + always_ff @(posedge i_clk) begin + if (i_rst) begin + valid[PIPE_G2] <= 0; + end else begin + if (o_hash.rdy) valid[PIPE_G2] <= valid[PIPE_G2-1]; + end + end + + always_ff @(posedge i_clk) begin + if (o_hash.rdy) begin + msg[PIPE_G2] <= msg[PIPE_G2-1]; + //if (PIPE_G2 != PIPE_G0) + h[PIPE_G2] <= h[PIPE_G2-1]; + ctl[PIPE_G2] <= ctl[PIPE_G2-1]; // TODO could remove? + end + end + + for (g3 = 0; g3 < 4; g3++) begin: GEN_G_FUNC_COL_DIAG + + blake2b_g + #( .PIPELINES(1) ) + blake2b_g ( + .i_clk(i_clk), + .i_a(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 0)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 0)]]), + .i_b(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 1)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 1)]]), + .i_c(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 2)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 2)]]), + .i_d(g2 == 0 ? v[PIPE_G2-1][blake2b_pkg::G_MAPPING[(g3*4 + 3)]] : v[PIPE_G2-1][blake2b_pkg::G_MAPPING[16 + (g3*4 + 3)]]), + .i_m0(msg[PIPE_G2-1][blake2b_pkg::SIGMA[16*(g1%10) + g2*8 + g3*2]]), + .i_m1(msg[PIPE_G2-1][blake2b_pkg::SIGMA[16*(g1%10) + g2*8 + g3*2 + 1]]), + .o_a(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 0] : blake2b_pkg::G_MAPPING[16 + g3*4 + 0]]), + .o_b(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 1] : blake2b_pkg::G_MAPPING[16 + g3*4 + 1]]), + .o_c(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 2] : blake2b_pkg::G_MAPPING[16 + g3*4 + 2]]), + .o_d(v[PIPE_G2][g2 == 0 ? blake2b_pkg::G_MAPPING[g3*4 + 3] : blake2b_pkg::G_MAPPING[16 + g3*4 + 3]]) + ); + end + end + end + end +endgenerate + +// Task to initialize local work vector for the compression function +// Modified to work with pipeline version +task init_local_work_vector_pipe(input integer j, input last_block); +begin + for (int i = 0; i < 16; i++) + case (i) inside + 0,1,2,3,4,5,6,7: v[j][i] <= h[j-1][i]; + 8,9,10,11: v[j][i] <= blake2b_pkg::IV[i%8]; + 12: v[j][i] <= blake2b_pkg::IV[i%8] ^ (last_block ? (MSG_LEN % 128) : j*128); + 13: v[j][i] <= blake2b_pkg::IV[i%8] ^ j*128 >> 64; + 14: v[j][i] <= blake2b_pkg::IV[i%8] ^ {64{last_block}}; + 15: v[j][i] <= blake2b_pkg::IV[i%8]; + endcase +end +endtask + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2b_pkg.sv b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv new file mode 100644 index 0000000..e73e65f --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2b_pkg.sv @@ -0,0 +1,69 @@ +/* + The BLAKE2b package file. + + 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 . +*/ + +package blake2b_pkg; + + // Initial values + parameter [7:0][63:0] IV = { + 64'h5be0cd19137e2179, + 64'h1f83d9abfb41bd6b, + 64'h9b05688c2b3e6c1f, + 64'h510e527fade682d1, + 64'ha54ff53a5f1d36f1, + 64'h3c6ef372fe94f82b, + 64'hbb67ae8584caa73b, + 64'h6a09e667f3bcc908 + }; + + // Sigma permutations used for G function blocks and input messages + parameter [16*10-1:0][31:0] SIGMA = { + 32'd0, 32'd13, 32'd12, 32'd3, 32'd14, 32'd9, 32'd11, 32'd15, 32'd5, 32'd1, 32'd6, 32'd7, 32'd4, 32'd8, 32'd2, 32'd10, + 32'd5, 32'd10, 32'd4, 32'd1, 32'd7, 32'd13, 32'd2, 32'd12, 32'd8, 32'd0, 32'd3, 32'd11, 32'd9, 32'd14, 32'd15, 32'd6, + 32'd10, 32'd2, 32'd6, 32'd8, 32'd4, 32'd15, 32'd0, 32'd5, 32'd9, 32'd3, 32'd1, 32'd12, 32'd14, 32'd7, 32'd11, 32'd13, + 32'd11, 32'd8, 32'd2, 32'd9, 32'd3, 32'd6, 32'd7, 32'd0, 32'd10, 32'd4, 32'd13, 32'd14, 32'd15, 32'd1, 32'd5, 32'd12, + 32'd9, 32'd1, 32'd14, 32'd15, 32'd5, 32'd7, 32'd13, 32'd4, 32'd3, 32'd8, 32'd11, 32'd0, 32'd10, 32'd6, 32'd12, 32'd2, + 32'd13, 32'd3, 32'd8, 32'd6, 32'd12, 32'd11, 32'd1, 32'd14, 32'd15, 32'd10, 32'd4, 32'd2, 32'd7, 32'd5, 32'd0, 32'd9, + 32'd8, 32'd15, 32'd0, 32'd4, 32'd10, 32'd5, 32'd6, 32'd2, 32'd14, 32'd11, 32'd12, 32'd13, 32'd1, 32'd3, 32'd9, 32'd7, + 32'd4, 32'd9, 32'd1, 32'd7, 32'd6, 32'd3, 32'd14, 32'd10, 32'd13, 32'd15, 32'd2, 32'd5, 32'd0, 32'd12, 32'd8, 32'd11, + 32'd3, 32'd5, 32'd7, 32'd11, 32'd2, 32'd0, 32'd12, 32'd1, 32'd6, 32'd13, 32'd15, 32'd9, 32'd8, 32'd4, 32'd10, 32'd14, + 32'd15, 32'd14, 32'd13, 32'd12, 32'd11, 32'd10, 32'd9, 32'd8, 32'd7, 32'd6, 32'd5, 32'd4, 32'd3, 32'd2, 32'd1, 32'd0 + }; + + // Mapping for each G function block to the state vector v + parameter [4*8-1:0][31:0] G_MAPPING = { + 32'd14, 32'd9, 32'd4, 32'd3, + 32'd13, 32'd8, 32'd7, 32'd2, + 32'd12, 32'd11, 32'd6, 32'd1, + 32'd15, 32'd10, 32'd5, 32'd0, + 32'd15, 32'd11, 32'd7, 32'd3, + 32'd14, 32'd10, 32'd6, 32'd2, + 32'd13, 32'd9, 32'd5, 32'd1, + 32'd12, 32'd8, 32'd4, 32'd0 + }; + + // This is so we can get the correct mapping back from the diagonal + // operation + parameter [4*4-1:0][31:0] G_MAPPING_DIAG = { + 32'd3, 32'd15, 32'd11, 32'd7, + 32'd6, 32'd2, 32'd14, 32'd10, + 32'd9, 32'd5, 32'd1, 32'd13, + 32'd12, 32'd8 , 32'd4, 32'd0 + }; + +endpackage \ No newline at end of file diff --git a/ip_cores/blake2b/src/rtl/blake2b_top.sv b/ip_cores/blake2b/src/rtl/blake2b_top.sv new file mode 100644 index 0000000..60a28a9 --- /dev/null +++ b/ip_cores/blake2b/src/rtl/blake2b_top.sv @@ -0,0 +1,229 @@ +/* + Implemented from RFC-7693, The BLAKE2b Cryptographic Hash and Message Authentication Code (MAC) + Parameters are passed in as an input. Inputs and outputs are AXI stream and respect flow control. + Only only hash is computed at a time, and takes 26 clocks * number of 128 Byte message blocks. + Does not have functionalty to use a key. + + 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 . +*/ + +module blake2b_top + import blake2b_pkg::*; +( + input i_clk, i_rst, + + input [7:0] i_byte_len, // Length of the input message + input [64*8-1:0] i_parameters, // Input parameters used in the inital state. + + if_axi_stream.sink i_block, // Input block with valid and ready signals for flow control + if_axi_stream.source o_hash // Output digest with valid and ready signals for flow control +); + +enum {STATE_IDLE = 0, + STATE_ROUNDS = 1, + STATE_NEXT_BLOCK = 2, + STATE_FINAL_BLOCK = 3} blake2_state; + +localparam ROUNDS = 12; + +logic [7:0][63:0] h, h_tmp; // The state vector +logic [15:0][63:0] v, v_tmp; // The local work vector and its intermediate value +logic [31:0][63:0] g_out; // Outputs of the G mixing function - use 8 here to save on timing +logic [127:0] t; // Counter +logic [$clog2(ROUNDS)-1:0] round_cntr, round_cntr_msg, round_cntr_fin; +logic g_col; +logic [15:0][63:0] block, block_r; // The message block registered and converted to a 2d array +logic block_eop_l; // Use to latch if this is the final block +logic h_xor_done; +logic [7:0] byte_len_l; + +// Pipelining logic that has no reset +always_ff @(posedge i_clk) begin + + if (blake2_state == STATE_IDLE) + block_r <= 0; + + if (i_block.val && i_block.rdy) + block_r <= i_block.dat; + + for (int i = 0; i < 16; i++) begin + v_tmp[blake2b_pkg::G_MAPPING[i]] <= g_out[i]; + end + + for (int i = 0; i < 8; i++) + if (blake2_state == STATE_ROUNDS) + h_tmp[i] <= g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i]] ^ g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i+8]]; + +end + +always_comb begin + block = i_block.dat; +end + +// State machine logic for compressing +always_ff @(posedge i_clk) begin + if (i_rst) begin + blake2_state <= STATE_IDLE; + i_block.rdy <= 0; + h <= 0; + v <= 0; + t <= 128; + g_col <= 0; + round_cntr <= 0; + round_cntr_msg <= 0; + o_hash.reset_source(); + round_cntr_fin <= 0; + block_eop_l <= 0; + h_xor_done <= 0; + byte_len_l <= 0; + end else begin + + g_col <= ~g_col; + + case (blake2_state) + STATE_IDLE: begin + h <= i_parameters ^ blake2b_pkg::IV; + t <= 2; + i_block.rdy <= 1; + v <= 0; + o_hash.val <= 0; + g_col <= 0; + round_cntr <= 0; + round_cntr_msg <= 0; + round_cntr_fin <= 0; + if (i_block.rdy && i_block.val && i_block.sop) begin + init_local_work_vector(i_block.eop ? i_byte_len : 128, i_block.eop); + blake2_state <= STATE_ROUNDS; + g_col <= 0; + i_block.rdy <= 0; + block_eop_l <= i_block.eop; + byte_len_l <= i_byte_len; + end + end + // Here we do the compression over 12 rounds, each round can be done in two clock cycles + STATE_ROUNDS: begin + + // Update local work vector with output of G function blocks depending on column or diagonal operation + for (int i = 0; i < 16; i++) + v[i] <= g_out[16 + blake2b_pkg::G_MAPPING_DIAG[i]]; + + if (g_col) + round_cntr <= round_cntr + 1; + else + round_cntr_msg <= (round_cntr_msg + 1) % 10; + + if (round_cntr == ROUNDS-1) + round_cntr_fin <= 1; + + if (round_cntr_fin) begin + if (block_eop_l) + blake2_state <= STATE_FINAL_BLOCK; + else + blake2_state <= STATE_NEXT_BLOCK; + end + end + STATE_NEXT_BLOCK: begin + round_cntr <= 0; + round_cntr_msg <= 0; + round_cntr_fin <= 0; + h_xor_done <= 1; + i_block.rdy <= 1; + if (~h_xor_done) + for (int i = 0; i < 8; i++) + h[i] <= h[i] ^ h_tmp[i]; + if (i_block.rdy && i_block.val) begin + init_local_work_vector(i_block.eop ? byte_len_l : t*128, i_block.eop); + block_eop_l <= i_block.eop; + t <= t + 1; + blake2_state <= STATE_ROUNDS; + h_xor_done <= 0; + i_block.rdy <= 0; + g_col <= 0; + end + end + STATE_FINAL_BLOCK: begin + round_cntr <= 0; + round_cntr_fin <= 0; + round_cntr_msg <= 0; + if (~o_hash.val || (o_hash.val && o_hash.rdy)) begin + if (~o_hash.val) begin + o_hash.dat <= h ^ h_tmp; + o_hash.val <= 1; + o_hash.sop <= 1; + o_hash.eop <= 1; + end + if (o_hash.rdy) begin + blake2_state <= STATE_IDLE; + i_block.rdy <= 1; + end + end + end + endcase + end +end + +// 8x G-function blocks. 4 are col and 4 are diagonal +generate begin + genvar gv_g; + for (gv_g = 0; gv_g < 8; gv_g++) begin: G_FUNCTION_GEN + + // For each G function we want to pipeline the input message to help timing + logic [63:0] m0, m1; + always_ff @ (posedge i_clk) begin + if(blake2_state == STATE_IDLE || blake2_state == STATE_NEXT_BLOCK) begin + m0 <= block[blake2b_pkg::SIGMA[gv_g*2]]; + m1 <= block[blake2b_pkg::SIGMA[gv_g*2 + 1]]; + end else begin + m0 <= block_r[blake2b_pkg::SIGMA[16*round_cntr_msg + gv_g*2]]; + m1 <= block_r[blake2b_pkg::SIGMA[16*round_cntr_msg + gv_g*2 + 1]]; + end + end + + blake2b_g + #(.PIPELINES(0)) + blake2b_g ( + .i_clk(i_clk), + .i_a(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 0)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 0)]]), + .i_b(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 1)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 1)]]), + .i_c(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 2)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 2)]]), + .i_d(gv_g < 4 ? v[blake2b_pkg::G_MAPPING[(gv_g*4 + 3)]] : v_tmp[blake2b_pkg::G_MAPPING[(gv_g*4 + 3)]]), + .i_m0(m0), + .i_m1(m1), + .o_a(g_out[gv_g*4 + 0]), + .o_b(g_out[gv_g*4 + 1]), + .o_c(g_out[gv_g*4 + 2]), + .o_d(g_out[gv_g*4 + 3])); + + end +end +endgenerate + +// Task to initialize local work vector for the compression function +task init_local_work_vector(input [127:0] cntr, input last_block); +begin + for (int i = 0; i < 16; i++) + case (i) inside + 0,1,2,3,4,5,6,7: v[i] <= h[i]; + 8,9,10,11: v[i] <= blake2b_pkg::IV[i%8]; + 12: v[i] <= blake2b_pkg::IV[i%8] ^ cntr[63:0]; + 13: v[i] <= blake2b_pkg::IV[i%8] ^ cntr[64 +: 64]; + 14: v[i] <= blake2b_pkg::IV[i%8] ^ {64{last_block}}; + 15: v[i] <= blake2b_pkg::IV[i%8]; + endcase +end +endtask + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/tb/blake2b_g_tb.sv b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv new file mode 100644 index 0000000..8a47e82 --- /dev/null +++ b/ip_cores/blake2b/src/tb/blake2b_g_tb.sv @@ -0,0 +1,65 @@ +/* + The BLAKE2b g function testbench. + + 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 . +*/ + +module blake2b_g_tb(); + +logic clk; +logic [63:0] o_a, o_b, o_c, o_d, i_a, i_b, i_c, i_d, i_m0, i_m1; +localparam PIPELINES = 1; + +blake2b_g #(.PIPELINES(PIPELINES)) DUT (.i_clk(clk), .o_a(o_a), .o_b(o_b), .o_c(o_c), .o_d(o_d), .i_a(i_a), .i_b(i_b), .i_c(i_c), .i_d(i_d), .i_m0(i_m0), .i_m1(i_m1)); + +initial begin + clk = 0; + forever #10ns clk = ~clk; +end + +task test1(); +begin + @(posedge clk) + i_a = 64'h6a09e667f2bdc948; + i_b = 64'h510e527fade682d1; + i_c = 64'h6a09e667f3bcc908; + i_d = 64'h510e527fade68251; + i_m0 = 64'h0000000000000000; + i_m1 = 64'h0000000000000000; + + repeat (PIPELINES) @(posedge clk); + + #1; + assert (o_a == 64'hf0c9aa0de38b1b89) else $fatal(0, "%m %t:ERROR, o_a did not match", $time); + assert (o_b == 64'hbbdf863401fde49b) else $fatal(0, "%m %t:ERROR, o_b did not match", $time); + assert (o_c == 64'he85eb23c42183d3d) else $fatal(0, "%m %t:ERROR, o_c did not match", $time); + assert (o_d == 64'h7111fd8b6445099d) else $fatal(0, "%m %t:ERROR, o_d did not match", $time); + + $display("test1 PASSED"); +end +endtask + +// Main testbench calls + +initial begin + #100ns; + test1(); + + #100ns $finish(); + +end + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/src/tb/blake2b_top_tb.sv b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv new file mode 100644 index 0000000..c768b60 --- /dev/null +++ b/ip_cores/blake2b/src/tb/blake2b_top_tb.sv @@ -0,0 +1,133 @@ +/* + The BLAKE2b testbench. + + 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 . +*/ + +module blake2b_top_tb(); + +parameter USE_BLAKE2B_PIPE = 1; // This instantiates the pipelined version instead +parameter USE_BLAKE2B_PIPE_MSG_LEN = 3; + +import blake2b_pkg::*; +import common_pkg::*; + +logic clk, rst; +logic [7:0] i_byte_len; +logic [64*8-1:0] parameters; + +logic [64*8-1:0] expected; +if_axi_stream #(.DAT_BYTS(USE_BLAKE2B_PIPE == 0 ? 128 : USE_BLAKE2B_PIPE_MSG_LEN)) i_block(clk); +if_axi_stream #(.DAT_BYTS(64)) out_hash(clk); + +initial begin + rst = 0; + #100ns rst = 1; + #100ns rst = 0; +end + +initial begin + clk = 0; + forever #10ns clk = ~clk; +end + +generate if ( USE_BLAKE2B_PIPE == 0 ) begin: DUT_GEN + blake2b_top DUT ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_parameters ( parameters ), + .i_byte_len ( i_byte_len ), + .i_block ( i_block ), + .o_hash ( out_hash ) + ); +end else begin + blake2b_pipe_top #( + .MSG_LEN ( 3 ), + .CTL_BITS ( 8 ) + ) + DUT ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_parameters ( parameters ), + .i_byte_len ( i_byte_len ), + .i_block ( i_block ), + .o_hash ( out_hash ) + ); +end +endgenerate + +// This test runs the hash which is shown in the RFC, for "abc" +task rfc_test(); +begin + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + $display("Running rfc_test...\n"); + expected = 'h239900d4ed8623b95a92f1dba88ad31895cc3345ded552c22d79ab2a39c5877dd1a2ffdb6fbb124bb7c45a68142f214ce9f6129fb697276a0d4d1c983fa580ba; + i_byte_len = 3; + i_block.put_stream("cba", i_byte_len); + out_hash.get_stream(get_dat, get_len); + common_pkg::compare_and_print(get_dat, expected); + $display("rfc_test PASSED"); +end +endtask + +// This is a test for hashing random string of 128 bytes +task test_128_bytes(); +begin + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + $display("Running test_128_bytes..."); + expected = 'hd2a56bb7bb1ff1fffcf2f151522455e32969ddfeb409b105f45299b8cbd68eb370fd6d45d63981d23cd2686dfd9a76f5b1d134be076f7d08ecc457522042e34a; + i_byte_len = 128; + i_block.put_stream("monek14SFMpNgHz12zMfplMfcHkx6JhKhSWTNwzGiq8UiPa4n4Ehq363oHG92GPDVpvQut4ui5e6XxieeKTn1THLWiMZ0iaOFndxcT6FGPgmHXQ5zJU96X71zfWbvUQs", i_byte_len); + out_hash.get_stream(get_dat, get_len); + common_pkg::compare_and_print(get_dat, expected); + $display("test_128_bytes PASSED"); +end +endtask + +// This is a test for hashing random string of 140 bytes (does two passes which is required for equihash) +task test_140_bytes(); +begin + integer signed get_len; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat; + $display("Running test_140_bytes..."); + expected = 'h2012a869a3b89a69ffc954f6855c7f61a61190553dc487171ec3fe944d04c83cd4c842fff5a8258d5e14b05b7b6f30e8ddcb754d719137ec42fb5cdb562f8c89; + i_byte_len = 140; + i_block.put_stream("YbEAEzgJ1tgC3t6vDaJFqlWp1PaL482f7iZZzRj3xXpY2PPupwdTKAaBzB6KuN6j0alaoaFQfNboDbkNv5KDs5d7zN9JssrtOjGJdrVLfvb7uAdnVYoIgIv2zbXUQIPpwWdzEzj1CzX5", i_byte_len); + out_hash.get_stream(get_dat, get_len); + common_pkg::compare_and_print(get_dat, expected); + $display("test_140_bytes PASSED"); +end +endtask + +// Main testbench calls +initial begin + i_block.reset_source(); + i_byte_len = 3; + out_hash.rdy = 1; + parameters = {32'd0, 8'd1, 8'd1, 8'd0, 8'd64}; + #200ns; + + rfc_test(); + // test_128_bytes(); + // test_140_bytes(); + + #10us $finish(); + +end + +endmodule \ No newline at end of file diff --git a/ip_cores/blake2b/synth/blake2b_top.xdc b/ip_cores/blake2b/synth/blake2b_top.xdc new file mode 100644 index 0000000..933adcc --- /dev/null +++ b/ip_cores/blake2b/synth/blake2b_top.xdc @@ -0,0 +1 @@ +create_clock -period 5.000 -name i_clk -waveform {0.000 2.500} [get_ports -filter { NAME =~ "i_clk" && DIRECTION == "IN" }] diff --git a/ip_cores/common/src/rtl/common_if.sv b/ip_cores/common/src/rtl/common_if.sv new file mode 100644 index 0000000..756b489 --- /dev/null +++ b/ip_cores/common/src/rtl/common_if.sv @@ -0,0 +1,98 @@ +/* + Interface for a AXI stream + + 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 . +*/ + +interface if_axi_stream # ( + parameter DAT_BYTS = 128, + parameter CTL_BYTS = 8 +)( + input clk +); + import common_pkg::*; + localparam DAT_BITS = DAT_BYTS*8; + localparam CTL_BITS = CTL_BYTS*8; + + logic rdy; + logic val; + logic err; + logic sop; + logic eop; + logic [CTL_BITS-1:0] ctl; + logic [DAT_BITS-1:0] dat; + logic [$clog2(DAT_BYTS)-1:0] mod; + + modport sink (input val, err, sop, eop, ctl, dat, mod, output rdy); + modport source (output val, err, sop, eop, ctl, dat, mod, input rdy, import task reset_source()); + + // Task to reset a source interface signals to all 0 + task reset_source(); + val <= 0; + err <= 0; + sop <= 0; + eop <= 0; + dat <= 0; + ctl <= 0; + mod <= 0; + endtask + + // Task used in simulation to drive data on a source interface + task automatic put_stream(input logic [common_pkg::MAX_SIM_BYTS*8-1:0] data, input integer signed len); + logic sop_l=0; + + reset_source(); + @(posedge clk); + + while (len > 0) begin + sop = ~sop_l; + eop = len - DAT_BYTS <= 0; + val = 1; + dat = data; + if (eop) mod = len; + data = data >> DAT_BITS; + sop_l = 1; + len = len - DAT_BYTS; + @(posedge clk); // Go to next clock edge + while (!rdy) @(posedge clk); // If not rdy then wait here + end + reset_source(); + endtask + + // Task used in simulation to get data from a sink interface + task automatic get_stream(ref logic [common_pkg::MAX_SIM_BYTS*8-1:0] data, ref integer signed len); + logic sop_l = 0; + rdy = 1; + len = 0; + data = 0; + @(posedge clk); + + while (1) begin + if (val && rdy) begin + sop_l = sop_l || sop; + if (!sop_l) $warning("%m %t:WARNING, get_stream() .val without seeing .sop", $time); + data[len*8 +: DAT_BITS] = dat; + len = len + (eop ? (mod == 0 ? DAT_BYTS : mod) : DAT_BYTS); + if (eop) break; + end + @(posedge clk); + end + + + endtask + + +endinterface \ No newline at end of file diff --git a/ip_cores/common/src/rtl/common_pkg.sv b/ip_cores/common/src/rtl/common_pkg.sv new file mode 100644 index 0000000..9887a10 --- /dev/null +++ b/ip_cores/common/src/rtl/common_pkg.sv @@ -0,0 +1,42 @@ +/* + Common parameter values and tasks + + 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 . +*/ + +package common_pkg; + parameter MAX_SIM_BYTS = 1024; // 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); + if (data == expected) begin + $display("%m %t INFO: Data matched", $time); + end else begin + $write("exp: 0x"); + while(expected != 0) begin + $write("%x", expected[7:0]); + expected = expected >> 8; + end + $write("\nwas: 0x"); + while(data != 0) begin + $write("%x", data[7:0]); + data = data >> 8; + end + $write("\n"); + $fatal(1, "%m %t ERROR: data did not match", $time); + end + endtask +endpackage \ No newline at end of file diff --git a/ip_cores/fifo/src/rtl/axi_stream_fifo.sv b/ip_cores/fifo/src/rtl/axi_stream_fifo.sv new file mode 100644 index 0000000..efeccdd --- /dev/null +++ b/ip_cores/fifo/src/rtl/axi_stream_fifo.sv @@ -0,0 +1,70 @@ +/* + This is a simple FIFO implementation using AXI stream source and sink interfaces. + It has a single clock delay from i_axi to o_axi in the case of an empty FIFO. + Only works with power of 2 A_BITS + + 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 . +*/ + +module axi_stream_fifo #( + parameter A_BITS, + parameter DAT_BITS, + parameter CTL_BITS +) ( + input i_clk, i_rst, + if_axi_stream.sink i_axi, + if_axi_stream.source o_axi +); + +localparam MOD_BITS = $clog2(DAT_BITS/8); + +logic [$clog2(A_BITS):0] rd_ptr, wr_ptr; +logic empty, full; + +logic [A_BITS-1:0][DAT_BITS + CTL_BITS + MOD_BITS + 3 -1:0] ram; + +// Control for full and empty, and assigning outputs from the ram +always_comb begin + empty = (rd_ptr == wr_ptr); + full = (wr_ptr == rd_ptr - 1); + i_axi.rdy = ~full; + o_axi.dat = ram[rd_ptr][0 +: DAT_BITS]; + o_axi.ctl = ram[rd_ptr][DAT_BITS +: CTL_BITS]; + o_axi.mod = ram[rd_ptr][CTL_BITS+DAT_BITS +: MOD_BITS]; + o_axi.sop = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS +: 1]; + o_axi.eop = ram[rd_ptr][CTL_BITS+DAT_BITS+MOD_BITS+1 +: 1]; + o_axi.val = ~empty; +end + +// Logic for writing and reading from ram without reset +always_ff @ (posedge i_clk) begin + if (i_axi.val && i_axi.rdy) begin + ram [wr_ptr] <= {i_axi.eop, i_axi.sop, i_axi.mod, i_axi.ctl, i_axi.dat}; + end +end + +// Control logic which requires a reset +always_ff @ (posedge i_clk) begin + if (i_rst) begin + rd_ptr <= 0; + wr_ptr <= 0; + end else begin + wr_ptr <= i_axi.val && i_axi.rdy ? (wr_ptr + 1) : wr_ptr; + rd_ptr <= o_axi.val && o_axi.rdy ? (rd_ptr + 1) : rd_ptr; + end +end + +endmodule \ No newline at end of file diff --git a/ip_cores/parsing/src/rtl/file_to_axi.sv b/ip_cores/parsing/src/rtl/file_to_axi.sv new file mode 100644 index 0000000..f7ad9d8 --- /dev/null +++ b/ip_cores/parsing/src/rtl/file_to_axi.sv @@ -0,0 +1,67 @@ +/* + This reads a binary or ASCII file and creates an AXI stream, + used for testbench purposes. Can optionally add in random flow control. + + Only binary is supported at this moment. + + 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 . +*/ + +module file_to_axi #( + parameter HDR_BYTS, + parameter DAT_BYTS, + parameter BINARY, // 0 for ASCII, 1 for binary + parameter string FILE = "", // Path to file + parameter FP = 0 // Forward pressure, if this is non-zero then this is the % of cycles o_axi.val will be low +) ( + input i_clk, i_rst, + if_axi_stream.source o_axi +); + + +logic [DAT_BYTS*8-1:0] data_temp; +integer fp, r; +logic sop_l; + +initial begin + o_axi.reset_source(); + sop_l = 0; + fp = $fopen(FILE, BINARY ? "rb" : "r"); + if (fp==0) $fatal(1, "%m %t ERROR: file_to_axi could not open file %s", $time, FILE); + + if (BINARY == 0) begin + $fatal(1, "%m %t ERROR: file_to_axi BINARY == 0 not supported", $time); + end else begin + while(!$feof(fp)) begin + r = $fread(o_axi.dat, fp); + o_axi.val = 1; // TODO + o_axi.sop = ~sop_l; + sop_l = 1; + o_axi.eop = $feof(fp); + o_axi.mod = $feof(fp) ? r : 0; + + @(posedge o_axi.clk); + while (!(o_axi.val && o_axi.rdy)) @(posedge o_axi.clk); + end + end + + + o_axi.reset_source(); + $display("%m %t INFO: file_to_axi finished reading file %s", $time, FILE); + $fclose(fp); +end + +endmodule \ No newline at end of file diff --git a/ip_cores/parsing/src/rtl/header_adder.sv b/ip_cores/parsing/src/rtl/header_adder.sv new file mode 100644 index 0000000..bcbc391 --- /dev/null +++ b/ip_cores/parsing/src/rtl/header_adder.sv @@ -0,0 +1,67 @@ +/* + This takes in a AXI stream, appends a header, and outputs the resulting stream. + + 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 . +*/ + +module header_adder #( + parameter HDR_BYTS, + parameter DAT_BYTS +) ( + input i_clk, i_rst, + + input [HDR_BYTS*8-1:0] i_header, // Must be valid during i_axi.val + if_axi_stream.sink i_axi, + if_axi_stream.source o_axi +); + +logic [(DAT_BYTS+(HDR_BYTS % DAT_BYTS))*8-1:0] dat_buff; +logic sop_l; +logic [$clog2(HDR_BYTS)-1:0] hdr_cnt; + +always_comb begin + i_axi.dat = dat_buff[HDR_BYTS*8 +: DAT_BYTS*8]; +end + +always_ff @ (posedge i_clk) begin + if (i_rst) begin + dat_buff <= 0; + hdr_cnt <= 0; + i_axi.rdy <= 0; + sop_l <= 0; + o_axi.reset_source(); + end else begin + i_axi.rdy <= o_axi.rdy && (hdr_cnt + DAT_BYTS >= HDR_BYTS); + if (~o_axi.val || (~o_axi.val && o_axi.rdy)) begin + o_axi.sop <= ~sop_l; + o_axi.val <= i_axi.val; + o_axi.err <= i_axi.err; + o_axi.ctl <= i_axi.ctl; + o_axi.mod <= (i_axi.mod + HDR_BYTS) % DAT_BYTS; + o_axi.eop <= i_axi.eop; + hdr_cnt <= (hdr_cnt + DAT_BYTS >= HDR_BYTS) ? hdr_cnt : hdr_cnt + DAT_BYTS; + sop_l <= i_axi.sop; + //TODO + dat_buff <= {dat_buff[0 +: (HDR_BYTS % DAT_BYTS)*8], i_axi.dat}; + + + if (i_axi.eop) hdr_cnt <= 0; + + end + end +end + +endmodule \ No newline at end of file diff --git a/zcash_verif/README.md b/zcash_verif/README.md new file mode 100644 index 0000000..9b9b52b --- /dev/null +++ b/zcash_verif/README.md @@ -0,0 +1 @@ +This is the design for verifing the Zcash blockchain on an FPGA diff --git a/zcash_verif/src/data/block_241.bin b/zcash_verif/src/data/block_241.bin new file mode 100644 index 0000000..fbb4089 Binary files /dev/null and b/zcash_verif/src/data/block_241.bin differ diff --git a/zcash_verif/src/rtl/zcash_verif_pkg.sv b/zcash_verif/src/rtl/zcash_verif_pkg.sv new file mode 100644 index 0000000..8a4dfc9 --- /dev/null +++ b/zcash_verif/src/rtl/zcash_verif_pkg.sv @@ -0,0 +1,22 @@ +/* + Parameter values and tasks for the verification system. + + 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 . +*/ + +package zcash_verif_pkg; + +endpackage \ No newline at end of file diff --git a/zcash_verif/src/rtl/zcash_verif_system.sv b/zcash_verif/src/rtl/zcash_verif_system.sv new file mode 100644 index 0000000..33094c2 --- /dev/null +++ b/zcash_verif/src/rtl/zcash_verif_system.sv @@ -0,0 +1,69 @@ +/* + This takes in an AXI stream of a block and runs verification + checks (detailed in the architecture document). When all the checks are + completed the o_val will go high, and o_mask bit mask will be 1 for any + checks that failed. + + 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 . + */ + +module zcash_verif_system( + input i_clk, i_rst, + + if_axi_stream.sink i_axi, + output logic [31:0] o_mask, + output logic o_val +); + +if_axi_stream #(.DAT_BYTS(128)) blake2b_in(clk); +if_axi_stream #(.DAT_BYTS(64)) blake2b_out(clk); + + +always_ff @ (posedge i_clk) begin + i_data.rdy <= blake2b_in.rdy; + blake2b_in.val <= i_data.val; + blake2b_in.sop <= i_data.sop; + blake2b_in.eop <= i_data.eop; + blake2b_in.dat <= i_data.dat; + blake2b_in.err <= 0; + blake2b_in.mod <= 0; + blake2b_in.ctl <= 0; + + blake2b_out.rdy <= 1; + o_valid <= (blake2b_out.val && blake2b_out.dat == {64{1'b1}}); +end + + +// The Blake2 core for generating hashes + +logic [64*8-1:0] blake2_parameters; +always_comb begin + blake2_parameters = {32'd0, 8'd1, 8'd1, 8'd0, 8'd64}; +end + +blake2_top #( + .EQUIHASH( 1 ) +) +blake2_top ( + .i_clk ( i_clk ), + .i_rst ( i_rst ), + .i_byte_len ( 8'd128 ), + .i_parameters ( blake2_parameters ), + .i_block ( blake2b_in ), + .o_hash ( blake2b_out ) +); + +endmodule \ No newline at end of file diff --git a/zcash_verif/synth/zcash_verif_top.xdc b/zcash_verif/synth/zcash_verif_top.xdc new file mode 100644 index 0000000..b99f66e --- /dev/null +++ b/zcash_verif/synth/zcash_verif_top.xdc @@ -0,0 +1 @@ +create_clock -period 5.000 -name i_clk -waveform {0.000 2.500} [get_ports -filter { NAME =~ "*i_clk*" && DIRECTION == "IN" }]