Merge branch 'master' into xc7dsp
authorDavid Shah <dave@ds0.me>
Fri, 30 Aug 2019 12:57:15 +0000 (13:57 +0100)
committerDavid Shah <dave@ds0.me>
Fri, 30 Aug 2019 12:57:15 +0000 (13:57 +0100)
12 files changed:
1  2 
kernel/rtlil.cc
kernel/rtlil.h
passes/pmgen/Makefile.inc
passes/pmgen/ice40_dsp.pmg
techlibs/ecp5/Makefile.inc
techlibs/ecp5/synth_ecp5.cc
techlibs/ice40/Makefile.inc
techlibs/ice40/synth_ice40.cc
techlibs/xilinx/Makefile.inc
techlibs/xilinx/cells_sim.v
techlibs/xilinx/cells_xtra.v
techlibs/xilinx/synth_xilinx.cc

diff --cc kernel/rtlil.cc
Simple merge
diff --cc kernel/rtlil.h
Simple merge
index e33866670611feeb4e42cbd583d8b3c78abd4b5e,8e0cbdca83f427720f7cffcb1568e9cdc58f4bb5..685024ec29f653e649042ee8b5c20f049e2c0722
@@@ -4,22 -9,21 +9,27 @@@ $(eval $(call add_extra_objs,passes/pmg
  
  # --------------------------------------
  
- passes/pmgen/%.o: passes/pmgen/%_pm.h
+ OBJS += passes/pmgen/ice40_dsp.o
  passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
- passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h
- EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
- EXTRA_OBJS += passes/pmgen/xilinx_dsp_pm.h
- .SECONDARY: passes/pmgen/ice40_dsp_pm.h
- .SECONDARY: passes/pmgen/xilinx_dsp_pm.h
+ $(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h))
  
- passes/pmgen/%_pm.h: passes/pmgen/pmgen.py passes/pmgen/%.pmg
-       $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $* $(filter-out $<,$^)
+ # --------------------------------------
+ OBJS += passes/pmgen/ice40_wrapcarry.o
+ passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h
+ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
+ # --------------------------------------
++OBJS += passes/pmgen/xilinx_dsp.o
++passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h
++$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
 +
 +# --------------------------------------
 +
+ OBJS += passes/pmgen/peepopt.o
  passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
- EXTRA_OBJS += passes/pmgen/peepopt_pm.h
- .SECONDARY: passes/pmgen/peepopt_pm.h
+ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
  
  PEEPOPT_PATTERN  = passes/pmgen/peepopt_shiftmul.pmg
  PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
index c59c5d20ad7f8d612adc650da866724916e2baf1,7003092bb05d521bc59cea7fa5e524dc423e00bf..ce2dcbc7e2612651bc26151ba45d316d00cdd4e4
@@@ -179,90 -139,25 +179,91 @@@ code muxA
                muxAB = muxB;
  endcode
  
 -match ffS
 -      if muxAB
 -      select ffS->type.in($dff)
 -      select nusers(port(ffS, \D)) == 2
 -      index <SigSpec> port(ffS, \D) === port(muxAB, \Y)
 -      index <SigSpec> port(ffS, \Q) === sigS
 +// Extract the bits of P that actually have a consumer
 +// (as opposed to being a dummy)
 +code sigOused
 +      for (int i = 0; i < GetSize(sigO); i++)
 +              if (!sigO[i].wire || nusers(sigO[i]) == 1)
 +                      sigOused.append(State::Sx);
 +              else
 +                      sigOused.append(sigO[i]);
 +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
 +
 +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 clock clock_pol clock_vld
 -      if (ffS) {
 -              SigBit c = port(ffS, \CLK).as_bit();
 -              bool cp = param(ffS, \CLK_POLARITY).as_bool();
 +code clock clock_pol sigO sigCD
 +      if (ffO_lo || ffO_hi) {
 +              if (mul->type == \SB_MAC16) {
 +                      // Ensure that register is not already used
 +                      if (param(mul, \TOPOUTPUT_SELECT).as_int() == 1 ||
 +                                      param(mul, \BOTOUTPUT_SELECT).as_int() == 1)
 +                              reject;
  
 -              if (clock_vld && (c != clock || cp != clock_pol))
 -                      reject;
 +                      // Ensure that OLOADTOP/OLOADBOT is unused or zero
 +                      if ((mul->hasPort(\OLOADTOP) && !port(mul, \OLOADTOP).is_fully_zero())
 +                              || (mul->hasPort(\OLOADBOT) && !port(mul, \OLOADBOT).is_fully_zero()))
 +                              reject;
 +              }
  
 -              clock = c;
 -              clock_pol = cp;
 -              clock_vld = true;
 +              if (ffO_lo) {
 +                      for (auto b : port(ffO_lo, \Q))
 +                              if (b.wire->get_bool_attribute(\keep))
 +                                      reject;
 +
 +                      SigBit c = port(ffO_lo, \CLK).as_bit();
 +                      bool cp = param(ffO_lo, \CLK_POLARITY).as_bool();
 +
 +                      if (clock != SigBit() && (c != clock || cp != clock_pol))
 +                              reject;
 +
 +                      clock = c;
 +                      clock_pol = cp;
 +
 +                      sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q));
 +              }
 +
 +              if (ffO_hi) {
 +                      for (auto b : port(ffO_hi, \Q))
 +                              if (b.wire->get_bool_attribute(\keep))
 +                                      reject;
 +
 +                      SigBit c = port(ffO_hi, \CLK).as_bit();
 +                      bool cp = param(ffO_hi, \CLK_POLARITY).as_bool();
 +
 +                      if (clock != SigBit() && (c != clock || cp != clock_pol))
 +                              reject;
 +
 +                      clock = c;
 +                      clock_pol = cp;
 +
 +                      sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q));
 +              }
 +
 +              // Loading value into output register is not
 +              //   supported unless using accumulator
 +              if (muxAB) {
 +                      if (sigCD != sigO)
 +                              reject;
 +                      if (muxA)
 +                              sigCD = port(muxAB, \B);
 +                      else if (muxB)
 +                              sigCD = port(muxAB, \A);
 +                      else log_abort();
 +                      sigCD.extend_u0(32, addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool());
 +              }
        }
+       accept;
  endcode
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 2731cb454eda64a263690ed9fe2818a37b48eab2,e12b77c024632e5d5c9a2b4c1a700738c27bb7eb..50f66d89d12417dbb38c2fba898656747185f0f2
@@@ -378,410 -445,3 +445,410 @@@ module SRLC32E 
        always @(posedge CLK) if (CE) r <= { r[30:0], D };
    endgenerate
  endmodule
-     input CLK,
 +
 +module DSP48E1 (
 +    output [29:0] ACOUT,
 +    output [17:0] BCOUT,
 +    output reg CARRYCASCOUT,
 +    output reg [3:0] CARRYOUT,
 +    output reg MULTSIGNOUT,
 +    output OVERFLOW,
 +    output reg signed [47:0] P,
 +    output PATTERNBDETECT,
 +    output PATTERNDETECT,
 +    output [47:0] PCOUT,
 +    output UNDERFLOW,
 +    input signed [29:0] A,
 +    input [29:0] ACIN,
 +    input [3:0] ALUMODE,
 +    input signed [17:0] B,
 +    input [17:0] BCIN,
 +    input [47:0] C,
 +    input CARRYCASCIN,
 +    input CARRYIN,
 +    input [2:0] CARRYINSEL,
 +    input CEA1,
 +    input CEA2,
 +    input CEAD,
 +    input CEALUMODE,
 +    input CEB1,
 +    input CEB2,
 +    input CEC,
 +    input CECARRYIN,
 +    input CECTRL,
 +    input CED,
 +    input CEINMODE,
 +    input CEM,
 +    input CEP,
++    (* clkbuf_sink *) input CLK,
 +    input [24:0] D,
 +    input [4:0] INMODE,
 +    input MULTSIGNIN,
 +    input [6:0] OPMODE,
 +    input [47:0] PCIN,
 +    input RSTA,
 +    input RSTALLCARRYIN,
 +    input RSTALUMODE,
 +    input RSTB,
 +    input RSTC,
 +    input RSTCTRL,
 +    input RSTD,
 +    input RSTINMODE,
 +    input RSTM,
 +    input RSTP
 +);
 +    parameter integer ACASCREG = 1;
 +    parameter integer ADREG = 1;
 +    parameter integer ALUMODEREG = 1;
 +    parameter integer AREG = 1;
 +    parameter AUTORESET_PATDET = "NO_RESET";
 +    parameter A_INPUT = "DIRECT";
 +    parameter integer BCASCREG = 1;
 +    parameter integer BREG = 1;
 +    parameter B_INPUT = "DIRECT";
 +    parameter integer CARRYINREG = 1;
 +    parameter integer CARRYINSELREG = 1;
 +    parameter integer CREG = 1;
 +    parameter integer DREG = 1;
 +    parameter integer INMODEREG = 1;
 +    parameter integer MREG = 1;
 +    parameter integer OPMODEREG = 1;
 +    parameter integer PREG = 1;
 +    parameter SEL_MASK = "MASK";
 +    parameter SEL_PATTERN = "PATTERN";
 +    parameter USE_DPORT = "FALSE";
 +    parameter USE_MULT = "MULTIPLY";
 +    parameter USE_PATTERN_DETECT = "NO_PATDET";
 +    parameter USE_SIMD = "ONE48";
 +    parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
 +    parameter [47:0] PATTERN = 48'h000000000000;
 +    parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
 +    parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
 +    parameter [0:0] IS_CLK_INVERTED = 1'b0;
 +    parameter [4:0] IS_INMODE_INVERTED = 5'b0;
 +    parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
 +
 +    initial begin
 +`ifdef __ICARUS__
 +        if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
 +        //if (PREG != 0)              $fatal(1, "Unsupported PREG value");
 +        if (SEL_MASK != "MASK")     $fatal(1, "Unsupported SEL_MASK value");
 +        if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
 +        if (USE_PATTERN_DETECT != "NO_PATDET") $fatal(1, "Unsupported USE_PATTERN_DETECT value");
 +        if (USE_SIMD != "ONE48" && USE_SIMD != "TWO24" && USE_SIMD != "FOUR12")    $fatal(1, "Unsupported USE_SIMD value");
 +        if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value");
 +        if (IS_CARRYIN_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CARRYIN_INVERTED value");
 +        if (IS_CLK_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CLK_INVERTED value");
 +        if (IS_INMODE_INVERTED != 5'b0) $fatal(1, "Unsupported IS_INMODE_INVERTED value");
 +        if (IS_OPMODE_INVERTED != 7'b0) $fatal(1, "Unsupported IS_OPMODE_INVERTED value");
 +`endif
 +    end
 +
 +    wire signed [29:0] A_muxed;
 +    wire signed [17:0] B_muxed;
 +
 +    generate
 +        if (A_INPUT == "CASCADE") assign A_muxed = ACIN;
 +        else assign A_muxed = A;
 +
 +        if (B_INPUT == "CASCADE") assign B_muxed = BCIN;
 +        else assign B_muxed = B;
 +    endgenerate
 +
 +    reg signed [29:0] Ar1 = 30'b0, Ar2 = 30'b0;
 +    reg signed [24:0] Dr = 25'b0;
 +    reg signed [17:0] Br1 = 18'b0, Br2 = 18'b0;
 +    reg signed [47:0] Cr = 48'b0;
 +    reg        [4:0]  INMODEr = 5'b0;
 +    reg        [6:0]  OPMODEr = 7'b0;
 +    reg        [3:0]  ALUMODEr = 4'b0;
 +    reg        [2:0]  CARRYINSELr = 3'b0;
 +
 +    generate
 +        // Configurable A register
 +        if (AREG == 2) begin
 +            always @(posedge CLK)
 +                if (RSTA) begin
 +                    Ar1 <= 30'b0;
 +                    Ar2 <= 30'b0;
 +                end else begin
 +                    if (CEA1) Ar1 <= A_muxed;
 +                    if (CEA2) Ar2 <= Ar1;
 +                end
 +        end else if (AREG == 1) begin
 +            always @(posedge CLK)
 +                if (RSTA) begin
 +                    Ar1 <= 30'b0;
 +                    Ar2 <= 30'b0;
 +                end else begin
 +                    if (CEA1) Ar1 <= A_muxed;
 +                    if (CEA2) Ar2 <= A_muxed;
 +                end
 +        end else begin
 +            always @* Ar1 <= A_muxed;
 +            always @* Ar2 <= A_muxed;
 +        end
 +
 +        // Configurable B register
 +        if (BREG == 2) begin
 +            always @(posedge CLK)
 +                if (RSTB) begin
 +                    Br1 <= 18'b0;
 +                    Br2 <= 18'b0;
 +                end else begin
 +                    if (CEB1) Br1 <= B_muxed;
 +                    if (CEB2) Br2 <= Br1;
 +                end
 +        end else if (BREG == 1) begin
 +            always @(posedge CLK)
 +                if (RSTB) begin
 +                    Br1 <= 18'b0;
 +                    Br2 <= 18'b0;
 +                end else begin
 +                    if (CEB1) Br1 <= B_muxed;
 +                    if (CEB2) Br2 <= B_muxed;
 +                end
 +        end else begin
 +            always @* Br1 <= B_muxed;
 +            always @* Br2 <= B_muxed;
 +        end
 +
 +        // C and D registers
 +        if (CREG == 1) begin always @(posedge CLK) if (RSTC) Cr <= 48'b0; else if (CEC) Cr <= C; end
 +        else           always @* Cr <= C;
 +
 +        if (DREG == 1) begin always @(posedge CLK) if (RSTD) Dr <= 25'b0; else if (CED) Dr <= D; end
 +        else           always @* Dr <= D;
 +
 +        // Control registers
 +        if (INMODEREG == 1) begin always @(posedge CLK) if (RSTINMODE) INMODEr <= 5'b0; else if (CEINMODE) INMODEr <= INMODE; end
 +        else           always @* INMODEr <= INMODE;
 +        if (OPMODEREG == 1) begin always @(posedge CLK) if (RSTCTRL) OPMODEr <= 7'b0; else if (CECTRL) OPMODEr <= OPMODE; end
 +        else           always @* OPMODEr <= OPMODE;
 +        if (ALUMODEREG == 1) begin always @(posedge CLK) if (RSTALUMODE) ALUMODEr <= 4'b0; else if (CEALUMODE) ALUMODEr <= ALUMODE; end
 +        else           always @* ALUMODEr <= ALUMODE;
 +        if (CARRYINSELREG == 1) begin always @(posedge CLK) if (RSTCTRL) CARRYINSELr <= 3'b0; else if (CECTRL) CARRYINSELr <= CARRYINSEL; end
 +        else           always @* CARRYINSELr <= CARRYINSEL;
 +    endgenerate
 +
 +    // A and B cascsde
 +    generate
 +        if (ACASCREG == 1 && AREG == 2) assign ACOUT = Ar1;
 +        else assign ACOUT = Ar2;
 +        if (BCASCREG == 1 && BREG == 2) assign BCOUT = Br1;
 +        else assign BCOUT = Br2;
 +    endgenerate
 +
 +    // A/D input selection and pre-adder
 +    wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2;
 +    wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed;
 +    wire signed [24:0] Dr_gated   = INMODEr[2] ? Dr : 25'b0;
 +    wire signed [24:0] AD_result  = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated);
 +    reg  signed [24:0] ADr = 25'b0;
 +
 +    generate
 +        if (ADREG == 1) begin always @(posedge CLK) if (RSTD) ADr <= 25'b0; else if (CEAD) ADr <= AD_result; end
 +        else            always @* ADr <= AD_result;
 +    endgenerate
 +
 +    // 25x18 multiplier
 +    wire signed [24:0] A_MULT;
 +    wire signed [17:0] B_MULT = INMODEr[4] ? Br1 : Br2;
 +    generate
 +        if (USE_DPORT == "TRUE") assign A_MULT = ADr;
 +        else assign A_MULT = Ar12_gated;
 +    endgenerate
 +
 +    wire signed [42:0] M = A_MULT * B_MULT;
 +    wire signed [42:0] Mx = (CARRYINSEL == 3'b010) ? 43'bx : M;
 +    reg  signed [42:0] Mr = 43'b0;
 +
 +    // Multiplier result register
 +    generate
 +        if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= Mx; end
 +        else           always @* Mr <= Mx;
 +    endgenerate
 +
 +    wire signed [42:0] Mrx = (CARRYINSELr == 3'b010) ? 43'bx : Mr;
 +
 +    // X, Y and Z ALU inputs
 +    reg signed [47:0] X, Y, Z;
 +
 +    always @* begin
 +        // X multiplexer
 +        case (OPMODEr[1:0])
 +            2'b00: X = 48'b0;
 +            2'b01: begin X = $signed(Mrx);
 +`ifdef __ICARUS__
 +                if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
 +`endif
 +            end
 +            2'b10: begin X = P;
 +`ifdef __ICARUS__
 +                if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
 +`endif
 +            end
 +            2'b11: X = $signed({Ar2, Br2});
 +            default: X = 48'bx;
 +        endcase
 +
 +        // Y multiplexer
 +        case (OPMODEr[3:2])
 +            2'b00: Y = 48'b0;
 +            2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
 +`ifdef __ICARUS__
 +                if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
 +`endif
 +            end
 +            2'b10: Y = {48{1'b1}};
 +            2'b11: Y = Cr;
 +            default: Y = 48'bx;
 +        endcase
 +
 +        // Z multiplexer
 +        case (OPMODEr[6:4])
 +            3'b000: Z = 48'b0;
 +            3'b001: Z = PCIN;
 +            3'b010: begin Z = P;
 +`ifdef __ICARUS__
 +                if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
 +`endif
 +            end
 +            3'b011: Z = Cr;
 +            3'b100: begin Z = P;
 +`ifdef __ICARUS__
 +                if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
 +                if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
 +`endif
 +            end
 +            3'b101: Z = $signed(PCIN[47:17]);
 +            3'b110: Z = $signed(P[47:17]);
 +            default: Z = 48'bx;
 +        endcase
 +    end
 +
 +    // Carry in
 +    wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
 +    reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0;
 +    generate
 +        if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
 +        else                 always @* CARRYINr = CARRYIN;
 +
 +        if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end
 +        else                 always @* A24_xnor_B17 = A24_xnor_B17d;
 +    endgenerate
 +
 +    reg cin_muxed;
 +
 +    always @(*) begin
 +        case (CARRYINSELr)
 +            3'b000: cin_muxed = CARRYINr;
 +            3'b001: cin_muxed = ~PCIN[47];
 +            3'b010: cin_muxed = CARRYCASCIN;
 +            3'b011: cin_muxed = PCIN[47];
 +            3'b100: cin_muxed = CARRYCASCOUT;
 +            3'b101: cin_muxed = ~P[47];
 +            3'b110: cin_muxed = A24_xnor_B17;
 +            3'b111: cin_muxed = P[47];
 +            default: cin_muxed = 1'bx;
 +        endcase
 +    end
 +
 +    wire alu_cin = (ALUMODEr[3] || ALUMODEr[2]) ? 1'b0 : cin_muxed;
 +
 +    // ALU core
 +    wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
 +    wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
 +    wire [47:0] maj_xyz = (X & Y) | (X & Z_muxinv) | (Y & Z_muxinv);
 +
 +    wire [47:0] xor_xyz_muxed = ALUMODEr[3] ? maj_xyz : xor_xyz;
 +    wire [47:0] maj_xyz_gated = ALUMODEr[2] ? 48'b0 :  maj_xyz;
 +
 +    wire [48:0] maj_xyz_simd_gated;
 +    wire [3:0] int_carry_in, int_carry_out, ext_carry_out;
 +    wire [47:0] alu_sum;
 +    assign int_carry_in[0] = 1'b0;
 +    wire [3:0] carryout_reset;
 +
 +    generate
 +        if (USE_SIMD == "FOUR12") begin
 +            assign maj_xyz_simd_gated = {
 +                    maj_xyz_gated[47:36],
 +                    1'b0, maj_xyz_gated[34:24],
 +                    1'b0, maj_xyz_gated[22:12],
 +                    1'b0, maj_xyz_gated[10:0],
 +                    alu_cin
 +                };
 +            assign int_carry_in[3:1] = 3'b000;
 +            assign ext_carry_out = {
 +                    int_carry_out[3],
 +                    maj_xyz_gated[35] ^ int_carry_out[2],
 +                    maj_xyz_gated[23] ^ int_carry_out[1],
 +                    maj_xyz_gated[11] ^ int_carry_out[0]
 +                };
 +            assign carryout_reset = 4'b0000;
 +        end else if (USE_SIMD == "TWO24") begin
 +            assign maj_xyz_simd_gated = {
 +                    maj_xyz_gated[47:24],
 +                    1'b0, maj_xyz_gated[22:0],
 +                    alu_cin
 +                };
 +            assign int_carry_in[3:1] = {int_carry_out[2], 1'b0, int_carry_out[0]};
 +            assign ext_carry_out = {
 +                    int_carry_out[3],
 +                    1'bx,
 +                    maj_xyz_gated[23] ^ int_carry_out[1],
 +                    1'bx
 +                };
 +            assign carryout_reset = 4'b0x0x;
 +        end else begin
 +            assign maj_xyz_simd_gated = {maj_xyz_gated, alu_cin};
 +            assign int_carry_in[3:1] = int_carry_out[2:0];
 +            assign ext_carry_out = {
 +                    int_carry_out[3],
 +                    3'bxxx
 +                };
 +            assign carryout_reset = 4'b0xxx;
 +        end
 +
 +        genvar i;
 +        for (i = 0; i < 4; i = i + 1)
 +            assign {int_carry_out[i], alu_sum[i*12 +: 12]} = {1'b0, maj_xyz_simd_gated[i*12 +: ((i == 3) ? 13 : 12)]}
 +                                                              + xor_xyz_muxed[i*12 +: 12] + int_carry_in[i];
 +    endgenerate
 +
 +    wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
 +    initial P = 48'b0;
 +    initial CARRYOUT = carryout_reset;
 +    initial CARRYCASCOUT = 1'b0;
 +    initial MULTSIGNOUT = 1'b0;
 +    wire [3:0] CARRYOUTd = (OPMODEr[3:0] == 4'b0101 || ALUMODEr[3:2] != 2'b00) ? 4'bxxxx :
 +                           ((ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out);
 +    wire CARRYCASCOUTd = ext_carry_out[3];
 +    wire MULTSIGNOUTd = Mrx[42];
 +
 +    generate
 +        if (PREG == 1) begin
 +            always @(posedge CLK)
 +                if (RSTP) begin
 +                    P <= 48'b0;
 +                    CARRYOUT <= carryout_reset;
 +                    CARRYCASCOUT <= 1'b0;
 +                    MULTSIGNOUT <= 1'b0;
 +                end else if (CEP) begin
 +                    P <= Pd;
 +                    CARRYOUT <= CARRYOUTd;
 +                    CARRYCASCOUT <= CARRYCASCOUTd;
 +                    MULTSIGNOUT <= MULTSIGNOUTd;
 +                end
 +        end else begin
 +            always @* begin
 +                P = Pd;
 +                CARRYOUT = CARRYOUTd;
 +                CARRYCASCOUT = CARRYCASCOUTd;
 +                MULTSIGNOUT = MULTSIGNOUTd;
 +            end
 +        end
 +    endgenerate
 +
 +endmodule
index d79349225810ba65466649a96be9087607148e46,a6669b8729dbe59298840b617b1f148c8161d258..b8abdda6482b8cdeca369e6ddc21c065d4a6a2a0
@@@ -108,9 -131,95 +131,12 @@@ endmodul
  module DNA_PORT (...);
      parameter [56:0] SIM_DNA_VALUE = 57'h0;
      output DOUT;
-     input CLK, DIN, READ, SHIFT;
+     input CLK;
+     input DIN;
+     input READ;
+     input SHIFT;
  endmodule
  
 -module DSP48E1 (...);
 -    parameter integer ACASCREG = 1;
 -    parameter integer ADREG = 1;
 -    parameter integer ALUMODEREG = 1;
 -    parameter integer AREG = 1;
 -    parameter AUTORESET_PATDET = "NO_RESET";
 -    parameter A_INPUT = "DIRECT";
 -    parameter integer BCASCREG = 1;
 -    parameter integer BREG = 1;
 -    parameter B_INPUT = "DIRECT";
 -    parameter integer CARRYINREG = 1;
 -    parameter integer CARRYINSELREG = 1;
 -    parameter integer CREG = 1;
 -    parameter integer DREG = 1;
 -    parameter integer INMODEREG = 1;
 -    parameter integer MREG = 1;
 -    parameter integer OPMODEREG = 1;
 -    parameter integer PREG = 1;
 -    parameter SEL_MASK = "MASK";
 -    parameter SEL_PATTERN = "PATTERN";
 -    parameter USE_DPORT = "FALSE";
 -    parameter USE_MULT = "MULTIPLY";
 -    parameter USE_PATTERN_DETECT = "NO_PATDET";
 -    parameter USE_SIMD = "ONE48";
 -    parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
 -    parameter [47:0] PATTERN = 48'h000000000000;
 -    parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
 -    parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
 -    parameter [0:0] IS_CLK_INVERTED = 1'b0;
 -    parameter [4:0] IS_INMODE_INVERTED = 5'b0;
 -    parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
 -    output [29:0] ACOUT;
 -    output [17:0] BCOUT;
 -    output CARRYCASCOUT;
 -    output [3:0] CARRYOUT;
 -    output MULTSIGNOUT;
 -    output OVERFLOW;
 -    output [47:0] P;
 -    output PATTERNBDETECT;
 -    output PATTERNDETECT;
 -    output [47:0] PCOUT;
 -    output UNDERFLOW;
 -    input [29:0] A;
 -    input [29:0] ACIN;
 -    input [3:0] ALUMODE;
 -    input [17:0] B;
 -    input [17:0] BCIN;
 -    input [47:0] C;
 -    input CARRYCASCIN;
 -    input CARRYIN;
 -    input [2:0] CARRYINSEL;
 -    input CEA1;
 -    input CEA2;
 -    input CEAD;
 -    input CEALUMODE;
 -    input CEB1;
 -    input CEB2;
 -    input CEC;
 -    input CECARRYIN;
 -    input CECTRL;
 -    input CED;
 -    input CEINMODE;
 -    input CEM;
 -    input CEP;
 -    (* clkbuf_sink *)
 -    input CLK;
 -    input [24:0] D;
 -    input [4:0] INMODE;
 -    input MULTSIGNIN;
 -    input [6:0] OPMODE;
 -    input [47:0] PCIN;
 -    input RSTA;
 -    input RSTALLCARRYIN;
 -    input RSTALUMODE;
 -    input RSTB;
 -    input RSTC;
 -    input RSTCTRL;
 -    input RSTD;
 -    input RSTINMODE;
 -    input RSTM;
 -    input RSTP;
 -endmodule
 -
  module EFUSE_USR (...);
      parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000;
      output [31:0] EFUSEUSR;
index 546d673377a76ddeed7c0db0fb0656c48ae498f0,f058da83d2cca7253582b1a2ab5bede2699a99f5..2bd8570ec7936907998e6269e62b45c085231fd2
@@@ -78,8 -81,14 +81,16 @@@ struct SynthXilinxPass : public ScriptP
                log("    -nowidelut\n");
                log("        do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
                log("\n");
 +              log("    -nodsp\n");
 +              log("        do not use DSP48E1s to implement multipliers and associated logic\n");
+               log("    -iopad\n");
+               log("        enable I/O buffer insertion (selected automatically by -ise)\n");
+               log("\n");
+               log("    -noiopad\n");
+               log("        disable I/O buffer insertion (only useful with -ise)\n");
+               log("\n");
+               log("    -noclkbuf\n");
+               log("        disable automatic clock buffer insertion\n");
                log("\n");
                log("    -widemux <int>\n");
                log("        enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
        }
  
        std::string top_opt, edif_file, blif_file, family;
 -      bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
 +      bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, nodsp, abc9;
++      bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, abc9;
+       bool flatten_before_abc;
        int widemux;
  
        void clear_flags() YS_OVERRIDE
                nosrl = false;
                nocarry = false;
                nowidelut = false;
 +              nodsp = false;
                abc9 = false;
+               flatten_before_abc = false;
                widemux = 0;
        }