hw/ip/prim_generic/rtl/prim_generic_ram_1p.sv Cov: 100%

   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 single-port SRAM model
   6: 
   7: module prim_generic_ram_1p #(
   8:   parameter  int Width           = 32, // bit
   9:   parameter  int Depth           = 128,
  10:   parameter  int DataBitsPerMask = 1, // Number of data bits per bit of write mask
  11:   localparam int Aw              = $clog2(Depth)  // derived parameter
  12: ) (
  13:   input clk_i,
  14:   input rst_ni,       // Memory content reset
  15: 
  16:   input                    req_i,
  17:   input                    write_i,
  18:   input        [Aw-1:0]    addr_i,
  19:   input        [Width-1:0] wdata_i,
  20:   input        [Width-1:0] wmask_i,
  21:   output logic             rvalid_o,
  22:   output logic [Width-1:0] rdata_o
  23: );
  24: 
  25:   // Width of internal write mask. Note wmask_i input into the module is always assumed
  26:   // to be the full bit mask
  27:   localparam int MaskWidth = Width / DataBitsPerMask;
  28: 
  29:   logic [Width-1:0] mem [Depth];
  30:   logic [MaskWidth-1:0] wmask;
  31: 
  32:   always_comb begin
  33:     for (int i=0; i < MaskWidth; i = i + 1) begin : create_wmask
  34:       wmask[i] = &wmask_i[i*DataBitsPerMask +: DataBitsPerMask];
  35:     end
  36:   end
  37: 
  38:   // using always instead of always_ff to avoid 'ICPD  - illegal combination of drivers' error
  39:   // thrown when using $readmemh system task to backdoor load an image
  40:   always @(posedge clk_i) begin
  41:     if (req_i) begin
  42:       if (write_i) begin
  43:         for (int i=0; i < MaskWidth; i = i + 1) begin
  44:           if (wmask[i]) begin
  45:             mem[addr_i][i*DataBitsPerMask +: DataBitsPerMask] <=
  46:               wdata_i[i*DataBitsPerMask +: DataBitsPerMask];
  47:           end
  48:         end
  49:       end else begin
  50:         rdata_o <= mem[addr_i];
  51:       end
  52:     end
  53:   end
  54: 
  55:   always_ff @(posedge clk_i, negedge rst_ni) begin
  56:     if (!rst_ni) begin
  57:       rvalid_o <= '0;
  58:     end else begin
  59:       rvalid_o <= req_i & ~write_i;
  60:     end
  61:   end
  62: 
  63:   `ifdef VERILATOR
  64:     // Task for loading 'mem' with SystemVerilog system task $readmemh()
  65:     export "DPI-C" task simutil_verilator_memload;
  66:     // Function for setting a specific 32 bit element in |mem|
  67:     // Returns 1 (true) for success, 0 (false) for errors.
  68:     export "DPI-C" function simutil_verilator_set_mem;
  69: 
  70:     task simutil_verilator_memload;
  71:       input string file;
  72:       $readmemh(file, mem);
  73:     endtask
  74: 
  75:     // TODO: Allow 'val' to have other widths than 32 bit
  76:     function int simutil_verilator_set_mem(input int index,
  77:                                            input logic[31:0] val);
  78:       if (index >= Depth) begin
  79:         return 0;
  80:       end
  81: 
  82:       mem[index] = val;
  83:       return 1;
  84:     endfunction
  85:   `endif
  86: 
  87:   `ifdef SRAM_INIT_FILE
  88:     localparam MEM_FILE = `"`SRAM_INIT_FILE`";
  89:     initial begin
  90:       $display("Initializing SRAM from %s", MEM_FILE);
  91:       $readmemh(MEM_FILE, mem);
  92:     end
  93:   `endif
  94: endmodule
  95: