iopadmap: Add native support for negative-polarity output enable.
authorMarcelina Kościelnicka <mwk@0x04.net>
Tue, 9 Nov 2021 10:22:48 +0000 (11:22 +0100)
committerMarcelina Kościelnicka <mwk@0x04.net>
Tue, 9 Nov 2021 14:40:16 +0000 (15:40 +0100)
12 files changed:
passes/techmap/iopadmap.cc
techlibs/gowin/cells_map.v
techlibs/gowin/synth_gowin.cc
techlibs/machxo2/cells_map.v
techlibs/machxo2/cells_sim.v
techlibs/machxo2/synth_machxo2.cc
techlibs/nexus/cells_map.v
techlibs/nexus/synth_nexus.cc
techlibs/xilinx/cells_map.v
techlibs/xilinx/synth_xilinx.cc
tests/arch/machxo2/mux.ys
tests/arch/machxo2/tribuf.ys

index 45fa5f226da6ac52b06ea4f5b4bc7a7182c3b574..ce1988c492607254a2fa6d1bcd46bed697f6ad6d 100644 (file)
@@ -43,26 +43,28 @@ struct IopadmapPass : public Pass {
                log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
                log("the resulting cells to more sophisticated PAD cells.\n");
                log("\n");
-               log("    -inpad <celltype> <portname>[:<portname>]\n");
+               log("    -inpad <celltype> <in_port>[:<ext_port>]\n");
                log("        Map module input ports to the given cell type with the\n");
                log("        given output port name. if a 2nd portname is given, the\n");
                log("        signal is passed through the pad call, using the 2nd\n");
                log("        portname as the port facing the module port.\n");
                log("\n");
-               log("    -outpad <celltype> <portname>[:<portname>]\n");
-               log("    -inoutpad <celltype> <portname>[:<portname>]\n");
+               log("    -outpad <celltype> <out_port>[:<ext_port>]\n");
+               log("    -inoutpad <celltype> <io_port>[:<ext_port>]\n");
                log("        Similar to -inpad, but for output and inout ports.\n");
                log("\n");
-               log("    -toutpad <celltype> <portname>:<portname>[:<portname>]\n");
+               log("    -toutpad <celltype> <oe_port>:<out_port>[:<ext_port>]\n");
                log("        Merges $_TBUF_ cells into the output pad cell. This takes precedence\n");
                log("        over the other -outpad cell. The first portname is the enable input\n");
-               log("        of the tristate driver.\n");
+               log("        of the tristate driver, which can be prefixed with `~` for negative\n");
+               log("        polarity enable.\n");
                log("\n");
-               log("    -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n");
+               log("    -tinoutpad <celltype> <oe_port>:<in_port>:<out_port>[:<ext_port>]\n");
                log("        Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n");
                log("        over the other -inoutpad cell. The first portname is the enable input\n");
                log("        of the tristate driver and the 2nd portname is the internal output\n");
-               log("        buffering the external signal.\n");
+               log("        buffering the external signal.  Like with `-toutpad`, the enable can\n");
+               log("        be marked as negative polarity by prefixing the name with `~`.\n");
                log("\n");
                log("    -ignore <celltype> <portname>[:<portname>]*\n");
                log("        Skips mapping inputs/outputs that are already connected to given\n");
@@ -106,6 +108,7 @@ struct IopadmapPass : public Pass {
                std::string inoutpad_celltype, inoutpad_portname_io, inoutpad_portname_pad;
                std::string toutpad_celltype, toutpad_portname_oe, toutpad_portname_i, toutpad_portname_pad;
                std::string tinoutpad_celltype, tinoutpad_portname_oe, tinoutpad_portname_o, tinoutpad_portname_i, tinoutpad_portname_pad;
+               bool toutpad_neg_oe = false, tinoutpad_neg_oe = false;
                std::string widthparam, nameparam;
                pool<pair<IdString, IdString>> ignore;
                bool flag_bits = false;
@@ -137,6 +140,10 @@ struct IopadmapPass : public Pass {
                                toutpad_portname_oe = args[++argidx];
                                split_portname_pair(toutpad_portname_oe, toutpad_portname_i);
                                split_portname_pair(toutpad_portname_i, toutpad_portname_pad);
+                               if (toutpad_portname_oe[0] == '~') {
+                                       toutpad_neg_oe = true;
+                                       toutpad_portname_oe = toutpad_portname_oe.substr(1);
+                               }
                                continue;
                        }
                        if (arg == "-tinoutpad" && argidx+2 < args.size()) {
@@ -145,6 +152,10 @@ struct IopadmapPass : public Pass {
                                split_portname_pair(tinoutpad_portname_oe, tinoutpad_portname_o);
                                split_portname_pair(tinoutpad_portname_o, tinoutpad_portname_i);
                                split_portname_pair(tinoutpad_portname_i, tinoutpad_portname_pad);
+                               if (toutpad_portname_oe[0] == '~') {
+                                       tinoutpad_neg_oe = true;
+                                       tinoutpad_portname_oe = tinoutpad_portname_oe.substr(1);
+                               }
                                continue;
                        }
                        if (arg == "-ignore" && argidx+2 < args.size()) {
@@ -318,6 +329,8 @@ struct IopadmapPass : public Pass {
                                                                module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
                                                                RTLIL::escape_id(tinoutpad_celltype));
 
+                                                       if (tinoutpad_neg_oe)
+                                                               en_sig = module->NotGate(NEW_ID, en_sig);
                                                        cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig);
                                                        cell->attributes[ID::keep] = RTLIL::Const(1);
 
@@ -340,6 +353,8 @@ struct IopadmapPass : public Pass {
                                                                module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
                                                                RTLIL::escape_id(toutpad_celltype));
 
+                                                       if (toutpad_neg_oe)
+                                                               en_sig = module->NotGate(NEW_ID, en_sig);
                                                        cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig);
                                                        cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
                                                        cell->attributes[ID::keep] = RTLIL::Const(1);
index 90eb9b5a435dcc8957fbaa5058f132bffce4e55a..5978a00d0c5146d3e7c03f286723df37576338b5 100644 (file)
@@ -122,14 +122,6 @@ module     \$_DFFE_NP0P_ (input D, C, R, E, output Q);
        wire _TECHMAP_REMOVEINIT_Q_ = 1;
 endmodule
 
-module \$__GW_IOBUF (input I, OE, output O, inout IO);
-       IOBUF _TECHMAP_REPLACE_ (.I(I), .O(O), .OEN(~OE), .IO(IO));
-endmodule
-
-module \$__GW_TBUF (input I, OE, output O);
-       TBUF _TECHMAP_REPLACE_ (.I(I), .OEN(~OE), .O(O));
-endmodule
-
 module \$lut (A, Y);
        parameter WIDTH = 0;
        parameter LUT = 0;
index 1f34a1d1d14fe0eedd07d0b39262a389528c0b30..cfbc9b9a63e8b264d79a238a29722a4b3a8c7894 100644 (file)
@@ -240,7 +240,7 @@ struct SynthGowinPass : public ScriptPass
                                run("abc -dff -D 1", "(only if -retime)");
                        if (!noiopads || help_mode)
                                run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O "
-                                       "-toutpad $__GW_TBUF OE:I:O -tinoutpad $__GW_IOBUF OE:O:I:IO", "(unless -noiopads)");
+                                       "-toutpad TBUF ~OEN:I:O -tinoutpad IOBUF ~OEN:O:I:IO", "(unless -noiopads)");
                }
 
                if (check_label("map_ffs"))
