Skip to content

Commit 8d2ce26

Browse files
authored
Merge pull request #87 from siliconcompiler/ali/ram-fix
Split rams into impl and wrappers
2 parents f81fbff + 0f6b610 commit 8d2ce26

File tree

6 files changed

+249
-71
lines changed

6 files changed

+249
-71
lines changed

lambdalib/ramlib/rtl/la_dpram.v

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,31 @@ module la_dpram #(
4747
input [TESTW-1:0] test // pass through ASIC test interface
4848
);
4949

50-
// Generic RTL RAM
51-
reg [DW-1:0] ram[(2**AW)-1:0];
52-
integer i;
50+
la_dpram_impl #(
51+
.DW (DW),
52+
.AW (AW),
53+
.PROP (PROP),
54+
.CTRLW (CTRLW),
55+
.TESTW (TESTW)
56+
) ram (
57+
.wr_clk (wr_clk),
58+
.wr_ce (wr_ce),
59+
.wr_we (wr_we),
60+
.wr_wmask (wr_wmask),
61+
.wr_addr (wr_addr),
62+
.wr_din (wr_din),
5363

54-
// Write port
55-
always @(posedge wr_clk)
56-
for (i = 0; i < DW; i = i + 1)
57-
if (wr_ce & wr_we & wr_wmask[i]) ram[wr_addr[AW-1:0]][i] <= wr_din[i];
64+
.rd_clk (rd_clk),
65+
.rd_ce (rd_ce),
66+
.rd_addr (rd_addr),
67+
.rd_dout (rd_dout),
5868

59-
// Read Port
60-
always @(posedge rd_clk) if (rd_ce) rd_dout[DW-1:0] <= ram[rd_addr[AW-1:0]];
69+
.vss (vss),
70+
.vdd (vdd),
71+
.vddio (vddio),
72+
73+
.ctrl (ctrl),
74+
.test (test)
75+
);
6176

6277
endmodule
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*****************************************************************************
2+
* Function: Dual Port RAM (One write port + One read port)
3+
* Copyright: Lambda Project Authors. All rights Reserved.
4+
* License: MIT (see LICENSE file in Lambda repository)
5+
*
6+
* Docs:
7+
*
8+
* This is a wrapper for selecting from a set of hardened memory macros.
9+
*
10+
* A synthesizable reference model is used when the PROP is DEFAULT. The
11+
* synthesizable model does not implement the cfg and test interface and should
12+
* only be used for basic testing and for synthesizing for FPGA devices.
13+
* Advanced ASIC development should rely on complete functional models
14+
* supplied on a per macro basis.
15+
*
16+
* Technologoy specific implementations of "la_dpram" would generally include
17+
* one or more hardcoded instantiations of RAM modules with a generate
18+
* statement relying on the "PROP" to select between the list of modules
19+
* at build time.
20+
*
21+
****************************************************************************/
22+
23+
module la_dpram_impl #(
24+
parameter DW = 32, // Memory width
25+
parameter AW = 10, // address width (derived)
26+
parameter PROP = "DEFAULT", // pass through variable for hard macro
27+
parameter CTRLW = 128, // width of asic ctrl interface
28+
parameter TESTW = 128 // width of asic test interface
29+
) ( // Write port
30+
input wr_clk, // write clock
31+
input wr_ce, // write chip-enable
32+
input wr_we, // write enable
33+
input [DW-1:0] wr_wmask, // write mask
34+
input [AW-1:0] wr_addr, // write address
35+
input [DW-1:0] wr_din, //write data in
36+
// Read port
37+
input rd_clk, // read clock
38+
input rd_ce, // read chip-enable
39+
input [AW-1:0] rd_addr, // read address
40+
output reg [DW-1:0] rd_dout, //read data out
41+
// Power signal
42+
input vss, // ground signal
43+
input vdd, // memory core array power
44+
input vddio, // periphery/io power
45+
// Generic interfaces
46+
input [CTRLW-1:0] ctrl, // pass through ASIC control interface
47+
input [TESTW-1:0] test // pass through ASIC test interface
48+
);
49+
50+
// Generic RTL RAM
51+
reg [DW-1:0] ram[(2**AW)-1:0];
52+
integer i;
53+
54+
// Write port
55+
always @(posedge wr_clk)
56+
for (i = 0; i < DW; i = i + 1)
57+
if (wr_ce & wr_we & wr_wmask[i]) ram[wr_addr[AW-1:0]][i] <= wr_din[i];
58+
59+
// Read Port
60+
always @(posedge rd_clk) if (rd_ce) rd_dout[DW-1:0] <= ram[rd_addr[AW-1:0]];
61+
62+
endmodule

