diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 5d50c7795..0700d3f61 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -269,7 +269,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) log("ffDmux: %s\n", log_id(st.ffDmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); log("ffM: %s\n", log_id(st.ffM, "--")); - log("ffMmux: %s\n", log_id(st.ffMmux, "--")); + log("ffMcemux: %s\n", log_id(st.ffMcemux, "--")); + log("ffMrstmux: %s\n", log_id(st.ffMrstmux, "--")); log("postAdd: %s\n", log_id(st.postAdd, "--")); log("postAddMux: %s\n", log_id(st.postAddMux, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); @@ -417,38 +418,48 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->setParam("\\DREG", 1); } if (st.ffM) { - if (st.ffMmux) { - SigSpec S = st.ffMmux->getPort("\\S"); + if (st.ffMrstmux) { + SigSpec S = st.ffMrstmux->getPort("\\S"); + cell->setPort("\\RSTM", st.ffMrstpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort("\\RSTM", State::S0); + if (st.ffMcemux) { + SigSpec S = st.ffMcemux->getPort("\\S"); cell->setPort("\\CEM", st.ffMcepol ? S : pm.module->Not(NEW_ID, S)); - pm.autoremove(st.ffMmux); } else cell->setPort("\\CEM", State::S1); SigSpec D = st.ffM->getPort("\\D"); SigSpec Q = st.ffM->getPort("\\Q"); - P.replace(pm.sigmap(D), Q); + st.ffM->connections_.at("\\Q").replace(st.sigM, pm.module->addWire(NEW_ID, GetSize(st.sigM))); + + for (auto c : Q.chunks()) { + auto it = c.wire->attributes.find("\\init"); + if (it == c.wire->attributes.end()) + continue; + for (int i = c.offset; i < c.offset+c.width; i++) { + log_assert(it->second[i] == State::S0 || it->second[i] == State::Sx); + it->second[i] = State::Sx; + } + } cell->setParam("\\MREG", State::S1); - pm.autoremove(st.ffM); } if (st.ffP) { if (st.ffPrstmux) { SigSpec S = st.ffPrstmux->getPort("\\S"); cell->setPort("\\RSTP", st.ffPrstpol ? S : pm.module->Not(NEW_ID, S)); - st.ffPrstmux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else cell->setPort("\\RSTP", State::S0); if (st.ffPcemux) { SigSpec S = st.ffPcemux->getPort("\\S"); cell->setPort("\\CEP", st.ffPcepol ? S : pm.module->Not(NEW_ID, S)); - st.ffPcemux->connections_.at("\\Y").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); } else cell->setPort("\\CEP", State::S1); - SigSpec D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); - P.replace(pm.sigmap(D), Q); st.ffP->connections_.at("\\Q").replace(P, pm.module->addWire(NEW_ID, GetSize(P))); for (auto c : Q.chunks()) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 7db8e95a6..686efd8c4 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -4,14 +4,15 @@ state > unextend state clock state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP state postAddAB postAddMuxAB -state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol ffPrstpol +state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffMrstpol ffPcepol ffPrstpol state ffPoffset -state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMmux ffP ffPcemux ffPrstmux +state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux // subpattern state argQ argD state ffcepol ffrstpol +state ffoffset udata dffD dffQ udata dffclock udata dff dffcemux dffrstmux @@ -159,7 +160,7 @@ code argQ ffD ffDmux ffDcepol sigD clock } endcode -code argD ffM ffMmux ffMcepol sigM sigP clock +code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { argD = sigM; subpattern(out_dffe); @@ -167,8 +168,10 @@ code argD ffM ffMmux ffMcepol sigM sigP clock ffM = dff; clock = dffclock; if (dffcemux) { - ffMmux = dffcemux; + ffMcemux = dffcemux; + ffMrstmux = dffrstmux; ffMcepol = dffcepol; + ffMrstpol = dffrstpol; } sigM = dffQ; } @@ -185,8 +188,8 @@ match postAdd select nusers(port(postAdd, \Y)) == 2 choice AB {\A, \B} select nusers(port(postAdd, AB)) <= 3 - filter ffMmux || nusers(port(postAdd, AB)) == 2 - filter !ffMmux || nusers(port(postAdd, AB)) == 3 + filter ffMcemux || nusers(port(postAdd, AB)) == 2 + filter !ffMcemux || nusers(port(postAdd, AB)) == 3 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 @@ -214,10 +217,10 @@ endcode code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock if (param(dsp, \PREG).as_int() == 0) { - // If ffMmux and no postAdd new-value net must have exactly three users: ffMmux, ffM and ffPcemux - if ((ffMmux && !postAdd && nusers(sigP) == 3) || + // If ffMcemux and no postAdd new-value net must have exactly three users: ffMcemux, ffM and ffPcemux + if ((ffMcemux && !postAdd && nusers(sigP) == 3) || // Otherwise new-value net must have exactly two users: dsp and ffPcemux - ((!ffMmux || postAdd) && nusers(sigP) == 2)) { + ((!ffMcemux || postAdd) && nusers(sigP) == 2)) { argD = sigP; subpattern(out_dffe); if (dff) { @@ -347,107 +350,130 @@ subpattern out_dffe arg argD argQ clock arg unextend +code + dff = nullptr; +endcode + match ffcemux select ffcemux->type.in($mux) // ffcemux output must have two users: ffcemux and ff.D select nusers(port(ffcemux, \Y)) == 2 - filter GetSize(port(ffcemux, \Y)) >= GetSize(argD) - choice BA {\B, \A} - // new-value net must have exactly two users: (upstream) and ffcemux - select nusers(port(ffcemux, BA)) == 2 - - define AB (BA == \B ? \A : \B) + choice AB {\A, \B} // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s) select nusers(port(ffcemux, AB)) >= 3 slice offset GetSize(port(ffcemux, \Y)) - filter GetSize(unextend(port(ffcemux, BA))) <= GetSize(argD) - filter unextend(port(ffcemux, BA)) == argD.extract(0, GetSize(unextend(port(ffcemux, BA)))) - // Remaining bits on argD must not have any other users - filter nusers(argD.extract_end(GetSize(unextend(port(ffcemux, BA))))) <= 1 - - define pol (AB == \A) + define BA (AB == \A ? \B : \A) + index port(ffcemux, BA)[offset] === argD[0] + set ffoffset offset + define pol (BA == \B) set ffcepol pol + semioptional endmatch code argD argQ + dffcemux = ffcemux; if (ffcemux) { + SigSpec BA = port(ffcemux, ffcepol ? \B : \A); + if (ffoffset + GetSize(argD) > GetSize(BA)) + reject; + + for (int i = 1; i < GetSize(argD); i++) + if (BA[ffoffset+i] != argD[i]) + reject; + + SigSpec Y = port(ffcemux, \Y); + argQ = argD; + argD.replace(BA, Y); + argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B)); + dffcemux = ffcemux; dffcepol = ffcepol; - argD = port(ffcemux, \Y); - argQ = port(ffcemux, ffcepol ? \A : \B); } - else - dffcemux = nullptr; endcode match ffrstmux - if !argQ.empty() select ffrstmux->type.in($mux) // ffrstmux output must have two users: ffrstmux and ff.D select nusers(port(ffrstmux, \Y)) == 2 - filter GetSize(port(ffrstmux, \Y)) >= GetSize(argD) choice BA {\B, \A} // DSP48E1 only supports reset to zero select port(ffrstmux, BA).is_fully_zero() - define AB (BA == \B ? \A : \B) - // keep-last-value net must have exactly 2 users: ffrstmux, ffcemux/ - select nusers(port(ffrstmux, AB)) == 2 - slice offset GetSize(port(ffrstmux, \Y)) - filter GetSize(port(ffrstmux, AB)) <= GetSize(argD) - filter port(ffrstmux, AB) == argD.extract(0, GetSize(port(ffrstmux, AB))) - // Remaining bits on argD must not have any other users - filter nusers(argD.extract_end(GetSize(port(ffrstmux, AB)))) <= 1 + define AB (BA == \B ? \A : \B) + index port(ffrstmux, AB)[offset] === argD[0] + filter !ffcemux || ffoffset == offset + set ffoffset offset define pol (AB == \A) set ffrstpol pol + semioptional endmatch code argD argQ + dffrstmux = ffrstmux; if (ffrstmux) { + SigSpec AB = port(ffrstmux, ffcepol ? \A : \B); + if (ffoffset + GetSize(argD) > GetSize(AB)) + reject; + + for (int i = 1; i < GetSize(argD); i++) + if (AB[ffoffset+i] != argD[i]) + reject; + + SigSpec Y = port(ffrstmux, \Y); + argD.replace(AB, Y); + dffrstmux = ffrstmux; dffrstpol = ffrstpol; - argD = port(ffrstmux, \Y); - } - else { - dffrstmux = nullptr; - argQ = SigSpec(); } endcode -match ff_enable - if !argQ.empty() - select ff_enable->type.in($dff) - // DSP48E1 does not support clock inversion - select param(ff_enable, \CLK_POLARITY).as_bool() - index port(ff_enable, \D) === argD - index port(ff_enable, \Q) === argQ -endmatch - match ff - if !ff_enable select ff->type.in($dff) // DSP48E1 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() - index port(ff, \D) === argD + + slice offset GetSize(port(ff, \D)) + index port(ff, \D)[offset] === argD[0] + + filter (!ffcemux && !ffrstmux) || ffoffset == offset + set ffoffset offset + semioptional endmatch -code - if (ff_enable) - dff = ff_enable; - else - dff = ff; - if (dff) { - dffQ = port(dff, \Q); +code argQ + if (ff) { + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) + reject; + } - for (auto c : dffQ.chunks()) { + SigSpec D = port(ff, \D); + if (ffoffset + GetSize(argD) > GetSize(D)) + reject; + for (int i = 1; i < GetSize(argD); i++) + if (D[ffoffset+i] != argD[i]) + reject; + + SigSpec Q = port(ff, \Q); + if (ffcemux) { + for (int i = 0; i < GetSize(argQ); i++) + if (Q[ffoffset+i] != argQ[i]) + reject; + } + else { + argQ = argD; + argQ.replace(D, Q); + } + + for (auto c : argQ.chunks()) { if (c.wire->get_bool_attribute(\keep)) reject; Const init = c.wire->attributes.at(\init, State::Sx); @@ -455,13 +481,11 @@ code reject; } - if (clock != SigBit()) { - if (port(dff, \CLK) != clock) - reject; - } + dff = ff; + dffQ = argQ; dffclock = port(dff, \CLK); } // No enable/reset mux possible without flop - else if (ffcemux || ffrstmux) + else if (dffcemux || dffrstmux) reject; endcode