blob: 4b1d2eeb26f9256a2f8e79abe54076de6590868d [file] [log] [blame]
// SPDX-FileCopyrightText:
// 2022 Nguyen Dao
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
module BlockRAM_1KB (clk, rd_addr, rd_data, wr_addr, wr_data, C0, C1, C2, C3, C4, C5);
parameter READ_ADDRESS_MSB_FROM_DATALSB = 24; //default 24 means bits wr_data[25:24] will become bits [9:8] of read address
parameter WRITE_ADDRESS_MSB_FROM_DATALSB = 16; //default 16 means bits wr_data[17:16] will become bits [9:8] of write address
parameter WRITE_ENABLE_FROM_DATA = 20; //default 20 means bit wr_data[20] will become the dynamic writeEnable input
input clk;
input [7:0] rd_addr;
output [31:0] rd_data;
input [7:0] wr_addr;
input [31:0] wr_data;
input C0;//naming of these doesnt really matter
input C1;// C0,C1 select write port width
input C2;// C2,C3 select read port width
input C3;
input C4;//C4 selects the alwaysWriteEnable
input C5; //C5 selects register bypass
// NOTE, the read enable is currently constantly ON
// NOTE, the R/W port on the standard cell is used only in write mode
// NOTE, enable ports on the primitive RAM are active lows
wire [1:0] rd_port_configuration;
wire [1:0] wr_port_configuration;
wire optional_register_enabled_configuration;
wire alwaysWriteEnable;
assign wr_port_configuration = {C0, C1};
assign rd_port_configuration = {C2, C3};
assign alwaysWriteEnable = C4;
assign optional_register_enabled_configuration = C5;
reg memWriteEnable;
always @ (*) begin // write enable
if(alwaysWriteEnable) begin
memWriteEnable = 0; // This RAM primitive is active low.
end else begin
memWriteEnable = (!(wr_data[WRITE_ENABLE_FROM_DATA])); // inverting the bit to make it active-high
end
end
reg [3:0] mem_wr_mask;
reg [31:0] muxedDataIn;
wire [1:0] wr_addr_topbits;
assign wr_addr_topbits = wr_data[WRITE_ADDRESS_MSB_FROM_DATALSB+1:WRITE_ADDRESS_MSB_FROM_DATALSB];
always @ (*) begin //write port config -> mask + write data multiplex
muxedDataIn = 32'dx;
if(wr_port_configuration == 0) begin
mem_wr_mask = 4'b1111;
muxedDataIn = wr_data;
end else if(wr_port_configuration == 1) begin
if(wr_addr_topbits == 0) begin
mem_wr_mask = 4'b0011;
muxedDataIn[15:0] = wr_data[15:0];
end else begin
mem_wr_mask = 4'b1100;
muxedDataIn[31:16] = wr_data[15:0];
end
end else if(wr_port_configuration == 2) begin
if(wr_addr_topbits == 0) begin
mem_wr_mask = 4'b0001;
muxedDataIn[7:0] = wr_data[7:0];
end else if(wr_addr_topbits == 1) begin
mem_wr_mask = 4'b0010;
muxedDataIn[15:8] = wr_data[7:0];
end else if(wr_addr_topbits == 2) begin
mem_wr_mask = 4'b0100;
muxedDataIn[23:16] = wr_data[7:0];
end else begin
mem_wr_mask = 4'b1000;
muxedDataIn[31:24] = wr_data[7:0];
end
end
end
wire [31:0] mem_dout;
sram_1rw1r_32_256_8_sky130 memory_cell( //dout0 is unused
.clk0(clk),.csb0(memWriteEnable),.web0(memWriteEnable),.wmask0(mem_wr_mask),.addr0(wr_addr[7:0]),.din0(muxedDataIn),//.dout0(),
.clk1(clk),.csb1(1'b0),.addr1(rd_addr[7:0]),.dout1(mem_dout)
);
reg [1:0] rd_dout_sel;
always @ (posedge clk) begin
rd_dout_sel <= wr_data[READ_ADDRESS_MSB_FROM_DATALSB+1:READ_ADDRESS_MSB_FROM_DATALSB];
end
reg [31:0] rd_dout_muxed;
always @ (*) begin
rd_dout_muxed[31:0] = mem_dout[31:0]; // a default value. Could be 32'dx if tools support it for logic saving!
if(rd_port_configuration == 0) begin
rd_dout_muxed[31:0] = mem_dout[31:0];
end else if(rd_port_configuration == 1) begin
if(rd_dout_sel[0] == 0) begin
rd_dout_muxed[15:0] = mem_dout[15:0];
end else begin
rd_dout_muxed[15:0] = mem_dout[31:16];
end
end else if(rd_port_configuration == 2) begin
if(rd_dout_sel == 0) begin
rd_dout_muxed[7:0] = mem_dout[7:0];
end else if(rd_dout_sel == 1) begin
rd_dout_muxed[7:0] = mem_dout[15:8];
end else if(rd_dout_sel == 2) begin
rd_dout_muxed[7:0] = mem_dout[23:16];
end else begin
rd_dout_muxed[7:0] = mem_dout[31:24];
end
end
end
reg [31:0] rd_dout_additional_register;
always @ (posedge clk) begin
rd_dout_additional_register <= rd_dout_muxed;
end
reg [31:0] final_dout;
assign rd_data = final_dout;
always @ (*) begin
if(optional_register_enabled_configuration) begin
final_dout = rd_dout_additional_register;
end else begin
final_dout = rd_dout_muxed;
end
end
endmodule
(* blackbox *)
module sram_1rw1r_32_256_8_sky130(
//`ifdef USE_POWER_PINS
// vdd,
// gnd,
//`endif
// Port 0: RW
clk0,csb0,web0,wmask0,addr0,din0,dout0,
// Port 1: R
clk1,csb1,addr1,dout1
);
parameter NUM_WMASKS = 4 ;
parameter DATA_WIDTH = 32 ;
parameter ADDR_WIDTH = 8 ;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;
// FIXME: This delay is arbitrary.
parameter DELAY = 3 ;
//`ifdef USE_POWER_PINS
// inout vdd;
// inout gnd;
//`endif
input clk0; // clock
input csb0; // active low chip select
input web0; // active low write control
input [NUM_WMASKS-1:0] wmask0; // write mask
input [ADDR_WIDTH-1:0] addr0;
input [DATA_WIDTH-1:0] din0;
output [DATA_WIDTH-1:0] dout0;
input clk1; // clock
input csb1; // active low chip select
input [ADDR_WIDTH-1:0] addr1;
output [DATA_WIDTH-1:0] dout1;
endmodule