lambdalib/ramlib/rtl/la_spram.v

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,27 @@ module la_spram #(
4343
input [TESTW-1:0] test // pass through ASIC test interface
4444
);
4545

46-
// Generic RTL RAM
47-
reg [DW-1:0] ram[(2**AW)-1:0];
48-
integer i;
46+
la_spram_impl #(
47+
.DW (DW),
48+
.AW (AW),
49+
.PROP (PROP),
50+
.CTRLW (CTRLW),
51+
.TESTW (TESTW)
52+
) ram (
53+
.clk (clk),
54+
.ce (ce),
55+
.we (we),
56+
.wmask (wmask),
57+
.addr (addr),
58+
.din (din),
59+
.dout (dout),
4960

50-
// Write port
51-
// always @(posedge clk)
52-
// for (i=0;i<DW;i=i+1)
53-
// if (ce & we & wmask[i])
54-
// ram[addr[AW-1:0]][i] <= din[i];
61+
.vss (vss),
62+
.vdd (vdd),
63+
.vddio (vddio),
5564

56-
// Re-writing as a mux for verilator
57-
always @(posedge clk)
58-
if (ce & we)
59-
ram[addr[AW-1:0]] <= din[DW-1:0] & wmask[DW-1:0] | ram[addr[AW-1:0]] & ~wmask[DW-1:0];
60-
61-
// Read Port
62-
always @(posedge clk) if (ce) dout[DW-1:0] <= ram[addr[AW-1:0]];
65+
.ctrl (ctrl),
66+
.test (test)
67+
);
6368

6469
endmodule
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*****************************************************************************
2+
* Function: Single Port RAM
3+
* Copyright: Lambda Project Authors. All rights Reserved.
4+
* License: MIT (see LICENSE file in Lambda repository)
5+
*
6+
* Docs:
7+
*
8+
* This is a wrapper for selecting from a set of hardened memory macros.
9+
*
10+
* A synthesizable reference model is used when the PROP is DEFAULT. The
11+
* synthesizable model does not implement the cfg and test interface and should
12+
* only be used for basic testing and for synthesizing for FPGA devices.
13+
* Advanced ASIC development should rely on complete functional models
14+
* supplied on a per macro basis.
15+
*
16+
* Technologoy specific implementations of "la_spram" would generally include
17+
* one or more hardcoded instantiations of RAM modules with a generate
18+
* statement relying on the "PROP" to select between the list of modules
19+
* at build time.
20+
*
21+
****************************************************************************/
22+
23+
module la_spram_impl #(
24+
parameter DW = 32, // Memory width
25+
parameter AW = 10, // Address width (derived)
26+
parameter PROP = "DEFAULT", // Pass through variable for hard macro
27+
parameter CTRLW = 1, // Width of asic ctrl interface
28+
parameter TESTW = 1 // Width of asic test interface
29+
) ( // Memory interface
30+
input clk, // write clock
31+
input ce, // chip enable
32+
input we, // write enable
33+
input [DW-1:0] wmask, //per bit write mask
34+
input [AW-1:0] addr, //write address
35+
input [DW-1:0] din, //write data
36+
output reg [DW-1:0] dout, //read output data
37+
// Power signals
38+
input vss, // ground signal
39+
input vdd, // memory core array power
40+
input vddio, // periphery/io power
41+
// Generic interfaces
42+
input [CTRLW-1:0] ctrl, // pass through ASIC control interface
43+
input [TESTW-1:0] test // pass through ASIC test interface
44+
);
45+
46+
// Generic RTL RAM
47+
reg [DW-1:0] ram[(2**AW)-1:0];
48+
integer i;
49+
50+
// Write port
51+
// always @(posedge clk)
52+
// for (i=0;i<DW;i=i+1)
53+
// if (ce & we & wmask[i])
54+
// ram[addr[AW-1:0]][i] <= din[i];
55+
56+
// Re-writing as a mux for verilator
57+
always @(posedge clk)
58+
if (ce & we)
59+
ram[addr[AW-1:0]] <= din[DW-1:0] & wmask[DW-1:0] | ram[addr[AW-1:0]] & ~wmask[DW-1:0];
60+
61+
// Read Port
62+
always @(posedge clk) if (ce) dout[DW-1:0] <= ram[addr[AW-1:0]];
63+
64+
endmodule

