hw/ip/prim/rtl/prim_ram_2p_adv.sv Cov: 65.4%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // Dual-port SRAM Wrapper
6: // This module to connect SRAM interface to actual SRAM interface
7: // At this time, it doesn't utilize ECC or any pipeline.
8: // This module stays to include any additional calculation logic later on.
9: // Instantiating SRAM is up to the top design to remove process dependency.
10:
11: // Parameter
12: // EnableECC:
13: // EnableParity:
14: // EnableInputPipeline:
15: // EnableOutputPipeline:
16:
17: module prim_ram_2p_adv #(
18: parameter int Depth = 512,
19: parameter int Width = 32,
20: parameter int CfgW = 8, // WTC, RTC, etc
21:
22: // Configurations
23: parameter bit EnableECC = 0,
24: parameter bit EnableParity = 0,
25: parameter bit EnableInputPipeline = 0,
26: parameter bit EnableOutputPipeline = 0,
27:
28: parameter MemT = "REGISTER", // can be "REGISTER" or "SRAM"
29:
30: // Do not touch
31: parameter int SramAw = $clog2(Depth)
32: ) (
33: input clk_i,
34: input rst_ni,
35:
36: input a_req_i,
37: input a_write_i,
38: input [SramAw-1:0] a_addr_i,
39: input [Width-1:0] a_wdata_i,
40: output logic a_rvalid_o,
41: output logic [Width-1:0] a_rdata_o,
42: output logic [1:0] a_rerror_o,
43:
44: input b_req_i,
45: input b_write_i,
46: input [SramAw-1:0] b_addr_i,
47: input [Width-1:0] b_wdata_i,
48: output logic b_rvalid_o,
49: output logic [Width-1:0] b_rdata_o,
50: output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
51:
52: // config
53: input [CfgW-1:0] cfg_i
54: );
55:
56: // Calculate ECC width
57: localparam int ParWidth = (EnableParity) ? 1 :
58: (!EnableECC) ? 0 :
59: (Width <= 4) ? 4 :
60: (Width <= 11) ? 5 :
61: (Width <= 26) ? 6 :
62: (Width <= 57) ? 7 :
63: (Width <= 120) ? 8 : 8 ;
64: localparam int TotalWidth = Width + ParWidth;
65:
66: logic a_req_q, a_req_d ;
67: logic a_write_q, a_write_d ;
68: logic [SramAw-1:0] a_addr_q, a_addr_d ;
69: logic [TotalWidth-1:0] a_wdata_q, a_wdata_d ;
70: logic a_rvalid_q, a_rvalid_d, a_rvalid_sram ;
71: logic [Width-1:0] a_rdata_q, a_rdata_d ;
72: logic [TotalWidth-1:0] a_rdata_sram ;
73: logic [1:0] a_rerror_q, a_rerror_d ;
74:
75: logic b_req_q, b_req_d ;
76: logic b_write_q, b_write_d ;
77: logic [SramAw-1:0] b_addr_q, b_addr_d ;
78: logic [TotalWidth-1:0] b_wdata_q, b_wdata_d ;
79: logic b_rvalid_q, b_rvalid_d, b_rvalid_sram ;
80: logic [Width-1:0] b_rdata_q, b_rdata_d ;
81: logic [TotalWidth-1:0] b_rdata_sram ;
82: logic [1:0] b_rerror_q, b_rerror_d ;
83:
84: if (MemT == "REGISTER") begin : gen_regmem
85: prim_ram_2p #(
86: .Width (TotalWidth),
87: .Depth (Depth),
88: // force register implementation for all targets
89: .Impl(prim_pkg::ImplGeneric)
90: ) u_mem (
91: .clk_a_i (clk_i),
92: .clk_b_i (clk_i),
93:
94: .a_req_i (a_req_q),
95: .a_write_i (a_write_q),
96: .a_addr_i (a_addr_q),
97: .a_wdata_i (a_wdata_q),
98: .a_rdata_o (a_rdata_sram),
99:
100: .b_req_i (b_req_q),
101: .b_write_i (b_write_q),
102: .b_addr_i (b_addr_q),
103: .b_wdata_i (b_wdata_q),
104: .b_rdata_o (b_rdata_sram)
105: );
106: // end else if (TotalWidth == aa && Depth == yy) begin
107: end else if (MemT == "SRAM") begin : gen_srammem
108: prim_ram_2p #(
109: .Width (TotalWidth),
110: .Depth (Depth)
111: ) u_mem (
112: .clk_a_i (clk_i),
113: .clk_b_i (clk_i),
114:
115: .a_req_i (a_req_q),
116: .a_write_i (a_write_q),
117: .a_addr_i (a_addr_q),
118: .a_wdata_i (a_wdata_q),
119: .a_rdata_o (a_rdata_sram),
120:
121: .b_req_i (b_req_q),
122: .b_write_i (b_write_q),
123: .b_addr_i (b_addr_q),
124: .b_wdata_i (b_wdata_q),
125: .b_rdata_o (b_rdata_sram)
126: );
127: end
128:
129: always_ff @(posedge clk_i, negedge rst_ni) begin
130: if (!rst_ni) begin
131: a_rvalid_sram <= '0;
132: b_rvalid_sram <= '0;
133: end else begin
134: a_rvalid_sram <= a_req_q & ~a_write_q;
135: b_rvalid_sram <= b_req_q & ~b_write_q;
136: end
137: end
138:
139: assign a_req_d = a_req_i;
140: assign a_write_d = a_write_i;
141: assign a_addr_d = a_addr_i;
142: assign a_rvalid_o = a_rvalid_q;
143: assign a_rdata_o = a_rdata_q;
144: assign a_rerror_o = a_rerror_q;
145:
146: assign b_req_d = b_req_i;
147: assign b_write_d = b_write_i;
148: assign b_addr_d = b_addr_i;
149: assign b_rvalid_o = b_rvalid_q;
150: assign b_rdata_o = b_rdata_q;
151: assign b_rerror_o = b_rerror_q;
152:
153: // TODO: Parity Logic
154: `ASSERT_INIT(ParityNotYetSupported_A, EnableParity == 0)
155:
156: if (EnableParity == 0 && EnableECC) begin : gen_secded
157:
158: // check supported widths
159: `ASSERT_INIT(SecDecWidth_A, Width inside {32})
160:
161: if (Width == 32) begin : gen_secded_39_32
162: prim_secded_39_32_enc u_enc_a (.in(a_wdata_i), .out(a_wdata_d));
163: prim_secded_39_32_dec u_dec_a (
164: .in (a_rdata_sram),
165: .d_o (a_rdata_d),
166: .syndrome_o (),
167: .err_o (a_rerror_d)
168: );
169: prim_secded_39_32_enc u_enc_b (.in(b_wdata_i), .out(b_wdata_d));
170: prim_secded_39_32_dec u_dec_b (
171: .in (b_rdata_sram),
172: .d_o (b_rdata_d),
173: .syndrome_o (),
174: .err_o (b_rerror_d)
175: );
176: assign a_rvalid_d = a_rvalid_sram;
177: assign b_rvalid_d = b_rvalid_sram;
178: end
179: end else begin : gen_nosecded
180: assign a_wdata_d[0+:Width] = a_wdata_i;
181: assign b_wdata_d[0+:Width] = b_wdata_i;
182: assign a_rdata_d = a_rdata_sram;
183: assign b_rdata_d = b_rdata_sram;
184: assign a_rvalid_d = a_rvalid_sram;
185: assign b_rvalid_d = b_rvalid_sram;
186: assign a_rerror_d = 2'b00;
187: assign b_rerror_d = 2'b00;
188: end
189:
190: if (EnableInputPipeline) begin : gen_regslice_input
191: // Put the register slices between ECC encoding to SRAM port
192: always_ff @(posedge clk_i or negedge rst_ni) begin
193: if (!rst_ni) begin
194: a_req_q <= '0;
195: a_write_q <= '0;
196: a_addr_q <= '0;
197: a_wdata_q <= '0;
198:
199: b_req_q <= '0;
200: b_write_q <= '0;
201: b_addr_q <= '0;
202: b_wdata_q <= '0;
203: end else begin
204: a_req_q <= a_req_d;
205: a_write_q <= a_write_d;
206: a_addr_q <= a_addr_d;
207: a_wdata_q <= a_wdata_d;
208:
209: b_req_q <= b_req_d;
210: b_write_q <= b_write_d;
211: b_addr_q <= b_addr_d;
212: b_wdata_q <= b_wdata_d;
213: end
214: end
215: end else begin : gen_dirconnect_input
216: assign a_req_q = a_req_d;
217: assign a_write_q = a_write_d;
218: assign a_addr_q = a_addr_d;
219: assign a_wdata_q = a_wdata_d;
220:
221: assign b_req_q = b_req_d;
222: assign b_write_q = b_write_d;
223: assign b_addr_q = b_addr_d;
224: assign b_wdata_q = b_wdata_d;
225: end
226:
227: if (EnableOutputPipeline) begin : gen_regslice_output
228: // Put the register slices between ECC decoding to output
229: always_ff @(posedge clk_i or negedge rst_ni) begin
230: if (!rst_ni) begin
231: a_rvalid_q <= '0;
232: a_rdata_q <= '0;
233: a_rerror_q <= '0;
234:
235: b_rvalid_q <= '0;
236: b_rdata_q <= '0;
237: b_rerror_q <= '0;
238: end else begin
239: a_rvalid_q <= a_rvalid_d;
240: a_rdata_q <= a_rdata_d ;
241: a_rerror_q <= a_rerror_d;
242:
243: b_rvalid_q <= b_rvalid_d;
244: b_rdata_q <= b_rdata_d ;
245: b_rerror_q <= b_rerror_d;
246: end
247: end
248: end else begin : gen_dirconnect_output
249: assign a_rvalid_q = a_rvalid_d;
250: assign a_rdata_q = a_rdata_d;
251: assign a_rerror_q = a_rerror_d;
252:
253: assign b_rvalid_q = b_rvalid_d;
254: assign b_rdata_q = b_rdata_d;
255: assign b_rerror_q = b_rerror_d;
256: end
257:
258: endmodule
259: