aboutsummaryrefslogblamecommitdiff
path: root/rtl/modexpng_io_block.v
blob: 88b10086109cc0b12d60f8093be01211f1560d08 (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_io_block
(
    clk, rst_n, clk_bus,
        
    bus_cs,
    bus_we,
    bus_addr,
    bus_data_wr,
    bus_data_rd,
    
    in_1_en,
    in_1_addr,
    in_1_dout,
    
    in_2_en,
    in_2_addr,
    in_2_dout,
    
    out_en,
    out_we,
    out_addr,
    out_din
);

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


    //
    // Ports
    //
    input                                         clk;
    input                                         rst_n;

    input                                         clk_bus;

    input                                         bus_cs;
    input                                         bus_we;
    input  [2 + BANK_ADDR_W + BUS_OP_ADDR_W -1:0] bus_addr;
    input  [                  BUS_DATA_W    -1:0] bus_data_wr;
    output [                  BUS_DATA_W    -1:0] bus_data_rd;
    
    input                                         in_1_en;
    input  [    BANK_ADDR_W + OP_ADDR_W     -1:0] in_1_addr;
    output [                  WORD_W        -1:0] in_1_dout;
    
    input                                         in_2_en;
    input  [    BANK_ADDR_W + OP_ADDR_W     -1:0] in_2_addr;
    output [                  WORD_W        -1:0] in_2_dout;
    
    input                                         out_en;
    input                                         out_we;
    input  [    BANK_ADDR_W + OP_ADDR_W     -1:0] out_addr;
    input  [                  WORD_W        -1:0] out_din;

    
    //
    // Internal Registers
    //
    reg in_1_reg_en            = 1'b0;
    reg in_2_reg_en            = 1'b0;

    always @(posedge clk or negedge rst_n)
        //
        if (!rst_n) begin
            in_1_reg_en            <= 1'b0;
            in_2_reg_en            <= 1'b0;
        end else begin
            in_1_reg_en            <= in_1_en;
            in_2_reg_en            <= in_2_en;
        end


    //
    // INPUT, OUTPUT Storage Buffers
    //
    wire [                          2 -1:0] bus_addr_msb = bus_addr[BANK_ADDR_W + BUS_OP_ADDR_W +: 2];
    wire [BANK_ADDR_W + BUS_OP_ADDR_W -1:0] bus_addr_lsb = bus_addr[BANK_ADDR_W + BUS_OP_ADDR_W -1:0];
    reg  [                          2 -1:0] bus_addr_msb_dly;
    wire [              BUS_DATA_W    -1:0] bus_data_rd_input_1;
    wire [              BUS_DATA_W    -1:0] bus_data_rd_output;

    wire                                    bus_we_input_1 = bus_we && (bus_addr_msb == 2'd1);
    wire                                    bus_we_input_2 = bus_we && (bus_addr_msb == 2'd2);

    wire bus_cs_input_1 = bus_cs && (bus_addr_msb == 2'd1);
    wire bus_cs_input_2 = bus_cs && (bus_addr_msb == 2'd2);
    wire bus_cs_output  = bus_cs && (bus_addr_msb == 2'd3);

    /* INPUT_1 */
    `MODEXPNG_TDP_36K_X16_X32 bram_input_1
    (
        .clk        (clk),                  // core clock
        .clk_bus    (clk_bus),              // bus clock
    
        .ena        (bus_cs_input_1),       // bus side read-write
        .wea        (bus_we_input_1),  //
        .addra      (bus_addr_lsb),         //
        .dina       (bus_data_wr),          //
        .douta      (bus_data_rd_input_1),  //
    
        .enb        (in_1_en),              // core side read-only
        .regceb     (in_1_reg_en),          //
        .addrb      (in_1_addr),            //
        .doutb      (in_1_dout)             //
    );
    
    
    /* INPUT_2 */
    `MODEXPNG_SDP_36K_X16_X32 bram_input_2
    (
        .clk        (clk),                  // core clock
        .clk_bus    (clk_bus),              // bus clock
    
        .ena        (bus_cs_input_2),       // bus side write-only
        .wea        (bus_we_input_2),       //
        .addra      (bus_addr_lsb),         //
        .dina       (bus_data_wr),          //
    
        .enb        (in_2_en),              // core side read-only
        .regceb     (in_2_reg_en),          //
        .addrb      (in_2_addr),            //
        .doutb      (in_2_dout)             //
    );

    /* OUTPUT */
    `MODEXPNG_SDP_36K_X32_X16 bram_output
    (
        .clk        (clk),                  // core clock 
        .clk_bus    (clk_bus),              // bus clock
    
        .ena        (out_en),               // core side write-only
        .wea        (out_we),               //
        .addra      (out_addr),             //
        .dina       (out_din),              //
    
        .enb        (bus_cs_output),        // bus side read-only
        .addrb      (bus_addr_lsb),         //
        .doutb      (bus_data_rd_output)    //
    );

    reg [31: 0] bus_data_rd_mux;
    assign bus_data_rd = bus_data_rd_mux;

    always @(posedge clk_bus)
        bus_addr_msb_dly <= bus_addr_msb;

    always @(*)
        //
        case (bus_addr_msb_dly)
            //
            2'd0: bus_data_rd_mux = 32'hDEADC0DE;
            2'd1: bus_data_rd_mux = bus_data_rd_input_1;
            2'd2: bus_data_rd_mux = 32'hDEADC0DE;
            2'd3: bus_data_rd_mux = bus_data_rd_output;
            //
        endcase

endmodule