lambdalib/utils/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from jinja2 import Template
22
import os
3+
import math
34
from collections import OrderedDict
45

56

6-
def write_la_spram(fout, memories, control_signals=None, la_type='ram'):
7+
def write_la_spram(fout, memories, control_signals=None, la_type='ram', minbits=None):
78
template_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
89
'templates',
910
'la_spmemory.v'))
@@ -33,6 +34,13 @@ def write_la_spram(fout, memories, control_signals=None, la_type='ram'):
3334
selection_table = OrderedDict(sorted(selection_table.items(), reverse=True))
3435
for aw, items in selection_table.items():
3536
selection_table[aw] = OrderedDict(sorted(items.items(), reverse=True))
37+
38+
if minbits is not None:
39+
depth = 2**aw
40+
dw = int(math.floor(minbits / depth))
41+
if dw > 0:
42+
selection_table[aw][dw] = "SOFT"
43+
selection_table[min(selection_table.keys()) - 1] = {0: "SOFT"}
3644
widths_table.sort()
3745
depths_table.sort()
3846

lambdalib/utils/templates/la_spmemory.v

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -56,61 +56,85 @@ module la_sp{{ type }}
5656
(MEM_PROP == "{{ memory }}") ? {{ depth }} :{% endfor %}
5757
0;
5858

59-
// Create memories
60-
localparam MEM_ADDRS = 2**(AW - MEM_DEPTH) < 1 ? 1 : 2**(AW - MEM_DEPTH);
61-
62-
{% if control_signals %}// Control signals{% for line in control_signals %}
63-
{{ line }}{% endfor %}{% endif %}
64-
6559
generate
66-
genvar o;
67-
for (o = 0; o < DW; o = o + 1) begin: OUTPUTS
68-
wire [MEM_ADDRS-1:0] mem_outputs;
69-
assign dout[o] = |mem_outputs;
60+
if (MEM_PROP == "SOFT") begin: isoft
61+
la_spram_impl #(
62+
.DW(DW),
63+
.AW(AW),
64+
.PROP(PROP),
65+
.CTRLW(CTRLW),
66+
.TESTW(TESTW)
67+
) memory(
68+
.clk(clk),
69+
.ce(ce),
70+
.we(we),
71+
.wmask(wmask),
72+
.addr(addr),
73+
.din(din),
74+
.dout(dout),
75+
.vss(vss),
76+
.vdd(vdd),
77+
.vddio(vddio),
78+
.ctrl(ctrl),
79+
.test(test)
80+
);
7081
end
82+
if (MEM_PROP != "SOFT") begin: itech
83+
// Create memories
84+
localparam MEM_ADDRS = 2**(AW - MEM_DEPTH) < 1 ? 1 : 2**(AW - MEM_DEPTH);
7185

72-
genvar a;
73-
for (a = 0; a < MEM_ADDRS; a = a + 1) begin: ADDR
74-
wire selected;
75-
wire [MEM_DEPTH-1:0] mem_addr;
86+
{% if control_signals %}// Control signals{% for line in control_signals %}
87+
{{ line }}{% endfor %}{% endif %}
7688

