mirror of https://github.com/YosysHQ/yosys.git
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.
This commit is contained in:
parent
fd306b0520
commit
7670a89e1f
|
@ -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()) {
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue