//====================================================================== // // montprod.v // --------- // Montgomery product calculator for the modular exponentiantion core. // // // Author: Peter Magnusson, Joachim Strombergson // Copyright (c) 2015, NORDUnet A/S All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // - Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // - 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. // // - Neither the name of the NORDUnet nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // 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 // HOLDER 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. // //====================================================================== module montprod( input wire clk, input wire reset_n, input wire calculate, output wire ready, input [7 : 0] length, output wire [7 : 0] opa_addr, input wire [31 : 0] opa_data, output wire [7 : 0] opb_addr, input wire [31 : 0] opb_data, output wire [7 : 0] opm_addr, input wire [31 : 0] opm_data, output wire [7 : 0] result_addr, output wire [31 : 0] result_data, output wire result_we ); //---------------------------------------------------------------- // Internal constant and parameter definitions. //---------------------------------------------------------------- localparam CTRL_IDLE = 4'h0; localparam CTRL_INIT_S = 4'h1; localparam CTRL_WAIT = 4'h2; localparam CTRL_LOOP_ITER = 4'h3; localparam CTRL_LOOP_BQ = 4'h4; localparam CTRL_CALC_ADD = 4'h5; localparam CTRL_STALLPIPE_ADD = 4'h6; localparam CTRL_CALC_SDIV2 = 4'h7; localparam CTRL_STALLPIPE_SDIV2 = 4'h8; localparam CTRL_L_STALLPIPE_ES = 4'h9; localparam CTRL_EMIT_S = 4'ha; localparam SMUX_0 = 2'h0; localparam SMUX_ADD = 2'h1; localparam SMUX_SHR = 2'h2; //---------------------------------------------------------------- // Registers including update variables and write enable. //---------------------------------------------------------------- reg [07 : 0] opa_addr_reg; reg [07 : 0] opb_addr_reg; reg [07 : 0] opm_addr_reg; reg [07 : 0] result_addr_reg; reg [31 : 0] result_data_reg; reg ready_reg; reg ready_new; reg ready_we; reg [3 : 0] montprod_ctrl_reg; reg [3 : 0] montprod_ctrl_new; reg montprod_ctrl_we; reg [1 : 0] s_mux_new; reg [1 : 0] s_mux_reg; reg [31 : 0] s_mem_new; reg s_mem_we_reg; reg s_mem_we_new; reg [07 : 0] s_mem_addr; reg [07 : 0] s_mem_wr_addr_reg; wire [31 : 0] s_mem_read_data; reg q_new; reg q_reg; reg b_new; reg b_reg; reg bq_we; reg [12 : 0] loop_ctr_reg; reg [12 : 0] loop_ctr_new; reg loop_ctr_we; reg loop_ctr_set; reg loop_ctr_dec; reg [07 : 0] b_word_index; //loop counter as a word index reg [04 : 0] b_bit_index_reg; reg [04 : 0] b_bit_index_new; reg b_bit_index_we; reg [07 : 0] word_index_reg; //register of what word is being read reg [07 : 0] word_index_new; //calculation of what word to be read reg [07 : 0] word_index_prev_reg; //register of what word was read previously (result address to emit) reg [07 : 0] length_m1; reg add_carry_in_sa_reg; reg add_carry_in_sa_new; reg add_carry_in_sm_reg; reg add_carry_in_sm_new; reg shr_carry_in_reg; reg shr_carry_in_new; reg first_iteration_reg; reg first_iteration_new; reg first_iteration_we; //---------------------------------------------------------------- // Wires. //---------------------------------------------------------------- reg tmp_result_we; wire [31 : 0] add_result_sa; wire add_carry_out_sa; wire [31 : 0] add_result_sm; wire add_carry_out_sm; reg [31 : 0] shr_data_in; wire shr_carry_out; wire [31 : 0] shr_data_out; reg reset_word_index_lsw; reg reset_word_index_msw; reg [31 : 0] sa_adder_data_in; reg [31 : 0] muxed_s_mem_read_data; //---------------------------------------------------------------- // Concurrent connectivity for ports etc. //---------------------------------------------------------------- assign opa_addr = opa_addr_reg; assign opb_addr = opb_addr_reg; assign opm_addr = opm_addr_reg; assign result_addr = result_addr_reg; assign result_data = result_data_reg; assign result_we = tmp_result_we; assign ready = ready_reg; //---------------------------------------------------------------- // Instantions //---------------------------------------------------------------- blockmem1r1w s_mem( .clk(clk), .read_addr(s_mem_addr), .read_data(s_mem_read_data), .wr(s_mem_we_reg), .write_addr(s_mem_wr_addr_reg), .write_data(s_mem_new) ); adder32 s_adder_sm( .a(muxed_s_mem_read_data), .b(opm_data), .carry_in(add_carry_in_sm_reg), .sum(add_result_sm), .carry_out(add_carry_out_sm) ); adder32 s_adder_sa( .a(sa_adder_data_in), .b(opa_data), .carry_in(add_carry_in_sa_reg), .sum(add_result_sa), .carry_out(add_carry_out_sa) ); shr32 shifter( .a(s_mem_read_data), .carry_in(shr_carry_in_reg), .adiv2(shr_data_out), .carry_out(shr_carry_out) ); //---------------------------------------------------------------- // 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 ready_reg <= 1'b1; loop_ctr_reg <= 13'h0; word_index_reg <= 8'h0; word_index_prev_reg <= 8'h0; add_carry_in_sa_reg <= 1'b0; add_carry_in_sm_reg <= 1'b0; shr_carry_in_reg <= 1'b0; b_reg <= 1'b0; q_reg <= 1'b0; s_mux_reg <= SMUX_0; s_mem_we_reg <= 1'b0; s_mem_wr_addr_reg <= 8'h0; b_bit_index_reg <= 5'h0; first_iteration_reg <= 1'b0; montprod_ctrl_reg <= CTRL_IDLE; end else begin s_mem_wr_addr_reg <= s_mem_addr; s_mem_we_reg <= s_mem_we_new; s_mux_reg <= s_mux_new; word_index_reg <= word_index_new; word_index_prev_reg <= word_index_reg; shr_carry_in_reg <= shr_carry_in_new; add_carry_in_sa_reg <= add_carry_in_sa_new; add_carry_in_sm_reg <= add_carry_in_sm_new; if (first_iteration_we) first_iteration_reg <= first_iteration_new; if (b_bit_index_we) b_bit_index_reg <= b_bit_index_new; if (bq_we) begin b_reg <= b_new; q_reg <= q_new; end if (ready_we) ready_reg <= ready_new; if (loop_ctr_we) loop_ctr_reg <= loop_ctr_new; if (montprod_ctrl_we) begin montprod_ctrl_reg <= montprod_ctrl_new; end end end // reg_update //---------------------------------------------------------------- // prodcalc //---------------------------------------------------------------- always @* begin : prodcalc opa_addr_reg = word_index_reg; opb_addr_reg = b_word_index; opm_addr_reg = word_index_reg; s_mem_addr = word_index_reg; tmp_result_we = 1'b0; result_addr_reg = word_index_prev_reg; result_data_reg = s_mem_read_data; if (montprod_ctrl_reg == CTRL_LOOP_ITER) opa_addr_reg = length_m1; if (montprod_ctrl_reg == CTRL_LOOP_ITER) s_mem_addr = length_m1; if (montprod_ctrl_reg == CTRL_EMIT_S) tmp_result_we = 1'b1; if (reset_word_index_lsw == 1'b1) word_index_new = length_m1; else if (reset_word_index_msw == 1'b1) word_index_new = 8'h0; else if (montprod_ctrl_reg == CTRL_CALC_SDIV2) word_index_new = word_index_reg + 1'b1; else word_index_new = word_index_reg - 1'b1; end // prodcalc //---------------------------------------------------------------- // s_logic //---------------------------------------------------------------- always @* begin : s_logic shr_carry_in_new = 1'b0; muxed_s_mem_read_data = 32'h0; sa_adder_data_in = 32'h0; add_carry_in_sa_new = 1'b0; add_carry_in_sm_new = 1'b0; s_mem_new = 32'h0; s_mem_we_new = 1'b0; case (montprod_ctrl_reg) CTRL_INIT_S: begin s_mem_we_new = 1'b1; end CTRL_CALC_ADD: begin //s = (s + q*M + b*A) >>> 1;, if(b==1) S+= A. Takes (1..length) cycles. s_mem_we_new = b_reg | q_reg | first_iteration_reg; end CTRL_CALC_SDIV2: begin //s = (s + q*M + b*A) >>> 1; s>>=1. Takes (1..length) cycles. s_mem_we_new = 1'b1; end default: begin end endcase case (s_mux_reg) SMUX_ADD: begin if (first_iteration_reg) muxed_s_mem_read_data = 32'h0; else muxed_s_mem_read_data = s_mem_read_data; if (q_reg) sa_adder_data_in = add_result_sm; else sa_adder_data_in = muxed_s_mem_read_data; if (b_reg) s_mem_new = add_result_sa; else if (q_reg) s_mem_new = add_result_sm; else s_mem_new = muxed_s_mem_read_data; add_carry_in_sa_new = add_carry_out_sa; add_carry_in_sm_new = add_carry_out_sm; end SMUX_SHR: begin shr_data_in = s_mem_read_data; s_mem_new = shr_data_out; shr_carry_in_new = shr_carry_out; end default: begin end endcase end // s_logic //---------------------------------------------------------------- // bq // // Extract b and q bits. // b: current bit of B used. // q = (s - b * A) & 1 //---------------------------------------------------------------- always @* begin : bq b_new = opb_data[b_bit_index_reg]; q_new = s_mem_read_data[0] ^ (opa_data[0] & b_new); end // bq //---------------------------------------------------------------- // loop_ctr // Logic for updating the loop counter and // setting related B indices. //---------------------------------------------------------------- always @* begin : loop_ctr loop_ctr_new = 13'h0; loop_ctr_we = 1'b0; length_m1 = length - 1'b1; b_bit_index_new = 5'h1f - loop_ctr_reg[4:0]; b_word_index = loop_ctr_reg[12:5]; if (loop_ctr_set) begin loop_ctr_new = {length, 5'b00000} - 1'b1; loop_ctr_we = 1'b1; end if (loop_ctr_dec) begin loop_ctr_new = loop_ctr_reg - 1'b1; loop_ctr_we = 1'b1; end end //---------------------------------------------------------------- // montprod_ctrl // // Control FSM for the montgomery product calculator. //---------------------------------------------------------------- always @* begin : montprod_ctrl ready_new = 1'b0; ready_we = 1'b0; loop_ctr_set = 1'b0; loop_ctr_dec = 1'b0; b_bit_index_we = 1'b0; bq_we = 1'b0; s_mux_new = SMUX_0; reset_word_index_lsw = 1'b0; reset_word_index_msw = 1'b0; first_iteration_new = 1'b0; first_iteration_we = 1'b0; montprod_ctrl_new = CTRL_IDLE; montprod_ctrl_we = 1'b0; case (montprod_ctrl_reg) CTRL_IDLE: begin if (calculate) begin ready_new = 1'b0; ready_we = 1'b1; first_iteration_new = 1'b0; first_iteration_we = 1'b1; reset_word_index_lsw = 1'b1; montprod_ctrl_new = CTRL_INIT_S; montprod_ctrl_we = 1'b1; end end CTRL_INIT_S: begin s_mux_new = SMUX_0; // write 0 if (word_index_reg == 8'h0) begin montprod_ctrl_new = CTRL_WAIT; montprod_ctrl_we = 1'b1; end end CTRL_WAIT: begin loop_ctr_set = 1'b1; montprod_ctrl_new = CTRL_LOOP_ITER; montprod_ctrl_we = 1'b1; end //calculate q = (s - b * A) & 1;. // Also abort loop if done. CTRL_LOOP_ITER: begin b_bit_index_we = 1'b1; reset_word_index_lsw = 1'b1; montprod_ctrl_new = CTRL_LOOP_BQ; montprod_ctrl_we = 1'b1; end CTRL_LOOP_BQ: begin reset_word_index_lsw = 1'b1; bq_we = 1'b1; montprod_ctrl_new = CTRL_CALC_ADD; montprod_ctrl_we = 1'b1; end CTRL_CALC_ADD: begin s_mux_new = SMUX_ADD; if (word_index_reg == 8'h0) begin reset_word_index_lsw = 1'b1; first_iteration_new = 1'b0; first_iteration_we = 1'b1; montprod_ctrl_new = CTRL_STALLPIPE_ADD; montprod_ctrl_we = 1'b1; end end CTRL_STALLPIPE_ADD: begin montprod_ctrl_new = CTRL_CALC_SDIV2; montprod_ctrl_we = 1'b1; reset_word_index_msw = 1'b1; end CTRL_CALC_SDIV2: begin s_mux_new = SMUX_SHR; if (word_index_reg == length_m1) begin montprod_ctrl_new = CTRL_STALLPIPE_SDIV2; montprod_ctrl_we = 1'b1; end end CTRL_STALLPIPE_SDIV2: begin loop_ctr_dec = 1'b1; montprod_ctrl_new = CTRL_LOOP_ITER; montprod_ctrl_we = 1'b1; reset_word_index_lsw = 1'b1; if (loop_ctr_reg == 0) begin montprod_ctrl_new = CTRL_L_STALLPIPE_ES; montprod_ctrl_we = 1'b1; end end CTRL_L_STALLPIPE_ES: begin montprod_ctrl_new = CTRL_EMIT_S; montprod_ctrl_we = 1'b1; end CTRL_EMIT_S: begin if (word_index_prev_reg == 8'h0) begin ready_new = 1'b1; ready_we = 1'b1; montprod_ctrl_new = CTRL_IDLE; montprod_ctrl_we = 1'b1; end end default: begin end endcase // case (montprod_ctrl_reg) end // montprod_ctrl endmodule // montprod //====================================================================== // EOF montprod.v //======================================================================