clk2fflogic: Consistently treat async control signals as negative hold.
authorMarcelina Kościelnicka <mwk@0x04.net>
Tue, 7 Jul 2020 12:22:04 +0000 (14:22 +0200)
committerMarcelina Kościelnicka <mwk@0x04.net>
Thu, 9 Jul 2020 16:12:47 +0000 (18:12 +0200)
This fixes some dfflegalize equivalence checks, and breaks others — and
I strongly suspect the others are due to bad support for multiple
async inputs in `proc` (in particular, lack of proper support for
dlatchsr and sketchy circuits on dffsr control inputs).

passes/sat/clk2fflogic.cc
tests/techmap/dfflegalize_adff.ys
tests/techmap/dfflegalize_adff_init.ys
tests/techmap/dfflegalize_adlatch.ys
tests/techmap/dfflegalize_adlatch_init.ys
tests/techmap/dfflegalize_dffsr_init.ys
tests/techmap/dfflegalize_sr.ys
tests/techmap/dfflegalize_sr_init.ys

index e5c5d0486d68ca5b0af79e4b2fb0771d618d5a22..cc24db6d4955afd84be901d37a2e4698eb84563c 100644 (file)
@@ -36,6 +36,30 @@ struct Clk2fflogicPass : public Pass {
                log("multiple clocks.\n");
                log("\n");
        }
+       SigSpec wrap_async_control(Module *module, SigSpec sig, bool polarity) {
+               Wire *past_sig = module->addWire(NEW_ID, GetSize(sig));
+               module->addFf(NEW_ID, sig, past_sig);
+               if (polarity)
+                       sig = module->Or(NEW_ID, sig, past_sig);
+               else
+                       sig = module->And(NEW_ID, sig, past_sig);
+               if (polarity)
+                       return sig;
+               else
+                       return module->Not(NEW_ID, sig);
+       }
+       SigSpec wrap_async_control_gate(Module *module, SigSpec sig, bool polarity) {
+               Wire *past_sig = module->addWire(NEW_ID);
+               module->addFfGate(NEW_ID, sig, past_sig);
+               if (polarity)
+                       sig = module->OrGate(NEW_ID, sig, past_sig);
+               else
+                       sig = module->AndGate(NEW_ID, sig, past_sig);
+               if (polarity)
+                       return sig;
+               else
+                       return module->NotGate(NEW_ID, sig);
+       }
        void execute(std::vector<std::string> args, RTLIL::Design *design) override
        {
                // bool flag_noinit = false;
@@ -153,7 +177,7 @@ struct Clk2fflogicPass : public Pass {
                                        cell->setPort(ID::WR_DATA, wr_data_port);
                                }
 
-                               if (cell->type.in(ID($dlatch), ID($dlatchsr)))
+                               if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr)))
                                {
                                        bool enpol = cell->parameters[ID::EN_POLARITY].as_bool();
 
@@ -165,32 +189,32 @@ struct Clk2fflogicPass : public Pass {
                                                        log_id(module), log_id(cell), log_id(cell->type),
                                                        log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
 
+                                       sig_en = wrap_async_control(module, sig_en, enpol);
+
                                        Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
                                        module->addFf(NEW_ID, sig_q, past_q);
 
                                        if (cell->type == ID($dlatch))
                                        {
-                                               if (enpol)
-                                                       module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
-                                               else
-                                                       module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
+                                               module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
+                                       }
+                                       else if (cell->type == ID($adlatch))
+                                       {
+                                               SigSpec t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
+                                               SigSpec arst = wrap_async_control(module, cell->getPort(ID::ARST), cell->parameters[ID::ARST_POLARITY].as_bool());
+                                               Const rstval = cell->parameters[ID::ARST_VALUE];
+
+                                               module->addMux(NEW_ID, t, rstval, arst, sig_q);
                                        }
                                        else
                                        {
-                                               SigSpec t;
-                                               if (enpol)
-                                                       t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
-                                               else
-                                                       t = module->Mux(NEW_ID, sig_d, past_q, sig_en);
-
-                                               SigSpec s = cell->getPort(ID::SET);
-                                               if (!cell->parameters[ID::SET_POLARITY].as_bool())
-                                                       s = module->Not(NEW_ID, s);
+                                               SigSpec t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
+
+                                               SigSpec s = wrap_async_control(module, cell->getPort(ID::SET), cell->parameters[ID::SET_POLARITY].as_bool());
                                                t = module->Or(NEW_ID, t, s);
 
-                                               SigSpec c = cell->getPort(ID::CLR);
-                                               if (cell->parameters[ID::CLR_POLARITY].as_bool())
-                                                       c = module->Not(NEW_ID, c);
+                                               SigSpec c = wrap_async_control(module, cell->getPort(ID::CLR), cell->parameters[ID::CLR_POLARITY].as_bool());
+                                               c = module->Not(NEW_ID, c);
                                                module->addAnd(NEW_ID, t, c, sig_q);
                                        }
 
@@ -279,55 +303,30 @@ struct Clk2fflogicPass : public Pass {
 
                                        if (cell->type == ID($adff))
                                        {
-                                               SigSpec arst = cell->getPort(ID::ARST);
+                                               SigSpec arst = wrap_async_control(module, cell->getPort(ID::ARST), cell->parameters[ID::ARST_POLARITY].as_bool());
                                                SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
                                                Const rstval = cell->parameters[ID::ARST_VALUE];
 
-                                               Wire *past_arst = module->addWire(NEW_ID);
-                                               module->addFf(NEW_ID, arst, past_arst);
-                                               if (cell->parameters[ID::ARST_POLARITY].as_bool())
-                                                       arst = module->LogicOr(NEW_ID, arst, past_arst);
-                                               else
-                                                       arst = module->LogicAnd(NEW_ID, arst, past_arst);
-
-                                               if (cell->parameters[ID::ARST_POLARITY].as_bool())
-                                                       module->addMux(NEW_ID, qval, rstval, arst, sig_q);
-                                               else
-                                                       module->addMux(NEW_ID, rstval, qval, arst, sig_q);
+                                               module->addMux(NEW_ID, qval, rstval, arst, sig_q);
                                        }
                                        else
                                        if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
                                                ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
                                        {
-                                               SigSpec arst = cell->getPort(ID::R);
+                                               SigSpec arst = wrap_async_control_gate(module, cell->getPort(ID::R), cell->type[7] == 'P');
                                                SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
                                                SigBit rstval = (cell->type[8] == '1');
 
-                                               Wire *past_arst = module->addWire(NEW_ID);
-                                               module->addFfGate(NEW_ID, arst, past_arst);
-                                               if (cell->type[7] == 'P')
-                                                       arst = module->OrGate(NEW_ID, arst, past_arst);
-                                               else
-                                                       arst = module->AndGate(NEW_ID, arst, past_arst);
-
-                                               if (cell->type[7] == 'P')
-                                                       module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q);
-                                               else
-                                                       module->addMuxGate(NEW_ID, rstval, qval, arst, sig_q);
+                                               module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q);
                                        }
                                        else
                                        if (cell->type == ID($dffsr))
                                        {
                                                SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
-                                               SigSpec setval = cell->getPort(ID::SET);
-                                               SigSpec clrval = cell->getPort(ID::CLR);
-
-                                               if (!cell->parameters[ID::SET_POLARITY].as_bool())
-                                                       setval = module->Not(NEW_ID, setval);
-
-                                               if (cell->parameters[ID::CLR_POLARITY].as_bool())
-                                                       clrval = module->Not(NEW_ID, clrval);
+                                               SigSpec setval = wrap_async_control(module, cell->getPort(ID::SET), cell->parameters[ID::SET_POLARITY].as_bool());
+                                               SigSpec clrval = wrap_async_control(module, cell->getPort(ID::CLR), cell->parameters[ID::CLR_POLARITY].as_bool());
 
+                                               clrval = module->Not(NEW_ID, clrval);
                                                qval = module->Or(NEW_ID, qval, setval);
                                                module->addAnd(NEW_ID, qval, clrval, sig_q);
                                        }
@@ -336,15 +335,10 @@ struct Clk2fflogicPass : public Pass {
                                                ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
                                        {
                                                SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
-                                               SigSpec setval = cell->getPort(ID::S);
-                                               SigSpec clrval = cell->getPort(ID::R);
-
-                                               if (cell->type[9] != 'P')
-                                                       setval = module->Not(NEW_ID, setval);
-
-                                               if (cell->type[10] == 'P')
-                                                       clrval = module->Not(NEW_ID, clrval);
+                                               SigSpec setval = wrap_async_control_gate(module, cell->getPort(ID::S), cell->type[9] == 'P');
+                                               SigSpec clrval = wrap_async_control_gate(module, cell->getPort(ID::R), cell->type[10] == 'P');
 
+                                               clrval = module->NotGate(NEW_ID, clrval);
                                                qval = module->OrGate(NEW_ID, qval, setval);
                                                module->addAndGate(NEW_ID, qval, clrval, sig_q);
                                        }
index a563e8c611f83418d58186b08946f2062ac64d9e..cf3e925a34835256a208b486834f6520c83872fb 100644 (file)
@@ -39,8 +39,8 @@ design -save orig
 flatten
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFF_PP0_ x
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ x
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x
 
 
 # Convert everything to ADFFs.
index 92f249815e54ed6b2e0e79d33fb8e904f9c1da00..a101617014ec3297da4274f93bc0fcc635ba75ed 100644 (file)
@@ -45,10 +45,10 @@ equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ 0
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_DLATCH_P_ 1
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_DLATCH_P_ 1
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_DLATCH_P_ 1
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1
 
 
 # Convert everything to ADFFs.
index dee17e40c735c474a35e8c96a6b704f3fe4f13e2..ea5aaa53c5d6785b78f87f559bd3dab3243a44b1 100644 (file)
@@ -22,7 +22,7 @@ EOT
 design -save orig
 flatten
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ x
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x
 
 
 # Convert everything to ADLATCHs.
index c221bbe0e1804b387ef37db78843a57153c53e40..0a31d7736441043b27399059fac85bbe4b5e192e 100644 (file)
@@ -25,8 +25,8 @@ equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 1
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 0
 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 1
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0
-#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0
+equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1
 
 
 # Convert everything to ADLATCHs.
index 646c086e0bf6e641f5605342398f1e73827db97a..a98bd0cfe5943b5a9e9aa76c40fcbdf7a52539a0 100644 (file)
@@ -49,10 +49,10 @@ flatten
 #equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_SR_PP_ 0
 #equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_SR_PP_ 0
 #equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_SR_PP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1
 
 
 # Convert everything to ADFFs.
index a75068ae064895076921d630582ca6cd9e4665c0..b8c91f7538dc7b0f833b78e781625b3fdcac3ac4 100644 (file)
@@ -9,12 +9,12 @@ endmodule
 EOT
 
 design -save orig
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ x
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ x
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ x
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ x
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ x
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ x
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x
 
 
 # Convert everything to SRs.
index 39bfdcdcff55e2a3f66eeadda00735fdf5b66411..5c52a0b28e2596bffee271c013ec2aa493af4198 100644 (file)
@@ -21,18 +21,18 @@ EOT
 
 design -save orig
 flatten
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 1
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 1
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 1
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0
-equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0
+#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1
 
 
 # Convert everything to SRs.