mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-20 04:43:40 +00:00
Pack CREG
This commit is contained in:
parent
6a9205280f
commit
74a5c802f7
2 changed files with 111 additions and 31 deletions
|
@ -38,6 +38,8 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
log("ffAmux: %s\n", log_id(st.ffAmux, "--"));
|
log("ffAmux: %s\n", log_id(st.ffAmux, "--"));
|
||||||
log("ffB: %s\n", log_id(st.ffB, "--"));
|
log("ffB: %s\n", log_id(st.ffB, "--"));
|
||||||
log("ffBmux: %s\n", log_id(st.ffBmux, "--"));
|
log("ffBmux: %s\n", log_id(st.ffBmux, "--"));
|
||||||
|
log("ffC: %s\n", log_id(st.ffC, "--"));
|
||||||
|
log("ffCmux: %s\n", log_id(st.ffCmux, "--"));
|
||||||
log("ffD: %s\n", log_id(st.ffD, "--"));
|
log("ffD: %s\n", log_id(st.ffD, "--"));
|
||||||
log("ffDmux: %s\n", log_id(st.ffDmux, "--"));
|
log("ffDmux: %s\n", log_id(st.ffDmux, "--"));
|
||||||
log("dsp: %s\n", log_id(st.dsp, "--"));
|
log("dsp: %s\n", log_id(st.dsp, "--"));
|
||||||
|
@ -53,7 +55,6 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
|
|
||||||
Cell *cell = st.dsp;
|
Cell *cell = st.dsp;
|
||||||
bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell));
|
bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell));
|
||||||
SigSpec C = st.sigC;
|
|
||||||
SigSpec P = st.sigP;
|
SigSpec P = st.sigP;
|
||||||
|
|
||||||
if (st.preAdd) {
|
if (st.preAdd) {
|
||||||
|
@ -91,15 +92,21 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
opmode[4] = st.postAddMux->getPort("\\S");
|
opmode[4] = st.postAddMux->getPort("\\S");
|
||||||
pm.autoremove(st.postAddMux);
|
pm.autoremove(st.postAddMux);
|
||||||
}
|
}
|
||||||
else if (st.ffP && C == P) {
|
else if (st.ffP && st.sigC == P)
|
||||||
C = SigSpec();
|
|
||||||
opmode[4] = State::S0;
|
opmode[4] = State::S0;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
opmode[4] = State::S1;
|
opmode[4] = State::S1;
|
||||||
opmode[6] = State::S0;
|
opmode[6] = State::S0;
|
||||||
opmode[5] = State::S1;
|
opmode[5] = State::S1;
|
||||||
|
|
||||||
|
if (opmode[4] != State::S0) {
|
||||||
|
if (st.postAddMuxAB == "\\A")
|
||||||
|
st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool());
|
||||||
|
else
|
||||||
|
st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool());
|
||||||
|
cell->setPort("\\C", st.sigC);
|
||||||
|
}
|
||||||
|
|
||||||
pm.autoremove(st.postAdd);
|
pm.autoremove(st.postAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,10 +150,30 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
|
|
||||||
cell->setParam("\\BREG", 1);
|
cell->setParam("\\BREG", 1);
|
||||||
}
|
}
|
||||||
|
if (st.ffC) {
|
||||||
|
SigSpec C = cell->getPort("\\C");
|
||||||
|
SigSpec D = st.ffC->getPort("\\D");
|
||||||
|
SigSpec Q = st.ffC->getPort("\\Q");
|
||||||
|
C.replace(Q, D);
|
||||||
|
|
||||||
|
if (st.ffCmux) {
|
||||||
|
SigSpec Y = st.ffCmux->getPort("\\Y");
|
||||||
|
SigSpec AB = st.ffCmux->getPort(st.ffCenpol ? "\\B" : "\\A");
|
||||||
|
SigSpec S = st.ffCmux->getPort("\\S");
|
||||||
|
C.replace(Y, AB);
|
||||||
|
|
||||||
|
cell->setPort("\\CEC", st.ffCenpol ? S : pm.module->Not(NEW_ID, S));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cell->setPort("\\CEC", State::S1);
|
||||||
|
cell->setPort("\\C", C);
|
||||||
|
|
||||||
|
cell->setParam("\\CREG", 1);
|
||||||
|
}
|
||||||
if (st.ffD) {
|
if (st.ffD) {
|
||||||
SigSpec D_ = cell->getPort("\\D");
|
SigSpec D_ = cell->getPort("\\D");
|
||||||
SigSpec D = st.ffB->getPort("\\D");
|
SigSpec D = st.ffD->getPort("\\D");
|
||||||
SigSpec Q = st.ffB->getPort("\\Q");
|
SigSpec Q = st.ffD->getPort("\\Q");
|
||||||
D_.replace(Q, D);
|
D_.replace(Q, D);
|
||||||
|
|
||||||
if (st.ffDmux) {
|
if (st.ffDmux) {
|
||||||
|
@ -205,6 +232,12 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
if (st.ffB)
|
if (st.ffB)
|
||||||
log(" ffB:%s", log_id(st.ffB));
|
log(" ffB:%s", log_id(st.ffB));
|
||||||
|
|
||||||
|
if (st.ffC)
|
||||||
|
log(" ffC:%s", log_id(st.ffC));
|
||||||
|
|
||||||
|
if (st.ffD)
|
||||||
|
log(" ffD:%s", log_id(st.ffD));
|
||||||
|
|
||||||
if (st.ffM)
|
if (st.ffM)
|
||||||
log(" ffM:%s", log_id(st.ffM));
|
log(" ffM:%s", log_id(st.ffM));
|
||||||
|
|
||||||
|
@ -214,12 +247,6 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!C.empty()) {
|
|
||||||
if (GetSize(C) < 48)
|
|
||||||
C.extend_u0(48, true);
|
|
||||||
cell->setPort("\\C", C);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetSize(P) < 48)
|
if (GetSize(P) < 48)
|
||||||
P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
|
P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
|
||||||
cell->setPort("\\P", P);
|
cell->setPort("\\P", P);
|
||||||
|
@ -265,6 +292,8 @@ struct XilinxDspPass : public Pass {
|
||||||
for (auto cell : module->cells()) {
|
for (auto cell : module->cells()) {
|
||||||
if (cell->type != "\\DSP48E1")
|
if (cell->type != "\\DSP48E1")
|
||||||
continue;
|
continue;
|
||||||
|
if (cell->parameters.at("\\CREG", State::S1).as_bool())
|
||||||
|
continue;
|
||||||
SigSpec &opmode = cell->connections_.at("\\OPMODE");
|
SigSpec &opmode = cell->connections_.at("\\OPMODE");
|
||||||
if (opmode.extract(4,3) != Const::from_string("011"))
|
if (opmode.extract(4,3) != Const::from_string("011"))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
pattern xilinx_dsp
|
pattern xilinx_dsp
|
||||||
|
|
||||||
state <std::function<SigSpec(const SigSpec&, bool)>> unextend
|
state <std::function<SigSpec(const SigSpec&)>> unextend
|
||||||
state <SigBit> clock
|
state <SigBit> clock
|
||||||
state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigP
|
state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP
|
||||||
state <IdString> postAddAB postAddMuxAB
|
state <IdString> postAddAB postAddMuxAB
|
||||||
state <bool> ffAenpol ffADenpol ffBenpol ffDenpol ffMenpol ffPenpol
|
state <bool> ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol
|
||||||
state <int> ffPoffset
|
state <int> ffPoffset
|
||||||
|
|
||||||
match dsp
|
match dsp
|
||||||
select dsp->type.in(\DSP48E1)
|
select dsp->type.in(\DSP48E1)
|
||||||
endmatch
|
endmatch
|
||||||
|
|
||||||
code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM
|
code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM
|
||||||
unextend = [](const SigSpec &sig, bool keep_sign) {
|
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])
|
||||||
break;
|
break;
|
||||||
// Do not remove non-const sign bit
|
// Do not remove non-const sign bit
|
||||||
if (!keep_sign && sig[i].wire)
|
if (sig[i].wire)
|
||||||
++i;
|
++i;
|
||||||
return sig.extract(0, i);
|
return sig.extract(0, i);
|
||||||
};
|
};
|
||||||
sigA = unextend(port(dsp, \A), false);
|
sigA = unextend(port(dsp, \A));
|
||||||
sigB = unextend(port(dsp, \B), false);
|
sigB = unextend(port(dsp, \B));
|
||||||
|
|
||||||
sigC = dsp->connections_.at(\C, SigSpec());
|
sigC = dsp->connections_.at(\C, SigSpec());
|
||||||
sigD = dsp->connections_.at(\D, SigSpec());
|
sigD = dsp->connections_.at(\D, SigSpec());
|
||||||
|
@ -42,6 +42,7 @@ code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM
|
||||||
|
|
||||||
sigffAmuxY = SigSpec();
|
sigffAmuxY = SigSpec();
|
||||||
sigffBmuxY = SigSpec();
|
sigffBmuxY = SigSpec();
|
||||||
|
sigffCmuxY = SigSpec();
|
||||||
sigffDmuxY = SigSpec();
|
sigffDmuxY = SigSpec();
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
@ -260,9 +261,9 @@ code sigD sigffDmuxY clock
|
||||||
|
|
||||||
SigSpec D = sigD;
|
SigSpec D = sigD;
|
||||||
D.replace(port(ffD, \Q), port(ffD, \D));
|
D.replace(port(ffD, \Q), port(ffD, \D));
|
||||||
// Only search for ffBmux if ffB.Q has at
|
// Only search for ffDmux if ffD.Q has at
|
||||||
// least 3 users (ffB, dsp, ffBmux) and
|
// least 3 users (ffD, dsp, ffDmux) and
|
||||||
// its ffB.D only has two (ffB, ffBmux)
|
// its ffD.D only has two (ffD, ffDmux)
|
||||||
if (nusers(sigD) >= 3 && nusers(D) == 2)
|
if (nusers(sigD) >= 3 && nusers(D) == 2)
|
||||||
sigffDmuxY = sigD;
|
sigffDmuxY = sigD;
|
||||||
sigD = std::move(D);
|
sigD = std::move(D);
|
||||||
|
@ -276,7 +277,7 @@ match ffDmux
|
||||||
filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD)
|
filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD)
|
||||||
slice offset GetSize(port(ffDmux, \Y))
|
slice offset GetSize(port(ffDmux, \Y))
|
||||||
filter offset+GetSize(sigD) <= GetSize(port(ffDmux, \Y))
|
filter offset+GetSize(sigD) <= GetSize(port(ffDmux, \Y))
|
||||||
filter port(ffDmux, \Y).extract(offset, GetSize(sigB)) == sigD
|
filter port(ffDmux, \Y).extract(offset, GetSize(sigD)) == sigD
|
||||||
choice <IdString> AB {\A, \B}
|
choice <IdString> AB {\A, \B}
|
||||||
filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y))
|
filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y))
|
||||||
filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY
|
filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY
|
||||||
|
@ -290,17 +291,17 @@ match ffMmux
|
||||||
if nusers(sigM) == 2
|
if nusers(sigM) == 2
|
||||||
select ffMmux->type.in($mux)
|
select ffMmux->type.in($mux)
|
||||||
choice <IdString> BA {\B, \A}
|
choice <IdString> BA {\B, \A}
|
||||||
// new-value net must have exactly two users: dsp and ffM
|
// new-value net must have exactly two users: dsp and ffMmux
|
||||||
select nusers(port(ffMmux, BA)) == 2
|
select nusers(port(ffMmux, BA)) == 2
|
||||||
define <IdString> AB (BA == \B ? \A : \B)
|
define <IdString> AB (BA == \B ? \A : \B)
|
||||||
// keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s)
|
// keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s)
|
||||||
select nusers(port(ffMmux, AB)) >= 3
|
select nusers(port(ffMmux, AB)) >= 3
|
||||||
// ffMmux output must have two users: ffMmux and ffM.D
|
// ffMmux output must have two users: ffMmux and ffM.D
|
||||||
select nusers(port(ffMmux, \Y)) == 2
|
select nusers(port(ffMmux, \Y)) == 2
|
||||||
filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM)
|
filter GetSize(unextend(port(ffMmux, BA))) <= GetSize(sigM)
|
||||||
filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y)))
|
filter unextend(port(ffMmux, BA)) == sigM.extract(0, GetSize(unextend(port(ffMmux, BA))))
|
||||||
// Remaining bits on sigM must not have any other users
|
// Remaining bits on sigM must not have any other users
|
||||||
filter nusers(sigM.extract_end(GetSize(port(ffMmux, BA)))) <= 1
|
filter nusers(sigM.extract_end(GetSize(unextend(port(ffMmux, BA))))) <= 1
|
||||||
define <bool> pol (AB == \A)
|
define <bool> pol (AB == \A)
|
||||||
set ffMenpol pol
|
set ffMenpol pol
|
||||||
optional
|
optional
|
||||||
|
@ -367,9 +368,9 @@ match postAdd
|
||||||
select nusers(port(postAdd, AB)) <= 3
|
select nusers(port(postAdd, AB)) <= 3
|
||||||
filter ffMmux || nusers(port(postAdd, AB)) == 2
|
filter ffMmux || nusers(port(postAdd, AB)) == 2
|
||||||
filter !ffMmux || nusers(port(postAdd, AB)) == 3
|
filter !ffMmux || nusers(port(postAdd, AB)) == 3
|
||||||
filter GetSize(port(postAdd, AB)) <= GetSize(sigP)
|
filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP)
|
||||||
filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB)))
|
filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB))))
|
||||||
filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1
|
filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1
|
||||||
set postAddAB AB
|
set postAddAB AB
|
||||||
optional
|
optional
|
||||||
endmatch
|
endmatch
|
||||||
|
@ -495,6 +496,56 @@ code sigC
|
||||||
sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
|
sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
match ffC
|
||||||
|
if param(dsp, \CREG).as_int() == 0
|
||||||
|
select ffC->type.in($dff)
|
||||||
|
// DSP48E1 does not support clock inversion
|
||||||
|
select param(ffC, \CLK_POLARITY).as_bool()
|
||||||
|
filter GetSize(port(ffC, \Q)) >= GetSize(sigD)
|
||||||
|
slice offset GetSize(port(ffC, \Q))
|
||||||
|
filter offset+GetSize(sigC) <= GetSize(port(ffC, \Q))
|
||||||
|
filter port(ffC, \Q).extract(offset, GetSize(sigC)) == sigC
|
||||||
|
optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code sigC sigffCmuxY clock
|
||||||
|
if (ffC) {
|
||||||
|
for (auto b : port(ffC, \Q))
|
||||||
|
if (b.wire->get_bool_attribute(\keep))
|
||||||
|
reject;
|
||||||
|
|
||||||
|
SigBit c = port(ffC, \CLK).as_bit();
|
||||||
|
if (clock != SigBit() && c != clock)
|
||||||
|
reject;
|
||||||
|
clock = c;
|
||||||
|
|
||||||
|
SigSpec C = sigC;
|
||||||
|
C.replace(port(ffC, \Q), port(ffC, \D));
|
||||||
|
// Only search for ffCmux if ffC.Q has at
|
||||||
|
// least 3 users (ffC, dsp, ffCmux) and
|
||||||
|
// its ffC.D only has two (ffC, ffCmux)
|
||||||
|
if (nusers(sigC) >= 3 && nusers(C) == 2)
|
||||||
|
sigffCmuxY = sigC;
|
||||||
|
sigC = std::move(C);
|
||||||
|
}
|
||||||
|
endcode
|
||||||
|
|
||||||
|
match ffCmux
|
||||||
|
if !sigffCmuxY.empty()
|
||||||
|
select ffCmux->type.in($mux)
|
||||||
|
index <SigSpec> port(ffCmux, \Y) === port(ffC, \D)
|
||||||
|
filter GetSize(port(ffCmux, \Y)) >= GetSize(sigC)
|
||||||
|
slice offset GetSize(port(ffCmux, \Y))
|
||||||
|
filter offset+GetSize(sigC) <= GetSize(port(ffCmux, \Y))
|
||||||
|
filter port(ffCmux, \Y).extract(offset, GetSize(sigC)) == sigC
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
filter offset+GetSize(sigffCmuxY) <= GetSize(port(ffCmux, \Y))
|
||||||
|
filter port(ffCmux, AB).extract(offset, GetSize(sigffCmuxY)) == sigffCmuxY
|
||||||
|
define <bool> pol (AB == \A)
|
||||||
|
set ffCenpol pol
|
||||||
|
optional
|
||||||
|
endmatch
|
||||||
|
|
||||||
code
|
code
|
||||||
accept;
|
accept;
|
||||||
endcode
|
endcode
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue