mirror of https://github.com/YosysHQ/yosys.git
1236 lines
36 KiB
C++
1236 lines
36 KiB
C++
/*
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
*
|
|
* Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>
|
|
*
|
|
* 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
|
|
|
|
enum FfType {
|
|
FF_DFF,
|
|
FF_DFFE,
|
|
FF_ADFF,
|
|
FF_ADFFE,
|
|
FF_ALDFF,
|
|
FF_ALDFFE,
|
|
FF_DFFSR,
|
|
FF_DFFSRE,
|
|
FF_SDFF,
|
|
FF_SDFFE,
|
|
FF_SDFFCE,
|
|
FF_RLATCH,
|
|
FF_SR,
|
|
FF_DLATCH,
|
|
FF_ADLATCH,
|
|
FF_DLATCHSR,
|
|
NUM_FFTYPES,
|
|
};
|
|
|
|
enum FfNeg {
|
|
NEG_CE = 0x1,
|
|
NEG_R = 0x2,
|
|
NEG_S = 0x4,
|
|
NEG_L = 0x8,
|
|
NEG_C = 0x10,
|
|
NUM_NEG = 0x20,
|
|
};
|
|
|
|
enum FfInit {
|
|
INIT_X = 0x1,
|
|
INIT_0 = 0x2,
|
|
INIT_1 = 0x4,
|
|
INIT_X_R0 = 0x10,
|
|
INIT_0_R0 = 0x20,
|
|
INIT_1_R0 = 0x40,
|
|
INIT_X_R1 = 0x100,
|
|
INIT_0_R1 = 0x200,
|
|
INIT_1_R1 = 0x400,
|
|
};
|
|
|
|
struct DffLegalizePass : public Pass {
|
|
DffLegalizePass() : Pass("dfflegalize", "convert FFs to types supported by the target") { }
|
|
void help() override
|
|
{
|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
|
log("\n");
|
|
log(" dfflegalize [options] [selection]\n");
|
|
log("\n");
|
|
log("Converts FFs to types supported by the target.\n");
|
|
log("\n");
|
|
log(" -cell <cell_type_pattern> <init_values>\n");
|
|
log(" specifies a supported group of FF cells. <cell_type_pattern>\n");
|
|
log(" is a yosys internal fine cell name, where ? characters can be\n");
|
|
log(" as a wildcard matching any character. <init_values> specifies\n");
|
|
log(" which initialization values these FF cells can support, and can\n");
|
|
log(" be one of:\n");
|
|
log("\n");
|
|
log(" - x (no init value supported)\n");
|
|
log(" - 0\n");
|
|
log(" - 1\n");
|
|
log(" - r (init value has to match reset value, only for some FF types)\n");
|
|
log(" - 01 (both 0 and 1 supported).\n");
|
|
log("\n");
|
|
log(" -mince <num>\n");
|
|
log(" specifies a minimum number of FFs that should be using any given\n");
|
|
log(" clock enable signal. If a clock enable signal doesn't meet this\n");
|
|
log(" threshold, it is unmapped into soft logic.\n");
|
|
log("\n");
|
|
log(" -minsrst <num>\n");
|
|
log(" specifies a minimum number of FFs that should be using any given\n");
|
|
log(" sync set/reset signal. If a sync set/reset signal doesn't meet this\n");
|
|
log(" threshold, it is unmapped into soft logic.\n");
|
|
log("\n");
|
|
log("The following cells are supported by this pass (ie. will be ingested,\n");
|
|
log("and can be specified as allowed targets):\n");
|
|
log("\n");
|
|
log("- $_DFF_[NP]_\n");
|
|
log("- $_DFFE_[NP][NP]_\n");
|
|
log("- $_DFF_[NP][NP][01]_\n");
|
|
log("- $_DFFE_[NP][NP][01][NP]_\n");
|
|
log("- $_ALDFF_[NP][NP]_\n");
|
|
log("- $_ALDFFE_[NP][NP][NP]_\n");
|
|
log("- $_DFFSR_[NP][NP][NP]_\n");
|
|
log("- $_DFFSRE_[NP][NP][NP][NP]_\n");
|
|
log("- $_SDFF_[NP][NP][01]_\n");
|
|
log("- $_SDFFE_[NP][NP][01][NP]_\n");
|
|
log("- $_SDFFCE_[NP][NP][01][NP]_\n");
|
|
log("- $_SR_[NP][NP]_\n");
|
|
log("- $_DLATCH_[NP]_\n");
|
|
log("- $_DLATCH_[NP][NP][01]_\n");
|
|
log("- $_DLATCHSR_[NP][NP][NP]_\n");
|
|
log("\n");
|
|
log("The following transformations are performed by this pass:");
|
|
log("\n");
|
|
log("- upconversion from a less capable cell to a more capable cell, if the less");
|
|
log(" capable cell is not supported (eg. dff -> dffe, or adff -> dffsr)");
|
|
log("\n");
|
|
log("- unmapping FFs with clock enable (due to unsupported cell type or -mince)");
|
|
log("\n");
|
|
log("- unmapping FFs with sync reset (due to unsupported cell type or -minsrst)");
|
|
log("\n");
|
|
log("- adding inverters on the control pins (due to unsupported polarity)");
|
|
log("\n");
|
|
log("- adding inverters on the D and Q pins and inverting the init/reset values\n");
|
|
log(" (due to unsupported init or reset value)");
|
|
log("\n");
|
|
log("- converting sr into adlatch (by tying D to 1 and using E as set input)");
|
|
log("\n");
|
|
log("- emulating unsupported dffsr cell by adff + adff + sr + mux");
|
|
log("\n");
|
|
log("- emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux");
|
|
log("\n");
|
|
log("- emulating adff when the (reset, init) value combination is unsupported by\n");
|
|
log(" dff + adff + dlatch + mux");
|
|
log("\n");
|
|
log("- emulating adlatch when the (reset, init) value combination is unsupported by\n");
|
|
log("- dlatch + adlatch + dlatch + mux");
|
|
log("\n");
|
|
log("If the pass is unable to realize a given cell type (eg. adff when only plain dff");
|
|
log("is available), an error is raised.");
|
|
}
|
|
|
|
// Table of all supported cell types.
|
|
// First index in the array is one of the FF_* values, second
|
|
// index is the set of negative-polarity inputs (OR of NEG_*
|
|
// values), and the value is the set of supported init values
|
|
// (OR of INIT_* values).
|
|
int supported_cells_neg[NUM_FFTYPES][NUM_NEG];
|
|
// Aggregated table ignoring signal polarity.
|
|
int supported_cells[NUM_FFTYPES];
|
|
// Aggregated for all *dff* cells.
|
|
int supported_dff;
|
|
// Aggregated for all *dffe* cells.
|
|
int supported_dffe;
|
|
// Aggregated for all dffsr* cells.
|
|
int supported_dffsr;
|
|
// Aggregated for all aldff cells.
|
|
int supported_aldff;
|
|
// Aggregated for all aldffe cells.
|
|
int supported_aldffe;
|
|
// Aggregated for all adff* cells and trivial emulations.
|
|
int supported_adff;
|
|
// Aggregated for all adffe* cells and trivial emulations.
|
|
int supported_adffe;
|
|
// Aggregated for all sdff* cells.
|
|
int supported_sdff;
|
|
// Aggregated for all ways to obtain a SR latch.
|
|
int supported_sr;
|
|
int supported_sr_plain;
|
|
// Aggregated for all *dlatch* cells.
|
|
int supported_dlatch;
|
|
int supported_dlatch_plain;
|
|
// Aggregated for all ways to obtain an R latch.
|
|
int supported_rlatch;
|
|
// Aggregated for all adlatch cells and trivial emulations.
|
|
int supported_adlatch;
|
|
|
|
int mince;
|
|
int minsrst;
|
|
|
|
dict<SigBit, int> ce_used;
|
|
dict<SigBit, int> srst_used;
|
|
|
|
SigMap sigmap;
|
|
FfInitVals initvals;
|
|
|
|
int flip_initmask(int mask) {
|
|
int res = mask & INIT_X;
|
|
if (mask & INIT_0)
|
|
res |= INIT_1;
|
|
if (mask & INIT_1)
|
|
res |= INIT_0;
|
|
if (mask & INIT_X_R0)
|
|
res |= INIT_X_R1;
|
|
if (mask & INIT_0_R0)
|
|
res |= INIT_1_R1;
|
|
if (mask & INIT_1_R0)
|
|
res |= INIT_0_R1;
|
|
if (mask & INIT_X_R1)
|
|
res |= INIT_X_R0;
|
|
if (mask & INIT_0_R1)
|
|
res |= INIT_1_R0;
|
|
if (mask & INIT_1_R1)
|
|
res |= INIT_0_R0;
|
|
return res;
|
|
}
|
|
|
|
int get_ff_type(const FfData &ff) {
|
|
if (ff.has_clk) {
|
|
if (ff.has_sr) {
|
|
return ff.has_ce ? FF_DFFSRE : FF_DFFSR;
|
|
} else if (ff.has_arst) {
|
|
return ff.has_ce ? FF_ADFFE : FF_ADFF;
|
|
} else if (ff.has_aload) {
|
|
return ff.has_ce ? FF_ALDFFE : FF_ALDFF;
|
|
} else if (ff.has_srst) {
|
|
if (ff.has_ce)
|
|
return ff.ce_over_srst ? FF_SDFFCE : FF_SDFFE;
|
|
else
|
|
return FF_SDFF;
|
|
} else {
|
|
return ff.has_ce ? FF_DFFE : FF_DFF;
|
|
}
|
|
} else {
|
|
if (ff.has_aload) {
|
|
if (ff.has_sr)
|
|
return FF_DLATCHSR;
|
|
else if (ff.has_arst)
|
|
return FF_ADLATCH;
|
|
else
|
|
return FF_DLATCH;
|
|
} else {
|
|
if (ff.has_sr) {
|
|
return FF_SR;
|
|
} else if (ff.has_arst) {
|
|
return FF_RLATCH;
|
|
} else {
|
|
log_assert(0);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int get_initmask(FfData &ff) {
|
|
int res = 0;
|
|
if (ff.val_init[0] == State::S0)
|
|
res = INIT_0;
|
|
else if (ff.val_init[0] == State::S1)
|
|
res = INIT_1;
|
|
else
|
|
res = INIT_X;
|
|
if (ff.has_arst) {
|
|
if (ff.val_arst[0] == State::S0)
|
|
res <<= 4;
|
|
else if (ff.val_arst[0] == State::S1)
|
|
res <<= 8;
|
|
} else if (ff.has_srst) {
|
|
if (ff.val_srst[0] == State::S0)
|
|
res <<= 4;
|
|
else if (ff.val_srst[0] == State::S1)
|
|
res <<= 8;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void fail_ff(const FfData &ff, const char *reason) {
|
|
log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(ff.module->name), log_id(ff.cell->name), log_id(ff.cell->type), reason);
|
|
}
|
|
|
|
bool try_flip(FfData &ff, int supported_mask) {
|
|
int initmask = get_initmask(ff);
|
|
if (supported_mask & initmask)
|
|
return true;
|
|
if (supported_mask & flip_initmask(initmask)) {
|
|
ff.flip_bits({0});
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void emulate_split_init_arst(FfData &ff) {
|
|
ff.remove();
|
|
|
|
FfData ff_dff(ff.module, &initvals, NEW_ID);
|
|
ff_dff.width = ff.width;
|
|
ff_dff.has_aload = ff.has_aload;
|
|
ff_dff.sig_aload = ff.sig_aload;
|
|
ff_dff.pol_aload = ff.pol_aload;
|
|
ff_dff.sig_ad = ff.sig_ad;
|
|
ff_dff.has_clk = ff.has_clk;
|
|
ff_dff.sig_clk = ff.sig_clk;
|
|
ff_dff.pol_clk = ff.pol_clk;
|
|
ff_dff.sig_d = ff.sig_d;
|
|
ff_dff.has_ce = ff.has_ce;
|
|
ff_dff.sig_ce = ff.sig_ce;
|
|
ff_dff.pol_ce = ff.pol_ce;
|
|
ff_dff.sig_q = ff.module->addWire(NEW_ID, ff.width);
|
|
ff_dff.val_init = ff.val_init;
|
|
ff_dff.is_fine = ff.is_fine;
|
|
|
|
FfData ff_adff(ff.module, &initvals, NEW_ID);
|
|
ff_adff.width = ff.width;
|
|
ff_adff.has_aload = ff.has_aload;
|
|
ff_adff.sig_aload = ff.sig_aload;
|
|
ff_adff.pol_aload = ff.pol_aload;
|
|
ff_adff.sig_ad = ff.sig_ad;
|
|
ff_adff.has_clk = ff.has_clk;
|
|
ff_adff.sig_clk = ff.sig_clk;
|
|
ff_adff.pol_clk = ff.pol_clk;
|
|
ff_adff.sig_d = ff.sig_d;
|
|
ff_adff.has_ce = ff.has_ce;
|
|
ff_adff.sig_ce = ff.sig_ce;
|
|
ff_adff.pol_ce = ff.pol_ce;
|
|
ff_adff.sig_q = ff.module->addWire(NEW_ID, ff.width);
|
|
ff_adff.val_init = Const(State::Sx, ff.width);
|
|
ff_adff.has_arst = true;
|
|
ff_adff.sig_arst = ff.sig_arst;
|
|
ff_adff.pol_arst = ff.pol_arst;
|
|
ff_adff.val_arst = ff.val_arst;
|
|
ff_adff.is_fine = ff.is_fine;
|
|
|
|
FfData ff_sel(ff.module, &initvals, NEW_ID);
|
|
ff_sel.width = 1;
|
|
ff_sel.sig_q = ff.module->addWire(NEW_ID);
|
|
ff_sel.has_arst = true;
|
|
ff_sel.sig_arst = ff.sig_arst;
|
|
ff_sel.pol_arst = ff.pol_arst;
|
|
ff_sel.val_arst = State::S1;
|
|
ff_sel.val_init = State::S0;
|
|
ff_sel.is_fine = ff.is_fine;
|
|
|
|
if (ff.is_fine)
|
|
ff.module->addMuxGate(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
|
|
else
|
|
ff.module->addMux(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
|
|
|
|
legalize_ff(ff_dff);
|
|
legalize_ff(ff_adff);
|
|
legalize_ff(ff_sel);
|
|
}
|
|
|
|
void emulate_split_set_clr(FfData &ff) {
|
|
// No native DFFSR. However, if we can conjure
|
|
// a SR latch and ADFF, it can still be emulated.
|
|
int initmask = get_initmask(ff);
|
|
int flipmask = flip_initmask(initmask);
|
|
bool init_clr = true;
|
|
bool init_set = true;
|
|
State initsel = State::Sx;
|
|
int supported_arst = ff.has_clk ? supported_adff : supported_adlatch;
|
|
bool init_clr_ok = (supported_arst & initmask << 4) || (supported_arst & flipmask << 8);
|
|
bool init_set_ok = (supported_arst & initmask << 8) || (supported_arst & flipmask << 4);
|
|
if (init_clr_ok && init_set_ok && supported_sr) {
|
|
// OK
|
|
} else if (init_clr_ok && (supported_sr & INIT_0)) {
|
|
init_set = false;
|
|
initsel = State::S0;
|
|
} else if (init_set_ok && (supported_sr & INIT_1)) {
|
|
init_clr = false;
|
|
initsel = State::S1;
|
|
} else if (init_clr_ok && (supported_sr & INIT_1)) {
|
|
init_set = false;
|
|
initsel = State::S0;
|
|
} else if (init_set_ok && (supported_sr & INIT_0)) {
|
|
init_clr = false;
|
|
initsel = State::S1;
|
|
} else {
|
|
if (ff.has_clk) {
|
|
if (!supported_dffsr)
|
|
fail_ff(ff, "dffs with async set and reset are not supported");
|
|
else
|
|
fail_ff(ff, "initialized dffs with async set and reset are not supported");
|
|
} else {
|
|
if (!supported_cells[FF_DLATCHSR])
|
|
fail_ff(ff, "dlatch with async set and reset are not supported");
|
|
else
|
|
fail_ff(ff, "initialized dlatch with async set and reset are not supported");
|
|
}
|
|
}
|
|
|
|
// If we have to unmap enable anyway, do it before breakdown.
|
|
if (ff.has_ce && !supported_cells[FF_ADFFE])
|
|
ff.unmap_ce();
|
|
|
|
log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
|
|
|
|
log_assert(ff.width == 1);
|
|
ff.remove();
|
|
|
|
FfData ff_clr(ff.module, &initvals, NEW_ID);
|
|
ff_clr.width = ff.width;
|
|
ff_clr.has_aload = ff.has_aload;
|
|
ff_clr.sig_aload = ff.sig_aload;
|
|
ff_clr.pol_aload = ff.pol_aload;
|
|
ff_clr.sig_ad = ff.sig_ad;
|
|
ff_clr.has_clk = ff.has_clk;
|
|
ff_clr.sig_clk = ff.sig_clk;
|
|
ff_clr.pol_clk = ff.pol_clk;
|
|
ff_clr.sig_d = ff.sig_d;
|
|
ff_clr.has_ce = ff.has_ce;
|
|
ff_clr.sig_ce = ff.sig_ce;
|
|
ff_clr.pol_ce = ff.pol_ce;
|
|
ff_clr.has_arst = true;
|
|
ff_clr.sig_arst = ff.sig_clr;
|
|
ff_clr.pol_arst = ff.pol_clr;
|
|
ff_clr.val_arst = Const(State::S0, ff.width);
|
|
ff_clr.sig_q = ff.module->addWire(NEW_ID, ff.width);
|
|
ff_clr.val_init = init_clr ? ff.val_init : Const(State::Sx, ff.width);
|
|
ff_clr.is_fine = ff.is_fine;
|
|
|
|
FfData ff_set(ff.module, &initvals, NEW_ID);
|
|
ff_set.width = ff.width;
|
|
ff_set.has_aload = ff.has_aload;
|
|
ff_set.sig_aload = ff.sig_aload;
|
|
ff_set.pol_aload = ff.pol_aload;
|
|
ff_set.sig_ad = ff.sig_ad;
|
|
ff_set.has_clk = ff.has_clk;
|
|
ff_set.sig_clk = ff.sig_clk;
|
|
ff_set.pol_clk = ff.pol_clk;
|
|
ff_set.sig_d = ff.sig_d;
|
|
ff_set.has_ce = ff.has_ce;
|
|
ff_set.sig_ce = ff.sig_ce;
|
|
ff_set.pol_ce = ff.pol_ce;
|
|
ff_set.has_arst = true;
|
|
ff_set.sig_arst = ff.sig_set;
|
|
ff_set.pol_arst = ff.pol_set;
|
|
ff_set.val_arst = Const(State::S1, ff.width);
|
|
ff_set.sig_q = ff.module->addWire(NEW_ID, ff.width);
|
|
ff_set.val_init = init_set ? ff.val_init : Const(State::Sx, ff.width);
|
|
ff_set.is_fine = ff.is_fine;
|
|
|
|
FfData ff_sel(ff.module, &initvals, NEW_ID);
|
|
ff_sel.width = ff.width;
|
|
ff_sel.has_sr = true;
|
|
ff_sel.pol_clr = ff.pol_clr;
|
|
ff_sel.pol_set = ff.pol_set;
|
|
ff_sel.sig_clr = ff.sig_clr;
|
|
ff_sel.sig_set = ff.sig_set;
|
|
ff_sel.sig_q = ff.module->addWire(NEW_ID, ff.width);
|
|
ff_sel.val_init = Const(initsel, ff.width);
|
|
ff_sel.is_fine = ff.is_fine;
|
|
|
|
if (!ff.is_fine)
|
|
ff.module->addMux(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
|
|
else
|
|
ff.module->addMuxGate(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
|
|
|
|
legalize_ff(ff_clr);
|
|
legalize_ff(ff_set);
|
|
legalize_ff(ff_sel);
|
|
}
|
|
|
|
void legalize_dff(FfData &ff) {
|
|
if (!try_flip(ff, supported_dff)) {
|
|
if (!supported_dff)
|
|
fail_ff(ff, "D flip-flops are not supported");
|
|
else
|
|
fail_ff(ff, "initialized D flip-flops are not supported");
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
// Some DFF is supported with this init val. Just pick a type.
|
|
if (ff.has_ce && !(supported_dffe & initmask)) {
|
|
ff.unmap_ce();
|
|
}
|
|
|
|
if (!ff.has_ce) {
|
|
if (supported_cells[FF_DFF] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try adding a set or reset pin.
|
|
if (supported_cells[FF_SDFF] & initmask) {
|
|
ff.add_dummy_srst();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
if (supported_cells[FF_ADFF] & initmask) {
|
|
ff.add_dummy_arst();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try adding async load.
|
|
if (supported_cells[FF_ALDFF] & initmask) {
|
|
ff.add_dummy_aload();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try adding both.
|
|
if (supported_cells[FF_DFFSR] & initmask) {
|
|
ff.add_dummy_sr();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Nope. Will need to add enable and go the DFFE route.
|
|
ff.add_dummy_ce();
|
|
}
|
|
if (supported_cells[FF_DFFE] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try adding a set or reset pin.
|
|
if (supported_cells[FF_SDFFCE] & initmask) {
|
|
ff.add_dummy_srst();
|
|
ff.ce_over_srst = true;
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
if (supported_cells[FF_SDFFE] & initmask) {
|
|
ff.add_dummy_srst();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
if (supported_cells[FF_ADFFE] & initmask) {
|
|
ff.add_dummy_arst();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
if (supported_cells[FF_ALDFFE] & initmask) {
|
|
ff.add_dummy_aload();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try adding both.
|
|
if (supported_cells[FF_DFFSRE] & initmask) {
|
|
ff.add_dummy_sr();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
log_assert(0);
|
|
}
|
|
|
|
void legalize_sdffce(FfData &ff) {
|
|
if (!try_flip(ff, supported_cells[FF_SDFFCE] | supported_cells[FF_SDFFE])) {
|
|
ff.unmap_srst();
|
|
legalize_dff(ff);
|
|
return;
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
if (supported_cells[FF_SDFFCE] & initmask) {
|
|
// OK
|
|
} else if (supported_cells[FF_SDFFE] & initmask) {
|
|
ff.convert_ce_over_srst(false);
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
legalize_finish(ff);
|
|
}
|
|
|
|
void legalize_sdff(FfData &ff) {
|
|
if (!try_flip(ff, supported_sdff)) {
|
|
ff.unmap_srst();
|
|
legalize_dff(ff);
|
|
return;
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
if (!ff.has_ce) {
|
|
if (supported_cells[FF_SDFF] & initmask) {
|
|
// OK
|
|
} else if (supported_cells[FF_SDFFE] & initmask) {
|
|
ff.add_dummy_ce();
|
|
} else if (supported_cells[FF_SDFFCE] & initmask) {
|
|
ff.add_dummy_ce();
|
|
ff.ce_over_srst = true;
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
} else {
|
|
log_assert(!ff.ce_over_srst);
|
|
if (supported_cells[FF_SDFFE] & initmask) {
|
|
// OK
|
|
} else if (supported_cells[FF_SDFFCE] & initmask) {
|
|
ff.convert_ce_over_srst(true);
|
|
} else if (supported_cells[FF_SDFF] & initmask) {
|
|
ff.unmap_ce();
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
}
|
|
legalize_finish(ff);
|
|
}
|
|
|
|
void legalize_adff(FfData &ff) {
|
|
if (!try_flip(ff, supported_adff)) {
|
|
if (!supported_adff)
|
|
fail_ff(ff, "dffs with async set or reset are not supported");
|
|
if (!(supported_dff & (INIT_0 | INIT_1)))
|
|
fail_ff(ff, "initialized dffs are not supported");
|
|
|
|
// If we got here, initialized dff is supported, but not this
|
|
// particular reset+init combination (nor its negation).
|
|
// The only hope left is breaking down to adff + dff + dlatch + mux.
|
|
|
|
if (!((supported_rlatch) & (INIT_0_R1 | INIT_1_R0)))
|
|
fail_ff(ff, "unsupported initial value and async reset value combination");
|
|
|
|
// If we have to unmap enable anyway, do it before breakdown.
|
|
if (ff.has_ce && !supported_cells[FF_ADFFE])
|
|
ff.unmap_ce();
|
|
|
|
if (ff.cell)
|
|
log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
|
|
emulate_split_init_arst(ff);
|
|
return;
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
if (ff.has_ce && !(supported_adffe & initmask)) {
|
|
ff.unmap_ce();
|
|
}
|
|
|
|
if (!ff.has_ce) {
|
|
if (supported_cells[FF_ADFF] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try converting to async load.
|
|
if (supported_cells[FF_ALDFF] & initmask) {
|
|
ff.arst_to_aload();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try convertint to SR.
|
|
if (supported_cells[FF_DFFSR] & initmask) {
|
|
ff.arst_to_sr();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
ff.add_dummy_ce();
|
|
}
|
|
if (supported_cells[FF_ADFFE] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try converting to async load.
|
|
if (supported_cells[FF_ALDFFE] & initmask) {
|
|
ff.arst_to_aload();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
// Try convertint to SR.
|
|
if (supported_cells[FF_DFFSRE] & initmask) {
|
|
ff.arst_to_sr();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
log_assert(0);
|
|
}
|
|
|
|
void legalize_aldff(FfData &ff) {
|
|
if (!try_flip(ff, supported_aldff)) {
|
|
ff.aload_to_sr();
|
|
emulate_split_set_clr(ff);
|
|
return;
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
if (ff.has_ce && !(supported_aldffe & initmask)) {
|
|
ff.unmap_ce();
|
|
}
|
|
|
|
if (!ff.has_ce) {
|
|
if (supported_cells[FF_ALDFF] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
if (supported_cells[FF_DFFSR] & initmask) {
|
|
ff.aload_to_sr();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
ff.add_dummy_ce();
|
|
}
|
|
if (supported_cells[FF_ALDFFE] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
if (supported_cells[FF_DFFSRE] & initmask) {
|
|
ff.aload_to_sr();
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
log_assert(0);
|
|
}
|
|
|
|
void legalize_dffsr(FfData &ff) {
|
|
if (!try_flip(ff, supported_dffsr)) {
|
|
emulate_split_set_clr(ff);
|
|
return;
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
if (ff.has_ce && !(supported_cells[FF_DFFSRE] & initmask)) {
|
|
ff.unmap_ce();
|
|
}
|
|
|
|
if (!ff.has_ce) {
|
|
if (supported_cells[FF_DFFSR] & initmask) {
|
|
legalize_finish(ff);
|
|
return;
|
|
}
|
|
ff.add_dummy_ce();
|
|
}
|
|
|
|
log_assert(supported_cells[FF_DFFSRE] & initmask);
|
|
legalize_finish(ff);
|
|
}
|
|
|
|
void legalize_dlatch(FfData &ff) {
|
|
if (!try_flip(ff, supported_dlatch)) {
|
|
if (!supported_dlatch)
|
|
fail_ff(ff, "D latches are not supported");
|
|
else
|
|
fail_ff(ff, "initialized D latches are not supported");
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
// Some DLATCH is supported with this init val. Just pick a type.
|
|
if (supported_cells[FF_DLATCH] & initmask) {
|
|
legalize_finish(ff);
|
|
} else if (supported_cells[FF_ADLATCH] & initmask) {
|
|
ff.add_dummy_arst();
|
|
legalize_finish(ff);
|
|
} else if (supported_cells[FF_DLATCHSR] & initmask) {
|
|
ff.add_dummy_sr();
|
|
legalize_finish(ff);
|
|
} else if (supported_cells[FF_ALDFF] & initmask) {
|
|
ff.add_dummy_clk();
|
|
legalize_finish(ff);
|
|
} else if (supported_cells[FF_ALDFFE] & initmask) {
|
|
ff.add_dummy_clk();
|
|
ff.add_dummy_ce();
|
|
legalize_finish(ff);
|
|
} else if (supported_sr & initmask) {
|
|
ff.aload_to_sr();
|
|
legalize_sr(ff);
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
}
|
|
|
|
void legalize_adlatch(FfData &ff) {
|
|
if (!try_flip(ff, supported_adlatch)) {
|
|
if (!supported_adlatch)
|
|
fail_ff(ff, "D latches with async set or reset are not supported");
|
|
if (!(supported_dlatch & (INIT_0 | INIT_1)))
|
|
fail_ff(ff, "initialized D latches are not supported");
|
|
|
|
// If we got here, initialized dlatch is supported, but not this
|
|
// particular reset+init combination (nor its negation).
|
|
// The only hope left is breaking down to adlatch + dlatch + dlatch + mux.
|
|
|
|
if (ff.cell)
|
|
log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
|
|
ff.remove();
|
|
|
|
emulate_split_init_arst(ff);
|
|
return;
|
|
}
|
|
int initmask = get_initmask(ff);
|
|
if (supported_cells[FF_ADLATCH] & initmask) {
|
|
// OK
|
|
} else if (supported_cells[FF_DLATCHSR] & initmask) {
|
|
ff.arst_to_sr();
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
legalize_finish(ff);
|
|
}
|
|
|
|
void legalize_dlatchsr(FfData &ff) {
|
|
if (!try_flip(ff, supported_cells[FF_DLATCHSR])) {
|
|
emulate_split_set_clr(ff);
|
|
return;
|
|
}
|
|
legalize_finish(ff);
|
|
}
|
|
|
|
void legalize_rlatch(FfData &ff) {
|
|
if (!try_flip(ff, supported_rlatch)) {
|
|
if (!supported_dlatch)
|
|
fail_ff(ff, "D latches are not supported");
|
|
else
|
|
fail_ff(ff, "initialized D latches are not supported");
|
|
}
|
|
|
|
int initmask = get_initmask(ff);
|
|
if (((supported_dlatch_plain & 7) * 0x111) & initmask) {
|
|
ff.arst_to_aload();
|
|
legalize_dlatch(ff);
|
|
} else if (supported_sr & initmask) {
|
|
ff.arst_to_sr();
|
|
legalize_sr(ff);
|
|
} else if (supported_adff & initmask) {
|
|
ff.add_dummy_clk();
|
|
legalize_adff(ff);
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
}
|
|
|
|
void legalize_sr(FfData &ff) {
|
|
if (!try_flip(ff, supported_sr)) {
|
|
if (!supported_sr)
|
|
fail_ff(ff, "sr latches are not supported");
|
|
else
|
|
fail_ff(ff, "initialized sr latches are not supported");
|
|
}
|
|
int initmask = get_initmask(ff);
|
|
if (supported_cells[FF_SR] & initmask) {
|
|
// OK
|
|
} else if (supported_cells[FF_DLATCHSR] & initmask) {
|
|
// Upgrade to DLATCHSR.
|
|
ff.add_dummy_aload();
|
|
} else if (supported_cells[FF_DFFSR] & initmask) {
|
|
// Upgrade to DFFSR.
|
|
ff.add_dummy_clk();
|
|
} else if (supported_cells[FF_DFFSRE] & initmask) {
|
|
// Upgrade to DFFSRE.
|
|
ff.add_dummy_clk();
|
|
ff.add_dummy_ce();
|
|
} else if (supported_cells[FF_ADLATCH] & (initmask << 4)) {
|
|
ff.has_sr = false;
|
|
ff.has_aload = true;
|
|
ff.has_arst = true;
|
|
ff.pol_arst = ff.pol_clr;
|
|
ff.sig_arst = ff.sig_clr;
|
|
ff.sig_aload = ff.sig_set;
|
|
ff.pol_aload = ff.pol_set;
|
|
ff.sig_ad = State::S1;
|
|
ff.val_arst = State::S0;
|
|
} else if (supported_cells[FF_ADLATCH] & (flip_initmask(initmask) << 8)) {
|
|
ff.has_sr = false;
|
|
ff.has_aload = true;
|
|
ff.has_arst = true;
|
|
ff.pol_arst = ff.pol_clr;
|
|
ff.sig_arst = ff.sig_clr;
|
|
ff.sig_aload = ff.sig_set;
|
|
ff.pol_aload = ff.pol_set;
|
|
ff.sig_ad = State::S0;
|
|
ff.val_arst = State::S1;
|
|
ff.remove_init();
|
|
Wire *new_q = ff.module->addWire(NEW_ID);
|
|
if (ff.is_fine)
|
|
ff.module->addNotGate(NEW_ID, new_q, ff.sig_q);
|
|
else
|
|
ff.module->addNot(NEW_ID, new_q, ff.sig_q);
|
|
ff.sig_q = new_q;
|
|
if (ff.val_init == State::S0)
|
|
ff.val_init = State::S1;
|
|
else if (ff.val_init == State::S1)
|
|
ff.val_init = State::S0;
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
legalize_finish(ff);
|
|
}
|
|
|
|
void fixup_reset_x(FfData &ff, int supported) {
|
|
for (int i = 0; i < ff.width; i++) {
|
|
int mask;
|
|
if (ff.val_init[i] == State::S0)
|
|
mask = INIT_0;
|
|
else if (ff.val_init[i] == State::S1)
|
|
mask = INIT_1;
|
|
else
|
|
mask = INIT_X;
|
|
if (ff.has_arst) {
|
|
if (ff.val_arst[i] == State::Sx) {
|
|
if (!(supported & (mask << 8)))
|
|
ff.val_arst[i] = State::S0;
|
|
if (!(supported & (mask << 4)))
|
|
ff.val_arst[i] = State::S1;
|
|
}
|
|
}
|
|
if (ff.has_srst) {
|
|
if (ff.val_srst[i] == State::Sx) {
|
|
if (!(supported & (mask << 8)))
|
|
ff.val_srst[i] = State::S0;
|
|
if (!(supported & (mask << 4)))
|
|
ff.val_srst[i] = State::S1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void legalize_ff(FfData &ff) {
|
|
if (ff.has_gclk)
|
|
return;
|
|
|
|
// TODO: consider supporting coarse as well.
|
|
if (!ff.is_fine)
|
|
return;
|
|
|
|
if (mince && ff.has_ce && ff.sig_ce[0].wire && ce_used[ff.sig_ce[0]] < mince)
|
|
ff.unmap_ce();
|
|
if (minsrst && ff.has_srst && ff.sig_srst[0].wire && srst_used[ff.sig_srst[0]] < minsrst)
|
|
ff.unmap_srst();
|
|
|
|
if (ff.has_clk) {
|
|
if (ff.has_sr) {
|
|
legalize_dffsr(ff);
|
|
} else if (ff.has_aload) {
|
|
legalize_aldff(ff);
|
|
} else if (ff.has_arst) {
|
|
legalize_adff(ff);
|
|
} else if (ff.has_srst) {
|
|
if (ff.has_ce && ff.ce_over_srst)
|
|
legalize_sdffce(ff);
|
|
else
|
|
legalize_sdff(ff);
|
|
} else {
|
|
legalize_dff(ff);
|
|
}
|
|
} else if (ff.has_aload) {
|
|
if (ff.has_sr) {
|
|
legalize_dlatchsr(ff);
|
|
} else if (ff.has_arst) {
|
|
legalize_adlatch(ff);
|
|
} else {
|
|
legalize_dlatch(ff);
|
|
}
|
|
} else {
|
|
if (ff.has_sr) {
|
|
legalize_sr(ff);
|
|
} else if (ff.has_arst) {
|
|
legalize_rlatch(ff);
|
|
} else {
|
|
log_assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void flip_pol(FfData &ff, SigSpec &sig, bool &pol) {
|
|
if (sig == State::S0) {
|
|
sig = State::S1;
|
|
} else if (sig == State::S1) {
|
|
sig = State::S0;
|
|
} else if (ff.is_fine) {
|
|
sig = ff.module->NotGate(NEW_ID, sig);
|
|
} else {
|
|
sig = ff.module->Not(NEW_ID, sig);
|
|
}
|
|
pol = !pol;
|
|
}
|
|
|
|
void legalize_finish(FfData &ff) {
|
|
int ff_type = get_ff_type(ff);
|
|
int initmask = get_initmask(ff);
|
|
log_assert(supported_cells[ff_type] & initmask);
|
|
int ff_neg = 0;
|
|
if (ff.has_sr) {
|
|
if (!ff.pol_clr)
|
|
ff_neg |= NEG_R;
|
|
if (!ff.pol_set)
|
|
ff_neg |= NEG_S;
|
|
}
|
|
if (ff.has_arst) {
|
|
if (!ff.pol_arst)
|
|
ff_neg |= NEG_R;
|
|
}
|
|
if (ff.has_srst) {
|
|
if (!ff.pol_srst)
|
|
ff_neg |= NEG_R;
|
|
}
|
|
if (ff.has_aload) {
|
|
if (!ff.pol_aload)
|
|
ff_neg |= NEG_L;
|
|
}
|
|
if (ff.has_clk) {
|
|
if (!ff.pol_clk)
|
|
ff_neg |= NEG_C;
|
|
}
|
|
if (ff.has_ce) {
|
|
if (!ff.pol_ce)
|
|
ff_neg |= NEG_CE;
|
|
}
|
|
if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) {
|
|
// Cell is supported, but not with those polarities.
|
|
// Will need to add some inverters.
|
|
|
|
// Find the smallest value that xored with the neg mask
|
|
// results in a supported one — this results in preferentially
|
|
// inverting resets before clocks, etc.
|
|
int xneg;
|
|
for (xneg = 0; xneg < NUM_NEG; xneg++)
|
|
if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask)
|
|
break;
|
|
log_assert(xneg < NUM_NEG);
|
|
if (xneg & NEG_CE)
|
|
flip_pol(ff, ff.sig_ce, ff.pol_ce);
|
|
if (ff.has_sr) {
|
|
if (xneg & NEG_R)
|
|
flip_pol(ff, ff.sig_clr, ff.pol_clr);
|
|
if (xneg & NEG_S)
|
|
flip_pol(ff, ff.sig_set, ff.pol_set);
|
|
}
|
|
if (ff.has_arst && xneg & NEG_R)
|
|
flip_pol(ff, ff.sig_arst, ff.pol_arst);
|
|
if (ff.has_srst && xneg & NEG_R)
|
|
flip_pol(ff, ff.sig_srst, ff.pol_srst);
|
|
if (xneg & NEG_L)
|
|
flip_pol(ff, ff.sig_aload, ff.pol_aload);
|
|
if (xneg & NEG_C)
|
|
flip_pol(ff, ff.sig_clk, ff.pol_clk);
|
|
ff_neg ^= xneg;
|
|
}
|
|
|
|
fixup_reset_x(ff, supported_cells_neg[ff_type][ff_neg]);
|
|
ff.emit();
|
|
}
|
|
|
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
|
{
|
|
|
|
log_header(design, "Executing DFFLEGALIZE pass (convert FFs to types supported by the target).\n");
|
|
|
|
for (int i = 0; i < NUM_FFTYPES; i++) {
|
|
for (int j = 0; j < NUM_NEG; j++)
|
|
supported_cells_neg[i][j] = 0;
|
|
supported_cells[i] = 0;
|
|
}
|
|
mince = 0;
|
|
minsrst = 0;
|
|
|
|
size_t argidx;
|
|
for (argidx = 1; argidx < args.size(); argidx++)
|
|
{
|
|
if (args[argidx] == "-cell" && argidx + 2 < args.size()) {
|
|
std::string celltype = args[++argidx];
|
|
std::string inittype = args[++argidx];
|
|
enum FfType ff_type;
|
|
char pol_c = 0;
|
|
char pol_l = 0;
|
|
char pol_s = 0;
|
|
char pol_r = 0;
|
|
char pol_ce = 0;
|
|
char srval = 0;
|
|
if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') {
|
|
ff_type = FF_SR;
|
|
pol_s = celltype[5];
|
|
pol_r = celltype[6];
|
|
} else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') {
|
|
ff_type = FF_DFF;
|
|
pol_c = celltype[6];
|
|
} else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') {
|
|
ff_type = FF_DFFE;
|
|
pol_c = celltype[7];
|
|
pol_ce = celltype[8];
|
|
} else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') {
|
|
ff_type = FF_ADFF;
|
|
pol_c = celltype[6];
|
|
pol_r = celltype[7];
|
|
srval = celltype[8];
|
|
} else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') {
|
|
ff_type = FF_ADFFE;
|
|
pol_c = celltype[7];
|
|
pol_r = celltype[8];
|
|
srval = celltype[9];
|
|
pol_ce = celltype[10];
|
|
} else if (celltype.substr(0, 8) == "$_ALDFF_" && celltype.size() == 11 && celltype[10] == '_') {
|
|
ff_type = FF_ALDFF;
|
|
pol_c = celltype[8];
|
|
pol_l = celltype[9];
|
|
} else if (celltype.substr(0, 9) == "$_ALDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
|
|
ff_type = FF_ALDFFE;
|
|
pol_c = celltype[9];
|
|
pol_l = celltype[10];
|
|
pol_ce = celltype[11];
|
|
} else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') {
|
|
ff_type = FF_DFFSR;
|
|
pol_c = celltype[8];
|
|
pol_s = celltype[9];
|
|
pol_r = celltype[10];
|
|
} else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') {
|
|
ff_type = FF_DFFSRE;
|
|
pol_c = celltype[9];
|
|
pol_s = celltype[10];
|
|
pol_r = celltype[11];
|
|
pol_ce = celltype[12];
|
|
} else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') {
|
|
ff_type = FF_SDFF;
|
|
pol_c = celltype[7];
|
|
pol_r = celltype[8];
|
|
srval = celltype[9];
|
|
} else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
|
|
ff_type = FF_SDFFE;
|
|
pol_c = celltype[8];
|
|
pol_r = celltype[9];
|
|
srval = celltype[10];
|
|
pol_ce = celltype[11];
|
|
} else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') {
|
|
ff_type = FF_SDFFCE;
|
|
pol_c = celltype[9];
|
|
pol_r = celltype[10];
|
|
srval = celltype[11];
|
|
pol_ce = celltype[12];
|
|
} else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') {
|
|
ff_type = FF_DLATCH;
|
|
pol_l = celltype[9];
|
|
} else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') {
|
|
ff_type = FF_ADLATCH;
|
|
pol_l = celltype[9];
|
|
pol_r = celltype[10];
|
|
srval = celltype[11];
|
|
} else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') {
|
|
ff_type = FF_DLATCHSR;
|
|
pol_l = celltype[11];
|
|
pol_s = celltype[12];
|
|
pol_r = celltype[13];
|
|
} else {
|
|
unrecognized:
|
|
log_error("unrecognized cell type %s.\n", celltype.c_str());
|
|
}
|
|
int mask = 0;
|
|
int match = 0;
|
|
for (auto pair : {
|
|
std::make_pair(pol_c, NEG_C),
|
|
std::make_pair(pol_l, NEG_L),
|
|
std::make_pair(pol_s, NEG_S),
|
|
std::make_pair(pol_r, NEG_R),
|
|
std::make_pair(pol_ce, NEG_CE),
|
|
}) {
|
|
if (pair.first == 'N') {
|
|
mask |= pair.second;
|
|
match |= pair.second;
|
|
} else if (pair.first == 'P' || pair.first == 0) {
|
|
mask |= pair.second;
|
|
} else if (pair.first != '?') {
|
|
goto unrecognized;
|
|
}
|
|
}
|
|
int initmask;
|
|
if (inittype == "x") {
|
|
initmask = 0x111;
|
|
} else if (inittype == "0") {
|
|
initmask = 0x333;
|
|
} else if (inittype == "1") {
|
|
initmask = 0x555;
|
|
} else if (inittype == "r") {
|
|
if (srval == 0)
|
|
log_error("init type r not valid for cell type %s.\n", celltype.c_str());
|
|
initmask = 0x537;
|
|
} else if (inittype == "01") {
|
|
initmask = 0x777;
|
|
} else {
|
|
log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
|
|
}
|
|
if (srval == '0') {
|
|
initmask &= 0x0ff;
|
|
} else if (srval == '1') {
|
|
initmask &= 0xf0f;
|
|
} else if (srval != 0 && srval != '?') {
|
|
goto unrecognized;
|
|
}
|
|
for (int neg = 0; neg < NUM_NEG; neg++)
|
|
if ((neg & mask) == match)
|
|
supported_cells_neg[ff_type][neg] |= initmask;
|
|
supported_cells[ff_type] |= initmask;
|
|
continue;
|
|
} else if (args[argidx] == "-mince" && argidx + 1 < args.size()) {
|
|
mince = atoi(args[++argidx].c_str());
|
|
continue;
|
|
} else if (args[argidx] == "-minsrst" && argidx + 1 < args.size()) {
|
|
minsrst = atoi(args[++argidx].c_str());
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
extra_args(args, argidx, design);
|
|
supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE];
|
|
supported_aldff = supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE] | supported_dffsr;
|
|
supported_aldffe = supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
|
|
supported_adff = supported_cells[FF_ADFF] | supported_cells[FF_ADFFE] | supported_dffsr | supported_aldff;
|
|
supported_adffe = supported_cells[FF_ADFFE] | supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
|
|
supported_sdff = supported_cells[FF_SDFF] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
|
|
supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_adff | supported_sdff;
|
|
supported_dffe = supported_cells[FF_DFFE] | supported_cells[FF_DFFSRE] | supported_cells[FF_ALDFFE] | supported_cells[FF_ADFFE] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
|
|
supported_sr_plain = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR];
|
|
supported_sr = supported_sr_plain;
|
|
supported_sr |= (supported_cells[FF_ADLATCH] >> 4 & 7) * 0x111;
|
|
supported_sr |= (flip_initmask(supported_cells[FF_ADLATCH]) >> 4 & 7) * 0x111;
|
|
supported_dlatch_plain = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR] | supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE];
|
|
supported_dlatch = supported_dlatch_plain | supported_sr_plain;
|
|
supported_rlatch = supported_adff | (supported_dlatch & 7) * 0x111;
|
|
supported_adlatch = supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR];
|
|
|
|
for (auto module : design->selected_modules())
|
|
{
|
|
sigmap.set(module);
|
|
initvals.set(&sigmap, module);
|
|
|
|
if (mince || minsrst) {
|
|
ce_used.clear();
|
|
srst_used.clear();
|
|
|
|
for (auto cell : module->cells()) {
|
|
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
|
|
continue;
|
|
|
|
FfData ff(&initvals, cell);
|
|
if (ff.has_ce && ff.sig_ce[0].wire)
|
|
ce_used[ff.sig_ce[0]] += ff.width;
|
|
if (ff.has_srst && ff.sig_srst[0].wire)
|
|
srst_used[ff.sig_srst[0]] += ff.width;
|
|
}
|
|
}
|
|
for (auto cell : module->selected_cells())
|
|
{
|
|
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
|
|
continue;
|
|
FfData ff(&initvals, cell);
|
|
legalize_ff(ff);
|
|
}
|
|
}
|
|
|
|
sigmap.clear();
|
|
initvals.clear();
|
|
ce_used.clear();
|
|
srst_used.clear();
|
|
}
|
|
} DffLegalizePass;
|
|
|
|
PRIVATE_NAMESPACE_END
|