diff options
-rw-r--r-- | kernel/rtlil.cc | 6 | ||||
-rw-r--r-- | kernel/rtlil.h | 8 | ||||
-rw-r--r-- | passes/pmgen/ice40_dsp.cc | 21 | ||||
-rw-r--r-- | passes/pmgen/ice40_dsp.pmg | 54 | ||||
-rw-r--r-- | passes/pmgen/xilinx_dsp.cc | 73 | ||||
-rw-r--r-- | passes/pmgen/xilinx_dsp.pmg | 24 | ||||
-rw-r--r-- | techlibs/common/mul2dsp.v | 256 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 2 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 2 |
9 files changed, 246 insertions, 200 deletions
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 909f60dd9..fade0bc36 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3299,7 +3299,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) check(); } -RTLIL::SigSpec& RTLIL::SigSpec::remove_const() +void RTLIL::SigSpec::remove_const() { if (packed()) { @@ -3333,7 +3333,6 @@ RTLIL::SigSpec& RTLIL::SigSpec::remove_const() } check(); - return *this; } void RTLIL::SigSpec::remove(int offset, int length) @@ -3429,7 +3428,7 @@ void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit) check(); } -RTLIL::SigSpec& RTLIL::SigSpec::extend_u0(int width, bool is_signed) +void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { cover("kernel.rtlil.sigspec.extend_u0"); @@ -3446,7 +3445,6 @@ RTLIL::SigSpec& RTLIL::SigSpec::extend_u0(int width, bool is_signed) append(padding); } - return *this; } RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 16fd852ba..37b5f984c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -754,8 +754,8 @@ public: inline int size() const { return width_; } inline bool empty() const { return width_ == 0; } - inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return index >= 0 ? bits_.at(index) : bits_.at(width_ + index); } - inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return index >= 0 ? bits_.at(index) : bits_.at(width_ + index); } + inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } + inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; } @@ -787,7 +787,7 @@ public: void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other); void remove(int offset, int length = 1); - RTLIL::SigSpec& remove_const(); + void remove_const(); RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const; @@ -797,7 +797,7 @@ public: void append(const RTLIL::SigSpec &signal); void append_bit(const RTLIL::SigBit &bit); - RTLIL::SigSpec& extend_u0(int width, bool is_signed = false); + void extend_u0(int width, bool is_signed = false); RTLIL::SigSpec repeat(int num) const; 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 diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index 8e37201e2..75b1242a2 100644 --- a/techlibs/common/mul2dsp.v +++ b/techlibs/common/mul2dsp.v @@ -27,20 +27,30 @@ */
`ifndef DSP_A_MAXWIDTH
-$error("Macro DSP_A_MAXWIDTH must be defined");
+$fatal(1, "Macro DSP_A_MAXWIDTH must be defined");
`endif
`ifndef DSP_B_MAXWIDTH
-$error("Macro DSP_B_MAXWIDTH must be defined");
+$fatal(1, "Macro DSP_B_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_B_MAXWIDTH
+$fatal(1, "Macro DSP_B_MAXWIDTH must be defined");
+`endif
+`ifndef DSP_A_MAXWIDTH_PARTIAL
+`define DSP_A_MAXWIDTH_PARTIAL `DSP_A_MAXWIDTH
+`endif
+`ifndef DSP_B_MAXWIDTH_PARTIAL
+`define DSP_B_MAXWIDTH_PARTIAL `DSP_B_MAXWIDTH
`endif
`ifndef DSP_NAME
-$error("Macro DSP_NAME must be defined");
+$fatal(1, "Macro DSP_NAME must be defined");
`endif
`define MAX(a,b) (a > b ? a : b)
`define MIN(a,b) (a < b ? a : b)
-module \$mul (A, B, Y);
+(* techmap_celltype = "$mul $__mul" *)
+module _80_mul (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
@@ -51,12 +61,26 @@ module \$mul (A, B, Y); input [B_WIDTH-1:0] B;
output [Y_WIDTH-1:0] Y;
+ parameter _TECHMAP_CELLTYPE_ = "";
+
generate
- if (A_SIGNED != B_SIGNED)
+ if (0) begin end
+`ifdef DSP_A_MINWIDTH
+ else if (A_WIDTH < `DSP_A_MINWIDTH)
+ wire _TECHMAP_FAIL_ = 1;
+`endif
+`ifdef DSP_B_MINWIDTH
+ else if (B_WIDTH < `DSP_B_MINWIDTH)
+ wire _TECHMAP_FAIL_ = 1;
+`endif
+`ifdef DSP_Y_MINWIDTH
+ else if (Y_WIDTH < `DSP_Y_MINWIDTH)
+ wire _TECHMAP_FAIL_ = 1;
+`endif
+ else if (_TECHMAP_CELLTYPE_ == "$mul" && A_SIGNED != B_SIGNED)
wire _TECHMAP_FAIL_ = 1;
- // NB: A_SIGNED == B_SIGNED from here
`ifdef DSP_SIGNEDONLY
- else if (!A_SIGNED)
+ else if (_TECHMAP_CELLTYPE_ == "$mul" && !A_SIGNED)
\$mul #(
.A_SIGNED(1),
.B_SIGNED(1),
@@ -69,7 +93,7 @@ module \$mul (A, B, Y); .Y(Y)
);
`endif
- else if (A_WIDTH < B_WIDTH)
+ else if (_TECHMAP_CELLTYPE_ == "$mul" && A_WIDTH < B_WIDTH)
\$mul #(
.A_SIGNED(B_SIGNED),
.B_SIGNED(A_SIGNED),
@@ -81,102 +105,53 @@ module \$mul (A, B, Y); .B(A),
.Y(Y)
);
- else
- \$__mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(Y_WIDTH)
- ) _TECHMAP_REPLACE_ (
- .A(A),
- .B(B),
- .Y(Y)
- );
- endgenerate
-endmodule
-
-module \$__mul (A, B, Y);
- parameter A_SIGNED = 0;
- parameter B_SIGNED = 0;
- parameter A_WIDTH = 1;
- parameter B_WIDTH = 1;
- parameter Y_WIDTH = 1;
-
- input [A_WIDTH-1:0] A;
- input [B_WIDTH-1:0] B;
- output [Y_WIDTH-1:0] Y;
-
- wire [1023:0] _TECHMAP_DO_ = "proc; clean";
+ else begin
+ wire [1023:0] _TECHMAP_DO_ = "proc; clean";
`ifdef DSP_SIGNEDONLY
- localparam sign_headroom = 1;
+ localparam sign_headroom = 1;
`else
- localparam sign_headroom = 0;
+ localparam sign_headroom = 0;
`endif
- genvar i;
- generate
- if (0) begin end
-`ifdef DSP_A_MINWIDTH
- else if (A_WIDTH < `DSP_A_MINWIDTH)
- wire _TECHMAP_FAIL_ = 1;
-`endif
-`ifdef DSP_B_MINWIDTH
- else if (B_WIDTH < `DSP_B_MINWIDTH)
- wire _TECHMAP_FAIL_ = 1;
-`endif
-`ifdef DSP_Y_MINWIDTH
- else if (Y_WIDTH < `DSP_Y_MINWIDTH)
- wire _TECHMAP_FAIL_ = 1;
-`endif
- else if (A_WIDTH > `DSP_A_MAXWIDTH) begin
- localparam n = (A_WIDTH+`DSP_A_MAXWIDTH-sign_headroom-1) / (`DSP_A_MAXWIDTH-sign_headroom);
- localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH);
- localparam last_Y_WIDTH = `MIN(partial_Y_WIDTH, B_WIDTH+A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom));
+ genvar i;
+ if (A_WIDTH > `DSP_A_MAXWIDTH) begin
+ localparam n = (A_WIDTH-`DSP_A_MAXWIDTH+`DSP_A_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH_PARTIAL);
+ localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH;
if (A_SIGNED && B_SIGNED) begin
- wire signed [partial_Y_WIDTH-1:0] partial [n-2:0];
+ wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
wire signed [last_Y_WIDTH-1:0] last_partial;
- wire signed [Y_WIDTH-1:0] partial_sum [n-1:0];
+ wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
wire [last_Y_WIDTH-1:0] last_partial;
- wire [Y_WIDTH-1:0] partial_sum [n-1:0];
+ wire [Y_WIDTH-1:0] partial_sum [n:0];
end
- \$__mul #(
- .A_SIGNED(sign_headroom),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(`DSP_A_MAXWIDTH),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(partial_Y_WIDTH)
- ) mul_slice_first (
- .A({{sign_headroom{1'b0}}, A[`DSP_A_MAXWIDTH-sign_headroom-1 : 0]}),
- .B(B),
- .Y(partial[0])
- );
- assign partial_sum[0] = partial[0];
-
- for (i = 1; i < n-1; i=i+1) begin:slice
+ for (i = 0; i < n; i=i+1) begin:slice
\$__mul #(
.A_SIGNED(sign_headroom),
.B_SIGNED(B_SIGNED),
- .A_WIDTH(`DSP_A_MAXWIDTH),
+ .A_WIDTH(`DSP_A_MAXWIDTH_PARTIAL),
.B_WIDTH(B_WIDTH),
.Y_WIDTH(partial_Y_WIDTH)
) mul_slice (
- .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH-sign_headroom) +: `DSP_A_MAXWIDTH-sign_headroom]}),
+ .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_A_MAXWIDTH_PARTIAL-sign_headroom]}),
.B(B),
.Y(partial[i])
);
// TODO: Currently a 'cascade' approach to summing the partial
// products is taken here, but a more efficient 'binary
// reduction' approach also exists...
- assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
+ if (i == 0)
+ assign partial_sum[i] = partial[i];
+ else
+ assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[i-1];
end
- localparam last_A_WIDTH = A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom);
\$__mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
@@ -188,56 +163,46 @@ module \$__mul (A, B, Y); .B(B),
.Y(last_partial)
);
- assign partial_sum[n-1] = (last_partial << (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
- assign Y = partial_sum[n-1];
+ assign partial_sum[n] = (last_partial << n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[n-1];
+ assign Y = partial_sum[n];
end
else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
- localparam n = (B_WIDTH+`DSP_B_MAXWIDTH-sign_headroom-1) / (`DSP_B_MAXWIDTH-sign_headroom);
- localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH);
- localparam last_Y_WIDTH = `MIN(partial_Y_WIDTH, A_WIDTH+B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH-sign_headroom));
+ localparam n = (B_WIDTH-`DSP_B_MAXWIDTH+`DSP_B_MAXWIDTH_PARTIAL-sign_headroom-1) / (`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH_PARTIAL);
+ localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
+ localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH;
if (A_SIGNED && B_SIGNED) begin
- wire signed [partial_Y_WIDTH-1:0] partial [n-2:0];
+ wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
wire signed [last_Y_WIDTH-1:0] last_partial;
- wire signed [Y_WIDTH-1:0] partial_sum [n-1:0];
+ wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
wire [last_Y_WIDTH-1:0] last_partial;
- wire [Y_WIDTH-1:0] partial_sum [n-1:0];
+ wire [Y_WIDTH-1:0] partial_sum [n:0];
end
- \$__mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(sign_headroom),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(`DSP_B_MAXWIDTH),
- .Y_WIDTH(partial_Y_WIDTH)
- ) mul_first (
- .A(A),
- .B({{sign_headroom{1'b0}}, B[`DSP_B_MAXWIDTH-sign_headroom-1 : 0]}),
- .Y(partial[0])
- );
- assign partial_sum[0] = partial[0];
-
- for (i = 1; i < n-1; i=i+1) begin:slice
+ for (i = 0; i < n; i=i+1) begin:slice
\$__mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(sign_headroom),
.A_WIDTH(A_WIDTH),
- .B_WIDTH(`DSP_B_MAXWIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH_PARTIAL),
.Y_WIDTH(partial_Y_WIDTH)
) mul (
.A(A),
- .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH-sign_headroom) +: `DSP_B_MAXWIDTH-sign_headroom]}),
+ .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom) +: `DSP_B_MAXWIDTH_PARTIAL-sign_headroom]}),
.Y(partial[i])
);
- // TODO: Currently a 'cascade' approach to summing the partial
+ // TODO: Currently a 'cascade' approach to summing the partial
// products is taken here, but a more efficient 'binary
// reduction' approach also exists...
- assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
+ if (i == 0)
+ assign partial_sum[i] = partial[i];
+ else
+ assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[i-1];
end
- localparam last_B_WIDTH = B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH-sign_headroom);
\$__mul #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
@@ -249,10 +214,10 @@ module \$__mul (A, B, Y); .B(B[B_WIDTH-1 -: last_B_WIDTH]),
.Y(last_partial)
);
- assign partial_sum[n-1] = (last_partial << (n-1)*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
- assign Y = partial_sum[n-1];
+ assign partial_sum[n] = (last_partial << n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom)) + partial_sum[n-1];
+ assign Y = partial_sum[n];
end
- else begin
+ else begin
if (A_SIGNED)
wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A);
else
@@ -274,11 +239,12 @@ module \$__mul (A, B, Y); .Y(Y)
);
end
+ end
endgenerate
endmodule
-(* techmap_celltype = "$__mul" *)
-module $__soft_mul (A, B, Y);
+(* techmap_celltype = "$mul $__mul" *)
+module _90_soft_mul (A, B, Y);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
@@ -292,41 +258,41 @@ module $__soft_mul (A, B, Y); // Indirection necessary since mapping
// back to $mul will cause recursion
generate
- if (A_SIGNED && !B_SIGNED)
- \$__soft__mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(1),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(B_WIDTH+1),
- .Y_WIDTH(Y_WIDTH)
- ) _TECHMAP_REPLACE_ (
- .A(A),
- .B({1'b0,B}),
- .Y(Y)
- );
- else if (!A_SIGNED && B_SIGNED)
- \$__soft_mul #(
- .A_SIGNED(1),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(A_WIDTH+1),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(Y_WIDTH)
- ) _TECHMAP_REPLACE_ (
- .A({1'b0,A}),
- .B(B),
- .Y(Y)
- );
- else
- \$__soft_mul #(
- .A_SIGNED(A_SIGNED),
- .B_SIGNED(B_SIGNED),
- .A_WIDTH(A_WIDTH),
- .B_WIDTH(B_WIDTH),
- .Y_WIDTH(Y_WIDTH)
- ) _TECHMAP_REPLACE_ (
- .A(A),
- .B(B),
- .Y(Y)
- );
+ if (A_SIGNED && !B_SIGNED)
+ \$__soft_mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(1),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH+1),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .B({1'b0,B}),
+ .Y(Y)
+ );
+ else if (!A_SIGNED && B_SIGNED)
+ \$__soft_mul #(
+ .A_SIGNED(1),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH+1),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A({1'b0,A}),
+ .B(B),
+ .Y(Y)
+ );
+ else
+ \$__soft_mul #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A),
+ .B(B),
+ .Y(Y)
+ );
endgenerate
endmodule
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 2731cb454..02ce0d61b 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -784,4 +784,6 @@ module DSP48E1 ( end endgenerate + assign PCOUT = P; + endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 546d67337..102c896aa 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -288,7 +288,7 @@ struct SynthXilinxPass : public ScriptPass if (check_label("dsp")) { if (!nodsp || help_mode) { // NB: Xilinx multipliers are signed only - run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')"); + run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')"); run("opt_expr -fine", " (skip if '-nodsp')"); run("wreduce", " (skip if '-nodsp')"); run("xilinx_dsp", " (skip if '-nodsp')"); |