../src/lowrisc_prim_ram_1p_adv_0.1/rtl/prim_ram_1p_adv.sv Cov: 66.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: // Single-Port SRAM Wrapper
   6: //
   7: // Supported configurations:
   8: // - ECC for 32b wide memories with no write mask
   9: //   (Width == 32 && DataBitsPerMask == 32).
  10: // - Byte parity if Width is a multiple of 8 bit and write masks have Byte
  11: //   granularity (DataBitsPerMask == 8).
  12: //
  13: // Note that the write mask needs to be per Byte if parity is enabled. If ECC is enabled, the write
  14: // mask cannot be used and has to be tied to {Width{1'b1}}.
  15: 
  16: `include "prim_assert.sv"
  17: `include "prim_util.svh"
  18: 
  19: module prim_ram_1p_adv #(
  20:   parameter  int Depth                = 512,
  21:   parameter  int Width                = 32,
  22:   parameter  int DataBitsPerMask      = 1,  // Number of data bits per bit of write mask
  23:   parameter  int CfgW                 = 8,  // WTC, RTC, etc
  24:   parameter      MemInitFile          = "", // VMEM file to initialize the memory with
  25: 
  26:   // Configurations
  27:   parameter  bit EnableECC            = 0, // Enables per-word ECC
  28:   parameter  bit EnableParity         = 0, // Enables per-Byte Parity
  29:   parameter  bit EnableInputPipeline  = 0, // Adds an input register (read latency +1)
  30:   parameter  bit EnableOutputPipeline = 0, // Adds an output register (read latency +1)
  31: 
  32:   localparam int Aw                   = vbits(Depth)
  33: ) (
  34:   input clk_i,
  35:   input rst_ni,
  36: 
  37:   input                      req_i,
  38:   input                      write_i,
  39:   input        [Aw-1:0]      addr_i,
  40:   input        [Width-1:0]   wdata_i,
  41:   input        [Width-1:0]   wmask_i,
  42:   output logic [Width-1:0]   rdata_o,
  43:   output logic               rvalid_o, // read response (rdata_o) is valid
  44:   output logic [1:0]         rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
  45: 
  46:   // config
  47:   input [CfgW-1:0] cfg_i
  48: );
  49: 
  50:   `ASSERT_INIT(CannotHaveEccAndParity_A, !(EnableParity && EnableECC))
  51: 
  52:   // While we require DataBitsPerMask to be per Byte (8) at the interface in case Byte parity is
  53:   // enabled, we need to switch this to a per-bit mask locally such that we can individually enable
  54:   // the parity bits to be written alongside the data.
  55:   localparam int LocalDataBitsPerMask = (EnableParity) ? 1 : DataBitsPerMask;
  56: 
  57:   // Calculate ECC width
  58:   localparam int ParWidth  = (EnableParity) ? Width/8 :
  59:                              (!EnableECC)   ? 0 :
  60:                              (Width <=   4) ? 4 :
  61:                              (Width <=  11) ? 5 :
  62:                              (Width <=  26) ? 6 :
  63:                              (Width <=  57) ? 7 :
  64:                              (Width <= 120) ? 8 : 8 ;
  65:   localparam int TotalWidth = Width + ParWidth;
  66: 
  67:   ////////////////////////////
  68:   // RAM Primitive Instance //
  69:   ////////////////////////////
  70: 
  71:   logic                    req_q,    req_d ;
  72:   logic                    write_q,  write_d ;
  73:   logic [Aw-1:0]           addr_q,   addr_d ;
  74:   logic [TotalWidth-1:0]   wdata_q,  wdata_d ;
  75:   logic [TotalWidth-1:0]   wmask_q,  wmask_d ;
  76:   logic                    rvalid_q, rvalid_d, rvalid_sram ;
  77:   logic [Width-1:0]        rdata_q,  rdata_d ;
  78:   logic [TotalWidth-1:0]   rdata_sram ;
  79:   logic [1:0]              rerror_q, rerror_d ;
  80: 
  81:   prim_ram_1p #(
  82:     .MemInitFile     (MemInitFile),
  83: 
  84:     .Width           (TotalWidth),
  85:     .Depth           (Depth),
  86:     .DataBitsPerMask (LocalDataBitsPerMask)
  87:   ) u_mem (
  88:     .clk_i,
  89: 
  90:     .req_i    (req_q),
  91:     .write_i  (write_q),
  92:     .addr_i   (addr_q),
  93:     .wdata_i  (wdata_q),
  94:     .wmask_i  (wmask_q),
  95:     .rdata_o  (rdata_sram)
  96:   );
  97: 
  98:   always_ff @(posedge clk_i or negedge rst_ni) begin
  99:     if (!rst_ni) begin
 100:       rvalid_sram <= 1'b0;
 101:     end else begin
 102:       rvalid_sram <= req_q & ~write_q;
 103:     end
 104:   end
 105: 
 106:   assign req_d              = req_i;
 107:   assign write_d            = write_i;
 108:   assign addr_d             = addr_i;
 109:   assign rvalid_o           = rvalid_q;
 110:   assign rdata_o            = rdata_q;
 111:   assign rerror_o           = rerror_q;
 112: 
 113:   /////////////////////////////
 114:   // ECC / Parity Generation //
 115:   /////////////////////////////
 116: 
 117:   if (EnableParity == 0 && EnableECC) begin : gen_secded
 118: 
 119:     // check supported widths
 120:     `ASSERT_INIT(SecDecWidth_A, Width inside {32})
 121: 
 122:     // the wmask is constantly set to 1 in this case
 123:     `ASSERT(OnlyWordWritePossibleWithEccPortA_A, req_i |->
 124:           wmask_i == {TotalWidth{1'b1}})
 125: 
 126:     assign wmask_d = {TotalWidth{1'b1}};
 127: 
 128:     if (Width == 32) begin : gen_secded_39_32
 129:       prim_secded_39_32_enc u_enc (.in(wdata_i), .out(wdata_d));
 130:       prim_secded_39_32_dec u_dec (
 131:         .in         (rdata_sram),
 132:         .d_o        (rdata_d[0+:Width]),
 133:         .syndrome_o ( ),
 134:         .err_o      (rerror_d)
 135:       );
 136:     end
 137:   end else if (EnableParity) begin : gen_byte_parity
 138: 
 139:     `ASSERT_INIT(WidthNeedsToBeByteAligned_A, Width % 8 == 0)
 140:     `ASSERT_INIT(ParityNeedsByteWriteMask_A, DataBitsPerMask == 8)
 141: 
 142:     always_comb begin : p_parity
 143:       rerror_d = '0;
 144:       wmask_d[0+:Width] = wmask_i;
 145:       wdata_d[0+:Width] = wdata_i;
 146: 
 147:       for (int i = 0; i < Width/8; i ++) begin
 148:         // parity generation (odd parity)
 149:         wdata_d[Width + i] = ~(^wdata_i[i*8 +: 8]);
 150:         wmask_d[Width + i] = &wmask_i[i*8 +: 8];
 151:         // parity decoding (errors are always uncorrectable)
 152:         rerror_d[1] |= ~(^{rdata_sram[i*8 +: 8], rdata_sram[Width + i]});
 153:       end
 154:       // tie to zero if the read data is not valid
 155:       rerror_d &= {2{rvalid_sram}};
 156:     end
 157: 
 158:     assign rdata_d  = rdata_sram[0+:Width];
 159:   end else begin : gen_nosecded_noparity
 160:     assign wmask_d = wmask_i;
 161:     assign wdata_d = wdata_i;
 162: 
 163:     assign rdata_d  = rdata_sram[0+:Width];
 164:     assign rerror_d = '0;
 165:   end
 166: 
 167:   assign rvalid_d = rvalid_sram;
 168: 
 169:   /////////////////////////////////////
 170:   // Input/Output Pipeline Registers //
 171:   /////////////////////////////////////
 172: 
 173:   if (EnableInputPipeline) begin : gen_regslice_input
 174:     // Put the register slices between ECC encoding to SRAM port
 175:     always_ff @(posedge clk_i or negedge rst_ni) begin
 176:       if (!rst_ni) begin
 177:         req_q   <= '0;
 178:         write_q <= '0;
 179:         addr_q  <= '0;
 180:         wdata_q <= '0;
 181:         wmask_q <= '0;
 182:       end else begin
 183:         req_q   <= req_d;
 184:         write_q <= write_d;
 185:         addr_q  <= addr_d;
 186:         wdata_q <= wdata_d;
 187:         wmask_q <= wmask_d;
 188:       end
 189:     end
 190:   end else begin : gen_dirconnect_input
 191:     assign req_q   = req_d;
 192:     assign write_q = write_d;
 193:     assign addr_q  = addr_d;
 194:     assign wdata_q = wdata_d;
 195:     assign wmask_q = wmask_d;
 196:   end
 197: 
 198:   if (EnableOutputPipeline) begin : gen_regslice_output
 199:     // Put the register slices between ECC decoding to output
 200:     always_ff @(posedge clk_i or negedge rst_ni) begin
 201:       if (!rst_ni) begin
 202:         rvalid_q <= '0;
 203:         rdata_q  <= '0;
 204:         rerror_q <= '0;
 205:       end else begin
 206:         rvalid_q <= rvalid_d;
 207:         rdata_q  <= rdata_d;
 208:         rerror_q <= rerror_d;
 209:       end
 210:     end
 211:   end else begin : gen_dirconnect_output
 212:     assign rvalid_q = rvalid_d;
 213:     assign rdata_q  = rdata_d;
 214:     assign rerror_q = rerror_d;
 215:   end
 216: 
 217: endmodule : prim_ram_1p_adv
 218: