diff options
author | Marcelina KoĆcielnicka <mwk@0x04.net> | 2020-10-08 13:33:47 +0200 |
---|---|---|
committer | Marcelina KoĆcielnicka <mwk@0x04.net> | 2020-10-08 18:05:51 +0200 |
commit | 7670a89e1fde7d0774695ab81031a90fafdf56b9 (patch) | |
tree | 063e90c411b1e76e395460c27402a9a504b7f00d | |
parent | fd306b0520ac42323cbfacfa3a41e7a7a9379ec0 (diff) | |
download | yosys-7670a89e1fde7d0774695ab81031a90fafdf56b9.tar.gz yosys-7670a89e1fde7d0774695ab81031a90fafdf56b9.tar.bz2 yosys-7670a89e1fde7d0774695ab81031a90fafdf56b9.zip |
opt_clean: Better memory handling.
Previously, `$memwr` and `$meminit` cells were always preserved (along
with the memory itself). With this change, they are instead part of the
main cell mark-and-sweep pass: a memory (and its `$meminit` and `$memwr`
cells) is only preserved iff any associated `$memrd` cell needs to be
preserved.
-rw-r--r-- | passes/opt/opt_clean.cc | 53 | ||||
-rw-r--r-- | tests/opt/opt_clean_mem.ys | 49 |
2 files changed, 94 insertions, 8 deletions
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index bd9856e81..883374cf6 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -55,7 +55,7 @@ struct keep_cache_t if (!module->get_bool_attribute(ID::keep)) { bool found_keep = false; for (auto cell : module->cells()) - if (query(cell, true /* ignore_specify_mem */)) { + if (query(cell, true /* ignore_specify */)) { found_keep = true; break; } @@ -70,12 +70,12 @@ struct keep_cache_t return cache[module]; } - bool query(Cell *cell, bool ignore_specify_mem = false) + bool query(Cell *cell, bool ignore_specify = false) { if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) return true; - if (!ignore_specify_mem && cell->type.in(ID($memwr), ID($meminit), ID($specify2), ID($specify3), ID($specrule))) + if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule))) return true; if (cell->has_keep_attr()) @@ -95,6 +95,8 @@ int count_rm_cells, count_rm_wires; void rmunused_module_cells(Module *module, bool verbose) { SigMap sigmap(module); + dict<IdString, pool<Cell*>> mem2cells; + pool<IdString> mem_unused; pool<Cell*> queue, unused; pool<SigBit> used_raw_bits; dict<SigBit, pool<Cell*>> wire2driver; @@ -108,6 +110,17 @@ void rmunused_module_cells(Module *module, bool verbose) } } + for (auto &it : module->memories) { + mem_unused.insert(it.first); + } + + for (Cell *cell : module->cells()) { + if (cell->type.in(ID($memwr), ID($meminit))) { + IdString mem_id = cell->getParam(ID::MEMID).decode_string(); + mem2cells[mem_id].insert(cell); + } + } + for (auto &it : module->cells_) { Cell *cell = it.second; for (auto &it2 : cell->connections()) { @@ -145,17 +158,33 @@ void rmunused_module_cells(Module *module, bool verbose) while (!queue.empty()) { pool<SigBit> bits; - for (auto cell : queue) - for (auto &it : cell->connections()) - if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first)) - for (auto bit : sigmap(it.second)) - bits.insert(bit); + pool<IdString> mems; + for (auto cell : queue) { + for (auto &it : cell->connections()) + if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first)) + for (auto bit : sigmap(it.second)) + bits.insert(bit); + + if (cell->type == ID($memrd)) { + IdString mem_id = cell->getParam(ID::MEMID).decode_string(); + if (mem_unused.count(mem_id)) { + mem_unused.erase(mem_id); + mems.insert(mem_id); + } + } + } queue.clear(); + for (auto bit : bits) for (auto c : wire2driver[bit]) if (unused.count(c)) queue.insert(c), unused.erase(c); + + for (auto mem : mems) + for (auto c : mem2cells[mem]) + if (unused.count(c)) + queue.insert(c), unused.erase(c); } unused.sort(RTLIL::sort_by_name_id<RTLIL::Cell>()); @@ -168,6 +197,14 @@ void rmunused_module_cells(Module *module, bool verbose) count_rm_cells++; } + for (auto it : mem_unused) + { + if (verbose) + log_debug(" removing unused memory `%s'.\n", it.c_str()); + delete module->memories.at(it); + module->memories.erase(it); + } + for (auto &it : module->cells_) { Cell *cell = it.second; for (auto &it2 : cell->connections()) { diff --git a/tests/opt/opt_clean_mem.ys b/tests/opt/opt_clean_mem.ys new file mode 100644 index 000000000..b35b15871 --- /dev/null +++ b/tests/opt/opt_clean_mem.ys @@ -0,0 +1,49 @@ +read_verilog <<EOT +module top(...); + +input [7:0] wa; +input [7:0] ra1; +input [7:0] ra2; +input [7:0] wd; +input clk; +wire [7:0] rd1; +wire [7:0] rd2; + +reg [7:0] mem[0:7]; + +always @(posedge clk) + mem[wa] <= wd; +assign rd1 = mem[ra1]; +assign rd2 = mem[ra2]; + +initial mem[8'h12] = 8'h34; + +endmodule +EOT + +proc +memory_dff + +select -assert-count 2 t:$memrd +select -assert-count 1 t:$memwr +select -assert-count 1 t:$meminit +design -save orig + +opt_clean +select -assert-none t:$memrd +select -assert-none t:$memwr +select -assert-none t:$meminit + +design -load orig +expose top/rd1 +opt_clean +select -assert-count 1 t:$memrd +select -assert-count 1 t:$memwr +select -assert-count 1 t:$meminit + +design -load orig +expose top/rd1 top/rd2 +opt_clean +select -assert-count 2 t:$memrd +select -assert-count 1 t:$memwr +select -assert-count 1 t:$meminit |