hw/ip/prim/rtl/prim_ram_2p_async_adv.sv Cov: 62.7%
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_async_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_a_i,
34: input clk_b_i,
35: input rst_a_ni,
36: input rst_b_ni,
37:
38: input a_req_i,
39: input a_write_i,
40: input [SramAw-1:0] a_addr_i,
41: input [Width-1:0] a_wdata_i,
42: output logic a_rvalid_o,
43: output logic [Width-1:0] a_rdata_o,
44: output logic [1:0] a_rerror_o,
45:
46: input b_req_i,
47: input b_write_i,
48: input [SramAw-1:0] b_addr_i,
49: input [Width-1:0] b_wdata_i,
50: output logic b_rvalid_o,
51: output logic [Width-1:0] b_rdata_o,
52: output logic [1:0] b_rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
53:
54: // config
55: input [CfgW-1:0] cfg_i
56: );
57:
58: // Calculate ECC width
59: localparam int ParWidth = (EnableParity) ? 1 :
60: (!EnableECC) ? 0 :
61: (Width <= 4) ? 4 :
62: (Width <= 11) ? 5 :
63: (Width <= 26) ? 6 :
64: (Width <= 57) ? 7 :
65: (Width <= 120) ? 8 : 8 ;
66: localparam int TotalWidth = Width + ParWidth;
67:
68: logic a_req_q, a_req_d ;
69: logic a_write_q, a_write_d ;
70: logic [SramAw-1:0] a_addr_q, a_addr_d ;
71: logic [TotalWidth-1:0] a_wdata_q, a_wdata_d ;
72: logic a_rvalid_q, a_rvalid_d, a_rvalid_sram ;
73: logic [TotalWidth-1:0] a_rdata_d, a_rdata_sram ;
74: logic [Width-1:0] a_rdata_q ;
75: logic [1:0] a_rerror_q, a_rerror_d ;
76:
77: logic b_req_q, b_req_d ;
78: logic b_write_q, b_write_d ;
79: logic [SramAw-1:0] b_addr_q, b_addr_d ;
80: logic [TotalWidth-1:0] b_wdata_q, b_wdata_d ;
81: logic b_rvalid_q, b_rvalid_d, b_rvalid_sram ;
82: logic [TotalWidth-1:0] b_rdata_d, b_rdata_sram ;
83: logic [Width-1:0] b_rdata_q ;
84: logic [1:0] b_rerror_q, b_rerror_d ;
85:
86: if (MemT == "REGISTER") begin : gen_regmem
87: prim_ram_2p #(
88: .Width (TotalWidth),
89: .Depth (Depth),
90: // force register implementation for all targets
91: .Impl(prim_pkg::ImplGeneric)
92: ) u_mem (
93: .clk_a_i (clk_a_i),
94: .clk_b_i (clk_b_i),
95:
96: .a_req_i (a_req_q),
97: .a_write_i (a_write_q),
98: .a_addr_i (a_addr_q),
99: .a_wdata_i (a_wdata_q),
100: .a_rdata_o (a_rdata_sram),
101:
102: .b_req_i (b_req_q),
103: .b_write_i (b_write_q),
104: .b_addr_i (b_addr_q),
105: .b_wdata_i (b_wdata_q),
106: .b_rdata_o (b_rdata_sram)
107: );
108: // end else if (TotalWidth == aa && Depth == yy) begin
109: end else if (MemT == "SRAM") begin : gen_srammem
110: prim_ram_2p #(
111: .Width (TotalWidth),
112: .Depth (Depth)
113: ) u_mem (
114: .clk_a_i (clk_a_i),
115: .clk_b_i (clk_b_i),
116:
117: .a_req_i (a_req_q),
118: .a_write_i (a_write_q),
119: .a_addr_i (a_addr_q),
120: .a_wdata_i (a_wdata_q),
121: .a_rdata_o (a_rdata_sram),
122:
123: .b_req_i (b_req_q),
124: .b_write_i (b_write_q),
125: .b_addr_i (b_addr_q),
126: .b_wdata_i (b_wdata_q),
127: .b_rdata_o (b_rdata_sram)
128: );
129: end
130:
131: always_ff @(posedge clk_a_i or negedge rst_a_ni) begin
132: if (!rst_a_ni) begin
133: a_rvalid_sram <= 1'b0;
134: end else begin
135: a_rvalid_sram <= a_req_q & ~a_write_q;
136: end
137: end
138: always_ff @(posedge clk_b_i or negedge rst_b_ni) begin
139: if (!rst_b_ni) begin
140: b_rvalid_sram <= 1'b0;
141: end else begin
142: b_rvalid_sram <= b_req_q & ~b_write_q;
143: end
144: end
145:
146: assign a_req_d = a_req_i;
147: assign a_write_d = a_write_i;
148: assign a_addr_d = a_addr_i;
149: assign a_rvalid_o = a_rvalid_q;
150: assign a_rdata_o = a_rdata_q;
151: assign a_rerror_o = a_rerror_q;
152:
153: assign b_req_d = b_req_i;
154: assign b_write_d = b_write_i;
155: assign b_addr_d = b_addr_i;
156: assign b_rvalid_o = b_rvalid_q;
157: assign b_rdata_o = b_rdata_q;
158: assign b_rerror_o = b_rerror_q;
159:
160: // TODO: Parity Logic
161: `ASSERT_INIT(ParityNotYetSupported_A, EnableParity == 0)
162:
163: if (EnableParity == 0 && EnableECC) begin : gen_secded
164:
165: // check supported widths
166: `ASSERT_INIT(SecDecWidth_A, Width inside {32})
167:
168: if (Width == 32) begin : gen_secded_39_32
169: prim_secded_39_32_enc u_enc_a (.in(a_wdata_i), .out(a_wdata_d));
170: prim_secded_39_32_dec u_dec_a (
171: .in (a_rdata_sram),
172: .d_o (a_rdata_d[0+:Width]),
173: .syndrome_o (a_rdata_d[Width+:ParWidth]),
174: .err_o (a_rerror_d)
175: );
176: prim_secded_39_32_enc u_enc_b (.in(b_wdata_i), .out(b_wdata_d));
177: prim_secded_39_32_dec u_dec_b (
178: .in (b_rdata_sram),
179: .d_o (b_rdata_d[0+:Width]),
180: .syndrome_o (b_rdata_d[Width+:ParWidth]),
181: .err_o (b_rerror_d)
182: );
183: assign a_rvalid_d = a_rvalid_sram;
184: assign b_rvalid_d = b_rvalid_sram;
185: end
186: end else begin : gen_nosecded
187: assign a_wdata_d[0+:Width] = a_wdata_i;
188: assign b_wdata_d[0+:Width] = b_wdata_i;
189: assign a_rdata_d[0+:Width] = a_rdata_sram;
190: assign b_rdata_d[0+:Width] = b_rdata_sram;
191: assign a_rvalid_d = a_rvalid_sram;
192: assign b_rvalid_d = b_rvalid_sram;
193: assign a_rerror_d = 2'b00;
194: assign b_rerror_d = 2'b00;
195: end
196:
197: if (EnableInputPipeline) begin : gen_regslice_input
198: // Put the register slices between ECC encoding to SRAM port
199: always_ff @(posedge clk_a_i or negedge rst_a_ni) begin
200: if (!rst_a_ni) begin
201: a_req_q <= '0;
202: a_write_q <= '0;
203: a_addr_q <= '0;
204: a_wdata_q <= '0;
205: end else begin
206: a_req_q <= a_req_d;
207: a_write_q <= a_write_d;
208: a_addr_q <= a_addr_d;
209: a_wdata_q <= a_wdata_d;
210: end
211: end
212: always_ff @(posedge clk_b_i or negedge rst_b_ni) begin
213: if (!rst_b_ni) begin
214: b_req_q <= '0;
215: b_write_q <= '0;
216: b_addr_q <= '0;
217: b_wdata_q <= '0;
218: end else begin
219: b_req_q <= b_req_d;
220: b_write_q <= b_write_d;
221: b_addr_q <= b_addr_d;
222: b_wdata_q <= b_wdata_d;
223: end
224: end
225: end else begin : gen_dirconnect_input
226: assign a_req_q = a_req_d;
227: assign a_write_q = a_write_d;
228: assign a_addr_q = a_addr_d;
229: assign a_wdata_q = a_wdata_d;
230:
231: assign b_req_q = b_req_d;
232: assign b_write_q = b_write_d;
233: assign b_addr_q = b_addr_d;
234: assign b_wdata_q = b_wdata_d;
235: end
236:
237: if (EnableOutputPipeline) begin : gen_regslice_output
238: // Put the register slices between ECC decoding to output
239: always_ff @(posedge clk_a_i or negedge rst_a_ni) begin
240: if (!rst_a_ni) begin
241: a_rvalid_q <= '0;
242: a_rdata_q <= '0;
243: a_rerror_q <= '0;
244: end else begin
245: a_rvalid_q <= a_rvalid_d;
246: a_rdata_q <= a_rdata_d[0+:Width] ;
247: a_rerror_q <= a_rerror_d;
248: end
249: end
250: always_ff @(posedge clk_b_i or negedge rst_b_ni) begin
251: if (!rst_b_ni) begin
252: b_rvalid_q <= '0;
253: b_rdata_q <= '0;
254: b_rerror_q <= '0;
255: end else begin
256: b_rvalid_q <= b_rvalid_d;
257: b_rdata_q <= b_rdata_d[0+:Width] ;
258: b_rerror_q <= b_rerror_d;
259: end
260: end
261: end else begin : gen_dirconnect_output
262: assign a_rvalid_q = a_rvalid_d;
263: assign a_rdata_q = a_rdata_d[0+:Width];
264: assign a_rerror_q = a_rerror_d;
265:
266: assign b_rvalid_q = b_rvalid_d;
267: assign b_rdata_q = b_rdata_d[0+:Width];
268: assign b_rerror_q = b_rerror_d;
269: end
270:
271: endmodule
272: