iopadmap: Look harder for already-present buffers. (#1731)
authorMarcelina Koƛcielnicka <mwk@0x04.net>
Mon, 2 Mar 2020 20:40:09 +0000 (21:40 +0100)
committerGitHub <noreply@github.com>
Mon, 2 Mar 2020 20:40:09 +0000 (21:40 +0100)
iopadmap: Look harder for already-present buffers.

Fixes #1720.

passes/techmap/iopadmap.cc
tests/techmap/iopadmap.ys

index a6e4fac14e03531d87e19448fed3030793cb4cb6..f63012d1a1147a70f27c046611f8fbaa00b87eab 100644 (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,22 +186,49 @@ 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> skip_wire_bits;
-                       dict<Wire *, dict<int, pair<Cell *, IdString>>> rewrite_bits;
+                       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())
-                               if (ignore.count(make_pair(cell->type, port.first)))
-                                       for (auto bit : port.second)
-                                               skip_wire_bits.insert(bit);
+                       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())
+               {
+                       dict<Wire *, dict<int, pair<Cell *, IdString>>> rewrite_bits;
 
                        if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
                        {
@@ -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))
index 0bcc71ccea488c8d4c49973b2d41e07f9b950e0c..25ea94dfce2082360f8bca8f304585504552dbe0 100644 (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