../src/lowrisc_prim_generic_ram_2p_0/rtl/prim_generic_ram_2p.sv Cov: 89.8%

   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: // Synchronous dual-port SRAM register model
   6: //   This module is for simulation and small size SRAM.
   7: //   Implementing ECC should be done inside wrapper not this model.
   8: 
   9: module prim_generic_ram_2p #(
  10:   parameter  int Width           = 32, // bit
  11:   parameter  int Depth           = 128,
  12:   parameter  int DataBitsPerMask = 1, // Number of data bits per bit of write mask
  13:   parameter      MemInitFile     = "", // VMEM file to initialize the memory with
  14: 
  15:   localparam int Aw              = $clog2(Depth)  // derived parameter
  16: ) (
  17:   input clk_a_i,
  18:   input clk_b_i,
  19: 
  20:   input                    a_req_i,
  21:   input                    a_write_i,
  22:   input        [Aw-1:0]    a_addr_i,
  23:   input        [Width-1:0] a_wdata_i,
  24:   input  logic [Width-1:0] a_wmask_i,
  25:   output logic [Width-1:0] a_rdata_o,
  26: 
  27: 
  28:   input                    b_req_i,
  29:   input                    b_write_i,
  30:   input        [Aw-1:0]    b_addr_i,
  31:   input        [Width-1:0] b_wdata_i,
  32:   input  logic [Width-1:0] b_wmask_i,
  33:   output logic [Width-1:0] b_rdata_o
  34: );
  35:   // Width of internal write mask. Note *_wmask_i input into the module is always assumed
  36:   // to be the full bit mask.
  37:   localparam int MaskWidth = Width / DataBitsPerMask;
  38: 
  39:   logic [Width-1:0]     mem [Depth];
  40:   logic [MaskWidth-1:0] a_wmask;
  41:   logic [MaskWidth-1:0] b_wmask;
  42: 
  43:   always_comb begin
  44:     for (int i=0; i < MaskWidth; i = i + 1) begin : create_wmask
  45:       a_wmask[i] = &a_wmask_i[i*DataBitsPerMask +: DataBitsPerMask];
  46:       b_wmask[i] = &b_wmask_i[i*DataBitsPerMask +: DataBitsPerMask];
  47:     end
  48:   end
  49: 
  50: 
  51:   // Xilinx FPGA specific Dual-port RAM coding style
  52:   // using always instead of always_ff to avoid 'ICPD  - illegal combination of drivers' error
  53:   // thrown due to 'mem' being driven by two always processes below
  54:   always @(posedge clk_a_i) begin
  55:     if (a_req_i) begin
  56:       if (a_write_i) begin
  57:         for (int i=0; i < MaskWidth; i = i + 1) begin
  58:           if (a_wmask[i]) begin
  59:             mem[a_addr_i][i*DataBitsPerMask +: DataBitsPerMask] <=
  60:               a_wdata_i[i*DataBitsPerMask +: DataBitsPerMask];
  61:           end
  62:         end
  63:       end else begin
  64:         a_rdata_o <= mem[a_addr_i];
  65:       end
  66:     end
  67:   end
  68: 
  69:   always @(posedge clk_b_i) begin
  70:     if (b_req_i) begin
  71:       if (b_write_i) begin
  72:         for (int i=0; i < MaskWidth; i = i + 1) begin
  73:           if (b_wmask[i]) begin
  74:             mem[b_addr_i][i*DataBitsPerMask +: DataBitsPerMask] <=
  75:               b_wdata_i[i*DataBitsPerMask +: DataBitsPerMask];
  76:           end
  77:         end
  78:       end else begin
  79:         b_rdata_o <= mem[b_addr_i];
  80:       end
  81:     end
  82:   end
  83: 
  84:   `include "prim_util_memload.sv"
  85: 
  86: endmodule
  87: