From: Marcelina Koƛcielnicka Date: Tue, 9 Nov 2021 10:22:48 +0000 (+0100) Subject: iopadmap: Add native support for negative-polarity output enable. X-Git-Tag: yosys-0.12~41 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=15b0d717ed658b342ce5f74df5a65827eed04a94;p=yosys.git iopadmap: Add native support for negative-polarity output enable. --- diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 45fa5f226..ce1988c49 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -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 [:]\n"); + log(" -inpad [:]\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 [:]\n"); - log(" -inoutpad [:]\n"); + log(" -outpad [:]\n"); + log(" -inoutpad [:]\n"); log(" Similar to -inpad, but for output and inout ports.\n"); log("\n"); - log(" -toutpad :[:]\n"); + log(" -toutpad :[:]\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 ::[:]\n"); + log(" -tinoutpad ::[:]\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 [:]*\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> 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); diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index 90eb9b5a4..5978a00d0 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -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; diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 1f34a1d1d..cfbc9b9a6 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -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")) diff --git a/techlibs/machxo2/cells_map.v b/techlibs/machxo2/cells_map.v index 82eb10d95..9c370f246 100644 --- a/techlibs/machxo2/cells_map.v +++ b/techlibs/machxo2/cells_map.v @@ -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 diff --git a/techlibs/machxo2/cells_sim.v b/techlibs/machxo2/cells_sim.v index 161ddfe2e..dc68a3127 100644 --- a/techlibs/machxo2/cells_sim.v +++ b/techlibs/machxo2/cells_sim.v @@ -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 diff --git a/techlibs/machxo2/synth_machxo2.cc b/techlibs/machxo2/synth_machxo2.cc index bba8f4830..e86ec5aaf 100644 --- a/techlibs/machxo2/synth_machxo2.cc +++ b/techlibs/machxo2/synth_machxo2.cc @@ -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]"); } diff --git a/techlibs/nexus/cells_map.v b/techlibs/nexus/cells_map.v index 1e53e4026..b70edbcf4 100644 --- a/techlibs/nexus/cells_map.v +++ b/techlibs/nexus/cells_map.v @@ -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; diff --git a/techlibs/nexus/synth_nexus.cc b/techlibs/nexus/synth_nexus.cc index d725546cc..03bff0649 100644 --- a/techlibs/nexus/synth_nexus.cc +++ b/techlibs/nexus/synth_nexus.cc @@ -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)"); diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index e8386e2e0..2b8eade2f 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -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 diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 28672fb2e..6a060c8fe 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -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); diff --git a/tests/arch/machxo2/mux.ys b/tests/arch/machxo2/mux.ys index 6c8aa857c..7b7e62d4c 100644 --- a/tests/arch/machxo2/mux.ys +++ b/tests/arch/machxo2/mux.ys @@ -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 diff --git a/tests/arch/machxo2/tribuf.ys b/tests/arch/machxo2/tribuf.ys index 9c00a8bcf..fce342e18 100644 --- a/tests/arch/machxo2/tribuf.ys +++ b/tests/arch/machxo2/tribuf.ys @@ -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