In progress sha256 integration
diff --git a/verilog/rtl/btc_miner_top.v b/verilog/rtl/btc_miner_top.v index 1372de4..dcfdb05 100644 --- a/verilog/rtl/btc_miner_top.v +++ b/verilog/rtl/btc_miner_top.v
@@ -89,16 +89,14 @@ wire [31:0] la_write2; wire [31:0] la_write3; - // Bitcoin mining variables - wire [BITS-1:0] o_nonce; + // SHA module variables + wire o_error; wire o_idle; - logic [639:0] o_block_header; - wire [255:0] o_target; - reg [127:0] la_data_out; // TODO + reg [127:0] la_data_out; // TODO ensure LA muxing does not require register // TODO use top 32-bits of LA to control muxing and other variables like starting state machine - wire [2:0] la_sel; - assign la_sel = la_data_in[127:125]; + wire [5:0] la_sel; + assign la_sel = la_data_in[127:122]; // WB MI A assign valid = wbs_cyc_i && wbs_stb_i; @@ -107,7 +105,7 @@ assign wdata = wbs_dat_i; // IO - assign io_out = o_nonce; + assign io_out = rdata; assign io_oeb = {(`MPRJ_IO_PADS-1){rst}}; // IRQ @@ -120,23 +118,21 @@ assign la_write2 = ~la_oenb[95:64] & ~{BITS{valid}}; assign la_write3 = ~la_oenb[127:96] & ~{BITS{valid}}; - // Assuming LA probes [97:96] are for controlling the clk & reset - assign clk = (~la_oenb[96]) ? la_data_in[96] : wb_clk_i; - assign rst = (~la_oenb[97]) ? la_data_in[97] : wb_rst_i; + // Assuming LA probes [107:106] are for controlling the clk & reset + assign clk = (~la_oenb[106]) ? la_data_in[106] : wb_clk_i; + assign rst = (~la_oenb[107]) ? la_data_in[107] : wb_rst_i; // TODO more LA muxing // la_data_in or la_data_out or la_oenb or la_sel or nonce or block_header or target - always @(la_data_in || la_oenb || la_sel || o_nonce || o_block_header || o_target) begin + always @(la_data_in || la_oenb || la_sel || rdata || o_error || o_idle) begin case (la_sel) - 3'b000: - la_data_out[95:0] <= {{(95-BITS){1'b0}}, o_nonce}; - 3'b001: - la_data_out[95:0] <= o_block_header[95:0]; - 3'b010: - la_data_out[95:0] <= o_block_header[191:96]; - 3'b011: - la_data_out[95:0] <= o_block_header[287:192]; + 6'b000000: + la_data_out[95:0] <= {{(95-(BITS-2)){1'b0}}, {o_idle, o_error, rdata}}; + default: + begin + // nothing + end endcase end @@ -147,17 +143,13 @@ .clk(clk), .rst(rst), .valid(valid), - .wb_we(wbs_we_i), + .wb_wr_mask(wstrb), .wdata(wbs_dat_i), - .la_write0(la_write0), .la_write3(la_write3), - .la_input0(la_data_in[31:0]), .la_input3(la_data_in[127:96]), - .ready(wbs_ack_o), .rdata(rdata), - .block_header(o_block_header), - .target(o_target), - .nonce(o_nonce), + .ready(wbs_ack_o), + .error(o_error), .idle(o_idle) ); @@ -168,46 +160,67 @@ module miner_ctrl #( parameter BITS = 32 )( - input clk, - input rst, - input valid, - input wb_we, - input [BITS-1:0] wdata, - input [BITS-1:0] la_write0, - input [BITS-1:0] la_write3, - input [BITS-1:0] la_input0, - input [BITS-1:0] la_input3, - output ready, - output [BITS-1:0] rdata, - output [639:0] block_header, - output [255:0] target, - output [BITS-1:0] nonce, - output idle + input wire clk, + input wire rst, + input wire valid, + input wire [3:0] wb_wr_mask, + input wire [BITS-1:0] wdata, + input wire [BITS-1:0] la_write3, + input wire [BITS-1:0] la_input3, + output reg [BITS-1:0] rdata, + output reg ready, + output wire error, + output wire idle ); - // enum logic [1:0] {WAIT_IN=2'b00, READ_IN=2'b01, COMPUTE=2'b10, CHECK=2'b11, WRITE_OUT=} state; - // enum integer unsigned {WAIT_IN=0, READ_IN=1, COMPUTE=2, INCR_NONCE=3, WRITE_OUT=4} state; - localparam WAIT_IN=0, READ_IN=1, COMPUTE=2, INCR_NONCE=3, WRITE_OUT=4; + // sha256 internal constants and parameters + localparam ADDR_NAME0 = 8'h00; + localparam ADDR_NAME1 = 8'h01; + localparam ADDR_VERSION = 8'h02; + + localparam ADDR_CTRL = 8'h08; + localparam CTRL_INIT_BIT = 0; + localparam CTRL_NEXT_BIT = 1; + localparam CTRL_MODE_BIT = 2; + + localparam ADDR_STATUS = 8'h09; + localparam STATUS_READY_BIT = 0; + localparam STATUS_VALID_BIT = 1; + + localparam ADDR_BLOCK0 = 8'h10; + localparam ADDR_BLOCK15 = 8'h1f; + + localparam ADDR_DIGEST0 = 8'h20; + localparam ADDR_DIGEST7 = 8'h27; + + localparam MODE_SHA_224 = 1'h0; + localparam MODE_SHA_256 = 1'h1; + + // enum logic [1:0] {WAIT_IN=2'b00, READ_IN=2'b01, WAIT_COMPUTE=2'b10, CHECK=2'b11, WRITE_OUT=} state; + // enum integer unsigned {WAIT_IN=0, READ_IN=1, WAIT_COMPUTE=2, INCR_NONCE=3, WRITE_OUT=4} state; + localparam WAIT_IN=0, READ_IN=1, WAIT_COMPUTE=2, WRITE_OUT=3; reg [2:0] state; - reg ready; - reg [BITS-1:0] rdata; - reg [BITS-1:0] wb_data_reg; - reg [BITS-1:0] nonce; - reg [BITS-1:0] encoded_target; - reg [255:0] target; - reg miner_rst; + wire start_ctrl; + wire sha_cs; + wire sha_we; + wire [7:0] sha_address; + wire [BITS-1:0] sha_write_data; + wire [BITS-1:0] sha_read_data; - logic [639:0] block_header; - logic [255:0] o_hash_val; - logic o_done_hash; - - wire idle; - wire start; + wire sha_in_ready; + wire sha_digest_valid; + wire auto_ctrl; assign idle = (state == WAIT_IN) ? 1'b1 : 1'b0; - assign start = la_write3[2] ? la_input3[2] : 1'b0; + assign start_ctrl = la_input3[12] & la_write3[12]; + + assign sha_cs = la_input3[8] & la_write3[8]; + assign sha_we = la_input3[9] & la_write3[9]; + assign sha_address = la_input3[7:0] & la_write3[7:0]; + + assign auto_ctrl = la_input3[13] & la_write3[13]; // need to count to 640/32 = 20 (decimal). Only to 19 b/c nonce is last 32-bits integer unsigned count; @@ -216,108 +229,41 @@ if (rst) begin ready <= 0; rdata <= 0; - wb_data_reg <= 0; - nonce <= 0; - encoded_target <= 0; - target <= 0; count <= 0; - miner_rst <= 1; - block_header <= 0; state <= WAIT_IN; - end else begin + end else if (auto_ctrl) begin ready <= 1'b0; // state machine for controlling miner and I/O case (state) WAIT_IN: begin // TODO? - miner_rst <= 1; - if (start == 1) begin + if (start_ctrl) begin state <= READ_IN; end end READ_IN: begin - // TODO - miner_rst <= 1; - + // TODO? if (valid && !ready) begin ready <= 1'b1; - if (wb_we) begin - // TODO read WB data into block header - if (count == 0) begin - block_header[BITS-1:0] <= wdata; - count <= count + 1; - end else if (count == 1) begin - block_header[BITS*2-1:BITS] <= wdata; - count <= count + 1; - end else if (count == 2) begin - block_header[BITS*3-1:BITS*2] <= wdata; - count <= count + 1; - end else if (count == 3) begin - block_header[BITS*4-1:BITS*3] <= wdata; - count <= count + 1; - end else if (count == 4) begin - block_header[BITS*5-1:BITS*4] <= wdata; - count <= count + 1; - end else if (count == 5) begin - block_header[BITS*6-1:BITS*5] <= wdata; - count <= count + 1; - end else if (count == 6) begin - block_header[BITS*7-1:BITS*6] <= wdata; - count <= count + 1; - end else if (count == 7) begin - block_header[BITS*8-1:BITS*7] <= wdata; - count <= count + 1; - end else if (count == 8) begin - block_header[BITS*9-1:BITS*8] <= wdata; - count <= count + 1; - end else if (count == 9) begin - block_header[BITS*10-1:BITS*9] <= wdata; - count <= count + 1; - end - - if (count == 18) begin - // TODO pass encoded_target into decoder module - encoded_target <= wdata; - target <= {{(255-BITS){1'b0}}, wdata}; - count <= count + 1; - end else if (count >= 19) begin - block_header[639:608] <= nonce; - count <= 0; - nonce <= nonce + 1; - miner_rst <= 0; - state <= COMPUTE; - end else begin - count <= count + 1; + if (wb_wr_mask == 4'b1111) begin + // if read up to the last address + if ((sha_address == ADDR_BLOCK15) && sha_cs && !sha_we) begin + state <= WAIT_COMPUTE; end end end end - COMPUTE: begin - // start miner - if (o_done_hash) begin - // TODO target - if (o_hash_val < target) begin - state <= WRITE_OUT; - end else begin - miner_rst <= 1; - block_header[639:608] <= nonce; - state <= INCR_NONCE; - end - end else begin - miner_rst <= 0; - end - end + WAIT_COMPUTE: begin + // read status register to determine when done + if (sha_cs && !sha_we) begin + // TODO read status register and move to WRITE_OUT state - INCR_NONCE: begin - // TODO? - miner_rst <= 0; - nonce <= nonce + 1; - state <= COMPUTE; + end end WRITE_OUT: begin @@ -325,247 +271,32 @@ if (valid && !ready) begin ready <= 1'b1; - if (wb_we) begin + if (wb_wr_mask == 4'b1111) begin // WB should not be writing to user project end else begin // Place output hash on wishbone - rdata <= o_hash_val[BITS*count +:BITS]; - if (count >= 7) begin - count <= 0; - state <= WAIT_IN; - end else begin - count <= count + 1; - end end end end endcase + end else begin + // TODO not automated control. FW controls all wr/rd and addresses. end end - miner double_sha256_miner( - .block(block_header), + // TODO + sha256 sha256_inst0( .clk(clk), - .rst(rst), - .hashed(o_hash_val), - .done(o_done_hash) + .reset_n(~rst), + .cs(sha_cs), + .we(sha_we), + .address(sha_address), + .write_data(sha_write_data), + .read_data(sha_read_data), + .error(error) ); + endmodule // miner_ctrl - -// miner -module miner( - input logic [639:0] block, - input logic clk, rst, - output logic [255:0] hashed, - output logic done -); - - logic [255:0] first_hash; - logic [255:0] secnd_hash; - - logic second_run_rst; - logic done_first_hash; - logic done_secnd_hash; - - sha_256 #(.MSG_SIZE(640), .PADDED_SIZE(1024)) first (.message(block), .hashed(first_hash), .clk(clk), .rst(rst), .done(done_first_hash)); - sha_256 #(.MSG_SIZE(256), .PADDED_SIZE(512)) second (.message(first_hash), .hashed(secnd_hash), .clk(clk), .rst(second_run_rst), .done(done_secnd_hash)); - - // always @* second_run_rst <= 1'b0; - - always @(posedge clk) begin - if (done_first_hash === 1'bX) second_run_rst <= 1'b1; - else if (done_first_hash == 1'b1) second_run_rst <= 1'b0; - end - - assign done = done_secnd_hash; - assign hashed = {secnd_hash[7:0], secnd_hash[15:8], secnd_hash[23:16], secnd_hash[31:24], secnd_hash[39:32], secnd_hash[47:40], secnd_hash[55:48], secnd_hash[63:56], secnd_hash[71:64], secnd_hash[79:72], secnd_hash[87:80], secnd_hash[95:88], secnd_hash[103:96], secnd_hash[111:104], secnd_hash[119:112], secnd_hash[127:120], secnd_hash[135:128], secnd_hash[143:136], secnd_hash[151:144], secnd_hash[159:152], secnd_hash[167:160], secnd_hash[175:168], secnd_hash[183:176], secnd_hash[191:184], secnd_hash[199:192], secnd_hash[207:200], secnd_hash[215:208], secnd_hash[223:216], secnd_hash[231:224], secnd_hash[239:232], secnd_hash[247:240], secnd_hash[255:248]}; -endmodule // miner - - -// sha_256 -module sha_256 #( - parameter MSG_SIZE = 24, - parameter PADDED_SIZE = 512 -)( - input logic [MSG_SIZE-1:0] message, - input logic clk, rst, - output logic [255:0] hashed, - output logic done -); - - logic[PADDED_SIZE-1:0] padded; - - sha_padder #(.MSG_SIZE(MSG_SIZE), .PADDED_SIZE(PADDED_SIZE)) padder (.message(message), .padded(padded)); - // sha_mainloop #(.PADDED_SIZE(PADDED_SIZE)) loop (.padded(padded), .hashed(hashed), .clk(clk), .rst(rst), .done(done)); - assign hashed = 0; - assign done = 0; -endmodule // sha_256 - - -// sha_padder -`define PACK_ARRAY(PK_WIDTH,PK_LEN,PK_SRC,PK_DEST) genvar pk_idx; generate for (pk_idx=0; pk_idx<(PK_LEN); pk_idx=pk_idx+1) begin; assign PK_DEST[((PK_WIDTH)*pk_idx+((PK_WIDTH)-1)):((PK_WIDTH)*pk_idx)] = PK_SRC[pk_idx][((PK_WIDTH)-1):0]; end; endgenerate -`define UNPACK_ARRAY(PK_WIDTH,PK_LEN,PK_DEST,PK_SRC) genvar unpk_idx; generate for (unpk_idx=0; unpk_idx<(PK_LEN); unpk_idx=unpk_idx+1) begin; assign PK_DEST[unpk_idx][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*unpk_idx+(PK_WIDTH-1)):((PK_WIDTH)*unpk_idx)]; end; endgenerate - -module sha_padder #( - parameter MSG_SIZE = 24, // size of full message - parameter PADDED_SIZE = 512 -)( - input logic [MSG_SIZE-1:0] message, - output logic [PADDED_SIZE-1:0] padded -); - - localparam zero_width = PADDED_SIZE-MSG_SIZE-1-64; - localparam back_0_width = 64-$bits(MSG_SIZE); - - assign padded = {message, 1'b1, {zero_width{1'b0}}, {back_0_width{1'b0}}, MSG_SIZE}; -endmodule //sha_padder - - -// sha_mainloop -module sha_mainloop #( - parameter PADDED_SIZE = 512 -)( - input logic [PADDED_SIZE-1:0] padded, - input logic clk, rst, - output logic [255:0] hashed, - output logic done -); - - function [31:0] K; - input [6:0] x; - K = k[2047-x*32 -: 32]; - endfunction - - function automatic [31:0] W; - input [6:0] x; - input [6:0] y; - if(^x === 1'bX) W = 32'h777; - else W = (x<16) ? padded[((PADDED_SIZE-1-y*512)-x*32) -: 32] : rho1(W(x-2, y)) + W(x-7, y) + rho0(W(x-15, y)) + W(x-16, y); - endfunction - - function automatic [31:0] rho0; - input [31:0] x; - if(^x === 1'bX) rho0 = 32'h888; - else rho0 = {x[6:0],x[31:7]} ^ {x[17:0],x[31:18]} ^ (x >> 3); - endfunction - - function automatic [31:0] rho1; - input [31:0] x; - if(^x === 1'bX) rho1 = 32'h888; - else rho1 = {x[16:0],x[31:17]} ^ {x[18:0],x[31:19]} ^ (x >> 10); - endfunction - - function [31:0] ch; - input [31:0] x,y,z; - if(^x === 1'bX) ch = 32'h888; - else ch = (x & y) ^ (~x & z); - endfunction - - function [31:0] maj; - input [31:0] x,y,z; - if(^x === 1'bX) maj = 32'h888; - else maj = (x & y) ^ (x & z) ^ (y & z); - endfunction - - function [31:0] sum0; - input [31:0] x; - if(^x === 1'bX) sum0 = 32'h888; - else sum0 = {x[1:0],x[31:2]} ^ {x[12:0],x[31:13]} ^ {x[21:0],x[31:22]}; - endfunction - - function [31:0] sum1; - input [31:0] x; - if(^x === 1'bX) sum1 = 32'h888; - else sum1 = {x[5:0],x[31:6]} ^ {x[10:0],x[31:11]} ^ {x[24:0],x[31:25]}; - endfunction - - logic [255:0] initial_hashes = {32'h6a09e667, 32'hbb67ae85, 32'h3c6ef372, 32'ha54ff53a, 32'h510e527f, 32'h9b05688c, 32'h1f83d9ab, 32'h5be0cd19}; - - logic [2047:0] k = {32'h428a2f98, 32'h71374491, 32'hb5c0fbcf, 32'he9b5dba5, 32'h3956c25b, 32'h59f111f1, 32'h923f82a4, 32'hab1c5ed5, 32'hd807aa98, 32'h12835b01, 32'h243185be, 32'h550c7dc3, 32'h72be5d74, 32'h80deb1fe, 32'h9bdc06a7, 32'hc19bf174, 32'he49b69c1, 32'hefbe4786, 32'h0fc19dc6, 32'h240ca1cc, 32'h2de92c6f, 32'h4a7484aa, 32'h5cb0a9dc, 32'h76f988da, 32'h983e5152, 32'ha831c66d, 32'hb00327c8, 32'hbf597fc7, 32'hc6e00bf3, 32'hd5a79147, 32'h06ca6351, 32'h14292967, 32'h27b70a85, 32'h2e1b2138, 32'h4d2c6dfc, 32'h53380d13, 32'h650a7354, 32'h766a0abb, 32'h81c2c92e, 32'h92722c85, 32'ha2bfe8a1, 32'ha81a664b, 32'hc24b8b70, 32'hc76c51a3, 32'hd192e819, 32'hd6990624, 32'hf40e3585, 32'h106aa070, 32'h19a4c116, 32'h1e376c08, 32'h2748774c, 32'h34b0bcb5, 32'h391c0cb3, 32'h4ed8aa4a, 32'h5b9cca4f, 32'h682e6ff3, 32'h748f82ee, 32'h78a5636f, 32'h84c87814, 32'h8cc70208, 32'h90befffa, 32'ha4506ceb, 32'hbef9a3f7, 32'hc67178f2}; - - logic [31:0] a, b, c, d, e, f, g, h, t1, t2; - logic [31:0] h1, h2, h3, h4, h5, h6, h7, h8; - - logic [6:0] j; - logic [6:0] i; - - localparam N = PADDED_SIZE/512; // number of blocks - - logic [31:0] ch_efg, maj_abc, sum0_a, sum1_e, kj, wj; - - // (e or f or g or ch_efg) - always_comb begin - ch_efg = ch(e,f,g); - maj_abc = maj(a,b,c); - sum0_a = sum0(a); - sum1_e = sum1(e); - wj = W(j, i); - kj = K(j); - end - - always @(negedge clk) begin - // t1 <= h + sum1(e) + ch(e,f,g) + K(j) + W(j); - // t2 <= sum0(a) + maj(a,b,c); - t1 <= (h + sum1_e + ch_efg + kj + wj)%4294967296; - t2 <= (sum0_a + maj_abc)%4294967296; - end - - always @(posedge clk or posedge rst) begin - if(rst) begin - i <= 1'b0; - j <= 1'bX; - h1 <= 32'h6a09e667; - h2 <= 32'hbb67ae85; - h3 <= 32'h3c6ef372; - h4 <= 32'ha54ff53a; - h5 <= 32'h510e527f; - h6 <= 32'h9b05688c; - h7 <= 32'h1f83d9ab; - h8 <= 32'h5be0cd19; - end - else if (^j === 1'bX && ^i !== 1'bX) begin - a <= h1; - b <= h2; - c <= h3; - d <= h4; - e <= h5; - f <= h6; - g <= h7; - h <= h8; - j <= 1'd0; - end - else if (j < 64) begin - h <= g; - g <= f; - f <= e; - e <= (d+t1)%4294967296; - d <= c; - c <= b; - b <= a; - a <= (t1+t2)%4294967296; - j <= j+1; - end - else if (j == 64) begin - h1 <= a + h1; - h2 <= b + h2; - h3 <= c + h3; - h4 <= d + h4; - h5 <= e + h5; - h6 <= f + h6; - h7 <= g + h7; - h8 <= h + h8; - j <= 1'bX; - if (i<N-1) i <= i+1; - else begin - i <= 1'bX; - done <= 1'b1; - end - end - end - - assign hashed = {h1, h2, h3, h4, h5, h6, h7, h8}; -endmodule // sha_mainloop - `default_nettype wire
diff --git a/verilog/rtl/btc_miner_top_old.v b/verilog/rtl/btc_miner_top_old.v new file mode 100644 index 0000000..19bb0d1 --- /dev/null +++ b/verilog/rtl/btc_miner_top_old.v
@@ -0,0 +1,575 @@ +// SPDX-FileCopyrightText: 2020 Efabless Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// SPDX-License-Identifier: Apache-2.0 + +`default_nettype none +/* + *------------------------------------------------------------- + * + * btc_miner_top + * TODO! + * + * This is an example of a (trivially simple) user project, + * showing how the user project can connect to the logic + * analyzer, the wishbone bus, and the I/O pads. + * + * This project generates an integer count, which is output + * on the user area GPIO pads (digital output only). The + * wishbone connection allows the project to be controlled + * (start and stop) from the management SoC program. + * + * See the testbenches in directory "mprj_counter" for the + * example programs that drive this user project. The three + * testbenches are "io_ports", "la_test1", and "la_test2". + * + *------------------------------------------------------------- + */ + +module btc_miner_top #( + parameter BITS = 32 +)( +`ifdef USE_POWER_PINS + inout vccd1, // User area 1 1.8V supply + inout vssd1, // User area 1 digital ground +`endif + + // Wishbone Slave ports (WB MI A) + input wb_clk_i, + input wb_rst_i, + input wbs_stb_i, + input wbs_cyc_i, + input wbs_we_i, + input [3:0] wbs_sel_i, + input [31:0] wbs_dat_i, + input [31:0] wbs_adr_i, + output wbs_ack_o, + output [31:0] wbs_dat_o, + + // Logic Analyzer Signals + input [127:0] la_data_in, + output [127:0] la_data_out, + input [127:0] la_oenb, + + // IOs + input [`MPRJ_IO_PADS-1:0] io_in, + output [`MPRJ_IO_PADS-1:0] io_out, + output [`MPRJ_IO_PADS-1:0] io_oeb, + + // IRQ + output [2:0] irq +); + wire clk; + wire rst; + + wire [`MPRJ_IO_PADS-1:0] io_in; + wire [`MPRJ_IO_PADS-1:0] io_out; + wire [`MPRJ_IO_PADS-1:0] io_oeb; + + // WB wires + wire [31:0] rdata; + wire [31:0] wdata; + + wire valid; + wire [3:0] wstrb; + + // LA wires + wire [31:0] la_write0; + wire [31:0] la_write1; + wire [31:0] la_write2; + wire [31:0] la_write3; + + // Bitcoin mining variables + wire [BITS-1:0] o_nonce; + wire o_idle; + wire [639:0] o_block_header; + wire [255:0] o_target; + reg [127:0] la_data_out; // TODO ensure LA muxing does not require register + + // TODO use top 32-bits of LA to control muxing and other variables like starting state machine + wire [5:0] la_sel; + assign la_sel = la_data_in[127:122]; + + // WB MI A + assign valid = wbs_cyc_i && wbs_stb_i; + assign wstrb = wbs_sel_i & {4{wbs_we_i}}; + assign wbs_dat_o = rdata; + assign wdata = wbs_dat_i; + + // IO + assign io_out = o_nonce; + assign io_oeb = {(`MPRJ_IO_PADS-1){rst}}; + + // IRQ + assign irq = 3'b000; // Unused + + // Assuming LA probes [31:0] (aka: la_write0) are for controlling the nonce register. + // * NOTE: These are used as a mask for the la_data_in[?:?] + assign la_write0 = ~la_oenb[31:0] & ~{BITS{valid}}; + assign la_write1 = ~la_oenb[63:32] & ~{BITS{valid}}; + assign la_write2 = ~la_oenb[95:64] & ~{BITS{valid}}; + assign la_write3 = ~la_oenb[127:96] & ~{BITS{valid}}; + + // Assuming LA probes [107:106] are for controlling the clk & reset + assign clk = (~la_oenb[106]) ? la_data_in[106] : wb_clk_i; + assign rst = (~la_oenb[107]) ? la_data_in[107] : wb_rst_i; + + // TODO more LA muxing + // la_data_in or la_data_out or la_oenb or la_sel or nonce or block_header or target + always @(la_data_in || la_oenb || la_sel || o_nonce || o_block_header || o_target) begin + case (la_sel) + 6'b000000: + la_data_out[95:0] <= {{(95-BITS){1'b0}}, o_nonce}; + 6'b000001: + la_data_out[95:0] <= o_block_header[95:0]; + 6'b000010: + la_data_out[95:0] <= o_block_header[191:96]; + 6'b000011: + la_data_out[95:0] <= o_block_header[287:192]; + + default: + begin + // nothing + end + endcase + end + + // TODO create state machine for reading block header and passing to miner + miner_ctrl #( + .BITS(BITS) + ) miner_ctrl( + .clk(clk), + .rst(rst), + .valid(valid), + .wb_we(wbs_we_i), + .wdata(wbs_dat_i), + .la_write0(la_write0), + .la_write3(la_write3), + .la_input0(la_data_in[31:0]), + .la_input3(la_data_in[127:96]), + .ready(wbs_ack_o), + .rdata(rdata), + .block_header(o_block_header), + .target(o_target), + .nonce(o_nonce), + .idle(o_idle) + ); + +endmodule // btc_miner_top + + +// miner_ctrl +module miner_ctrl #( + parameter BITS = 32 +)( + input clk, + input rst, + input valid, + input wb_we, + input [BITS-1:0] wdata, + input [BITS-1:0] la_write0, + input [BITS-1:0] la_write3, + input [BITS-1:0] la_input0, + input [BITS-1:0] la_input3, + output ready, + output [BITS-1:0] rdata, + output [639:0] block_header, + output [255:0] target, + output [BITS-1:0] nonce, + output idle +); + + // enum logic [1:0] {WAIT_IN=2'b00, READ_IN=2'b01, COMPUTE=2'b10, CHECK=2'b11, WRITE_OUT=} state; + // enum integer unsigned {WAIT_IN=0, READ_IN=1, COMPUTE=2, INCR_NONCE=3, WRITE_OUT=4} state; + localparam WAIT_IN=0, READ_IN=1, COMPUTE=2, INCR_NONCE=3, WRITE_OUT=4; + + reg [2:0] state; + + reg ready; + reg [BITS-1:0] rdata; + reg [BITS-1:0] wb_data_reg; + reg [BITS-1:0] nonce; + reg [BITS-1:0] encoded_target; + reg [255:0] target; + reg miner_rst; + + reg [639:0] block_header; + reg [255:0] o_hash_val; + reg o_done_hash; + + wire idle; + wire start_ctrl; + + assign idle = (state == WAIT_IN) ? 1'b1 : 1'b0; + assign start_ctrl = la_write3[12] ? la_input3[12] : 1'b0; + + // need to count to 640/32 = 20 (decimal). Only to 19 b/c nonce is last 32-bits + integer unsigned count; + + always @(posedge clk) begin + if (rst) begin + ready <= 0; + rdata <= 0; + wb_data_reg <= 0; + nonce <= 0; + encoded_target <= 0; + target <= 0; + count <= 0; + miner_rst <= 1; + block_header <= 0; + + state <= WAIT_IN; + end else begin + ready <= 1'b0; + + // state machine for controlling miner and I/O + case (state) + WAIT_IN: begin + // TODO? + miner_rst <= 1; + if (start_ctrl == 1) begin + state <= READ_IN; + end + end + + READ_IN: begin + // TODO + miner_rst <= 1; + + if (valid && !ready) begin + ready <= 1'b1; + + if (wb_we) begin + // TODO read WB data into block header + if (count == 0) begin + block_header[BITS-1:0] <= wdata; + count <= count + 1; + end else if (count == 1) begin + block_header[BITS*2-1:BITS] <= wdata; + count <= count + 1; + end else if (count == 2) begin + block_header[BITS*3-1:BITS*2] <= wdata; + count <= count + 1; + end else if (count == 3) begin + block_header[BITS*4-1:BITS*3] <= wdata; + count <= count + 1; + end else if (count == 4) begin + block_header[BITS*5-1:BITS*4] <= wdata; + count <= count + 1; + end else if (count == 5) begin + block_header[BITS*6-1:BITS*5] <= wdata; + count <= count + 1; + end else if (count == 6) begin + block_header[BITS*7-1:BITS*6] <= wdata; + count <= count + 1; + end else if (count == 7) begin + block_header[BITS*8-1:BITS*7] <= wdata; + count <= count + 1; + end else if (count == 8) begin + block_header[BITS*9-1:BITS*8] <= wdata; + count <= count + 1; + end else if (count == 9) begin + block_header[BITS*10-1:BITS*9] <= wdata; + count <= count + 1; + end + + if (count == 18) begin + // TODO pass encoded_target into decoder module + encoded_target <= wdata; + target <= {{(255-BITS){1'b0}}, wdata}; + count <= count + 1; + end else if (count >= 19) begin + block_header[639:608] <= nonce; + count <= 0; + nonce <= nonce + 1; + miner_rst <= 0; + state <= COMPUTE; + end else begin + count <= count + 1; + end + end + end + end + + COMPUTE: begin + // start miner + if (o_done_hash) begin + // TODO target + if (o_hash_val < target) begin + state <= WRITE_OUT; + end else begin + miner_rst <= 1; + block_header[639:608] <= nonce; + state <= INCR_NONCE; + end + end else begin + miner_rst <= 0; + end + end + + INCR_NONCE: begin + // TODO? + miner_rst <= 0; + nonce <= nonce + 1; + state <= COMPUTE; + end + + WRITE_OUT: begin + // TODO + if (valid && !ready) begin + ready <= 1'b1; + + if (wb_we) begin + // WB should not be writing to user project + end else begin + // Place output hash on wishbone + rdata <= o_hash_val[BITS*count +:BITS]; + if (count >= 7) begin + count <= 0; + state <= WAIT_IN; + end else begin + count <= count + 1; + end + end + end + end + + endcase + end + end + + miner double_sha256_miner( + .block(block_header), + .clk(clk), + .rst(rst), + .hashed(o_hash_val), + .done(o_done_hash) + ); +endmodule // miner_ctrl + + +// miner +module miner( + input logic [639:0] block, + input logic clk, rst, + output logic [255:0] hashed, + output logic done +); + + logic [255:0] first_hash; + logic [255:0] secnd_hash; + + logic second_run_rst; + logic done_first_hash; + logic done_secnd_hash; + + sha_256 #(.MSG_SIZE(640), .PADDED_SIZE(1024)) first (.message(block), .hashed(first_hash), .clk(clk), .rst(rst), .done(done_first_hash)); + sha_256 #(.MSG_SIZE(256), .PADDED_SIZE(512)) second (.message(first_hash), .hashed(secnd_hash), .clk(clk), .rst(second_run_rst), .done(done_secnd_hash)); + + // always @* second_run_rst <= 1'b0; + + always @(posedge clk) begin + if (done_first_hash === 1'bX) second_run_rst <= 1'b1; + else if (done_first_hash == 1'b1) second_run_rst <= 1'b0; + end + + assign done = done_secnd_hash; + assign hashed = {secnd_hash[7:0], secnd_hash[15:8], secnd_hash[23:16], secnd_hash[31:24], secnd_hash[39:32], secnd_hash[47:40], secnd_hash[55:48], secnd_hash[63:56], secnd_hash[71:64], secnd_hash[79:72], secnd_hash[87:80], secnd_hash[95:88], secnd_hash[103:96], secnd_hash[111:104], secnd_hash[119:112], secnd_hash[127:120], secnd_hash[135:128], secnd_hash[143:136], secnd_hash[151:144], secnd_hash[159:152], secnd_hash[167:160], secnd_hash[175:168], secnd_hash[183:176], secnd_hash[191:184], secnd_hash[199:192], secnd_hash[207:200], secnd_hash[215:208], secnd_hash[223:216], secnd_hash[231:224], secnd_hash[239:232], secnd_hash[247:240], secnd_hash[255:248]}; +endmodule // miner + + +// sha_256 +module sha_256 #( + parameter MSG_SIZE = 24, + parameter PADDED_SIZE = 512 +)( + input logic [MSG_SIZE-1:0] message, + input logic clk, rst, + output logic [255:0] hashed, + output logic done +); + + logic[PADDED_SIZE-1:0] padded; + + sha_padder #(.MSG_SIZE(MSG_SIZE), .PADDED_SIZE(PADDED_SIZE)) padder (.message(message), .padded(padded)); + // sha_mainloop #(.PADDED_SIZE(PADDED_SIZE)) loop (.padded(padded), .hashed(hashed), .clk(clk), .rst(rst), .done(done)); + assign hashed = 0; + assign done = 0; +endmodule // sha_256 + + +// sha_padder +`define PACK_ARRAY(PK_WIDTH,PK_LEN,PK_SRC,PK_DEST) genvar pk_idx; generate for (pk_idx=0; pk_idx<(PK_LEN); pk_idx=pk_idx+1) begin; assign PK_DEST[((PK_WIDTH)*pk_idx+((PK_WIDTH)-1)):((PK_WIDTH)*pk_idx)] = PK_SRC[pk_idx][((PK_WIDTH)-1):0]; end; endgenerate +`define UNPACK_ARRAY(PK_WIDTH,PK_LEN,PK_DEST,PK_SRC) genvar unpk_idx; generate for (unpk_idx=0; unpk_idx<(PK_LEN); unpk_idx=unpk_idx+1) begin; assign PK_DEST[unpk_idx][((PK_WIDTH)-1):0] = PK_SRC[((PK_WIDTH)*unpk_idx+(PK_WIDTH-1)):((PK_WIDTH)*unpk_idx)]; end; endgenerate + +module sha_padder #( + parameter MSG_SIZE = 24, // size of full message + parameter PADDED_SIZE = 512 +)( + input logic [MSG_SIZE-1:0] message, + output logic [PADDED_SIZE-1:0] padded +); + + localparam zero_width = PADDED_SIZE-MSG_SIZE-1-64; + localparam back_0_width = 64-$bits(MSG_SIZE); + + assign padded = {message, 1'b1, {zero_width{1'b0}}, {back_0_width{1'b0}}, MSG_SIZE}; +endmodule //sha_padder + + +// sha_mainloop +module sha_mainloop #( + parameter PADDED_SIZE = 512 +)( + input logic [PADDED_SIZE-1:0] padded, + input logic clk, rst, + output logic [255:0] hashed, + output logic done +); + + function [31:0] K; + input [6:0] x; + K = k[2047-x*32 -: 32]; + endfunction + + function automatic [31:0] W; + input [6:0] x; + input [6:0] y; + if(^x === 1'bX) W = 32'h777; + else W = (x<16) ? padded[((PADDED_SIZE-1-y*512)-x*32) -: 32] : rho1(W(x-2, y)) + W(x-7, y) + rho0(W(x-15, y)) + W(x-16, y); + endfunction + + function automatic [31:0] rho0; + input [31:0] x; + if(^x === 1'bX) rho0 = 32'h888; + else rho0 = {x[6:0],x[31:7]} ^ {x[17:0],x[31:18]} ^ (x >> 3); + endfunction + + function automatic [31:0] rho1; + input [31:0] x; + if(^x === 1'bX) rho1 = 32'h888; + else rho1 = {x[16:0],x[31:17]} ^ {x[18:0],x[31:19]} ^ (x >> 10); + endfunction + + function [31:0] ch; + input [31:0] x,y,z; + if(^x === 1'bX) ch = 32'h888; + else ch = (x & y) ^ (~x & z); + endfunction + + function [31:0] maj; + input [31:0] x,y,z; + if(^x === 1'bX) maj = 32'h888; + else maj = (x & y) ^ (x & z) ^ (y & z); + endfunction + + function [31:0] sum0; + input [31:0] x; + if(^x === 1'bX) sum0 = 32'h888; + else sum0 = {x[1:0],x[31:2]} ^ {x[12:0],x[31:13]} ^ {x[21:0],x[31:22]}; + endfunction + + function [31:0] sum1; + input [31:0] x; + if(^x === 1'bX) sum1 = 32'h888; + else sum1 = {x[5:0],x[31:6]} ^ {x[10:0],x[31:11]} ^ {x[24:0],x[31:25]}; + endfunction + + logic [255:0] initial_hashes = {32'h6a09e667, 32'hbb67ae85, 32'h3c6ef372, 32'ha54ff53a, 32'h510e527f, 32'h9b05688c, 32'h1f83d9ab, 32'h5be0cd19}; + + logic [2047:0] k = {32'h428a2f98, 32'h71374491, 32'hb5c0fbcf, 32'he9b5dba5, 32'h3956c25b, 32'h59f111f1, 32'h923f82a4, 32'hab1c5ed5, 32'hd807aa98, 32'h12835b01, 32'h243185be, 32'h550c7dc3, 32'h72be5d74, 32'h80deb1fe, 32'h9bdc06a7, 32'hc19bf174, 32'he49b69c1, 32'hefbe4786, 32'h0fc19dc6, 32'h240ca1cc, 32'h2de92c6f, 32'h4a7484aa, 32'h5cb0a9dc, 32'h76f988da, 32'h983e5152, 32'ha831c66d, 32'hb00327c8, 32'hbf597fc7, 32'hc6e00bf3, 32'hd5a79147, 32'h06ca6351, 32'h14292967, 32'h27b70a85, 32'h2e1b2138, 32'h4d2c6dfc, 32'h53380d13, 32'h650a7354, 32'h766a0abb, 32'h81c2c92e, 32'h92722c85, 32'ha2bfe8a1, 32'ha81a664b, 32'hc24b8b70, 32'hc76c51a3, 32'hd192e819, 32'hd6990624, 32'hf40e3585, 32'h106aa070, 32'h19a4c116, 32'h1e376c08, 32'h2748774c, 32'h34b0bcb5, 32'h391c0cb3, 32'h4ed8aa4a, 32'h5b9cca4f, 32'h682e6ff3, 32'h748f82ee, 32'h78a5636f, 32'h84c87814, 32'h8cc70208, 32'h90befffa, 32'ha4506ceb, 32'hbef9a3f7, 32'hc67178f2}; + + logic [31:0] a, b, c, d, e, f, g, h, t1, t2; + logic [31:0] h1, h2, h3, h4, h5, h6, h7, h8; + + logic [6:0] j; + logic [6:0] i; + + localparam N = PADDED_SIZE/512; // number of blocks + + logic [31:0] ch_efg, maj_abc, sum0_a, sum1_e, kj, wj; + + // (e or f or g or ch_efg) + always_comb begin + ch_efg = ch(e,f,g); + maj_abc = maj(a,b,c); + sum0_a = sum0(a); + sum1_e = sum1(e); + wj = W(j, i); + kj = K(j); + end + + always @(negedge clk) begin + // t1 <= h + sum1(e) + ch(e,f,g) + K(j) + W(j); + // t2 <= sum0(a) + maj(a,b,c); + t1 <= (h + sum1_e + ch_efg + kj + wj)%4294967296; + t2 <= (sum0_a + maj_abc)%4294967296; + end + + always @(posedge clk or posedge rst) begin + if(rst) begin + i <= 1'b0; + j <= 1'bX; + h1 <= 32'h6a09e667; + h2 <= 32'hbb67ae85; + h3 <= 32'h3c6ef372; + h4 <= 32'ha54ff53a; + h5 <= 32'h510e527f; + h6 <= 32'h9b05688c; + h7 <= 32'h1f83d9ab; + h8 <= 32'h5be0cd19; + end + else if (^j === 1'bX && ^i !== 1'bX) begin + a <= h1; + b <= h2; + c <= h3; + d <= h4; + e <= h5; + f <= h6; + g <= h7; + h <= h8; + j <= 1'd0; + end + else if (j < 64) begin + h <= g; + g <= f; + f <= e; + e <= (d+t1)%4294967296; + d <= c; + c <= b; + b <= a; + a <= (t1+t2)%4294967296; + j <= j+1; + end + else if (j == 64) begin + h1 <= a + h1; + h2 <= b + h2; + h3 <= c + h3; + h4 <= d + h4; + h5 <= e + h5; + h6 <= f + h6; + h7 <= g + h7; + h8 <= h + h8; + j <= 1'bX; + if (i<N-1) i <= i+1; + else begin + i <= 1'bX; + done <= 1'b1; + end + end + end + + assign hashed = {h1, h2, h3, h4, h5, h6, h7, h8}; +endmodule // sha_mainloop + +`default_nettype wire
diff --git a/verilog/rtl/sha256.v b/verilog/rtl/sha256.v new file mode 100644 index 0000000..3fe2a92 --- /dev/null +++ b/verilog/rtl/sha256.v
@@ -0,0 +1,266 @@ +//====================================================================== +// +// sha256.v +// -------- +// Top level wrapper for the SHA-256 hash function providing +// a simple memory like interface with 32 bit data access. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2013, 201, Secworks Sweden AB +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//====================================================================== + +`default_nettype none + +module sha256( + // Clock and reset. + input wire clk, + input wire reset_n, + + // Control. + input wire cs, + input wire we, + + // Data ports. + input wire [7 : 0] address, + input wire [31 : 0] write_data, + output wire [31 : 0] read_data, + output wire error + ); + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + localparam ADDR_NAME0 = 8'h00; + localparam ADDR_NAME1 = 8'h01; + localparam ADDR_VERSION = 8'h02; + + localparam ADDR_CTRL = 8'h08; + localparam CTRL_INIT_BIT = 0; + localparam CTRL_NEXT_BIT = 1; + localparam CTRL_MODE_BIT = 2; + + localparam ADDR_STATUS = 8'h09; + localparam STATUS_READY_BIT = 0; + localparam STATUS_VALID_BIT = 1; + + localparam ADDR_BLOCK0 = 8'h10; + localparam ADDR_BLOCK15 = 8'h1f; + + localparam ADDR_DIGEST0 = 8'h20; + localparam ADDR_DIGEST7 = 8'h27; + + localparam CORE_NAME0 = 32'h73686132; // "sha2" + localparam CORE_NAME1 = 32'h2d323536; // "-256" + localparam CORE_VERSION = 32'h312e3830; // "1.80" + + localparam MODE_SHA_224 = 1'h0; + localparam MODE_SHA_256 = 1'h1; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg init_reg; + reg init_new; + + reg next_reg; + reg next_new; + + reg mode_reg; + reg mode_new; + reg mode_we; + + reg ready_reg; + + reg [31 : 0] block_reg [0 : 15]; + reg block_we; + + reg [255 : 0] digest_reg; + + reg digest_valid_reg; + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + wire core_ready; + wire [511 : 0] core_block; + wire [255 : 0] core_digest; + wire core_digest_valid; + + reg [31 : 0] tmp_read_data; + reg tmp_error; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign core_block = {block_reg[00], block_reg[01], block_reg[02], block_reg[03], + block_reg[04], block_reg[05], block_reg[06], block_reg[07], + block_reg[08], block_reg[09], block_reg[10], block_reg[11], + block_reg[12], block_reg[13], block_reg[14], block_reg[15]}; + + assign read_data = tmp_read_data; + assign error = tmp_error; + + + //---------------------------------------------------------------- + // core instantiation. + //---------------------------------------------------------------- + sha256_core core( + .clk(clk), + .reset_n(reset_n), + + .init(init_reg), + .next(next_reg), + .mode(mode_reg), + + .block(core_block), + + .ready(core_ready), + + .digest(core_digest), + .digest_valid(core_digest_valid) + ); + + + //---------------------------------------------------------------- + // reg_update + // + // Update functionality for all registers in the core. + // All registers are positive edge triggered with asynchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk or negedge reset_n) + begin : reg_update + integer i; + + if (!reset_n) + begin + for (i = 0 ; i < 16 ; i = i + 1) + block_reg[i] <= 32'h0; + + init_reg <= 0; + next_reg <= 0; + ready_reg <= 0; + mode_reg <= MODE_SHA_256; + digest_reg <= 256'h0; + digest_valid_reg <= 0; + end + else + begin + ready_reg <= core_ready; + digest_valid_reg <= core_digest_valid; + init_reg <= init_new; + next_reg <= next_new; + + if (mode_we) + mode_reg <= mode_new; + + if (core_digest_valid) + digest_reg <= core_digest; + + if (block_we) + block_reg[address[3 : 0]] <= write_data; + end + end // reg_update + + + //---------------------------------------------------------------- + // api_logic + // + // Implementation of the api logic. If cs is enabled will either + // try to write to or read from the internal registers. + //---------------------------------------------------------------- + always @* + begin : api_logic + init_new = 0; + next_new = 0; + mode_new = 0; + mode_we = 0; + block_we = 0; + tmp_read_data = 32'h0; + tmp_error = 0; + + if (cs) + begin + if (we) + begin + if (address == ADDR_CTRL) + begin + init_new = write_data[CTRL_INIT_BIT]; + next_new = write_data[CTRL_NEXT_BIT]; + mode_new = write_data[CTRL_MODE_BIT]; + mode_we = 1; + end + + if ((address >= ADDR_BLOCK0) && (address <= ADDR_BLOCK15)) + block_we = 1; + end // if (we) + + else + begin + // read + if ((address >= ADDR_BLOCK0) && (address <= ADDR_BLOCK15)) + tmp_read_data = block_reg[address[3 : 0]]; + + if ((address >= ADDR_DIGEST0) && (address <= ADDR_DIGEST7)) + tmp_read_data = digest_reg[(7 - (address - ADDR_DIGEST0)) * 32 +: 32]; + + case (address) + // Read operations. + ADDR_NAME0: + tmp_read_data = CORE_NAME0; + + ADDR_NAME1: + tmp_read_data = CORE_NAME1; + + ADDR_VERSION: + tmp_read_data = CORE_VERSION; + + ADDR_CTRL: + tmp_read_data = {29'h0, mode_reg, next_reg, init_reg}; + + ADDR_STATUS: + tmp_read_data = {30'h0, digest_valid_reg, ready_reg}; + + default: + begin + end + endcase // case (address) + end + end + end // addr_decoder +endmodule // sha256 + +//====================================================================== +// EOF sha256.v +//======================================================================
diff --git a/verilog/rtl/sha256_core.v b/verilog/rtl/sha256_core.v new file mode 100644 index 0000000..b2c880e --- /dev/null +++ b/verilog/rtl/sha256_core.v
@@ -0,0 +1,552 @@ +//====================================================================== +// +// sha256_core.v +// ------------- +// Verilog 2001 implementation of the SHA-256 hash function. +// This is the internal core with wide interfaces. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2013, Secworks Sweden AB +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//====================================================================== + +`default_nettype none + +module sha256_core( + input wire clk, + input wire reset_n, + + input wire init, + input wire next, + input wire mode, + + input wire [511 : 0] block, + + output wire ready, + output wire [255 : 0] digest, + output wire digest_valid + ); + + + //---------------------------------------------------------------- + // Internal constant and parameter definitions. + //---------------------------------------------------------------- + localparam SHA224_H0_0 = 32'hc1059ed8; + localparam SHA224_H0_1 = 32'h367cd507; + localparam SHA224_H0_2 = 32'h3070dd17; + localparam SHA224_H0_3 = 32'hf70e5939; + localparam SHA224_H0_4 = 32'hffc00b31; + localparam SHA224_H0_5 = 32'h68581511; + localparam SHA224_H0_6 = 32'h64f98fa7; + localparam SHA224_H0_7 = 32'hbefa4fa4; + + localparam SHA256_H0_0 = 32'h6a09e667; + localparam SHA256_H0_1 = 32'hbb67ae85; + localparam SHA256_H0_2 = 32'h3c6ef372; + localparam SHA256_H0_3 = 32'ha54ff53a; + localparam SHA256_H0_4 = 32'h510e527f; + localparam SHA256_H0_5 = 32'h9b05688c; + localparam SHA256_H0_6 = 32'h1f83d9ab; + localparam SHA256_H0_7 = 32'h5be0cd19; + + localparam SHA256_ROUNDS = 63; + + localparam CTRL_IDLE = 0; + localparam CTRL_ROUNDS = 1; + localparam CTRL_DONE = 2; + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg [31 : 0] a_reg; + reg [31 : 0] a_new; + reg [31 : 0] b_reg; + reg [31 : 0] b_new; + reg [31 : 0] c_reg; + reg [31 : 0] c_new; + reg [31 : 0] d_reg; + reg [31 : 0] d_new; + reg [31 : 0] e_reg; + reg [31 : 0] e_new; + reg [31 : 0] f_reg; + reg [31 : 0] f_new; + reg [31 : 0] g_reg; + reg [31 : 0] g_new; + reg [31 : 0] h_reg; + reg [31 : 0] h_new; + reg a_h_we; + + reg [31 : 0] H0_reg; + reg [31 : 0] H0_new; + reg [31 : 0] H1_reg; + reg [31 : 0] H1_new; + reg [31 : 0] H2_reg; + reg [31 : 0] H2_new; + reg [31 : 0] H3_reg; + reg [31 : 0] H3_new; + reg [31 : 0] H4_reg; + reg [31 : 0] H4_new; + reg [31 : 0] H5_reg; + reg [31 : 0] H5_new; + reg [31 : 0] H6_reg; + reg [31 : 0] H6_new; + reg [31 : 0] H7_reg; + reg [31 : 0] H7_new; + reg H_we; + + reg [5 : 0] t_ctr_reg; + reg [5 : 0] t_ctr_new; + reg t_ctr_we; + reg t_ctr_inc; + reg t_ctr_rst; + + reg digest_valid_reg; + reg digest_valid_new; + reg digest_valid_we; + + reg [1 : 0] sha256_ctrl_reg; + reg [1 : 0] sha256_ctrl_new; + reg sha256_ctrl_we; + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + reg digest_init; + reg digest_update; + + reg state_init; + reg state_update; + + reg first_block; + + reg ready_flag; + + reg [31 : 0] t1; + reg [31 : 0] t2; + + wire [31 : 0] k_data; + + reg w_init; + reg w_next; + wire [31 : 0] w_data; + + + //---------------------------------------------------------------- + // Module instantiantions. + //---------------------------------------------------------------- + sha256_k_constants k_constants_inst( + .round(t_ctr_reg), + .K(k_data) + ); + + + sha256_w_mem w_mem_inst( + .clk(clk), + .reset_n(reset_n), + + .block(block), + + .init(w_init), + .next(w_next), + .w(w_data) + ); + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign ready = ready_flag; + + assign digest = {H0_reg, H1_reg, H2_reg, H3_reg, + H4_reg, H5_reg, H6_reg, H7_reg}; + + assign digest_valid = digest_valid_reg; + + + //---------------------------------------------------------------- + // reg_update + // Update functionality for all registers in the core. + // All registers are positive edge triggered with asynchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk or negedge reset_n) + begin : reg_update + if (!reset_n) + begin + a_reg <= 32'h0; + b_reg <= 32'h0; + c_reg <= 32'h0; + d_reg <= 32'h0; + e_reg <= 32'h0; + f_reg <= 32'h0; + g_reg <= 32'h0; + h_reg <= 32'h0; + H0_reg <= 32'h0; + H1_reg <= 32'h0; + H2_reg <= 32'h0; + H3_reg <= 32'h0; + H4_reg <= 32'h0; + H5_reg <= 32'h0; + H6_reg <= 32'h0; + H7_reg <= 32'h0; + digest_valid_reg <= 0; + t_ctr_reg <= 6'h0; + sha256_ctrl_reg <= CTRL_IDLE; + end + else + begin + + if (a_h_we) + begin + a_reg <= a_new; + b_reg <= b_new; + c_reg <= c_new; + d_reg <= d_new; + e_reg <= e_new; + f_reg <= f_new; + g_reg <= g_new; + h_reg <= h_new; + end + + if (H_we) + begin + H0_reg <= H0_new; + H1_reg <= H1_new; + H2_reg <= H2_new; + H3_reg <= H3_new; + H4_reg <= H4_new; + H5_reg <= H5_new; + H6_reg <= H6_new; + H7_reg <= H7_new; + end + + if (t_ctr_we) + t_ctr_reg <= t_ctr_new; + + if (digest_valid_we) + digest_valid_reg <= digest_valid_new; + + if (sha256_ctrl_we) + sha256_ctrl_reg <= sha256_ctrl_new; + end + end // reg_update + + + //---------------------------------------------------------------- + // digest_logic + // + // The logic needed to init as well as update the digest. + //---------------------------------------------------------------- + always @* + begin : digest_logic + H0_new = 32'h0; + H1_new = 32'h0; + H2_new = 32'h0; + H3_new = 32'h0; + H4_new = 32'h0; + H5_new = 32'h0; + H6_new = 32'h0; + H7_new = 32'h0; + H_we = 0; + + if (digest_init) + begin + H_we = 1; + if (mode) + begin + H0_new = SHA256_H0_0; + H1_new = SHA256_H0_1; + H2_new = SHA256_H0_2; + H3_new = SHA256_H0_3; + H4_new = SHA256_H0_4; + H5_new = SHA256_H0_5; + H6_new = SHA256_H0_6; + H7_new = SHA256_H0_7; + end + else + begin + H0_new = SHA224_H0_0; + H1_new = SHA224_H0_1; + H2_new = SHA224_H0_2; + H3_new = SHA224_H0_3; + H4_new = SHA224_H0_4; + H5_new = SHA224_H0_5; + H6_new = SHA224_H0_6; + H7_new = SHA224_H0_7; + end + end + + if (digest_update) + begin + H0_new = H0_reg + a_reg; + H1_new = H1_reg + b_reg; + H2_new = H2_reg + c_reg; + H3_new = H3_reg + d_reg; + H4_new = H4_reg + e_reg; + H5_new = H5_reg + f_reg; + H6_new = H6_reg + g_reg; + H7_new = H7_reg + h_reg; + H_we = 1; + end + end // digest_logic + + + //---------------------------------------------------------------- + // t1_logic + // + // The logic for the T1 function. + //---------------------------------------------------------------- + always @* + begin : t1_logic + reg [31 : 0] sum1; + reg [31 : 0] ch; + + sum1 = {e_reg[5 : 0], e_reg[31 : 6]} ^ + {e_reg[10 : 0], e_reg[31 : 11]} ^ + {e_reg[24 : 0], e_reg[31 : 25]}; + + ch = (e_reg & f_reg) ^ ((~e_reg) & g_reg); + + t1 = h_reg + sum1 + ch + w_data + k_data; + end // t1_logic + + + //---------------------------------------------------------------- + // t2_logic + // + // The logic for the T2 function + //---------------------------------------------------------------- + always @* + begin : t2_logic + reg [31 : 0] sum0; + reg [31 : 0] maj; + + sum0 = {a_reg[1 : 0], a_reg[31 : 2]} ^ + {a_reg[12 : 0], a_reg[31 : 13]} ^ + {a_reg[21 : 0], a_reg[31 : 22]}; + + maj = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg); + + t2 = sum0 + maj; + end // t2_logic + + + //---------------------------------------------------------------- + // state_logic + // + // The logic needed to init as well as update the state during + // round processing. + //---------------------------------------------------------------- + always @* + begin : state_logic + a_new = 32'h0; + b_new = 32'h0; + c_new = 32'h0; + d_new = 32'h0; + e_new = 32'h0; + f_new = 32'h0; + g_new = 32'h0; + h_new = 32'h0; + a_h_we = 0; + + if (state_init) + begin + a_h_we = 1; + if (first_block) + begin + if (mode) + begin + a_new = SHA256_H0_0; + b_new = SHA256_H0_1; + c_new = SHA256_H0_2; + d_new = SHA256_H0_3; + e_new = SHA256_H0_4; + f_new = SHA256_H0_5; + g_new = SHA256_H0_6; + h_new = SHA256_H0_7; + end + else + begin + a_new = SHA224_H0_0; + b_new = SHA224_H0_1; + c_new = SHA224_H0_2; + d_new = SHA224_H0_3; + e_new = SHA224_H0_4; + f_new = SHA224_H0_5; + g_new = SHA224_H0_6; + h_new = SHA224_H0_7; + end + end + else + begin + a_new = H0_reg; + b_new = H1_reg; + c_new = H2_reg; + d_new = H3_reg; + e_new = H4_reg; + f_new = H5_reg; + g_new = H6_reg; + h_new = H7_reg; + end + end + + if (state_update) + begin + a_new = t1 + t2; + b_new = a_reg; + c_new = b_reg; + d_new = c_reg; + e_new = d_reg + t1; + f_new = e_reg; + g_new = f_reg; + h_new = g_reg; + a_h_we = 1; + end + end // state_logic + + + //---------------------------------------------------------------- + // t_ctr + // + // Update logic for the round counter, a monotonically + // increasing counter with reset. + //---------------------------------------------------------------- + always @* + begin : t_ctr + t_ctr_new = 0; + t_ctr_we = 0; + + if (t_ctr_rst) + begin + t_ctr_new = 0; + t_ctr_we = 1; + end + + if (t_ctr_inc) + begin + t_ctr_new = t_ctr_reg + 1'b1; + t_ctr_we = 1; + end + end // t_ctr + + + //---------------------------------------------------------------- + // sha256_ctrl_fsm + // + // Logic for the state machine controlling the core behaviour. + //---------------------------------------------------------------- + always @* + begin : sha256_ctrl_fsm + digest_init = 0; + digest_update = 0; + + state_init = 0; + state_update = 0; + + first_block = 0; + ready_flag = 0; + + w_init = 0; + w_next = 0; + + t_ctr_inc = 0; + t_ctr_rst = 0; + + digest_valid_new = 0; + digest_valid_we = 0; + + sha256_ctrl_new = CTRL_IDLE; + sha256_ctrl_we = 0; + + + case (sha256_ctrl_reg) + CTRL_IDLE: + begin + ready_flag = 1; + + if (init) + begin + digest_init = 1; + w_init = 1; + state_init = 1; + first_block = 1; + t_ctr_rst = 1; + digest_valid_new = 0; + digest_valid_we = 1; + sha256_ctrl_new = CTRL_ROUNDS; + sha256_ctrl_we = 1; + end + + if (next) + begin + t_ctr_rst = 1; + w_init = 1; + state_init = 1; + digest_valid_new = 0; + digest_valid_we = 1; + sha256_ctrl_new = CTRL_ROUNDS; + sha256_ctrl_we = 1; + end + end + + + CTRL_ROUNDS: + begin + w_next = 1; + state_update = 1; + t_ctr_inc = 1; + + if (t_ctr_reg == SHA256_ROUNDS) + begin + sha256_ctrl_new = CTRL_DONE; + sha256_ctrl_we = 1; + end + end + + + CTRL_DONE: + begin + digest_update = 1; + digest_valid_new = 1; + digest_valid_we = 1; + + sha256_ctrl_new = CTRL_IDLE; + sha256_ctrl_we = 1; + end + endcase // case (sha256_ctrl_reg) + end // sha256_ctrl_fsm + +endmodule // sha256_core + +//====================================================================== +// EOF sha256_core.v +//======================================================================
diff --git a/verilog/rtl/sha256_k_constants.v b/verilog/rtl/sha256_k_constants.v new file mode 100644 index 0000000..bae748e --- /dev/null +++ b/verilog/rtl/sha256_k_constants.v
@@ -0,0 +1,134 @@ +//====================================================================== +// +// sha256_k_constants.v +// -------------------- +// The table K with constants in the SHA-256 hash function. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2013, Secworks Sweden AB +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//====================================================================== + +`default_nettype none + +module sha256_k_constants( + input wire [5 : 0] round, + output wire [31 : 0] K + ); + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + reg [31 : 0] tmp_K; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign K = tmp_K; + + + //---------------------------------------------------------------- + // round_mux + //---------------------------------------------------------------- + always @* + begin : round_mux + case(round) + 00: tmp_K = 32'h428a2f98; + 01: tmp_K = 32'h71374491; + 02: tmp_K = 32'hb5c0fbcf; + 03: tmp_K = 32'he9b5dba5; + 04: tmp_K = 32'h3956c25b; + 05: tmp_K = 32'h59f111f1; + 06: tmp_K = 32'h923f82a4; + 07: tmp_K = 32'hab1c5ed5; + 08: tmp_K = 32'hd807aa98; + 09: tmp_K = 32'h12835b01; + 10: tmp_K = 32'h243185be; + 11: tmp_K = 32'h550c7dc3; + 12: tmp_K = 32'h72be5d74; + 13: tmp_K = 32'h80deb1fe; + 14: tmp_K = 32'h9bdc06a7; + 15: tmp_K = 32'hc19bf174; + 16: tmp_K = 32'he49b69c1; + 17: tmp_K = 32'hefbe4786; + 18: tmp_K = 32'h0fc19dc6; + 19: tmp_K = 32'h240ca1cc; + 20: tmp_K = 32'h2de92c6f; + 21: tmp_K = 32'h4a7484aa; + 22: tmp_K = 32'h5cb0a9dc; + 23: tmp_K = 32'h76f988da; + 24: tmp_K = 32'h983e5152; + 25: tmp_K = 32'ha831c66d; + 26: tmp_K = 32'hb00327c8; + 27: tmp_K = 32'hbf597fc7; + 28: tmp_K = 32'hc6e00bf3; + 29: tmp_K = 32'hd5a79147; + 30: tmp_K = 32'h06ca6351; + 31: tmp_K = 32'h14292967; + 32: tmp_K = 32'h27b70a85; + 33: tmp_K = 32'h2e1b2138; + 34: tmp_K = 32'h4d2c6dfc; + 35: tmp_K = 32'h53380d13; + 36: tmp_K = 32'h650a7354; + 37: tmp_K = 32'h766a0abb; + 38: tmp_K = 32'h81c2c92e; + 39: tmp_K = 32'h92722c85; + 40: tmp_K = 32'ha2bfe8a1; + 41: tmp_K = 32'ha81a664b; + 42: tmp_K = 32'hc24b8b70; + 43: tmp_K = 32'hc76c51a3; + 44: tmp_K = 32'hd192e819; + 45: tmp_K = 32'hd6990624; + 46: tmp_K = 32'hf40e3585; + 47: tmp_K = 32'h106aa070; + 48: tmp_K = 32'h19a4c116; + 49: tmp_K = 32'h1e376c08; + 50: tmp_K = 32'h2748774c; + 51: tmp_K = 32'h34b0bcb5; + 52: tmp_K = 32'h391c0cb3; + 53: tmp_K = 32'h4ed8aa4a; + 54: tmp_K = 32'h5b9cca4f; + 55: tmp_K = 32'h682e6ff3; + 56: tmp_K = 32'h748f82ee; + 57: tmp_K = 32'h78a5636f; + 58: tmp_K = 32'h84c87814; + 59: tmp_K = 32'h8cc70208; + 60: tmp_K = 32'h90befffa; + 61: tmp_K = 32'ha4506ceb; + 62: tmp_K = 32'hbef9a3f7; + 63: tmp_K = 32'hc67178f2; + endcase // case (round) + end // block: round_mux +endmodule // sha256_k_constants + +//====================================================================== +// sha256_k_constants.v +//======================================================================
diff --git a/verilog/rtl/sha256_w_mem.v b/verilog/rtl/sha256_w_mem.v new file mode 100644 index 0000000..06f4d46 --- /dev/null +++ b/verilog/rtl/sha256_w_mem.v
@@ -0,0 +1,272 @@ +//====================================================================== +// +// sha256_w_mem_regs.v +// ------------------- +// The W memory. This version uses 16 32-bit registers as a sliding +// window to generate the 64 words. +// +// +// Author: Joachim Strombergson +// Copyright (c) 2013, Secworks Sweden AB +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//====================================================================== + +`default_nettype none + +module sha256_w_mem( + input wire clk, + input wire reset_n, + + input wire [511 : 0] block, + + input wire init, + input wire next, + output wire [31 : 0] w + ); + + + //---------------------------------------------------------------- + // Registers including update variables and write enable. + //---------------------------------------------------------------- + reg [31 : 0] w_mem [0 : 15]; + reg [31 : 0] w_mem00_new; + reg [31 : 0] w_mem01_new; + reg [31 : 0] w_mem02_new; + reg [31 : 0] w_mem03_new; + reg [31 : 0] w_mem04_new; + reg [31 : 0] w_mem05_new; + reg [31 : 0] w_mem06_new; + reg [31 : 0] w_mem07_new; + reg [31 : 0] w_mem08_new; + reg [31 : 0] w_mem09_new; + reg [31 : 0] w_mem10_new; + reg [31 : 0] w_mem11_new; + reg [31 : 0] w_mem12_new; + reg [31 : 0] w_mem13_new; + reg [31 : 0] w_mem14_new; + reg [31 : 0] w_mem15_new; + reg w_mem_we; + + reg [5 : 0] w_ctr_reg; + reg [5 : 0] w_ctr_new; + reg w_ctr_we; + + + //---------------------------------------------------------------- + // Wires. + //---------------------------------------------------------------- + reg [31 : 0] w_tmp; + reg [31 : 0] w_new; + + + //---------------------------------------------------------------- + // Concurrent connectivity for ports etc. + //---------------------------------------------------------------- + assign w = w_tmp; + + + //---------------------------------------------------------------- + // reg_update + // Update functionality for all registers in the core. + // All registers are positive edge triggered with synchronous + // active low reset. All registers have write enable. + //---------------------------------------------------------------- + always @ (posedge clk or negedge reset_n) + begin : reg_update + integer i; + + if (!reset_n) + begin + for (i = 0 ; i < 16 ; i = i + 1) + w_mem[i] <= 32'h0; + + w_ctr_reg <= 6'h0; + end + else + begin + if (w_mem_we) + begin + w_mem[00] <= w_mem00_new; + w_mem[01] <= w_mem01_new; + w_mem[02] <= w_mem02_new; + w_mem[03] <= w_mem03_new; + w_mem[04] <= w_mem04_new; + w_mem[05] <= w_mem05_new; + w_mem[06] <= w_mem06_new; + w_mem[07] <= w_mem07_new; + w_mem[08] <= w_mem08_new; + w_mem[09] <= w_mem09_new; + w_mem[10] <= w_mem10_new; + w_mem[11] <= w_mem11_new; + w_mem[12] <= w_mem12_new; + w_mem[13] <= w_mem13_new; + w_mem[14] <= w_mem14_new; + w_mem[15] <= w_mem15_new; + end + + if (w_ctr_we) + w_ctr_reg <= w_ctr_new; + end + end // reg_update + + + //---------------------------------------------------------------- + // select_w + // + // Mux for the external read operation. This is where we exract + // the W variable. + //---------------------------------------------------------------- + always @* + begin : select_w + if (w_ctr_reg < 16) + w_tmp = w_mem[w_ctr_reg[3 : 0]]; + else + w_tmp = w_new; + end // select_w + + + //---------------------------------------------------------------- + // w_new_logic + // + // Logic that calculates the next value to be inserted into + // the sliding window of the memory. + //---------------------------------------------------------------- + always @* + begin : w_mem_update_logic + reg [31 : 0] w_0; + reg [31 : 0] w_1; + reg [31 : 0] w_9; + reg [31 : 0] w_14; + reg [31 : 0] d0; + reg [31 : 0] d1; + + w_mem00_new = 32'h0; + w_mem01_new = 32'h0; + w_mem02_new = 32'h0; + w_mem03_new = 32'h0; + w_mem04_new = 32'h0; + w_mem05_new = 32'h0; + w_mem06_new = 32'h0; + w_mem07_new = 32'h0; + w_mem08_new = 32'h0; + w_mem09_new = 32'h0; + w_mem10_new = 32'h0; + w_mem11_new = 32'h0; + w_mem12_new = 32'h0; + w_mem13_new = 32'h0; + w_mem14_new = 32'h0; + w_mem15_new = 32'h0; + w_mem_we = 0; + + w_0 = w_mem[0]; + w_1 = w_mem[1]; + w_9 = w_mem[9]; + w_14 = w_mem[14]; + + d0 = {w_1[6 : 0], w_1[31 : 7]} ^ + {w_1[17 : 0], w_1[31 : 18]} ^ + {3'b000, w_1[31 : 3]}; + + d1 = {w_14[16 : 0], w_14[31 : 17]} ^ + {w_14[18 : 0], w_14[31 : 19]} ^ + {10'b0000000000, w_14[31 : 10]}; + + w_new = d1 + w_9 + d0 + w_0; + + if (init) + begin + w_mem00_new = block[511 : 480]; + w_mem01_new = block[479 : 448]; + w_mem02_new = block[447 : 416]; + w_mem03_new = block[415 : 384]; + w_mem04_new = block[383 : 352]; + w_mem05_new = block[351 : 320]; + w_mem06_new = block[319 : 288]; + w_mem07_new = block[287 : 256]; + w_mem08_new = block[255 : 224]; + w_mem09_new = block[223 : 192]; + w_mem10_new = block[191 : 160]; + w_mem11_new = block[159 : 128]; + w_mem12_new = block[127 : 96]; + w_mem13_new = block[95 : 64]; + w_mem14_new = block[63 : 32]; + w_mem15_new = block[31 : 0]; + w_mem_we = 1; + end + + if (next && (w_ctr_reg > 15)) + begin + w_mem00_new = w_mem[01]; + w_mem01_new = w_mem[02]; + w_mem02_new = w_mem[03]; + w_mem03_new = w_mem[04]; + w_mem04_new = w_mem[05]; + w_mem05_new = w_mem[06]; + w_mem06_new = w_mem[07]; + w_mem07_new = w_mem[08]; + w_mem08_new = w_mem[09]; + w_mem09_new = w_mem[10]; + w_mem10_new = w_mem[11]; + w_mem11_new = w_mem[12]; + w_mem12_new = w_mem[13]; + w_mem13_new = w_mem[14]; + w_mem14_new = w_mem[15]; + w_mem15_new = w_new; + w_mem_we = 1; + end + end // w_mem_update_logic + + + //---------------------------------------------------------------- + // w_ctr + // W schedule adress counter. Counts from 0x10 to 0x3f and + // is used to expand the block into words. + //---------------------------------------------------------------- + always @* + begin : w_ctr + w_ctr_new = 6'h0; + w_ctr_we = 1'h0; + + if (init) + begin + w_ctr_new = 6'h0; + w_ctr_we = 1'h1; + end + + if (next) + begin + w_ctr_new = w_ctr_reg + 6'h01; + w_ctr_we = 1'h1; + end + end // w_ctr +endmodule // sha256_w_mem + +//====================================================================== +// sha256_w_mem.v +//======================================================================