/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *                2019  Eddie Hung    <eddie@fpgeh.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// ============================================================================

module RAM32X1D (
  output DPO, SPO,
  (* techmap_autopurge *) input  D,
  (* techmap_autopurge *) input  WCLK,
  (* techmap_autopurge *) input  WE,
  (* techmap_autopurge *) input  A0, A1, A2, A3, A4,
  (* techmap_autopurge *) input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
  parameter INIT = 32'h0;
  parameter IS_WCLK_INVERTED = 1'b0;
  wire \$DPO , \$SPO ;
  RAM32X1D #(
    .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .DPO(\$DPO ), .SPO(\$SPO ),
    .D(D), .WCLK(WCLK), .WE(WE),
    .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
    .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
  );
  \$__ABC9_LUT6 spo (.A(\$SPO ), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO));
  \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
endmodule

module RAM64X1D (
  output DPO, SPO,
  (* techmap_autopurge *) input  D,
  (* techmap_autopurge *) input  WCLK,
  (* techmap_autopurge *) input  WE,
  (* techmap_autopurge *) input  A0, A1, A2, A3, A4, A5,
  (* techmap_autopurge *) input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
  parameter INIT = 64'h0;
  parameter IS_WCLK_INVERTED = 1'b0;
  wire \$DPO , \$SPO ;
  RAM64X1D #(
    .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .DPO(\$DPO ), .SPO(\$SPO ),
    .D(D), .WCLK(WCLK), .WE(WE),
    .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
    .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
  );
  \$__ABC9_LUT6 spo (.A(\$SPO ), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO));
  \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
endmodule

module RAM128X1D (
  output       DPO, SPO,
  (* techmap_autopurge *) input        D,
  (* techmap_autopurge *) input        WCLK,
  (* techmap_autopurge *) input        WE,
  (* techmap_autopurge *) input  [6:0] A, DPRA
);
  parameter INIT = 128'h0;
  parameter IS_WCLK_INVERTED = 1'b0;
  wire \$DPO , \$SPO ;
  RAM128X1D #(
    .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .DPO(\$DPO ), .SPO(\$SPO ),
    .D(D), .WCLK(WCLK), .WE(WE),
    .A(A),
    .DPRA(DPRA)
  );
  \$__ABC9_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO));
  \$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO));
endmodule

