Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HW]: Add mem_multibanked_pwrgate for correct power management #246

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ sources:
- src/lfsr_8bit.sv
- src/lossy_valid_to_stream.sv
- src/mv_filter.sv
- src/mem_multibank_pwrgate.sv
- src/onehot_to_bin.sv
- src/plru_tree.sv
- src/passthrough_stream_fifo.sv
Expand Down Expand Up @@ -129,6 +130,7 @@ sources:
- test/fifo_tb.sv
- test/graycode_tb.sv
- test/id_queue_tb.sv
- test/mem_multibank_pwrgate_tb.sv
- test/passthrough_stream_fifo_tb.sv
- test/popcount_tb.sv
- test/rr_arb_tree_tb.sv
Expand Down
200 changes: 200 additions & 0 deletions src/mem_multibank_pwrgate.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// Copyright 2024 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Lorenzo Leone <[email protected]>

// ## Description:
// A wrapper for `tc_sram_impl` that instantiates logic banks with retention mode
// or power-off capability.
// This module can be used for power-aware simulations, with control signals driven
// directly by UPF signals.
//
// ## Goal:
// In a memory with multiple banks that support power gating and retention,
// each bank’s addressing must ensure that interleaving remains intact. During retention
// or power-off states, only contiguous addresses should be switched.
// The memory should always appear as a set of contiguous addresses, with no gaps in the
// address mapping.
// This module is responsible for managing the correct memory addressing
//
module mem_multibank_pwrgate #(
parameter int unsigned NumWords = 32'd1024, // Number of Words in data array
parameter int unsigned DataWidth = 32'd128, // Data signal width
parameter int unsigned ByteWidth = 32'd8, // Width of a data byte
parameter int unsigned NumPorts = 32'd2, // Number of read and write ports
parameter int unsigned Latency = 32'd1, // Latency when the read data is available
parameter int unsigned NumLogicBanks = 32'd1, // Logic bank for Power Management
parameter SimInit = "none", // Simulation initialization

Check warning on line 28 in src/mem_multibank_pwrgate.sv

View workflow job for this annotation

GitHub Actions / verible-verilog-lint

[verible-verilog-lint] src/mem_multibank_pwrgate.sv#L28

Explicitly define a storage type for every parameter and localparam, (SimInit). [Style: constants] [explicit-parameter-storage-type]
Raw output
message:"Explicitly define a storage type for every parameter and localparam, (SimInit). [Style: constants] [explicit-parameter-storage-type]"  location:{path:"./src/mem_multibank_pwrgate.sv"  range:{start:{line:28  column:28}}}  severity:WARNING  source:{name:"verible-verilog-lint"  url:"https://github.com/chipsalliance/verible"}
parameter bit PrintSimCfg = 1'b0, // Print configuration
parameter ImplKey = "none", // Reference to specific implementation

Check warning on line 30 in src/mem_multibank_pwrgate.sv

View workflow job for this annotation

GitHub Actions / verible-verilog-lint

[verible-verilog-lint] src/mem_multibank_pwrgate.sv#L30

Explicitly define a storage type for every parameter and localparam, (ImplKey). [Style: constants] [explicit-parameter-storage-type]
Raw output
message:"Explicitly define a storage type for every parameter and localparam, (ImplKey). [Style: constants] [explicit-parameter-storage-type]"  location:{path:"./src/mem_multibank_pwrgate.sv"  range:{start:{line:30  column:28}}}  severity:WARNING  source:{name:"verible-verilog-lint"  url:"https://github.com/chipsalliance/verible"}
// DEPENDENT PARAMETERS, DO NOT OVERWRITE!
parameter int unsigned AddrWidth = (NumWords > 32'd1) ? $clog2(NumWords) : 32'd1,
parameter int unsigned BeWidth = (DataWidth + ByteWidth - 32'd1) / ByteWidth, // ceil_div
parameter type addr_t = logic [AddrWidth-1:0],
parameter type data_t = logic [DataWidth-1:0],
parameter type be_t = logic [BeWidth-1:0]
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// input ports
input logic [ NumPorts-1:0] req_i, // request
input logic [ NumPorts-1:0] we_i, // write enable
input addr_t [ NumPorts-1:0] addr_i, // request address
input data_t [ NumPorts-1:0] wdata_i, // write data
input be_t [ NumPorts-1:0] be_i, // write byte enable
input logic [NumLogicBanks-1:0] deepsleep_i, // deep sleep enable
input logic [NumLogicBanks-1:0] powergate_i, // power gate enable
// output ports
output data_t [ NumPorts-1:0] rdata_o // read data
);

// Implementation type for Power Gating and Deppesleep ports
typedef struct packed {
logic deepsleep;
logic powergate;
} impl_in_t;


if (NumLogicBanks == 32'd0) begin : gen_no_logic_bank
$fatal("Error: %d logic banks are not supported", NumLogicBanks);
niwis marked this conversation as resolved.
Show resolved Hide resolved
end else if (NumLogicBanks == 32'd1) begin : gen_simple_sram
tc_sram_impl #(
.NumWords (NumWords),
.DataWidth (DataWidth),
.ByteWidth (ByteWidth),
.NumPorts (NumPorts),
.Latency (Latency),
.SimInit (SimInit),
.PrintSimCfg(PrintSimCfg),
.ImplKey (ImplKey),
.impl_in_t (impl_in_t),
.impl_out_t (impl_in_t)
) i_tc_sram_impl (
.clk_i,
.rst_ni,
.impl_i({deepsleep_i, powergate_i}),
.impl_o(),
.req_i,
.we_i,
.addr_i,
.wdata_i,
.be_i,
.rdata_o
);

end else begin : gen_logic_bank // block: gen_simple_sram
localparam int unsigned LogicBankSize = NumWords / NumLogicBanks;
localparam int unsigned BankSelWidth = (NumLogicBanks > 32'd1) ? $clog2(
NumLogicBanks
) : 32'd1;
niwis marked this conversation as resolved.
Show resolved Hide resolved

if (LogicBankSize != 2 ** (AddrWidth - BankSelWidth))
$fatal("Logic Bank size is not a power of two: UNSUPPORTED ");
niwis marked this conversation as resolved.
Show resolved Hide resolved

// Signals from/to logic banks
logic [NumLogicBanks-1:0][ NumPorts-1:0] req_cut;
logic [NumLogicBanks-1:0][ NumPorts-1:0] we_cut;
logic [NumLogicBanks-1:0][ NumPorts-1:0][AddrWidth-BankSelWidth-1:0] addr_cut;
data_t [NumLogicBanks-1:0][ NumPorts-1:0] wdata_cut;
be_t [NumLogicBanks-1:0][ NumPorts-1:0] be_cut;
data_t [NumLogicBanks-1:0][ NumPorts-1:0] rdata_cut;

// Signals to select the right bank
logic [ NumPorts-1:0][BankSelWidth-1:0] bank_sel;
niwis marked this conversation as resolved.
Show resolved Hide resolved
logic [NumPorts-1:0][Latency-1:0][BankSelWidth-1:0] out_mux_sel_d, out_mux_sel_q;
niwis marked this conversation as resolved.
Show resolved Hide resolved

// Identify bank looking at the BankSelWidth-th MSBs of the Address
for (genvar PortIdx = 0; PortIdx < NumPorts; PortIdx++) begin : gen_bank_sel
assign bank_sel[PortIdx] = addr_i[PortIdx][AddrWidth-1-:BankSelWidth];
end

// Read Data Mux Logic:
//
// If the memory has Latency != 0, the read data will arive after a certain delay.
// During this time, the bank_select signal must be stored in order to
// correctly select the output bank after the expected latency.
if (Latency == 32'd0) begin : gen_no_latency
for (genvar PortIdx = 0; PortIdx < NumPorts; PortIdx++) begin : gen_read_mux_signals
assign rdata_o[PortIdx] = rdata_cut[bank_sel[PortIdx]][PortIdx];
end
end else begin : gen_read_latency
always_comb begin
for (int PortIdx = 0; PortIdx < NumPorts; PortIdx++) begin : gen_read_mux_signals
rdata_o[PortIdx] = rdata_cut[out_mux_sel_q[PortIdx][0]][PortIdx];
for (int shift_idx = 0; shift_idx < (Latency - 1); shift_idx++) begin : gen_shift
out_mux_sel_d[PortIdx][shift_idx] = out_mux_sel_q[PortIdx][shift_idx+1];
end
out_mux_sel_d[PortIdx][Latency-1] = bank_sel[PortIdx];
end
end

always_ff @(posedge clk_i or negedge rst_ni) begin
for (int PortIdx = 0; PortIdx < NumPorts; PortIdx++) begin
if (!rst_ni) begin
out_mux_sel_q[PortIdx] <= '0;
end else begin
for (int shift_idx = 0; shift_idx < Latency; shift_idx++) begin
out_mux_sel_q[PortIdx][shift_idx] <= out_mux_sel_d[PortIdx][shift_idx];
end
end
end
niwis marked this conversation as resolved.
Show resolved Hide resolved
end
end : gen_read_latency

// Write data Mux Logic
//
for (genvar BankIdx = 0; BankIdx < NumLogicBanks; BankIdx++) begin : gen_logic_bank
for (genvar PortIdx = 0; PortIdx < NumPorts; PortIdx++) begin: gen_port_write_logic
// DEMUX the input signals to the correct logic bank
// Assign req channel to the correct logic bank
assign req_cut[BankIdx][PortIdx] = req_i[PortIdx] && (bank_sel[PortIdx] == BankIdx);
// Assign lowest part of the address to the correct logic bank
assign addr_cut[BankIdx][PortIdx] = req_cut[BankIdx][PortIdx] ?
addr_i[PortIdx][AddrWidth-BankSelWidth-1:0] : '0;
// Assign data to the correct logic bank
assign wdata_cut[BankIdx][PortIdx] = req_cut[BankIdx][PortIdx] ? wdata_i[PortIdx] : '0;
assign we_cut[BankIdx][PortIdx] = req_cut[BankIdx][PortIdx] ? we_i[PortIdx] : '0;
assign be_cut[BankIdx][PortIdx] = req_cut[BankIdx][PortIdx] ? be_i[PortIdx] : '0;
end

tc_sram_impl #(
.NumWords (LogicBankSize),
.DataWidth (DataWidth),
.ByteWidth (ByteWidth),
.NumPorts (NumPorts),
.Latency (Latency),
.SimInit (SimInit),
.PrintSimCfg(PrintSimCfg),
.ImplKey (ImplKey),
.impl_in_t (impl_in_t),
.impl_out_t (impl_in_t)
) i_tc_sram_impl (
.clk_i,
.rst_ni,
.impl_i ({deepsleep_i[BankIdx], powergate_i[BankIdx]}),
.impl_o (),
.req_i (req_cut[BankIdx]),
.we_i (we_cut[BankIdx]),
.addr_i (addr_cut[BankIdx]),
.wdata_i(wdata_cut[BankIdx]),
.be_i (be_cut[BankIdx]),
.rdata_o(rdata_cut[BankIdx])
);
end
end

// Trigger warnings when power signals (deepsleep_i and powergate_i) are not connected.
// Usually those signals must be linked through the UPF.
`ifndef VERILATOR
`ifndef TARGET_SYNTHESIS
initial begin
assert (!$isunknown(deepsleep_i))
else $warning("deepsleep_i has some unconnected signals");
assert (!$isunknown(powergate_i))
else $warning("powergate_i has some unconnected signals");
end
`endif
`endif
niwis marked this conversation as resolved.
Show resolved Hide resolved

endmodule //endmodule: mem_multibank_pwrgate
Loading
Loading