hw/ip/prim/rtl/prim_ram_2p_async_adv.sv Cov: 62%

   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: