mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-19 07:16:27 +00:00
Recognise asynchronous set/reset.
This commit is contained in:
parent
8869ce61dc
commit
a5bdb29d7f
2 changed files with 177 additions and 18 deletions
|
|
@ -201,6 +201,77 @@ struct proc_dlatch_db_t
|
|||
sig[index] = State::Sx;
|
||||
cell->setPort(ID::A, sig);
|
||||
}
|
||||
bool sibling_undef = true;
|
||||
for (int i = 0; i < (is_bwmux ? 1 : GetSize(sig_s)); i++)
|
||||
if (sig_b[i*width + index] != State::Sx)
|
||||
sibling_undef = false;
|
||||
if (!sibling_undef) {
|
||||
if (!is_bwmux) {
|
||||
for (int i = 0; i < GetSize(sig_s); i++)
|
||||
n = make_inner(sig_s[i], State::S0, n);
|
||||
} else {
|
||||
n = make_inner(sig_s[index], State::S0, n);
|
||||
}
|
||||
}
|
||||
children.insert(n);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (is_bwmux ? 1 : GetSize(sig_s)); i++) {
|
||||
n = find_mux_feedback(sig_b[i*width + index], needle, set_undef);
|
||||
if (n != false_node) {
|
||||
if (set_undef && sig_b[i*width + index] == needle) {
|
||||
SigSpec sig = cell->getPort(ID::B);
|
||||
sig[i*width + index] = State::Sx;
|
||||
cell->setPort(ID::B, sig);
|
||||
}
|
||||
bool sibling_undef = (sig_a[index] == State::Sx);
|
||||
if (!is_bwmux)
|
||||
for (int j = 0; j < GetSize(sig_s); j++)
|
||||
if (j != i && sig_b[j*width + index] != State::Sx)
|
||||
sibling_undef = false;
|
||||
if (!sibling_undef)
|
||||
n = make_inner(sig_s[is_bwmux ? index : i], State::S1, n);
|
||||
children.insert(n);
|
||||
}
|
||||
}
|
||||
|
||||
if (children.empty())
|
||||
return false_node;
|
||||
|
||||
return make_inner(children);
|
||||
}
|
||||
|
||||
int find_mux_constant(SigBit haystack, State needle, bool set_undef)
|
||||
{
|
||||
if (sigusers[haystack] > 1)
|
||||
set_undef = false;
|
||||
|
||||
if (haystack == SigBit(needle))
|
||||
return true_node;
|
||||
|
||||
auto it = mux_drivers.find(haystack);
|
||||
if (it == mux_drivers.end())
|
||||
return false_node;
|
||||
|
||||
Cell *cell = it->second.first;
|
||||
int index = it->second.second;
|
||||
|
||||
log_assert(cell->type.in(ID($mux), ID($pmux), ID($bwmux)));
|
||||
bool is_bwmux = (cell->type == ID($bwmux));
|
||||
SigSpec sig_a = sigmap(cell->getPort(ID::A));
|
||||
SigSpec sig_b = sigmap(cell->getPort(ID::B));
|
||||
SigSpec sig_s = sigmap(cell->getPort(ID::S));
|
||||
int width = GetSize(sig_a);
|
||||
|
||||
pool<int> children;
|
||||
|
||||
int n = find_mux_constant(sig_a[index], needle, set_undef);
|
||||
if (n != false_node) {
|
||||
if (set_undef && sig_a[index] == SigBit(needle)) {
|
||||
SigSpec sig = cell->getPort(ID::A);
|
||||
sig[index] = State::Sx;
|
||||
cell->setPort(ID::A, sig);
|
||||
}
|
||||
if (!is_bwmux) {
|
||||
for (int i = 0; i < GetSize(sig_s); i++)
|
||||
n = make_inner(sig_s[i], State::S0, n);
|
||||
|
|
@ -211,9 +282,9 @@ struct proc_dlatch_db_t
|
|||
}
|
||||
|
||||
for (int i = 0; i < (is_bwmux ? 1 : GetSize(sig_s)); i++) {
|
||||
n = find_mux_feedback(sig_b[i*width + index], needle, set_undef);
|
||||
n = find_mux_constant(sig_b[i*width + index], needle, set_undef);
|
||||
if (n != false_node) {
|
||||
if (set_undef && sig_b[i*width + index] == needle) {
|
||||
if (set_undef && sig_b[i*width + index] == SigBit(needle)) {
|
||||
SigSpec sig = cell->getPort(ID::B);
|
||||
sig[i*width + index] = State::Sx;
|
||||
cell->setPort(ID::B, sig);
|
||||
|
|
@ -349,7 +420,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
|
|||
{
|
||||
RTLIL::SigSig latches_bits, nolatches_bits;
|
||||
dict<SigBit, SigBit> latches_out_in;
|
||||
dict<SigBit, int> latches_hold;
|
||||
dict<SigBit, int> latches_hold, latches_rst, latches_set;
|
||||
std::string src = proc->get_src_attribute();
|
||||
|
||||
for (auto sr : proc->syncs)
|
||||
|
|
@ -381,15 +452,31 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
|
|||
|
||||
latches_out_in.sort();
|
||||
for (auto &it : latches_out_in) {
|
||||
int n = db.find_mux_feedback(it.second, it.first, true);
|
||||
if (n == db.false_node) {
|
||||
if (db.find_mux_feedback(it.second, it.first, false) == db.false_node) {
|
||||
nolatches_bits.first.append(it.first);
|
||||
nolatches_bits.second.append(it.second);
|
||||
} else {
|
||||
latches_bits.first.append(it.first);
|
||||
latches_bits.second.append(it.second);
|
||||
latches_hold[it.first] = n;
|
||||
continue;
|
||||
}
|
||||
|
||||
latches_bits.first.append(it.first);
|
||||
latches_bits.second.append(it.second);
|
||||
int nrst = db.find_mux_constant(it.second, State::S0, false);
|
||||
int nset = db.find_mux_constant(it.second, State::S1, false);
|
||||
bool has_rst = (nrst != db.false_node);
|
||||
bool has_set = (nset != db.false_node);
|
||||
|
||||
if (has_rst && !has_set)
|
||||
nrst = db.find_mux_constant(it.second, State::S0, true);
|
||||
else if (has_set && !has_rst)
|
||||
nset = db.find_mux_constant(it.second, State::S1, true);
|
||||
else
|
||||
nrst = nset = db.false_node;
|
||||
|
||||
int n = db.find_mux_feedback(it.second, it.first, true);
|
||||
log_assert(n != db.false_node);
|
||||
latches_hold[it.first] = n;
|
||||
latches_rst[it.first] = nrst;
|
||||
latches_set[it.first] = nset;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
|
|
@ -423,20 +510,35 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
|
|||
while (offset < GetSize(latches_bits.first))
|
||||
{
|
||||
int width = 1;
|
||||
int n = latches_hold[latches_bits.first[offset]];
|
||||
Wire *w = latches_bits.first[offset].wire;
|
||||
SigBit obit = latches_bits.first[offset];
|
||||
int n = latches_hold[obit];
|
||||
int nrst = latches_rst[obit];
|
||||
int nset = latches_set[obit];
|
||||
Wire *w = obit.wire;
|
||||
|
||||
if (w != nullptr)
|
||||
{
|
||||
while (offset+width < GetSize(latches_bits.first) &&
|
||||
n == latches_hold[latches_bits.first[offset+width]] &&
|
||||
nrst == latches_rst[latches_bits.first[offset+width]] &&
|
||||
nset == latches_set[latches_bits.first[offset+width]] &&
|
||||
w == latches_bits.first[offset+width].wire)
|
||||
width++;
|
||||
|
||||
SigSpec lhs = latches_bits.first.extract(offset, width);
|
||||
SigSpec rhs = latches_bits.second.extract(offset, width);
|
||||
|
||||
Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n, src)), rhs, lhs);
|
||||
SigBit en = db.module->Not(NEW_ID, db.make_hold(n, src));
|
||||
bool has_rst = (nrst != db.false_node);
|
||||
bool has_set = (nset != db.false_node);
|
||||
|
||||
Cell *cell;
|
||||
if (has_rst)
|
||||
cell = db.module->addAdlatch(NEW_ID, en, db.make_hold(nrst, src), rhs, lhs, RTLIL::Const(State::S0, width));
|
||||
else if (has_set)
|
||||
cell = db.module->addAdlatch(NEW_ID, en, db.make_hold(nset, src), rhs, lhs, RTLIL::Const(State::S1, width));
|
||||
else
|
||||
cell = db.module->addDlatch(NEW_ID, en, rhs, lhs);
|
||||
cell->set_src_attribute(src);
|
||||
db.generated_dlatches.insert(cell);
|
||||
|
||||
|
|
|
|||
|
|
@ -370,10 +370,16 @@ struct DffLegalizePass : public Pass {
|
|||
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 (!supported_dlatch) {
|
||||
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 (ff.cell)
|
||||
log_warning("Emulating async set + reset latch with a plain D latch and logic for %s.%s\n", ff.module->name.unescape(), ff.cell->name.unescape());
|
||||
emulate_dlatch(ff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -449,6 +455,51 @@ struct DffLegalizePass : public Pass {
|
|||
legalize_ff(ff_sel);
|
||||
}
|
||||
|
||||
void emulate_dlatch(FfData &ff) {
|
||||
// emulate adlatch or dlatchsr
|
||||
log_assert(!ff.has_clk);
|
||||
log_assert(ff.has_aload);
|
||||
log_assert(ff.width == 1);
|
||||
|
||||
auto active_high = [&](SigBit sig, bool pol) -> SigBit {
|
||||
if (pol)
|
||||
return sig;
|
||||
return ff.is_fine ? ff.module->NotGate(NEW_ID, sig) : ff.module->Not(NEW_ID, sig)[0];
|
||||
};
|
||||
|
||||
auto do_mux = [&](SigBit a, SigBit b, SigBit s) -> SigBit {
|
||||
return ff.is_fine ? ff.module->MuxGate(NEW_ID, a, b, s) : ff.module->Mux(NEW_ID, a, b, s)[0];
|
||||
};
|
||||
|
||||
auto do_or = [&](SigBit a, SigBit b) -> SigBit {
|
||||
return ff.is_fine ? ff.module->OrGate(NEW_ID, a, b) : ff.module->Or(NEW_ID, a, b)[0];
|
||||
};
|
||||
|
||||
SigBit en = active_high(ff.sig_aload, ff.pol_aload);
|
||||
SigBit d = ff.sig_ad;
|
||||
|
||||
if (ff.has_sr) {
|
||||
SigBit set = active_high(ff.sig_set[0], ff.pol_set);
|
||||
SigBit clr = active_high(ff.sig_clr[0], ff.pol_clr);
|
||||
// clr > set > load > hold
|
||||
d = do_mux(d, State::S1, set);
|
||||
d = do_mux(d, State::S0, clr);
|
||||
en = do_or(en, do_or(set, clr));
|
||||
ff.has_sr = false;
|
||||
}
|
||||
if (ff.has_arst) {
|
||||
SigBit arst = active_high(ff.sig_arst[0], ff.pol_arst);
|
||||
d = do_mux(d, ff.val_arst[0], arst);
|
||||
en = do_or(en, arst);
|
||||
ff.has_arst = false;
|
||||
}
|
||||
|
||||
ff.sig_ad = d;
|
||||
ff.sig_aload = en;
|
||||
ff.pol_aload = true;
|
||||
legalize_dlatch(ff);
|
||||
}
|
||||
|
||||
void legalize_dff(FfData &ff) {
|
||||
if (!try_flip(ff, supported_dff)) {
|
||||
if (!supported_dff)
|
||||
|
|
@ -742,8 +793,14 @@ struct DffLegalizePass : public Pass {
|
|||
|
||||
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_adlatch) {
|
||||
if (!supported_dlatch)
|
||||
fail_ff(ff, "D latches with async set or reset are not supported");
|
||||
if (ff.cell)
|
||||
log_warning("Emulating async reset latch with a plain D latch and logic for %s.%s\n", ff.module->name.unescape(), ff.cell->name.unescape());
|
||||
emulate_dlatch(ff);
|
||||
return;
|
||||
}
|
||||
if (!(supported_dlatch & (INIT_0 | INIT_1)))
|
||||
fail_ff(ff, "initialized D latches are not supported");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue