// 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