aboutsummaryrefslogblamecommitdiff
path: root/rtl/modexpng_wrapper.v
blob: 687a9636595cba3bad7fc6282a9eb4fa9f6708fe (plain) (tree)








































































































































































































































































































































































































                                                                                                                                    
//======================================================================
//
// Copyright (c) 2019, 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 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
    `define MODEXPNG_DEFAULT_NAME1   32'h78706E67
    `define MODEXPNG_DEFAULT_VERSION 32'h302E3130

    `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 ZEROES_BIT_INDEX_W = 1 + cryptech_clog2(NUM_MULTS) + cryptech_clog2(WORD_W);
    
    
    //
    // Register Values
    //
    localparam CORE_NAME0   = `MODEXPNG_DEFAULT_NAME0;   // "mode"
    localparam CORE_NAME1   = `MODEXPNG_DEFAULT_NAME1;   // "xpng"
    localparam CORE_VERSION = `MODEXPNG_DEFAULT_VERSION; // "0.10"


    //
    // Registers
    //
    reg wrap_reg_control     = `MODEXPNG_DEFAULT_CONTROL;
    reg sync_reg_control     = `MODEXPNG_DEFAULT_CONTROL;
    reg sync_reg_control_dly = `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:ZEROES_BIT_INDEX_W] wrap_modulus_bits_msb;
    reg [BIT_INDEX_W:                 0] wrap_exponent_bits;

    initial write_modulus_bits(`MODEXPNG_DEFAULT_MODULUS_BITS);
    initial write_exponent_bits(`MODEXPNG_DEFAULT_EXPONENT_BITS);

    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;
    wire core_reg_status;
    
    always @(posedge clk or negedge rst_n)
        //
        if (!rst_n) {wrap_reg_status, sync_reg_status} <= {           1'b1,            1'b1};
        else        {wrap_reg_status, sync_reg_status} <= {sync_reg_status, 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];
    

    //
    // 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 (sync_reg_control_rising) 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
    
    
    //
    // Trigger Logic
    //    
    always @(posedge clk_core or negedge rst_n)
        //
        if (!rst_n) {sync_reg_control_dly, sync_reg_control} <= {`MODEXPNG_DEFAULT_CONTROL, `MODEXPNG_DEFAULT_CONTROL};
        else        {sync_reg_control_dly, sync_reg_control} <= {         sync_reg_control,          wrap_reg_control};

    always @(posedge clk_core or negedge rst_n)
        //
        if (!rst_n) core_reg_control <= `MODEXPNG_DEFAULT_CONTROL;
        else        core_reg_control <= sync_reg_control_rising;     
    
    
    //
    // 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
    //
    always @(posedge clk or negedge rst_n)
        //
        if (!rst_n) begin
            //
            wrap_reg_control   <= `MODEXPNG_DEFAULT_CONTROL;
            wrap_reg_mode      <= `MODEXPNG_DEFAULT_MODE;
            //
            write_modulus_bits(`MODEXPNG_DEFAULT_MODULUS_BITS);
            write_exponent_bits(`MODEXPNG_DEFAULT_EXPONENT_BITS);
            //
        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:  write_modulus_bits(write_data[BIT_INDEX_W:0]);
                ADDR_EXPONENT_BITS: write_exponent_bits(write_data[BIT_INDEX_W:0]);
            endcase


    //
    // Update modulus width
    // 
    function [BIT_INDEX_W:ZEROES_BIT_INDEX_W] fix_modulus_bits;
       input [BIT_INDEX_W:                 0] width;
            if      (width < MIN_OP_W) fix_modulus_bits = MIN_OP_W[BIT_INDEX_W:ZEROES_BIT_INDEX_W];
            else if (width > MAX_OP_W) fix_modulus_bits = MAX_OP_W[BIT_INDEX_W:ZEROES_BIT_INDEX_W];
            else                       fix_modulus_bits = width   [BIT_INDEX_W:ZEROES_BIT_INDEX_W];
    endfunction
    
    function [OP_ADDR_W-1:                 0] calc_modulus_num_words_n;
       input [BIT_INDEX_W:ZEROES_BIT_INDEX_W] width;
       calc_modulus_num_words_n = {width, {(ZEROES_BIT_INDEX_W-WORD_MUX_W){1'b0}}} - 1'b1; // truncates msb
    endfunction
    
    function [OP_ADDR_W-1:                 0] calc_modulus_num_words_pq;
       input [BIT_INDEX_W:ZEROES_BIT_INDEX_W] width;
       calc_modulus_num_words_pq = {width, {(ZEROES_BIT_INDEX_W-WORD_MUX_W-1){1'b0}}} - 1'b1; // fits exactly
    endfunction
   
    task write_modulus_bits;
        input [BIT_INDEX_W:0] width;
        begin
            wrap_modulus_bits_msb   <= fix_modulus_bits(width);
            wrap_word_index_last_n  <= calc_modulus_num_words_n(fix_modulus_bits(width));
            wrap_word_index_last_pq <= calc_modulus_num_words_pq(fix_modulus_bits(width));
        end
    endtask
    
    
    //
    // Update exponent width 
    //
    function [BIT_INDEX_W:0] fix_exponent_bits;
       input [BIT_INDEX_W:0] width;
            if      (width < MIN_EXP_W) fix_exponent_bits = MIN_EXP_W;
            else if (width > MAX_OP_W ) fix_exponent_bits = MAX_OP_W;
            else                        fix_exponent_bits = width;
    endfunction
    
    function [BIT_INDEX_W-1:0] calc_exponent_num_bits_n;
       input [BIT_INDEX_W  :0] width;
       calc_exponent_num_bits_n = width - 1'b1;  // truncates msb
    endfunction
    
    function [BIT_INDEX_W-1:0] calc_exponent_num_bits_pq;
       input [BIT_INDEX_W:  0] width;
       calc_exponent_num_bits_pq = width[BIT_INDEX_W:1] - 1'b1; // fits exactly
    endfunction
   
    task write_exponent_bits;
        input [BIT_INDEX_W:0] width;
        begin
            wrap_exponent_bits     <= fix_exponent_bits(width);
            wrap_bit_index_last_n  <= calc_exponent_num_bits_n(fix_exponent_bits(width));
            wrap_bit_index_last_pq <= calc_exponent_num_bits_pq(fix_exponent_bits(width));
        end
    endtask
    
    
    //
    // 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, {ZEROES_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