module RAM32M (
  output [1:0] DOA,
  output [1:0] DOB,
  output [1:0] DOC,
  output [1:0] DOD,
  (* techmap_autopurge *) input [4:0] ADDRA,
  (* techmap_autopurge *) input [4:0] ADDRB,
  (* techmap_autopurge *) input [4:0] ADDRC,
  (* techmap_autopurge *) input [4:0] ADDRD,
  (* techmap_autopurge *) input [1:0] DIA,
  (* techmap_autopurge *) input [1:0] DIB,
  (* techmap_autopurge *) input [1:0] DIC,
  (* techmap_autopurge *) input [1:0] DID,
  (* techmap_autopurge *) input WCLK,
  (* techmap_autopurge *) input WE
);
  parameter [63:0] INIT_A = 64'h0000000000000000;
  parameter [63:0] INIT_B = 64'h0000000000000000;
  parameter [63:0] INIT_C = 64'h0000000000000000;
  parameter [63:0] INIT_D = 64'h0000000000000000;
  parameter [0:0] IS_WCLK_INVERTED = 1'b0;
  wire [1:0] \$DOA , \$DOB , \$DOC , \$DOD ;
  RAM32M #(
    .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
    .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ),
    .WCLK(WCLK), .WE(WE),
    .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
    .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
  );
  \$__ABC9_LUT6 doa0 (.A(\$DOA [0]), .S({1'b1, ADDRA}), .Y(DOA[0]));
  \$__ABC9_LUT6 doa1 (.A(\$DOA [1]), .S({1'b1, ADDRA}), .Y(DOA[1]));
  \$__ABC9_LUT6 dob0 (.A(\$DOB [0]), .S({1'b1, ADDRB}), .Y(DOB[0]));
  \$__ABC9_LUT6 dob1 (.A(\$DOB [1]), .S({1'b1, ADDRB}), .Y(DOB[1]));
  \$__ABC9_LUT6 doc0 (.A(\$DOC [0]), .S({1'b1, ADDRC}), .Y(DOC[0]));
  \$__ABC9_LUT6 doc1 (.A(\$DOC [1]), .S({1'b1, ADDRC}), .Y(DOC[1]));
  \$__ABC9_LUT6 dod0 (.A(\$DOD [0]), .S({1'b1, ADDRD}), .Y(DOD[0]));
  \$__ABC9_LUT6 dod1 (.A(\$DOD [1]), .S({1'b1, ADDRD}), .Y(DOD[1]));
endmodule

module RAM64M (
  output DOA,
  output DOB,
  output DOC,
  output DOD,
  (* techmap_autopurge *) input [5:0] ADDRA,
  (* techmap_autopurge *) input [5:0] ADDRB,
  (* techmap_autopurge *) input [5:0] ADDRC,
  (* techmap_autopurge *) input [5:0] ADDRD,
  (* techmap_autopurge *) input DIA,
  (* techmap_autopurge *) input DIB,
  (* techmap_autopurge *) input DIC,
  (* techmap_autopurge *) input DID,
  (* techmap_autopurge *) input WCLK,
  (* techmap_autopurge *) input WE
);
  parameter [63:0] INIT_A = 64'h0000000000000000;
  parameter [63:0] INIT_B = 64'h0000000000000000;
  parameter [63:0] INIT_C = 64'h0000000000000000;
  parameter [63:0] INIT_D = 64'h0000000000000000;
  parameter [0:0] IS_WCLK_INVERTED = 1'b0;
  wire \$DOA , \$DOB , \$DOC , \$DOD ;
  RAM64M #(
    .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
    .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ),
    .WCLK(WCLK), .WE(WE),
    .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
    .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
  );
  \$__ABC9_LUT6 doa (.A(\$DOA ), .S(ADDRA), .Y(DOA));
  \$__ABC9_LUT6 dob (.A(\$DOB ), .S(ADDRB), .Y(DOB));
  \$__ABC9_LUT6 doc (.A(\$DOC ), .S(ADDRC), .Y(DOC));
  \$__ABC9_LUT6 dod (.A(\$DOD ), .S(ADDRD), .Y(DOD));
endmodule

module SRL16E (
  output Q,
  (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D
);
  parameter [15:0] INIT = 16'h0000;
  parameter [0:0] IS_CLK_INVERTED = 1'b0;
  wire \$Q ;
  SRL16E #(
    .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .Q(\$Q ),
    .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
  );
  \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
endmodule

module SRLC32E (
  output Q,
  output Q31,
  (* techmap_autopurge *) input [4:0] A,
  (* techmap_autopurge *) input CE, CLK, D
);
  parameter [31:0] INIT = 32'h00000000;
  parameter [0:0] IS_CLK_INVERTED = 1'b0;
  wire \$Q ;
  SRLC32E #(
    .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
  ) _TECHMAP_REPLACE_ (
    .Q(\$Q ), .Q31(Q31),
    .A(A), .CE(CE), .CLK(CLK), .D(D)
  );
  \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q));
endmodule

module DSP48E1 (
    (* techmap_autopurge *) output [29:0] ACOUT,
    (* techmap_autopurge *) output [17:0] BCOUT,
    (* techmap_autopurge *) output reg CARRYCASCOUT,
    (* techmap_autopurge *) output reg [3:0] CARRYOUT,
    (* techmap_autopurge *) output reg MULTSIGNOUT,
    (* techmap_autopurge *) output OVERFLOW,
    (* techmap_autopurge *) output reg signed [47:0] P,
    (* techmap_autopurge *) output PATTERNBDETECT,
    (* techmap_autopurge *) output PATTERNDETECT,
    (* techmap_autopurge *) output [47:0] PCOUT,
    (* techmap_autopurge *) output UNDERFLOW,
    (* techmap_autopurge *) input signed [29:0] A,
    (* techmap_autopurge *) input [29:0] ACIN,
    (* techmap_autopurge *) input [3:0] ALUMODE,
    (* techmap_autopurge *) input signed [17:0] B,
    (* techmap_autopurge *) input [17:0] BCIN,
    (* techmap_autopurge *) input [47:0] C,
    (* techmap_autopurge *) input CARRYCASCIN,
    (* techmap_autopurge *) input CARRYIN,
    (* techmap_autopurge *) input [2:0] CARRYINSEL,
    (* techmap_autopurge *) input CEA1,
    (* techmap_autopurge *) input CEA2,
    (* techmap_autopurge *) input CEAD,
    (* techmap_autopurge *) input CEALUMODE,
    (* techmap_autopurge *) input CEB1,
    (* techmap_autopurge *) input CEB2,
    (* techmap_autopurge *) input CEC,
    (* techmap_autopurge *) input CECARRYIN,
    (* techmap_autopurge *) input CECTRL,
    (* techmap_autopurge *) input CED,
    (* techmap_autopurge *) input CEINMODE,
    (* techmap_autopurge *) input CEM,
    (* techmap_autopurge *) input CEP,
    (* techmap_autopurge *) input CLK,
    (* techmap_autopurge *) input [24:0] D,
    (* techmap_autopurge *) input [4:0] INMODE,
    (* techmap_autopurge *) input MULTSIGNIN,
    (* techmap_autopurge *) input [6:0] OPMODE,
    (* techmap_autopurge *) input [47:0] PCIN,
    (* techmap_autopurge *) input RSTA,
    (* techmap_autopurge *) input RSTALLCARRYIN,
    (* techmap_autopurge *) input RSTALUMODE,
    (* techmap_autopurge *) input RSTB,
    (* techmap_autopurge *) input RSTC,
    (* techmap_autopurge *) input RSTCTRL,
    (* techmap_autopurge *) input RSTD,
    (* techmap_autopurge *) input RSTINMODE,
    (* techmap_autopurge *) input RSTM,
    (* techmap_autopurge *) 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;

    parameter _TECHMAP_CELLTYPE_ = "";
    localparam techmap_guard = (_TECHMAP_CELLTYPE_ != "");

`define DSP48E1_INST(__CELL__) """
__CELL__ #(
            .ACASCREG(ACASCREG),
            .ADREG(ADREG),
            .ALUMODEREG(ALUMODEREG),
            .AREG(AREG),
            .AUTORESET_PATDET(AUTORESET_PATDET),
            .A_INPUT(A_INPUT),
            .BCASCREG(BCASCREG),
            .BREG(BREG),
            .B_INPUT(B_INPUT),
            .CARRYINREG(CARRYINREG),
            .CARRYINSELREG(CARRYINSELREG),
            .CREG(CREG),
            .DREG(DREG),
            .INMODEREG(INMODEREG),
            .MREG(MREG),
            .OPMODEREG(OPMODEREG),
            .PREG(PREG),
            .SEL_MASK(SEL_MASK),
            .SEL_PATTERN(SEL_PATTERN),
            .USE_DPORT(USE_DPORT),
            .USE_MULT(USE_MULT),
            .USE_PATTERN_DETECT(USE_PATTERN_DETECT),
            .USE_SIMD(USE_SIMD),
            .MASK(MASK),
            .PATTERN(PATTERN),
            .IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
            .IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
            .IS_CLK_INVERTED(IS_CLK_INVERTED),
            .IS_INMODE_INVERTED(IS_INMODE_INVERTED),
            .IS_OPMODE_INVERTED(IS_OPMODE_INVERTED)
        ) _TECHMAP_REPLACE_ (
            .ACOUT(ACOUT),
            .BCOUT(BCOUT),
            .CARRYCASCOUT(CARRYCASCOUT),
            .CARRYOUT(CARRYOUT),
            .MULTSIGNOUT(MULTSIGNOUT),
            .OVERFLOW(OVERFLOW),
            .P(oP),
            .PATTERNBDETECT(PATTERNBDETECT),
            .PATTERNDETECT(PATTERNDETECT),
            .PCOUT(oPCOUT),
            .UNDERFLOW(UNDERFLOW),
            .A(iA),
            .ACIN(ACIN),
            .ALUMODE(ALUMODE),
            .B(iB),
            .BCIN(BCIN),
            .C(iC),
            .CARRYCASCIN(CARRYCASCIN),
            .CARRYIN(CARRYIN),
            .CARRYINSEL(CARRYINSEL),
            .CEA1(CEA1),
            .CEA2(CEA2),
            .CEAD(CEAD),
            .CEALUMODE(CEALUMODE),
            .CEB1(CEB1),
            .CEB2(CEB2),
            .CEC(CEC),
            .CECARRYIN(CECARRYIN),
            .CECTRL(CECTRL),
            .CED(CED),
            .CEINMODE(CEINMODE),
            .CEM(CEM),
            .CEP(CEP),
            .CLK(CLK),
            .D(iD),
            .INMODE(INMODE),
            .MULTSIGNIN(MULTSIGNIN),
            .OPMODE(OPMODE),
            .PCIN(PCIN),
            .RSTA(RSTA),
            .RSTALLCARRYIN(RSTALLCARRYIN),
            .RSTALUMODE(RSTALUMODE),
            .RSTB(RSTB),
            .RSTC(RSTC),
            .RSTCTRL(RSTCTRL),
            .RSTD(RSTD),
            .RSTINMODE(RSTINMODE),
            .RSTM(RSTM),
            .RSTP(RSTP)
        );
"""

    wire [29:0] iA;
    wire [17:0] iB;
    wire [47:0] iC;
    wire [24:0] iD;

    wire pA, pB, pC, pD, pAD, pM, pP;
    wire [47:0] oP, mP;
    wire [47:0] oPCOUT, mPCOUT;

    generate
    if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
        // Disconnect the A-input if MREG is enabled, since
        //   combinatorial path is broken
        if (AREG == 0 && MREG == 0 && PREG == 0)
            assign iA = A, pA = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
        if (BREG == 0 && MREG == 0 && PREG == 0)
            assign iB = B, pB = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
        if (CREG == 0 && PREG == 0)
            assign iC = C, pC = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
        if (DREG == 0)
            assign iD = D;
        else if (techmap_guard)
        $error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
        assign pD = 1'bx;
        if (ADREG == 1 && techmap_guard)
            $error("Invalid DSP48E1 configuration: ADREG enabled but USE_DPORT == \"FALSE\"");
        assign pAD = 1'bx;
    if (PREG == 0) begin
        if (MREG == 1)
        \$__ABC9_REG rM (.Q(pM));
        else
        assign pM = 1'bx;
        assign pP = 1'bx;
    end else begin
            assign pM = 1'bx;
            \$__ABC9_REG rP (.Q(pP));
        end

        if (MREG == 0 && PREG == 0)
            assign mP = oP, mPCOUT = oPCOUT;
        else
            assign mP = 1'bx, mPCOUT = 1'bx;
        \$__ABC9_DSP48E1_MULT_P_MUX muxP (
            .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
        );
        \$__ABC9_DSP48E1_MULT_PCOUT_MUX muxPCOUT (
            .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
        );

        `DSP48E1_INST(\$__ABC9_DSP48E1_MULT )
    end
    else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
        // Disconnect the A-input if MREG is enabled, since
        //   combinatorial path is broken
        if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0)
            assign iA = A, pA = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
        if (BREG == 0 && MREG == 0 && PREG == 0)
            assign iB = B, pB = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
        if (CREG == 0 && PREG == 0)
            assign iC = C, pC = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
        if (DREG == 0 && ADREG == 0)
            assign iD = D, pD = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD));
        if (PREG == 0) begin
            if (MREG == 1) begin
                assign pAD = 1'bx;
        \$__ABC9_REG rM (.Q(pM));
            end else begin
                if (ADREG == 1)
                    \$__ABC9_REG rAD (.Q(pAD));
                else
                    assign pAD = 1'bx;
        assign pM = 1'bx;
        end
        assign pP = 1'bx;
    end else begin
            assign pAD = 1'bx, pM = 1'bx;
            \$__ABC9_REG rP (.Q(pP));
        end

        if (MREG == 0 && PREG == 0)
            assign mP = oP, mPCOUT = oPCOUT;
        else
            assign mP = 1'bx, mPCOUT = 1'bx;
        \$__ABC9_DSP48E1_MULT_DPORT_P_MUX muxP (
            .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
        );
        \$__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT (
            .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
        );

        `DSP48E1_INST(\$__ABC9_DSP48E1_MULT_DPORT )
    end
    else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
        // Disconnect the A-input if MREG is enabled, since
        //   combinatorial path is broken
        if (AREG == 0 && PREG == 0)
            assign iA = A, pA = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
        if (BREG == 0 && PREG == 0)
            assign iB = B, pB = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
        if (CREG == 0 && PREG == 0)
            assign iC = C, pC = 1'bx;
        else
            \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
        if (DREG == 1 && techmap_guard)
            $error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
        assign pD = 1'bx;
        if (ADREG == 1 && techmap_guard)
            $error("Invalid DSP48E1 configuration: ADREG enabled but USE_DPORT == \"FALSE\"");
        assign pAD = 1'bx;
        if (MREG == 1 && techmap_guard)
            $error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\"");
        assign pM = 1'bx;
        if (PREG == 1)
            \$__ABC9_REG rP (.Q(pP));
        else
            assign pP = 1'bx;

        if (MREG == 0 && PREG == 0)
            assign mP = oP, mPCOUT = oPCOUT;
        else
            assign mP = 1'bx, mPCOUT = 1'bx;
        \$__ABC9_DSP48E1_P_MUX muxP (
            .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
        );
        \$__ABC9_DSP48E1_PCOUT_MUX muxPCOUT (
            .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
        );

        `DSP48E1_INST(\$__ABC9_DSP48E1 )
    end
    else
        $error("Invalid DSP48E1 configuration");
    endgenerate
    `undef DSP48E1_INST
endmodule