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