From: Marcelina Kościelnicka Date: Thu, 12 Aug 2021 22:43:15 +0000 (+0200) Subject: Add opt_mem_widen pass. X-Git-Tag: yosys-0.10~41 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f7913285067ed30bf5087f265db7e0bd523af2b6;p=yosys.git Add opt_mem_widen pass. If all of us are wide, then none of us are! --- diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc index bc1b19d00..bac547c1a 100644 --- a/passes/memory/memory.cc +++ b/passes/memory/memory.cc @@ -41,6 +41,7 @@ struct MemoryPass : public Pass { log(" memory_dff (skipped if called with -nordff or -memx)\n"); log(" opt_clean\n"); log(" memory_share [-nowiden] [-nosat]\n"); + log(" opt_mem_widen\n"); log(" memory_memx (when called with -memx)\n"); log(" opt_clean\n"); log(" memory_collect\n"); @@ -100,6 +101,7 @@ struct MemoryPass : public Pass { Pass::call(design, "memory_dff"); Pass::call(design, "opt_clean"); Pass::call(design, "memory_share" + memory_share_opts); + Pass::call(design, "opt_mem_widen"); if (flag_memx) Pass::call(design, "memory_memx"); Pass::call(design, "opt_clean"); diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index d8eb2f0b9..4e52ad8da 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -4,6 +4,7 @@ OBJS += passes/opt/opt_merge.o OBJS += passes/opt/opt_mem.o OBJS += passes/opt/opt_mem_feedback.o OBJS += passes/opt/opt_mem_priority.o +OBJS += passes/opt/opt_mem_widen.o OBJS += passes/opt/opt_muxtree.o OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_dff.o diff --git a/passes/opt/opt_mem_widen.cc b/passes/opt/opt_mem_widen.cc new file mode 100644 index 000000000..95e01088c --- /dev/null +++ b/passes/opt/opt_mem_widen.cc @@ -0,0 +1,107 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2021 Marcelina Kościelnicka + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/mem.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct OptMemWidenPass : public Pass { + OptMemWidenPass() : Pass("opt_mem_widen", "optimize memories where all ports are wide") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_mem_widen [options] [selection]\n"); + log("\n"); + log("This pass looks for memories where all ports are wide and adjusts the base\n"); + log("memory width up until that stops being the case.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing OPT_MEM_WIDEN pass (optimize memories where all ports are wide).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + // if (args[argidx] == "-nomux") { + // mode_nomux = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + int total_count = 0; + for (auto module : design->selected_modules()) { + for (auto &mem : Mem::get_selected_memories(module)) { + // If the memory has no read ports, opt_clean will remove it + // instead. + if (mem.rd_ports.empty()) + continue; + int factor_log2 = mem.rd_ports[0].wide_log2; + for (auto &port : mem.rd_ports) + if (port.wide_log2 < factor_log2) + factor_log2 = port.wide_log2; + for (auto &port : mem.wr_ports) + if (port.wide_log2 < factor_log2) + factor_log2 = port.wide_log2; + if (factor_log2 == 0) + continue; + log("Widening base width of memory %s in module %s by factor %d.\n", log_id(mem.memid), log_id(module->name), 1 << factor_log2); + total_count++; + // The inits are too messy to expand one-by-one, for they may + // collide with one another after expansion. Just hit it with + // a hammer. + bool has_init = !mem.inits.empty(); + Const init_data; + if (has_init) { + init_data = mem.get_init_data(); + mem.clear_inits(); + } + mem.width <<= factor_log2; + mem.size >>= factor_log2; + mem.start_offset >>= factor_log2; + if (has_init) { + MemInit new_init; + new_init.addr = mem.start_offset; + new_init.data = init_data; + new_init.en = Const(State::S1, mem.width); + mem.inits.push_back(new_init); + } + for (auto &port : mem.rd_ports) { + port.wide_log2 -= factor_log2; + port.addr = port.addr.extract_end(factor_log2); + } + for (auto &port : mem.wr_ports) { + port.wide_log2 -= factor_log2; + port.addr = port.addr.extract_end(factor_log2); + } + mem.emit(); + } + } + + if (total_count) + design->scratchpad_set_bool("opt.did_something", true); + log("Performed a total of %d transformations.\n", total_count); + } +} OptMemWidenPass; + +PRIVATE_NAMESPACE_END diff --git a/tests/memories/wide_all.v b/tests/memories/wide_all.v new file mode 100644 index 000000000..f7bc3e5ce --- /dev/null +++ b/tests/memories/wide_all.v @@ -0,0 +1,36 @@ +// expect-wr-ports 2 +// expect-rd-ports 1 +// expect-wr-wide-continuation 2'10 + +module test( + input clk, + input [3:0] we, + input [6:0] ra, + input [5:0] wa, + input [31:0] wd, + output [15:0] rd +); + +reg [7:0] mem[3:254]; + +assign rd[7:0] = mem[{ra, 1'b0}]; +assign rd[15:0] = mem[{ra, 1'b1}]; + +initial begin + mem[5] = 8'h12; + mem[6] = 8'h34; + mem[7] = 8'h56; +end + +always @(posedge clk) begin + if (we[0]) + mem[{wa, 2'b00}] <= wd[7:0]; + if (we[1]) + mem[{wa, 2'b01}] <= wd[15:8]; + if (we[2]) + mem[{wa, 2'b10}] <= wd[23:16]; + if (we[3]) + mem[{wa, 2'b11}] <= wd[31:24]; +end + +endmodule