latch_scm.sv 3.85 KB
Newer Older
sakundu committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51

module latch_scm #(
  parameter ADDR_WIDTH    = 5,
  parameter DATA_WIDTH    = 32
) (
  input  logic                  clk,
  // Read port
  input  logic                  ReadEnable,
  input  logic [ADDR_WIDTH-1:0] ReadAddr,
  output logic [DATA_WIDTH-1:0] ReadData,
  // Write port
  input  logic                  WriteEnable,
  input  logic [ADDR_WIDTH-1:0] WriteAddr,
  input  logic [DATA_WIDTH-1:0] WriteData
);

  localparam NUM_WORDS = 2**ADDR_WIDTH;

  // Read address register, located at the input of the address decoder
  logic [ADDR_WIDTH-1:0] RAddrRegxDP;
  logic [NUM_WORDS-1:0]  RAddrOneHotxD;

  logic [DATA_WIDTH-1:0] MemContentxDP[NUM_WORDS];

  logic [NUM_WORDS-1:0]  WAddrOneHotxD;
  logic [NUM_WORDS-1:0]  ClocksxC;
  logic [DATA_WIDTH-1:0] WDataIntxD;

  logic                  clk_int;

  int unsigned i;
  int unsigned j;
  int unsigned k;
  int unsigned l;
  int unsigned m;

  genvar x;
  genvar y;

  tc_clk_gating CG_WE_GLOBAL (
    .clk_o     (clk_int    ),
    .en_i      (WriteEnable),
    .test_en_i (1'b0       ),
    .clk_i     (clk        )
  );

  //-----------------------------------------------------------------------------
  //-- READ : Read address register
  //-----------------------------------------------------------------------------
  always_ff @(posedge clk) begin : p_RAddrReg
    if(ReadEnable)
      RAddrRegxDP <= ReadAddr;
  end


  //-----------------------------------------------------------------------------
  //-- READ : Read address decoder RAD
  //-----------------------------------------------------------------------------
  always_comb begin : p_RAD
    RAddrOneHotxD = '0;
    RAddrOneHotxD[RAddrRegxDP] = 1'b1;
  end
  assign ReadData = MemContentxDP[RAddrRegxDP];


  //-----------------------------------------------------------------------------
  //-- WRITE : Write Address Decoder (WAD), combinatorial process
  //-----------------------------------------------------------------------------
  always_comb begin : p_WAD
    for(i=0; i<NUM_WORDS; i++) begin : p_WordIter
      if ( (WriteEnable == 1'b1 ) && (WriteAddr == i) )
        WAddrOneHotxD[i] = 1'b1;
      else
        WAddrOneHotxD[i] = 1'b0;
    end
  end

  //-----------------------------------------------------------------------------
  //-- WRITE : Clock gating (if integrated clock-gating cells are available)
  //-----------------------------------------------------------------------------
  generate
    for(x=0; x<NUM_WORDS; x++) begin : CG_CELL_WORD_ITER
      tc_clk_gating CG_Inst (
        .clk_o     ( ClocksxC[x]      ),
        .en_i      ( WAddrOneHotxD[x] ),
        .test_en_i ( 1'b0             ),
        .clk_i     ( clk_int          )
      );
    end
  endgenerate

  //-----------------------------------------------------------------------------
  // WRITE : SAMPLE INPUT DATA
  //---------------------------------------------------------------------------
  always_ff @(posedge clk) begin : sample_waddr
    if(WriteEnable)
      WDataIntxD <= WriteData;
  end


  //-----------------------------------------------------------------------------
  //-- WRITE : Write operation
  //-----------------------------------------------------------------------------
  //-- Generate M = WORDS sequential processes, each of which describes one
  //-- word of the memory. The processes are synchronized with the clocks
  //-- ClocksxC(i), i = 0, 1, ..., M-1
  //-- Use active low, i.e. transparent on low latches as storage elements
  //-- Data is sampled on rising clock edge

  /* verilator lint_off NOLATCH */
  always_latch begin : latch_wdata
    for(k=0; k<NUM_WORDS; k++) begin : w_WordIter
      if( ClocksxC[k] == 1'b1)
        MemContentxDP[k] <= WDataIntxD;
    end
  end
  /* verilator lint_on NOLATCH */

endmodule