//
// Copyright 2015 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//

`timescale  1 ps / 1 ps

//
// Implements acc=((a+d)*b)+c or acc=((a+d)*b)+acc'
//

module add_then_mac
  #(parameter DEVICE = "VIRTEX6")
    (
     // Output ports
     output [47:0] acc,

     // Input ports
     input carryin,
     input ce,
     input clk,
     input [17:0] b,
     input load,
     input [47:0] c,
     input [17:0] a,
     input [17:0] d,
     input rst
     );


   wire [24:0] a_in;
   wire [24:0] d_in;

   localparam  AREG_IN = 1;
   localparam  BREG_IN = 1;
   localparam  MREG_IN = 1;
   localparam  PREG_IN = 1;
   localparam  A1REG_IN = 1;
   localparam  A0REG_IN = 0;
   localparam  B1REG_IN = 1;
   localparam  B0REG_IN = 1;

   // Sign extend inputs
   assign      a_in = (a[17] == 1'b1) ? {7'h7f, a} : {7'h00, a};
   assign      d_in = (d[17] == 1'b1) ? {7'h7f, d} : {7'h00, d};

   generate
      case(DEVICE)
	// begin generate virtex6
	"VIRTEX6", "7SERIES" :
	  begin
	     DSP48E1 #(
		       .ACASCREG(AREG_IN),
		       .AREG(AREG_IN),
		       .BCASCREG(BREG_IN),
		       .BREG(BREG_IN),
		       .MREG(MREG_IN),
		       .PREG(PREG_IN),
		       .USE_DPORT("TRUE")
		       )
	       DSP48E_BL (
			  .ACOUT(),
			  .BCOUT(),
			  .CARRYCASCOUT(),
			  .CARRYOUT(),
			  .MULTSIGNOUT(),
			  .OVERFLOW(),
			  .P(acc),
			  .PATTERNBDETECT(),
			  .PATTERNDETECT(),
			  .PCOUT(),
			  .UNDERFLOW(),
			  .A({5'b0, a_in[24:0]}),
			  .ACIN(30'b0),
			  .ALUMODE(4'b0000),
			  .B(b[17:0]),
			  .BCIN(18'b0),
			  .C(c),
			  .CARRYCASCIN(1'b0),
			  .CARRYIN(carryin),
			  .CARRYINSEL(3'b0),
			  .CEA1(1'b0),
			  .CEA2(ce),
			  .CEAD(ce),
			  .CEALUMODE(ce),
			  .CEB1(1'b0),
			  .CEB2(ce),
			  .CEC(ce),
			  .CECARRYIN(ce),
			  .CECTRL(ce),
			  .CED(ce),
			  .CEINMODE(ce),
			  .CEM(ce),
			  .CEP(ce),
			  .CLK(clk),
			  .D(d_in[24:0]),
			  .INMODE(5'b00100),
			  .MULTSIGNIN(1'b0),
			  .OPMODE({2'b01,load,4'b0101}),
			  .PCIN(48'b0),
			  .RSTA(rst),
			  .RSTALLCARRYIN(rst),
			  .RSTALUMODE(rst),
			  .RSTB(rst),
			  .RSTC(rst),
			  .RSTCTRL(rst),
			  .RSTD(rst),
			  .RSTINMODE(rst),
			  .RSTM(rst),
			  .RSTP(rst)
			  );
	  end // end generate virtex6
	// begin generate spartan6
	"SPARTAN6" :
	  begin
	     // DSP48A1 has 18b+18b=18b pre-adder, must discard LSB of A and D and compensate by shifting ACC.
	     wire discard;;
	     assign acc[0] = 1'b0;
	     
	     DSP48A1 #(
		       .A0REG(A0REG_IN),
		       .A1REG(A1REG_IN),
		       .B0REG(B0REG_IN),
		       .B1REG(B1REG_IN),
		       .MREG(MREG_IN),
		       .PREG(PREG_IN)
		       )
	       DSP48AST (
			 .BCOUT(),
			 .CARRYOUT(),
			 .CARRYOUTF(),
			 .M(),
			 .P({discard,acc[47:1]}),
			 .PCOUT(),
			 .A(b[17:0]),
			 .B({a_in[17],a_in[17:1]}),
			 .C(c),
			 .CARRYIN(carryin),
			 .CEA(ce),
			 .CEB(ce),
			 .CEC(ce),
			 .CECARRYIN(ce),
			 .CED(ce),
			 .CEM(ce),
			 .CEOPMODE(ce),
			 .CEP(ce),
			 .CLK(clk),
			 .D({d_in[17],d_in[17:1]}),
			 .OPMODE({5'b00011,load, 2'b01}),
			 .PCIN(48'b0),
			 .RSTA(rst),
			 .RSTB(rst),
			 .RSTC(rst),
			 .RSTCARRYIN(rst),
			 .RSTD(rst),
			 .RSTM(rst),
			 .RSTOPMODE(rst),
			 .RSTP(rst)
			 );
	  end // end generate spartan6
      endcase
   endgenerate
endmodule
