diff options
-rw-r--r-- | backends/verilog/verilog_backend.cc | 90 | ||||
-rw-r--r-- | passes/opt/wreduce.cc | 14 | ||||
-rw-r--r-- | passes/pmgen/xilinx_dsp.pmg | 12 | ||||
-rw-r--r-- | passes/pmgen/xilinx_dsp_CREG.pmg | 8 | ||||
-rw-r--r-- | passes/techmap/extract_fa.cc | 12 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 511 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.py | 10 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.v | 127 | ||||
-rw-r--r-- | tests/various/bug1462.ys | 11 | ||||
-rw-r--r-- | tests/various/bug1480.ys | 18 | ||||
-rw-r--r-- | tests/various/bug1496.ys | 13 |
11 files changed, 667 insertions, 159 deletions
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 24e397bda..54d0f6148 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -33,11 +33,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit; -int auto_name_counter, auto_name_offset, auto_name_digits; +bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit; +int auto_name_counter, auto_name_offset, auto_name_digits, extmem_counter; std::map<RTLIL::IdString, int> auto_name_map; std::set<RTLIL::IdString> reg_wires, reg_ct; -std::string auto_prefix; +std::string auto_prefix, extmem_prefix; RTLIL::Module *active_module; dict<RTLIL::SigBit, RTLIL::State> active_initdata; @@ -1069,14 +1069,64 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset); if (use_init) { - f << stringf("%s" "initial begin\n", indent.c_str()); - for (int i=0; i<size; i++) + if (extmem) + { + std::string extmem_filename = stringf("%s-%d.mem", extmem_prefix.c_str(), extmem_counter++); + + std::string extmem_filename_esc; + for (auto c : extmem_filename) + { + if (c == '\n') + extmem_filename_esc += "\\n"; + else if (c == '\t') + extmem_filename_esc += "\\t"; + else if (c < 32) + extmem_filename_esc += stringf("\\%03o", c); + else if (c == '"') + extmem_filename_esc += "\\\""; + else if (c == '\\') + extmem_filename_esc += "\\\\"; + else + extmem_filename_esc += c; + } + f << stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent.c_str(), extmem_filename_esc.c_str(), mem_id.c_str()); + + std::ofstream extmem_f(extmem_filename, std::ofstream::trunc); + if (extmem_f.fail()) + log_error("Can't open file `%s' for writing: %s\n", extmem_filename.c_str(), strerror(errno)); + else + { + for (int i=0; i<size; i++) + { + RTLIL::Const element = cell->parameters["\\INIT"].extract(i*width, width); + for (int j=0; j<element.size(); j++) + { + switch (element[element.size()-j-1]) + { + case State::S0: extmem_f << '0'; break; + case State::S1: extmem_f << '1'; break; + case State::Sx: extmem_f << 'x'; break; + case State::Sz: extmem_f << 'z'; break; + case State::Sa: extmem_f << '_'; break; + case State::Sm: log_error("Found marker state in final netlist."); + } + } + extmem_f << '\n'; + } + } + + } + else { - f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i); - dump_const(f, cell->parameters["\\INIT"].extract(i*width, width)); - f << stringf(";\n"); + f << stringf("%s" "initial begin\n", indent.c_str()); + for (int i=0; i<size; i++) + { + f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i); + dump_const(f, cell->parameters["\\INIT"].extract(i*width, width)); + f << stringf(";\n"); + } + f << stringf("%s" "end\n", indent.c_str()); } - f << stringf("%s" "end\n", indent.c_str()); } // create a map : "edge clk" -> expressions within that clock domain @@ -1777,8 +1827,16 @@ struct VerilogBackend : public Backend { log(" deactivates this feature and instead will write string constants\n"); log(" as binary numbers.\n"); log("\n"); + log(" -extmem\n"); + log(" instead of initializing memories using assignments to individual\n"); + log(" elements, use the '$readmemh' function to read initialization data\n"); + log(" from a file. This data is written to a file named by appending\n"); + log(" a sequential index to the Verilog filename and replacing the extension\n"); + log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n"); + log(" 'foo-2.mem' and so on.\n"); + log("\n"); log(" -defparam\n"); - log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n"); + log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n"); log(" cell parameters.\n"); log("\n"); log(" -blackboxes\n"); @@ -1812,6 +1870,7 @@ struct VerilogBackend : public Backend { nodec = false; nohex = false; nostr = false; + extmem = false; defparam = false; decimal = false; siminit = false; @@ -1885,6 +1944,11 @@ struct VerilogBackend : public Backend { nostr = true; continue; } + if (arg == "-extmem") { + extmem = true; + extmem_counter = 1; + continue; + } if (arg == "-defparam") { defparam = true; continue; @@ -1912,6 +1976,12 @@ struct VerilogBackend : public Backend { break; } extra_args(f, filename, args, argidx); + if (extmem) + { + if (filename.empty()) + log_cmd_error("Option -extmem must be used with a filename.\n"); + extmem_prefix = filename.substr(0, filename.rfind('.')); + } design->sort(); diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index c02c355cb..04b882db9 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -143,13 +143,18 @@ struct WreduceWorker SigSpec sig_d = mi.sigmap(cell->getPort(ID(D))); SigSpec sig_q = mi.sigmap(cell->getPort(ID(Q))); - Const initval; + bool is_adff = (cell->type == ID($adff)); + Const initval, arst_value; int width_before = GetSize(sig_q); if (width_before == 0) return; + if (cell->parameters.count(ID(ARST_VALUE))) { + arst_value = cell->parameters[ID(ARST_VALUE)]; + } + bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0; bool sign_ext = !zero_ext; @@ -163,7 +168,8 @@ struct WreduceWorker for (int i = GetSize(sig_q)-1; i >= 0; i--) { - if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) { + if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx) && + (!is_adff || i >= GetSize(arst_value) || arst_value[i] == State::S0 || arst_value[i] == State::Sx)) { module->connect(sig_q[i], State::S0); remove_init_bits.insert(sig_q[i]); sig_d.remove(i); @@ -171,7 +177,8 @@ struct WreduceWorker continue; } - if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) { + if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] && + (!is_adff || i >= GetSize(arst_value) || arst_value[i] == arst_value[i-1])) { module->connect(sig_q[i], sig_q[i-1]); remove_init_bits.insert(sig_q[i]); sig_d.remove(i); @@ -214,7 +221,6 @@ struct WreduceWorker // Narrow ARST_VALUE parameter to new size. if (cell->parameters.count(ID(ARST_VALUE))) { - Const arst_value = cell->getParam(ID(ARST_VALUE)); arst_value.bits.resize(GetSize(sig_q)); cell->setParam(ID(ARST_VALUE), arst_value); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 604aa222b..0ba529011 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -98,16 +98,16 @@ code sigA sigB sigC sigD sigM clock if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { // Only care about those bits that are used int i; - for (i = 0; i < GetSize(P); i++) { - if (nusers(P[i]) <= 1) + for (i = GetSize(P)-1; i >= 0; i--) + if (nusers(P[i]) > 1) break; - sigM.append(P[i]); - } + i++; log_assert(nusers(P.extract_end(i)) <= 1); // This sigM could have no users if downstream sinks (e.g. $add) is // narrower than $mul result, for example - if (sigM.empty()) + if (i == 0) reject; + sigM = P.extract(0, i); } else sigM = P; @@ -460,6 +460,8 @@ arg argD argQ clock code dff = nullptr; + if (GetSize(argQ) == 0) + reject; for (const auto &c : argQ.chunks()) { // Abandon matches when 'Q' is a constant if (!c.wire) diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg index a57043009..5cd34162e 100644 --- a/passes/pmgen/xilinx_dsp_CREG.pmg +++ b/passes/pmgen/xilinx_dsp_CREG.pmg @@ -63,12 +63,12 @@ code sigC sigP clock if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { // Only care about those bits that are used int i; - for (i = 0; i < GetSize(P); i++) { - if (nusers(P[i]) <= 1) + for (i = GetSize(P)-1; i >= 0; i--) + if (nusers(P[i]) > 1) break; - sigP.append(P[i]); - } + i++; log_assert(nusers(P.extract_end(i)) <= 1); + sigP = P.extract(0, i); } else sigP = P; diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index 29700c37b..9f3bb525b 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -262,10 +262,14 @@ struct ExtractFaWorker pool<SigBit> new_leaves = leaves; new_leaves.erase(bit); - if (cell->hasPort(ID::A)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::A)))); - if (cell->hasPort(ID::B)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::B)))); - if (cell->hasPort(ID(C))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(C))))); - if (cell->hasPort(ID(D))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(D))))); + for (auto port : {ID::A, ID::B, ID(C), ID(D)}) { + if (!cell->hasPort(port)) + continue; + auto bit = sigmap(SigBit(cell->getPort(port))); + if (!bit.wire) + continue; + new_leaves.insert(bit); + } if (GetSize(new_leaves) > maxbreadth) continue; diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 03985b1be..5faddcd52 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -581,6 +581,515 @@ module SRLC32E ( endgenerate endmodule +// DSP + +// Virtex 2, Virtex 2 Pro, Spartan 3. + +// Asynchronous mode. + +module MULT18X18 ( + input signed [17:0] A, + input signed [17:0] B, + output signed [35:0] P +); + +assign P = A * B; + +endmodule + +// Synchronous mode. + +module MULT18X18S ( + input signed [17:0] A, + input signed [17:0] B, + output reg signed [35:0] P, + (* clkbuf_sink *) + input C, + input CE, + input R +); + +always @(posedge C) + if (R) + P <= 0; + else if (CE) + P <= A * B; + +endmodule + +// Spartan 3E, Spartan 3A. + +module MULT18X18SIO ( + input signed [17:0] A, + input signed [17:0] B, + output signed [35:0] P, + (* clkbuf_sink *) + input CLK, + input CEA, + input CEB, + input CEP, + input RSTA, + input RSTB, + input RSTP, + input signed [17:0] BCIN, + output signed [17:0] BCOUT +); + +parameter integer AREG = 1; +parameter integer BREG = 1; +parameter B_INPUT = "DIRECT"; +parameter integer PREG = 1; + +// The multiplier. +wire signed [35:0] P_MULT; +assign P_MULT = A_MULT * B_MULT; + +// The cascade output. +assign BCOUT = B_MULT; + +// The B input multiplexer. +wire signed [17:0] B_MUX; +assign B_MUX = (B_INPUT == "DIRECT") ? B : BCIN; + +// The registers. +reg signed [17:0] A_REG; +reg signed [17:0] B_REG; +reg signed [35:0] P_REG; + +initial begin + A_REG = 0; + B_REG = 0; + P_REG = 0; +end + +always @(posedge CLK) begin + if (RSTA) + A_REG <= 0; + else if (CEA) + A_REG <= A; + + if (RSTB) + B_REG <= 0; + else if (CEB) + B_REG <= B_MUX; + + if (RSTP) + P_REG <= 0; + else if (CEP) + P_REG <= P_MULT; +end + +// The register enables. +wire signed [17:0] A_MULT; +wire signed [17:0] B_MULT; +assign A_MULT = (AREG == 1) ? A_REG : A; +assign B_MULT = (BREG == 1) ? B_REG : B_MUX; +assign P = (PREG == 1) ? P_REG : P_MULT; + +endmodule + +// Spartan 3A DSP. + +module DSP48A ( + input signed [17:0] A, + input signed [17:0] B, + input signed [47:0] C, + input signed [17:0] D, + input signed [47:0] PCIN, + input CARRYIN, + input [7:0] OPMODE, + output signed [47:0] P, + output signed [17:0] BCOUT, + output signed [47:0] PCOUT, + output CARRYOUT, + (* clkbuf_sink *) + input CLK, + input CEA, + input CEB, + input CEC, + input CED, + input CEM, + input CECARRYIN, + input CEOPMODE, + input CEP, + input RSTA, + input RSTB, + input RSTC, + input RSTD, + input RSTM, + input RSTCARRYIN, + input RSTOPMODE, + input RSTP +); + +parameter integer A0REG = 0; +parameter integer A1REG = 1; +parameter integer B0REG = 0; +parameter integer B1REG = 1; +parameter integer CREG = 1; +parameter integer DREG = 1; +parameter integer MREG = 1; +parameter integer CARRYINREG = 1; +parameter integer OPMODEREG = 1; +parameter integer PREG = 1; +parameter CARRYINSEL = "CARRYIN"; +parameter RSTTYPE = "SYNC"; + +// This is a strict subset of Spartan 6 -- reuse its model. + +DSP48A1 #( + .A0REG(A0REG), + .A1REG(A1REG), + .B0REG(B0REG), + .B1REG(B1REG), + .CREG(CREG), + .DREG(DREG), + .MREG(MREG), + .CARRYINREG(CARRYINREG), + .CARRYOUTREG(0), + .OPMODEREG(OPMODEREG), + .PREG(PREG), + .CARRYINSEL(CARRYINSEL), + .RSTTYPE(RSTTYPE) +) upgrade ( + .A(A), + .B(B), + .C(C), + .D(D), + .PCIN(PCIN), + .CARRYIN(CARRYIN), + .OPMODE(OPMODE), + // M unconnected + .P(P), + .BCOUT(BCOUT), + .PCOUT(PCOUT), + .CARRYOUT(CARRYOUT), + // CARRYOUTF unconnected + .CLK(CLK), + .CEA(CEA), + .CEB(CEB), + .CEC(CEC), + .CED(CED), + .CEM(CEM), + .CECARRYIN(CECARRYIN), + .CEOPMODE(CEOPMODE), + .CEP(CEP), + .RSTA(RSTA), + .RSTB(RSTB), + .RSTC(RSTC), + .RSTD(RSTD), + .RSTM(RSTM), + .RSTCARRYIN(RSTCARRYIN), + .RSTOPMODE(RSTOPMODE), + .RSTP(RSTP) +); + +endmodule + +// Spartan 6. + +module DSP48A1 ( + input signed [17:0] A, + input signed [17:0] B, + input signed [47:0] C, + input signed [17:0] D, + input signed [47:0] PCIN, + input CARRYIN, + input [7:0] OPMODE, + output signed [35:0] M, + output signed [47:0] P, + output signed [17:0] BCOUT, + output signed [47:0] PCOUT, + output CARRYOUT, + output CARRYOUTF, + (* clkbuf_sink *) + input CLK, + input CEA, + input CEB, + input CEC, + input CED, + input CEM, + input CECARRYIN, + input CEOPMODE, + input CEP, + input RSTA, + input RSTB, + input RSTC, + input RSTD, + input RSTM, + input RSTCARRYIN, + input RSTOPMODE, + input RSTP +); + +parameter integer A0REG = 0; +parameter integer A1REG = 1; +parameter integer B0REG = 0; +parameter integer B1REG = 1; +parameter integer CREG = 1; +parameter integer DREG = 1; +parameter integer MREG = 1; +parameter integer CARRYINREG = 1; +parameter integer CARRYOUTREG = 1; +parameter integer OPMODEREG = 1; +parameter integer PREG = 1; +parameter CARRYINSEL = "OPMODE5"; +parameter RSTTYPE = "SYNC"; + +wire signed [35:0] M_MULT; +wire signed [47:0] P_IN; +wire signed [17:0] A0_OUT; +wire signed [17:0] B0_OUT; +wire signed [17:0] A1_OUT; +wire signed [17:0] B1_OUT; +wire signed [17:0] B1_IN; +wire signed [47:0] C_OUT; +wire signed [17:0] D_OUT; +wire signed [7:0] OPMODE_OUT; +wire CARRYIN_OUT; +wire CARRYOUT_IN; +wire CARRYIN_IN; +reg signed [47:0] XMUX; +reg signed [47:0] ZMUX; + +// The registers. +reg signed [17:0] A0_REG; +reg signed [17:0] A1_REG; +reg signed [17:0] B0_REG; +reg signed [17:0] B1_REG; +reg signed [47:0] C_REG; +reg signed [17:0] D_REG; +reg signed [35:0] M_REG; +reg signed [47:0] P_REG; +reg [7:0] OPMODE_REG; +reg CARRYIN_REG; +reg CARRYOUT_REG; + +initial begin + A0_REG = 0; + A1_REG = 0; + B0_REG = 0; + B1_REG = 0; + C_REG = 0; + D_REG = 0; + M_REG = 0; + P_REG = 0; + OPMODE_REG = 0; + CARRYIN_REG = 0; + CARRYOUT_REG = 0; +end + +generate + +if (RSTTYPE == "SYNC") begin + always @(posedge CLK) begin + if (RSTA) begin + A0_REG <= 0; + A1_REG <= 0; + end else if (CEA) begin + A0_REG <= A; + A1_REG <= A0_OUT; + end + end + + always @(posedge CLK) begin + if (RSTB) begin + B0_REG <= 0; + B1_REG <= 0; + end else if (CEB) begin + B0_REG <= B; + B1_REG <= B1_IN; + end + end + + always @(posedge CLK) begin + if (RSTC) begin + C_REG <= 0; + end else if (CEC) begin + C_REG <= C; + end + end + + always @(posedge CLK) begin + if (RSTD) begin + D_REG <= 0; + end else if (CED) begin + D_REG <= D; + end + end + + always @(posedge CLK) begin + if (RSTM) begin + M_REG <= 0; + end else if (CEM) begin + M_REG <= M_MULT; + end + end + + always @(posedge CLK) begin + if (RSTP) begin + P_REG <= 0; + end else if (CEP) begin + P_REG <= P_IN; + end + end + + always @(posedge CLK) begin + if (RSTOPMODE) begin + OPMODE_REG <= 0; + end else if (CEOPMODE) begin + OPMODE_REG <= OPMODE; + end + end + + always @(posedge CLK) begin + if (RSTCARRYIN) begin + CARRYIN_REG <= 0; + CARRYOUT_REG <= 0; + end else if (CECARRYIN) begin + CARRYIN_REG <= CARRYIN_IN; + CARRYOUT_REG <= CARRYOUT_IN; + end + end +end else begin + always @(posedge CLK, posedge RSTA) begin + if (RSTA) begin + A0_REG <= 0; + A1_REG <= 0; + end else if (CEA) begin + A0_REG <= A; + A1_REG <= A0_OUT; + end + end + + always @(posedge CLK, posedge RSTB) begin + if (RSTB) begin + B0_REG <= 0; + B1_REG <= 0; + end else if (CEB) begin + B0_REG <= B; + B1_REG <= B1_IN; + end + end + + always @(posedge CLK, posedge RSTC) begin + if (RSTC) begin + C_REG <= 0; + end else if (CEC) begin + C_REG <= C; + end + end + + always @(posedge CLK, posedge RSTD) begin + if (RSTD) begin + D_REG <= 0; + end else if (CED) begin + D_REG <= D; + end + end + + always @(posedge CLK, posedge RSTM) begin + if (RSTM) begin + M_REG <= 0; + end else if (CEM) begin + M_REG <= M_MULT; + end + end + + always @(posedge CLK, posedge RSTP) begin + if (RSTP) begin + P_REG <= 0; + end else if (CEP) begin + P_REG <= P_IN; + end + end + + always @(posedge CLK, posedge RSTOPMODE) begin + if (RSTOPMODE) begin + OPMODE_REG <= 0; + end else if (CEOPMODE) begin + OPMODE_REG <= OPMODE; + end + end + + always @(posedge CLK, posedge RSTCARRYIN) begin + if (RSTCARRYIN) begin + CARRYIN_REG <= 0; + CARRYOUT_REG <= 0; + end else if (CECARRYIN) begin + CARRYIN_REG <= CARRYIN_IN; + CARRYOUT_REG <= CARRYOUT_IN; + end + end +end + +endgenerate + +// The register enables. +assign A0_OUT = (A0REG == 1) ? A0_REG : A; +assign A1_OUT = (A1REG == 1) ? A1_REG : A0_OUT; +assign B0_OUT = (B0REG == 1) ? B0_REG : B; +assign B1_OUT = (B1REG == 1) ? B1_REG : B1_IN; +assign C_OUT = (CREG == 1) ? C_REG : C; +assign D_OUT = (DREG == 1) ? D_REG : D; +assign M = (MREG == 1) ? M_REG : M_MULT; +assign P = (PREG == 1) ? P_REG : P_IN; +assign OPMODE_OUT = (OPMODEREG == 1) ? OPMODE_REG : OPMODE; +assign CARRYIN_OUT = (CARRYINREG == 1) ? CARRYIN_REG : CARRYIN_IN; +assign CARRYOUT = (CARRYOUTREG == 1) ? CARRYOUT_REG : CARRYOUT_IN; +assign CARRYOUTF = CARRYOUT; + +// The pre-adder. +wire signed [17:0] PREADDER; +assign B1_IN = OPMODE_OUT[4] ? PREADDER : B0_OUT; +assign PREADDER = OPMODE_OUT[6] ? D_OUT - B0_OUT : D_OUT + B0_OUT; + +// The multiplier. +assign M_MULT = A1_OUT * B1_OUT; + +// The carry in selection. +assign CARRYIN_IN = (CARRYINSEL == "OPMODE5") ? OPMODE_OUT[5] : CARRYIN; + +// The post-adder inputs. +always @* begin + case (OPMODE_OUT[1:0]) + 2'b00: XMUX <= 0; + 2'b01: XMUX <= M; + 2'b10: XMUX <= P; + 2'b11: XMUX <= {D_OUT[11:0], B1_OUT, A1_OUT}; + default: XMUX <= 48'hxxxxxxxxxxxx; + endcase +end + +always @* begin + case (OPMODE_OUT[3:2]) + 2'b00: ZMUX <= 0; + 2'b01: ZMUX <= PCIN; + 2'b10: ZMUX <= P; + 2'b11: ZMUX <= C_OUT; + default: ZMUX <= 48'hxxxxxxxxxxxx; + endcase +end + +// The post-adder. +wire signed [48:0] X_EXT; +wire signed [48:0] Z_EXT; +assign X_EXT = XMUX; +assign Z_EXT = ZMUX; +assign {CARRYOUT_IN, P_IN} = OPMODE_OUT[7] ? (Z_EXT - (X_EXT + CARRYIN_OUT)) : (Z_EXT + X_EXT + CARRYIN_OUT); + +// Cascade outputs. +assign BCOUT = B1_OUT; +assign PCOUT = P; + +endmodule + +// TODO: DSP48 (Virtex 4). + +// TODO: DSP48E (Virtex 5). + +// Virtex 6, Series 7. + module DSP48E1 ( output [29:0] ACOUT, output [17:0] BCOUT, @@ -1043,3 +1552,5 @@ module DSP48E1 ( endgenerate endmodule + +// TODO: DSP48E2 (Ultrascale). diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py index ef7ce856a..f401ebe78 100644 --- a/techlibs/xilinx/cells_xtra.py +++ b/techlibs/xilinx/cells_xtra.py @@ -204,11 +204,11 @@ CELLS = [ Cell('URAM288_BASE', port_attrs={'CLK': ['clkbuf_sink']}), # Multipliers and DSP. - Cell('MULT18X18'), # Spartan 3 - Cell('MULT18X18S', port_attrs={'C': ['clkbuf_sink']}), # Spartan 3 - Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E - Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP - Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6 + # Cell('MULT18X18'), # Virtex 2, Spartan 3 + # Cell('MULT18X18S', port_attrs={'C': ['clkbuf_sink']}), # Spartan 3 + # Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E + # Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP + # Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6 Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4 Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5 #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7 diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 72a3b6cbb..ce0949f2c 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -6218,133 +6218,6 @@ module URAM288_BASE (...); input SLEEP; endmodule -module MULT18X18 (...); - output [35:0] P; - input [17:0] A; - input [17:0] B; -endmodule - -module MULT18X18S (...); - output [35:0] P; - input [17:0] A; - input [17:0] B; - (* clkbuf_sink *) - input C; - input CE; - input R; -endmodule - -module MULT18X18SIO (...); - parameter integer AREG = 1; - parameter integer BREG = 1; - parameter B_INPUT = "DIRECT"; - parameter integer PREG = 1; - output [17:0] BCOUT; - output [35:0] P; - input [17:0] A; - input [17:0] B; - input [17:0] BCIN; - input CEA; - input CEB; - input CEP; - (* clkbuf_sink *) - input CLK; - input RSTA; - input RSTB; - input RSTP; -endmodule - -module DSP48A (...); - parameter integer A0REG = 0; - parameter integer A1REG = 1; - parameter integer B0REG = 0; - parameter integer B1REG = 1; - parameter integer CARRYINREG = 1; - parameter CARRYINSEL = "CARRYIN"; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer MREG = 1; - parameter integer OPMODEREG = 1; - parameter integer PREG = 1; - parameter RSTTYPE = "SYNC"; - output [17:0] BCOUT; - output CARRYOUT; - output [47:0] P; - output [47:0] PCOUT; - input [17:0] A; - input [17:0] B; - input [47:0] C; - input CARRYIN; - input CEA; - input CEB; - input CEC; - input CECARRYIN; - input CED; - input CEM; - input CEOPMODE; - input CEP; - (* clkbuf_sink *) - input CLK; - input [17:0] D; - input [7:0] OPMODE; - input [47:0] PCIN; - input RSTA; - input RSTB; - input RSTC; - input RSTCARRYIN; - input RSTD; - input RSTM; - input RSTOPMODE; - input RSTP; -endmodule - -module DSP48A1 (...); - parameter integer A0REG = 0; - parameter integer A1REG = 1; - parameter integer B0REG = 0; - parameter integer B1REG = 1; - parameter integer CARRYINREG = 1; - parameter integer CARRYOUTREG = 1; - parameter CARRYINSEL = "OPMODE5"; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer MREG = 1; - parameter integer OPMODEREG = 1; - parameter integer PREG = 1; - parameter RSTTYPE = "SYNC"; - output [17:0] BCOUT; - output CARRYOUT; - output CARRYOUTF; - output [35:0] M; - output [47:0] P; - output [47:0] PCOUT; - input [17:0] A; - input [17:0] B; - input [47:0] C; - input CARRYIN; - input CEA; - input CEB; - input CEC; - input CECARRYIN; - input CED; - input CEM; - input CEOPMODE; - input CEP; - (* clkbuf_sink *) - input CLK; - input [17:0] D; - input [7:0] OPMODE; - input [47:0] PCIN; - input RSTA; - input RSTB; - input RSTC; - input RSTCARRYIN; - input RSTD; - input RSTM; - input RSTOPMODE; - input RSTP; -endmodule - module DSP48 (...); parameter integer AREG = 1; parameter integer BREG = 1; diff --git a/tests/various/bug1462.ys b/tests/various/bug1462.ys new file mode 100644 index 000000000..15cab5121 --- /dev/null +++ b/tests/various/bug1462.ys @@ -0,0 +1,11 @@ +read_verilog << EOF +module top(...); +input wire [31:0] A; +output wire [31:0] P; + +assign P = A * 32'h12300000; + +endmodule +EOF + +synth_xilinx diff --git a/tests/various/bug1480.ys b/tests/various/bug1480.ys new file mode 100644 index 000000000..84faea08a --- /dev/null +++ b/tests/various/bug1480.ys @@ -0,0 +1,18 @@ +read_verilog << EOF +module top(...); + +input signed [17:0] A; +input signed [17:0] B; +output X; +output Y; + +wire [35:0] P; +assign P = A * B; + +assign X = P[0]; +assign Y = P[35]; + +endmodule +EOF + +synth_xilinx diff --git a/tests/various/bug1496.ys b/tests/various/bug1496.ys new file mode 100644 index 000000000..d050161dc --- /dev/null +++ b/tests/various/bug1496.ys @@ -0,0 +1,13 @@ +read_ilang << EOF +module \top + wire input 1 \A + wire output 2 \Y + cell $_AND_ \sub + connect \A \A + connect \B 1'0 + connect \Y \Y + end +end +EOF + +extract_fa |