aboutsummaryrefslogtreecommitdiffstats
path: root/passes/pmgen
diff options
context:
space:
mode:
Diffstat (limited to 'passes/pmgen')
-rw-r--r--passes/pmgen/ice40_dsp.cc21
-rw-r--r--passes/pmgen/ice40_dsp.pmg54
-rw-r--r--passes/pmgen/xilinx_dsp.cc73
-rw-r--r--passes/pmgen/xilinx_dsp.pmg24
4 files changed, 126 insertions, 46 deletions
diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc
index bb45b8a4e..a1a397b83 100644
--- a/passes/pmgen/ice40_dsp.cc
+++ b/passes/pmgen/ice40_dsp.cc
@@ -23,9 +23,10 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-template<class T> bool includes(const T &lhs, const T &rhs) {
+template<class T> inline bool includes(const T &lhs, const T &rhs) {
return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
+#include <set>
#include "passes/pmgen/ice40_dsp_pm.h"
void create_ice40_dsp(ice40_dsp_pm &pm)
@@ -37,7 +38,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
log("ffA: %s\n", log_id(st.ffA, "--"));
log("ffB: %s\n", log_id(st.ffB, "--"));
log("mul: %s\n", log_id(st.mul, "--"));
- log("ffH: %s\n", log_id(st.ffH, "--"));
+ log("ffFJKG: %s\n", log_id(st.ffFJKG, "--"));
log("addAB: %s\n", log_id(st.addAB, "--"));
log("muxAB: %s\n", log_id(st.muxAB, "--"));
log("ffO_lo: %s\n", log_id(st.ffO_lo, "--"));
@@ -118,8 +119,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
if (st.ffB)
log(" ffB:%s", log_id(st.ffB));
- if (st.ffH)
- log(" ffH:%s", log_id(st.ffH));
+ if (st.ffFJKG)
+ log(" ffFJKG:%s", log_id(st.ffFJKG));
if (st.ffO_lo)
log(" ffO_lo:%s", log_id(st.ffO_lo));
@@ -154,9 +155,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
// If we have a signed multiply-add, then perform sign extension
// TODO: Need to check CD[31:16] is sign extension of CD[15:0]?
if (st.addAB->getParam("\\A_SIGNED").as_bool() && st.addAB->getParam("\\B_SIGNED").as_bool())
- pm.module->connect(O[-1], O[-2]);
+ pm.module->connect(O[32], O[31]);
else
- cell->setPort("\\CO", O[-1]);
+ cell->setPort("\\CO", O[32]);
O.remove(O_width-1);
}
else
@@ -205,9 +206,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\C_REG", State::S0);
cell->setParam("\\D_REG", State::S0);
- cell->setParam("\\TOP_8x8_MULT_REG", st.ffH ? State::S1 : State::S0);
- cell->setParam("\\BOT_8x8_MULT_REG", st.ffH ? State::S1 : State::S0);
- cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffH ? State::S1 : State::S0);
+ cell->setParam("\\TOP_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0);
+ cell->setParam("\\BOT_8x8_MULT_REG", st.ffFJKG ? State::S1 : State::S0);
+ cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffFJKG ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO_hi ? 1 : (st.addAB ? 0 : 3), 2));
@@ -228,7 +229,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
pm.autoremove(st.mul);
else
pm.blacklist(st.mul);
- pm.autoremove(st.ffH);
+ pm.autoremove(st.ffFJKG);
pm.autoremove(st.addAB);
if (st.ffO_lo) {
SigSpec O = st.sigO.extract(0,std::min(16,st.ffO_lo->getParam("\\WIDTH").as_int()));
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg
index c59c5d20a..11064e072 100644
--- a/passes/pmgen/ice40_dsp.pmg
+++ b/passes/pmgen/ice40_dsp.pmg
@@ -2,6 +2,7 @@ pattern ice40_dsp
state <SigBit> clock
state <bool> clock_pol
+state <std::set<SigBit>> sigAset sigBset
state <SigSpec> sigA sigB sigCD sigH sigO sigOused
state <Cell*> addAB muxAB
@@ -10,6 +11,15 @@ match mul
select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
endmatch
+code sigAset sigBset
+ SigSpec A = port(mul, \A);
+ A.remove_const();
+ sigAset = A.to_sigbit_set();
+ SigSpec B = port(mul, \B);
+ B.remove_const();
+ sigBset = B.to_sigbit_set();
+endcode
+
code sigH
if (mul->type == $mul)
sigH = mul->getPort(\Y);
@@ -22,9 +32,9 @@ endcode
match ffA
if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()
- if !port(mul, \A).remove_const().empty()
+ if !sigAset.empty()
select ffA->type.in($dff)
- filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set())
+ filter includes(port(ffA, \Q).to_sigbit_set(), sigAset)
optional
endmatch
@@ -45,9 +55,9 @@ endcode
match ffB
if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()
- if !port(mul, \B).remove_const().empty()
+ if !sigBset.empty()
select ffB->type.in($dff)
- filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set())
+ filter includes(port(ffB, \Q).to_sigbit_set(), sigBset)
optional
endmatch
@@ -72,11 +82,11 @@ code sigB clock clock_pol
}
endcode
-match ffH
+match ffFJKG
if mul->type != \SB_MAC16 || (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())
- select ffH->type.in($dff)
- select nusers(port(ffH, \D)) == 2
- index <SigSpec> port(ffH, \D) === sigH
+ select ffFJKG->type.in($dff)
+ select nusers(port(ffFJKG, \D)) == 2
+ index <SigSpec> port(ffFJKG, \D) === sigH
// Ensure pipeline register is not already used
optional
endmatch
@@ -84,16 +94,16 @@ endmatch
code sigH sigO clock clock_pol
sigO = sigH;
- if (ffH) {
- sigH = port(ffH, \Q);
+ if (ffFJKG) {
+ sigH = port(ffFJKG, \Q);
for (auto b : sigH)
if (b.wire->get_bool_attribute(\keep))
reject;
sigO = sigH;
- SigBit c = port(ffH, \CLK).as_bit();
- bool cp = param(ffH, \CLK_POLARITY).as_bool();
+ SigBit c = port(ffFJKG, \CLK).as_bit();
+ bool cp = param(ffFJKG, \CLK_POLARITY).as_bool();
if (clock != SigBit() && (c != clock || cp != clock_pol))
reject;
@@ -192,18 +202,34 @@ endcode
match ffO_lo
if nusers(sigOused.extract(0,std::min(16,GetSize(sigOused)))) == 2
select ffO_lo->type.in($dff)
- filter includes(port(ffO_lo, \D).to_sigbit_set(), sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int())).remove_const().to_sigbit_set())
optional
endmatch
+code
+ if (ffO_lo) {
+ SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int()));
+ O.remove_const();
+ if (!includes(port(ffO_lo, \D).to_sigbit_set(), O.to_sigbit_set()))
+ reject;
+ }
+endcode
+
match ffO_hi
if GetSize(sigOused) > 16
if nusers(sigOused.extract_end(16)) == 2
select ffO_hi->type.in($dff)
- filter includes(port(ffO_hi, \D).to_sigbit_set(), sigOused.extract_end(16).remove_const().to_sigbit_set())
optional
endmatch
+code
+ if (ffO_hi) {
+ SigSpec O = sigOused.extract_end(16);
+ O.remove_const();
+ if (!includes(port(ffO_hi, \D).to_sigbit_set(), O.to_sigbit_set()))
+ reject;
+ }
+endcode
+
code clock clock_pol sigO sigCD
if (ffO_lo || ffO_hi) {
if (mul->type == \SB_MAC16) {
diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc
index cd88f9449..e7b72e312 100644
--- a/passes/pmgen/xilinx_dsp.cc
+++ b/passes/pmgen/xilinx_dsp.cc
@@ -23,22 +23,23 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-template<class T> bool includes(const T &lhs, const T &rhs) {
+template<class T> inline bool includes(const T &lhs, const T &rhs) {
return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
+#include <set>
#include "passes/pmgen/xilinx_dsp_pm.h"
-void pack_xilinx_dsp(xilinx_dsp_pm &pm)
+void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
{
auto &st = pm.st_xilinx_dsp;
#if 1
log("\n");
- log("ffA: %s\n", log_id(st.ffA, "--"));
- log("ffB: %s\n", log_id(st.ffB, "--"));
- log("dsp: %s\n", log_id(st.dsp, "--"));
- log("addAB: %s\n", log_id(st.addAB, "--"));
- log("ffP: %s\n", log_id(st.ffP, "--"));
+ log("ffA: %s\n", log_id(st.ffA, "--"));
+ log("ffB: %s\n", log_id(st.ffB, "--"));
+ log("dsp: %s\n", log_id(st.dsp, "--"));
+ log("addAB: %s\n", log_id(st.addAB, "--"));
+ log("ffP: %s\n", log_id(st.ffP, "--"));
//log("muxP: %s\n", log_id(st.muxP, "--"));
log("sigPused: %s\n", log_signal(st.sigPused));
#endif
@@ -46,11 +47,17 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
Cell *cell = st.dsp;
+ bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell));
SigSpec P = st.sigP;
if (st.addAB) {
+ log_assert(st.addAB->getParam("\\A_SIGNED").as_bool());
+ log_assert(st.addAB->getParam("\\B_SIGNED").as_bool());
log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
- cell->setPort("\\C", st.sigC.extend_u0(48, true));
+
+ SigSpec C = st.sigC;
+ C.extend_u0(48, true);
+ cell->setPort("\\C", C);
SigSpec &opmode = cell->connections_.at("\\OPMODE");
opmode[6] = State::S0;
opmode[5] = State::S1;
@@ -127,8 +134,8 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
pm.blacklist(cell);
}
-struct Ice40DspPass : public Pass {
- Ice40DspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { }
+struct XilinxDspPass : public Pass {
+ XilinxDspPass() : Pass("xilinx_dsp", "Xilinx: pack DSP registers") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -153,9 +160,49 @@ struct Ice40DspPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto module : design->selected_modules())
- xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp);
+ for (auto module : design->selected_modules()) {
+ xilinx_dsp_pm pm(module, module->selected_cells());
+ dict<SigBit, Cell*> bit_to_driver;
+ auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); };
+ pm.run_xilinx_dsp(f);
+
+ // Look for ability to convert C input from another DSP into PCIN
+ // NB: Needs to be done after pattern matcher has folded all
+ // $add cells into the DSP
+ for (auto cell : module->cells()) {
+ if (cell->type != "\\DSP48E1")
+ continue;
+ SigSpec &opmode = cell->connections_.at("\\OPMODE");
+ if (opmode.extract(4,3) != Const::from_string("011"))
+ continue;
+ SigSpec C = pm.sigmap(cell->getPort("\\C"));
+ if (C.has_const())
+ continue;
+ auto it = bit_to_driver.find(C[0]);
+ if (it == bit_to_driver.end())
+ continue;
+ auto driver = it->second;
+
+ // Unextend C
+ int i;
+ for (i = GetSize(C)-1; i > 0; i--)
+ if (C[i] != C[i-1])
+ break;
+ if (i > 48-17)
+ continue;
+ if (driver->getPort("\\P").extract(17, i) == C.extract(0, i)) {
+ cell->setPort("\\C", Const(0, 48));
+ Wire *cascade = module->addWire(NEW_ID, 48);
+ driver->setPort("\\PCOUT", cascade);
+ cell->setPort("\\PCIN", cascade);
+ opmode[6] = State::S1;
+ opmode[5] = State::S0;
+ opmode[4] = State::S1;
+ bit_to_driver.erase(it);
+ }
+ }
+ }
}
-} Ice40DspPass;
+} XilinxDspPass;
PRIVATE_NAMESPACE_END
diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg
index 5dee36a11..1a3dcdcbb 100644
--- a/passes/pmgen/xilinx_dsp.pmg
+++ b/passes/pmgen/xilinx_dsp.pmg
@@ -1,6 +1,7 @@
pattern xilinx_dsp
state <SigBit> clock
+state <std::set<SigBit>> sigAset sigBset
state <SigSpec> sigC sigP sigPused
state <Cell*> addAB
@@ -8,13 +9,22 @@ match dsp
select dsp->type.in(\DSP48E1)
endmatch
+code sigAset sigBset
+ SigSpec A = port(dsp, \A);
+ A.remove_const();
+ sigAset = A.to_sigbit_set();
+ SigSpec B = port(dsp, \B);
+ B.remove_const();
+ sigBset = B.to_sigbit_set();
+endcode
+
match ffA
if param(dsp, \AREG).as_int() == 0
- if !port(dsp, \A).remove_const().empty()
+ if !sigAset.empty()
select ffA->type.in($dff)
// DSP48E1 does not support clock inversion
select param(ffA, \CLK_POLARITY).as_bool()
- filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set())
+ filter includes(port(ffA, \Q).to_sigbit_set(), sigAset)
optional
endmatch
@@ -25,11 +35,11 @@ endcode
match ffB
if param(dsp, \BREG).as_int() == 0
- if !port(dsp, \B).remove_const().empty()
+ if !sigBset.empty()
select ffB->type.in($dff)
// DSP48E1 does not support clock inversion
select param(ffB, \CLK_POLARITY).as_bool()
- filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set())
+ filter includes(port(ffB, \Q).to_sigbit_set(), sigBset)
optional
endmatch
@@ -65,21 +75,18 @@ match addB
index <int> nusers(port(addB, \B)) === 2
//index <SigSpec> port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int())
filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP)
- filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int())
+ filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int())
optional
endmatch
code addAB sigC sigP
- bool C_SIGNED = false;
if (addA) {
addAB = addA;
sigC = port(addAB, \B);
- C_SIGNED = param(addAB, \B_SIGNED).as_bool();
}
if (addB) {
addAB = addB;
sigC = port(addAB, \A);
- C_SIGNED = param(addAB, \B_SIGNED).as_bool();
}
if (addAB) {
// Ensure that adder is not used
@@ -97,7 +104,6 @@ code addAB sigC sigP
// reject;
sigP = port(addAB, \Y);
- sigC.extend_u0(32, C_SIGNED);
}
endcode