hw/ip/prim/rtl/prim_ram_2p_adv.sv Cov: 65%

   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: