├── FPGA ├── sha256d.srcs │ ├── constrs_1 │ │ └── new │ │ │ └── sha256_constraints.xdc │ ├── sim_1 │ │ └── new │ │ │ └── sha256d_tb.vhd │ └── sources_1 │ │ ├── bd │ │ └── soc │ │ │ ├── hdl │ │ │ └── soc_wrapper.vhd │ │ │ └── soc.bd │ │ ├── ip │ │ └── clk_wiz_0 │ │ │ └── clk_wiz_0.xci │ │ └── new │ │ ├── miner_top.vhd │ │ ├── pulse_cdc.vhd │ │ ├── sha256_digester.vhd │ │ ├── sha256_transform.vhd │ │ └── sha256d_wrapper.vhd └── sha256d.tcl ├── README.md ├── fpgaminer.py ├── merkle_test.py ├── overlays ├── miner_top.bit ├── miner_top.hwh └── miner_top.tcl └── sha256d_fpga_sim.py /FPGA/sha256d.srcs/constrs_1/new/sha256_constraints.xdc: -------------------------------------------------------------------------------- 1 | ## This file is a general .xdc for the PYNQ-Z2 board 2 | ## To use it in a project: 3 | ## - uncomment the lines corresponding to used pins 4 | ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project 5 | 6 | 7 | ## Create clocks 8 | 9 | create_clock -name {clk_125m} -period 8.00 [get_ports {CLK_125M}] 10 | create_generated_clock -name {clk_hash} [get_pins mmcm_clk_hash/clk_out1] 11 | 12 | create_clock -name {clk_avl} -period 20.00 [get_pins {u_soc_wrapper/soc_i/processing_system7_0/inst/PS7_i/FCLKCLK[0]}] 13 | create_generated_clock -name {clk_hash_1} [get_pins {mmcm_clk_hash/inst/mmcm_adv_inst/CLKOUT0}] 14 | 15 | ## Clock groups 16 | 17 | set_clock_groups -asynchronous \ 18 | -group {clk_125m} \ 19 | -group {clk_hash} \ 20 | -group {clk_hash_1} \ 21 | -group {clk_avl} 22 | 23 | #set_clock_groups -asynchronous \ 24 | #-group {clk_fpga_0} \ 25 | #-group {clk_fpga_1} \ 26 | 27 | 28 | ## Clock signal 125 MHz 29 | 30 | set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { CLK_125M }]; #IO_L13P_T2_MRCC_35 Sch=sysclk 31 | #create_clock -add -name clk_125m_pin -period 8.00 -waveform {0 4} [get_ports { CLK_125M }]; 32 | 33 | ##Switches 34 | 35 | #set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { sw[0] }]; #IO_L7N_T1_AD2N_35 Sch=sw[0] 36 | #set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { sw[1] }]; #IO_L7P_T1_AD2P_35 Sch=sw[1] 37 | 38 | ##RGB LEDs 39 | 40 | #set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports { led4_b }]; #IO_L22N_T3_AD7N_35 Sch=led4_b 41 | #set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led4_g }]; #IO_L16P_T2_35 Sch=led4_g 42 | #set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { led4_r }]; #IO_L21P_T3_DQS_AD14P_35 Sch=led4_r 43 | #set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { led5_b }]; #IO_0_35 Sch=led5_b 44 | #set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { led5_g }]; #IO_L22P_T3_AD7P_35 Sch=led5_g 45 | #set_property -dict { PACKAGE_PIN M15 IOSTANDARD LVCMOS33 } [get_ports { led5_r }]; #IO_L23N_T3_35 Sch=led5_r 46 | 47 | ##LEDs 48 | 49 | #set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { LED[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0] 50 | #set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { LED[1] }]; #IO_L6P_T0_34 Sch=led[1] 51 | #set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { LED[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2] 52 | #set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { LED[3] }]; #IO_L23P_T3_35 Sch=led[3] 53 | 54 | ##Buttons 55 | 56 | #set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; #IO_L4P_T0_35 Sch=btn[0] 57 | #set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; #IO_L4N_T0_35 Sch=btn[1] 58 | #set_property -dict { PACKAGE_PIN L20 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L9N_T1_DQS_AD3N_35 Sch=btn[2] 59 | #set_property -dict { PACKAGE_PIN L19 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L9P_T1_DQS_AD3P_35 Sch=btn[3] 60 | 61 | ##PmodA 62 | 63 | #set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { ja[0] }]; #IO_L17P_T2_34 Sch=ja_p[1] 64 | #set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { ja[1] }]; #IO_L17N_T2_34 Sch=ja_n[1] 65 | #set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { ja[2] }]; #IO_L7P_T1_34 Sch=ja_p[2] 66 | #set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports { ja[3] }]; #IO_L7N_T1_34 Sch=ja_n[2] 67 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ja[4] }]; #IO_L12P_T1_MRCC_34 Sch=ja_p[3] 68 | #set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { ja[5] }]; #IO_L12N_T1_MRCC_34 Sch=ja_n[3] 69 | #set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { ja[6] }]; #IO_L22P_T3_34 Sch=ja_p[4] 70 | #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { ja[7] }]; #IO_L22N_T3_34 Sch=ja_n[4] 71 | 72 | ##PmodB 73 | 74 | #set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { jb[0] }]; #IO_L8P_T1_34 Sch=jb_p[1] 75 | #set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS33 } [get_ports { jb[1] }]; #IO_L8N_T1_34 Sch=jb_n[1] 76 | #set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { jb[2] }]; #IO_L1P_T0_34 Sch=jb_p[2] 77 | #set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { jb[3] }]; #IO_L1N_T0_34 Sch=jb_n[2] 78 | #set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { jb[4] }]; #IO_L18P_T2_34 Sch=jb_p[3] 79 | #set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { jb[5] }]; #IO_L18N_T2_34 Sch=jb_n[3] 80 | #set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { jb[6] }]; #IO_L4P_T0_34 Sch=jb_p[4] 81 | #set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { jb[7] }]; #IO_L4N_T0_34 Sch=jb_n[4] 82 | 83 | ##Audio 84 | 85 | #set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { adr0 }]; #IO_L8P_T1_AD10P_35 Sch=adr0 86 | #set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { adr1 }]; #IO_L8N_T1_AD10N_35 Sch=adr1 87 | 88 | #set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { au_mclk_r }]; #IO_L19N_T3_VREF_13 Sch=au_mclk_r 89 | #set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { au_sda_r }]; #IO_L12P_T1_MRCC_13 Sch=au_sda_r 90 | #set_property -dict { PACKAGE_PIN U9 IOSTANDARD LVCMOS33 } [get_ports { au_scl_r }]; #IO_L17P_T2_13 Sch= au_scl_r 91 | #set_property -dict { PACKAGE_PIN F17 IOSTANDARD LVCMOS33 } [get_ports { au_dout_r }]; #IO_L6N_T0_VREF_35 Sch=au_dout_r 92 | #set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { au_din_r }]; #IO_L16N_T2_35 Sch=au_din_r 93 | #set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { au_wclk_r }]; #IO_L20P_T3_34 Sch=au_wclk_r 94 | #set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { au_bclk_r }]; #IO_L20N_T3_34 Sch=au_bclk_r 95 | 96 | 97 | ## Single Ended Analog Inputs 98 | ##NOTE: The ar_an_p pins can be used as single ended analog inputs with voltages from 0-3.3V (Arduino Analog pins a[0]-a[5]). 99 | ## These signals should only be connected to the XADC core. When using these pins as digital I/O, use pins a[0]-a[5]. 100 | 101 | #set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { ar_an0_p }]; #IO_L3P_T0_DQS_AD1P_35 Sch=ar_an0_p 102 | #set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { ar_an0_n }]; #IO_L3P_T0_DQS_AD1P_35 Sch=ar_an0_n 103 | #set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { ar_an1_p }]; #IO_L5N_T0_AD9P_35 Sch=ar_an1_p 104 | #set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { ar_an1_n }]; #IO_L5N_T0_AD9N_35 Sch=ar_an1_n 105 | #set_property -dict { PACKAGE_PIN K14 IOSTANDARD LVCMOS33 } [get_ports { ar_an2_p }]; #IO_L20P_T3_AD6P_35 Sch=ar_an2_p 106 | #set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { ar_an2_n }]; #IO_L20P_T3_AD6N_35 Sch=ar_an2_n 107 | #set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { ar_an3_p }]; #IO_L24P_T3_AD15P_35 Sch=ar_an3_p 108 | #set_property -dict { PACKAGE_PIN J16 IOSTANDARD LVCMOS33 } [get_ports { ar_an3_n }]; #IO_L24P_T3_AD15N_35 Sch=ar_an3_n 109 | #set_property -dict { PACKAGE_PIN J20 IOSTANDARD LVCMOS33 } [get_ports { ar_an4_p }]; #IO_L17P_T2_AD5P_35 Sch=ar_an4_p 110 | #set_property -dict { PACKAGE_PIN H20 IOSTANDARD LVCMOS33 } [get_ports { ar_an4_n }]; #IO_L17P_T2_AD5P_35 Sch=ar_an4_n 111 | #set_property -dict { PACKAGE_PIN G19 IOSTANDARD LVCMOS33 } [get_ports { ar_an5_p }]; #IO_L18P_T2_AD13P_35 Sch=ar_an5_p 112 | #set_property -dict { PACKAGE_PIN G20 IOSTANDARD LVCMOS33 } [get_ports { ar_an5_n }]; #IO_L18P_T2_AD13P_35 Sch=ar_an5_n 113 | 114 | ##Arduino Digital I/O 115 | 116 | #set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ar[0] }]; #IO_L5P_T0_34 Sch=ar[0] 117 | #set_property -dict { PACKAGE_PIN U12 IOSTANDARD LVCMOS33 } [get_ports { ar[1] }]; #IO_L2N_T0_34 Sch=ar[1] 118 | #set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { ar[2] }]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=ar[2] 119 | #set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { ar[3] }]; #IO_L3N_T0_DQS_34 Sch=ar[3] 120 | #set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ar[4] }]; #IO_L10P_T1_34 Sch=ar[4] 121 | #set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ar[5] }]; #IO_L5N_T0_34 Sch=ar[5] 122 | #set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ar[6] }]; #IO_L19P_T3_34 Sch=ar[6] 123 | #set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ar[7] }]; #IO_L9N_T1_DQS_34 Sch=ar[7] 124 | #set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ar[8] }]; #IO_L21P_T3_DQS_34 Sch=ar[8] 125 | #set_property -dict { PACKAGE_PIN V18 IOSTANDARD LVCMOS33 } [get_ports { ar[9] }]; #IO_L21N_T3_DQS_34 Sch=ar[9] 126 | #set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ar[10] }]; #IO_L9P_T1_DQS_34 Sch=ar[10] 127 | #set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ar[11] }]; #IO_L19N_T3_VREF_34 Sch=ar[11] 128 | #set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ar[12] }]; #IO_L23N_T3_34 Sch=ar[12] 129 | #set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ar[13] }]; #IO_L23P_T3_34 Sch=ar[13] 130 | #set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS33 } [get_ports { a }]; #IO_L20N_T3_13 Sch=a 131 | 132 | ##Arduino Digital I/O On Outer Analog Header 133 | ##NOTE: These pins should be used when using the analog header signals A0-A5 as digital I/O 134 | 135 | #set_property -dict { PACKAGE_PIN Y11 IOSTANDARD LVCMOS33 } [get_ports { a[0] }]; #IO_L18N_T2_13 Sch=a[0] 136 | #set_property -dict { PACKAGE_PIN Y12 IOSTANDARD LVCMOS33 } [get_ports { a[1] }]; #IO_L20P_T3_13 Sch=a[1] 137 | #set_property -dict { PACKAGE_PIN W11 IOSTANDARD LVCMOS33 } [get_ports { a[2] }]; #IO_L18P_T2_13 Sch=a[2] 138 | #set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { a[3] }]; #IO_L21P_T3_DQS_13 Sch=a[3] 139 | #set_property -dict { PACKAGE_PIN T5 IOSTANDARD LVCMOS33 } [get_ports { a[4] }]; #IO_L19P_T3_13 Sch=a[4] 140 | #set_property -dict { PACKAGE_PIN U10 IOSTANDARD LVCMOS33 } [get_ports { a[5] }]; #IO_L12N_T1_MRCC_13 Sch=a[5] 141 | 142 | ## Arduino SPI 143 | 144 | #set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L10N_T1_34 Sch=miso 145 | #set_property -dict { PACKAGE_PIN T12 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L2P_T0_34 Sch=ar_mosi_r 146 | #set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L19P_T3_35 Sch=sck 147 | #set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L6P_T0_35 Sch=ss 148 | 149 | ## Arduino I2C 150 | 151 | #set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { ar_scl }]; #IO_L24N_T3_34 Sch=ar_scl 152 | #set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ar_sda }]; #IO_L24P_T3_34 Sch=ar_sda 153 | 154 | ##Raspberry Digital I/O 155 | 156 | #set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { rpio_02_r }]; #IO_L22P_T3_34 Sch=rpio_02_r 157 | #set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { rpio_03_r }]; #IO_L22N_T3_34 Sch=rpio_03_r 158 | #set_property -dict { PACKAGE_PIN Y18 IOSTANDARD LVCMOS33 } [get_ports { rpio_04_r }]; #IO_L17P_T2_34 Sch=rpio_04_r 159 | #set_property -dict { PACKAGE_PIN Y19 IOSTANDARD LVCMOS33 } [get_ports { rpio_05_r }]; #IO_L17N_T2_34 Sch=rpio_05_r 160 | #set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { rpio_06_r }]; #IO_L22P_T3_13 Sch=rpio_06_r 161 | #set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { rpio_07_r }]; #IO_L12P_T1_MRCC_34 Sch=rpio_07_r 162 | #set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports { rpio_08_r }]; #IO_L12N_T1_MRCC_34 Sch=rpio_08_r 163 | #set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { rpio_09_r }]; #IO_L21N_T3_DQS_13 Sch=rpio_09_r 164 | #set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { rpio_10_r }]; #IO_L15P_T2_DQS_13 Sch=rpio_10_r 165 | #set_property -dict { PACKAGE_PIN W10 IOSTANDARD LVCMOS33 } [get_ports { rpio_11_r }]; #IO_L16P_T2_13 Sch=rpio_11_r 166 | #set_property -dict { PACKAGE_PIN B20 IOSTANDARD LVCMOS33 } [get_ports { rpio_12_r }]; #IO_L1N_T0_AD0N_35 Sch=rpio_12_r 167 | #set_property -dict { PACKAGE_PIN W8 IOSTANDARD LVCMOS33 } [get_ports { rpio_13_r }]; #IO_L15N_T2_DQS_13 Sch=rpio_13_r 168 | #set_property -dict { PACKAGE_PIN V6 IOSTANDARD LVCMOS33 } [get_ports { rpio_14_r }]; #IO_L22P_T3_13 Sch=rpio_14_r 169 | #set_property -dict { PACKAGE_PIN Y6 IOSTANDARD LVCMOS33 } [get_ports { rpio_15_r }]; #IO_L13N_T2_MRCC_13 Sch=rpio_15_r 170 | #set_property -dict { PACKAGE_PIN B19 IOSTANDARD LVCMOS33 } [get_ports { rpio_16_r }]; #IO_L2P_T0_AD8P_35 Sch=rpio_16_r 171 | #set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { rpio_17_r }]; #IO_L11P_T1_SRCC_13 Sch=rpio_17_r 172 | #set_property -dict { PACKAGE_PIN C20 IOSTANDARD LVCMOS33 } [get_ports { rpio_18_r }]; #IO_L1P_T0_AD0P_35 Sch=rpio_18_r 173 | #set_property -dict { PACKAGE_PIN Y8 IOSTANDARD LVCMOS33 } [get_ports { rpio_19_r }]; #IO_L14N_T2_SRCC_13 Sch=rpio_19_r 174 | #set_property -dict { PACKAGE_PIN A20 IOSTANDARD LVCMOS33 } [get_ports { rpio_20_r }]; #IO_L2N_T0_AD8N_35 Sch=rpio_20_r 175 | #set_property -dict { PACKAGE_PIN Y9 IOSTANDARD LVCMOS33 } [get_ports { rpio_21_r }]; #IO_L14P_T2_SRCC_13 Sch=rpio_21_r 176 | #set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { rpio_22_r }]; #IO_L17N_T2_13 Sch=rpio_22_r 177 | #set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { rpio_23_r }]; #IO_IO_L22N_T3_13 Sch=rpio_23_r 178 | #set_property -dict { PACKAGE_PIN Y7 IOSTANDARD LVCMOS33 } [get_ports { rpio_24_r }]; #IO_L13P_T2_MRCC_13 Sch=rpio_24_r 179 | #set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports { rpio_25_r }]; #IO_L15N_T2_DQS_AD12N_35 Sch=rpio_25_r 180 | #set_property -dict { PACKAGE_PIN W9 IOSTANDARD LVCMOS33 } [get_ports { rpio_26_r }]; #IO_L16N_T2_13 Sch=rpio_26_r 181 | #set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { rpio_sd_r }]; #IO_L7P_T1_34 Sch=rpio_sd_r 182 | #set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports { rpio_sc_r }]; #IO_L7N_T1_34 Sch=rpio_sc_r 183 | 184 | ##HDMI Rx 185 | 186 | #set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_cec }]; #IO_L13N_T2_MRCC_35 Sch=hdmi_rx_cec 187 | #set_property -dict { PACKAGE_PIN P19 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_clk_n }]; #IO_L13N_T2_MRCC_34 Sch=hdmi_rx_clk_n 188 | #set_property -dict { PACKAGE_PIN N18 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_clk_p }]; #IO_L13P_T2_MRCC_34 Sch=hdmi_rx_clk_p 189 | #set_property -dict { PACKAGE_PIN W20 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_d_n[0] }]; #IO_L16N_T2_34 Sch=hdmi_rx_d_n[0] 190 | #set_property -dict { PACKAGE_PIN V20 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_d_p[0] }]; #IO_L16P_T2_34 Sch=hdmi_rx_d_p[0] 191 | #set_property -dict { PACKAGE_PIN U20 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_d_n[1] }]; #IO_L15N_T2_DQS_34 Sch=hdmi_rx_d_n[1] 192 | #set_property -dict { PACKAGE_PIN T20 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_d_p[1] }]; #IO_L15P_T2_DQS_34 Sch=hdmi_rx_d_p[1] 193 | #set_property -dict { PACKAGE_PIN P20 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_d_n[2] }]; #IO_L14N_T2_SRCC_34 Sch=hdmi_rx_d_n[2] 194 | #set_property -dict { PACKAGE_PIN N20 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_d_p[2] }]; #IO_L14P_T2_SRCC_34 Sch=hdmi_rx_d_p[2] 195 | #set_property -dict { PACKAGE_PIN T19 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_hpd }]; #IO_25_34 Sch=hdmi_rx_hpd 196 | #set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_scl }]; #IO_L11P_T1_SRCC_34 Sch=hdmi_rx_scl 197 | #set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_sda }]; #IO_L11N_T1_SRCC_34 Sch=hdmi_rx_sda 198 | 199 | ##HDMI Tx 200 | 201 | #set_property -dict { PACKAGE_PIN G15 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L19N_T3_VREF_35 Sch=hdmi_tx_cec 202 | #set_property -dict { PACKAGE_PIN L17 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_clk_n }]; #IO_L11N_T1_SRCC_35 Sch=hdmi_tx_clk_n 203 | #set_property -dict { PACKAGE_PIN L16 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_clk_p }]; #IO_L11P_T1_SRCC_35 Sch=hdmi_tx_clk_p 204 | #set_property -dict { PACKAGE_PIN K18 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_d_n[0] }]; #IO_L12N_T1_MRCC_35 Sch=hdmi_tx_d_n[0] 205 | #set_property -dict { PACKAGE_PIN K17 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_d_p[0] }]; #IO_L12P_T1_MRCC_35 Sch=hdmi_tx_d_p[0] 206 | #set_property -dict { PACKAGE_PIN J19 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_d_n[1] }]; #IO_L10N_T1_AD11N_35 Sch=hdmi_tx_d_n[1] 207 | #set_property -dict { PACKAGE_PIN K19 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_d_p[1] }]; #IO_L10P_T1_AD11P_35 Sch=hdmi_tx_d_p[1] 208 | #set_property -dict { PACKAGE_PIN H18 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_d_n[2] }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=hdmi_tx_d_n[2] 209 | #set_property -dict { PACKAGE_PIN J18 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_d_p[2] }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=hdmi_tx_d_p[2] 210 | #set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_hpdn }]; #IO_0_34 Sch=hdmi_tx_hpdn 211 | 212 | 213 | ##Crypto SDA 214 | 215 | #set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { crypto_sda }]; #IO_25_35 Sch=crypto_sda -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sim_1/new/sha256d_tb.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Richie Harris 3 | -- rkharris12@gmail.com 4 | -- 5/23/2021 5 | ---------------------------------------------------------------------------------- 6 | 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | 13 | entity sha256d_tb is 14 | 15 | end sha256d_tb; 16 | 17 | architecture sim of sha256d_tb is 18 | 19 | function rev_byte_order_in_words( 20 | rev_input : std_logic_vector) 21 | return std_logic_vector is 22 | variable temp : std_logic_vector(rev_input'length - 1 downto 0); 23 | constant c_num_words : integer := rev_input'length/32; 24 | begin 25 | for word in 0 to c_num_words-1 loop -- for each 32 bit word 26 | for byte in 0 to 3 loop -- for each byte in the word 27 | temp(32*word+8*(3-byte+1)-1 downto 32*word+8*(3-byte)) := rev_input(32*word+8*(byte+1)-1 downto 32*word+8*(byte)); 28 | end loop; 29 | end loop; 30 | return temp; 31 | end rev_byte_order_in_words; 32 | 33 | component sha256_transform is 34 | generic ( 35 | G_ROLL_FACTOR : integer -- 1=fully unrolled, 64=fully rolled 36 | ); 37 | port ( 38 | CLK : in std_logic; 39 | ARST_N : in std_logic; 40 | FEEDBACK : in std_logic; 41 | COUNT : in unsigned(5 downto 0); 42 | STATE : in std_logic_vector(255 downto 0); 43 | DATA : in std_logic_vector(511 downto 0); 44 | HASH : out std_logic_vector(255 downto 0) 45 | ); 46 | end component; 47 | 48 | constant C_CLK_PERIOD : time := 10 ns; -- 100 MHz 49 | 50 | constant C_ROLL_FACTOR_LOG2 : integer := 0; 51 | constant C_ROLL_FACTOR : integer := 2**C_ROLL_FACTOR_LOG2; 52 | constant C_NUM_STARTUP_ROUNDS : integer := 2*(64/C_ROLL_FACTOR) + 1; 53 | constant C_GOLDEN_NONCE_OFFSET : integer := 2**(7 - C_ROLL_FACTOR_LOG2) + 1; 54 | 55 | constant C_STATE_INIT : std_logic_vector := X"5be0cd191f83d9ab9b05688c510e527fa54ff53a3c6ef372bb67ae856a09e667"; 56 | constant C_FIRST_HASH_PAD : std_logic_vector := X"000002800000000000000000000000000000000000000000000000000000000000000000000000000000000080000000"; 57 | constant C_SECOND_HASH_PAD : std_logic_vector := X"0000010000000000000000000000000000000000000000000000000080000000"; 58 | 59 | signal clk : std_logic := '1'; 60 | signal arst_n : std_logic := '0'; 61 | 62 | signal start : std_logic; 63 | signal residual_data : std_logic_vector(95 downto 0); 64 | signal mid_state : std_logic_vector(255 downto 0); 65 | signal target : unsigned(255 downto 0); 66 | signal true_golden_nonce : std_logic_vector(31 downto 0); 67 | 68 | signal nonce : unsigned(31 downto 0); 69 | signal feedback : std_logic; 70 | signal count : unsigned(5 downto 0); 71 | signal valid : std_logic; 72 | signal startup_rounds_count : unsigned(7 downto 0); 73 | 74 | signal hash1 : std_logic_vector(255 downto 0); 75 | signal hash2 : std_logic_vector(255 downto 0); 76 | 77 | signal done : std_logic; 78 | signal golden_nonce : std_logic_vector(31 downto 0); 79 | signal golden_hash : std_logic_vector(255 downto 0); 80 | 81 | begin 82 | 83 | -- clk and arst_n 84 | clk <= not clk after C_CLK_PERIOD/2; 85 | arst_n <= '1' after 10*C_CLK_PERIOD; 86 | 87 | -- send input data 88 | process begin 89 | start <= '0'; 90 | mid_state <= (others => '0'); 91 | residual_data <= (others => '0'); 92 | target <= (others => '0'); 93 | true_golden_nonce <= (others => '0'); 94 | 95 | wait for 20*C_CLK_PERIOD; 96 | 97 | start <= '1'; 98 | mid_state <= X"74b4c79dbf5de76d0815e94b0d66604341602d39063461d5faf888259fd47d57"; 99 | residual_data <= X"b3936a1aa6c8cb4d1a65600e"; 100 | target <= X"0000000000006a93b30000000000000000000000000000000000000000000000"; 101 | true_golden_nonce <= X"913914e3"; 102 | 103 | wait for C_CLK_PERIOD; 104 | 105 | start <= '0'; 106 | 107 | wait until (done = '1'); 108 | report "golden nonce found!"; 109 | report "nonce: 0x" & to_hstring(golden_nonce); 110 | report "hash2: 0x" & to_hstring(golden_hash); 111 | report "target: 0x" & to_hstring(target); 112 | wait; 113 | end process; 114 | 115 | -- control logic 116 | process(clk, arst_n) begin 117 | if (arst_n = '0') then 118 | feedback <= '0'; 119 | count <= (others => '0'); 120 | nonce <= (others => '0'); 121 | startup_rounds_count <= (others => '0'); 122 | valid <= '0'; 123 | elsif rising_edge(clk) then 124 | count <= count + 1; 125 | feedback <= '1'; 126 | valid <= '0'; 127 | if (count = C_ROLL_FACTOR - 1) then 128 | count <= (others => '0'); 129 | feedback <= '0'; 130 | nonce <= nonce + 1; 131 | if (startup_rounds_count < C_NUM_STARTUP_ROUNDS) then 132 | startup_rounds_count <= startup_rounds_count + 1; 133 | end if; 134 | end if; 135 | if (start = '1') then 136 | nonce <= unsigned(true_golden_nonce) - 5; -- exercise the code a little 137 | count <= (others => '0'); 138 | feedback <= '0'; 139 | startup_rounds_count <= (others => '0'); 140 | end if; 141 | if (startup_rounds_count = C_NUM_STARTUP_ROUNDS) then 142 | valid <= not feedback; 143 | end if; 144 | end if; 145 | end process; 146 | 147 | -- instantiate hashers 148 | sha1 : sha256_transform 149 | generic map ( 150 | G_ROLL_FACTOR => C_ROLL_FACTOR -- 1=fully unrolled, 64=fully rolled 151 | ) 152 | port map ( 153 | CLK => clk, 154 | ARST_N => arst_n, 155 | FEEDBACK => feedback, 156 | COUNT => count, 157 | STATE => mid_state, 158 | DATA => C_FIRST_HASH_PAD & rev_byte_order_in_words(std_logic_vector(nonce)) & residual_data, 159 | HASH => hash1 160 | ); 161 | 162 | sha2 : sha256_transform 163 | generic map ( 164 | G_ROLL_FACTOR => C_ROLL_FACTOR -- 1=fully unrolled, 64=fully rolled 165 | ) 166 | port map ( 167 | CLK => clk, 168 | ARST_N => arst_n, 169 | FEEDBACK => feedback, 170 | COUNT => count, 171 | STATE => C_STATE_INIT, 172 | DATA => C_SECOND_HASH_PAD & hash1, 173 | HASH => hash2 174 | ); 175 | 176 | -- see if we found the golden nonce 177 | process(clk, arst_n) 178 | variable hash2_rev : std_logic_vector(255 downto 0); 179 | begin 180 | if (arst_n = '0') then 181 | done <= '0'; 182 | golden_nonce <= (others => '0'); 183 | golden_hash <= (others => '0'); 184 | elsif rising_edge(clk) then 185 | done <= '0'; 186 | hash2_rev := rev_byte_order_in_words(hash2); 187 | if ((valid = '1') and (unsigned(hash2_rev) < target)) then 188 | done <= '1'; 189 | golden_hash <= hash2_rev; 190 | if (C_ROLL_FACTOR = 1) then 191 | golden_nonce <= std_logic_vector(nonce - 130); 192 | else 193 | golden_nonce <= std_logic_vector(nonce - C_GOLDEN_NONCE_OFFSET); 194 | end if; 195 | end if; 196 | end if; 197 | end process; 198 | 199 | end sim; 200 | -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/bd/soc/hdl/soc_wrapper.vhd: -------------------------------------------------------------------------------- 1 | --Copyright 1986-2019 Xilinx, Inc. All Rights Reserved. 2 | ---------------------------------------------------------------------------------- 3 | --Tool Version: Vivado v.2019.1 (win64) Build 2552052 Fri May 24 14:49:42 MDT 2019 4 | --Date : Sat Oct 2 15:21:07 2021 5 | --Host : MSI running 64-bit major release (build 9200) 6 | --Command : generate_target soc_wrapper.bd 7 | --Design : soc_wrapper 8 | --Purpose : IP block netlist 9 | ---------------------------------------------------------------------------------- 10 | library IEEE; 11 | use IEEE.STD_LOGIC_1164.ALL; 12 | library UNISIM; 13 | use UNISIM.VCOMPONENTS.ALL; 14 | entity soc_wrapper is 15 | port ( 16 | ARST_AVL_N : out STD_LOGIC_VECTOR ( 0 to 0 ); 17 | CLK_AVL : out STD_LOGIC; 18 | M_AVALON_address : out STD_LOGIC_VECTOR ( 31 downto 0 ); 19 | M_AVALON_byteenable : out STD_LOGIC_VECTOR ( 3 downto 0 ); 20 | M_AVALON_read : out STD_LOGIC; 21 | M_AVALON_readdata : in STD_LOGIC_VECTOR ( 31 downto 0 ); 22 | M_AVALON_readdatavalid : in STD_LOGIC; 23 | M_AVALON_waitrequest : in STD_LOGIC; 24 | M_AVALON_write : out STD_LOGIC; 25 | M_AVALON_writedata : out STD_LOGIC_VECTOR ( 31 downto 0 ) 26 | ); 27 | end soc_wrapper; 28 | 29 | architecture STRUCTURE of soc_wrapper is 30 | component soc is 31 | port ( 32 | CLK_AVL : out STD_LOGIC; 33 | ARST_AVL_N : out STD_LOGIC_VECTOR ( 0 to 0 ); 34 | M_AVALON_address : out STD_LOGIC_VECTOR ( 31 downto 0 ); 35 | M_AVALON_byteenable : out STD_LOGIC_VECTOR ( 3 downto 0 ); 36 | M_AVALON_read : out STD_LOGIC; 37 | M_AVALON_readdata : in STD_LOGIC_VECTOR ( 31 downto 0 ); 38 | M_AVALON_readdatavalid : in STD_LOGIC; 39 | M_AVALON_waitrequest : in STD_LOGIC; 40 | M_AVALON_write : out STD_LOGIC; 41 | M_AVALON_writedata : out STD_LOGIC_VECTOR ( 31 downto 0 ) 42 | ); 43 | end component soc; 44 | begin 45 | soc_i: component soc 46 | port map ( 47 | ARST_AVL_N(0) => ARST_AVL_N(0), 48 | CLK_AVL => CLK_AVL, 49 | M_AVALON_address(31 downto 0) => M_AVALON_address(31 downto 0), 50 | M_AVALON_byteenable(3 downto 0) => M_AVALON_byteenable(3 downto 0), 51 | M_AVALON_read => M_AVALON_read, 52 | M_AVALON_readdata(31 downto 0) => M_AVALON_readdata(31 downto 0), 53 | M_AVALON_readdatavalid => M_AVALON_readdatavalid, 54 | M_AVALON_waitrequest => M_AVALON_waitrequest, 55 | M_AVALON_write => M_AVALON_write, 56 | M_AVALON_writedata(31 downto 0) => M_AVALON_writedata(31 downto 0) 57 | ); 58 | end STRUCTURE; 59 | -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/bd/soc/soc.bd: -------------------------------------------------------------------------------- 1 | { 2 | "design": { 3 | "design_info": { 4 | "boundary_crc": "0xA7CDADF92B5BED93", 5 | "device": "xc7z020clg400-1", 6 | "name": "soc", 7 | "synth_flow_mode": "Hierarchical", 8 | "tool_version": "2019.1", 9 | "validated": "true" 10 | }, 11 | "design_tree": { 12 | "processing_system7_0": "", 13 | "axi_amm_bridge_0": "", 14 | "axi_interconnect_0": { 15 | "s00_couplers": { 16 | "auto_pc": "" 17 | } 18 | }, 19 | "proc_sys_reset_0": "" 20 | }, 21 | "interface_ports": { 22 | "M_AVALON": { 23 | "mode": "Master", 24 | "vlnv": "xilinx.com:interface:avalon_rtl:1.0" 25 | } 26 | }, 27 | "ports": { 28 | "CLK_AVL": { 29 | "direction": "O", 30 | "parameters": { 31 | "CLK_DOMAIN": { 32 | "value": "soc_processing_system7_0_0_FCLK_CLK0", 33 | "value_src": "default_prop" 34 | }, 35 | "FREQ_HZ": { 36 | "value": "50000000", 37 | "value_src": "user_prop" 38 | }, 39 | "PHASE": { 40 | "value": "0.000", 41 | "value_src": "default_prop" 42 | } 43 | } 44 | }, 45 | "ARST_AVL_N": { 46 | "type": "rst", 47 | "direction": "O", 48 | "left": "0", 49 | "right": "0", 50 | "parameters": { 51 | "INSERT_VIP": { 52 | "value": "0", 53 | "value_src": "default" 54 | }, 55 | "POLARITY": { 56 | "value": "ACTIVE_LOW", 57 | "value_src": "const_prop" 58 | } 59 | } 60 | } 61 | }, 62 | "components": { 63 | "processing_system7_0": { 64 | "vlnv": "xilinx.com:ip:processing_system7:5.5", 65 | "xci_name": "soc_processing_system7_0_0", 66 | "parameters": { 67 | "PCW_ACT_APU_PERIPHERAL_FREQMHZ": { 68 | "value": "666.666687" 69 | }, 70 | "PCW_ACT_CAN_PERIPHERAL_FREQMHZ": { 71 | "value": "10.000000" 72 | }, 73 | "PCW_ACT_DCI_PERIPHERAL_FREQMHZ": { 74 | "value": "10.158730" 75 | }, 76 | "PCW_ACT_ENET0_PERIPHERAL_FREQMHZ": { 77 | "value": "10.000000" 78 | }, 79 | "PCW_ACT_ENET1_PERIPHERAL_FREQMHZ": { 80 | "value": "10.000000" 81 | }, 82 | "PCW_ACT_FPGA0_PERIPHERAL_FREQMHZ": { 83 | "value": "50.000000" 84 | }, 85 | "PCW_ACT_FPGA1_PERIPHERAL_FREQMHZ": { 86 | "value": "10.000000" 87 | }, 88 | "PCW_ACT_FPGA2_PERIPHERAL_FREQMHZ": { 89 | "value": "10.000000" 90 | }, 91 | "PCW_ACT_FPGA3_PERIPHERAL_FREQMHZ": { 92 | "value": "10.000000" 93 | }, 94 | "PCW_ACT_PCAP_PERIPHERAL_FREQMHZ": { 95 | "value": "200.000000" 96 | }, 97 | "PCW_ACT_QSPI_PERIPHERAL_FREQMHZ": { 98 | "value": "10.000000" 99 | }, 100 | "PCW_ACT_SDIO_PERIPHERAL_FREQMHZ": { 101 | "value": "10.000000" 102 | }, 103 | "PCW_ACT_SMC_PERIPHERAL_FREQMHZ": { 104 | "value": "10.000000" 105 | }, 106 | "PCW_ACT_SPI_PERIPHERAL_FREQMHZ": { 107 | "value": "10.000000" 108 | }, 109 | "PCW_ACT_TPIU_PERIPHERAL_FREQMHZ": { 110 | "value": "200.000000" 111 | }, 112 | "PCW_ACT_TTC0_CLK0_PERIPHERAL_FREQMHZ": { 113 | "value": "111.111115" 114 | }, 115 | "PCW_ACT_TTC0_CLK1_PERIPHERAL_FREQMHZ": { 116 | "value": "111.111115" 117 | }, 118 | "PCW_ACT_TTC0_CLK2_PERIPHERAL_FREQMHZ": { 119 | "value": "111.111115" 120 | }, 121 | "PCW_ACT_TTC1_CLK0_PERIPHERAL_FREQMHZ": { 122 | "value": "111.111115" 123 | }, 124 | "PCW_ACT_TTC1_CLK1_PERIPHERAL_FREQMHZ": { 125 | "value": "111.111115" 126 | }, 127 | "PCW_ACT_TTC1_CLK2_PERIPHERAL_FREQMHZ": { 128 | "value": "111.111115" 129 | }, 130 | "PCW_ACT_UART_PERIPHERAL_FREQMHZ": { 131 | "value": "10.000000" 132 | }, 133 | "PCW_ACT_WDT_PERIPHERAL_FREQMHZ": { 134 | "value": "111.111115" 135 | }, 136 | "PCW_CLK0_FREQ": { 137 | "value": "50000000" 138 | }, 139 | "PCW_CLK1_FREQ": { 140 | "value": "10000000" 141 | }, 142 | "PCW_CLK2_FREQ": { 143 | "value": "10000000" 144 | }, 145 | "PCW_CLK3_FREQ": { 146 | "value": "10000000" 147 | }, 148 | "PCW_EN_CLK1_PORT": { 149 | "value": "0" 150 | }, 151 | "PCW_EN_QSPI": { 152 | "value": "0" 153 | }, 154 | "PCW_FCLK1_PERIPHERAL_CLKSRC": { 155 | "value": "IO PLL" 156 | }, 157 | "PCW_FPGA0_PERIPHERAL_FREQMHZ": { 158 | "value": "50" 159 | }, 160 | "PCW_FPGA1_PERIPHERAL_FREQMHZ": { 161 | "value": "50" 162 | }, 163 | "PCW_FPGA_FCLK0_ENABLE": { 164 | "value": "1" 165 | }, 166 | "PCW_NAND_PERIPHERAL_ENABLE": { 167 | "value": "0" 168 | }, 169 | "PCW_NOR_PERIPHERAL_ENABLE": { 170 | "value": "0" 171 | }, 172 | "PCW_QSPI_PERIPHERAL_ENABLE": { 173 | "value": "0" 174 | }, 175 | "PCW_UIPARAM_ACT_DDR_FREQ_MHZ": { 176 | "value": "533.333374" 177 | }, 178 | "PCW_USE_FABRIC_INTERRUPT": { 179 | "value": "0" 180 | } 181 | } 182 | }, 183 | "axi_amm_bridge_0": { 184 | "vlnv": "xilinx.com:ip:axi_amm_bridge:1.0", 185 | "xci_name": "soc_axi_amm_bridge_0_0", 186 | "parameters": { 187 | "C_ADDRESS_MODE": { 188 | "value": "1" 189 | }, 190 | "C_AVM_BURST_WIDTH": { 191 | "value": "1" 192 | }, 193 | "C_BEGIN_BURST_TRANSFER": { 194 | "value": "0" 195 | }, 196 | "C_BURST_SUPPORT": { 197 | "value": "0" 198 | }, 199 | "C_HAS_RESPONSE": { 200 | "value": "0" 201 | }, 202 | "C_PROTOCOL": { 203 | "value": "0" 204 | }, 205 | "C_S_AXI_ADDR_WIDTH": { 206 | "value": "32" 207 | }, 208 | "C_USE_BYTEENABLE": { 209 | "value": "1" 210 | } 211 | } 212 | }, 213 | "axi_interconnect_0": { 214 | "vlnv": "xilinx.com:ip:axi_interconnect:2.1", 215 | "xci_name": "soc_axi_interconnect_0_0", 216 | "parameters": { 217 | "NUM_MI": { 218 | "value": "1" 219 | } 220 | }, 221 | "interface_ports": { 222 | "S00_AXI": { 223 | "mode": "Slave", 224 | "vlnv": "xilinx.com:interface:aximm_rtl:1.0" 225 | }, 226 | "M00_AXI": { 227 | "mode": "Master", 228 | "vlnv": "xilinx.com:interface:aximm_rtl:1.0" 229 | } 230 | }, 231 | "ports": { 232 | "ACLK": { 233 | "type": "clk", 234 | "direction": "I", 235 | "parameters": { 236 | "ASSOCIATED_RESET": { 237 | "value": "ARESETN" 238 | } 239 | } 240 | }, 241 | "ARESETN": { 242 | "type": "rst", 243 | "direction": "I" 244 | }, 245 | "S00_ACLK": { 246 | "type": "clk", 247 | "direction": "I", 248 | "parameters": { 249 | "ASSOCIATED_BUSIF": { 250 | "value": "S00_AXI" 251 | }, 252 | "ASSOCIATED_RESET": { 253 | "value": "S00_ARESETN" 254 | } 255 | } 256 | }, 257 | "S00_ARESETN": { 258 | "type": "rst", 259 | "direction": "I" 260 | }, 261 | "M00_ACLK": { 262 | "type": "clk", 263 | "direction": "I", 264 | "parameters": { 265 | "ASSOCIATED_BUSIF": { 266 | "value": "M00_AXI" 267 | }, 268 | "ASSOCIATED_RESET": { 269 | "value": "M00_ARESETN" 270 | } 271 | } 272 | }, 273 | "M00_ARESETN": { 274 | "type": "rst", 275 | "direction": "I" 276 | } 277 | }, 278 | "components": { 279 | "s00_couplers": { 280 | "interface_ports": { 281 | "M_AXI": { 282 | "mode": "Master", 283 | "vlnv": "xilinx.com:interface:aximm_rtl:1.0" 284 | }, 285 | "S_AXI": { 286 | "mode": "Slave", 287 | "vlnv": "xilinx.com:interface:aximm_rtl:1.0" 288 | } 289 | }, 290 | "ports": { 291 | "M_ACLK": { 292 | "type": "clk", 293 | "direction": "I", 294 | "parameters": { 295 | "ASSOCIATED_BUSIF": { 296 | "value": "M_AXI" 297 | }, 298 | "ASSOCIATED_RESET": { 299 | "value": "M_ARESETN" 300 | } 301 | } 302 | }, 303 | "M_ARESETN": { 304 | "type": "rst", 305 | "direction": "I" 306 | }, 307 | "S_ACLK": { 308 | "type": "clk", 309 | "direction": "I", 310 | "parameters": { 311 | "ASSOCIATED_BUSIF": { 312 | "value": "S_AXI" 313 | }, 314 | "ASSOCIATED_RESET": { 315 | "value": "S_ARESETN" 316 | } 317 | } 318 | }, 319 | "S_ARESETN": { 320 | "type": "rst", 321 | "direction": "I" 322 | } 323 | }, 324 | "components": { 325 | "auto_pc": { 326 | "vlnv": "xilinx.com:ip:axi_protocol_converter:2.1", 327 | "xci_name": "soc_auto_pc_0", 328 | "parameters": { 329 | "MI_PROTOCOL": { 330 | "value": "AXI4LITE" 331 | }, 332 | "SI_PROTOCOL": { 333 | "value": "AXI3" 334 | } 335 | } 336 | } 337 | }, 338 | "interface_nets": { 339 | "auto_pc_to_s00_couplers": { 340 | "interface_ports": [ 341 | "M_AXI", 342 | "auto_pc/M_AXI" 343 | ] 344 | }, 345 | "s00_couplers_to_auto_pc": { 346 | "interface_ports": [ 347 | "S_AXI", 348 | "auto_pc/S_AXI" 349 | ] 350 | } 351 | }, 352 | "nets": { 353 | "S_ACLK_1": { 354 | "ports": [ 355 | "S_ACLK", 356 | "auto_pc/aclk" 357 | ] 358 | }, 359 | "S_ARESETN_1": { 360 | "ports": [ 361 | "S_ARESETN", 362 | "auto_pc/aresetn" 363 | ] 364 | } 365 | } 366 | } 367 | }, 368 | "interface_nets": { 369 | "axi_interconnect_0_to_s00_couplers": { 370 | "interface_ports": [ 371 | "S00_AXI", 372 | "s00_couplers/S_AXI" 373 | ] 374 | }, 375 | "s00_couplers_to_axi_interconnect_0": { 376 | "interface_ports": [ 377 | "M00_AXI", 378 | "s00_couplers/M_AXI" 379 | ] 380 | } 381 | }, 382 | "nets": { 383 | "axi_interconnect_0_ACLK_net": { 384 | "ports": [ 385 | "M00_ACLK", 386 | "s00_couplers/M_ACLK" 387 | ] 388 | }, 389 | "axi_interconnect_0_ARESETN_net": { 390 | "ports": [ 391 | "M00_ARESETN", 392 | "s00_couplers/M_ARESETN" 393 | ] 394 | }, 395 | "S00_ACLK_1": { 396 | "ports": [ 397 | "S00_ACLK", 398 | "s00_couplers/S_ACLK" 399 | ] 400 | }, 401 | "S00_ARESETN_1": { 402 | "ports": [ 403 | "S00_ARESETN", 404 | "s00_couplers/S_ARESETN" 405 | ] 406 | } 407 | } 408 | }, 409 | "proc_sys_reset_0": { 410 | "vlnv": "xilinx.com:ip:proc_sys_reset:5.0", 411 | "xci_name": "soc_proc_sys_reset_0_0", 412 | "parameters": { 413 | "C_EXT_RST_WIDTH": { 414 | "value": "1" 415 | } 416 | } 417 | } 418 | }, 419 | "interface_nets": { 420 | "axi_interconnect_0_M00_AXI": { 421 | "interface_ports": [ 422 | "axi_interconnect_0/M00_AXI", 423 | "axi_amm_bridge_0/S_AXI_LITE" 424 | ] 425 | }, 426 | "processing_system7_0_M_AXI_GP0": { 427 | "interface_ports": [ 428 | "processing_system7_0/M_AXI_GP0", 429 | "axi_interconnect_0/S00_AXI" 430 | ] 431 | }, 432 | "axi_amm_bridge_0_M_AVALON": { 433 | "interface_ports": [ 434 | "M_AVALON", 435 | "axi_amm_bridge_0/M_AVALON" 436 | ] 437 | } 438 | }, 439 | "nets": { 440 | "processing_system7_0_FCLK_RESET0_N": { 441 | "ports": [ 442 | "processing_system7_0/FCLK_RESET0_N", 443 | "proc_sys_reset_0/ext_reset_in" 444 | ] 445 | }, 446 | "processing_system7_0_FCLK_CLK0": { 447 | "ports": [ 448 | "processing_system7_0/FCLK_CLK0", 449 | "proc_sys_reset_0/slowest_sync_clk", 450 | "processing_system7_0/M_AXI_GP0_ACLK", 451 | "axi_amm_bridge_0/s_axi_aclk", 452 | "axi_interconnect_0/ACLK", 453 | "axi_interconnect_0/S00_ACLK", 454 | "axi_interconnect_0/M00_ACLK", 455 | "CLK_AVL" 456 | ] 457 | }, 458 | "proc_sys_reset_0_interconnect_aresetn": { 459 | "ports": [ 460 | "proc_sys_reset_0/interconnect_aresetn", 461 | "axi_interconnect_0/ARESETN" 462 | ] 463 | }, 464 | "proc_sys_reset_0_peripheral_aresetn": { 465 | "ports": [ 466 | "proc_sys_reset_0/peripheral_aresetn", 467 | "axi_interconnect_0/S00_ARESETN", 468 | "axi_interconnect_0/M00_ARESETN", 469 | "axi_amm_bridge_0/s_axi_aresetn", 470 | "ARST_AVL_N" 471 | ] 472 | } 473 | }, 474 | "addressing": { 475 | "/": { 476 | "memory_maps": { 477 | "M_AVALON": { 478 | "address_blocks": { 479 | "Reg": { 480 | "base_address": "0", 481 | "range": "64K", 482 | "width": "32", 483 | "usage": "register" 484 | } 485 | } 486 | } 487 | } 488 | }, 489 | "/processing_system7_0": { 490 | "address_spaces": { 491 | "Data": { 492 | "range": "4G", 493 | "width": "32", 494 | "segments": { 495 | "SEG_M_AVALON_Reg": { 496 | "address_block": "/M_AVALON/Reg", 497 | "offset": "0x43C00000", 498 | "range": "64K" 499 | } 500 | } 501 | } 502 | } 503 | } 504 | } 505 | } 506 | } -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/new/miner_top.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Richie Harris 3 | -- rkharris12@gmail.com 4 | -- 5/23/2021 5 | ---------------------------------------------------------------------------------- 6 | 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | 13 | entity miner_top is 14 | port ( 15 | CLK_125M : in std_logic 16 | ); 17 | end miner_top; 18 | 19 | architecture rtl of miner_top is 20 | 21 | component soc_wrapper is 22 | port ( 23 | ARST_AVL_N : out std_logic_vector(0 to 0); 24 | CLK_AVL : out std_logic; 25 | M_AVALON_ADDRESS : out std_logic_vector(31 downto 0); 26 | M_AVALON_BYTEENABLE : out std_logic_vector(3 downto 0); 27 | M_AVALON_READ : out std_logic; 28 | M_AVALON_READDATA : in std_logic_vector(31 downto 0); 29 | M_AVALON_READDATAVALID : in std_logic; 30 | M_AVALON_WAITREQUEST : in std_logic; 31 | M_AVALON_WRITE : out std_logic; 32 | M_AVALON_WRITEDATA : out std_logic_vector(31 downto 0) 33 | ); 34 | end component; 35 | 36 | component sha256d_wrapper is 37 | generic ( 38 | G_ROLL_FACTOR_LOG2 : integer -- 0=fully unrolled, 6=fully rolled 39 | ); 40 | port ( 41 | CLK : in std_logic; 42 | ARST_N : in std_logic; 43 | SRST : in std_logic; 44 | START : in std_logic; 45 | MID_STATE : in std_logic_vector(255 downto 0); 46 | RESIDUAL_DATA : in std_logic_vector(95 downto 0); 47 | TARGET : in unsigned(255 downto 0); 48 | FOUND : out std_logic; 49 | NOT_FOUND : out std_logic; 50 | GOLDEN_NONCE : out std_logic_vector(31 downto 0); 51 | CURRENT_NONCE : out std_logic_vector(31 downto 0) 52 | ); 53 | end component; 54 | 55 | component pulse_cdc is 56 | port ( 57 | CLK_IN : in std_logic; 58 | ARST_IN_N : in std_logic; 59 | CLK_OUT : in std_logic; 60 | ARST_OUT_N : in std_logic; 61 | DIN : in std_logic; 62 | DOUT : out std_logic 63 | ); 64 | end component; 65 | 66 | component clk_wiz_0 is 67 | port ( 68 | clk_out1 : out std_logic; 69 | resetn : in std_logic; 70 | locked : out std_logic; 71 | clk_in1 : in std_logic 72 | ); 73 | end component; 74 | 75 | -- constants 76 | constant C_ROLL_FACTOR_LOG2 : integer := 1; 77 | constant C_WORD_SIZE : integer := 32; 78 | 79 | -- register interface 80 | signal arst_avl_n : std_logic; 81 | signal clk_avl : std_logic; 82 | signal avl_address : std_logic_vector(31 downto 0); 83 | signal avl_byteenable : std_logic_vector(3 downto 0); 84 | signal avl_read : std_logic; 85 | signal avl_readdata : std_logic_vector(31 downto 0); 86 | signal avl_readdatavalid : std_logic; 87 | signal avl_waitrequest : std_logic; 88 | signal avl_write : std_logic; 89 | signal avl_writedata : std_logic_vector(31 downto 0); 90 | 91 | -- address decoding 92 | signal address_bank : std_logic_vector(7 downto 0); 93 | signal address_offset : std_logic_vector(7 downto 0); 94 | 95 | -- sha256d 96 | signal srst : std_logic; 97 | signal start : std_logic; 98 | signal mid_state : std_logic_vector(255 downto 0); 99 | signal residual_data : std_logic_vector(95 downto 0); 100 | signal target : std_logic_vector(255 downto 0); 101 | signal found : std_logic; 102 | signal not_found : std_logic; 103 | signal found_reg : std_logic; 104 | signal not_found_reg : std_logic; 105 | signal golden_nonce : std_logic_vector(31 downto 0); 106 | signal current_hash_req : std_logic; 107 | signal current_nonce : std_logic_vector(31 downto 0); 108 | signal current_nonce_latched : std_logic_vector(31 downto 0); 109 | 110 | -- CDC 111 | signal clk_hash : std_logic; 112 | signal arst_hash_n : std_logic; 113 | signal arst_hash_sr : std_logic_vector(3 downto 0); 114 | signal srst_resync : std_logic; 115 | signal start_resync : std_logic; 116 | signal found_resync : std_logic; 117 | signal not_found_resync : std_logic; 118 | signal current_hash_req_resync : std_logic; 119 | 120 | begin 121 | 122 | -- clock generation -------------------------------------------- 123 | mmcm_clk_hash : clk_wiz_0 124 | port map ( 125 | clk_out1 => clk_hash, 126 | resetn => '1', 127 | locked => open, 128 | clk_in1 => CLK_125M 129 | ); 130 | 131 | -- register interface ------------------------------------------ 132 | process(clk_avl, arst_avl_n) begin 133 | if (arst_avl_n = '0') then 134 | avl_readdata <= (others => '0'); 135 | avl_readdatavalid <= '0'; 136 | srst <= '0'; 137 | start <= '0'; 138 | found_reg <= '0'; 139 | not_found_reg <= '0'; 140 | current_hash_req <= '0'; 141 | mid_state <= (others => '0'); 142 | residual_data <= (others => '0'); 143 | target <= (others => '0'); 144 | elsif rising_edge(clk_avl) then 145 | --pulse generation 146 | avl_readdatavalid <= '0'; 147 | avl_readdata <= (others => '0'); 148 | srst <= '0'; 149 | start <= '0'; 150 | current_hash_req <= '0'; 151 | -- register pulses from sha256d_wrapper 152 | if (found_resync = '1') then 153 | found_reg <= '1'; 154 | end if; 155 | if (not_found_resync = '1') then 156 | not_found_reg <= '1'; 157 | end if; 158 | -- read 159 | if (avl_read = '1') then 160 | avl_readdatavalid <= '1'; 161 | if (to_integer(unsigned(address_bank)) = 0) then 162 | case to_integer(unsigned(address_offset)) is 163 | when 2 => 164 | avl_readdata(0) <= found_reg; 165 | avl_readdata(1) <= not_found_reg; 166 | -- clear status on read 167 | found_reg <= '0'; 168 | not_found_reg <= '0'; 169 | when 3 => 170 | avl_readdata <= golden_nonce; 171 | when 5 => 172 | avl_readdata <= current_nonce_latched; 173 | when others => 174 | null; 175 | end case; 176 | end if; 177 | if (to_integer(unsigned(address_bank)) = 1) then 178 | case to_integer(unsigned(address_offset)) is 179 | when 0 => 180 | avl_readdata <= mid_state(C_WORD_SIZE - 1 downto 0); 181 | when 1 => 182 | avl_readdata <= mid_state(2*C_WORD_SIZE - 1 downto C_WORD_SIZE); 183 | when 2 => 184 | avl_readdata <= mid_state(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE); 185 | when 3 => 186 | avl_readdata <= mid_state(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE); 187 | when 4 => 188 | avl_readdata <= mid_state(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE); 189 | when 5 => 190 | avl_readdata <= mid_state(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE); 191 | when 6 => 192 | avl_readdata <= mid_state(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE); 193 | when 7 => 194 | avl_readdata <= mid_state(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE); 195 | when others => 196 | null; 197 | end case; 198 | end if; 199 | if (to_integer(unsigned(address_bank)) = 2) then 200 | case to_integer(unsigned(address_offset)) is 201 | when 0 => 202 | avl_readdata <= residual_data(C_WORD_SIZE - 1 downto 0); 203 | when 1 => 204 | avl_readdata <= residual_data(2*C_WORD_SIZE - 1 downto C_WORD_SIZE); 205 | when 2 => 206 | avl_readdata <= residual_data(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE); 207 | when others => 208 | null; 209 | end case; 210 | end if; 211 | if (to_integer(unsigned(address_bank)) = 3) then 212 | case to_integer(unsigned(address_offset)) is 213 | when 0 => 214 | avl_readdata <= target(C_WORD_SIZE - 1 downto 0); 215 | when 1 => 216 | avl_readdata <= target(2*C_WORD_SIZE - 1 downto C_WORD_SIZE); 217 | when 2 => 218 | avl_readdata <= target(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE); 219 | when 3 => 220 | avl_readdata <= target(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE); 221 | when 4 => 222 | avl_readdata <= target(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE); 223 | when 5 => 224 | avl_readdata <= target(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE); 225 | when 6 => 226 | avl_readdata <= target(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE); 227 | when 7 => 228 | avl_readdata <= target(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE); 229 | when others => 230 | null; 231 | end case; 232 | end if; 233 | -- write 234 | elsif (avl_write = '1') then 235 | if (to_integer(unsigned(address_bank)) = 0) then 236 | case to_integer(unsigned(address_offset)) is 237 | when 0 => 238 | srst <= avl_writedata(0); 239 | when 1 => 240 | start <= avl_writedata(0); 241 | when 4 => 242 | current_hash_req <= avl_writedata(0); 243 | when others => 244 | null; 245 | end case; 246 | end if; 247 | if (to_integer(unsigned(address_bank)) = 1) then 248 | case to_integer(unsigned(address_offset)) is 249 | when 0 => 250 | mid_state(C_WORD_SIZE - 1 downto 0) <= avl_writedata; 251 | when 1 => 252 | mid_state(2*C_WORD_SIZE - 1 downto C_WORD_SIZE) <= avl_writedata; 253 | when 2 => 254 | mid_state(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE) <= avl_writedata; 255 | when 3 => 256 | mid_state(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE) <= avl_writedata; 257 | when 4 => 258 | mid_state(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE) <= avl_writedata; 259 | when 5 => 260 | mid_state(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE) <= avl_writedata; 261 | when 6 => 262 | mid_state(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE) <= avl_writedata; 263 | when 7 => 264 | mid_state(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE) <= avl_writedata; 265 | when others => 266 | null; 267 | end case; 268 | end if; 269 | if (to_integer(unsigned(address_bank)) = 2) then 270 | case to_integer(unsigned(address_offset)) is 271 | when 0 => 272 | residual_data(C_WORD_SIZE - 1 downto 0) <= avl_writedata; 273 | when 1 => 274 | residual_data(2*C_WORD_SIZE - 1 downto C_WORD_SIZE) <= avl_writedata; 275 | when 2 => 276 | residual_data(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE) <= avl_writedata; 277 | when others => 278 | null; 279 | end case; 280 | end if; 281 | if (to_integer(unsigned(address_bank)) = 3) then 282 | case to_integer(unsigned(address_offset)) is 283 | when 0 => 284 | target(C_WORD_SIZE - 1 downto 0) <= avl_writedata; 285 | when 1 => 286 | target(2*C_WORD_SIZE - 1 downto C_WORD_SIZE) <= avl_writedata; 287 | when 2 => 288 | target(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE) <= avl_writedata; 289 | when 3 => 290 | target(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE) <= avl_writedata; 291 | when 4 => 292 | target(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE) <= avl_writedata; 293 | when 5 => 294 | target(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE) <= avl_writedata; 295 | when 6 => 296 | target(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE) <= avl_writedata; 297 | when 7 => 298 | target(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE) <= avl_writedata; 299 | when others => 300 | null; 301 | end case; 302 | end if; 303 | end if; 304 | end if; 305 | end process; 306 | 307 | avl_waitrequest <= '0'; -- always ready 308 | 309 | -- decode register address 310 | address_bank <= avl_address(15 downto 8); 311 | address_offset <= avl_address(7 downto 0); 312 | 313 | -- instantiate processor interface -------------------------------- 314 | u_soc_wrapper : soc_wrapper 315 | port map ( 316 | ARST_AVL_N(0) => arst_avl_n, 317 | CLK_AVL => clk_avl, 318 | M_AVALON_ADDRESS => avl_address, 319 | M_AVALON_BYTEENABLE => avl_byteenable, 320 | M_AVALON_READ => avl_read, 321 | M_AVALON_READDATA => avl_readdata, 322 | M_AVALON_READDATAVALID => avl_readdatavalid, 323 | M_AVALON_WAITREQUEST => avl_waitrequest, 324 | M_AVALON_WRITE => avl_write, 325 | M_AVALON_WRITEDATA => avl_writedata 326 | ); 327 | 328 | -- CDC logic ------------------------------------------------------ 329 | -- don't bother CDC'ing mid_state, residual_data, target, and golden_nonce because 330 | -- they should be stable and unchanging when they will be used 331 | 332 | -- create async assertion, sync release reset_n for sha256d hasher 333 | process(clk_hash, arst_avl_n) begin 334 | if (arst_avl_n = '0') then 335 | arst_hash_sr <= (others => '0'); 336 | elsif rising_edge(clk_hash) then 337 | arst_hash_sr <= arst_hash_sr(arst_hash_sr'high - 1 downto 0) & '1'; 338 | end if; 339 | end process; 340 | 341 | arst_hash_n <= arst_hash_sr(arst_hash_sr'high); 342 | 343 | -- pulse CDCs 344 | srst_cdc : pulse_cdc 345 | port map ( 346 | CLK_IN => clk_avl, 347 | ARST_IN_N => arst_avl_n, 348 | CLK_OUT => clk_hash, 349 | ARST_OUT_N => arst_hash_n, 350 | DIN => srst, 351 | DOUT => srst_resync 352 | ); 353 | 354 | start_cdc : pulse_cdc 355 | port map ( 356 | CLK_IN => clk_avl, 357 | ARST_IN_N => arst_avl_n, 358 | CLK_OUT => clk_hash, 359 | ARST_OUT_N => arst_hash_n, 360 | DIN => start, 361 | DOUT => start_resync 362 | ); 363 | 364 | found_cdc : pulse_cdc 365 | port map ( 366 | CLK_IN => clk_hash, 367 | ARST_IN_N => arst_hash_n, 368 | CLK_OUT => clk_avl, 369 | ARST_OUT_N => arst_avl_n, 370 | DIN => found, 371 | DOUT => found_resync 372 | ); 373 | 374 | not_found_cdc : pulse_cdc 375 | port map ( 376 | CLK_IN => clk_hash, 377 | ARST_IN_N => arst_hash_n, 378 | CLK_OUT => clk_avl, 379 | ARST_OUT_N => arst_avl_n, 380 | DIN => not_found, 381 | DOUT => not_found_resync 382 | ); 383 | 384 | current_hash_req_cdc : pulse_cdc 385 | port map ( 386 | CLK_IN => clk_avl, 387 | ARST_IN_N => arst_avl_n, 388 | CLK_OUT => clk_hash, 389 | ARST_OUT_N => arst_hash_n, 390 | DIN => current_hash_req, 391 | DOUT => current_hash_req_resync 392 | ); 393 | 394 | -- latch current_nonce when requested, current_nonce_latched should be stable 395 | -- when we read it on clk_avl so don't bother registering it on clk_avl 396 | process(clk_hash, arst_hash_n) begin 397 | if (arst_hash_n = '0') then 398 | current_nonce_latched <= (others => '0'); 399 | elsif rising_edge(clk_hash) then 400 | if (current_hash_req_resync = '1') then 401 | current_nonce_latched <= current_nonce; 402 | end if; 403 | end if; 404 | end process; 405 | 406 | -- instantiate sha256d hasher ------------------------------------- 407 | u_sha256d_wrapper : sha256d_wrapper 408 | generic map ( 409 | G_ROLL_FACTOR_LOG2 => C_ROLL_FACTOR_LOG2 -- 0=fully unrolled, 6=fully rolled 410 | ) 411 | port map ( 412 | CLK => clk_hash, 413 | ARST_N => arst_hash_n, 414 | SRST => srst_resync, 415 | START => start_resync, 416 | MID_STATE => mid_state, 417 | RESIDUAL_DATA => residual_data, 418 | TARGET => unsigned(target), 419 | FOUND => found, 420 | NOT_FOUND => not_found, 421 | GOLDEN_NONCE => golden_nonce, 422 | CURRENT_NONCE => current_nonce 423 | ); 424 | 425 | end rtl; 426 | -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/new/pulse_cdc.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Richie Harris 3 | -- rkharris12@gmail.com 4 | -- 5/23/2021 5 | ---------------------------------------------------------------------------------- 6 | 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | 11 | 12 | entity pulse_cdc is 13 | port ( 14 | CLK_IN : in std_logic; 15 | ARST_IN_N : in std_logic; 16 | CLK_OUT : in std_logic; 17 | ARST_OUT_N : in std_logic; 18 | DIN : in std_logic; 19 | DOUT : out std_logic 20 | ); 21 | end pulse_cdc; 22 | 23 | architecture rtl of pulse_cdc is 24 | 25 | signal toggle : std_logic; 26 | signal toggle_sr : std_logic_vector(3 downto 0); 27 | 28 | begin 29 | 30 | -- input toggle 31 | process(CLK_IN, ARST_IN_N) begin 32 | if (ARST_IN_N = '0') then 33 | toggle <= '0'; 34 | elsif rising_edge(CLK_IN) then 35 | toggle <= toggle xor DIN; 36 | end if; 37 | end process; 38 | 39 | -- toggle resync 40 | process(CLK_OUT, ARST_OUT_N) begin 41 | if (ARST_OUT_N = '0') then 42 | toggle_sr <= (others => '0'); 43 | elsif rising_edge(CLK_OUT) then 44 | toggle_sr <= toggle_sr(toggle_sr'high - 1 downto 0) & toggle; 45 | end if; 46 | end process; 47 | 48 | -- output pulse 49 | DOUT <= toggle_sr(toggle_sr'high) xor toggle_sr(toggle_sr'high - 1); 50 | 51 | end rtl; 52 | -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/new/sha256_digester.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Richie Harris 3 | -- rkharris12@gmail.com 4 | -- 5/23/2021 5 | ---------------------------------------------------------------------------------- 6 | 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | 13 | entity sha256_digester is 14 | port ( 15 | CLK : in std_logic; 16 | ARST_N : in std_logic; 17 | K : in std_logic_vector(31 downto 0); 18 | STATE_IN : in std_logic_vector(255 downto 0); 19 | DATA_IN : in std_logic_vector(511 downto 0); 20 | STATE_OUT : out std_logic_vector(255 downto 0); 21 | DATA_OUT : out std_logic_vector(511 downto 0) 22 | ); 23 | end sha256_digester; 24 | 25 | architecture rtl of sha256_digester is 26 | 27 | constant C_WORD_SIZE : integer := 32; 28 | 29 | signal t1 : unsigned(31 downto 0); 30 | signal t2 : unsigned(31 downto 0); 31 | signal new_word : unsigned(31 downto 0); 32 | signal e0 : std_logic_vector(31 downto 0); 33 | signal e1 : std_logic_vector(31 downto 0); 34 | signal ch : std_logic_vector(31 downto 0); 35 | signal maj : std_logic_vector(31 downto 0); 36 | signal s0 : std_logic_vector(31 downto 0); 37 | signal s1 : std_logic_vector(31 downto 0); 38 | 39 | begin 40 | 41 | -- bit shuffling 42 | e0 <= (STATE_IN(1 downto 0) & STATE_IN(C_WORD_SIZE - 1 downto 2)) 43 | xor (STATE_IN(12 downto 0) & STATE_IN(C_WORD_SIZE - 1 downto 13)) 44 | xor (STATE_IN(21 downto 0) & STATE_IN(C_WORD_SIZE - 1 downto 22)); 45 | e1 <= (STATE_IN(4*C_WORD_SIZE + 5 downto 4*C_WORD_SIZE) & STATE_IN(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE + 6)) 46 | xor (STATE_IN(4*C_WORD_SIZE + 10 downto 4*C_WORD_SIZE) & STATE_IN(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE + 11)) 47 | xor (STATE_IN(4*C_WORD_SIZE + 24 downto 4*C_WORD_SIZE) & STATE_IN(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE + 25)); 48 | ch <= STATE_IN(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE) 49 | xor (STATE_IN(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE) 50 | and (STATE_IN(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE) 51 | xor STATE_IN(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE))); 52 | maj <= (STATE_IN(C_WORD_SIZE - 1 downto 0) and STATE_IN(2*C_WORD_SIZE - 1 downto C_WORD_SIZE)) 53 | or (STATE_IN(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE) 54 | and (STATE_IN(C_WORD_SIZE - 1 downto 0) or STATE_IN(2*C_WORD_SIZE - 1 downto C_WORD_SIZE))); 55 | s0(C_WORD_SIZE - 1 downto 29) <= DATA_IN(C_WORD_SIZE + 6 downto C_WORD_SIZE + 4) xor DATA_IN(C_WORD_SIZE + 17 downto C_WORD_SIZE + 15); 56 | s0(28 downto 0) <= (DATA_IN(C_WORD_SIZE + 3 downto C_WORD_SIZE) & DATA_IN(2*C_WORD_SIZE - 1 downto C_WORD_SIZE + 7)) 57 | xor (DATA_IN(C_WORD_SIZE + 14 downto C_WORD_SIZE) & DATA_IN(2*C_WORD_SIZE - 1 downto C_WORD_SIZE + 18)) 58 | xor DATA_IN(2*C_WORD_SIZE - 1 downto C_WORD_SIZE + 3); 59 | s1(C_WORD_SIZE - 1 downto 22) <= DATA_IN(14*C_WORD_SIZE + 16 downto 14*C_WORD_SIZE + 7) xor DATA_IN(14*C_WORD_SIZE + 18 downto 14*C_WORD_SIZE + 9); 60 | s1(21 downto 0) <= (DATA_IN(14*C_WORD_SIZE + 6 downto 14*C_WORD_SIZE) & DATA_IN(15*C_WORD_SIZE - 1 downto 14*C_WORD_SIZE + 17)) 61 | xor (DATA_IN(14*C_WORD_SIZE + 8 downto 14*C_WORD_SIZE) & DATA_IN(15*C_WORD_SIZE - 1 downto 14*C_WORD_SIZE + 19)) 62 | xor DATA_IN(15*C_WORD_SIZE - 1 downto 14*C_WORD_SIZE + 10); 63 | 64 | -- t1, t2, and new word in message schedule 65 | t1 <= unsigned(STATE_IN(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE)) + unsigned(e1) + unsigned(ch) + unsigned(DATA_IN(C_WORD_SIZE - 1 downto 0)) + unsigned(K); 66 | t2 <= unsigned(e0) + unsigned(maj); 67 | new_word <= unsigned(s1) + unsigned(DATA_IN(10*C_WORD_SIZE - 1 downto 9*C_WORD_SIZE)) + unsigned(s0) + unsigned(DATA_IN(C_WORD_SIZE - 1 downto 0)); 68 | 69 | -- compute output and shift in new word from message schedule 70 | process(CLK, ARST_N) begin 71 | if (ARST_N = '0') then 72 | DATA_OUT <= (others => '0'); 73 | STATE_OUT <= (others => '0'); 74 | elsif rising_edge(CLK) then 75 | DATA_OUT <= std_logic_vector(new_word) & DATA_IN(511 downto C_WORD_SIZE); 76 | 77 | STATE_OUT(C_WORD_SIZE - 1 downto 0) <= std_logic_vector(t1 + t2); 78 | STATE_OUT(2*C_WORD_SIZE - 1 downto C_WORD_SIZE) <= STATE_IN(C_WORD_SIZE - 1 downto 0); 79 | STATE_OUT(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE) <= STATE_IN(2*C_WORD_SIZE - 1 downto C_WORD_SIZE); 80 | STATE_OUT(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE) <= STATE_IN(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE); 81 | STATE_OUT(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE_IN(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE)) + t1); 82 | STATE_OUT(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE) <= STATE_IN(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE); 83 | STATE_OUT(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE) <= STATE_IN(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE); 84 | STATE_OUT(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE) <= STATE_IN(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE); 85 | end if; 86 | end process; 87 | 88 | end rtl; 89 | -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/new/sha256_transform.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Richie Harris 3 | -- rkharris12@gmail.com 4 | -- 5/23/2021 5 | ---------------------------------------------------------------------------------- 6 | 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | 13 | entity sha256_transform is 14 | generic ( 15 | G_ROLL_FACTOR : integer -- 1=fully unrolled, 64=fully rolled 16 | ); 17 | port ( 18 | CLK : in std_logic; 19 | ARST_N : in std_logic; 20 | FEEDBACK : in std_logic; 21 | COUNT : in unsigned(5 downto 0); 22 | STATE : in std_logic_vector(255 downto 0); 23 | DATA : in std_logic_vector(511 downto 0); 24 | HASH : out std_logic_vector(255 downto 0) 25 | ); 26 | end sha256_transform; 27 | 28 | architecture rtl of sha256_transform is 29 | 30 | component sha256_digester is 31 | port ( 32 | CLK : in std_logic; 33 | ARST_N : in std_logic; 34 | K : in std_logic_vector(31 downto 0); 35 | STATE_IN : in std_logic_vector(255 downto 0); 36 | DATA_IN : in std_logic_vector(511 downto 0); 37 | STATE_OUT : out std_logic_vector(255 downto 0); 38 | DATA_OUT : out std_logic_vector(511 downto 0) 39 | ); 40 | end component; 41 | 42 | constant C_NUM_DIGESTERS : integer := 64/G_ROLL_FACTOR; 43 | constant C_WORD_SIZE : integer := 32; 44 | type slv_array_type is array (natural range <>) of std_logic_vector; 45 | 46 | constant C_SHA_CONSTS : slv_array_type(63 downto 0)(C_WORD_SIZE - 1 downto 0) := 47 | ( 48 | 63 => X"428a2f98", 49 | 62 => X"71374491", 50 | 61 => X"b5c0fbcf", 51 | 60 => X"e9b5dba5", 52 | 59 => X"3956c25b", 53 | 58 => X"59f111f1", 54 | 57 => X"923f82a4", 55 | 56 => X"ab1c5ed5", 56 | 55 => X"d807aa98", 57 | 54 => X"12835b01", 58 | 53 => X"243185be", 59 | 52 => X"550c7dc3", 60 | 51 => X"72be5d74", 61 | 50 => X"80deb1fe", 62 | 49 => X"9bdc06a7", 63 | 48 => X"c19bf174", 64 | 47 => X"e49b69c1", 65 | 46 => X"efbe4786", 66 | 45 => X"0fc19dc6", 67 | 44 => X"240ca1cc", 68 | 43 => X"2de92c6f", 69 | 42 => X"4a7484aa", 70 | 41 => X"5cb0a9dc", 71 | 40 => X"76f988da", 72 | 39 => X"983e5152", 73 | 38 => X"a831c66d", 74 | 37 => X"b00327c8", 75 | 36 => X"bf597fc7", 76 | 35 => X"c6e00bf3", 77 | 34 => X"d5a79147", 78 | 33 => X"06ca6351", 79 | 32 => X"14292967", 80 | 31 => X"27b70a85", 81 | 30 => X"2e1b2138", 82 | 29 => X"4d2c6dfc", 83 | 28 => X"53380d13", 84 | 27 => X"650a7354", 85 | 26 => X"766a0abb", 86 | 25 => X"81c2c92e", 87 | 24 => X"92722c85", 88 | 23 => X"a2bfe8a1", 89 | 22 => X"a81a664b", 90 | 21 => X"c24b8b70", 91 | 20 => X"c76c51a3", 92 | 19 => X"d192e819", 93 | 18 => X"d6990624", 94 | 17 => X"f40e3585", 95 | 16 => X"106aa070", 96 | 15 => X"19a4c116", 97 | 14 => X"1e376c08", 98 | 13 => X"2748774c", 99 | 12 => X"34b0bcb5", 100 | 11 => X"391c0cb3", 101 | 10 => X"4ed8aa4a", 102 | 9 => X"5b9cca4f", 103 | 8 => X"682e6ff3", 104 | 7 => X"748f82ee", 105 | 6 => X"78a5636f", 106 | 5 => X"84c87814", 107 | 4 => X"8cc70208", 108 | 3 => X"90befffa", 109 | 2 => X"a4506ceb", 110 | 1 => X"bef9a3f7", 111 | 0 => X"c67178f2" 112 | ); 113 | 114 | signal state_in_slv : slv_array_type(C_NUM_DIGESTERS - 1 downto 0)(255 downto 0); 115 | signal state_out_slv : slv_array_type(C_NUM_DIGESTERS - 1 downto 0)(255 downto 0); 116 | signal data_in_slv : slv_array_type(C_NUM_DIGESTERS - 1 downto 0)(511 downto 0); 117 | signal data_out_slv : slv_array_type(C_NUM_DIGESTERS - 1 downto 0)(511 downto 0); 118 | 119 | begin 120 | 121 | -- choose to feed in or feedback data and state 122 | process(all) begin 123 | if (feedback = '1') then 124 | for i in 0 to C_NUM_DIGESTERS - 1 loop 125 | state_in_slv(i) <= state_out_slv(i); 126 | data_in_slv(i) <= data_out_slv(i); 127 | end loop; 128 | else 129 | for i in 0 to C_NUM_DIGESTERS - 1 loop 130 | if (i = 0) then 131 | state_in_slv(i) <= STATE; 132 | data_in_slv(i) <= DATA; 133 | else 134 | state_in_slv(i) <= state_out_slv(i - 1); 135 | data_in_slv(i) <= data_out_slv(i - 1); 136 | end if; 137 | end loop; 138 | end if; 139 | end process; 140 | 141 | -- instantiate the number of parallel digesters we want 142 | GEN_DIGESTERS : for i in 0 to C_NUM_DIGESTERS - 1 generate 143 | sha256_digester_x : sha256_digester 144 | port map ( 145 | CLK => CLK, 146 | ARST_N => ARST_N, 147 | K => C_SHA_CONSTS(63 - G_ROLL_FACTOR*i - to_integer(COUNT)), 148 | STATE_IN => state_in_slv(i), 149 | DATA_IN => data_in_slv(i), 150 | STATE_OUT => state_out_slv(i), 151 | DATA_OUT => data_out_slv(i) 152 | ); 153 | end generate; 154 | 155 | -- assign output 156 | process(CLK, ARST_N) begin 157 | if (ARST_N = '0') then 158 | HASH <= (others => '0'); 159 | elsif rising_edge(CLK) then 160 | if (feedback = '0') then 161 | HASH(C_WORD_SIZE - 1 downto 0) <= std_logic_vector(unsigned(STATE(C_WORD_SIZE - 1 downto 0)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(C_WORD_SIZE - 1 downto 0))); 162 | HASH(2*C_WORD_SIZE - 1 downto C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(2*C_WORD_SIZE - 1 downto C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(2*C_WORD_SIZE - 1 downto C_WORD_SIZE))); 163 | HASH(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(3*C_WORD_SIZE - 1 downto 2*C_WORD_SIZE))); 164 | HASH(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(4*C_WORD_SIZE - 1 downto 3*C_WORD_SIZE))); 165 | HASH(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(5*C_WORD_SIZE - 1 downto 4*C_WORD_SIZE))); 166 | HASH(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(6*C_WORD_SIZE - 1 downto 5*C_WORD_SIZE))); 167 | HASH(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(7*C_WORD_SIZE - 1 downto 6*C_WORD_SIZE))); 168 | HASH(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE) <= std_logic_vector(unsigned(STATE(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE)) + unsigned(state_out_slv(C_NUM_DIGESTERS - 1)(8*C_WORD_SIZE - 1 downto 7*C_WORD_SIZE))); 169 | end if; 170 | end if; 171 | end process; 172 | 173 | end rtl; 174 | -------------------------------------------------------------------------------- /FPGA/sha256d.srcs/sources_1/new/sha256d_wrapper.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Richie Harris 3 | -- rkharris12@gmail.com 4 | -- 5/23/2021 5 | ---------------------------------------------------------------------------------- 6 | 7 | 8 | library IEEE; 9 | use IEEE.STD_LOGIC_1164.ALL; 10 | use IEEE.NUMERIC_STD.ALL; 11 | 12 | 13 | entity sha256d_wrapper is 14 | generic ( 15 | G_ROLL_FACTOR_LOG2 : integer -- 0=fully unrolled, 6=fully rolled 16 | ); 17 | port ( 18 | CLK : in std_logic; 19 | ARST_N : in std_logic; 20 | SRST : in std_logic; 21 | START : in std_logic; 22 | MID_STATE : in std_logic_vector(255 downto 0); 23 | RESIDUAL_DATA : in std_logic_vector(95 downto 0); 24 | TARGET : in unsigned(255 downto 0); 25 | FOUND : out std_logic; 26 | NOT_FOUND : out std_logic; 27 | GOLDEN_NONCE : out std_logic_vector(31 downto 0); 28 | CURRENT_NONCE : out std_logic_vector(31 downto 0) 29 | ); 30 | end sha256d_wrapper; 31 | 32 | architecture rtl of sha256d_wrapper is 33 | 34 | function rev_byte_order_in_words( 35 | rev_input : std_logic_vector) 36 | return std_logic_vector is 37 | variable temp : std_logic_vector(rev_input'length - 1 downto 0); 38 | constant c_num_words : integer := rev_input'length/32; 39 | begin 40 | for word in 0 to c_num_words-1 loop -- for each 32 bit word 41 | for byte in 0 to 3 loop -- for each byte in the word 42 | temp(32*word+8*(3-byte+1)-1 downto 32*word+8*(3-byte)) := rev_input(32*word+8*(byte+1)-1 downto 32*word+8*(byte)); 43 | end loop; 44 | end loop; 45 | return temp; 46 | end rev_byte_order_in_words; 47 | 48 | component sha256_transform is 49 | generic ( 50 | G_ROLL_FACTOR : integer -- 1=fully unrolled, 64=fully rolled 51 | ); 52 | port ( 53 | CLK : in std_logic; 54 | ARST_N : in std_logic; 55 | FEEDBACK : in std_logic; 56 | COUNT : in unsigned(5 downto 0); 57 | STATE : in std_logic_vector(255 downto 0); 58 | DATA : in std_logic_vector(511 downto 0); 59 | HASH : out std_logic_vector(255 downto 0) 60 | ); 61 | end component; 62 | 63 | constant C_ROLL_FACTOR : integer := 2**G_ROLL_FACTOR_LOG2; 64 | constant C_NUM_STARTUP_ROUNDS : integer := 2*(64/C_ROLL_FACTOR) + 1; 65 | constant C_GOLDEN_NONCE_OFFSET : integer := 2**(7 - G_ROLL_FACTOR_LOG2) + 1; 66 | constant C_MAX_NONCE : std_logic_vector := X"FFFFFFFF"; 67 | 68 | constant C_STATE_INIT : std_logic_vector := X"5be0cd191f83d9ab9b05688c510e527fa54ff53a3c6ef372bb67ae856a09e667"; 69 | constant C_FIRST_HASH_PAD : std_logic_vector := X"000002800000000000000000000000000000000000000000000000000000000000000000000000000000000080000000"; 70 | constant C_SECOND_HASH_PAD : std_logic_vector := X"0000010000000000000000000000000000000000000000000000000080000000"; 71 | 72 | type state_type is (E_IDLE, E_HASH); 73 | signal state : state_type; 74 | 75 | signal nonce : unsigned(31 downto 0); 76 | signal feedback : std_logic; 77 | signal count : unsigned(5 downto 0); 78 | signal valid : std_logic; 79 | signal startup_rounds_count : unsigned(7 downto 0); 80 | 81 | signal hash1 : std_logic_vector(255 downto 0); 82 | signal hash2 : std_logic_vector(255 downto 0); 83 | signal found_i : std_logic; 84 | 85 | begin 86 | 87 | -- control logic 88 | process(clk, arst_n) begin 89 | if (arst_n = '0') then 90 | state <= E_IDLE; 91 | feedback <= '0'; 92 | count <= (others => '0'); 93 | nonce <= (others => '0'); 94 | startup_rounds_count <= (others => '0'); 95 | valid <= '0'; 96 | NOT_FOUND <= '0'; 97 | elsif rising_edge(clk) then 98 | NOT_FOUND <= '0'; -- pulse generation 99 | if (SRST = '1') then 100 | state <= E_IDLE; 101 | feedback <= '0'; 102 | count <= (others => '0'); 103 | nonce <= (others => '0'); 104 | startup_rounds_count <= (others => '0'); 105 | valid <= '0'; 106 | else 107 | case (state) is 108 | -- wait for driver to configure registers and send start signal 109 | when E_IDLE => 110 | if (START = '1') then 111 | state <= E_HASH; 112 | nonce <= (others => '0'); 113 | count <= (others => '0'); 114 | feedback <= '0'; 115 | startup_rounds_count <= (others => '0'); 116 | end if; 117 | 118 | -- iterate through all nonce values until golden nonce is found or the end is reached 119 | when E_HASH => 120 | if (found_i = '1') then 121 | state <= E_IDLE; 122 | else 123 | count <= count + 1; 124 | feedback <= '1'; 125 | valid <= '0'; 126 | -- control feedback to digesters 127 | if (count = C_ROLL_FACTOR - 1) then 128 | count <= (others => '0'); 129 | feedback <= '0'; 130 | nonce <= nonce + 1; 131 | if (nonce = unsigned(C_MAX_NONCE)) then 132 | state <= E_IDLE; 133 | NOT_FOUND <= '1'; 134 | end if; 135 | if (startup_rounds_count < C_NUM_STARTUP_ROUNDS) then 136 | startup_rounds_count <= startup_rounds_count + 1; 137 | end if; 138 | end if; 139 | -- account for initial pipeline delay 140 | if (startup_rounds_count = C_NUM_STARTUP_ROUNDS) then 141 | valid <= not feedback; 142 | end if; 143 | end if; 144 | 145 | when others => null; 146 | end case; 147 | end if; 148 | end if; 149 | end process; 150 | 151 | -- instantiate hashers 152 | sha1 : sha256_transform 153 | generic map ( 154 | G_ROLL_FACTOR => C_ROLL_FACTOR -- 1=fully unrolled, 64=fully rolled 155 | ) 156 | port map ( 157 | CLK => clk, 158 | ARST_N => arst_n, 159 | FEEDBACK => feedback, 160 | COUNT => count, 161 | STATE => MID_STATE, 162 | DATA => C_FIRST_HASH_PAD & rev_byte_order_in_words(std_logic_vector(nonce)) & RESIDUAL_DATA, 163 | HASH => hash1 164 | ); 165 | 166 | sha2 : sha256_transform 167 | generic map ( 168 | G_ROLL_FACTOR => C_ROLL_FACTOR -- 1=fully unrolled, 64=fully rolled 169 | ) 170 | port map ( 171 | CLK => clk, 172 | ARST_N => arst_n, 173 | FEEDBACK => feedback, 174 | COUNT => count, 175 | STATE => C_STATE_INIT, 176 | DATA => C_SECOND_HASH_PAD & hash1, 177 | HASH => hash2 178 | ); 179 | 180 | -- see if we found the golden nonce 181 | process(clk, arst_n) 182 | variable hash2_rev : std_logic_vector(255 downto 0); 183 | begin 184 | if (arst_n = '0') then 185 | found_i <= '0'; 186 | GOLDEN_NONCE <= (others => '0'); 187 | elsif rising_edge(clk) then 188 | found_i <= '0'; 189 | hash2_rev := rev_byte_order_in_words(hash2); 190 | if ((valid = '1') and (unsigned(hash2_rev) < TARGET)) then 191 | found_i <= '1'; 192 | -- account for offset from current nonce, no clean way for C_ROLL_FACTOR = 1 193 | if (C_ROLL_FACTOR = 1) then 194 | GOLDEN_NONCE <= std_logic_vector(nonce - 130); 195 | else 196 | GOLDEN_NONCE <= std_logic_vector(nonce - C_GOLDEN_NONCE_OFFSET); 197 | end if; 198 | end if; 199 | end if; 200 | end process; 201 | 202 | FOUND <= found_i; 203 | CURRENT_NONCE <= std_logic_vector(nonce); 204 | 205 | end rtl; 206 | -------------------------------------------------------------------------------- /FPGA/sha256d.tcl: -------------------------------------------------------------------------------- 1 | #***************************************************************************************** 2 | # Vivado (TM) v2019.1 (64-bit) 3 | # 4 | # sha256d.tcl: Tcl script for re-creating project 'sha256d' 5 | # 6 | # Generated by Vivado on Sat Nov 13 08:25:26 -0800 2021 7 | # IP Build 2548770 on Fri May 24 18:01:18 MDT 2019 8 | # 9 | # This file contains the Vivado Tcl commands for re-creating the project to the state* 10 | # when this script was generated. In order to re-create the project, please source this 11 | # file in the Vivado Tcl Shell. 12 | # 13 | # * Note that the runs in the created project will be configured the same way as the 14 | # original project, however they will not be launched automatically. To regenerate the 15 | # run results please launch the synthesis/implementation runs as needed. 16 | # 17 | #***************************************************************************************** 18 | # NOTE: In order to use this script for source control purposes, please make sure that the 19 | # following files are added to the source control system:- 20 | # 21 | # 1. This project restoration tcl script (sha256d.tcl) that was generated. 22 | # 23 | # 2. The following source(s) files that were local or imported into the original project. 24 | # (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) 25 | # 26 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/bd/soc/soc.bd" 27 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/new/miner_top.vhd" 28 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/bd/soc/hdl/soc_wrapper.vhd" 29 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/new/sha256_transform.vhd" 30 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/new/sha256_digester.vhd" 31 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/new/sha256d_wrapper.vhd" 32 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/new/pulse_cdc.vhd" 33 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sources_1/ip/clk_wiz_0/clk_wiz_0.xci" 34 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/constrs_1/new/sha256_constraints.xdc" 35 | # "C:/Users/rkhar/OneDrive/Documents/Vivado/sha256d/sha256d.srcs/sim_1/new/sha256d_tb.vhd" 36 | # 37 | # 3. The following remote source files that were added to the original project:- 38 | # 39 | # 40 | # 41 | #***************************************************************************************** 42 | 43 | # Set the reference directory for source file relative paths (by default the value is script directory path) 44 | set origin_dir "." 45 | 46 | # Use origin directory path location variable, if specified in the tcl shell 47 | if { [info exists ::origin_dir_loc] } { 48 | set origin_dir $::origin_dir_loc 49 | } 50 | 51 | # Set the project name 52 | set _xil_proj_name_ "sha256d" 53 | 54 | # Use project name variable, if specified in the tcl shell 55 | if { [info exists ::user_project_name] } { 56 | set _xil_proj_name_ $::user_project_name 57 | } 58 | 59 | variable script_file 60 | set script_file "sha256d.tcl" 61 | 62 | # Help information for this script 63 | proc print_help {} { 64 | variable script_file 65 | puts "\nDescription:" 66 | puts "Recreate a Vivado project from this script. The created project will be" 67 | puts "functionally equivalent to the original project for which this script was" 68 | puts "generated. The script contains commands for creating a project, filesets," 69 | puts "runs, adding/importing sources and setting properties on various objects.\n" 70 | puts "Syntax:" 71 | puts "$script_file" 72 | puts "$script_file -tclargs \[--origin_dir \]" 73 | puts "$script_file -tclargs \[--project_name \]" 74 | puts "$script_file -tclargs \[--help\]\n" 75 | puts "Usage:" 76 | puts "Name Description" 77 | puts "-------------------------------------------------------------------------" 78 | puts "\[--origin_dir \] Determine source file paths wrt this path. Default" 79 | puts " origin_dir path value is \".\", otherwise, the value" 80 | puts " that was set with the \"-paths_relative_to\" switch" 81 | puts " when this script was generated.\n" 82 | puts "\[--project_name \] Create project with the specified name. Default" 83 | puts " name is the name of the project from where this" 84 | puts " script was generated.\n" 85 | puts "\[--help\] Print help information for this script" 86 | puts "-------------------------------------------------------------------------\n" 87 | exit 0 88 | } 89 | 90 | if { $::argc > 0 } { 91 | for {set i 0} {$i < $::argc} {incr i} { 92 | set option [string trim [lindex $::argv $i]] 93 | switch -regexp -- $option { 94 | "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } 95 | "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } 96 | "--help" { print_help } 97 | default { 98 | if { [regexp {^-} $option] } { 99 | puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" 100 | return 1 101 | } 102 | } 103 | } 104 | } 105 | } 106 | 107 | # Set the directory path for the original project from where this script was exported 108 | set orig_proj_dir "[file normalize "$origin_dir/"]" 109 | 110 | # Create project 111 | create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7z020clg400-1 112 | 113 | # Set the directory path for the new project 114 | set proj_dir [get_property directory [current_project]] 115 | 116 | # Set project properties 117 | set obj [current_project] 118 | set_property -name "board_part" -value "tul.com.tw:pynq-z2:part0:1.0" -objects $obj 119 | set_property -name "default_lib" -value "xil_defaultlib" -objects $obj 120 | set_property -name "dsa.accelerator_binary_content" -value "bitstream" -objects $obj 121 | set_property -name "dsa.accelerator_binary_format" -value "xclbin2" -objects $obj 122 | set_property -name "dsa.board_id" -value "pynq-z2" -objects $obj 123 | set_property -name "dsa.description" -value "Vivado generated DSA" -objects $obj 124 | set_property -name "dsa.dr_bd_base_address" -value "0" -objects $obj 125 | set_property -name "dsa.emu_dir" -value "emu" -objects $obj 126 | set_property -name "dsa.flash_interface_type" -value "bpix16" -objects $obj 127 | set_property -name "dsa.flash_offset_address" -value "0" -objects $obj 128 | set_property -name "dsa.flash_size" -value "1024" -objects $obj 129 | set_property -name "dsa.host_architecture" -value "x86_64" -objects $obj 130 | set_property -name "dsa.host_interface" -value "pcie" -objects $obj 131 | set_property -name "dsa.num_compute_units" -value "60" -objects $obj 132 | set_property -name "dsa.platform_state" -value "pre_synth" -objects $obj 133 | set_property -name "dsa.vendor" -value "xilinx" -objects $obj 134 | set_property -name "dsa.version" -value "0.0" -objects $obj 135 | set_property -name "enable_vhdl_2008" -value "1" -objects $obj 136 | set_property -name "ip_cache_permissions" -value "read write" -objects $obj 137 | set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj 138 | set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj 139 | set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj 140 | set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj 141 | set_property -name "simulator_language" -value "Mixed" -objects $obj 142 | set_property -name "source_mgmt_mode" -value "DisplayOnly" -objects $obj 143 | set_property -name "target_language" -value "VHDL" -objects $obj 144 | set_property -name "webtalk.activehdl_export_sim" -value "42" -objects $obj 145 | set_property -name "webtalk.ies_export_sim" -value "42" -objects $obj 146 | set_property -name "webtalk.modelsim_export_sim" -value "42" -objects $obj 147 | set_property -name "webtalk.questa_export_sim" -value "42" -objects $obj 148 | set_property -name "webtalk.riviera_export_sim" -value "42" -objects $obj 149 | set_property -name "webtalk.vcs_export_sim" -value "42" -objects $obj 150 | set_property -name "webtalk.xsim_export_sim" -value "42" -objects $obj 151 | set_property -name "webtalk.xsim_launch_sim" -value "12" -objects $obj 152 | set_property -name "xpm_libraries" -value "XPM_CDC XPM_FIFO XPM_MEMORY" -objects $obj 153 | 154 | # Create 'sources_1' fileset (if not found) 155 | if {[string equal [get_filesets -quiet sources_1] ""]} { 156 | create_fileset -srcset sources_1 157 | } 158 | 159 | # Set 'sources_1' fileset object 160 | set obj [get_filesets sources_1] 161 | # Import local files from the original project 162 | set files [list \ 163 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/bd/soc/soc.bd" ]\ 164 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/new/miner_top.vhd" ]\ 165 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/bd/soc/hdl/soc_wrapper.vhd" ]\ 166 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/new/sha256_transform.vhd" ]\ 167 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/new/sha256_digester.vhd" ]\ 168 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/new/sha256d_wrapper.vhd" ]\ 169 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/new/pulse_cdc.vhd" ]\ 170 | [file normalize "${origin_dir}/sha256d.srcs/sources_1/ip/clk_wiz_0/clk_wiz_0.xci" ]\ 171 | ] 172 | set imported_files [import_files -fileset sources_1 $files] 173 | 174 | # Set 'sources_1' fileset file properties for remote files 175 | # None 176 | 177 | # Set 'sources_1' fileset file properties for local files 178 | set file "soc/soc.bd" 179 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 180 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 181 | 182 | set file "new/miner_top.vhd" 183 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 184 | set_property -name "file_type" -value "VHDL 2008" -objects $file_obj 185 | 186 | set file "hdl/soc_wrapper.vhd" 187 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 188 | set_property -name "file_type" -value "VHDL" -objects $file_obj 189 | 190 | set file "new/sha256_transform.vhd" 191 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 192 | set_property -name "file_type" -value "VHDL 2008" -objects $file_obj 193 | 194 | set file "new/sha256_digester.vhd" 195 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 196 | set_property -name "file_type" -value "VHDL 2008" -objects $file_obj 197 | 198 | set file "new/sha256d_wrapper.vhd" 199 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 200 | set_property -name "file_type" -value "VHDL" -objects $file_obj 201 | 202 | set file "new/pulse_cdc.vhd" 203 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 204 | set_property -name "file_type" -value "VHDL" -objects $file_obj 205 | 206 | set file "clk_wiz_0/clk_wiz_0.xci" 207 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 208 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 209 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 210 | if { ![get_property "is_locked" $file_obj] } { 211 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 212 | } 213 | 214 | 215 | # Set 'sources_1' fileset properties 216 | set obj [get_filesets sources_1] 217 | set_property -name "top" -value "miner_top" -objects $obj 218 | set_property -name "top_auto_set" -value "0" -objects $obj 219 | 220 | # Create 'constrs_1' fileset (if not found) 221 | if {[string equal [get_filesets -quiet constrs_1] ""]} { 222 | create_fileset -constrset constrs_1 223 | } 224 | 225 | # Set 'constrs_1' fileset object 226 | set obj [get_filesets constrs_1] 227 | 228 | # Add/Import constrs file and set constrs file properties 229 | set file "[file normalize "$origin_dir/sha256d.srcs/constrs_1/new/sha256_constraints.xdc"]" 230 | set file_imported [import_files -fileset constrs_1 [list $file]] 231 | set file "new/sha256_constraints.xdc" 232 | set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] 233 | set_property -name "file_type" -value "XDC" -objects $file_obj 234 | 235 | # Set 'constrs_1' fileset properties 236 | set obj [get_filesets constrs_1] 237 | 238 | # Create 'sim_1' fileset (if not found) 239 | if {[string equal [get_filesets -quiet sim_1] ""]} { 240 | create_fileset -simset sim_1 241 | } 242 | 243 | # Set 'sim_1' fileset object 244 | set obj [get_filesets sim_1] 245 | # Import local files from the original project 246 | set files [list \ 247 | [file normalize "${origin_dir}/sha256d.srcs/sim_1/new/sha256d_tb.vhd" ]\ 248 | ] 249 | set imported_files [import_files -fileset sim_1 $files] 250 | 251 | # Set 'sim_1' fileset file properties for remote files 252 | # None 253 | 254 | # Set 'sim_1' fileset file properties for local files 255 | set file "new/sha256d_tb.vhd" 256 | set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]] 257 | set_property -name "file_type" -value "VHDL" -objects $file_obj 258 | 259 | 260 | # Set 'sim_1' fileset properties 261 | set obj [get_filesets sim_1] 262 | set_property -name "top" -value "sha256_transform_sim" -objects $obj 263 | set_property -name "top_auto_set" -value "0" -objects $obj 264 | 265 | # Set 'utils_1' fileset object 266 | set obj [get_filesets utils_1] 267 | # Empty (no sources present) 268 | 269 | # Set 'utils_1' fileset properties 270 | set obj [get_filesets utils_1] 271 | 272 | # Create 'synth_1' run (if not found) 273 | if {[string equal [get_runs -quiet synth_1] ""]} { 274 | create_run -name synth_1 -part xc7z020clg400-1 -flow {Vivado Synthesis 2019} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 275 | } else { 276 | set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] 277 | set_property flow "Vivado Synthesis 2019" [get_runs synth_1] 278 | } 279 | set obj [get_runs synth_1] 280 | set_property set_report_strategy_name 1 $obj 281 | set_property report_strategy {Vivado Synthesis Default Reports} $obj 282 | set_property set_report_strategy_name 0 $obj 283 | # Create 'synth_1_synth_report_utilization_0' report (if not found) 284 | if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { 285 | create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 286 | } 287 | set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] 288 | if { $obj != "" } { 289 | 290 | } 291 | set obj [get_runs synth_1] 292 | set_property -name "needs_refresh" -value "1" -objects $obj 293 | set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj 294 | 295 | # set the current synth run 296 | current_run -synthesis [get_runs synth_1] 297 | 298 | # Create 'impl_1' run (if not found) 299 | if {[string equal [get_runs -quiet impl_1] ""]} { 300 | create_run -name impl_1 -part xc7z020clg400-1 -flow {Vivado Implementation 2019} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 301 | } else { 302 | set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] 303 | set_property flow "Vivado Implementation 2019" [get_runs impl_1] 304 | } 305 | set obj [get_runs impl_1] 306 | set_property set_report_strategy_name 1 $obj 307 | set_property report_strategy {Vivado Implementation Default Reports} $obj 308 | set_property set_report_strategy_name 0 $obj 309 | # Create 'impl_1_init_report_timing_summary_0' report (if not found) 310 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { 311 | 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 312 | } 313 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] 314 | if { $obj != "" } { 315 | set_property -name "is_enabled" -value "0" -objects $obj 316 | set_property -name "options.max_paths" -value "10" -objects $obj 317 | 318 | } 319 | # Create 'impl_1_opt_report_drc_0' report (if not found) 320 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { 321 | create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 322 | } 323 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] 324 | if { $obj != "" } { 325 | 326 | } 327 | # Create 'impl_1_opt_report_timing_summary_0' report (if not found) 328 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { 329 | 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 330 | } 331 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] 332 | if { $obj != "" } { 333 | set_property -name "is_enabled" -value "0" -objects $obj 334 | set_property -name "options.max_paths" -value "10" -objects $obj 335 | 336 | } 337 | # Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) 338 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { 339 | 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 340 | } 341 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] 342 | if { $obj != "" } { 343 | set_property -name "is_enabled" -value "0" -objects $obj 344 | set_property -name "options.max_paths" -value "10" -objects $obj 345 | 346 | } 347 | # Create 'impl_1_place_report_io_0' report (if not found) 348 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { 349 | create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 350 | } 351 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] 352 | if { $obj != "" } { 353 | 354 | } 355 | # Create 'impl_1_place_report_utilization_0' report (if not found) 356 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { 357 | create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 358 | } 359 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] 360 | if { $obj != "" } { 361 | 362 | } 363 | # Create 'impl_1_place_report_control_sets_0' report (if not found) 364 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { 365 | 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 366 | } 367 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] 368 | if { $obj != "" } { 369 | set_property -name "options.verbose" -value "1" -objects $obj 370 | 371 | } 372 | # Create 'impl_1_place_report_incremental_reuse_0' report (if not found) 373 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { 374 | 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 375 | } 376 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] 377 | if { $obj != "" } { 378 | set_property -name "is_enabled" -value "0" -objects $obj 379 | 380 | } 381 | # Create 'impl_1_place_report_incremental_reuse_1' report (if not found) 382 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { 383 | 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 384 | } 385 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] 386 | if { $obj != "" } { 387 | set_property -name "is_enabled" -value "0" -objects $obj 388 | 389 | } 390 | # Create 'impl_1_place_report_timing_summary_0' report (if not found) 391 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { 392 | 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 393 | } 394 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] 395 | if { $obj != "" } { 396 | set_property -name "is_enabled" -value "0" -objects $obj 397 | set_property -name "options.max_paths" -value "10" -objects $obj 398 | 399 | } 400 | # Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) 401 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { 402 | 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 403 | } 404 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] 405 | if { $obj != "" } { 406 | set_property -name "is_enabled" -value "0" -objects $obj 407 | set_property -name "options.max_paths" -value "10" -objects $obj 408 | 409 | } 410 | # Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) 411 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { 412 | 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 413 | } 414 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] 415 | if { $obj != "" } { 416 | set_property -name "is_enabled" -value "0" -objects $obj 417 | set_property -name "options.max_paths" -value "10" -objects $obj 418 | 419 | } 420 | # Create 'impl_1_route_report_drc_0' report (if not found) 421 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { 422 | create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 423 | } 424 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] 425 | if { $obj != "" } { 426 | 427 | } 428 | # Create 'impl_1_route_report_methodology_0' report (if not found) 429 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { 430 | create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 431 | } 432 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] 433 | if { $obj != "" } { 434 | 435 | } 436 | # Create 'impl_1_route_report_power_0' report (if not found) 437 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { 438 | create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 439 | } 440 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] 441 | if { $obj != "" } { 442 | 443 | } 444 | # Create 'impl_1_route_report_route_status_0' report (if not found) 445 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { 446 | 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 447 | } 448 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] 449 | if { $obj != "" } { 450 | 451 | } 452 | # Create 'impl_1_route_report_timing_summary_0' report (if not found) 453 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { 454 | 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 455 | } 456 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] 457 | if { $obj != "" } { 458 | set_property -name "options.max_paths" -value "10" -objects $obj 459 | 460 | } 461 | # Create 'impl_1_route_report_incremental_reuse_0' report (if not found) 462 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { 463 | 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 464 | } 465 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] 466 | if { $obj != "" } { 467 | 468 | } 469 | # Create 'impl_1_route_report_clock_utilization_0' report (if not found) 470 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { 471 | 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 472 | } 473 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] 474 | if { $obj != "" } { 475 | 476 | } 477 | # Create 'impl_1_route_report_bus_skew_0' report (if not found) 478 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { 479 | 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 480 | } 481 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] 482 | if { $obj != "" } { 483 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 484 | 485 | } 486 | # Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) 487 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { 488 | 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 489 | } 490 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] 491 | if { $obj != "" } { 492 | set_property -name "options.max_paths" -value "10" -objects $obj 493 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 494 | 495 | } 496 | # Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) 497 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { 498 | 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 499 | } 500 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] 501 | if { $obj != "" } { 502 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 503 | 504 | } 505 | set obj [get_runs impl_1] 506 | set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj 507 | set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj 508 | set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj 509 | 510 | # set the current impl run 511 | current_run -implementation [get_runs impl_1] 512 | 513 | puts "INFO: Project created:${_xil_proj_name_}" 514 | # Create 'drc_1' gadget (if not found) 515 | if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} { 516 | create_dashboard_gadget -name {drc_1} -type drc 517 | } 518 | set obj [get_dashboard_gadgets [ list "drc_1" ] ] 519 | set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj 520 | 521 | # Create 'methodology_1' gadget (if not found) 522 | if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} { 523 | create_dashboard_gadget -name {methodology_1} -type methodology 524 | } 525 | set obj [get_dashboard_gadgets [ list "methodology_1" ] ] 526 | set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj 527 | 528 | # Create 'power_1' gadget (if not found) 529 | if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} { 530 | create_dashboard_gadget -name {power_1} -type power 531 | } 532 | set obj [get_dashboard_gadgets [ list "power_1" ] ] 533 | set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj 534 | 535 | # Create 'timing_1' gadget (if not found) 536 | if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} { 537 | create_dashboard_gadget -name {timing_1} -type timing 538 | } 539 | set obj [get_dashboard_gadgets [ list "timing_1" ] ] 540 | set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj 541 | 542 | # Create 'utilization_1' gadget (if not found) 543 | if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} { 544 | create_dashboard_gadget -name {utilization_1} -type utilization 545 | } 546 | set obj [get_dashboard_gadgets [ list "utilization_1" ] ] 547 | set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj 548 | set_property -name "run.step" -value "synth_design" -objects $obj 549 | set_property -name "run.type" -value "synthesis" -objects $obj 550 | 551 | # Create 'utilization_2' gadget (if not found) 552 | if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} { 553 | create_dashboard_gadget -name {utilization_2} -type utilization 554 | } 555 | set obj [get_dashboard_gadgets [ list "utilization_2" ] ] 556 | set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj 557 | 558 | move_dashboard_gadget -name {utilization_1} -row 0 -col 0 559 | move_dashboard_gadget -name {power_1} -row 1 -col 0 560 | move_dashboard_gadget -name {drc_1} -row 2 -col 0 561 | move_dashboard_gadget -name {timing_1} -row 0 -col 1 562 | move_dashboard_gadget -name {utilization_2} -row 1 -col 1 563 | move_dashboard_gadget -name {methodology_1} -row 2 -col 1 564 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fpga_bitcoin_miner 2 | Stratum Bitcoin mining client with support for CPU and FPGA mining. FPGA implementation of Sha256d for the Pynq-Z2 board. 3 | https://www.youtube.com/watch?v=M_AocgfvTIs 4 | ## Requirements 5 | Standard Python modules 6 | 7 | Pynq-Z2 board - http://www.pynq.io/board.html 8 | ## Tool versions 9 | Xilinx Vivado 2019.1 10 | 11 | Python 3.6.5 12 | ## Instructions 13 | Copy the overlays folder to the same directory as fpgaminer.py to match line 115 of fpgaminer.py 14 | 15 | Copy the pynq module located in /usr/local/lib/python3.6/dist-packages/pynq to the same directory as fpgaminer.py 16 | 17 | run `python3 fpgaminer.py -h` for command line arguments 18 | 19 | To regenerate the Vivado project, open Vivado, cd to the FPGA directory, and run `source sha256d.tcl` in the TCL command prompt 20 | ## Results 21 | 22 | FPGA Sha256d: 40 Mhashes/sec 23 | 24 | Hashlib Sha256d: 17 khashes/sec 25 | 26 | Python Sha256d: 67 hashes/sec 27 | ## Credits 28 | I used these repositories as reference for this project. 29 | 30 | https://github.com/progranism/Open-Source-FPGA-Bitcoin-Miner 31 | 32 | https://github.com/ricmoo/nightminer 33 | -------------------------------------------------------------------------------- /fpgaminer.py: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # Richie Harris 3 | # rkharris12@gmail.com 4 | # 5/23/2021 5 | ######################################################################### 6 | 7 | import base64, json, hashlib, hmac, math, socket, struct, sys, threading, time, urllib.parse, sha256d_fpga_sim 8 | from pynq import Overlay, mmio 9 | 10 | # RPC ID 11 | USER_AGENT = "FPGAMiner" 12 | VERSION = [0, 1] 13 | 14 | # These control which sha256d implementation to use 15 | SHA256D_LIBRARY_AUTO = 'auto' 16 | SHA256D_LIBRARY_HASHLIB = 'hashlib' 17 | SHA256D_LIBRARY_PYTHON = 'python' 18 | SHA256D_LIBRARY_FPGA = 'fpga' 19 | SHA256D_LIBRARIES = [ SHA256D_LIBRARY_AUTO, SHA256D_LIBRARY_HASHLIB, SHA256D_LIBRARY_PYTHON, SHA256D_LIBRARY_FPGA ] 20 | 21 | # Verbosity and log level 22 | QUIET = False 23 | DEBUG = False 24 | DEBUG_PROTOCOL = False 25 | TEST = False 26 | LEVEL_PROTOCOL = 'protocol' 27 | LEVEL_INFO = 'info' 28 | LEVEL_DEBUG = 'debug' 29 | LEVEL_ERROR = 'error' 30 | 31 | # FPGA hasher register banks 32 | base_addr = 0x43c00000 33 | ctl_status_base_addr = 0x000 34 | mid_state_base_addr = 0x400 35 | residual_data_base_addr = 0x800 36 | target_base_addr = 0xc00 37 | ctl_status_mem = mmio.MMIO(base_addr + ctl_status_base_addr, 24) 38 | mid_state_mem = mmio.MMIO(base_addr + mid_state_base_addr, 32) 39 | residual_data_mem = mmio.MMIO(base_addr + residual_data_base_addr, 12) 40 | target_mem = mmio.MMIO(base_addr + target_base_addr, 32) 41 | 42 | def sha256d_python(message_bin): 43 | '''FPGA hashing python simulator.''' 44 | message = message_bin.hex() # convert to hex string 45 | state_init = 0x5be0cd191f83d9ab9b05688c510e527fa54ff53a3c6ef372bb67ae856a09e667 # initial state of state registers in hash function 46 | message_blocks = sha256d_fpga_sim.pad(message) 47 | # hash first 512 bit message block 48 | first_block = sha256d_fpga_sim.reverse_word_order(message_blocks[0:(512//4)]) # reverse word ordering for hash function 49 | data_in = int(first_block, 16) # convert from hex string to numerical data 50 | mid_state = sha256d_fpga_sim.hash(state_init, data_in) 51 | # hash second 512 bit message_block 52 | second_block = sha256d_fpga_sim.reverse_word_order(message_blocks[(512//4):(1024//4)]) # reverse word ordering for hash function 53 | data_in = int(second_block, 16) # convert from hex string to numerical data 54 | hash_1 = sha256d_fpga_sim.hash(mid_state, data_in) 55 | hash_1_word_rev = sha256d_fpga_sim.reverse_word_order(hex(hash_1).rstrip("L").lstrip("0x")) # put it back into big endian word order for padding function 56 | # hash a second time 57 | padded_in_2 = sha256d_fpga_sim.pad(hash_1_word_rev) 58 | block = sha256d_fpga_sim.reverse_word_order(padded_in_2) # reverse word ordering for hash function 59 | data_in = int(block, 16) # convert from hex string to numerical data 60 | hash_2 = sha256d_fpga_sim.hash(state_init, data_in) 61 | hash_2_word_rev = sha256d_fpga_sim.reverse_word_order(hex(hash_2).rstrip("L").lstrip("0x")) # put it back into big endian word order 62 | while len(hash_2_word_rev) < 64: 63 | hash_2_word_rev = hash_2_word_rev + "0" 64 | hash_2_result = bytes.fromhex(hash_2_word_rev) # convert to bytes which is the expected output 65 | return hash_2_result 66 | 67 | def sha256d_hashlib(message): 68 | '''Double SHA256 Hashing function.''' 69 | return hashlib.sha256(hashlib.sha256(message).digest()).digest() 70 | 71 | def log(message, level): 72 | '''Conditionally write a message to stdout based on command line options and level.''' 73 | global DEBUG 74 | global DEBUG_PROTOCOL 75 | global QUIET 76 | 77 | if QUIET and level != LEVEL_ERROR: return 78 | if not DEBUG_PROTOCOL and level == LEVEL_PROTOCOL: return 79 | if not DEBUG and level == LEVEL_DEBUG: return 80 | 81 | if level != LEVEL_PROTOCOL: message = '[%s] %s' % (level.upper(), message) 82 | 83 | print ("[%s] %s" % (time.strftime("%Y-%m-%d %H:%M:%S"), message)) 84 | 85 | def swap_endian_word(hex_word): 86 | '''Swaps the endianness of a hexidecimal string of a word and converts to bytes.''' 87 | message = bytes.fromhex(hex_word) 88 | if len(message) != 4: raise ValueError('Must be 4-byte word') 89 | return message[::-1] 90 | 91 | def swap_endian_words(hex_words): 92 | '''Swaps the endianness of a hexidecimal string of words and converts to bytes.''' 93 | message = bytes.fromhex(hex_words) 94 | if len(message) % 4 != 0: raise ValueError('Must be 4-byte word aligned') 95 | return b''.join([ message[4 * i: 4 * i + 4][::-1] for i in range(0, len(message) // 4) ]) 96 | 97 | def human_readable_hashrate(hashrate): 98 | '''Returns a human readable representation of hashrate.''' 99 | if hashrate < 1000: 100 | return '%2f hashes/s' % hashrate 101 | if hashrate < 1000000: 102 | return '%2f khashes/s' % (hashrate / 1000) 103 | if hashrate < 1000000000: 104 | return '%2f Mhashes/s' % (hashrate / 1000000) 105 | return '%2f Ghashes/s' % (hashrate / 1000000000) 106 | 107 | SHA256D_LIBRARY = None 108 | sha256d_proof_of_work = None 109 | def set_sha256d_library(library = SHA256D_LIBRARY_AUTO): 110 | '''Sets the sha256d library implementation to use.''' 111 | global SHA256D_LIBRARY 112 | global sha256d_proof_of_work 113 | 114 | if library == SHA256D_LIBRARY_FPGA: 115 | overlay = Overlay('/home/xilinx/overlays/miner_top.bit') # Load Pynq FPGA overlay 116 | sha256d_proof_of_work = None 117 | SHA256D_LIBRARY = library 118 | 119 | elif library == SHA256D_LIBRARY_PYTHON: 120 | sha256d_proof_of_work = lambda message: sha256d_python(message) 121 | SHA256D_LIBRARY = library 122 | 123 | else: 124 | sha256d_proof_of_work = lambda message: sha256d_hashlib(message) 125 | SHA256D_LIBRARY = SHA256D_LIBRARY_HASHLIB 126 | 127 | class Job(object): 128 | '''Encapsulates a Job from the network and necessary helper methods to mine. 129 | 130 | "If you have a procedure with 10 parameters, you probably missed some." 131 | ~Alan Perlis 132 | ''' 133 | def __init__(self, job_id, prevhash, coinb1, coinb2, merkle_branches, version, nbits, ntime, target, extranonce1, extranonce2_size, proof_of_work): 134 | # Job parts from the mining.notify command 135 | self._job_id = job_id 136 | self._prevhash = prevhash 137 | self._coinb1 = coinb1 138 | self._coinb2 = coinb2 139 | self._merkle_branches = [ b for b in merkle_branches ] 140 | self._version = version 141 | self._nbits = nbits 142 | self._ntime = ntime 143 | # Job information needed to mine from mining.subsribe 144 | self._target = target 145 | self._extranonce1 = extranonce1 146 | self._extranonce2_size = extranonce2_size 147 | # Proof of work algorithm 148 | self._proof_of_work = proof_of_work 149 | # Flag to stop this job's mine coroutine 150 | self._done = False 151 | # Hash metrics (start time, delta time, total hashes) 152 | self._dt = 0.0 153 | self._hash_count = 0 154 | 155 | # Accessors 156 | id = property(lambda s: s._job_id) 157 | prevhash = property(lambda s: s._prevhash) 158 | coinb1 = property(lambda s: s._coinb1) 159 | coinb2 = property(lambda s: s._coinb2) 160 | merkle_branches = property(lambda s: [ b for b in s._merkle_branches ]) 161 | version = property(lambda s: s._version) 162 | nbits = property(lambda s: s._nbits) 163 | ntime = property(lambda s: s._ntime) 164 | 165 | target = property(lambda s: s._target) 166 | extranonce1 = property(lambda s: s._extranonce1) 167 | extranonce2_size = property(lambda s: s._extranonce2_size) 168 | 169 | proof_of_work = property(lambda s: s._proof_of_work) 170 | 171 | @property 172 | def hashrate(self): 173 | '''The current hashrate, or if stopped hashrate for the job's lifetime.''' 174 | if self._dt == 0: return 0.0 175 | return self._hash_count / self._dt 176 | 177 | def merkle_root_bin(self, extranonce2_bin): 178 | '''Builds a merkle root from the merkle tree''' 179 | coinbase_bin = bytes.fromhex(self._coinb1) + bytes.fromhex(self._extranonce1) + extranonce2_bin + bytes.fromhex(self._coinb2) 180 | coinbase_hash_bin = sha256d_hashlib(coinbase_bin) 181 | 182 | merkle_root = coinbase_hash_bin 183 | for branch in self._merkle_branches: 184 | merkle_root = sha256d_hashlib(merkle_root + bytes.fromhex(branch)) 185 | return merkle_root 186 | 187 | def stop(self): 188 | '''Requests the mine coroutine stop after its current iteration.''' 189 | self._done = True 190 | 191 | def mine(self, nonce_start = 0, nonce_stride = 1): 192 | '''Returns an iterator that iterates over valid proof-of-work shares. 193 | 194 | This is a co-routine; that takes a LONG time; the calling thread should look like: 195 | 196 | for result in job.mine(self): 197 | submit_work(result) 198 | 199 | nonce_start and nonce_stride are useful for multi-processing if you would like 200 | to assign each process a different starting nonce (0, 1, 2, ...) and a stride 201 | equal to the number of processes. 202 | ''' 203 | t0 = time.time() 204 | 205 | # @TODO: test for extranonce != 0... Do I reverse it or not? 206 | for extranonce2 in range(0, 0x7fffffff): 207 | 208 | # Must be unique for any given job id, according to http://mining.bitcoin.cz/stratum-mining/ but never seems enforced? 209 | extranonce2_bin = struct.pack('' % (self.id, self.prevhash, self.coinb1, self.coinb2, self.merkle_branches, self.version, self.nbits, self.ntime, self.target, self.extranonce1, self.extranonce2_size) 298 | 299 | # Subscription state 300 | class Subscription(object): 301 | '''Encapsulates the Subscription state from the JSON-RPC server''' 302 | 303 | # Subclasses should override this 304 | def ProofOfWork(header): 305 | raise Exception('Do not use the Subscription class directly, subclass it') 306 | 307 | class StateException(Exception): pass 308 | 309 | def __init__(self): 310 | self._id = None 311 | self._difficulty = None 312 | self._extranonce1 = None 313 | self._extranonce2_size = None 314 | self._target = None 315 | self._worker_name = None 316 | self._mining_thread = None 317 | 318 | # Accessors 319 | id = property(lambda s: s._id) 320 | worker_name = property(lambda s: s._worker_name) 321 | 322 | difficulty = property(lambda s: s._difficulty) 323 | target = property(lambda s: s._target) 324 | 325 | extranonce1 = property(lambda s: s._extranonce1) 326 | extranonce2_size = property(lambda s: s._extranonce2_size) 327 | 328 | def set_worker_name(self, worker_name): 329 | if self._worker_name: 330 | raise self.StateException('Already authenticated as %r (requesting %r)' % (self._username, username)) 331 | 332 | self._worker_name = worker_name 333 | 334 | def _set_target(self, target): 335 | self._target = '%064x' % target 336 | 337 | def set_difficulty(self, difficulty): 338 | if difficulty < 0: raise self.StateException('Difficulty must be non-negative') 339 | 340 | # Compute target 341 | if difficulty == 0: 342 | target = 2 ** 256 - 1 343 | else: 344 | target = min(int((0xffff0000 * 2 ** (256 - 64) + 1) / difficulty - 1 + 0.5), 2 ** 256 - 1) 345 | 346 | self._difficulty = difficulty 347 | self._set_target(target) 348 | 349 | def set_subscription(self, subscription_id, extranonce1, extranonce2_size): 350 | if self._id is not None: 351 | raise self.StateException('Already subscribed') 352 | 353 | self._id = subscription_id 354 | self._extranonce1 = extranonce1 355 | self._extranonce2_size = extranonce2_size 356 | 357 | def create_job(self, job_id, prevhash, coinb1, coinb2, merkle_branches, version, nbits, ntime): 358 | '''Creates a new Job object populated with all the goodness it needs to mine.''' 359 | if self._id is None: 360 | raise self.StateException('Not subscribed') 361 | 362 | return Job( 363 | job_id = job_id, 364 | prevhash = prevhash, 365 | coinb1 = coinb1, 366 | coinb2 = coinb2, 367 | merkle_branches = merkle_branches, 368 | version = version, 369 | nbits = nbits, 370 | ntime = ntime, 371 | target = self.target, 372 | extranonce1 = self._extranonce1, 373 | extranonce2_size = self.extranonce2_size, 374 | proof_of_work = self.ProofOfWork 375 | ) 376 | 377 | def __str__(self): 378 | return '' % (self.id, self.extranonce1, self.extranonce2_size, self.difficulty, self.worker_name) 379 | 380 | class SubscriptionSHA256D(Subscription): 381 | '''Subscription for Double-SHA256-based coins, like Bitcoin.''' 382 | ProofOfWork = lambda s, m: (sha256d_proof_of_work(m)) 383 | 384 | class SimpleJsonRpcClient(object): 385 | '''Simple JSON-RPC client. 386 | 387 | To use this class: 388 | 1) Create a sub-class 389 | 2) Override handle_reply(self, request, reply) 390 | 3) Call connect(socket) 391 | 392 | Use self.send(method, params) to send JSON-RPC commands to the server. 393 | 394 | A new thread is created for listening to the connection; so calls to handle_reply 395 | are synchronized. It is safe to call send from withing handle_reply. 396 | ''' 397 | 398 | class ClientException(Exception): pass 399 | 400 | class RequestReplyException(Exception): 401 | def __init__(self, message, reply, request = None): 402 | Exception.__init__(self, message) 403 | self._reply = reply 404 | self._request = request 405 | 406 | request = property(lambda s: s._request) 407 | reply = property(lambda s: s._reply) 408 | 409 | class RequestReplyWarning(RequestReplyException): 410 | '''Sub-classes can raise this to inform the user of JSON-RPC server issues.''' 411 | pass 412 | 413 | def __init__(self): 414 | self._socket = None 415 | self._lock = threading.RLock() 416 | self._rpc_thread = None 417 | self._message_id = 1 418 | self._requests = dict() 419 | 420 | 421 | def _handle_incoming_rpc(self): 422 | data = "" 423 | while True: 424 | # Get the next line if we have one, otherwise, read and block 425 | if '\n' in data: 426 | (line, data) = data.split('\n', 1) 427 | else: 428 | chunk = self._socket.recv(1024).decode() 429 | data += chunk 430 | continue 431 | 432 | log('JSON-RPC Server > ' + line, LEVEL_PROTOCOL) 433 | 434 | # Parse the JSON 435 | try: 436 | reply = json.loads(line) 437 | except Exception as e: 438 | log("JSON-RPC Error: Failed to parse JSON %r (skipping)" % line, LEVEL_ERROR) 439 | continue 440 | 441 | try: 442 | request = None 443 | with self._lock: 444 | if 'id' in reply and reply['id'] in self._requests: 445 | request = self._requests[reply['id']] 446 | self.handle_reply(request = request, reply = reply) 447 | except self.RequestReplyWarning as e: 448 | output = e.message 449 | if e.request: 450 | output += '\n ' + e.request 451 | output += '\n ' + e.reply 452 | log(output, LEVEL_ERROR) 453 | 454 | def handle_reply(self, request, reply): 455 | # Override this method in sub-classes to handle a message from the server 456 | raise self.RequestReplyWarning('Override this method') 457 | 458 | def send(self, method, params): 459 | '''Sends a message to the JSON-RPC server''' 460 | if not self._socket: 461 | raise self.ClientException('Not connected') 462 | 463 | request = dict(id = self._message_id, method = method, params = params) 464 | message = json.dumps(request) 465 | message += '\n' 466 | with self._lock: 467 | self._requests[self._message_id] = request 468 | self._message_id += 1 469 | self._socket.send(message.encode()) 470 | 471 | log('JSON-RPC Server < ' + message, LEVEL_PROTOCOL) 472 | 473 | return request 474 | 475 | def connect(self, socket): 476 | '''Connects to a remove JSON-RPC server''' 477 | if self._rpc_thread: 478 | raise self.ClientException('Already connected') 479 | 480 | self._socket = socket 481 | self._rpc_thread = threading.Thread(target = self._handle_incoming_rpc) 482 | self._rpc_thread.daemon = True 483 | self._rpc_thread.start() 484 | 485 | # Miner client 486 | class Miner(SimpleJsonRpcClient): 487 | '''Simple mining client''' 488 | 489 | class MinerWarning(SimpleJsonRpcClient.RequestReplyWarning): 490 | def __init__(self, message, reply, request = None): 491 | SimpleJsonRpcClient.RequestReplyWarning.__init__(self, 'Mining Sate Error: ' + message, reply, request) 492 | 493 | class MinerAuthenticationException(SimpleJsonRpcClient.RequestReplyException): pass 494 | 495 | def __init__(self, url, username, password): 496 | SimpleJsonRpcClient.__init__(self) 497 | 498 | self._url = url 499 | self._username = username 500 | self._password = password 501 | 502 | self._subscription = SubscriptionSHA256D() 503 | 504 | self._job = None 505 | 506 | self._accepted_shares = 0 507 | 508 | # Accessors 509 | url = property(lambda s: s._url) 510 | username = property(lambda s: s._username) 511 | password = property(lambda s: s._password) 512 | 513 | # Overridden from SimpleJsonRpcClient 514 | def handle_reply(self, request, reply): 515 | 516 | # New work, stop what we were doing before, and start on this. 517 | if reply.get('method') == 'mining.notify': 518 | if 'params' not in reply or len(reply['params']) != 9: 519 | raise self.MinerWarning('Malformed mining.notify message', reply) 520 | 521 | (job_id, prevhash, coinb1, coinb2, merkle_branches, version, nbits, ntime, clean_jobs) = reply['params'] 522 | self._spawn_job_thread(job_id, prevhash, coinb1, coinb2, merkle_branches, version, nbits, ntime) 523 | 524 | log('New job: job_id=%s' % job_id, LEVEL_DEBUG) 525 | 526 | # The server wants us to change our difficulty (on all *future* work) 527 | elif reply.get('method') == 'mining.set_difficulty': 528 | if 'params' not in reply or len(reply['params']) != 1: 529 | raise self.MinerWarning('Malformed mining.set_difficulty message', reply) 530 | 531 | (difficulty, ) = reply['params'] 532 | self._subscription.set_difficulty(difficulty) 533 | 534 | log('Change difficulty: difficulty=%s' % difficulty, LEVEL_DEBUG) 535 | 536 | # This is a reply to... 537 | elif request: 538 | 539 | # ...subscribe; set-up the work and request authorization 540 | if request.get('method') == 'mining.subscribe': 541 | if 'result' not in reply or len(reply['result']) != 3 or len(reply['result'][0]) != 2: 542 | raise self.MinerWarning('Reply to mining.subscribe is malformed', reply, request) 543 | 544 | ((mining_notify, subscription_id), extranonce1, extranonce2_size) = reply['result'] 545 | 546 | self._subscription.set_subscription(subscription_id, extranonce1, extranonce2_size) 547 | 548 | log('Subscribed: subscription_id=%s' % subscription_id, LEVEL_DEBUG) 549 | 550 | # Request authentication 551 | self.send(method = 'mining.authorize', params = [ self.username, self.password ]) 552 | 553 | # ...authorize; if we failed to authorize, quit 554 | elif request.get('method') == 'mining.authorize': 555 | if 'result' not in reply or not reply['result']: 556 | raise self.MinerAuthenticationException('Failed to authenticate worker', reply, request) 557 | 558 | worker_name = request['params'][0] 559 | self._subscription.set_worker_name(worker_name) 560 | 561 | log('Authorized: worker_name=%s' % worker_name, LEVEL_DEBUG) 562 | 563 | # ...submit; complain if the server didn't accept our submission 564 | elif request.get('method') == 'mining.submit': 565 | if 'result' not in reply or not reply['result']: 566 | log('Share - Invalid', LEVEL_INFO) 567 | raise self.MinerWarning('Failed to accept submit', reply, request) 568 | 569 | self._accepted_shares += 1 570 | log('Accepted shares: %d' % self._accepted_shares, LEVEL_INFO) 571 | 572 | # ??? *shrug* 573 | else: 574 | raise self.MinerWarning('Unhandled message', reply, request) 575 | 576 | # ??? *double shrug* 577 | else: 578 | raise self.MinerWarning('Bad message state', reply) 579 | 580 | def _spawn_job_thread(self, job_id, prevhash, coinb1, coinb2, merkle_branches, version, nbits, ntime): 581 | '''Stops any previous job and begins a new job.''' 582 | # Stop the old job (if any) 583 | if self._job: self._job.stop() 584 | 585 | # Create the new job 586 | self._job = self._subscription.create_job( 587 | job_id = job_id, 588 | prevhash = prevhash, 589 | coinb1 = coinb1, 590 | coinb2 = coinb2, 591 | merkle_branches = merkle_branches, 592 | version = version, 593 | nbits = nbits, 594 | ntime = ntime 595 | ) 596 | 597 | def run(job): 598 | try: 599 | for result in job.mine(): 600 | params = [ self._subscription.worker_name ] + [ result[k] for k in ('job_id', 'extranonce2', 'ntime', 'nonce') ] 601 | self.send(method = 'mining.submit', params = params) 602 | log("Found share: " + str(params), LEVEL_INFO) 603 | log("Hashrate: %s" % human_readable_hashrate(job.hashrate), LEVEL_INFO) 604 | except Exception as e: 605 | log("ERROR: %s" % e, LEVEL_ERROR) 606 | 607 | thread = threading.Thread(target = run, args = (self._job, )) 608 | thread.daemon = True 609 | thread.start() 610 | 611 | def serve_forever(self): 612 | '''Begins the miner. This method does not return.''' 613 | # Figure out the hostname and port 614 | url = urllib.parse.urlparse(self.url) 615 | hostname = url.hostname or '' 616 | port = url.port or 9333 617 | 618 | log('Starting server on %s:%d' % (hostname, port), LEVEL_INFO) 619 | 620 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 621 | sock.connect((hostname, port)) 622 | self.connect(sock) 623 | 624 | self.send(method = 'mining.subscribe', params = [ "%s/%s" % (USER_AGENT, '.'.join(str(p) for p in VERSION)) ]) 625 | 626 | # Forever... 627 | while True: 628 | time.sleep(10) 629 | 630 | def test_subscription(library): 631 | '''Test harness for mining, using a known valid share.''' 632 | 633 | log('TEST: Sha256d implementation = %r' % library, LEVEL_INFO) 634 | time.sleep(2) 635 | log('TEST: Testing Subscription', LEVEL_DEBUG) 636 | 637 | subscription = SubscriptionSHA256D() 638 | 639 | # Set up the subscription 640 | reply = json.loads('{"id":1,"result":[[["mining.set_difficulty","1"],["mining.notify","1"]],"",8],"error":null}') 641 | log('TEST: %r' % reply, LEVEL_DEBUG) 642 | ((mining_notify, subscription_id), extranonce1, extranonce2_size) = reply['result'] 643 | subscription.set_subscription(subscription_id, extranonce1, extranonce2_size) 644 | 645 | # Set the difficulty 646 | reply = json.loads('{"id":null,"method":"mining.set_difficulty","params":[32768]}') 647 | log('TEST: %r' % reply, LEVEL_DEBUG) 648 | (difficulty, ) = reply['params'] 649 | subscription.set_difficulty(difficulty) 650 | 651 | # Create a job 652 | reply = json.loads('{"id":null,"method":"mining.notify","params":["1d987a1338","3ac400955224c625ad00510bf9b92cf824fd72dabc96a44700000b6000000000","01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704b3936a1a017cffffffff01403d522a01000000434104563053b8900762f3d3e8725012d617d177e3c4af3275c3265a1908b434e0df91ec75603d0d8955ef040e5f68d5c36989efe21a59f4ef94a5cc95c99794a84492ac","",["b4839c227eb12a4682ef507024a44066d1b54b2a224cf4765bdd46b35a42d0e3", "ff55ad590268952712d3586af4f4619eb5f280ed671e2a7dca766076994e19ff", "d8adfb1856bc923a6da4e83914013405334915d4ece1eb36d09cef8119850ea4", "ce28b22ba91639d5ae35d0f7a17e02b422fa251c372cb600daf62b7f3df0bdbd"],"00000001","1a6a93b3","4dcbc8a6",true]}') 653 | log('TEST: %r' % reply, LEVEL_DEBUG) 654 | (job_id, prevhash, coinb1, coinb2, merkle_branches, version, nbits, ntime, clean_jobs) = reply['params'] 655 | job = subscription.create_job( 656 | job_id = job_id, 657 | prevhash = prevhash, 658 | coinb1 = coinb1, 659 | coinb2 = coinb2, 660 | merkle_branches = merkle_branches, 661 | version = version, 662 | nbits = nbits, 663 | ntime = ntime 664 | ) 665 | 666 | # Scan that job (if I broke something, this will run for a long time)) 667 | for result in job.mine(nonce_start = 2436437219 - 5): 668 | log('TEST: found share - %r' % repr(result), LEVEL_INFO) 669 | break 670 | 671 | valid = { 'ntime': '4dcbc8a6', 'nonce': '913914e3', 'extranonce2': '00000000', 'job_id': u'1d987a1338' } 672 | log('TEST: Correct answer %r' % valid, LEVEL_INFO) 673 | time.sleep(2) 674 | 675 | 676 | # CLI for mining 677 | if __name__ == '__main__': 678 | import argparse 679 | 680 | # Parse the command line 681 | parser = argparse.ArgumentParser(description = "CPU and FPGA Bitcoin miner using the stratum protocol") 682 | 683 | parser.add_argument('-o', '--url', help = 'stratum mining server url (eg: stratum+tcp://foobar.com:3333)') 684 | parser.add_argument('-u', '--user', dest = 'username', default = '', help = 'username for mining server', metavar = "USERNAME") 685 | parser.add_argument('-p', '--pass', dest = 'password', default = '', help = 'password for mining server', metavar = "PASSWORD") 686 | 687 | parser.add_argument('-O', '--userpass', help = 'username:password pair for mining server', metavar = "USERNAME:PASSWORD") 688 | 689 | parser.add_argument('-i', '--impl', default = SHA256D_LIBRARY_AUTO, choices = list(set(SHA256D_LIBRARIES)), help = 'library implementation for sha256d') 690 | 691 | parser.add_argument('-B', '--background', action ='store_true', help = 'run in the background as a daemon') 692 | 693 | parser.add_argument('-q', '--quiet', action ='store_true', help = 'suppress non-errors') 694 | parser.add_argument('-P', '--dump-protocol', dest = 'protocol', action ='store_true', help = 'show all JSON-RPC chatter') 695 | parser.add_argument('-d', '--debug', action ='store_true', help = 'show extra debug information') 696 | parser.add_argument('-t', '--test', action ='store_true', help = 'run offline test harness with all implementations') 697 | 698 | parser.add_argument('-v', '--version', action = 'version', version = '%s/%s' % (USER_AGENT, '.'.join(str(v) for v in VERSION))) 699 | 700 | options = parser.parse_args(sys.argv[1:]) 701 | 702 | message = None 703 | 704 | # Get the username/password 705 | username = options.username 706 | password = options.password 707 | 708 | if options.userpass: 709 | if username or password: 710 | message = 'May not use -O/-userpass in conjunction with -u/--user or -p/--pass' 711 | else: 712 | try: 713 | (username, password) = options.userpass.split(':') 714 | except Exception as e: 715 | message = 'Could not parse username:password for -O/--userpass' 716 | 717 | # Was there an issue? Show the help screen and exit. 718 | if message: 719 | parser.print_help() 720 | print("") 721 | print(message) 722 | sys.exit(1) 723 | 724 | # Set the logging level 725 | if options.debug: DEBUG = True 726 | if options.protocol: DEBUG_PROTOCOL = True 727 | if options.quiet: QUIET = True 728 | if options.test: TEST = True 729 | 730 | # Set the library implementation 731 | if options.impl: 732 | if options.impl not in SHA256D_LIBRARIES: 733 | parser.print_help() 734 | print("") 735 | print('Implementation not available for sha256d') 736 | sys.exit(1) 737 | else: 738 | set_sha256d_library(options.impl) 739 | else: 740 | set_sha256d_library(SHA256D_LIBRARY_AUTO) 741 | log('Using sha256d library %r' % SHA256D_LIBRARY, LEVEL_DEBUG) 742 | 743 | if TEST: 744 | for library in SHA256D_LIBRARIES: 745 | set_sha256d_library(library) 746 | test_subscription(library) 747 | else: 748 | # They want a daemon, give them a daemon 749 | if options.background: 750 | import os 751 | if os.fork() or os.fork(): sys.exit() 752 | 753 | # Heigh-ho, heigh-ho, it's off to work we go... 754 | if options.url: 755 | miner = Miner(options.url, username, password) 756 | miner.serve_forever() 757 | -------------------------------------------------------------------------------- /merkle_test.py: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # Richie Harris 3 | # rkharris12@gmail.com 4 | # 5/23/2021 5 | ######################################################################### 6 | 7 | # functions to build a merkle tree and find a merkle root 8 | 9 | import hashlib, math 10 | 11 | 12 | def reverse_byte_order(hex_str): 13 | '''reverse the order of bytes in a hex string''' 14 | 15 | return ''.join([ hex_str[2 * i: 2 * i + 2] for i in list(range(0, len(hex_str) // 2))[::-1] ]) 16 | 17 | 18 | def reverse_word_order(hex_str): 19 | '''reverse the order of 32 bit words in a hex string''' 20 | 21 | return ''.join([ hex_str[8 * i: 8 * i + 8] for i in list(range(0, len(hex_str) // 8))[::-1] ]) 22 | 23 | 24 | def sha256d(message): 25 | '''Double SHA256 Hashing function.''' 26 | 27 | return hashlib.sha256(hashlib.sha256(message).digest()).digest() 28 | 29 | 30 | def merkle_root_tree_bin(coinbase, merkle_tree): 31 | '''Builds a merkle root from the merkle tree''' 32 | 33 | coinbase_bin = bytes.fromhex(coinbase) 34 | coinbase_hash_bin = sha256d(coinbase_bin) 35 | 36 | merkle_root_tree_bin = coinbase_hash_bin 37 | for branch in merkle_tree: 38 | merkle_root_tree_bin = sha256d(merkle_root_tree_bin + bytes.fromhex(branch)) 39 | return merkle_root_tree_bin 40 | 41 | 42 | def merkle_root_txids_bin(txids_bin): 43 | '''Builds a merkle root from a list of transactions''' 44 | 45 | if len(txids_bin) <= 1: 46 | return txids_bin[0] 47 | else: 48 | merkle_level = [] 49 | for i in range(0, len(txids_bin)-1, 2): 50 | merkle_level.append(sha256d(txids_bin[i]+txids_bin[i+1])) 51 | if len(txids_bin) % 2 == 1: 52 | merkle_level.append(sha256d(txids_bin[-1]+txids_bin[-1])) 53 | return merkle_root_txids_bin(merkle_level) 54 | 55 | 56 | def merkle_tree(txids_bin): 57 | '''Computes merkle branches from nonempty list of transactions not including coinbase''' 58 | 59 | num_branches = int(math.ceil(math.log(len(txids_bin), 2))) 60 | txids_range = 2 61 | merkle_tree = [txids_bin[1].hex()] 62 | for i in range(num_branches-1): 63 | merkle_tree.append(merkle_root_txids_bin(txids_bin[txids_range:(2*txids_range)]).hex()) 64 | txids_range *= 2 65 | 66 | return merkle_tree 67 | 68 | 69 | # setup from bitcoin block 123,456 70 | coinbase = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704b3936a1a017cffffffff01403d522a01000000434104563053b8900762f3d3e8725012d617d177e3c4af3275c3265a1908b434e0df91ec75603d0d8955ef040e5f68d5c36989efe21a59f4ef94a5cc95c99794a84492ac00000000" 71 | tx1 = "e3d0425ab346dd5b76f44c222a4bb5d16640a4247050ef82462ab17e229c83b4" 72 | tx2 = "137d247eca8b99dee58e1e9232014183a5c5a9e338001a0109df32794cdcc92e" 73 | tx3 = "5fd167f7b8c417e59106ef5acfe181b09d71b8353a61a55a2f01aa266af5412d" 74 | tx4 = "60925f1948b71f429d514ead7ae7391e0edf965bf5a60331398dae24c6964774" 75 | tx5 = "d4d5fc1529487527e9873256934dfb1e4cdcb39f4c0509577ca19bfad6c5d28f" 76 | tx6 = "7b29d65e5018c56a33652085dbb13f2df39a1a9942bfe1f7e78e97919a6bdea2" 77 | tx7 = "0b89e120efd0a4674c127a76ff5f7590ca304e6a064fbc51adffbd7ce3a3deef" 78 | tx8 = "603f2044da9656084174cfb5812feaf510f862d3addcf70cacce3dc55dab446e" 79 | tx9 = "9a4ed892b43a4df916a7a1213b78e83cd83f5695f635d535c94b2b65ffb144d3" 80 | tx10 = "dda726e3dad9504dce5098dfab5064ecd4a7650bfe854bb2606da3152b60e427" 81 | tx11 = "e46ea8b4d68719b65ead930f07f1f3804cb3701014f8e6d76c4bdbc390893b94" 82 | tx12 = "864a102aeedf53dd9b2baab4eeb898c5083fde6141113e0606b664c41fe15e1f" 83 | txids = [reverse_byte_order(sha256d(bytes.fromhex(coinbase)).hex()), tx1, tx2, tx3, tx4, tx5, tx6, tx7, tx8, tx9, tx10, tx11, tx12] 84 | txids_bin = [] 85 | for i, txid in enumerate(txids): 86 | txids_bin.append(bytes.fromhex(reverse_byte_order(txid))) 87 | 88 | # merkle root from TX IDs 89 | merkle_root_bin = merkle_root_txids_bin(txids_bin) 90 | merkle_root_rev = merkle_root_bin.hex() 91 | merkle_root = reverse_byte_order(merkle_root_rev) 92 | print("merkle root from TXIDs: %s" % merkle_root) 93 | 94 | # merkle root from merkle tree 95 | merkle_tree = merkle_tree(txids_bin) 96 | print("merkle tree:") 97 | print(merkle_tree) 98 | merkle_root_bin = merkle_root_tree_bin(coinbase, merkle_tree) 99 | merkle_root_rev = merkle_root_bin.hex() 100 | merkle_root = reverse_byte_order(merkle_root_rev) 101 | print("merkle root from merkle tree: %s" % merkle_root) 102 | -------------------------------------------------------------------------------- /overlays/miner_top.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rkharris12/fpga_bitcoin_miner/0ba507e87e2b0401a389ffae75b8ec1b1c4ccfee/overlays/miner_top.bit -------------------------------------------------------------------------------- /overlays/miner_top.tcl: -------------------------------------------------------------------------------- 1 | 2 | ################################################################ 3 | # This is a generated script based on design: soc 4 | # 5 | # Though there are limitations about the generated script, 6 | # the main purpose of this utility is to make learning 7 | # IP Integrator Tcl commands easier. 8 | ################################################################ 9 | 10 | namespace eval _tcl { 11 | proc get_script_folder {} { 12 | set script_path [file normalize [info script]] 13 | set script_folder [file dirname $script_path] 14 | return $script_folder 15 | } 16 | } 17 | variable script_folder 18 | set script_folder [_tcl::get_script_folder] 19 | 20 | ################################################################ 21 | # Check if script is running in correct Vivado version. 22 | ################################################################ 23 | set scripts_vivado_version 2019.1 24 | set current_vivado_version [version -short] 25 | 26 | if { [string first $scripts_vivado_version $current_vivado_version] == -1 } { 27 | puts "" 28 | catch {common::send_msg_id "BD_TCL-109" "ERROR" "This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Please run the script in Vivado <$scripts_vivado_version> then open the design in Vivado <$current_vivado_version>. Upgrade the design by running \"Tools => Report => Report IP Status...\", then run write_bd_tcl to create an updated script."} 29 | 30 | return 1 31 | } 32 | 33 | ################################################################ 34 | # START 35 | ################################################################ 36 | 37 | # To test this script, run the following commands from Vivado Tcl console: 38 | # source soc_script.tcl 39 | 40 | # If there is no project opened, this script will create a 41 | # project, but make sure you do not have an existing project 42 | # <./myproj/project_1.xpr> in the current working folder. 43 | 44 | set list_projs [get_projects -quiet] 45 | if { $list_projs eq "" } { 46 | create_project project_1 myproj -part xc7z020clg400-1 47 | set_property BOARD_PART tul.com.tw:pynq-z2:part0:1.0 [current_project] 48 | } 49 | 50 | 51 | # CHANGE DESIGN NAME HERE 52 | variable design_name 53 | set design_name soc 54 | 55 | # If you do not already have an existing IP Integrator design open, 56 | # you can create a design using the following command: 57 | # create_bd_design $design_name 58 | 59 | # Creating design if needed 60 | set errMsg "" 61 | set nRet 0 62 | 63 | set cur_design [current_bd_design -quiet] 64 | set list_cells [get_bd_cells -quiet] 65 | 66 | if { ${design_name} eq "" } { 67 | # USE CASES: 68 | # 1) Design_name not set 69 | 70 | set errMsg "Please set the variable to a non-empty value." 71 | set nRet 1 72 | 73 | } elseif { ${cur_design} ne "" && ${list_cells} eq "" } { 74 | # USE CASES: 75 | # 2): Current design opened AND is empty AND names same. 76 | # 3): Current design opened AND is empty AND names diff; design_name NOT in project. 77 | # 4): Current design opened AND is empty AND names diff; design_name exists in project. 78 | 79 | if { $cur_design ne $design_name } { 80 | common::send_msg_id "BD_TCL-001" "INFO" "Changing value of from <$design_name> to <$cur_design> since current design is empty." 81 | set design_name [get_property NAME $cur_design] 82 | } 83 | common::send_msg_id "BD_TCL-002" "INFO" "Constructing design in IPI design <$cur_design>..." 84 | 85 | } elseif { ${cur_design} ne "" && $list_cells ne "" && $cur_design eq $design_name } { 86 | # USE CASES: 87 | # 5) Current design opened AND has components AND same names. 88 | 89 | set errMsg "Design <$design_name> already exists in your project, please set the variable to another value." 90 | set nRet 1 91 | } elseif { [get_files -quiet ${design_name}.bd] ne "" } { 92 | # USE CASES: 93 | # 6) Current opened design, has components, but diff names, design_name exists in project. 94 | # 7) No opened design, design_name exists in project. 95 | 96 | set errMsg "Design <$design_name> already exists in your project, please set the variable to another value." 97 | set nRet 2 98 | 99 | } else { 100 | # USE CASES: 101 | # 8) No opened design, design_name not in project. 102 | # 9) Current opened design, has components, but diff names, design_name not in project. 103 | 104 | common::send_msg_id "BD_TCL-003" "INFO" "Currently there is no design <$design_name> in project, so creating one..." 105 | 106 | create_bd_design $design_name 107 | 108 | common::send_msg_id "BD_TCL-004" "INFO" "Making design <$design_name> as current_bd_design." 109 | current_bd_design $design_name 110 | 111 | } 112 | 113 | common::send_msg_id "BD_TCL-005" "INFO" "Currently the variable is equal to \"$design_name\"." 114 | 115 | if { $nRet != 0 } { 116 | catch {common::send_msg_id "BD_TCL-114" "ERROR" $errMsg} 117 | return $nRet 118 | } 119 | 120 | set bCheckIPsPassed 1 121 | ################################################################## 122 | # CHECK IPs 123 | ################################################################## 124 | set bCheckIPs 1 125 | if { $bCheckIPs == 1 } { 126 | set list_check_ips "\ 127 | xilinx.com:ip:axi_amm_bridge:1.0\ 128 | xilinx.com:ip:proc_sys_reset:5.0\ 129 | xilinx.com:ip:processing_system7:5.5\ 130 | " 131 | 132 | set list_ips_missing "" 133 | common::send_msg_id "BD_TCL-006" "INFO" "Checking if the following IPs exist in the project's IP catalog: $list_check_ips ." 134 | 135 | foreach ip_vlnv $list_check_ips { 136 | set ip_obj [get_ipdefs -all $ip_vlnv] 137 | if { $ip_obj eq "" } { 138 | lappend list_ips_missing $ip_vlnv 139 | } 140 | } 141 | 142 | if { $list_ips_missing ne "" } { 143 | catch {common::send_msg_id "BD_TCL-115" "ERROR" "The following IPs are not found in the IP Catalog:\n $list_ips_missing\n\nResolution: Please add the repository containing the IP(s) to the project." } 144 | set bCheckIPsPassed 0 145 | } 146 | 147 | } 148 | 149 | if { $bCheckIPsPassed != 1 } { 150 | common::send_msg_id "BD_TCL-1003" "WARNING" "Will not continue with creation of design due to the error(s) above." 151 | return 3 152 | } 153 | 154 | ################################################################## 155 | # DESIGN PROCs 156 | ################################################################## 157 | 158 | 159 | 160 | # Procedure to create entire design; Provide argument to make 161 | # procedure reusable. If parentCell is "", will use root. 162 | proc create_root_design { parentCell } { 163 | 164 | variable script_folder 165 | variable design_name 166 | 167 | if { $parentCell eq "" } { 168 | set parentCell [get_bd_cells /] 169 | } 170 | 171 | # Get object for parentCell 172 | set parentObj [get_bd_cells $parentCell] 173 | if { $parentObj == "" } { 174 | catch {common::send_msg_id "BD_TCL-100" "ERROR" "Unable to find parent cell <$parentCell>!"} 175 | return 176 | } 177 | 178 | # Make sure parentObj is hier blk 179 | set parentType [get_property TYPE $parentObj] 180 | if { $parentType ne "hier" } { 181 | catch {common::send_msg_id "BD_TCL-101" "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} 182 | return 183 | } 184 | 185 | # Save current instance; Restore later 186 | set oldCurInst [current_bd_instance .] 187 | 188 | # Set parent object as current 189 | current_bd_instance $parentObj 190 | 191 | 192 | # Create interface ports 193 | set M_AVALON [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:avalon_rtl:1.0 M_AVALON ] 194 | 195 | 196 | # Create ports 197 | set ARST_AVL_N [ create_bd_port -dir O -from 0 -to 0 -type rst ARST_AVL_N ] 198 | set CLK_AVL [ create_bd_port -dir O CLK_AVL ] 199 | 200 | # Create instance: axi_amm_bridge_0, and set properties 201 | set axi_amm_bridge_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_amm_bridge:1.0 axi_amm_bridge_0 ] 202 | set_property -dict [ list \ 203 | CONFIG.C_ADDRESS_MODE {1} \ 204 | CONFIG.C_AVM_BURST_WIDTH {1} \ 205 | CONFIG.C_BEGIN_BURST_TRANSFER {0} \ 206 | CONFIG.C_BURST_SUPPORT {0} \ 207 | CONFIG.C_HAS_RESPONSE {0} \ 208 | CONFIG.C_PROTOCOL {0} \ 209 | CONFIG.C_S_AXI_ADDR_WIDTH {32} \ 210 | CONFIG.C_USE_BYTEENABLE {1} \ 211 | ] $axi_amm_bridge_0 212 | 213 | # Create instance: axi_interconnect_0, and set properties 214 | set axi_interconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 axi_interconnect_0 ] 215 | set_property -dict [ list \ 216 | CONFIG.NUM_MI {1} \ 217 | ] $axi_interconnect_0 218 | 219 | # Create instance: proc_sys_reset_0, and set properties 220 | set proc_sys_reset_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_0 ] 221 | set_property -dict [ list \ 222 | CONFIG.C_EXT_RST_WIDTH {1} \ 223 | ] $proc_sys_reset_0 224 | 225 | # Create instance: processing_system7_0, and set properties 226 | set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 ] 227 | set_property -dict [ list \ 228 | CONFIG.PCW_ACT_APU_PERIPHERAL_FREQMHZ {666.666687} \ 229 | CONFIG.PCW_ACT_CAN_PERIPHERAL_FREQMHZ {10.000000} \ 230 | CONFIG.PCW_ACT_DCI_PERIPHERAL_FREQMHZ {10.158730} \ 231 | CONFIG.PCW_ACT_ENET0_PERIPHERAL_FREQMHZ {10.000000} \ 232 | CONFIG.PCW_ACT_ENET1_PERIPHERAL_FREQMHZ {10.000000} \ 233 | CONFIG.PCW_ACT_FPGA0_PERIPHERAL_FREQMHZ {50.000000} \ 234 | CONFIG.PCW_ACT_FPGA1_PERIPHERAL_FREQMHZ {10.000000} \ 235 | CONFIG.PCW_ACT_FPGA2_PERIPHERAL_FREQMHZ {10.000000} \ 236 | CONFIG.PCW_ACT_FPGA3_PERIPHERAL_FREQMHZ {10.000000} \ 237 | CONFIG.PCW_ACT_PCAP_PERIPHERAL_FREQMHZ {200.000000} \ 238 | CONFIG.PCW_ACT_QSPI_PERIPHERAL_FREQMHZ {10.000000} \ 239 | CONFIG.PCW_ACT_SDIO_PERIPHERAL_FREQMHZ {10.000000} \ 240 | CONFIG.PCW_ACT_SMC_PERIPHERAL_FREQMHZ {10.000000} \ 241 | CONFIG.PCW_ACT_SPI_PERIPHERAL_FREQMHZ {10.000000} \ 242 | CONFIG.PCW_ACT_TPIU_PERIPHERAL_FREQMHZ {200.000000} \ 243 | CONFIG.PCW_ACT_TTC0_CLK0_PERIPHERAL_FREQMHZ {111.111115} \ 244 | CONFIG.PCW_ACT_TTC0_CLK1_PERIPHERAL_FREQMHZ {111.111115} \ 245 | CONFIG.PCW_ACT_TTC0_CLK2_PERIPHERAL_FREQMHZ {111.111115} \ 246 | CONFIG.PCW_ACT_TTC1_CLK0_PERIPHERAL_FREQMHZ {111.111115} \ 247 | CONFIG.PCW_ACT_TTC1_CLK1_PERIPHERAL_FREQMHZ {111.111115} \ 248 | CONFIG.PCW_ACT_TTC1_CLK2_PERIPHERAL_FREQMHZ {111.111115} \ 249 | CONFIG.PCW_ACT_UART_PERIPHERAL_FREQMHZ {10.000000} \ 250 | CONFIG.PCW_ACT_WDT_PERIPHERAL_FREQMHZ {111.111115} \ 251 | CONFIG.PCW_ARMPLL_CTRL_FBDIV {40} \ 252 | CONFIG.PCW_CAN_PERIPHERAL_DIVISOR0 {1} \ 253 | CONFIG.PCW_CAN_PERIPHERAL_DIVISOR1 {1} \ 254 | CONFIG.PCW_CLK0_FREQ {50000000} \ 255 | CONFIG.PCW_CLK1_FREQ {10000000} \ 256 | CONFIG.PCW_CLK2_FREQ {10000000} \ 257 | CONFIG.PCW_CLK3_FREQ {10000000} \ 258 | CONFIG.PCW_CPU_CPU_PLL_FREQMHZ {1333.333} \ 259 | CONFIG.PCW_CPU_PERIPHERAL_DIVISOR0 {2} \ 260 | CONFIG.PCW_DCI_PERIPHERAL_DIVISOR0 {15} \ 261 | CONFIG.PCW_DCI_PERIPHERAL_DIVISOR1 {7} \ 262 | CONFIG.PCW_DDRPLL_CTRL_FBDIV {32} \ 263 | CONFIG.PCW_DDR_DDR_PLL_FREQMHZ {1066.667} \ 264 | CONFIG.PCW_DDR_PERIPHERAL_DIVISOR0 {2} \ 265 | CONFIG.PCW_ENET0_PERIPHERAL_DIVISOR0 {1} \ 266 | CONFIG.PCW_ENET0_PERIPHERAL_DIVISOR1 {1} \ 267 | CONFIG.PCW_ENET1_PERIPHERAL_DIVISOR0 {1} \ 268 | CONFIG.PCW_ENET1_PERIPHERAL_DIVISOR1 {1} \ 269 | CONFIG.PCW_EN_CLK1_PORT {0} \ 270 | CONFIG.PCW_EN_QSPI {0} \ 271 | CONFIG.PCW_FCLK0_PERIPHERAL_DIVISOR0 {8} \ 272 | CONFIG.PCW_FCLK0_PERIPHERAL_DIVISOR1 {4} \ 273 | CONFIG.PCW_FCLK1_PERIPHERAL_CLKSRC {IO PLL} \ 274 | CONFIG.PCW_FCLK1_PERIPHERAL_DIVISOR0 {1} \ 275 | CONFIG.PCW_FCLK1_PERIPHERAL_DIVISOR1 {1} \ 276 | CONFIG.PCW_FCLK2_PERIPHERAL_DIVISOR0 {1} \ 277 | CONFIG.PCW_FCLK2_PERIPHERAL_DIVISOR1 {1} \ 278 | CONFIG.PCW_FCLK3_PERIPHERAL_DIVISOR0 {1} \ 279 | CONFIG.PCW_FCLK3_PERIPHERAL_DIVISOR1 {1} \ 280 | CONFIG.PCW_FCLK_CLK1_BUF {FALSE} \ 281 | CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {50} \ 282 | CONFIG.PCW_FPGA1_PERIPHERAL_FREQMHZ {50} \ 283 | CONFIG.PCW_FPGA_FCLK0_ENABLE {1} \ 284 | CONFIG.PCW_FPGA_FCLK1_ENABLE {0} \ 285 | CONFIG.PCW_FPGA_FCLK2_ENABLE {0} \ 286 | CONFIG.PCW_FPGA_FCLK3_ENABLE {0} \ 287 | CONFIG.PCW_I2C_PERIPHERAL_FREQMHZ {25} \ 288 | CONFIG.PCW_IOPLL_CTRL_FBDIV {48} \ 289 | CONFIG.PCW_IO_IO_PLL_FREQMHZ {1600.000} \ 290 | CONFIG.PCW_IRQ_F2P_INTR {1} \ 291 | CONFIG.PCW_NAND_GRP_D8_ENABLE {0} \ 292 | CONFIG.PCW_NAND_PERIPHERAL_ENABLE {0} \ 293 | CONFIG.PCW_NOR_GRP_A25_ENABLE {0} \ 294 | CONFIG.PCW_NOR_GRP_CS0_ENABLE {0} \ 295 | CONFIG.PCW_NOR_GRP_CS1_ENABLE {0} \ 296 | CONFIG.PCW_NOR_GRP_SRAM_CS0_ENABLE {0} \ 297 | CONFIG.PCW_NOR_GRP_SRAM_CS1_ENABLE {0} \ 298 | CONFIG.PCW_NOR_GRP_SRAM_INT_ENABLE {0} \ 299 | CONFIG.PCW_NOR_PERIPHERAL_ENABLE {0} \ 300 | CONFIG.PCW_PCAP_PERIPHERAL_DIVISOR0 {8} \ 301 | CONFIG.PCW_QSPI_GRP_FBCLK_ENABLE {0} \ 302 | CONFIG.PCW_QSPI_GRP_IO1_ENABLE {0} \ 303 | CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {0} \ 304 | CONFIG.PCW_QSPI_GRP_SS1_ENABLE {0} \ 305 | CONFIG.PCW_QSPI_PERIPHERAL_DIVISOR0 {1} \ 306 | CONFIG.PCW_QSPI_PERIPHERAL_ENABLE {0} \ 307 | CONFIG.PCW_QSPI_PERIPHERAL_FREQMHZ {200} \ 308 | CONFIG.PCW_SDIO_PERIPHERAL_DIVISOR0 {1} \ 309 | CONFIG.PCW_SMC_PERIPHERAL_DIVISOR0 {1} \ 310 | CONFIG.PCW_SPI_PERIPHERAL_DIVISOR0 {1} \ 311 | CONFIG.PCW_TPIU_PERIPHERAL_DIVISOR0 {1} \ 312 | CONFIG.PCW_UART_PERIPHERAL_DIVISOR0 {1} \ 313 | CONFIG.PCW_UIPARAM_ACT_DDR_FREQ_MHZ {533.333374} \ 314 | CONFIG.PCW_USE_FABRIC_INTERRUPT {0} \ 315 | ] $processing_system7_0 316 | 317 | # Create interface connections 318 | connect_bd_intf_net -intf_net axi_amm_bridge_0_M_AVALON [get_bd_intf_ports M_AVALON] [get_bd_intf_pins axi_amm_bridge_0/M_AVALON] 319 | connect_bd_intf_net -intf_net axi_interconnect_0_M00_AXI [get_bd_intf_pins axi_amm_bridge_0/S_AXI_LITE] [get_bd_intf_pins axi_interconnect_0/M00_AXI] 320 | connect_bd_intf_net -intf_net processing_system7_0_M_AXI_GP0 [get_bd_intf_pins axi_interconnect_0/S00_AXI] [get_bd_intf_pins processing_system7_0/M_AXI_GP0] 321 | 322 | # Create port connections 323 | connect_bd_net -net proc_sys_reset_0_interconnect_aresetn [get_bd_pins axi_interconnect_0/ARESETN] [get_bd_pins proc_sys_reset_0/interconnect_aresetn] 324 | connect_bd_net -net proc_sys_reset_0_peripheral_aresetn [get_bd_ports ARST_AVL_N] [get_bd_pins axi_amm_bridge_0/s_axi_aresetn] [get_bd_pins axi_interconnect_0/M00_ARESETN] [get_bd_pins axi_interconnect_0/S00_ARESETN] [get_bd_pins proc_sys_reset_0/peripheral_aresetn] 325 | connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_ports CLK_AVL] [get_bd_pins axi_amm_bridge_0/s_axi_aclk] [get_bd_pins axi_interconnect_0/ACLK] [get_bd_pins axi_interconnect_0/M00_ACLK] [get_bd_pins axi_interconnect_0/S00_ACLK] [get_bd_pins proc_sys_reset_0/slowest_sync_clk] [get_bd_pins processing_system7_0/FCLK_CLK0] [get_bd_pins processing_system7_0/M_AXI_GP0_ACLK] 326 | connect_bd_net -net processing_system7_0_FCLK_RESET0_N [get_bd_pins proc_sys_reset_0/ext_reset_in] [get_bd_pins processing_system7_0/FCLK_RESET0_N] 327 | 328 | # Create address segments 329 | create_bd_addr_seg -range 0x00010000 -offset 0x43C00000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs M_AVALON/Reg] SEG_M_AVALON_Reg 330 | 331 | 332 | # Restore current instance 333 | current_bd_instance $oldCurInst 334 | 335 | validate_bd_design 336 | save_bd_design 337 | } 338 | # End of create_root_design() 339 | 340 | 341 | ################################################################## 342 | # MAIN FLOW 343 | ################################################################## 344 | 345 | create_root_design "" 346 | 347 | 348 | -------------------------------------------------------------------------------- /sha256d_fpga_sim.py: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # Richie Harris 3 | # rkharris12@gmail.com 4 | # 5/23/2021 5 | ######################################################################### 6 | 7 | # simulation of the FPGA implementation of sha256d 8 | 9 | import hashlib 10 | import binascii 11 | 12 | 13 | # utility functions 14 | def reverse_byte_order(hex_str): # reverse the order of bytes in a hex string 15 | return ''.join([ hex_str[2 * i: 2 * i + 2] for i in list(range(0, len(hex_str) // 2))[::-1] ]) 16 | 17 | def reverse_word_order(hex_str): # reverse the order of 32 bit words in a hex string 18 | return ''.join([ hex_str[8 * i: 8 * i + 8] for i in list(range(0, len(hex_str) // 8))[::-1] ]) 19 | 20 | def pad(msg_hex_str): 21 | """takes in a hex string representing the hash input, pads it to nearest 512 bit boundary, appends input size""" 22 | # find pad size 23 | msg_len = len(msg_hex_str)*4 # need the length in bits, not hex chars 24 | padded_str = msg_hex_str 25 | padded_str += "8" # add the 1 bit "1" separator between original message and zero pad 26 | pad_len = 512 # in bits 27 | while pad_len < len(padded_str)*4 + 64: 28 | pad_len += 512 29 | 30 | pad_len = pad_len//4 # convert bits to hex chars 31 | 32 | # zero pad 33 | for i in list(range(len(padded_str), pad_len - 64//4)): # 64 bits at the end encodes message size 34 | padded_str += "0" 35 | 36 | # append encoded message size in last 64 bits 37 | msg_len_str = hex(msg_len)[2:] 38 | extra_pad_len = 64//4 - len(msg_len_str) 39 | for i in list(range(extra_pad_len)): 40 | padded_str += "0" 41 | padded_str += msg_len_str 42 | 43 | return padded_str 44 | 45 | # python simulation of the FPGA hasher 46 | k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\ 47 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\ 48 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\ 49 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\ 50 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\ 51 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\ 52 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\ 53 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2] 54 | 55 | def idx(x, y): 56 | return (x >> (y * 32)) & 0xFFFFFFFF 57 | 58 | def ror(x, y): 59 | return (x >> y) | ((x << (32 - y)) & 0xFFFFFFFF) 60 | 61 | def round(a, b, c, d, e, f, g, h, data, k): 62 | w14 = idx(data, 14) 63 | w9 = idx(data, 9) 64 | w1 = idx(data, 1) 65 | w0 = idx(data, 0) 66 | s0 = ror(w1, 7) ^ ror(w1, 18) ^ (w1 >> 3) 67 | s1 = ror(w14, 17) ^ ror(w14, 19) ^ (w14 >> 10) 68 | w16 = (w0 + s0 + s1 + w9) & 0xFFFFFFFF 69 | 70 | data = (data >> 32) | (w16 << 480) 71 | 72 | e0 = ror(a, 2) ^ ror(a, 13) ^ ror(a, 22) 73 | e1 = ror(e, 6) ^ ror(e, 11) ^ ror(e, 25) 74 | maj = (a & b) ^ (a & c) ^ (b & c) 75 | ch = (e & f) ^ ((~e) & g) 76 | 77 | t2 = (e0 + maj) & 0xFFFFFFFF 78 | t1 = (h + e1 + ch + k + w0) & 0xFFFFFFFF 79 | 80 | h = g 81 | g = f 82 | f = e 83 | e = (d + t1) & 0xFFFFFFFF 84 | d = c 85 | c = b 86 | b = a 87 | a = (t1 + t2) & 0xFFFFFFFF 88 | 89 | return (a, b, c, d, e, f, g, h, data) 90 | 91 | def hash(state, data): 92 | a = idx(state, 0) 93 | b = idx(state, 1) 94 | c = idx(state, 2) 95 | d = idx(state, 3) 96 | e = idx(state, 4) 97 | f = idx(state, 5) 98 | g = idx(state, 6) 99 | h = idx(state, 7) 100 | 101 | for i in range(64): 102 | (a, b, c, d, e, f, g, h, data) = round(a, b, c, d, e, f, g, h, data, k[i]) 103 | 104 | #print "\t[%d]\t\t%08x%08x%08x%08x%08x%08x%08x%08x" % (i, h, g, f, e, d, c, b, a) 105 | 106 | a = (a + idx(state, 0)) & 0xFFFFFFFF 107 | b = (b + idx(state, 1)) & 0xFFFFFFFF 108 | c = (c + idx(state, 2)) & 0xFFFFFFFF 109 | d = (d + idx(state, 3)) & 0xFFFFFFFF 110 | e = (e + idx(state, 4)) & 0xFFFFFFFF 111 | f = (f + idx(state, 5)) & 0xFFFFFFFF 112 | g = (g + idx(state, 6)) & 0xFFFFFFFF 113 | h = (h + idx(state, 7)) & 0xFFFFFFFF 114 | 115 | return (h << 224) | (g << 192) | (f << 160) | (e << 128) | (d << 96) | (c << 64) | (b << 32) | a 116 | 117 | if __name__ == "__main__": 118 | # bitcoin block 123,456: test input - 80 bytes, 640 bits, already flipped to network byte order 119 | #network_in = "010000009500c43a25c624520b5100adf82cb9f9da72fd2447a496bc600b0000000000006cd862370395dedf1da2841ccda0fc489e3039de5f1ccddef0e834991a65600ea6c8cb4db3936a1ae3143991" 120 | # test output (in true byte order) 121 | #test_out = 0x0000000000002917ed80650c6174aac8dfc46f5fe36480aaef682ff6cd83c3ca 122 | #mid_state <= X"74b4c79dbf5de76d0815e94b0d66604341602d39063461d5faf888259fd47d57"; 123 | #residual_data <= X"b3936a1aa6c8cb4d1a65600e"; 124 | #target <= X"0000000000006a93b30000000000000000000000000000000000000000000000"; 125 | 126 | 127 | # block header fields in big endian hex strings 128 | version = "00000001" 129 | prev_block_hash = "0000000000000b60bc96a44724fd72daf9b92cf8ad00510b5224c6253ac40095" 130 | merkle_root = "0e60651a9934e8f0decd1c5fde39309e48fca0cd1c84a21ddfde95033762d86c" 131 | time = "4dcbc8a6" 132 | bits = "1a6a93b3" 133 | golden_nonce = 2436437219 134 | nonce_counter = golden_nonce - 5 # exercise the code a little 135 | nonce = hex(nonce_counter).rstrip("L").lstrip("0x") 136 | 137 | # convert to little endian and concatenate to form block header - block header is 80 bytes = 640 bits 138 | block_header = reverse_byte_order(version) + reverse_byte_order(prev_block_hash) + reverse_byte_order(merkle_root) + reverse_byte_order(time) + reverse_byte_order(bits) + reverse_byte_order(nonce) 139 | 140 | target_hex = "0000000000006a93b30000000000000000000000000000000000000000000000" 141 | target = int(target_hex, 16) 142 | 143 | # iterate until golden nonce is found 144 | while (True): 145 | print("nonce : %s" % hex(nonce_counter).rstrip("L")) 146 | 147 | # use library function to compute double sha256 hash for validation 148 | sha256_lib_in = bytes.fromhex(block_header) 149 | sha256_lib_out = hashlib.sha256(hashlib.sha256(sha256_lib_in).digest()).hexdigest() 150 | print("hashlib result : 0x%s" % reverse_byte_order(sha256_lib_out)) 151 | 152 | # FPGA hash simulator 153 | state_init = 0x5be0cd191f83d9ab9b05688c510e527fa54ff53a3c6ef372bb67ae856a09e667 # initial state of state registers in hash function 154 | message_blocks = pad(block_header) 155 | # hash first 512 bit message block 156 | first_block = reverse_word_order(message_blocks[0:(512//4)]) # reverse word ordering for hash function 157 | data_in = int(first_block, 16) # convert from hex string to numerical data 158 | mid_state = hash(state_init, data_in) 159 | 160 | # hash second 512 bit message_block 161 | second_block = reverse_word_order(message_blocks[(512//4):(1024//4)]) # reverse word ordering for hash function 162 | data_in = int(second_block, 16) # convert from hex string to numerical data 163 | hash_1 = hash(mid_state, data_in) 164 | hash_1_word_rev = reverse_word_order(hex(hash_1).rstrip("L").lstrip("0x")) # put it back into big endian word order for padding function 165 | # hash a second time 166 | padded_in_2 = pad(hash_1_word_rev) 167 | block = reverse_word_order(padded_in_2) # reverse word ordering for hash function 168 | data_in = int(block, 16) # convert from hex string to numerical data 169 | hash_2 = hash(state_init, data_in) 170 | hash_2_word_rev = reverse_word_order(hex(hash_2).rstrip("L").lstrip("0x")) # put it back into big endian word order 171 | while len(hash_2_word_rev) < 64: 172 | hash_2_word_rev = hash_2_word_rev + "0" 173 | hash_2_result = reverse_byte_order(hash_2_word_rev) # convert back to big endian byte order before comparing to target 174 | print("sha256d result : 0x%s" % hash_2_result) 175 | print("target: : %s" % ("0x" + target_hex)) 176 | 177 | # compare hash result to target 178 | if int(hash_2_result, 16) < target: 179 | print("golden nonce found!") 180 | break 181 | 182 | # increment nonce 183 | nonce_counter = nonce_counter + 1 184 | nonce = hex(nonce_counter).rstrip("L").lstrip("0x") 185 | block_header = block_header[0:-8] + reverse_byte_order(nonce) 186 | print("") 187 | --------------------------------------------------------------------------------