module modexpng_storage_block
(
clk, clk_bus, rst,
wr_wide_xy_ena,
wr_wide_xy_bank,
wr_wide_xy_addr,
wr_wide_x_din,
wr_wide_y_din,
wr_narrow_xy_ena,
wr_narrow_xy_bank,
wr_narrow_xy_addr,
wr_narrow_x_din,
wr_narrow_y_din,
rd_wide_xy_ena,
rd_wide_xy_ena_aux,
rd_wide_xy_bank,
rd_wide_xy_bank_aux,
rd_wide_xy_addr,
rd_wide_xy_addr_aux,
rd_wide_x_dout,
rd_wide_y_dout,
rd_wide_x_dout_aux,
rd_wide_y_dout_aux,
rd_narrow_xy_ena,
rd_narrow_xy_bank,
rd_narrow_xy_addr,
rd_narrow_x_dout,
rd_narrow_y_dout,
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"
//
// Ports
//
input clk;
input clk_bus;
input rst;
input wr_wide_xy_ena;
input [ BANK_ADDR_W -1:0] wr_wide_xy_bank;
input [ OP_ADDR_W -1:0] wr_wide_xy_addr;
input [ WORD_EXT_W -1:0] wr_wide_x_din;
input [ WORD_EXT_W -1:0] wr_wide_y_din;
input wr_narrow_xy_ena;
input [ BANK_ADDR_W -1:0] wr_narrow_xy_bank;
input [ OP_ADDR_W -1:0] wr_narrow_xy_addr;
input [ WORD_EXT_W -1:0] wr_narrow_x_din;
input [ WORD_EXT_W -1:0] wr_narrow_y_din;
input rd_wide_xy_ena;
input rd_wide_xy_ena_aux;
input [ BANK_ADDR_W -1:0] rd_wide_xy_bank;
input [ BANK_ADDR_W -1:0] rd_wide_xy_bank_aux;
input [ NUM_MULTS_HALF * OP_ADDR_W -1:0] rd_wide_xy_addr;
input [ OP_ADDR_W -1:0] rd_wide_xy_addr_aux;
output [ NUM_MULTS_HALF * WORD_EXT_W -1:0] rd_wide_x_dout;
output [ NUM_MULTS_HALF * WORD_EXT_W -1:0] rd_wide_y_dout;
output [ WORD_EXT_W -1:0] rd_wide_x_dout_aux;
output [ WORD_EXT_W -1:0] rd_wide_y_dout_aux;
input rd_narrow_xy_ena;
input [ BANK_ADDR_W -1:0] rd_narrow_xy_bank;
input [ OP_ADDR_W -1:0] rd_narrow_xy_addr;
output [ WORD_EXT_W -1:0] rd_narrow_x_dout;
output [ WORD_EXT_W -1:0] rd_narrow_y_dout;
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 rd_wide_xy_reg_ena = 1'b0;
reg rd_wide_xy_reg_ena_aux = 1'b0;
reg rd_narrow_xy_reg_ena = 1'b0;
reg in_1_reg_en = 1'b0;
reg in_2_reg_en = 1'b0;
always @(posedge clk)
//
if (rst) begin
rd_wide_xy_reg_ena <= 1'b0;
rd_wide_xy_reg_ena_aux <= 1'b0;
rd_narrow_xy_reg_ena <= 1'b0;
in_1_reg_en <= 1'b0;
in_2_reg_en <= 1'b0;
end else begin
rd_wide_xy_reg_ena <= rd_wide_xy_ena;
rd_wide_xy_reg_ena_aux <= rd_wide_xy_ena_aux;
rd_narrow_xy_reg_ena <= rd_narrow_xy_ena;
in_1_reg_en <= in_1_en;
in_2_reg_en <= in_2_en;
end
//
// Helper Signals
//
wire [BANK_ADDR_W + OP_ADDR_W -1:0] rd_wide_xy_offset[0:NUM_MULTS_HALF-1];
wire [BANK_ADDR_W + OP_ADDR_W -1:0] rd_wide_xy_offset_aux;
wire [BANK_ADDR_W + OP_ADDR_W -1:0] rd_narrow_xy_offset;
wire [BANK_ADDR_W + OP_ADDR_W -1:0] wr_wide_xy_offset;
wire [BANK_ADDR_W + OP_ADDR_W -1:0] wr_narrow_xy_offset;
assign rd_wide_xy_offset_aux = {rd_wide_xy_bank_aux, rd_wide_xy_addr_aux};
assign rd_narrow_xy_offset = {rd_narrow_xy_bank, rd_narrow_xy_addr};
assign wr_wide_xy_offset = {wr_wide_xy_bank, wr_wide_xy_addr};
assign wr_narrow_xy_offset = {wr_narrow_xy_bank, wr_narrow_xy_addr};
//
// "Wide" Storage
//
genvar z;
generate for (z=0; z<NUM_MULTS_HALF; z=z+1)
begin : gen_wide_bram
//
assign rd_wide_xy_offset[z] = {1'b0, rd_wide_xy_bank, rd_wide_xy_addr[z*OP_ADDR_W +: OP_ADDR_W]};
//
modexpng_sdp_36k_wrapper wide_bram_x
(
.clk (clk),
.ena (wr_wide_xy_ena),
.wea (wr_wide_xy_ena),
.addra (wr_wide_xy_offset),
.dina (wr_wide_x_din),
.enb (rd_wide_xy_ena),
.regceb (rd_wide_xy_reg_ena),
.addrb (rd_wide_xy_offset[z]),
.doutb (rd_wide_x_dout[z*WORD_EXT_W +: WORD_EXT_W])
);
//
modexpng_sdp_36k_wrapper wide_bram_y
(
.clk (clk),
.ena (wr_wide_xy_ena),
.wea (wr_wide_xy_ena),
.addra (wr_wide_xy_offset),
.dina (wr_wide_y_din),
.enb (rd_wide_xy_ena),
.regceb (rd_wide_xy_reg_ena),
.addrb (rd_wide_xy_offset[z]),
.doutb (rd_wide_y_dout[z*WORD_EXT_W +: WORD_EXT_W])
);
//
end
endgenerate
//
// Auxilary Storage
//
modexpng_sdp_36k_wrapper wide_bram_x_aux
(
.clk (clk),
.ena (wr_wide_xy_ena),
.wea (wr_wide_xy_ena),
.addra (wr_wide_xy_offset),
.dina (wr_wide_x_din),
.enb (rd_wide_xy_ena_aux),
.regceb (rd_wide_xy_reg_ena_aux),
.addrb (rd_wide_xy_offset_aux),
.doutb (rd_wide_x_dout_aux)
);
//
modexpng_sdp_36k_wrapper wide_bram_y_aux
(
.clk (clk),
.ena (wr_wide_xy_ena),
.wea (wr_wide_xy_ena),
.addra (wr_wide_xy_offset),
.dina (wr_wide_y_din),
.enb (rd_wide_xy_ena_aux),
.regceb (rd_wide_xy_reg_ena_aux),
.addrb (rd_wide_xy_offset_aux),
.doutb (rd_wide_y_dout_aux)
);
//
// "Narrow" Storage
//
modexpng_sdp_36k_wrapper narrow_bram_x
(
.clk (clk),
.ena (wr_narrow_xy_ena),
.wea (wr_narrow_xy_ena),
.addra (wr_narrow_xy_offset),
.dina (wr_narrow_x_din),
.enb (rd_narrow_xy_ena),
.regceb (rd_narrow_xy_reg_ena),
.addrb (rd_narrow_xy_offset),
.doutb (rd_narrow_x_dout)
);
modexpng_sdp_36k_wrapper narrow_bram_y
(
.clk (clk),
.ena (wr_narrow_xy_ena),
.wea (wr_narrow_xy_ena),
.addra (wr_narrow_xy_offset),
.dina (wr_narrow_y_din),
.enb (rd_narrow_xy_ena),
.regceb (rd_narrow_xy_reg_ena),
.addrb (rd_narrow_xy_offset),
.doutb (rd_narrow_y_dout)
);
//
// 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_data_wr_input_1 = bus_data_wr && (bus_addr_msb == 2'd0);
wire bus_data_wr_input_2 = bus_data_wr && (bus_addr_msb == 2'd1);
/* INPUT_1 */
modexpng_sdp_36k_x16_x32_wrapper bram_input_1
(
.clk (clk), // core clock
.clk_bus (clk_bus), // bus clock
.ena (bus_cs), // bus side read-write
.wea (bus_data_wr_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_wrapper bram_input_2
(
.clk (clk), // core clock
.clk_bus (clk_bus), // bus clock
.ena (bus_cs), // bus side write-only
.wea (bus_data_wr_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_wrapper 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), // 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 = bus_data_rd_input_1;
2'd1: bus_data_rd_mux = 32'hDEADC0DE;
2'd2: bus_data_rd_mux = bus_data_rd_output;
2'd3: bus_data_rd_mux = 32'hDEADC0DE;
//
endcase
endmodule