aboutsummaryrefslogblamecommitdiff
path: root/rtl/modexpng_wrapper.v
blob: d6fe62d3794ec3c236c8ff17e54e20f2621ea4a7 (plain) (tree)
1
2
3
4

                                                                        

                                                            










                                                                         


                                                                         















































































                                                                                

                                                             
                                                             












                                                     

                                                                                        




                      


                                                        




                


                                                     


                      

                                                            
 



                                                                              




            


                                    

                         




















                                                                   

















































                                                                                                       
    
















                                                                                                                               
 
    


































                                                           
                                                                            










                                                               































                                                      
























































                                                                                                                                                        






                                                            

                                         





                                                                                     

                                                              



                   
                                        
       
                                                   
                                    



                                                                       


      
                                          
      
                                                   
                                   


                                                                          
               
  

















                                                                                           
                                                                                                                                 






















                                                                                                     
//======================================================================
//
// Copyright: 2019, The Commons Conservancy Cryptech Project
// SPDX-License-Identifier: BSD-3-Clause
//
// 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 copyright holder 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 modexpng_wrapper
(
    input           clk,
    input           rst_n,
    
    input           clk_core,

    input           cs,
    input           we,

    input   [11:0]  address,
    input   [31:0]  write_data,
    output  [31:0]  read_data
);

    //
    // Headers
    //
    `include "modexpng_parameters.vh"


    //
    // Address Decoder
    //
    localparam ADDR_MSB_WRAP = 2'b00;

    wire [1:0] addr_msb = address[11:10];
    wire [9:0] addr_lsb = address[ 9: 0];
    
    wire addr_msb_is_wrap = addr_msb == ADDR_MSB_WRAP;


    //
    // Register Addresses
    //
    localparam ADDR_NAME0         = 10'h000;
    localparam ADDR_NAME1         = 10'h001;
    localparam ADDR_VERSION       = 10'h002;

    localparam ADDR_CONTROL       = 10'h008; // {next, init}
    localparam ADDR_STATUS        = 10'h009; // {valid, ready}
    localparam ADDR_MODE          = 10'h010; // {crt, dummy}
    localparam ADDR_MODULUS_BITS  = 10'h011; // number of bits in modulus
    localparam ADDR_EXPONENT_BITS = 10'h012; // number of bits in exponent
    localparam ADDR_BANK_BITS     = 10'h013; // largest supported number of bits
    localparam ADDR_NUM_MULTS     = 10'h014; // number of parallel multipliers


    //
    // Register Bits
    //
    
    // localparam CONTROL_INIT_BIT    = 0; -- not used
    localparam CONTROL_NEXT_BIT       = 1;

    // localparam STATUS_READY_BIT    = 0; -- hardcoded to always read 1
    localparam STATUS_VALID_BIT       = 1;

    // localparam MODE_FASTUNSAFE_BIT = 0; - not used
    localparam MODE_FULLCRT_BIT       = 1;

    
    //
    // Default Values
    //
    `define MODEXPNG_DEFAULT_NAME0   32'h6D6F6465   // "mode"
    `define MODEXPNG_DEFAULT_NAME1   32'h78706E67   // "xpng"
    `define MODEXPNG_DEFAULT_VERSION 32'h302E3231   // "0.21"

    `define MODEXPNG_DEFAULT_CONTROL 1'b0
    `define MODEXPNG_DEFAULT_MODE    1'b0

    `define MODEXPNG_DEFAULT_MODULUS_BITS  13'd1024
    `define MODEXPNG_DEFAULT_EXPONENT_BITS 13'd17
    
    
    //
    // Handy Values
    //
    localparam MIN_OP_W = 2 * NUM_MULTS * WORD_W * 2;
    localparam MIN_EXP_W = 2 * 2;
    localparam LSB_BIT_INDEX_W = 1 + cryptech_clog2(NUM_MULTS) + cryptech_clog2(WORD_W);
    localparam MSB_BIT_INDEX_W = BIT_INDEX_W - LSB_BIT_INDEX_W;
    
    
    //
    // Register Values
    //
    localparam CORE_NAME0   = `MODEXPNG_DEFAULT_NAME0;
    localparam CORE_NAME1   = `MODEXPNG_DEFAULT_NAME1;
    localparam CORE_VERSION = `MODEXPNG_DEFAULT_VERSION;


    //
    // Registers
    //
    reg wrap_reg_control = `MODEXPNG_DEFAULT_CONTROL;
    reg core_reg_control = `MODEXPNG_DEFAULT_CONTROL;
    reg wrap_reg_mode    = `MODEXPNG_DEFAULT_MODE;
    reg sync_reg_mode;
    reg core_reg_mode;
        
    reg [BIT_INDEX_W:LSB_BIT_INDEX_W] wrap_modulus_bits_msb;
    reg [BIT_INDEX_W:              0] wrap_exponent_bits;

    initial update_modulus_bits_user;
    initial update_exponent_bits_user;
    
    //wire sync_reg_control_rising = sync_reg_control & ~sync_reg_control_dly;


    //
    // Wires
    //
    reg  wrap_reg_status     = 1'b1;
    reg  sync_reg_status     = 1'b1;
    reg  sync_reg_status_dly = 1'b1;
    wire core_reg_status;
    

    //
    // Output Mux
    //
    reg  [31: 0] wrap_read_data;
    wire [31: 0] core_read_data;
    
    
    //
    // Reset Resync
    //
    wire core_rst_n;
    
    reg [15: 0] core_rst_shreg = {16{1'b0}};

    always @(posedge clk_core or negedge rst_n)
        //
        if (!rst_n) core_rst_shreg <= {16{1'b0}};
        else        core_rst_shreg <= {core_rst_shreg[14:0], 1'b1};

    assign core_rst_n = core_rst_shreg[15];
     
    
    //
    // Trigger Logic
    //
    reg wrap_reg_control_dly     = `MODEXPNG_DEFAULT_CONTROL;
    reg wrap_reg_control_posedge = 1'b0;
    reg sync_reg_control_posedge = 1'b0;
    reg core_reg_control_posedge = 1'b0;
    reg core_reg_control_posedge_dly = 1'b0;
    reg sync_reg_control_posedge_ack = 1'b0;
    reg wrap_reg_control_posedge_ack = 1'b0;
    
    always @(posedge clk or negedge rst_n)
        if (!rst_n) wrap_reg_control_dly <= `MODEXPNG_DEFAULT_CONTROL;
        else        wrap_reg_control_dly <= wrap_reg_control;
        
    always @(posedge clk or negedge rst_n)
        if (!rst_n) wrap_reg_control_posedge <= 1'b0;
        else begin
            if (!wrap_reg_control_posedge) begin
                if (wrap_reg_control && !wrap_reg_control_dly) wrap_reg_control_posedge <= 1'b1;
            end else begin
                if (wrap_reg_control_posedge_ack) wrap_reg_control_posedge <= 1'b0;
            end
        end
    
    always @(posedge clk_core or negedge core_rst_n)
        if (!core_rst_n) sync_reg_control_posedge <= 1'b0;
        else             sync_reg_control_posedge <= wrap_reg_control_posedge;
    
    always @(posedge clk_core or negedge core_rst_n)
        if (!core_rst_n) core_reg_control_posedge <= 1'b0;
        else             core_reg_control_posedge <= sync_reg_control_posedge;
        
    always @(posedge clk_core or negedge core_rst_n)
        if (!core_rst_n) core_reg_control_posedge_dly <= 1'b0;
        else             core_reg_control_posedge_dly <= core_reg_control_posedge;
    
    always @(posedge clk or negedge rst_n)
        if (!rst_n) sync_reg_control_posedge_ack <= 1'b0;
        else        sync_reg_control_posedge_ack <= core_reg_control_posedge;
        
    always @(posedge clk or negedge rst_n)
        if (!rst_n) wrap_reg_control_posedge_ack <= 1'b0;
        else        wrap_reg_control_posedge_ack <= sync_reg_control_posedge_ack;

    always @(posedge clk_core or negedge core_rst_n)
        if (!core_rst_n) core_reg_control <= `MODEXPNG_DEFAULT_CONTROL;
        else             core_reg_control <= core_reg_control_posedge && !core_reg_control_posedge_dly;
    
    always @(posedge clk or negedge rst_n)
        if (!rst_n) sync_reg_status <= 1'b1;
        else        sync_reg_status <= core_reg_status;
        
    always @(posedge clk or negedge rst_n)
        if (!rst_n) sync_reg_status_dly <= 1'b1;
        else        sync_reg_status_dly <= sync_reg_status;
        
    always @(posedge clk or negedge rst_n)
        if (!rst_n) wrap_reg_status <= 1'b1;
        else begin
            if (wrap_reg_status) begin
                if (wrap_reg_control && !wrap_reg_control_dly) wrap_reg_status <= 1'b0;
            end else begin
                if (!wrap_reg_control_posedge && !wrap_reg_control_posedge_ack && sync_reg_status_dly) wrap_reg_status <= 1'b1;
            end
        end

    
    //
    // Parameters Resync
    //
    reg [OP_ADDR_W   -1:0] wrap_word_index_last_n;
    reg [OP_ADDR_W   -1:0] wrap_word_index_last_pq;

    reg [BIT_INDEX_W -1:0] wrap_bit_index_last_n;
    reg [BIT_INDEX_W -1:0] wrap_bit_index_last_pq;
    
    reg [OP_ADDR_W   -1:0] sync_word_index_last_n;
    reg [OP_ADDR_W   -1:0] sync_word_index_last_pq;

    reg [BIT_INDEX_W -1:0] sync_bit_index_last_n;
    reg [BIT_INDEX_W -1:0] sync_bit_index_last_pq;
    
    reg [OP_ADDR_W   -1:0] core_word_index_last_n;
    reg [OP_ADDR_W   -1:0] core_word_index_last_pq;

    reg [BIT_INDEX_W -1:0] core_bit_index_last_n;
    reg [BIT_INDEX_W -1:0] core_bit_index_last_pq;
    
    always @(posedge clk_core) begin
        //
        sync_reg_mode <= wrap_reg_mode;
        //
        sync_word_index_last_n  <= wrap_word_index_last_n;
        sync_word_index_last_pq <= wrap_word_index_last_pq;
        //
        sync_bit_index_last_n  <= wrap_bit_index_last_n;
        sync_bit_index_last_pq <= wrap_bit_index_last_pq;
        //
    end
    
    always @(posedge clk_core)
        //
        if (core_reg_control_posedge && !core_reg_control_posedge_dly) begin
            //
            core_reg_mode <= sync_reg_mode;
            //
            core_word_index_last_n  <= sync_word_index_last_n;
            core_word_index_last_pq <= sync_word_index_last_pq;
            //
            core_bit_index_last_n  <= sync_bit_index_last_n;
            core_bit_index_last_pq <= sync_bit_index_last_pq;
            //
        end
    
    //
    // ModExpNG
    //
    modexpng_core_top modexpng
    (
        .clk                (clk_core),
        .clk_bus            (clk),
        
        .rst_n              (core_rst_n),
        
        .next               (core_reg_control),
        .valid              (core_reg_status),
        
        .crt_mode           (core_reg_mode),
        
        .word_index_last_n  (core_word_index_last_n),
        .word_index_last_pq (core_word_index_last_pq),
        
        .bit_index_last_n   (core_bit_index_last_n),
        .bit_index_last_pq  (core_bit_index_last_pq),
        
        .bus_cs             (cs),
        .bus_we             (we),
        .bus_addr           (address),
        .bus_data_wr        (write_data),
        .bus_data_rd        (core_read_data)
    );


    //
    // Write Interface
    //
    
    wire [    BIT_INDEX_W  :0] corrected_modulus_bits_user     = correct_modulus_bits(write_data[BIT_INDEX_W:0]);
    wire [MSB_BIT_INDEX_W  :0] corrected_modulus_bits_msb_user = corrected_modulus_bits_user[BIT_INDEX_W:LSB_BIT_INDEX_W];
    wire [      OP_ADDR_W  :0] modulus_num_words_n_user        = {corrected_modulus_bits_msb_user, {(LSB_BIT_INDEX_W-WORD_MUX_W){1'b0}}} - 1'b1;
    wire [      OP_ADDR_W-1:0] modulus_num_words_n_lsb_user    = modulus_num_words_n_user[OP_ADDR_W-1:0];
    wire [      OP_ADDR_W-1:0] modulus_num_words_pq_user       = {corrected_modulus_bits_msb_user, {(LSB_BIT_INDEX_W-WORD_MUX_W-1){1'b0}}} - 1'b1;

    wire [    BIT_INDEX_W  :0] corrected_modulus_bits_default     = `MODEXPNG_DEFAULT_MODULUS_BITS;
    wire [MSB_BIT_INDEX_W  :0] corrected_modulus_bits_msb_default = corrected_modulus_bits_default[BIT_INDEX_W:LSB_BIT_INDEX_W];
    wire [      OP_ADDR_W  :0] modulus_num_words_n_default        = {corrected_modulus_bits_msb_default, {(LSB_BIT_INDEX_W-WORD_MUX_W){1'b0}}} - 1'b1;
    wire [      OP_ADDR_W-1:0] modulus_num_words_n_lsb_default    = modulus_num_words_n_default[OP_ADDR_W-1:0];
    wire [      OP_ADDR_W-1:0] modulus_num_words_pq_default       = {corrected_modulus_bits_msb_default, {(LSB_BIT_INDEX_W-WORD_MUX_W-1){1'b0}}} - 1'b1;
    
    wire [    BIT_INDEX_W  :0] corrected_exponent_bits_user     = correct_exponent_bits(write_data[BIT_INDEX_W:0]);
    wire [    BIT_INDEX_W-1:0] corrected_exponent_bits_msb_user = corrected_exponent_bits_user[BIT_INDEX_W:1];
    wire [    BIT_INDEX_W  :0] exponent_num_bits_n_user         = corrected_exponent_bits_user - 1'b1;
    wire [    BIT_INDEX_W-1:0] exponent_num_bits_n_lsb_user     = exponent_num_bits_n_user[BIT_INDEX_W-1:0];
    wire [    BIT_INDEX_W-1:0] exponent_num_bits_pq_user        = corrected_exponent_bits_msb_user - 1'b1;
    
    wire [    BIT_INDEX_W  :0] corrected_exponent_bits_default     = `MODEXPNG_DEFAULT_EXPONENT_BITS;
    wire [    BIT_INDEX_W-1:0] corrected_exponent_bits_msb_default = corrected_exponent_bits_default[BIT_INDEX_W:1];
    wire [    BIT_INDEX_W  :0] exponent_num_bits_n_default         = corrected_exponent_bits_default - 1'b1;
    wire [    BIT_INDEX_W-1:0] exponent_num_bits_n_lsb_default     = exponent_num_bits_n_default[BIT_INDEX_W-1:0];
    wire [    BIT_INDEX_W-1:0] exponent_num_bits_pq_default        = corrected_exponent_bits_msb_default - 1'b1;
    
    task update_modulus_bits_user;
        begin
            wrap_modulus_bits_msb   <= corrected_modulus_bits_msb_user;
            wrap_word_index_last_n  <= modulus_num_words_n_lsb_user;
            wrap_word_index_last_pq <= modulus_num_words_pq_user;
        end
    endtask
    
    task update_modulus_bits_default;
        begin
            wrap_modulus_bits_msb   <= corrected_modulus_bits_msb_default;
            wrap_word_index_last_n  <= modulus_num_words_n_lsb_default;
            wrap_word_index_last_pq <= modulus_num_words_pq_default;
        end
    endtask
    
    task update_exponent_bits_user;
        begin
            wrap_exponent_bits     <= corrected_exponent_bits_user;
            wrap_bit_index_last_n  <= exponent_num_bits_n_lsb_user;
            wrap_bit_index_last_pq <= exponent_num_bits_pq_user;
        end
    endtask
    
    task update_exponent_bits_default;
        begin
            wrap_exponent_bits     <= corrected_exponent_bits_default;
            wrap_bit_index_last_n  <= exponent_num_bits_n_lsb_default;
            wrap_bit_index_last_pq <= exponent_num_bits_pq_default;
        end
    endtask
    
    always @(posedge clk or negedge rst_n)
        //
        if (!rst_n) begin
            //
            wrap_reg_control   <= `MODEXPNG_DEFAULT_CONTROL;
            wrap_reg_mode      <= `MODEXPNG_DEFAULT_MODE;
            //
            update_modulus_bits_default;
            update_exponent_bits_default;
            //
        end else if (cs && we && addr_msb_is_wrap)
            //
            case (addr_lsb)
                ADDR_CONTROL:       wrap_reg_control <= write_data[CONTROL_NEXT_BIT];
                ADDR_MODE:          wrap_reg_mode    <= write_data[MODE_FULLCRT_BIT];
                ADDR_MODULUS_BITS:  update_modulus_bits_user;
                ADDR_EXPONENT_BITS: update_exponent_bits_user;
            endcase


    //
    // Only accept correct modulus width
    // 
    function  [BIT_INDEX_W:0] correct_modulus_bits;
        input [BIT_INDEX_W:0] width;
            if      (width < MIN_OP_W) correct_modulus_bits = MIN_OP_W;
            else if (width > MAX_OP_W) correct_modulus_bits = MAX_OP_W;
            else                       correct_modulus_bits = width;
    endfunction
    
    
    //
    // Only accept correct exponent width 
    //
    function [BIT_INDEX_W:0] correct_exponent_bits;
       input [BIT_INDEX_W:0] width;
            if      (width < MIN_EXP_W) correct_exponent_bits = MIN_EXP_W;
            else if (width > MAX_OP_W ) correct_exponent_bits = MAX_OP_W;
            else                        correct_exponent_bits = width;
    endfunction
  
    
    
    //
    // Read Interface
    //
    always @(posedge clk)
        //
        if (cs && addr_msb_is_wrap)
            //
            case (address)
                //
                ADDR_NAME0:         wrap_read_data <= CORE_NAME0;
                ADDR_NAME1:         wrap_read_data <= CORE_NAME1;
                ADDR_VERSION:       wrap_read_data <= CORE_VERSION;
                ADDR_CONTROL:       wrap_read_data <= {{30{1'b0}}, wrap_reg_control, 1'b0};
                ADDR_STATUS:        wrap_read_data <= {{30{1'b0}}, wrap_reg_status,  1'b1};
                //
                ADDR_MODE:          wrap_read_data <= {{30{1'b0}}, wrap_reg_mode, 1'b0};
                ADDR_MODULUS_BITS:  wrap_read_data <= {{(31-BIT_INDEX_W){1'b0}}, wrap_modulus_bits_msb, {LSB_BIT_INDEX_W{1'b0}}};
                ADDR_EXPONENT_BITS: wrap_read_data <= {{(31-BIT_INDEX_W){1'b0}}, wrap_exponent_bits};
                ADDR_BANK_BITS:     wrap_read_data <= MAX_OP_W;
                ADDR_NUM_MULTS:     wrap_read_data <= NUM_MULTS;
                //
                default:            wrap_read_data <= 32'h00000000;
                //
            endcase


    //
    // Register / Core Memory Selector
    //
    reg [1:0] addr_msb_last;
    
    wire addr_msb_last_is_wrap = addr_msb_last == ADDR_MSB_WRAP;
    
    always @(posedge clk)   
        addr_msb_last <= addr_msb;

    assign read_data = addr_msb_last_is_wrap ? wrap_read_data : core_read_data;


endmodule