77-
if (MEM_ADDRS == 1) begin: FITS
78-
assign selected = 1'b1;
79-
assign mem_addr = addr;
80-
end else begin: NOFITS
81-
assign selected = addr[AW-1:MEM_DEPTH] == a;
82-
assign mem_addr = addr[MEM_DEPTH-1:0];
89+
genvar o;
90+
for (o = 0; o < DW; o = o + 1) begin: OUTPUTS
91+
wire [MEM_ADDRS-1:0] mem_outputs;
92+
assign dout[o] = |mem_outputs;
8393
end
8494

85-
genvar n;
86-
for (n = 0; n < DW; n = n + MEM_WIDTH) begin: WORD
87-
wire [MEM_WIDTH-1:0] mem_din;
88-
wire [MEM_WIDTH-1:0] mem_dout;
89-
wire [MEM_WIDTH-1:0] mem_wmask;
95+
genvar a;
96+
for (a = 0; a < MEM_ADDRS; a = a + 1) begin: ADDR
97+
wire selected;
98+
wire [MEM_DEPTH-1:0] mem_addr;
9099

91-
genvar i;
92-
for (i = 0; i < MEM_WIDTH; i = i + 1) begin: WORD_SELECT
93-
if (n + i < DW) begin: ACTIVE
94-
assign mem_din[i] = din[n + i];
95-
assign mem_wmask[i] = wmask[n + i];
96-
assign OUTPUTS[n + i].mem_outputs[a] = selected ? mem_dout[i] : 1'b0;
97-
end
98-
else begin: INACTIVE
99-
assign mem_din[i] = 1'b0;
100-
assign mem_wmask[i] = 1'b0;
101-
end
100+
if (MEM_ADDRS == 1) begin: FITS
101+
assign selected = 1'b1;
102+
assign mem_addr = addr;
103+
end else begin: NOFITS
104+
assign selected = addr[AW-1:MEM_DEPTH] == a;
105+
assign mem_addr = addr[MEM_DEPTH-1:0];
102106
end
103107

104-
wire ce_in;
105-
wire we_in;
106-
assign ce_in = ce && selected;
107-
assign we_in = we && selected;
108-
{% for memory, inst_name in inst_map.items() %}
109-
if (MEM_PROP == "{{ memory }}") begin: i{{ memory }}
110-
{{ inst_name }} memory ({% for port, net in port_mapping[memory] %}
111-
.{{ port }}({{ net }}){% if loop.nextitem is defined %},{% endif %}{% endfor %}
112-
);
113-
end{% endfor %}
108+
genvar n;
109+
for (n = 0; n < DW; n = n + MEM_WIDTH) begin: WORD
110+
wire [MEM_WIDTH-1:0] mem_din;
111+
wire [MEM_WIDTH-1:0] mem_dout;
112+
wire [MEM_WIDTH-1:0] mem_wmask;
113+
114+
genvar i;
115+
for (i = 0; i < MEM_WIDTH; i = i + 1) begin: WORD_SELECT
116+
if (n + i < DW) begin: ACTIVE
117+
assign mem_din[i] = din[n + i];
118+
assign mem_wmask[i] = wmask[n + i];
119+
assign OUTPUTS[n + i].mem_outputs[a] = selected ? mem_dout[i] : 1'b0;
120+
end
121+
else begin: INACTIVE
122+
assign mem_din[i] = 1'b0;
123+
assign mem_wmask[i] = 1'b0;
124+
end
125+
end
126+
127+
wire ce_in;
128+
wire we_in;
129+
assign ce_in = ce && selected;
130+
assign we_in = we && selected;
131+
{% for memory, inst_name in inst_map.items() %}
132+
if (MEM_PROP == "{{ memory }}") begin: i{{ memory }}
133+
{{ inst_name }} memory ({% for port, net in port_mapping[memory] %}
134+
.{{ port }}({{ net }}){% if loop.nextitem is defined %},{% endif %}{% endfor %}
135+
);
136+
end{% endfor %}
137+
end
114138
end
115139
end
116140
endgenerate

0 commit comments

Comments
 (0)