index 82eb10d9592b16b418e5803e4daf5732c2a6eed2..9c370f246aacb235ff2274ea74a573c7d9d5129b 100644 (file)
@@ -30,5 +30,5 @@ module  \$_DFF_P_ (input D, C, output Q); FACADE_FF #(.CEMUX("1"), .CLKMUX("CLK"
 // IO- "$__" cells for the iopadmap pass.
 module  \$__FACADE_OUTPAD (input I, output O); FACADE_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.PAD(O), .I(I), .T(1'b0)); endmodule
 module  \$__FACADE_INPAD (input I, output O); FACADE_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.PAD(I), .O(O)); endmodule
-module  \$__FACADE_TOUTPAD (input I, OE, output O); FACADE_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.PAD(O), .I(I), .T(~OE)); endmodule
-module  \$__FACADE_TINOUTPAD (input I, OE, output O, inout B); FACADE_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.PAD(B), .I(I), .O(O), .T(~OE)); endmodule
+module  \$__FACADE_TOUTPAD (input I, T, output O); FACADE_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.PAD(O), .I(I), .T(T)); endmodule
+module  \$__FACADE_TINOUTPAD (input I, T, output O, inout B); FACADE_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.PAD(B), .I(I), .O(O), .T(T)); endmodule
index 161ddfe2ea3250ea273d18d0f9d9ffad14c069e5..dc68a3127d597079f424c77d215ab8aa5f3f644e 100644 (file)
@@ -207,6 +207,6 @@ module  \$__FACADE_OUTPAD (input I, output O); endmodule
 (* blackbox *)
 module  \$__FACADE_INPAD (input I, output O); endmodule
 (* blackbox *)
-module  \$__FACADE_TOUTPAD (input I, OE, output O); endmodule
+module  \$__FACADE_TOUTPAD (input I, T, output O); endmodule
 (* blackbox *)
-module  \$__FACADE_TINOUTPAD (input I, OE, output O, inout B); endmodule
+module  \$__FACADE_TINOUTPAD (input I, T, output O, inout B); endmodule
index bba8f48308d38562629ed560739d601efb202ac4..e86ec5aafbbc2314f0ba3c3972a29267629c8f14 100644 (file)
@@ -185,7 +185,7 @@ struct SynthMachXO2Pass : public ScriptPass
                {
                        if (!noiopad || help_mode)
                        {
-                               run("iopadmap -bits -outpad $__FACADE_OUTPAD I:O -inpad $__FACADE_INPAD O:I -toutpad $__FACADE_TOUTPAD OE:I:O -tinoutpad $__FACADE_TINOUTPAD OE:O:I:B A:top");
+                               run("iopadmap -bits -outpad $__FACADE_OUTPAD I:O -inpad $__FACADE_INPAD O:I -toutpad $__FACADE_TOUTPAD ~T:I:O -tinoutpad $__FACADE_TINOUTPAD ~T:O:I:B A:top");
                                run("attrmvcp -attr src -attr LOC t:$__FACADE_OUTPAD %x:+[O] t:$__FACADE_TOUTPAD %x:+[O] t:$__FACADE_TINOUTPAD %x:+[B]");
                                run("attrmvcp -attr src -attr LOC -driven t:$__FACADE_INPAD %x:+[I]");
                        }
index 1e53e4026521e0e4478e90e67211741116417fb3..b70edbcf4d642165d6c229a15c3d910a94386ddf 100644 (file)
@@ -53,14 +53,6 @@ module  \$_DFFE_PP1P_ (input D, C, E, R, output Q); \$__FF_ASYNCLSR #(1)  _TECHM
 module  \$_SDFFE_PP0P_ (input D, C, E, R, output Q); \$__FF_SYNCLSR #(0)  _TECHMAP_REPLACE_ (.D(D), .C(C), .R(R), .E(E), .Q(Q)); endmodule
 module  \$_SDFFE_PP1P_ (input D, C, E, R, output Q); \$__FF_SYNCLSR #(1)  _TECHMAP_REPLACE_ (.D(D), .C(C), .R(R), .E(E), .Q(Q)); endmodule
 
-module \$__NX_TINOUTPAD (input I, OE, output O, inout B);
-       BB _TECHMAP_REPLACE_ (.I(I), .O(O), .T(~OE), .B(B));
-endmodule
-
-module \$__NX_TOUTPAD (input I, OE, output O);
-       OBZ _TECHMAP_REPLACE_ (.I(I), .T(~OE), .O(O));
-endmodule
-
 `ifndef NO_LUT
 module \$lut (A, Y);
        parameter WIDTH = 0;
index d725546cc5a587a8afaf59744d72bd5f53a0520f..03bff0649143ce41d8105b3b46cb7fb7f033f6ba 100644 (file)
@@ -333,7 +333,7 @@ struct SynthNexusPass : public ScriptPass
                        else
                                run("techmap -map +/techmap.v -map +/nexus/arith_map.v");
                        if (help_mode || !noiopad)
-                               run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad $__NX_TOUTPAD OE:I:O -tinoutpad $__NX_TINOUTPAD OE:O:I:B A:top", "(skip if '-noiopad')");
+                               run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad OBZ ~T:I:O -tinoutpad BB ~T:O:I:B A:top", "(skip if '-noiopad')");
                        run("opt -fast");
                        if (retime || help_mode)
                                run("abc -dff -D 1", "(only if -retime)");
index e8386e2e0ccf05479036a39596da90fd2c0dc924..2b8eade2fccf6e62426063cd50a506ef3d4c8279 100644 (file)
@@ -359,11 +359,3 @@ module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1);
   else
     MUXF8 mux8 (.I0(T0), .I1(T1), .S(S1), .O(O));
 endmodule
-
-module \$__XILINX_TINOUTPAD (input I, OE, output O, inout IO);
-  IOBUF _TECHMAP_REPLACE_ (.I(I), .O(O), .T(~OE), .IO(IO));
-endmodule
-
-module \$__XILINX_TOUTPAD (input I, OE, output O);
-  OBUFT _TECHMAP_REPLACE_ (.I(I), .O(O), .T(~OE));
-endmodule
index 28672fb2ea8d5320abd3ad2023361b29372ad465..6a060c8fee6c9060fca4a5b1aa575ccfd2b85263 100644 (file)
@@ -558,9 +558,10 @@ struct SynthXilinxPass : public ScriptPass
                }
 
                if (check_label("map_cells")) {
-                       // Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
+                       // Needs to be done before logic optimization, so that inverters (inserted
+                       // here because of negative-polarity output enable) are handled.
                        if (help_mode || !noiopad)
-                               run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(skip if '-noiopad')");
+                               run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad OBUFT ~T:I:O -tinoutpad IOBUF ~T:O:I:IO A:top", "(skip if '-noiopad')");
                        std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
                        if (widemux > 0)
                                techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
index 6c8aa857c0fffde9e85137ec427254901e3edc38..7b7e62d4caa491a468b708f65600f3cebc649ab8 100644 (file)
@@ -35,6 +35,6 @@ proc
 equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check
 design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 cd mux16 # Constrain all select calls below inside the top module
-select -assert-count 11 t:LUT4
+select -assert-max 12 t:LUT4
 
 select -assert-none t:LUT4 t:FACADE_IO %% t:* %D
index 9c00a8bcf6b4cf945d9086f0c5f5c50ef6895e28..fce342e183f8fbf95356de23389818a2658ff94f 100644 (file)
@@ -6,5 +6,5 @@ equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check
 design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 cd tristate # Constrain all select calls below inside the top module
 select -assert-count 3 t:FACADE_IO
-select -assert-count 1 t:$not
-select -assert-none t:FACADE_IO t:$not %% t:* %D
+select -assert-count 1 t:LUT4
+select -assert-none t:FACADE_IO t:LUT4 %% t:* %D