hw/ip/prim_xilinx/rtl/prim_xilinx_rom.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: /**
   6:  * Implementation of a Read-Only Memory (ROM) primitive for Xilinx FPGAs
   7:  *
   8:  * This implementation of a ROM primitive is coded as outlined in UG 901 to
   9:  * enable Xilinx Vivado infer Block RAM (BRAM) or LUT RAM from it. No mapping
  10:  * target is forced; depending on the Width, Depth and other factors Vivado
  11:  * chooses a mapping target.
  12:  *
  13:  * It is possible to force the mapping to BRAM or distributed RAM by using the
  14:  * ROM_STYLE directive in an XDC file.
  15:  */
  16: module prim_xilinx_rom #(
  17:   parameter  int Width     = 32,
  18:   parameter  int Depth     = 2048, // 8kB default
  19:   parameter  int Aw        = $clog2(Depth)
  20: ) (
  21:   input                        clk_i,
  22:   input        [Aw-1:0]        addr_i,
  23:   input                        cs_i,
  24:   output logic [Width-1:0]     dout_o,
  25:   output logic                 dvalid_o
  26: 
  27: );
  28: 
  29:   `ifdef ROM_INIT_FILE
  30:    // Only create an actual ROM block if ROM data is specified
  31:    //
  32:    // Xilinx Vivado infers a BRAM or LUTRAM from the ROM code below only if mem
  33:    // is actually being written to through $readmemh(). If no ROM_INIT_FILE is
  34:    // given and hence the mem initialization is missing, registers are inferred
  35:    // instead. This severely degrades the synthesis quality for no good reason.
  36:    logic [Width-1:0] mem [Depth];
  37: 
  38:    localparam MEM_FILE = `"`ROM_INIT_FILE`";
  39:    initial
  40:    begin
  41:       $display("Initializing ROM from %s", MEM_FILE);
  42:       $readmemh(MEM_FILE, mem);
  43:    end
  44: 
  45:   always_ff @(posedge clk_i) begin
  46:     if (cs_i) begin
  47:       dout_o <= mem[addr_i];
  48:     end
  49:   end
  50:   `else
  51:     // ROM is not initialized
  52:     always_ff @(posedge clk_i) begin
  53:       dout_o <= '0;
  54:     end
  55:   `endif
  56: 
  57:   always_ff @(posedge clk_i) begin
  58:     dvalid_o <= cs_i;
  59:   end
  60: 
  61: 
  62:   ////////////////
  63:   // ASSERTIONS //
  64:   ////////////////
  65: 
  66:   // Control Signals should never be X
  67:   `ASSERT(noXOnCsI, !$isunknown(cs_i), clk_i, '0)
  68: 
  69: endmodule
  70: