aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/montprod.v
blob: 1b9346ff2d21b2bcbbdc13c577f04b0e2e3defce (plain) (tree)
































































                                                                           
                       
 














                                        




                                        



                                                                    

















                                 



                             
                                  

                                



                                        
 
                                
                                
                               
 



                                                             
                                                                    
                                                                    
                                                                                                        

                         



                                   
 

                                


































                                                                    



                                                 
                                       
                                                    




                                           

                                         
                                                    


                                                 

                     

                                         
                                                    


                                                 

                



                                            
                 
 
 










                                                                    



                                       


                                      






                                           


             

                                            
 

                                                
 


                                                     





                                         



                                   


                                                 



                                                      
           

                     



                                                                    
           





















                                                                    

                
 





                                                          
 
                     



                                                                                     


                                                                    

                                                              

                                                                    

                              


                                 
                                       
                                                



                                         



                                                         


                       

                                                         


                            



                                                       

                

               















                                                                    
                                        


                                   
                                     




                                 
                                      


             
                                             

                                         
 












                                                      
                                               
          
                                               


                   


                                                                    
           
                    
                                 
                                
                           
 
































                                                                                   

                                 


                      
                                                 

                    
                                                 

                 
                                           




                
                          




































                                                                    
                                       

















                                                    

                                                




                                        

                                                  



                       
                                       
                   


                                                           




                            

                                                  




                                        
                                       
                   


                                                           




                            

                                                     




                                        
                                            

                                                        
                                         




                            

                                                         
                                        

                                      

                                                        
                                         





                                            
                                     



                    
                       

                                                                     

























                                                                        
//======================================================================
//
// 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_LOOP_INIT      = 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 CTRL_DONE           = 4'hD;

  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; //q = (s - b * A) & 1
  reg           q_reg;
  reg           b; //b: bit of B
  reg           b_reg;

  reg [12 : 0] loop_counter_reg;
  reg [12 : 0] loop_counter_new;
  reg          loop_counter_we;

  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;


  //----------------------------------------------------------------
  // 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_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)
                    );

  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)
                    );

  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_counter_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;
          q_reg <= q;
          b_reg <= b;

          s_mux_reg <= s_mux_new;

          if (ready_we)
            ready_reg <= ready_new;

          if (loop_counter_we)
            loop_counter_reg <= loop_counter_new;

          if (montprod_ctrl_we)
            begin
               montprod_ctrl_reg <= montprod_ctrl_new;
             end
        end
    end // reg_update


  //----------------------------------------------------------------
  // s_mux
  //----------------------------------------------------------------
  always @*
    begin : s_mux
      case (s_mux_reg)
        SMUX_0:
          s_mem_new = 32'b0;
        SMUX_ADD_SA:
          s_mem_new = add_result_sa;
        SMUX_ADD_SM:
          s_mem_new = add_result_sm;
        SMUX_SHR:
          s_mem_new = shr_adiv2;
      endcase

      if (DEBUG)
        $display("S-MUX %x: %x", s_mux_reg, s_mem_new);
    end


  //----------------------------------------------------------------
  // bq
  //----------------------------------------------------------------
  always @*
   begin : bq
      b = b_reg;
      q = q_reg;

      if (montprod_ctrl_reg == CTRL_LOOP_BQ)
         begin
           b = opb_data[ B_bit_index_reg ];
           //opa_addr will point to length-1 to get A LSB.
           //s_read_addr will point to length-1
           q = s_mem_read_data[0] ^ (opa_data[0] & b);

           if (DEBUG)
             $display("s_mem_read_data: %x opa_data %x b %x q %x B_bit_index_reg %x",
                      s_mem_read_data, opa_data, b, q, B_bit_index_reg);
         end
   end // bq


  //----------------------------------------------------------------
  // loop_counter_logic
  // Logic for the loop counter and setting related B indices.
  //----------------------------------------------------------------
  always @*
    begin : loop_counter_logic

      loop_counter_new = 13'h000;
      loop_counter_we  = 1'b0;

      length_m1        = length - 1'b1;
      B_word_index     = loop_counter_reg[12:5];
      B_bit_index      = B_bit_index_reg;

      case (montprod_ctrl_reg)
        CTRL_LOOP_INIT:
          begin
            loop_counter_new = {length, 5'b00000} - 1'b1;
            loop_counter_we  = 1'b1;
          end

        CTRL_LOOP_ITER:
          begin
            B_word_index = loop_counter_reg[12:5];
            B_bit_index  = 5'h1f - loop_counter_reg[4:0];
          end

        CTRL_L_STALLPIPE_D2:
          begin
            loop_counter_new = loop_counter_reg - 1'b1;
            loop_counter_we  = 1'b1;
          end

        default:
          begin
          end
      endcase
    end


  //----------------------------------------------------------------
  // prodcalc
  //----------------------------------------------------------------
  always @*
    begin : prodcalc

      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

       opb_addr_reg = B_word_index;
       opm_addr_reg = word_index_reg;

      case (montprod_ctrl_reg)
        CTRL_LOOP_ITER:
          s_mem_addr = length_m1;
        default:
          s_mem_addr = word_index_reg;
      endcase


      result_addr_reg  = word_index_prev_reg;
      result_data_reg  = s_mem_read_data;


      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_writer
  //----------------------------------------------------------------
  always @*
    begin : s_writer
      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_mem_we_new = 1'b1;
            s_mux_new    = SMUX_0; // write 0
          end

        CTRL_L_CALC_SM:
          begin
            //s = (s + q*M + b*A) >>> 1;, if(q==1) S+= M. Takes (1..length) cycles.
            s_mem_we_new     = q_reg;
            s_mux_new        = SMUX_ADD_SM;
          end

        CTRL_L_CALC_SA:
          begin
            //s = (s + q*M + b*A) >>> 1;, if(b==1) S+= A. Takes (1..length) cycles.
            s_mem_we_new     = b_reg;
            s_mux_new        = SMUX_ADD_SA;
          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

      add_carry_in_sa_new = 1'b0;
      add_carry_in_sm_new = 1'b0;

      case (s_mux_reg)
        SMUX_ADD_SM:
          add_carry_in_sm_new = add_carry_out_sm;

        SMUX_ADD_SA:
          add_carry_in_sa_new = add_carry_out_sa;

        SMUX_SHR:
          shr_carry_in_new = shr_carry_out;

        default:
          begin
          end
      endcase
    end // block: s_writer


  //----------------------------------------------------------------
  // 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;

      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
                 montprod_ctrl_new = CTRL_LOOP_INIT;
                 montprod_ctrl_we = 1'b1;
              end
          end


        CTRL_LOOP_INIT:
          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
            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;
            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
            montprod_ctrl_new    = CTRL_LOOP_ITER; //loop
            montprod_ctrl_we     = 1'b1;
            reset_word_index_LSW = 1'b1;

            if (loop_counter_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
                 montprod_ctrl_new = CTRL_DONE;
                 montprod_ctrl_we  = 1'b1;
               end
           end

        CTRL_DONE:
          begin
            ready_new         = 1'b1;
            ready_we          = 1'b1;
            montprod_ctrl_new = CTRL_IDLE;
            montprod_ctrl_we  = 1'b1;
          end

        default:
          begin
          end

      endcase // case (montprod_ctrl_reg)
    end // montprod_ctrl

endmodule // montprod

//======================================================================
// EOF montprod.v
//======================================================================