From 74a5c802f70c181520ce762376e9673a5f6f6465 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 21:01:36 -0700 Subject: [PATCH] Pack CREG --- passes/pmgen/xilinx_dsp.cc | 53 +++++++++++++++++----- passes/pmgen/xilinx_dsp.pmg | 89 +++++++++++++++++++++++++++++-------- 2 files changed, 111 insertions(+), 31 deletions(-) diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index ba8a1de05..10308de57 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -38,6 +38,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffAmux: %s\n", log_id(st.ffAmux, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); 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("ffDmux: %s\n", log_id(st.ffDmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); @@ -53,7 +55,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) Cell *cell = st.dsp; bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell)); - SigSpec C = st.sigC; SigSpec P = st.sigP; if (st.preAdd) { @@ -91,15 +92,21 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) opmode[4] = st.postAddMux->getPort("\\S"); pm.autoremove(st.postAddMux); } - else if (st.ffP && C == P) { - C = SigSpec(); + else if (st.ffP && st.sigC == P) opmode[4] = State::S0; - } else opmode[4] = State::S1; opmode[6] = State::S0; 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); } @@ -143,10 +150,30 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) 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) { SigSpec D_ = cell->getPort("\\D"); - SigSpec D = st.ffB->getPort("\\D"); - SigSpec Q = st.ffB->getPort("\\Q"); + SigSpec D = st.ffD->getPort("\\D"); + SigSpec Q = st.ffD->getPort("\\Q"); D_.replace(Q, D); if (st.ffDmux) { @@ -205,6 +232,12 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) if (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) log(" ffM:%s", log_id(st.ffM)); @@ -214,12 +247,6 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("\n"); } - if (!C.empty()) { - if (GetSize(C) < 48) - C.extend_u0(48, true); - cell->setPort("\\C", C); - } - if (GetSize(P) < 48) P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); cell->setPort("\\P", P); @@ -265,6 +292,8 @@ struct XilinxDspPass : public Pass { for (auto cell : module->cells()) { if (cell->type != "\\DSP48E1") continue; + if (cell->parameters.at("\\CREG", State::S1).as_bool()) + continue; SigSpec &opmode = cell->connections_.at("\\OPMODE"); if (opmode.extract(4,3) != Const::from_string("011")) continue; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 3aab807bd..6b981bc13 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,29 +1,29 @@ pattern xilinx_dsp -state > unextend +state > unextend state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigP +state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAenpol ffADenpol ffBenpol ffDenpol ffMenpol ffPenpol +state ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol state ffPoffset match dsp select dsp->type.in(\DSP48E1) endmatch -code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM - unextend = [](const SigSpec &sig, bool keep_sign) { +code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM + 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 (!keep_sign && sig[i].wire) + if (sig[i].wire) ++i; return sig.extract(0, i); }; - sigA = unextend(port(dsp, \A), false); - sigB = unextend(port(dsp, \B), false); + sigA = unextend(port(dsp, \A)); + sigB = unextend(port(dsp, \B)); sigC = dsp->connections_.at(\C, SigSpec()); sigD = dsp->connections_.at(\D, SigSpec()); @@ -42,6 +42,7 @@ code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigffAmuxY = SigSpec(); sigffBmuxY = SigSpec(); + sigffCmuxY = SigSpec(); sigffDmuxY = SigSpec(); endcode @@ -260,9 +261,9 @@ code sigD sigffDmuxY clock SigSpec D = sigD; D.replace(port(ffD, \Q), port(ffD, \D)); - // Only search for ffBmux if ffB.Q has at - // least 3 users (ffB, dsp, ffBmux) and - // its ffB.D only has two (ffB, ffBmux) + // Only search for ffDmux if ffD.Q has at + // least 3 users (ffD, dsp, ffDmux) and + // its ffD.D only has two (ffD, ffDmux) if (nusers(sigD) >= 3 && nusers(D) == 2) sigffDmuxY = sigD; sigD = std::move(D); @@ -276,7 +277,7 @@ match ffDmux filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD) slice offset 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 AB {\A, \B} filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y)) filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY @@ -290,17 +291,17 @@ match ffMmux if nusers(sigM) == 2 select ffMmux->type.in($mux) choice 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 define AB (BA == \B ? \A : \B) // keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s) select nusers(port(ffMmux, AB)) >= 3 // ffMmux output must have two users: ffMmux and ffM.D select nusers(port(ffMmux, \Y)) == 2 - filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM) - filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y))) + filter GetSize(unextend(port(ffMmux, BA))) <= GetSize(sigM) + filter unextend(port(ffMmux, BA)) == sigM.extract(0, GetSize(unextend(port(ffMmux, BA)))) // 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 pol (AB == \A) set ffMenpol pol optional @@ -367,9 +368,9 @@ match postAdd select nusers(port(postAdd, AB)) <= 3 filter ffMmux || nusers(port(postAdd, AB)) == 2 filter !ffMmux || nusers(port(postAdd, AB)) == 3 - filter GetSize(port(postAdd, AB)) <= GetSize(sigP) - filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB))) - filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1 + filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP) + filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB)))) + filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1 set postAddAB AB optional endmatch @@ -495,6 +496,56 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); 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 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 AB {\A, \B} + filter offset+GetSize(sigffCmuxY) <= GetSize(port(ffCmux, \Y)) + filter port(ffCmux, AB).extract(offset, GetSize(sigffCmuxY)) == sigffCmuxY + define pol (AB == \A) + set ffCenpol pol + optional +endmatch + code accept; endcode -- 2.30.2