1//
2// Copyright 2015 Ettus Research, a National Instruments Company
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6
7`timescale  1 ps / 1 ps
8
9//
10// Implements acc=((a+d)*b)+c or acc=((a+d)*b)+acc'
11//
12
13module add_then_mac
14  #(parameter DEVICE = "VIRTEX6")
15    (
16     // Output ports
17     output [47:0] acc,
18
19     // Input ports
20     input carryin,
21     input ce,
22     input clk,
23     input [17:0] b,
24     input load,
25     input [47:0] c,
26     input [17:0] a,
27     input [17:0] d,
28     input rst
29     );
30
31
32   wire [24:0] a_in;
33   wire [24:0] d_in;
34
35   localparam  AREG_IN = 1;
36   localparam  BREG_IN = 1;
37   localparam  MREG_IN = 1;
38   localparam  PREG_IN = 1;
39   localparam  A1REG_IN = 1;
40   localparam  A0REG_IN = 0;
41   localparam  B1REG_IN = 1;
42   localparam  B0REG_IN = 1;
43
44   // Sign extend inputs
45   assign      a_in = (a[17] == 1'b1) ? {7'hff, a} : {7'h00, a};
46   assign      d_in = (d[17] == 1'b1) ? {7'hff, d} : {7'h00, d};
47
48   generate
49      case(DEVICE)
50	// begin generate virtex6
51	"VIRTEX6", "7SERIES" :
52	  begin
53	     DSP48E1 #(
54		       .ACASCREG(AREG_IN),
55		       .AREG(AREG_IN),
56		       .BCASCREG(BREG_IN),
57		       .BREG(BREG_IN),
58		       .MREG(MREG_IN),
59		       .PREG(PREG_IN),
60		       .USE_DPORT("TRUE")
61		       )
62	       DSP48E_BL (
63			  .ACOUT(),
64			  .BCOUT(),
65			  .CARRYCASCOUT(),
66			  .CARRYOUT(),
67			  .MULTSIGNOUT(),
68			  .OVERFLOW(),
69			  .P(acc),
70			  .PATTERNBDETECT(),
71			  .PATTERNDETECT(),
72			  .PCOUT(),
73			  .UNDERFLOW(),
74			  .A({5'b0, a_in[24:0]}),
75			  .ACIN(30'b0),
76			  .ALUMODE(4'b0000),
77			  .B(b[17:0]),
78			  .BCIN(18'b0),
79			  .C(c),
80			  .CARRYCASCIN(1'b0),
81			  .CARRYIN(carryin),
82			  .CARRYINSEL(3'b0),
83			  .CEA1(1'b0),
84			  .CEA2(ce),
85			  .CEAD(ce),
86			  .CEALUMODE(ce),
87			  .CEB1(1'b0),
88			  .CEB2(ce),
89			  .CEC(ce),
90			  .CECARRYIN(ce),
91			  .CECTRL(ce),
92			  .CED(ce),
93			  .CEINMODE(ce),
94			  .CEM(ce),
95			  .CEP(ce),
96			  .CLK(clk),
97			  .D(d_in[24:0]),
98			  .INMODE(5'b00100),
99			  .MULTSIGNIN(1'b0),
100			  .OPMODE({2'b01,load,4'b0101}),
101			  .PCIN(48'b0),
102			  .RSTA(rst),
103			  .RSTALLCARRYIN(rst),
104			  .RSTALUMODE(rst),
105			  .RSTB(rst),
106			  .RSTC(rst),
107			  .RSTCTRL(rst),
108			  .RSTD(rst),
109			  .RSTINMODE(rst),
110			  .RSTM(rst),
111			  .RSTP(rst)
112			  );
113	  end // end generate virtex6
114	// begin generate spartan6
115	"SPARTAN6" :
116	  begin
117	     // DSP48A1 has 18b+18b=18b pre-adder, must discard LSB of A and D and compensate by shifting ACC.
118	     wire discard;;
119	     assign acc[0] = 1'b0;
120
121	     DSP48A1 #(
122		       .A0REG(A0REG_IN),
123		       .A1REG(A1REG_IN),
124		       .B0REG(B0REG_IN),
125		       .B1REG(B1REG_IN),
126		       .MREG(MREG_IN),
127		       .PREG(PREG_IN)
128		       )
129	       DSP48AST (
130			 .BCOUT(),
131			 .CARRYOUT(),
132			 .CARRYOUTF(),
133			 .M(),
134			 .P({discard,acc[47:1]}),
135			 .PCOUT(),
136			 .A(b[17:0]),
137			 .B({a_in[17],a_in[17:1]}),
138			 .C(c),
139			 .CARRYIN(carryin),
140			 .CEA(ce),
141			 .CEB(ce),
142			 .CEC(ce),
143			 .CECARRYIN(ce),
144			 .CED(ce),
145			 .CEM(ce),
146			 .CEOPMODE(ce),
147			 .CEP(ce),
148			 .CLK(clk),
149			 .D({d_in[17],d_in[17:1]}),
150			 .OPMODE({5'b00011,load, 2'b01}),
151			 .PCIN(48'b0),
152			 .RSTA(rst),
153			 .RSTB(rst),
154			 .RSTC(rst),
155			 .RSTCARRYIN(rst),
156			 .RSTD(rst),
157			 .RSTM(rst),
158			 .RSTOPMODE(rst),
159			 .RSTP(rst)
160			 );
161	  end // end generate spartan6
162      endcase
163   endgenerate
164endmodule
165