diff --git a/lambdalib/ramlib/__init__.py b/lambdalib/ramlib/__init__.py index 8e27dec..80e5dfe 100644 --- a/lambdalib/ramlib/__init__.py +++ b/lambdalib/ramlib/__init__.py @@ -4,11 +4,13 @@ from .la_syncfifo.la_syncfifo import Syncfifo from .la_dpram.la_dpram import Dpram from .la_spram.la_spram import Spram +from .la_tdpram.la_tdpram import Tdpram __all__ = ['Asyncfifo', 'Syncfifo', 'Dpram', - 'Spram'] + 'Spram', + 'Tdpram'] class RAMLib(Design): @@ -20,3 +22,4 @@ def __init__(self): self.add_depfileset(Syncfifo(), depfileset="rtl") self.add_depfileset(Dpram(), depfileset="rtl") self.add_depfileset(Spram(), depfileset="rtl") + self.add_depfileset(Tdpram(), depfileset="rtl") diff --git a/lambdalib/ramlib/la_tdpram/la_tdpram.py b/lambdalib/ramlib/la_tdpram/la_tdpram.py new file mode 100644 index 0000000..d58e2d7 --- /dev/null +++ b/lambdalib/ramlib/la_tdpram/la_tdpram.py @@ -0,0 +1,12 @@ +from lambdalib.lambdalib import Lambda + + +class Tdpram(Lambda): + def __init__(self): + name = 'la_tdpram' + super().__init__(name, __file__, extrasources=['rtl/la_tdpram_impl.v']) + + +if __name__ == "__main__": + d = Tdpram() + d.write_fileset(f"{d.name}.f", fileset="rtl") diff --git a/lambdalib/ramlib/la_tdpram/rtl/la_tdpram.v b/lambdalib/ramlib/la_tdpram/rtl/la_tdpram.v new file mode 100644 index 0000000..64fc405 --- /dev/null +++ b/lambdalib/ramlib/la_tdpram/rtl/la_tdpram.v @@ -0,0 +1,85 @@ +/***************************************************************************** + * Function: + * Copyright: Lambda Project Authors. All rights Reserved. + * License: MIT (see LICENSE file in Lambda repository) + * + * Docs: + * + * This is a wrapper for selecting from a set of hardened memory macros. + * + * A synthesizable reference model is used when the PROP is DEFAULT. The + * synthesizable model does not implement the cfg and test interface and should + * only be used for basic testing and for synthesizing for FPGA devices. + * Advanced ASIC development should rely on complete functional models + * supplied on a per macro basis. + * + * Technology specific implementations of "la_tdpram" would generally include + * one or more hardcoded instantiations of RAM modules with a generate + * statement relying on the "PROP" to select between the list of modules + * at build time. + * + ****************************************************************************/ + +module la_tdpram #( + parameter DW = 32, // Memory width + parameter AW = 10, // address width (derived) + parameter PROP = "DEFAULT", // pass through variable for hard macro + parameter CTRLW = 128, // width of asic ctrl interface + parameter TESTW = 128 // width of asic test interface +) ( // A port + input clk_a, // write clock + input ce_a, // write chip-enable + input we_a, // write enable + input [DW-1:0] wmask_a, // write mask + input [AW-1:0] addr_a, // write address + input [DW-1:0] din_a, // write data in + output [DW-1:0] dout_a, // read data out + // B port + input clk_b, // write clock + input ce_b, // write chip-enable + input we_b, // write enable + input [DW-1:0] wmask_b, // write mask + input [AW-1:0] addr_b, // write address + input [DW-1:0] din_b, // write data in + output [DW-1:0] dout_b, // read data out + // Power signal + input vss, // ground signal + input vdd, // memory core array power + input vddio, // periphery/io power + // Generic interfaces + input [CTRLW-1:0] ctrl, // pass through ASIC control interface + input [TESTW-1:0] test // pass through ASIC test interface +); + + la_tdpram_impl #( + .DW (DW), + .AW (AW), + .PROP (PROP), + .CTRLW (CTRLW), + .TESTW (TESTW) + ) memory ( + .clk_a (clk_a), + .ce_a (ce_a), + .we_a (we_a), + .wmask_a (wmask_a), + .addr_a (addr_a), + .din_a (din_a), + .dout_a (dout_a), + + .clk_b (clk_b), + .ce_b (ce_b), + .we_b (we_b), + .wmask_b (wmask_b), + .addr_b (addr_b), + .din_b (din_b), + .dout_b (dout_b), + + .vss (vss), + .vdd (vdd), + .vddio (vddio), + + .ctrl (ctrl), + .test (test) + ); + +endmodule diff --git a/lambdalib/ramlib/la_tdpram/rtl/la_tdpram_impl.v b/lambdalib/ramlib/la_tdpram/rtl/la_tdpram_impl.v new file mode 100644 index 0000000..4a34550 --- /dev/null +++ b/lambdalib/ramlib/la_tdpram/rtl/la_tdpram_impl.v @@ -0,0 +1,93 @@ +/***************************************************************************** + * Function: True Dual Port RAM (Two write + read ports) + * Copyright: Lambda Project Authors. All rights Reserved. + * License: MIT (see LICENSE file in Lambda repository) + * + * Docs: + * + * This is a wrapper for selecting from a set of hardened memory macros. + * + * A synthesizable reference model is used when the PROP is DEFAULT. The + * synthesizable model does not implement the cfg and test interface and should + * only be used for basic testing and for synthesizing for FPGA devices. + * Advanced ASIC development should rely on complete functional models + * supplied on a per macro basis. + * + * Technology specific implementations of "la_tdpram" would generally include + * one or more hardcoded instantiations of RAM modules with a generate + * statement relying on the "PROP" to select between the list of modules + * at build time. + * + ****************************************************************************/ + +module la_tdpram_impl #( + parameter DW = 32, // Memory width + parameter AW = 10, // address width (derived) + parameter PROP = "DEFAULT", // pass through variable for hard macro + parameter CTRLW = 128, // width of asic ctrl interface + parameter TESTW = 128 // width of asic test interface +) ( // Write port + input clk_a, // write clock + input ce_a, // write chip-enable + input we_a, // write enable + input [DW-1:0] wmask_a, // write mask + input [AW-1:0] addr_a, // write address + input [DW-1:0] din_a, // write data in + output reg [DW-1:0] dout_a, // read data out + // B port + input clk_b, // write clock + input ce_b, // write chip-enable + input we_b, // write enable + input [DW-1:0] wmask_b, // write mask + input [AW-1:0] addr_b, // write address + input [DW-1:0] din_b, // write data in + output reg [DW-1:0] dout_b, // read data out + // Power signal + input vss, // ground signal + input vdd, // memory core array power + input vddio, // periphery/io power + // Generic interfaces + input [CTRLW-1:0] ctrl, // pass through ASIC control interface + input [TESTW-1:0] test // pass through ASIC test interface +); + + // Generic RTL RAM + /* verilator lint_off MULTIDRIVEN */ + reg [DW-1:0] ram[(2**AW)-1:0]; + /* verilator lint_on MULTIDRIVEN */ + + integer i; + + // Port A write + always @(posedge clk_a) begin + for (i = 0; i < DW; i = i + 1) begin + if (ce_a && we_a && wmask_a[i]) begin + ram[addr_a][i] <= din_a[i]; + end + end + end + + // Port B write + always @(posedge clk_b) begin + for (i = 0; i < DW; i = i + 1) begin + if (ce_b && we_b && wmask_b[i]) begin + ram[addr_b][i] <= din_b[i]; + end + end + end + + // Port A read + always @(posedge clk_a) begin + if (ce_a && ~we_a) begin + dout_a <= ram[addr_a]; + end + end + + // Port B read + always @(posedge clk_b) begin + if (ce_b && ~we_b) begin + dout_b <= ram[addr_b]; + end + end + +endmodule