From 0d709d2bb56fed3a1100b72071ca8d584746a095 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 11 Sep 2019 10:15:19 -0700 Subject: [PATCH] Add support for A/B/C/D/AD reset --- passes/pmgen/xilinx_dsp.cc | 121 +++++++++------------------ passes/pmgen/xilinx_dsp.pmg | 159 +++++++++++++++++++++++------------- 2 files changed, 141 insertions(+), 139 deletions(-) diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 0700d3f61..fdd0ac2fa 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -257,25 +257,16 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) #if 1 log("\n"); log("preAdd: %s\n", log_id(st.preAdd, "--")); - log("ffAD: %s\n", log_id(st.ffAD, "--")); - log("ffADmux: %s\n", log_id(st.ffADmux, "--")); - log("ffA: %s\n", log_id(st.ffA, "--")); - 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("ffAD: %s %s %s\n", log_id(st.ffAD, "--"), log_id(st.ffADcemux, "--"), log_id(st.ffADrstmux, "--")); + log("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAcemux, "--"), log_id(st.ffArstmux, "--")); + log("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBcemux, "--"), log_id(st.ffBrstmux, "--")); + log("ffC: %s %s %s\n", log_id(st.ffC, "--"), log_id(st.ffCcemux, "--"), log_id(st.ffCrstmux, "--")); + log("ffD: %s %s %s\n", log_id(st.ffD, "--"), log_id(st.ffDcemux, "--"), log_id(st.ffDrstmux, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); - log("ffM: %s\n", log_id(st.ffM, "--")); - log("ffMcemux: %s\n", log_id(st.ffMcemux, "--")); - log("ffMrstmux: %s\n", log_id(st.ffMrstmux, "--")); + log("ffM: %s %s %s\n", log_id(st.ffM, "--"), log_id(st.ffMcemux, "--"), 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, "--")); - log("ffPcemux: %s\n", log_id(st.ffPcemux, "--")); - log("ffPrstmux: %s\n", log_id(st.ffPrstmux, "--")); + log("ffP: %s %s %s\n", log_id(st.ffP, "--"), log_id(st.ffPcemux, "--"), log_id(st.ffPrstmux, "--")); #endif log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); @@ -297,8 +288,8 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) cell->connections_.at("\\INMODE") = Const::from_string("00100"); if (st.ffAD) { - if (st.ffADmux) { - SigSpec S = st.ffADmux->getPort("\\S"); + if (st.ffADcemux) { + SigSpec S = st.ffADcemux->getPort("\\S"); cell->setPort("\\CEAD", st.ffADcepol ? S : pm.module->Not(NEW_ID, S)); } else @@ -341,80 +332,46 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) { cell->setPort("\\CLK", st.clock); - if (st.ffA) { - SigSpec A = cell->getPort("\\A"); - SigSpec D = st.ffA->getPort("\\D"); - SigSpec Q = pm.sigmap(st.ffA->getPort("\\Q")); + auto f = [&pm,cell](IdString port, Cell* ff, Cell* cemux, bool cepol, IdString ceport, Cell* rstmux, bool rstpol, IdString rstport) { + SigSpec A = cell->getPort(port); + SigSpec D = ff->getPort("\\D"); + SigSpec Q = pm.sigmap(ff->getPort("\\Q")); A.replace(Q, D); - if (st.ffAmux) { - SigSpec Y = st.ffAmux->getPort("\\Y"); - SigSpec AB = st.ffAmux->getPort(st.ffAcepol ? "\\B" : "\\A"); - SigSpec S = st.ffAmux->getPort("\\S"); + if (rstmux) { + SigSpec Y = rstmux->getPort("\\Y"); + SigSpec AB = rstmux->getPort(rstpol ? "\\A" : "\\B"); + SigSpec S = rstmux->getPort("\\S"); A.replace(Y, AB); - cell->setPort("\\CEA2", st.ffAcepol ? S : pm.module->Not(NEW_ID, S)); + cell->setPort(rstport, rstpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort(rstport, State::S0); + if (cemux) { + SigSpec Y = cemux->getPort("\\Y"); + SigSpec BA = cemux->getPort(cepol ? "\\B" : "\\A"); + SigSpec S = cemux->getPort("\\S"); + A.replace(Y, BA); + cell->setPort(ceport, cepol ? S : pm.module->Not(NEW_ID, S)); } else - cell->setPort("\\CEA2", State::S1); - cell->setPort("\\A", A); + cell->setPort(ceport, State::S1); + cell->setPort(port, A); + }; + if (st.ffA) { + f("\\A", st.ffA, st.ffAcemux, st.ffAcepol, "\\CEA2", st.ffArstmux, st.ffArstpol, "\\RSTA"); cell->setParam("\\AREG", 1); } if (st.ffB) { - SigSpec B = cell->getPort("\\B"); - SigSpec D = st.ffB->getPort("\\D"); - SigSpec Q = st.ffB->getPort("\\Q"); - B.replace(Q, D); - if (st.ffBmux) { - SigSpec Y = st.ffBmux->getPort("\\Y"); - SigSpec AB = st.ffBmux->getPort(st.ffBcepol ? "\\B" : "\\A"); - SigSpec S = st.ffBmux->getPort("\\S"); - B.replace(Y, AB); - cell->setPort("\\CEB2", st.ffBcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CEB2", State::S1); - cell->setPort("\\B", B); - + f("\\B", st.ffB, st.ffBcemux, st.ffBcepol, "\\CEB2", st.ffBrstmux, st.ffBrstpol, "\\RSTB"); 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.ffCcepol ? "\\B" : "\\A"); - SigSpec S = st.ffCmux->getPort("\\S"); - C.replace(Y, AB); - - cell->setPort("\\CEC", st.ffCcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CEC", State::S1); - cell->setPort("\\C", C); - + f("\\C", st.ffC, st.ffCcemux, st.ffCcepol, "\\CEC", st.ffCrstmux, st.ffCrstpol, "\\RSTC"); cell->setParam("\\CREG", 1); } if (st.ffD) { - SigSpec D_ = cell->getPort("\\D"); - SigSpec D = st.ffD->getPort("\\D"); - SigSpec Q = st.ffD->getPort("\\Q"); - D_.replace(Q, D); - - if (st.ffDmux) { - SigSpec Y = st.ffDmux->getPort("\\Y"); - SigSpec AB = st.ffDmux->getPort(st.ffDcepol ? "\\B" : "\\A"); - SigSpec S = st.ffDmux->getPort("\\S"); - D_.replace(Y, AB); - - cell->setPort("\\CED", st.ffDcepol ? S : pm.module->Not(NEW_ID, S)); - } - else - cell->setPort("\\CED", State::S1); - cell->setPort("\\D", D_); - + f("\\D", st.ffD, st.ffDcemux, st.ffDcepol, "\\CED", st.ffDrstmux, st.ffDrstpol, "\\RSTD"); cell->setParam("\\DREG", 1); } if (st.ffM) { @@ -516,9 +473,9 @@ struct XilinxDspPass : public Pass { log("\n"); log(" xilinx_dsp [options] [selection]\n"); log("\n"); - log("Pack input registers (A, B, C, D, AD; with optional enable), pipeline registers\n"); - log("(M; with optional enable), output registers (P; with optional enable),\n"); - log("pre-adder and/or post-adder into Xilinx DSP resources.\n"); + log("Pack input registers (A, B, C, D, AD; with optional enable/reset), pipeline\n"); + log("registers (M; with optional enable/reset), output registers (P; with optional\n"); + log("enable/reset), pre-adder and/or post-adder into Xilinx DSP resources.\n"); log("\n"); log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n"); log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n"); @@ -528,8 +485,6 @@ struct XilinxDspPass : public Pass { log("where 'P' is right-shifted by 18-bits and used as an input to the post-adder (a\n"); log("pattern common for summing partial products to implement wide multiplies).\n"); log("\n"); - log("Not currently supported: reset (RST*) inputs on any register.\n"); - log("\n"); log("\n"); log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n"); diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 686efd8c4..6e726d1c2 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -2,12 +2,13 @@ pattern xilinx_dsp state > unextend state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP +state sigA sigffAcemuxY sigB sigffBcemuxY sigC sigffCcemuxY sigD sigffDcemuxY sigM sigP state postAddAB postAddMuxAB -state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffMrstpol ffPcepol ffPrstpol -state ffPoffset +state ffAcepol ffADcepol ffBcepol ffCcepol ffDcepol ffMcepol ffPcepol +state ffArstpol ffADrstpol ffBrstpol ffCrstpol ffDrstpol ffMrstpol ffPrstpol -state ffAD ffADmux ffA ffAmux ffB ffBmux ffC ffCmux ffD ffDmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux +state ffAD ffADcemux ffADrstmux ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffC ffCcemux ffCrstmux +state ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux // subpattern state argQ argD @@ -54,7 +55,7 @@ code unextend sigA sigB sigC sigD sigM sigM = P; endcode -code argQ ffAD ffADmux ffADcepol sigA clock +code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock if (param(dsp, \ADREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); @@ -62,8 +63,10 @@ code argQ ffAD ffADmux ffADcepol sigA clock ffAD = dff; clock = dffclock; if (dffcemux) { - ffADmux = dffcemux; + ffADcemux = dffcemux; + ffADrstmux = dffrstmux; ffADcepol = dffcepol; + ffADrstpol = dffrstpol; } sigA = dffD; } @@ -100,7 +103,7 @@ code sigA sigD } endcode -code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol +code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol // Only search for ffA if there was a pre-adder // (otherwise ffA would have been matched as ffAD) if (preAdd) { @@ -111,8 +114,10 @@ code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol ffA = dff; clock = dffclock; if (dffcemux) { - ffAmux = dffcemux; + ffAcemux = dffcemux; + ffArstmux = dffrstmux; ffAcepol = dffcepol; + ffArstpol = dffrstpol; } sigA = dffD; } @@ -121,14 +126,16 @@ code argQ ffA ffAmux ffAcepol sigA clock ffAD ffADmux ffADcepol // And if there wasn't a pre-adder, // move AD register to A else if (ffAD) { - log_assert(!ffA && !ffAmux); + log_assert(!ffA && !ffAcemux && !ffArstmux); std::swap(ffA, ffAD); - std::swap(ffAmux, ffADmux); + std::swap(ffAcemux, ffADcemux); + std::swap(ffArstmux, ffADrstmux); ffAcepol = ffADcepol; + ffArstpol = ffADrstpol; } endcode -code argQ ffB ffBmux ffBcepol sigB clock +code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock if (param(dsp, \BREG).as_int() == 0) { argQ = sigB; subpattern(in_dffe); @@ -136,15 +143,17 @@ code argQ ffB ffBmux ffBcepol sigB clock ffB = dff; clock = dffclock; if (dffcemux) { - ffBmux = dffcemux; + ffBcemux = dffcemux; + ffBrstmux = dffrstmux; ffBcepol = dffcepol; + ffBrstpol = dffrstpol; } sigB = dffD; } } endcode -code argQ ffD ffDmux ffDcepol sigD clock +code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock if (param(dsp, \DREG).as_int() == 0) { argQ = sigD; subpattern(in_dffe); @@ -152,8 +161,10 @@ code argQ ffD ffDmux ffDcepol sigD clock ffD = dff; clock = dffclock; if (dffcemux) { - ffDmux = dffcemux; + ffDcemux = dffcemux; + ffDrstmux = dffrstmux; ffDcepol = dffcepol; + ffDrstpol = dffrstpol; } sigD = dffD; } @@ -255,16 +266,18 @@ code sigC sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A); endcode -code argQ ffC ffCmux ffCcepol sigC clock - if (param(dsp, \CREG).as_int() == 0) { +code argQ ffC ffCcemux ffCrstmux ffCcepol ffCrstpol sigC clock + if (param(dsp, \CREG).as_int() == 0 && sigC != sigP) { argQ = sigC; subpattern(in_dffe); if (dff) { ffC = dff; clock = dffclock; if (dffcemux) { - ffCmux = dffcemux; + ffCcemux = dffcemux; + ffCrstmux = dffrstmux; ffCcepol = dffcepol; + ffCrstpol = dffrstpol; } sigC = dffD; } @@ -278,67 +291,102 @@ endcode // ####################### subpattern in_dffe -arg argQ clock ffcepol +arg argD argQ clock + +code + dff = nullptr; + for (auto c : argQ.chunks()) { + if (!c.wire) + reject; + if (c.wire->get_bool_attribute(\keep)) + reject; + } +endcode match ff select ff->type.in($dff) // DSP48E1 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() - filter GetSize(port(ff, \Q)) >= GetSize(argQ) - slice offset GetSize(port(ff, \Q)) - filter offset+GetSize(argQ) <= GetSize(port(ff, \Q)) - filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ - semioptional + + slice offset GetSize(port(ff, \D)) + index port(ff, \Q)[offset] === argQ[0] + set ffoffset offset endmatch -code argQ - if (ff) { - for (auto c : argQ.chunks()) - if (c.wire->get_bool_attribute(\keep)) - reject; +code argQ argD +{ + if (clock != SigBit()) { + if (port(ff, \CLK) != clock) + reject; + } - if (clock != SigBit()) { - if (port(ff, \CLK) != clock) - reject; - } - dffclock = port(ff, \CLK); + SigSpec Q = port(ff, \Q); + if (ffoffset + GetSize(argQ) > GetSize(Q)) + reject; + for (int i = 1; i < GetSize(argQ); i++) + if (Q[ffoffset+i] != argQ[i]) + reject; - dff = ff; - dffD = argQ; - dffD.replace(port(ff, \Q), port(ff, \D)); - // Only search for ffcemux if argQ has at - // least 3 users (ff, , ffcemux) and - // its ff.D only has two (ff, ffcemux) + dff = ff; + dffclock = port(ff, \CLK); + dffD = argQ; + argD = port(ff, \D); + argQ = Q; + dffD.replace(argQ, argD); + // Only search for ffrstmux if dffD only + // has two (ff, ffrstmux) users + if (nusers(dffD) > 2) + argD = SigSpec(); +} +endcode + +match ffrstmux + if !argD.empty() + select ffrstmux->type.in($mux) + index port(ffrstmux, \Y) === argD + + choice BA {\B, \A} + // DSP48E1 only supports reset to zero + select port(ffrstmux, BA).is_fully_zero() + + define pol (BA == \B) + set ffrstpol pol + semioptional +endmatch + +code argD + if (ffrstmux) { + dffrstmux = ffrstmux; + dffrstpol = ffrstpol; + argD = port(ffrstmux, ffrstpol ? \A : \B); + dffD.replace(port(ffrstmux, \Y), argD); + + // Only search for ffrstmux if argQ has at + // least 3 users (ff, , ffrstmux) and + // dffD only has two (ff, ffrstmux) if (!(nusers(argQ) >= 3 && nusers(dffD) == 2)) - argQ = SigSpec(); - } - else { - dff = nullptr; - argQ = SigSpec(); + argD = SigSpec(); } + else + dffrstmux = nullptr; endcode match ffcemux - if !argQ.empty() + if !argD.empty() select ffcemux->type.in($mux) - index port(ffcemux, \Y) === port(ff, \D) - filter GetSize(port(ffcemux, \Y)) >= GetSize(dffD) - slice offset GetSize(port(ffcemux, \Y)) - filter offset+GetSize(dffD) <= GetSize(port(ffcemux, \Y)) - filter port(ffcemux, \Y).extract(offset, GetSize(dffD)) == dffD + index port(ffcemux, \Y) === argD choice AB {\A, \B} - filter offset+GetSize(argQ) <= GetSize(port(ffcemux, \Y)) - filter port(ffcemux, AB).extract(offset, GetSize(argQ)) == argQ + index port(ffcemux, AB) === argQ define pol (AB == \A) set ffcepol pol semioptional endmatch -code +code argD if (ffcemux) { dffcemux = ffcemux; dffcepol = ffcepol; - dffD = port(ffcemux, dffcepol ? \B : \A); + dffD.replace(port(ffcemux, \Y), argD); } else dffcemux = nullptr; @@ -379,7 +427,6 @@ code argD argQ 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; @@ -440,7 +487,7 @@ match ff select param(ff, \CLK_POLARITY).as_bool() slice offset GetSize(port(ff, \D)) - index port(ff, \D)[offset] === argD[0] + index port(ff, \D)[offset] === argD[0] filter (!ffcemux && !ffrstmux) || ffoffset == offset set ffoffset offset -- 2.30.2