//====================================================================== // // 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 DEBUG = 0; 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_L_CALC_SM = 4'h5; localparam CTRL_L_STALLPIPE_SM = 4'h6; localparam CTRL_L_CALC_SA = 4'h7; localparam CTRL_L_STALLPIPE_SA = 4'h8; localparam CTRL_L_CALC_SDIV2 = 4'h9; localparam CTRL_L_STALLPIPE_D2 = 4'hA; localparam CTRL_L_STALLPIPE_ES = 4'hB; localparam CTRL_EMIT_S = 4'hC; localparam SMUX_0 = 2'h0; localparam SMUX_ADD_SM = 2'h1; localparam SMUX_ADD_SA = 2'h2; localparam SMUX_SHR = 2'h3; //---------------------------------------------------------------- // 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 update_bq; 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; //loop counter as a bit index reg [04 : 0] B_bit_index_reg; //loop counter as a bit index 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 reset_word_index_LSW; reg reset_word_index_MSW; //---------------------------------------------------------------- // 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; wire shr_carry_out; wire [31 : 0] shr_adiv2; reg set_B_bit_index; //---------------------------------------------------------------- // 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(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(s_mem_read_data), .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_adiv2), .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'b0; 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; montprod_ctrl_reg <= CTRL_IDLE; end else begin s_mem_wr_addr_reg <= s_mem_addr; s_mem_we_reg <= s_mem_we_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; B_bit_index_reg <= B_bit_index; if (update_bq) begin b_reg <= b_new; q_reg <= q_new; end s_mux_reg <= s_mux_new; 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 opb_addr_reg = B_word_index; opm_addr_reg = word_index_reg; result_addr_reg = word_index_prev_reg; result_data_reg = s_mem_read_data; case (montprod_ctrl_reg) CTRL_LOOP_ITER: //q = (s[length-1] ^ A[length-1]) & 1; opa_addr_reg = length_m1; default: opa_addr_reg = word_index_reg; endcase case (montprod_ctrl_reg) CTRL_LOOP_ITER: s_mem_addr = length_m1; default: s_mem_addr = word_index_reg; endcase case (montprod_ctrl_reg) CTRL_EMIT_S: tmp_result_we = 1'b1; default: tmp_result_we = 1'b0; endcase 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_L_CALC_SDIV2) word_index_new = word_index_reg + 1'b1; else word_index_new = word_index_reg - 1'b1; end // prodcalc //---------------------------------------------------------------- // s_select_write //---------------------------------------------------------------- always @* begin : s_select_write shr_carry_in_new = 1'b0; s_mux_new = SMUX_0; s_mem_we_new = 1'b0; case (montprod_ctrl_reg) CTRL_INIT_S: begin s_mux_new = SMUX_0; // write 0 s_mem_we_new = 1'b1; end CTRL_L_CALC_SM: begin //s = (s + q*M + b*A) >>> 1;, if(q==1) S+= M. Takes (1..length) cycles. s_mux_new = SMUX_ADD_SM; s_mem_we_new = q_reg; end CTRL_L_CALC_SA: begin //s = (s + q*M + b*A) >>> 1;, if(b==1) S+= A. Takes (1..length) cycles. s_mux_new = SMUX_ADD_SA; s_mem_we_new = b_reg; end CTRL_L_CALC_SDIV2: begin //s = (s + q*M + b*A) >>> 1; s>>=1. Takes (1..length) cycles. s_mux_new = SMUX_SHR; s_mem_we_new = 1'b1; end default: begin end endcase s_mem_new = 32'h0; add_carry_in_sa_new = 1'b0; add_carry_in_sm_new = 1'b0; case (s_mux_reg) SMUX_0: s_mem_new = 32'h0; SMUX_ADD_SM: begin s_mem_new = add_result_sm; add_carry_in_sm_new = add_carry_out_sm; end SMUX_ADD_SA: begin s_mem_new = add_result_sa; add_carry_in_sa_new = add_carry_out_sa; end SMUX_SHR: begin s_mem_new = shr_adiv2; shr_carry_in_new = shr_carry_out; end default: begin end endcase end // block: s_writer //---------------------------------------------------------------- // bq // b: bit of B // 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 = loop_ctr_reg; loop_ctr_we = 1'b0; length_m1 = length - 1'b1; B_bit_index = B_bit_index_reg; 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 if (set_B_bit_index) begin B_bit_index = 5'h1f - loop_ctr_reg[4:0]; end end //---------------------------------------------------------------- // montprod_ctrl // // Control FSM for the montgomery product calculator. //---------------------------------------------------------------- always @* begin : montprod_ctrl ready_new = 1'b0; ready_we = 1'b0; montprod_ctrl_new = CTRL_IDLE; montprod_ctrl_we = 1'b0; loop_ctr_set = 1'b0; loop_ctr_dec = 1'b0; set_B_bit_index = 1'b0; update_bq = 1'b0; reset_word_index_LSW = 1'b0; reset_word_index_MSW = 1'b0; case (montprod_ctrl_reg) CTRL_IDLE: begin if (calculate) begin ready_new = 1'b0; ready_we = 1'b1; montprod_ctrl_new = CTRL_INIT_S; montprod_ctrl_we = 1'b1; reset_word_index_LSW = 1'b1; end else begin ready_new = 1'b1; ready_we = 1'b1; end end CTRL_INIT_S: begin if (word_index_reg == 8'h0) begin loop_ctr_set = 1'b1; montprod_ctrl_new = CTRL_WAIT; montprod_ctrl_we = 1'b1; end end CTRL_WAIT: begin 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 set_B_bit_index = 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; update_bq = 1'b1; montprod_ctrl_new = CTRL_L_CALC_SM; montprod_ctrl_we = 1'b1; end CTRL_L_CALC_SM: begin if (word_index_reg == 8'h0) begin reset_word_index_LSW = 1'b1; montprod_ctrl_we = 1'b1; montprod_ctrl_new = CTRL_L_STALLPIPE_SM; end end CTRL_L_STALLPIPE_SM: begin montprod_ctrl_new = CTRL_L_CALC_SA; montprod_ctrl_we = 1'b1; reset_word_index_LSW = 1'b1; end CTRL_L_CALC_SA: begin if (word_index_reg == 8'h0) begin reset_word_index_LSW = 1'b1; montprod_ctrl_new = CTRL_L_STALLPIPE_SA; montprod_ctrl_we = 1'b1; end end CTRL_L_STALLPIPE_SA: begin montprod_ctrl_new = CTRL_L_CALC_SDIV2; montprod_ctrl_we = 1'b1; reset_word_index_MSW = 1'b1; end CTRL_L_CALC_SDIV2: begin if (word_index_reg == length_m1) begin montprod_ctrl_new = CTRL_L_STALLPIPE_D2; montprod_ctrl_we = 1'b1; end end CTRL_L_STALLPIPE_D2: 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 (DEBUG) $display("EMIT_S word_index_reg: %d", word_index_reg); 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 //======================================================================