iopadmap: Look harder for already-present buffers. (#1731)

iopadmap: Look harder for already-present buffers.

Fixes #1720.
This commit is contained in:
Marcelina Kościelnicka 2020-03-02 21:40:09 +01:00 committed by GitHub
parent 4f889b2f57
commit 968956badb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 18 deletions

View File

@ -83,6 +83,20 @@ struct IopadmapPass : public Pass {
log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n");
log("\n");
}
void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) {
if (modules_processed.count(module))
return;
for (auto cell : module->cells()) {
Module *submodule = design->module(cell->type);
if (!submodule)
continue;
module_queue(design, submodule, modules_sorted, modules_processed);
}
modules_sorted.push_back(module);
modules_processed.insert(module);
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
@ -172,23 +186,50 @@ struct IopadmapPass : public Pass {
if (!tinoutpad_portname_pad.empty())
ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname_pad)));
for (auto module : design->modules())
if (module->get_blackbox_attribute())
for (auto wire : module->wires())
if (wire->get_bool_attribute("\\iopad_external_pin"))
ignore.insert(make_pair(module->name, wire->name));
// Recursively collect list of (module, port, bit) triples that already have buffers.
pool<pair<IdString, pair<IdString, int>>> buf_ports;
// Process submodules before module using them.
std::vector<Module *> modules_sorted;
pool<Module *> modules_processed;
for (auto module : design->selected_modules())
module_queue(design, module, modules_sorted, modules_processed);
for (auto module : modules_sorted)
{
pool<SigBit> buf_bits;
SigMap sigmap(module);
// Collect explicitly-marked already-buffered SigBits.
for (auto wire : module->wires())
if (wire->get_bool_attribute("\\iopad_external_pin") || ignore.count(make_pair(module->name, wire->name)))
for (int i = 0; i < GetSize(wire); i++)
buf_bits.insert(sigmap(SigBit(wire, i)));
// Collect SigBits connected to already-buffered ports.
for (auto cell : module->cells())
for (auto port : cell->connections())
for (int i = 0; i < port.second.size(); i++)
if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i))))
buf_bits.insert(sigmap(port.second[i]));
// Now fill buf_ports.
for (auto wire : module->wires())
if (wire->port_input || wire->port_output)
for (int i = 0; i < GetSize(wire); i++)
if (buf_bits.count(sigmap(SigBit(wire, i)))) {
buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
log("Marking already mapped port: %s.%s[%d].\n", log_id(module), log_id(wire), i);
}
}
// Now do the actual buffer insertion.
for (auto module : design->selected_modules())
{
pool<SigBit> skip_wire_bits;
dict<Wire *, dict<int, pair<Cell *, IdString>>> rewrite_bits;
for (auto cell : module->cells())
for (auto port : cell->connections())
if (ignore.count(make_pair(cell->type, port.first)))
for (auto bit : port.second)
skip_wire_bits.insert(bit);
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{
dict<SigBit, Cell *> tbuf_bits;
@ -234,7 +275,7 @@ struct IopadmapPass : public Pass {
SigBit wire_bit(wire, i);
Cell *tbuf_cell = nullptr;
if (skip_wire_bits.count(wire_bit))
if (buf_ports.count(make_pair(module->name, make_pair(wire->name, i))))
continue;
if (tbuf_bits.count(wire_bit))
@ -282,7 +323,6 @@ struct IopadmapPass : public Pass {
cell->setPort(RTLIL::escape_id(tinoutpad_portname_o), wire_bit);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_i), data_sig);
}
skip_wire_bits.insert(wire_bit);
if (!tinoutpad_portname_pad.empty())
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(tinoutpad_portname_pad));
} else {
@ -298,10 +338,10 @@ struct IopadmapPass : public Pass {
module->remove(tbuf_cell);
module->connect(wire_bit, data_sig);
}
skip_wire_bits.insert(wire_bit);
if (!toutpad_portname_pad.empty())
rewrite_bits[wire][i] = make_pair(cell, RTLIL::escape_id(toutpad_portname_pad));
}
buf_ports.insert(make_pair(module->name, make_pair(wire->name, i)));
}
}
}
@ -315,7 +355,7 @@ struct IopadmapPass : public Pass {
pool<int> skip_bit_indices;
for (int i = 0; i < GetSize(wire); i++)
if (skip_wire_bits.count(SigBit(wire, i)))
if (buf_ports.count(make_pair(module->name, make_pair(wire->name, i))))
skip_bit_indices.insert(i);
if (GetSize(wire) == GetSize(skip_bit_indices))

View File

@ -4,12 +4,15 @@ module obuf (input i, (* iopad_external_pin *) output o); endmodule
module obuft (input i, input oe, (* iopad_external_pin *) output o); endmodule
module iobuf (input i, input oe, output o, (* iopad_external_pin *) inout io); endmodule
module buf_inside (input i, output o);
obuf b (.i(i), .o(o));
endmodule
module a(input i, output o);
assign o = i;
endmodule
module b(input i, output o);
assign o = i;
ibuf b (.i(i), .o(o));
endmodule
@ -42,12 +45,22 @@ assign io = i;
assign o = io;
endmodule
module i(input i, output o);
buf_inside b (.i(i), .o(o));
endmodule
module j(input i, output o);
wire tmp;
obuf b (.i(i), .o(tmp));
assign o = tmp;
endmodule
EOT
opt_clean
tribuf
simplemap
iopadmap -bits -inpad ibuf o:i -outpad obuf i:o -toutpad obuft oe:i:o -tinoutpad iobuf oe:o:i:io
iopadmap -bits -inpad ibuf o:i -outpad obuf i:o -toutpad obuft oe:i:o -tinoutpad iobuf oe:o:i:io a b c d e f g h i j
opt_clean
select -assert-count 1 a/t:ibuf
@ -121,6 +134,12 @@ select -assert-count 1 h/t:ibuf
select -assert-count 1 h/t:iobuf
select -assert-count 1 h/t:obuf
select -assert-count 1 i/t:ibuf
select -assert-count 0 i/t:obuf
select -assert-count 1 j/t:ibuf
select -assert-count 1 j/t:obuf
# Check that \init attributes get moved from output buffer
# to buffer input