mirror of https://github.com/YosysHQ/yosys.git
Add the $anyinit cell and the formalff pass
These can be used to protect undefined flip-flop initialization values from optimizations that are not sound for formal verification and can help mapping all solver-provided values in witness traces for flows that use different backends simultaneously.
This commit is contained in:
parent
c26b2bf543
commit
c0063288d6
|
@ -4,6 +4,12 @@ List of major changes and improvements between releases
|
||||||
|
|
||||||
Yosys 0.20 .. Yosys 0.20-dev
|
Yosys 0.20 .. Yosys 0.20-dev
|
||||||
--------------------------
|
--------------------------
|
||||||
|
* New commands and options
|
||||||
|
- Added "formalff" pass - transforms FFs for formal verification
|
||||||
|
|
||||||
|
* Formal Verification
|
||||||
|
- Added $anyinit cell to directly represent FFs with an unconstrained
|
||||||
|
initialization value. These can be generated by the new formalff pass.
|
||||||
|
|
||||||
Yosys 0.19 .. Yosys 0.20
|
Yosys 0.19 .. Yosys 0.20
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -51,6 +51,7 @@ struct CellTypes
|
||||||
|
|
||||||
setup_internals();
|
setup_internals();
|
||||||
setup_internals_mem();
|
setup_internals_mem();
|
||||||
|
setup_internals_anyinit();
|
||||||
setup_stdcells();
|
setup_stdcells();
|
||||||
setup_stdcells_mem();
|
setup_stdcells_mem();
|
||||||
}
|
}
|
||||||
|
@ -155,6 +156,11 @@ struct CellTypes
|
||||||
setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q});
|
setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setup_internals_anyinit()
|
||||||
|
{
|
||||||
|
setup_type(ID($anyinit), {ID::D}, {ID::Q});
|
||||||
|
}
|
||||||
|
|
||||||
void setup_internals_mem()
|
void setup_internals_mem()
|
||||||
{
|
{
|
||||||
setup_internals_ff();
|
setup_internals_ff();
|
||||||
|
|
19
kernel/ff.cc
19
kernel/ff.cc
|
@ -33,10 +33,14 @@ FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initva
|
||||||
|
|
||||||
std::string type_str = cell->type.str();
|
std::string type_str = cell->type.str();
|
||||||
|
|
||||||
if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
|
if (cell->type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
|
||||||
if (cell->type == ID($ff)) {
|
if (cell->type.in(ID($anyinit), ID($ff))) {
|
||||||
has_gclk = true;
|
has_gclk = true;
|
||||||
sig_d = cell->getPort(ID::D);
|
sig_d = cell->getPort(ID::D);
|
||||||
|
if (cell->type == ID($anyinit)) {
|
||||||
|
is_anyinit = true;
|
||||||
|
log_assert(val_init.is_fully_undef());
|
||||||
|
}
|
||||||
} else if (cell->type == ID($sr)) {
|
} else if (cell->type == ID($sr)) {
|
||||||
// No data input at all.
|
// No data input at all.
|
||||||
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
|
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
|
||||||
|
@ -274,6 +278,7 @@ FfData FfData::slice(const std::vector<int> &bits) {
|
||||||
res.has_sr = has_sr;
|
res.has_sr = has_sr;
|
||||||
res.ce_over_srst = ce_over_srst;
|
res.ce_over_srst = ce_over_srst;
|
||||||
res.is_fine = is_fine;
|
res.is_fine = is_fine;
|
||||||
|
res.is_anyinit = is_anyinit;
|
||||||
res.pol_clk = pol_clk;
|
res.pol_clk = pol_clk;
|
||||||
res.pol_ce = pol_ce;
|
res.pol_ce = pol_ce;
|
||||||
res.pol_aload = pol_aload;
|
res.pol_aload = pol_aload;
|
||||||
|
@ -542,7 +547,7 @@ Cell *FfData::emit() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (initvals)
|
if (initvals && !is_anyinit)
|
||||||
initvals->set_init(sig_q, val_init);
|
initvals->set_init(sig_q, val_init);
|
||||||
if (!is_fine) {
|
if (!is_fine) {
|
||||||
if (has_gclk) {
|
if (has_gclk) {
|
||||||
|
@ -552,7 +557,12 @@ Cell *FfData::emit() {
|
||||||
log_assert(!has_arst);
|
log_assert(!has_arst);
|
||||||
log_assert(!has_srst);
|
log_assert(!has_srst);
|
||||||
log_assert(!has_sr);
|
log_assert(!has_sr);
|
||||||
cell = module->addFf(name, sig_d, sig_q);
|
if (is_anyinit) {
|
||||||
|
cell = module->addAnyinit(name, sig_d, sig_q);
|
||||||
|
log_assert(val_init.is_fully_undef());
|
||||||
|
} else {
|
||||||
|
cell = module->addFf(name, sig_d, sig_q);
|
||||||
|
}
|
||||||
} else if (!has_aload && !has_clk) {
|
} else if (!has_aload && !has_clk) {
|
||||||
log_assert(has_sr);
|
log_assert(has_sr);
|
||||||
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
|
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
|
||||||
|
@ -603,6 +613,7 @@ Cell *FfData::emit() {
|
||||||
log_assert(!has_arst);
|
log_assert(!has_arst);
|
||||||
log_assert(!has_srst);
|
log_assert(!has_srst);
|
||||||
log_assert(!has_sr);
|
log_assert(!has_sr);
|
||||||
|
log_assert(!is_anyinit);
|
||||||
cell = module->addFfGate(name, sig_d, sig_q);
|
cell = module->addFfGate(name, sig_d, sig_q);
|
||||||
} else if (!has_aload && !has_clk) {
|
} else if (!has_aload && !has_clk) {
|
||||||
log_assert(has_sr);
|
log_assert(has_sr);
|
||||||
|
|
|
@ -28,7 +28,10 @@ YOSYS_NAMESPACE_BEGIN
|
||||||
// Describes a flip-flop or a latch.
|
// Describes a flip-flop or a latch.
|
||||||
//
|
//
|
||||||
// If has_gclk, this is a formal verification FF with implicit global clock:
|
// If has_gclk, this is a formal verification FF with implicit global clock:
|
||||||
// Q is simply previous cycle's D.
|
// Q is simply previous cycle's D. Additionally if is_anyinit is true, this is
|
||||||
|
// an $anyinit cell which always has an undefined initialization value. Note
|
||||||
|
// that $anyinit is not considered to be among the FF celltypes, so a pass has
|
||||||
|
// to explicitly opt-in to process $anyinit cells with FfData.
|
||||||
//
|
//
|
||||||
// Otherwise, the FF/latch can have any number of features selected by has_*
|
// Otherwise, the FF/latch can have any number of features selected by has_*
|
||||||
// attributes that determine Q's value (in order of decreasing priority):
|
// attributes that determine Q's value (in order of decreasing priority):
|
||||||
|
@ -126,6 +129,8 @@ struct FfData {
|
||||||
// True if this FF is a fine cell, false if it is a coarse cell.
|
// True if this FF is a fine cell, false if it is a coarse cell.
|
||||||
// If true, width must be 1.
|
// If true, width must be 1.
|
||||||
bool is_fine;
|
bool is_fine;
|
||||||
|
// True if this FF is an $anyinit cell. Depends on has_gclk.
|
||||||
|
bool is_anyinit;
|
||||||
// Polarities, corresponding to sig_*. True means active-high, false
|
// Polarities, corresponding to sig_*. True means active-high, false
|
||||||
// means active-low.
|
// means active-low.
|
||||||
bool pol_clk;
|
bool pol_clk;
|
||||||
|
@ -156,6 +161,7 @@ struct FfData {
|
||||||
has_sr = false;
|
has_sr = false;
|
||||||
ce_over_srst = false;
|
ce_over_srst = false;
|
||||||
is_fine = false;
|
is_fine = false;
|
||||||
|
is_anyinit = false;
|
||||||
pol_clk = false;
|
pol_clk = false;
|
||||||
pol_aload = false;
|
pol_aload = false;
|
||||||
pol_ce = false;
|
pol_ce = false;
|
||||||
|
|
|
@ -1632,6 +1632,13 @@ namespace {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cell->type.in(ID($anyinit))) {
|
||||||
|
port(ID::D, param(ID::WIDTH));
|
||||||
|
port(ID::Q, param(ID::WIDTH));
|
||||||
|
check_expected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cell->type == ID($equiv)) {
|
if (cell->type == ID($equiv)) {
|
||||||
port(ID::A, 1);
|
port(ID::A, 1);
|
||||||
port(ID::B, 1);
|
port(ID::B, 1);
|
||||||
|
@ -3120,6 +3127,16 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, const RTLIL::S
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src)
|
||||||
|
{
|
||||||
|
RTLIL::Cell *cell = addCell(name, ID($anyinit));
|
||||||
|
cell->parameters[ID::WIDTH] = sig_q.size();
|
||||||
|
cell->setPort(ID::D, sig_d);
|
||||||
|
cell->setPort(ID::Q, sig_q);
|
||||||
|
cell->set_src_attribute(src);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src)
|
RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src)
|
||||||
{
|
{
|
||||||
RTLIL::SigSpec sig = addWire(NEW_ID, width);
|
RTLIL::SigSpec sig = addWire(NEW_ID, width);
|
||||||
|
|
|
@ -1375,6 +1375,8 @@ public:
|
||||||
RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
|
RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
|
||||||
RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
|
RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
|
||||||
|
|
||||||
|
RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = "");
|
||||||
|
|
||||||
// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
|
// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
|
||||||
|
|
||||||
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||||
|
|
|
@ -1176,7 +1176,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timestep > 0 && RTLIL::builtin_ff_cell_types().count(cell->type))
|
if (timestep > 0 && (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)))
|
||||||
{
|
{
|
||||||
FfData ff(nullptr, cell);
|
FfData ff(nullptr, cell);
|
||||||
|
|
||||||
|
|
|
@ -603,7 +603,7 @@ Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} c
|
||||||
|
|
||||||
\begin{fixme}
|
\begin{fixme}
|
||||||
Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv},
|
Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv},
|
||||||
{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells.
|
{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$anyinit}, {\tt \$allconst}, {\tt \$allseq} cells.
|
||||||
\end{fixme}
|
\end{fixme}
|
||||||
|
|
||||||
\begin{fixme}
|
\begin{fixme}
|
||||||
|
|
|
@ -574,6 +574,7 @@ struct ShowWorker
|
||||||
{
|
{
|
||||||
ct.setup_internals();
|
ct.setup_internals();
|
||||||
ct.setup_internals_mem();
|
ct.setup_internals_mem();
|
||||||
|
ct.setup_internals_anyinit();
|
||||||
ct.setup_stdcells();
|
ct.setup_stdcells();
|
||||||
ct.setup_stdcells_mem();
|
ct.setup_stdcells_mem();
|
||||||
ct.setup_design(design);
|
ct.setup_design(design);
|
||||||
|
|
|
@ -280,6 +280,7 @@ struct FsmDetectPass : public Pass {
|
||||||
|
|
||||||
CellTypes ct;
|
CellTypes ct;
|
||||||
ct.setup_internals();
|
ct.setup_internals();
|
||||||
|
ct.setup_internals_anyinit();
|
||||||
ct.setup_internals_mem();
|
ct.setup_internals_mem();
|
||||||
ct.setup_stdcells();
|
ct.setup_stdcells();
|
||||||
ct.setup_stdcells_mem();
|
ct.setup_stdcells_mem();
|
||||||
|
|
|
@ -260,6 +260,7 @@ struct SubmodWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
ct.setup_internals();
|
ct.setup_internals();
|
||||||
|
ct.setup_internals_anyinit();
|
||||||
ct.setup_internals_mem();
|
ct.setup_internals_mem();
|
||||||
ct.setup_stdcells();
|
ct.setup_stdcells();
|
||||||
ct.setup_stdcells_mem();
|
ct.setup_stdcells_mem();
|
||||||
|
|
|
@ -633,6 +633,7 @@ struct OptCleanPass : public Pass {
|
||||||
keep_cache.reset(design);
|
keep_cache.reset(design);
|
||||||
|
|
||||||
ct_reg.setup_internals_mem();
|
ct_reg.setup_internals_mem();
|
||||||
|
ct_reg.setup_internals_anyinit();
|
||||||
ct_reg.setup_stdcells_mem();
|
ct_reg.setup_stdcells_mem();
|
||||||
|
|
||||||
ct_all.setup(design);
|
ct_all.setup(design);
|
||||||
|
@ -694,6 +695,7 @@ struct CleanPass : public Pass {
|
||||||
keep_cache.reset(design);
|
keep_cache.reset(design);
|
||||||
|
|
||||||
ct_reg.setup_internals_mem();
|
ct_reg.setup_internals_mem();
|
||||||
|
ct_reg.setup_internals_anyinit();
|
||||||
ct_reg.setup_stdcells_mem();
|
ct_reg.setup_stdcells_mem();
|
||||||
|
|
||||||
ct_all.setup(design);
|
ct_all.setup(design);
|
||||||
|
|
|
@ -10,6 +10,7 @@ OBJS += passes/sat/expose.o
|
||||||
OBJS += passes/sat/assertpmux.o
|
OBJS += passes/sat/assertpmux.o
|
||||||
OBJS += passes/sat/clk2fflogic.o
|
OBJS += passes/sat/clk2fflogic.o
|
||||||
OBJS += passes/sat/async2sync.o
|
OBJS += passes/sat/async2sync.o
|
||||||
|
OBJS += passes/sat/formalff.o
|
||||||
OBJS += passes/sat/supercover.o
|
OBJS += passes/sat/supercover.o
|
||||||
OBJS += passes/sat/fmcombine.o
|
OBJS += passes/sat/fmcombine.o
|
||||||
OBJS += passes/sat/mutate.o
|
OBJS += passes/sat/mutate.o
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/ffinit.h"
|
||||||
|
#include "kernel/ff.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct FormalFfPass : public Pass {
|
||||||
|
FormalFfPass() : Pass("formalff", "prepare FFs for formal") { }
|
||||||
|
void help() override
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" formalff [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass transforms clocked flip-flops to prepare a design for formal\n");
|
||||||
|
log("verification. If a design contains latches and/or multiple different clocks run\n");
|
||||||
|
log("the async2sync or clk2fflogic passes before using this pass.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -clk2ff\n");
|
||||||
|
log(" Replace all clocked flip-flops with $ff cells that use the implicit\n");
|
||||||
|
log(" global clock. This assumes, without checking, that the design uses a\n");
|
||||||
|
log(" single global clock. If that is not the case, the clk2fflogic pass\n");
|
||||||
|
log(" should be used instead.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -ff2anyinit\n");
|
||||||
|
log(" Replace uninitialized bits of $ff cells with $anyinit cells. An\n");
|
||||||
|
log(" $anyinit cell behaves exactly like an $ff cell with an undefined\n");
|
||||||
|
log(" initialization value. The difference is that $anyinit inhibits\n");
|
||||||
|
log(" don't-care optimizations and is used to track solver-provided values\n");
|
||||||
|
log(" in witness traces.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" If combined with -clk2ff this also affects newly created $ff cells.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -anyinit2ff\n");
|
||||||
|
log(" Replaces $anyinit cells with uninitialized $ff cells. This performs the\n");
|
||||||
|
log(" reverse of -ff2anyinit and can be used, before running a backend pass\n");
|
||||||
|
log(" (or similar) that is not yet aware of $anyinit cells.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" Note that after running -anyinit2ff, in general, performing don't-care\n");
|
||||||
|
log(" optimizations is not sound in a formal verification setting.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -fine\n");
|
||||||
|
log(" Emit fine-grained $_FF_ cells instead of coarse-grained $ff cells for\n");
|
||||||
|
log(" -anyinit2ff. Cannot be combined with -clk2ff or -ff2anyinit.\n");
|
||||||
|
log("\n");
|
||||||
|
|
||||||
|
// TODO: An option to check whether all FFs use the same clock before changing it to the global clock
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
|
{
|
||||||
|
bool flag_clk2ff = false;
|
||||||
|
bool flag_ff2anyinit = false;
|
||||||
|
bool flag_anyinit2ff = false;
|
||||||
|
bool flag_fine = false;
|
||||||
|
|
||||||
|
log_header(design, "Executing FORMALFF pass.\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-clk2ff") {
|
||||||
|
flag_clk2ff = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-ff2anyinit") {
|
||||||
|
flag_ff2anyinit = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-anyinit2ff") {
|
||||||
|
flag_anyinit2ff = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-fine") {
|
||||||
|
flag_fine = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if (!(flag_clk2ff || flag_ff2anyinit || flag_anyinit2ff))
|
||||||
|
log_cmd_error("One of the options -clk2ff, -ff2anyinit, or -anyinit2ff must be specified.\n");
|
||||||
|
|
||||||
|
if (flag_ff2anyinit && flag_anyinit2ff)
|
||||||
|
log_cmd_error("The options -ff2anyinit and -anyinit2ff are exclusive.\n");
|
||||||
|
|
||||||
|
if (flag_fine && !flag_anyinit2ff)
|
||||||
|
log_cmd_error("The option -fine requries the -anyinit2ff option.\n");
|
||||||
|
|
||||||
|
if (flag_fine && flag_clk2ff)
|
||||||
|
log_cmd_error("The options -fine and -clk2ff are exclusive.\n");
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
{
|
||||||
|
SigMap sigmap(module);
|
||||||
|
FfInitVals initvals(&sigmap, module);
|
||||||
|
|
||||||
|
|
||||||
|
for (auto cell : module->selected_cells())
|
||||||
|
{
|
||||||
|
if (flag_anyinit2ff && cell->type == ID($anyinit))
|
||||||
|
{
|
||||||
|
FfData ff(&initvals, cell);
|
||||||
|
ff.remove();
|
||||||
|
ff.is_anyinit = false;
|
||||||
|
ff.is_fine = flag_fine;
|
||||||
|
if (flag_fine)
|
||||||
|
for (int i = 0; i < ff.width; i++)
|
||||||
|
ff.slice({i}).emit();
|
||||||
|
else
|
||||||
|
ff.emit();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FfData ff(&initvals, cell);
|
||||||
|
bool emit = false;
|
||||||
|
|
||||||
|
if (flag_clk2ff && ff.has_clk) {
|
||||||
|
if (ff.sig_clk.is_fully_const())
|
||||||
|
log_error("Const CLK on %s (%s) from module %s, run async2sync first.\n",
|
||||||
|
log_id(cell), log_id(cell->type), log_id(module));
|
||||||
|
|
||||||
|
ff.unmap_ce_srst();
|
||||||
|
ff.has_clk = false;
|
||||||
|
ff.has_gclk = true;
|
||||||
|
emit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ff.has_gclk) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag_ff2anyinit && !ff.val_init.is_fully_def())
|
||||||
|
{
|
||||||
|
ff.remove();
|
||||||
|
emit = false;
|
||||||
|
|
||||||
|
int cursor = 0;
|
||||||
|
while (cursor < ff.val_init.size())
|
||||||
|
{
|
||||||
|
bool is_anyinit = ff.val_init[cursor] == State::Sx;
|
||||||
|
std::vector<int> bits;
|
||||||
|
bits.push_back(cursor++);
|
||||||
|
while (cursor < ff.val_init.size() && (ff.val_init[cursor] == State::Sx) == is_anyinit)
|
||||||
|
bits.push_back(cursor++);
|
||||||
|
|
||||||
|
if ((int)bits.size() == ff.val_init.size()) {
|
||||||
|
// This check is only to make the private names more helpful for debugging
|
||||||
|
ff.is_anyinit = true;
|
||||||
|
emit = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto slice = ff.slice(bits);
|
||||||
|
slice.is_anyinit = is_anyinit;
|
||||||
|
slice.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emit)
|
||||||
|
ff.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} FormalFfPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -231,7 +231,7 @@ struct SimInstance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
|
if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) {
|
||||||
FfData ff_data(nullptr, cell);
|
FfData ff_data(nullptr, cell);
|
||||||
ff_state_t ff;
|
ff_state_t ff;
|
||||||
ff.past_d = Const(State::Sx, ff_data.width);
|
ff.past_d = Const(State::Sx, ff_data.width);
|
||||||
|
|
|
@ -1696,6 +1696,23 @@ assign Y = 'bx;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// --------------------------------------------------------
|
||||||
|
`ifdef SIMLIB_FF
|
||||||
|
module \$anyinit (D, Q);
|
||||||
|
|
||||||
|
parameter WIDTH = 0;
|
||||||
|
|
||||||
|
input [WIDTH-1:0] D;
|
||||||
|
output reg [WIDTH-1:0] Q;
|
||||||
|
|
||||||
|
initial Q <= 'bx;
|
||||||
|
|
||||||
|
always @($global_clk) begin
|
||||||
|
Q <= D;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
`endif
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
|
||||||
module \$allconst (Y);
|
module \$allconst (Y);
|
||||||
|
|
Loading…
Reference in New Issue