Merge pull request #1569 from YosysHQ/eddie/fix_1531
[yosys.git] / techlibs / xilinx / abc9_map.v
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * 2019 Eddie Hung <eddie@fpgeh.com>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 // ============================================================================
22
23 module RAM32X1D (
24 output DPO, SPO,
25 (* techmap_autopurge *) input D,
26 (* techmap_autopurge *) input WCLK,
27 (* techmap_autopurge *) input WE,
28 (* techmap_autopurge *) input A0, A1, A2, A3, A4,
29 (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
30 );
31 parameter INIT = 32'h0;
32 parameter IS_WCLK_INVERTED = 1'b0;
33 wire \$DPO , \$SPO ;
34 RAM32X1D #(
35 .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
36 ) _TECHMAP_REPLACE_ (
37 .DPO(\$DPO ), .SPO(\$SPO ),
38 .D(D), .WCLK(WCLK), .WE(WE),
39 .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
40 .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
41 );
42 \$__ABC9_LUT6 spo (.A(\$SPO ), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO));
43 \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
44 endmodule
45
46 module RAM64X1D (
47 output DPO, SPO,
48 (* techmap_autopurge *) input D,
49 (* techmap_autopurge *) input WCLK,
50 (* techmap_autopurge *) input WE,
51 (* techmap_autopurge *) input A0, A1, A2, A3, A4, A5,
52 (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
53 );
54 parameter INIT = 64'h0;
55 parameter IS_WCLK_INVERTED = 1'b0;
56 wire \$DPO , \$SPO ;
57 RAM64X1D #(
58 .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
59 ) _TECHMAP_REPLACE_ (
60 .DPO(\$DPO ), .SPO(\$SPO ),
61 .D(D), .WCLK(WCLK), .WE(WE),
62 .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
63 .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
64 );
65 \$__ABC9_LUT6 spo (.A(\$SPO ), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO));
66 \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
67 endmodule
68
69 module RAM128X1D (
70 output DPO, SPO,
71 (* techmap_autopurge *) input D,
72 (* techmap_autopurge *) input WCLK,
73 (* techmap_autopurge *) input WE,
74 (* techmap_autopurge *) input [6:0] A, DPRA
75 );
76 parameter INIT = 128'h0;
77 parameter IS_WCLK_INVERTED = 1'b0;
78 wire \$DPO , \$SPO ;
79 RAM128X1D #(
80 .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
81 ) _TECHMAP_REPLACE_ (
82 .DPO(\$DPO ), .SPO(\$SPO ),
83 .D(D), .WCLK(WCLK), .WE(WE),
84 .A(A),
85 .DPRA(DPRA)
86 );
87 \$__ABC9_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO));
88 \$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO));
89 endmodule
90
91 module SRL16E (
92 output Q,
93 (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D
94 );
95 parameter [15:0] INIT = 16'h0000;
96 parameter [0:0] IS_CLK_INVERTED = 1'b0;
97 wire \$Q ;
98 SRL16E #(
99 .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
100 ) _TECHMAP_REPLACE_ (
101 .Q(\$Q ),
102 .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
103 );
104 \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
105 endmodule
106
107 module SRLC32E (
108 output Q,
109 output Q31,
110 (* techmap_autopurge *) input [4:0] A,
111 (* techmap_autopurge *) input CE, CLK, D
112 );
113 parameter [31:0] INIT = 32'h00000000;
114 parameter [0:0] IS_CLK_INVERTED = 1'b0;
115 wire \$Q ;
116 SRLC32E #(
117 .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
118 ) _TECHMAP_REPLACE_ (
119 .Q(\$Q ), .Q31(Q31),
120 .A(A), .CE(CE), .CLK(CLK), .D(D)
121 );
122 \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q));
123 endmodule
124
125 module DSP48E1 (
126 (* techmap_autopurge *) output [29:0] ACOUT,
127 (* techmap_autopurge *) output [17:0] BCOUT,
128 (* techmap_autopurge *) output reg CARRYCASCOUT,
129 (* techmap_autopurge *) output reg [3:0] CARRYOUT,
130 (* techmap_autopurge *) output reg MULTSIGNOUT,
131 (* techmap_autopurge *) output OVERFLOW,
132 (* techmap_autopurge *) output reg signed [47:0] P,
133 (* techmap_autopurge *) output PATTERNBDETECT,
134 (* techmap_autopurge *) output PATTERNDETECT,
135 (* techmap_autopurge *) output [47:0] PCOUT,
136 (* techmap_autopurge *) output UNDERFLOW,
137 (* techmap_autopurge *) input signed [29:0] A,
138 (* techmap_autopurge *) input [29:0] ACIN,
139 (* techmap_autopurge *) input [3:0] ALUMODE,
140 (* techmap_autopurge *) input signed [17:0] B,
141 (* techmap_autopurge *) input [17:0] BCIN,
142 (* techmap_autopurge *) input [47:0] C,
143 (* techmap_autopurge *) input CARRYCASCIN,
144 (* techmap_autopurge *) input CARRYIN,
145 (* techmap_autopurge *) input [2:0] CARRYINSEL,
146 (* techmap_autopurge *) input CEA1,
147 (* techmap_autopurge *) input CEA2,
148 (* techmap_autopurge *) input CEAD,
149 (* techmap_autopurge *) input CEALUMODE,
150 (* techmap_autopurge *) input CEB1,
151 (* techmap_autopurge *) input CEB2,
152 (* techmap_autopurge *) input CEC,
153 (* techmap_autopurge *) input CECARRYIN,
154 (* techmap_autopurge *) input CECTRL,
155 (* techmap_autopurge *) input CED,
156 (* techmap_autopurge *) input CEINMODE,
157 (* techmap_autopurge *) input CEM,
158 (* techmap_autopurge *) input CEP,
159 (* techmap_autopurge *) input CLK,
160 (* techmap_autopurge *) input [24:0] D,
161 (* techmap_autopurge *) input [4:0] INMODE,
162 (* techmap_autopurge *) input MULTSIGNIN,
163 (* techmap_autopurge *) input [6:0] OPMODE,
164 (* techmap_autopurge *) input [47:0] PCIN,
165 (* techmap_autopurge *) input RSTA,
166 (* techmap_autopurge *) input RSTALLCARRYIN,
167 (* techmap_autopurge *) input RSTALUMODE,
168 (* techmap_autopurge *) input RSTB,
169 (* techmap_autopurge *) input RSTC,
170 (* techmap_autopurge *) input RSTCTRL,
171 (* techmap_autopurge *) input RSTD,
172 (* techmap_autopurge *) input RSTINMODE,
173 (* techmap_autopurge *) input RSTM,
174 (* techmap_autopurge *) input RSTP
175 );
176 parameter integer ACASCREG = 1;
177 parameter integer ADREG = 1;
178 parameter integer ALUMODEREG = 1;
179 parameter integer AREG = 1;
180 parameter AUTORESET_PATDET = "NO_RESET";
181 parameter A_INPUT = "DIRECT";
182 parameter integer BCASCREG = 1;
183 parameter integer BREG = 1;
184 parameter B_INPUT = "DIRECT";
185 parameter integer CARRYINREG = 1;
186 parameter integer CARRYINSELREG = 1;
187 parameter integer CREG = 1;
188 parameter integer DREG = 1;
189 parameter integer INMODEREG = 1;
190 parameter integer MREG = 1;
191 parameter integer OPMODEREG = 1;
192 parameter integer PREG = 1;
193 parameter SEL_MASK = "MASK";
194 parameter SEL_PATTERN = "PATTERN";
195 parameter USE_DPORT = "FALSE";
196 parameter USE_MULT = "MULTIPLY";
197 parameter USE_PATTERN_DETECT = "NO_PATDET";
198 parameter USE_SIMD = "ONE48";
199 parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
200 parameter [47:0] PATTERN = 48'h000000000000;
201 parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
202 parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
203 parameter [0:0] IS_CLK_INVERTED = 1'b0;
204 parameter [4:0] IS_INMODE_INVERTED = 5'b0;
205 parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
206
207 parameter _TECHMAP_CELLTYPE_ = "";
208 localparam techmap_guard = (_TECHMAP_CELLTYPE_ != "");
209
210 `define DSP48E1_INST(__CELL__) """
211 __CELL__ #(
212 .ACASCREG(ACASCREG),
213 .ADREG(ADREG),
214 .ALUMODEREG(ALUMODEREG),
215 .AREG(AREG),
216 .AUTORESET_PATDET(AUTORESET_PATDET),
217 .A_INPUT(A_INPUT),
218 .BCASCREG(BCASCREG),
219 .BREG(BREG),
220 .B_INPUT(B_INPUT),
221 .CARRYINREG(CARRYINREG),
222 .CARRYINSELREG(CARRYINSELREG),
223 .CREG(CREG),
224 .DREG(DREG),
225 .INMODEREG(INMODEREG),
226 .MREG(MREG),
227 .OPMODEREG(OPMODEREG),
228 .PREG(PREG),
229 .SEL_MASK(SEL_MASK),
230 .SEL_PATTERN(SEL_PATTERN),
231 .USE_DPORT(USE_DPORT),
232 .USE_MULT(USE_MULT),
233 .USE_PATTERN_DETECT(USE_PATTERN_DETECT),
234 .USE_SIMD(USE_SIMD),
235 .MASK(MASK),
236 .PATTERN(PATTERN),
237 .IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED),
238 .IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED),
239 .IS_CLK_INVERTED(IS_CLK_INVERTED),
240 .IS_INMODE_INVERTED(IS_INMODE_INVERTED),
241 .IS_OPMODE_INVERTED(IS_OPMODE_INVERTED)
242 ) _TECHMAP_REPLACE_ (
243 .ACOUT(ACOUT),
244 .BCOUT(BCOUT),
245 .CARRYCASCOUT(CARRYCASCOUT),
246 .CARRYOUT(CARRYOUT),
247 .MULTSIGNOUT(MULTSIGNOUT),
248 .OVERFLOW(OVERFLOW),
249 .P(oP),
250 .PATTERNBDETECT(PATTERNBDETECT),
251 .PATTERNDETECT(PATTERNDETECT),
252 .PCOUT(oPCOUT),
253 .UNDERFLOW(UNDERFLOW),
254 .A(iA),
255 .ACIN(ACIN),
256 .ALUMODE(ALUMODE),
257 .B(iB),
258 .BCIN(BCIN),
259 .C(iC),
260 .CARRYCASCIN(CARRYCASCIN),
261 .CARRYIN(CARRYIN),
262 .CARRYINSEL(CARRYINSEL),
263 .CEA1(CEA1),
264 .CEA2(CEA2),
265 .CEAD(CEAD),
266 .CEALUMODE(CEALUMODE),
267 .CEB1(CEB1),
268 .CEB2(CEB2),
269 .CEC(CEC),
270 .CECARRYIN(CECARRYIN),
271 .CECTRL(CECTRL),
272 .CED(CED),
273 .CEINMODE(CEINMODE),
274 .CEM(CEM),
275 .CEP(CEP),
276 .CLK(CLK),
277 .D(iD),
278 .INMODE(INMODE),
279 .MULTSIGNIN(MULTSIGNIN),
280 .OPMODE(OPMODE),
281 .PCIN(PCIN),
282 .RSTA(RSTA),
283 .RSTALLCARRYIN(RSTALLCARRYIN),
284 .RSTALUMODE(RSTALUMODE),
285 .RSTB(RSTB),
286 .RSTC(RSTC),
287 .RSTCTRL(RSTCTRL),
288 .RSTD(RSTD),
289 .RSTINMODE(RSTINMODE),
290 .RSTM(RSTM),
291 .RSTP(RSTP)
292 );
293 """
294
295 wire [29:0] iA;
296 wire [17:0] iB;
297 wire [47:0] iC;
298 wire [24:0] iD;
299
300 wire pA, pB, pC, pD, pAD, pM, pP;
301 wire [47:0] oP, mP;
302 wire [47:0] oPCOUT, mPCOUT;
303
304 generate
305 if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
306 // Disconnect the A-input if MREG is enabled, since
307 // combinatorial path is broken
308 if (AREG == 0 && MREG == 0 && PREG == 0)
309 assign iA = A, pA = 1'bx;
310 else
311 \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
312 if (BREG == 0 && MREG == 0 && PREG == 0)
313 assign iB = B, pB = 1'bx;
314 else
315 \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
316 if (CREG == 0 && PREG == 0)
317 assign iC = C, pC = 1'bx;
318 else
319 \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
320 if (DREG == 0)
321 assign iD = D;
322 else if (techmap_guard)
323 $error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
324 assign pD = 1'bx;
325 if (ADREG == 1 && techmap_guard)
326 $error("Invalid DSP48E1 configuration: ADREG enabled but USE_DPORT == \"FALSE\"");
327 assign pAD = 1'bx;
328 if (PREG == 0) begin
329 if (MREG == 1)
330 \$__ABC9_REG rM (.Q(pM));
331 else
332 assign pM = 1'bx;
333 assign pP = 1'bx;
334 end else begin
335 assign pM = 1'bx;
336 \$__ABC9_REG rP (.Q(pP));
337 end
338
339 if (MREG == 0 && PREG == 0)
340 assign mP = oP, mPCOUT = oPCOUT;
341 else
342 assign mP = 1'bx, mPCOUT = 1'bx;
343 \$__ABC9_DSP48E1_MULT_P_MUX muxP (
344 .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
345 );
346 \$__ABC9_DSP48E1_MULT_PCOUT_MUX muxPCOUT (
347 .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
348 );
349
350 `DSP48E1_INST(\$__ABC9_DSP48E1_MULT )
351 end
352 else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
353 // Disconnect the A-input if MREG is enabled, since
354 // combinatorial path is broken
355 if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0)
356 assign iA = A, pA = 1'bx;
357 else
358 \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
359 if (BREG == 0 && MREG == 0 && PREG == 0)
360 assign iB = B, pB = 1'bx;
361 else
362 \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
363 if (CREG == 0 && PREG == 0)
364 assign iC = C, pC = 1'bx;
365 else
366 \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
367 if (DREG == 0 && ADREG == 0)
368 assign iD = D, pD = 1'bx;
369 else
370 \$__ABC9_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD));
371 if (PREG == 0) begin
372 if (MREG == 1) begin
373 assign pAD = 1'bx;
374 \$__ABC9_REG rM (.Q(pM));
375 end else begin
376 if (ADREG == 1)
377 \$__ABC9_REG rAD (.Q(pAD));
378 else
379 assign pAD = 1'bx;
380 assign pM = 1'bx;
381 end
382 assign pP = 1'bx;
383 end else begin
384 assign pAD = 1'bx, pM = 1'bx;
385 \$__ABC9_REG rP (.Q(pP));
386 end
387
388 if (MREG == 0 && PREG == 0)
389 assign mP = oP, mPCOUT = oPCOUT;
390 else
391 assign mP = 1'bx, mPCOUT = 1'bx;
392 \$__ABC9_DSP48E1_MULT_DPORT_P_MUX muxP (
393 .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
394 );
395 \$__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT (
396 .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
397 );
398
399 `DSP48E1_INST(\$__ABC9_DSP48E1_MULT_DPORT )
400 end
401 else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
402 // Disconnect the A-input if MREG is enabled, since
403 // combinatorial path is broken
404 if (AREG == 0 && PREG == 0)
405 assign iA = A, pA = 1'bx;
406 else
407 \$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
408 if (BREG == 0 && PREG == 0)
409 assign iB = B, pB = 1'bx;
410 else
411 \$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
412 if (CREG == 0 && PREG == 0)
413 assign iC = C, pC = 1'bx;
414 else
415 \$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
416 if (DREG == 1 && techmap_guard)
417 $error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
418 assign pD = 1'bx;
419 if (ADREG == 1 && techmap_guard)
420 $error("Invalid DSP48E1 configuration: ADREG enabled but USE_DPORT == \"FALSE\"");
421 assign pAD = 1'bx;
422 if (MREG == 1 && techmap_guard)
423 $error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\"");
424 assign pM = 1'bx;
425 if (PREG == 1)
426 \$__ABC9_REG rP (.Q(pP));
427 else
428 assign pP = 1'bx;
429
430 if (MREG == 0 && PREG == 0)
431 assign mP = oP, mPCOUT = oPCOUT;
432 else
433 assign mP = 1'bx, mPCOUT = 1'bx;
434 \$__ABC9_DSP48E1_P_MUX muxP (
435 .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
436 );
437 \$__ABC9_DSP48E1_PCOUT_MUX muxPCOUT (
438 .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
439 );
440
441 `DSP48E1_INST(\$__ABC9_DSP48E1 )
442 end
443 else
444 $error("Invalid DSP48E1 configuration");
445 endgenerate
446 `undef DSP48E1_INST
447 endmodule