From e926f2973e5c6bf8e00cd67fc44200ceb47e215e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 6 Sep 2019 14:06:57 -0700 Subject: [PATCH] Add support for pre-adder and AD register --- passes/pmgen/xilinx_dsp.cc | 31 ++++++++++- passes/pmgen/xilinx_dsp.pmg | 101 ++++++++++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 38b1a12be..9587ed28a 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -31,6 +31,9 @@ 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, "--")); @@ -51,8 +54,34 @@ void pack_xilinx_dsp(dict &bit_to_driver, xilinx_dsp_pm &pm) SigSpec C = st.sigC; SigSpec P = st.sigP; + if (st.preAdd) { + log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type)); + bool A_SIGNED = st.preAdd->getParam("\\A_SIGNED").as_bool(); + bool D_SIGNED = st.preAdd->getParam("\\B_SIGNED").as_bool(); + if (st.sigA == st.preAdd->getPort("\\B")) + std::swap(A_SIGNED, D_SIGNED); + st.sigA.extend_u0(30, A_SIGNED); + st.sigD.extend_u0(25, D_SIGNED); + cell->setPort("\\A", st.sigA); + cell->setPort("\\D", st.sigD); + cell->connections_.at("\\INMODE") = Const::from_string("00100"); + + if (st.ffAD) { + if (st.ffADmux) { + SigSpec S = st.ffADmux->getPort("\\S"); + cell->setPort("\\CEAD", st.ffADenpol ? S : pm.module->Not(NEW_ID, S)); + } + else + cell->setPort("\\CEAD", State::S1); + cell->setParam("\\ADREG", 1); + } + + cell->setParam("\\USE_DPORT", Const("TRUE")); + + pm.autoremove(st.preAdd); + } if (st.postAdd) { - log(" adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); + log(" postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); SigSpec &opmode = cell->connections_.at("\\OPMODE"); if (st.postAddMux) { diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 5cea69b16..83963804b 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,16 +1,16 @@ pattern xilinx_dsp state clock -state sigA sigffAmuxY sigB sigffBmuxY sigC sigM sigP +state sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigM sigP state postAddAB postAddMuxAB -state ffAenpol ffBenpol ffMenpol ffPenpol +state ffAenpol ffADenpol ffBenpol ffMenpol ffPenpol state ffPoffset match dsp select dsp->type.in(\DSP48E1) endmatch -code sigA sigffAmuxY sigB sigffBmuxY sigM +code sigA sigffAmuxY sigB sigffBmuxY sigD sigM sigA = port(dsp, \A); int i; for (i = GetSize(sigA)-1; i > 0; i--) @@ -29,6 +29,8 @@ code sigA sigffAmuxY sigB sigffBmuxY sigM ++i; sigB.remove(i, GetSize(sigB)-i); + sigD = dsp->connections_.at(\D, SigSpec()); + SigSpec P = port(dsp, \P); // Only care about those bits that are used for (i = 0; i < GetSize(P); i++) { @@ -44,7 +46,85 @@ code sigA sigffAmuxY sigB sigffBmuxY sigM sigffBmuxY = SigSpec(); endcode +match ffAD + if param(dsp, \ADREG).as_int() == 0 + select ffAD->type.in($dff) + // DSP48E1 does not support clock inversion + select param(ffAD, \CLK_POLARITY).as_bool() + filter GetSize(port(ffAD, \Q)) >= GetSize(sigA) + slice offset GetSize(port(ffAD, \Q)) + filter offset+GetSize(sigA) <= GetSize(port(ffAD, \Q)) + filter port(ffAD, \Q).extract(offset, GetSize(sigA)) == sigA + optional +endmatch + +code sigA sigffAmuxY clock + if (ffAD) { + for (auto b : port(ffAD, \Q)) + if (b.wire->get_bool_attribute(\keep)) + reject; + + clock = port(ffAD, \CLK).as_bit(); + + SigSpec A = sigA; + A.replace(port(ffAD, \Q), port(ffAD, \D)); + // Only search for ffAmux if ffA.Q has at + // least 3 users (ffA, dsp, ffAmux) and + // its ffA.D only has two (ffA, ffAmux) + if (nusers(sigA) >= 3 && nusers(A) == 2) + sigffAmuxY = sigA; + sigA = std::move(A); + } +endcode + +match ffADmux + if !sigffAmuxY.empty() + select ffADmux->type.in($mux) + index port(ffADmux, \Y) === port(ffAD, \D) + filter GetSize(port(ffADmux, \Y)) >= GetSize(sigA) + slice offset GetSize(port(ffADmux, \Y)) + filter offset+GetSize(sigA) <= GetSize(port(ffADmux, \Y)) + filter port(ffADmux, \Y).extract(offset, GetSize(sigA)) == sigA + choice BA {\B, \A} + filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffADmux, \Y)) + filter port(ffADmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY + define pol (BA == \B) + set ffADenpol pol + optional +endmatch + +match preAdd + if sigD.empty() || sigD.is_fully_zero() + // Ensure that preAdder not already used + if dsp->parameters.at(\USE_DPORT, Const("FALSE")).decode_string() == "FALSE" + if dsp->connections_.at(\INMODE, Const(0, 5)).is_fully_zero() + + select preAdd->type.in($add) + // Output has to be 25 bits or less + select GetSize(port(preAdd, \Y)) <= 25 + select nusers(port(preAdd, \Y)) == 2 + choice AB {\A, \B} + // A port has to be 30 bits or less + select GetSize(port(preAdd, AB)) <= 30 + define BA (AB == \A ? \B : \A) + // D port has to be 25 bits or less + select GetSize(port(preAdd, BA)) <= 25 + index port(preAdd, \Y) === sigA + + optional +endmatch + +code sigA sigD + if (preAdd) { + sigA = port(preAdd, \A); + sigD = port(preAdd, \B); + if (GetSize(sigA) < GetSize(sigD)) + std::swap(sigA, sigD); + } +endcode + match ffA + if !preAdd if param(dsp, \AREG).as_int() == 0 select ffA->type.in($dff) // DSP48E1 does not support clock inversion @@ -73,6 +153,9 @@ code sigA sigffAmuxY clock sigffAmuxY = sigA; sigA = std::move(A); } + else if (!preAdd) { + sigffAmuxY = SigSpec(); + } endcode match ffAmux @@ -91,6 +174,18 @@ match ffAmux optional endmatch +code ffA ffAmux ffAenpol ffAD ffADmux + // Move AD register to A if no pre-adder + if (!ffA && !preAdd && ffAD) { + ffA = ffAD; + ffAmux = ffADmux; + ffAenpol = ffADenpol; + + ffAD = nullptr; + ffADmux = nullptr; + } +endcode + match ffB if param(dsp, \BREG).as_int() == 0 select ffB->type.in($dff) -- 2.30.2