Try recursive pmgen for P cascade

This commit is contained in:
Eddie Hung 2019-09-26 12:09:57 -07:00
parent 84825f9378
commit 832216dab0
1 changed files with 115 additions and 85 deletions

View File

@ -1,100 +1,133 @@
pattern xilinx_dsp_cascadeP pattern xilinx_dsp_cascadeP
udata <std::function<SigSpec(const SigSpec&)>> unextend udata <vector<std::pair<Cell*,bool>>> chain longest_chain
state <SigSpec> sigC
match dsp_pcin code
select dsp_pcin->type.in(\DSP48E1) #define MAX_DSP_CASCADE 20
select !param(dsp_pcin, \CREG, State::S1).as_bool()
select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
select nusers(port(dsp_pcin, \C, SigSpec())) > 1
select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0
endmatch
code sigC
unextend = [](const SigSpec &sig) {
int i;
for (i = GetSize(sig)-1; i > 0; i--)
if (sig[i] != sig[i-1])
break;
// Do not remove non-const sign bit
if (sig[i].wire)
++i;
return sig.extract(0, i);
};
sigC = unextend(port(dsp_pcin, \C));
endcode endcode
match dsp_pcout match first
select dsp_pcout->type.in(\DSP48E1) select first->type.in(\DSP48E1)
select nusers(port(dsp_pcout, \P, SigSpec())) > 1 select port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000")
select nusers(port(dsp_pcout, \PCOUT, SigSpec())) <= 1 select nusers(port(first, \PCOUT, SigSpec())) <= 1
index <SigBit> port(dsp_pcout, \P)[0] === sigC[0]
filter GetSize(port(dsp_pcin, \P)) >= GetSize(sigC)
filter port(dsp_pcout, \P).extract(0, GetSize(sigC)) == sigC
optional
endmatch
match dsp_pcout_shift17
if !dsp_pcout
select dsp_pcout_shift17->type.in(\DSP48E1)
select nusers(port(dsp_pcout_shift17, \P, SigSpec())) > 1
select nusers(port(dsp_pcout_shift17, \PCOUT, SigSpec())) <= 1
index <SigBit> port(dsp_pcout_shift17, \P)[17] === sigC[0]
filter GetSize(port(dsp_pcout_shift17, \P)) >= GetSize(sigC)+17
filter port(dsp_pcout_shift17, \P).extract(17, GetSize(sigC)) == sigC
endmatch endmatch
code code
Cell *dsp; longest_chain.clear();
if (dsp_pcout) chain.emplace_back(first, false);
dsp = dsp_pcout; subpattern(tail);
else if (dsp_pcout_shift17) finally
dsp = dsp_pcout_shift17; chain.pop_back();
else log_abort(); log_assert(chain.empty());
if (GetSize(longest_chain) > 1) {
Cell *dsp = longest_chain.front().first;
dsp_pcin->setPort(ID(C), Const(0, 48)); for (int i = 1; i < GetSize(longest_chain); i++) {
Cell *dsp_pcin = longest_chain[i].first;
bool shift17 = longest_chain[i].second;
Wire *cascade = module->addWire(NEW_ID, 48); dsp_pcin->setPort(ID(C), Const(0, 48));
dsp_pcin->setPort(ID(PCIN), cascade);
dsp->setPort(ID(PCOUT), cascade);
add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp);
SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7)); if (i % MAX_DSP_CASCADE > 0) {
if (dsp_pcout) Wire *cascade = module->addWire(NEW_ID, 48);
opmode[6] = State::S0; dsp_pcin->setPort(ID(PCIN), cascade);
else if (dsp_pcout_shift17) dsp->setPort(ID(PCOUT), cascade);
opmode[6] = State::S1; add_siguser(cascade, dsp_pcin);
else log_abort(); add_siguser(cascade, dsp);
opmode[5] = State::S0; SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7));
opmode[4] = State::S1; if (shift17)
dsp_pcin->setPort(\OPMODE, opmode); opmode[6] = State::S1;
else
opmode[6] = State::S0;
log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); opmode[5] = State::S0;
opmode[4] = State::S1;
dsp_pcin->setPort(\OPMODE, opmode);
if (nusers(port(dsp_pcin, \PCOUT, SigSpec())) > 1) { log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp_pcin)); }
blacklist(dsp_pcin); else {
} log_debug("Blocking PCOUT -> PCIN cascade for %s -> %s (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE);
if (nusers(port(dsp, \PCIN, SigSpec())) > 1) { }
log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp));
blacklist(dsp_pcout); dsp = dsp_pcin;
}
did_something = true;
accept;
} }
endcode
did_something = true; // ------------------------------------------------------------------
accept;
subpattern tail
arg first
match next
select next->type.in(\DSP48E1)
select !param(next, \CREG, State::S1).as_bool()
select port(next, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
select nusers(port(next, \C, SigSpec())) > 1
select nusers(port(next, \PCIN, SigSpec())) == 0
index <SigBit> port(next, \C)[0] === port(chain.back().first, \P)[0]
semioptional
endmatch
match next_shift17
if !next_shift17
select next_shift17->type.in(\DSP48E1)
select !param(next_shift17, \CREG, State::S1).as_bool()
select port(next_shift17, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
select nusers(port(next_shift17, \C, SigSpec())) > 1
select nusers(port(next_shift17, \PCIN, SigSpec())) == 0
index <SigBit> port(next_shift17, \C)[0] === port(chain.back().first, \P)[17]
semioptional
endmatch
code next
if (!next)
next = next_shift17;
if (next) {
chain.emplace_back(next, next_shift17);
auto unextend = [](const SigSpec &sig) {
int i;
for (i = GetSize(sig)-1; i > 0; i--)
if (sig[i] != sig[i-1])
break;
// Do not remove non-const sign bit
if (sig[i].wire)
++i;
return sig.extract(0, i);
};
SigSpec sigC = unextend(port(next, \C));
// TODO: Cannot use 'reject' since semioptional
if (next_shift17) {
if (GetSize(sigC)+17 <= GetSize(port(chain.back().first, \P)) &&
port(chain.back().first, \P).extract(17, GetSize(sigC)) != sigC)
subpattern(tail);
}
else {
if (GetSize(sigC) <= GetSize(port(chain.back().first, \P)) &&
port(chain.back().first, \P).extract(0, GetSize(sigC)) != sigC)
subpattern(tail);
}
} else {
if (GetSize(chain) > GetSize(longest_chain))
longest_chain = chain;
}
finally
if (next)
chain.pop_back();
endcode endcode
// ########## // ##########
pattern xilinx_dsp_cascadeAB pattern xilinx_dsp_cascadeAB
udata <std::function<SigSpec(const SigSpec&)>> unextend
state <SigBit> clock state <SigBit> clock
state <SigSpec> sigA sigB state <SigSpec> sigA sigB
@ -113,8 +146,13 @@ udata <SigBit> dffclock
udata <Cell*> dff dffcemux dffrstmux udata <Cell*> dff dffcemux dffrstmux
udata <bool> dffcepol dffrstpol udata <bool> dffcepol dffrstpol
code match dspD
unextend = [](const SigSpec &sig) { select dspD->type.in(\DSP48E1)
select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0)
endmatch
code sigA sigB
auto unextend = [](const SigSpec &sig) {
int i; int i;
for (i = GetSize(sig)-1; i > 0; i--) for (i = GetSize(sig)-1; i > 0; i--)
if (sig[i] != sig[i-1]) if (sig[i] != sig[i-1])
@ -124,14 +162,6 @@ code
++i; ++i;
return sig.extract(0, i); return sig.extract(0, i);
}; };
endcode
match dspD
select dspD->type.in(\DSP48E1)
select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0)
endmatch
code sigA sigB
if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT") if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT")
sigA = unextend(port(dspD, \A)); sigA = unextend(port(dspD, \A));
if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT") if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT")