From d786262ad645aca167c97db6c5dfa4e126fd5bd1 Mon Sep 17 00:00:00 2001 From: Kelvin Chung Date: Fri, 11 Jul 2025 16:42:35 +0100 Subject: [PATCH] external init implementation and testing --- passes/memory/memory.cc | 9 ++++-- passes/opt/opt_mem.cc | 40 ++++++++++++++----------- tests/opt/opt_mem_external.ys | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 tests/opt/opt_mem_external.ys diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc index d5dec6198..7dc38a507 100644 --- a/passes/memory/memory.cc +++ b/passes/memory/memory.cc @@ -31,7 +31,7 @@ struct MemoryPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" memory [-norom] [-nomap] [-nordff] [-nowiden] [-nosat] [-memx] [-no-rw-check] [-bram ] [selection]\n"); + log(" memory [-external-init] [-norom] [-nomap] [-nordff] [-nowiden] [-nosat] [-memx] [-no-rw-check] [-bram ] [selection]\n"); log("\n"); log("This pass calls all the other memory_* passes in a useful order:\n"); log("\n"); @@ -59,6 +59,7 @@ struct MemoryPass : public Pass { bool flag_nomap = false; bool flag_nordff = false; bool flag_memx = false; + string opt_mem_opts; string memory_dff_opts; string memory_bram_opts; string memory_share_opts; @@ -68,6 +69,10 @@ struct MemoryPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-external-init") { + opt_mem_opts += " -external-init"; + continue; + } if (args[argidx] == "-norom") { flag_norom = true; continue; @@ -105,7 +110,7 @@ struct MemoryPass : public Pass { } extra_args(args, argidx, design); - Pass::call(design, "opt_mem"); + Pass::call(design, "opt_mem" + opt_mem_opts); Pass::call(design, "opt_mem_priority"); Pass::call(design, "opt_mem_feedback"); if (!flag_norom) diff --git a/passes/opt/opt_mem.cc b/passes/opt/opt_mem.cc index f8354c960..64ba66301 100644 --- a/passes/opt/opt_mem.cc +++ b/passes/opt/opt_mem.cc @@ -17,16 +17,16 @@ * */ -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/mem.h" #include "kernel/ff.h" +#include "kernel/mem.h" +#include "kernel/sigtools.h" +#include "kernel/yosys.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct OptMemPass : public Pass { - OptMemPass() : Pass("opt_mem", "optimize memories") { } + OptMemPass() : Pass("opt_mem", "optimize memories") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -35,17 +35,23 @@ struct OptMemPass : public Pass { log("\n"); log("This pass performs various optimizations on memories in the design.\n"); log("\n"); + log(" -external-init\n"); + log(" Assume memories are initialised externally, i.e. the memory\n"); + log(" is pre-populated so content is available even when there is no\n"); + log(" write within the circuit.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { log_header(design, "Executing OPT_MEM pass (optimize memories).\n"); + bool external_init = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - // if (args[argidx] == "-nomux") { - // mode_nomux = true; - // continue; - // } + if (args[argidx] == "-external-init") { + external_init = true; + continue; + } break; } extra_args(args, argidx, design); @@ -102,7 +108,7 @@ struct OptMemPass : public Pass { } std::vector swizzle; for (int i = 0; i < mem.width; i++) { - if (!always_0[i] && !always_1[i]) { + if ((!always_0[i] && !always_1[i]) || external_init) { swizzle.push_back(i); continue; } @@ -118,7 +124,7 @@ struct OptMemPass : public Pass { bit = State::Sx; } // Reconnect read port data. - for (auto &port: mem.rd_ports) { + for (auto &port : mem.rd_ports) { for (int sub = 0; sub < (1 << port.wide_log2); sub++) { int bidx = sub * mem.width + i; if (!port.clk_enable) { @@ -161,11 +167,11 @@ struct OptMemPass : public Pass { continue; } if (GetSize(swizzle) != mem.width) { - for (auto &port: mem.wr_ports) { + for (auto &port : mem.wr_ports) { SigSpec new_data; SigSpec new_en; for (int sub = 0; sub < (1 << port.wide_log2); sub++) { - for (auto i: swizzle) { + for (auto i : swizzle) { new_data.append(port.data[sub * mem.width + i]); new_en.append(port.en[sub * mem.width + i]); } @@ -173,13 +179,13 @@ struct OptMemPass : public Pass { port.data = new_data; port.en = new_en; } - for (auto &port: mem.rd_ports) { + for (auto &port : mem.rd_ports) { SigSpec new_data; Const new_init; Const new_arst; Const new_srst; for (int sub = 0; sub < (1 << port.wide_log2); sub++) { - for (auto i: swizzle) { + for (auto i : swizzle) { int bidx = sub * mem.width + i; new_data.append(port.data[bidx]); new_init.bits().push_back(port.init_value[bidx]); @@ -192,15 +198,15 @@ struct OptMemPass : public Pass { port.arst_value = new_arst; port.srst_value = new_srst; } - for (auto &init: mem.inits) { + for (auto &init : mem.inits) { Const new_data; Const new_en; for (int s = 0; s < GetSize(init.data); s += mem.width) { - for (auto i: swizzle) { + for (auto i : swizzle) { new_data.bits().push_back(init.data[s + i]); } } - for (auto i: swizzle) { + for (auto i : swizzle) { new_en.bits().push_back(init.en[i]); } init.data = new_data; diff --git a/tests/opt/opt_mem_external.ys b/tests/opt/opt_mem_external.ys new file mode 100644 index 000000000..7b68dc2a7 --- /dev/null +++ b/tests/opt/opt_mem_external.ys @@ -0,0 +1,55 @@ +read_verilog << EOF +module Mem #( + parameter WIDTH = 8, + parameter SIZE = 16, + parameter IDX_SIZE = 16 +) ( + input wire [WIDTH-1:0] addr, + input wire [WIDTH-1:0] write_data, + input wire write_en, + + input wire clk, + + output reg [WIDTH-1:0] read_data, + +); + reg [WIDTH-1:0] mem[SIZE-1:0]; + + always @(posedge clk) begin + if (write_en) + mem[addr0[IDX_SIZE-1:0]] <= write_data; + + read_data <= mem[addr0[IDX_SIZE-1:0]]; + end + +endmodule + +module test_keep_at_instance (clk, addr, data); + +input wire clk; +input wire [15:0] addr; +output wire[7:0] data; + +Mem mem ( + .clk(clk), + .addr(addr), + .read_data(data), + .write_en(1'b0), + .write_data() +); + +endmodule + +EOF + +hierarchy -auto-top; +flatten; +proc; + +select -assert-any t:$mem* +opt_mem -external-init +select -assert-any t:$mem* + +select -assert-any t:$mem* +opt_mem +select -assert-none t:$mem*