Merge remote-tracking branch 'origin/master' into xc7dsp
[yosys.git] / techlibs / xilinx / cells_sim.v
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 // See Xilinx UG953 and UG474 for a description of the cell types below.
21 // http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
22 // http://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_4/ug953-vivado-7series-libraries.pdf
23
24 module VCC(output P);
25 assign P = 1;
26 endmodule
27
28 module GND(output G);
29 assign G = 0;
30 endmodule
31
32 module IBUF(
33 output O,
34 (* iopad_external_pin *)
35 input I);
36 parameter IOSTANDARD = "default";
37 parameter IBUF_LOW_PWR = 0;
38 assign O = I;
39 endmodule
40
41 module OBUF(
42 (* iopad_external_pin *)
43 output O,
44 input I);
45 parameter IOSTANDARD = "default";
46 parameter DRIVE = 12;
47 parameter SLEW = "SLOW";
48 assign O = I;
49 endmodule
50
51 module BUFG(
52 (* clkbuf_driver *)
53 output O,
54 input I);
55
56 assign O = I;
57 endmodule
58
59 module BUFGCTRL(
60 (* clkbuf_driver *)
61 output O,
62 input I0, input I1,
63 input S0, input S1,
64 input CE0, input CE1,
65 input IGNORE0, input IGNORE1);
66
67 parameter [0:0] INIT_OUT = 1'b0;
68 parameter PRESELECT_I0 = "FALSE";
69 parameter PRESELECT_I1 = "FALSE";
70 parameter [0:0] IS_CE0_INVERTED = 1'b0;
71 parameter [0:0] IS_CE1_INVERTED = 1'b0;
72 parameter [0:0] IS_S0_INVERTED = 1'b0;
73 parameter [0:0] IS_S1_INVERTED = 1'b0;
74 parameter [0:0] IS_IGNORE0_INVERTED = 1'b0;
75 parameter [0:0] IS_IGNORE1_INVERTED = 1'b0;
76
77 wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT);
78 wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT);
79 wire S0_true = (S0 ^ IS_S0_INVERTED);
80 wire S1_true = (S1 ^ IS_S1_INVERTED);
81
82 assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT);
83
84 endmodule
85
86 module BUFHCE(
87 (* clkbuf_driver *)
88 output O,
89 input I,
90 input CE);
91
92 parameter [0:0] INIT_OUT = 1'b0;
93 parameter CE_TYPE = "SYNC";
94 parameter [0:0] IS_CE_INVERTED = 1'b0;
95
96 assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT);
97
98 endmodule
99
100 // module OBUFT(output O, input I, T);
101 // assign O = T ? 1'bz : I;
102 // endmodule
103
104 // module IOBUF(inout IO, output O, input I, T);
105 // assign O = IO, IO = T ? 1'bz : I;
106 // endmodule
107
108 module INV(output O, input I);
109 assign O = !I;
110 endmodule
111
112 module LUT1(output O, input I0);
113 parameter [1:0] INIT = 0;
114 assign O = I0 ? INIT[1] : INIT[0];
115 endmodule
116
117 module LUT2(output O, input I0, I1);
118 parameter [3:0] INIT = 0;
119 wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
120 assign O = I0 ? s1[1] : s1[0];
121 endmodule
122
123 module LUT3(output O, input I0, I1, I2);
124 parameter [7:0] INIT = 0;
125 wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
126 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
127 assign O = I0 ? s1[1] : s1[0];
128 endmodule
129
130 module LUT4(output O, input I0, I1, I2, I3);
131 parameter [15:0] INIT = 0;
132 wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
133 wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
134 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
135 assign O = I0 ? s1[1] : s1[0];
136 endmodule
137
138 module LUT5(output O, input I0, I1, I2, I3, I4);
139 parameter [31:0] INIT = 0;
140 wire [15: 0] s4 = I4 ? INIT[31:16] : INIT[15: 0];
141 wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
142 wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
143 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
144 assign O = I0 ? s1[1] : s1[0];
145 endmodule
146
147 module LUT6(output O, input I0, I1, I2, I3, I4, I5);
148 parameter [63:0] INIT = 0;
149 wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
150 wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
151 wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
152 wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
153 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
154 assign O = I0 ? s1[1] : s1[0];
155 endmodule
156
157 module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5);
158 parameter [63:0] INIT = 0;
159 wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
160 wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
161 wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
162 wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
163 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
164 assign O6 = I0 ? s1[1] : s1[0];
165
166 wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0];
167 wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0];
168 wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0];
169 wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0];
170 assign O5 = I0 ? s5_1[1] : s5_1[0];
171 endmodule
172
173 module MUXCY(output O, input CI, DI, S);
174 assign O = S ? CI : DI;
175 endmodule
176
177 (* abc_box_id = 1, lib_whitebox *)
178 module MUXF7(output O, input I0, I1, S);
179 assign O = S ? I1 : I0;
180 endmodule
181
182 (* abc_box_id = 2, lib_whitebox *)
183 module MUXF8(output O, input I0, I1, S);
184 assign O = S ? I1 : I0;
185 endmodule
186
187 `ifdef _ABC
188 (* abc_box_id = 3, lib_whitebox *)
189 module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
190 assign O = S1 ? (S0 ? I3 : I2)
191 : (S0 ? I1 : I0);
192 endmodule
193 `endif
194
195 module XORCY(output O, input CI, LI);
196 assign O = CI ^ LI;
197 endmodule
198
199 (* abc_box_id = 4, lib_whitebox *)
200 module CARRY4(
201 (* abc_carry *)
202 output [3:0] CO,
203 output [3:0] O,
204 (* abc_carry *)
205 input CI,
206 input CYINIT,
207 input [3:0] DI, S
208 );
209 assign O = S ^ {CO[2:0], CI | CYINIT};
210 assign CO[0] = S[0] ? CI | CYINIT : DI[0];
211 assign CO[1] = S[1] ? CO[0] : DI[1];
212 assign CO[2] = S[2] ? CO[1] : DI[2];
213 assign CO[3] = S[3] ? CO[2] : DI[3];
214 endmodule
215
216 `ifdef _EXPLICIT_CARRY
217
218 module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
219 parameter CYINIT_FABRIC = 0;
220 wire CI_COMBINE;
221 if(CYINIT_FABRIC) begin
222 assign CI_COMBINE = CI_INIT;
223 end else begin
224 assign CI_COMBINE = CI;
225 end
226 assign CO_CHAIN = S ? CI_COMBINE : DI;
227 assign CO_FABRIC = S ? CI_COMBINE : DI;
228 assign O = S ^ CI_COMBINE;
229 endmodule
230
231 module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
232 assign CO_CHAIN = S ? CI : DI;
233 assign CO_FABRIC = S ? CI : DI;
234 assign O = S ^ CI;
235 endmodule
236
237 `endif
238
239 module FDRE (output reg Q, (* clkbuf_sink *) input C, input CE, D, R);
240 parameter [0:0] INIT = 1'b0;
241 parameter [0:0] IS_C_INVERTED = 1'b0;
242 parameter [0:0] IS_D_INVERTED = 1'b0;
243 parameter [0:0] IS_R_INVERTED = 1'b0;
244 initial Q <= INIT;
245 generate case (|IS_C_INVERTED)
246 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
247 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
248 endcase endgenerate
249 endmodule
250
251 module FDSE (output reg Q, (* clkbuf_sink *) input C, input CE, D, S);
252 parameter [0:0] INIT = 1'b1;
253 parameter [0:0] IS_C_INVERTED = 1'b0;
254 parameter [0:0] IS_D_INVERTED = 1'b0;
255 parameter [0:0] IS_S_INVERTED = 1'b0;
256 initial Q <= INIT;
257 generate case (|IS_C_INVERTED)
258 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
259 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
260 endcase endgenerate
261 endmodule
262
263 module FDCE (output reg Q, (* clkbuf_sink *) input C, input CE, D, CLR);
264 parameter [0:0] INIT = 1'b0;
265 parameter [0:0] IS_C_INVERTED = 1'b0;
266 parameter [0:0] IS_D_INVERTED = 1'b0;
267 parameter [0:0] IS_CLR_INVERTED = 1'b0;
268 initial Q <= INIT;
269 generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED})
270 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
271 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
272 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
273 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
274 endcase endgenerate
275 endmodule
276
277 module FDPE (output reg Q, (* clkbuf_sink *) input C, input CE, D, PRE);
278 parameter [0:0] INIT = 1'b1;
279 parameter [0:0] IS_C_INVERTED = 1'b0;
280 parameter [0:0] IS_D_INVERTED = 1'b0;
281 parameter [0:0] IS_PRE_INVERTED = 1'b0;
282 initial Q <= INIT;
283 generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
284 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
285 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
286 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
287 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
288 endcase endgenerate
289 endmodule
290
291 module FDRE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, R);
292 parameter [0:0] INIT = 1'b0;
293 initial Q <= INIT;
294 always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
295 endmodule
296
297 module FDSE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, S);
298 parameter [0:0] INIT = 1'b1;
299 initial Q <= INIT;
300 always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
301 endmodule
302
303 module FDCE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, CLR);
304 parameter [0:0] INIT = 1'b0;
305 initial Q <= INIT;
306 always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
307 endmodule
308
309 module FDPE_1 (output reg Q, (* clkbuf_sink *) input C, input CE, D, PRE);
310 parameter [0:0] INIT = 1'b1;
311 initial Q <= INIT;
312 always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
313 endmodule
314
315 (* abc_box_id = 5 *)
316 module RAM32X1D (
317 output DPO, SPO,
318 (* abc_scc_break *)
319 input D,
320 (* clkbuf_sink *)
321 input WCLK,
322 (* abc_scc_break *)
323 input WE,
324 input A0, A1, A2, A3, A4,
325 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
326 );
327 parameter INIT = 32'h0;
328 parameter IS_WCLK_INVERTED = 1'b0;
329 wire [4:0] a = {A4, A3, A2, A1, A0};
330 wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
331 reg [31:0] mem = INIT;
332 assign SPO = mem[a];
333 assign DPO = mem[dpra];
334 wire clk = WCLK ^ IS_WCLK_INVERTED;
335 always @(posedge clk) if (WE) mem[a] <= D;
336 endmodule
337
338 (* abc_box_id = 6 *)
339 module RAM64X1D (
340 output DPO, SPO,
341 (* abc_scc_break *)
342 input D,
343 (* clkbuf_sink *)
344 input WCLK,
345 (* abc_scc_break *)
346 input WE,
347 input A0, A1, A2, A3, A4, A5,
348 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
349 );
350 parameter INIT = 64'h0;
351 parameter IS_WCLK_INVERTED = 1'b0;
352 wire [5:0] a = {A5, A4, A3, A2, A1, A0};
353 wire [5:0] dpra = {DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
354 reg [63:0] mem = INIT;
355 assign SPO = mem[a];
356 assign DPO = mem[dpra];
357 wire clk = WCLK ^ IS_WCLK_INVERTED;
358 always @(posedge clk) if (WE) mem[a] <= D;
359 endmodule
360
361 (* abc_box_id = 7 *)
362 module RAM128X1D (
363 output DPO, SPO,
364 (* abc_scc_break *)
365 input D,
366 (* clkbuf_sink *)
367 input WCLK,
368 (* abc_scc_break *)
369 input WE,
370 input [6:0] A, DPRA
371 );
372 parameter INIT = 128'h0;
373 parameter IS_WCLK_INVERTED = 1'b0;
374 reg [127:0] mem = INIT;
375 assign SPO = mem[A];
376 assign DPO = mem[DPRA];
377 wire clk = WCLK ^ IS_WCLK_INVERTED;
378 always @(posedge clk) if (WE) mem[A] <= D;
379 endmodule
380
381 module SRL16E (
382 output Q,
383 input A0, A1, A2, A3, CE,
384 (* clkbuf_sink *)
385 input CLK,
386 input D
387 );
388 parameter [15:0] INIT = 16'h0000;
389 parameter [0:0] IS_CLK_INVERTED = 1'b0;
390
391 reg [15:0] r = INIT;
392 assign Q = r[{A3,A2,A1,A0}];
393 generate
394 if (IS_CLK_INVERTED) begin
395 always @(negedge CLK) if (CE) r <= { r[14:0], D };
396 end
397 else
398 always @(posedge CLK) if (CE) r <= { r[14:0], D };
399 endgenerate
400 endmodule
401
402 module SRLC16E (
403 output Q,
404 output Q15,
405 input A0, A1, A2, A3, CE,
406 (* clkbuf_sink *)
407 input CLK,
408 input D
409 );
410 parameter [15:0] INIT = 16'h0000;
411 parameter [0:0] IS_CLK_INVERTED = 1'b0;
412
413 reg [15:0] r = INIT;
414 assign Q15 = r[15];
415 assign Q = r[{A3,A2,A1,A0}];
416 generate
417 if (IS_CLK_INVERTED) begin
418 always @(negedge CLK) if (CE) r <= { r[14:0], D };
419 end
420 else
421 always @(posedge CLK) if (CE) r <= { r[14:0], D };
422 endgenerate
423 endmodule
424
425 module SRLC32E (
426 output Q,
427 output Q31,
428 input [4:0] A,
429 input CE,
430 (* clkbuf_sink *)
431 input CLK,
432 input D
433 );
434 parameter [31:0] INIT = 32'h00000000;
435 parameter [0:0] IS_CLK_INVERTED = 1'b0;
436
437 reg [31:0] r = INIT;
438 assign Q31 = r[31];
439 assign Q = r[A];
440 generate
441 if (IS_CLK_INVERTED) begin
442 always @(negedge CLK) if (CE) r <= { r[30:0], D };
443 end
444 else
445 always @(posedge CLK) if (CE) r <= { r[30:0], D };
446 endgenerate
447 endmodule
448
449 module DSP48E1 (
450 output [29:0] ACOUT,
451 output [17:0] BCOUT,
452 output reg CARRYCASCOUT,
453 output reg [3:0] CARRYOUT,
454 output reg MULTSIGNOUT,
455 output OVERFLOW,
456 output reg signed [47:0] P,
457 output PATTERNBDETECT,
458 output PATTERNDETECT,
459 output [47:0] PCOUT,
460 output UNDERFLOW,
461 input signed [29:0] A,
462 input [29:0] ACIN,
463 input [3:0] ALUMODE,
464 input signed [17:0] B,
465 input [17:0] BCIN,
466 input [47:0] C,
467 input CARRYCASCIN,
468 input CARRYIN,
469 input [2:0] CARRYINSEL,
470 input CEA1,
471 input CEA2,
472 input CEAD,
473 input CEALUMODE,
474 input CEB1,
475 input CEB2,
476 input CEC,
477 input CECARRYIN,
478 input CECTRL,
479 input CED,
480 input CEINMODE,
481 input CEM,
482 input CEP,
483 (* clkbuf_sink *) input CLK,
484 input [24:0] D,
485 input [4:0] INMODE,
486 input MULTSIGNIN,
487 input [6:0] OPMODE,
488 input [47:0] PCIN,
489 input RSTA,
490 input RSTALLCARRYIN,
491 input RSTALUMODE,
492 input RSTB,
493 input RSTC,
494 input RSTCTRL,
495 input RSTD,
496 input RSTINMODE,
497 input RSTM,
498 input RSTP
499 );
500 parameter integer ACASCREG = 1;
501 parameter integer ADREG = 1;
502 parameter integer ALUMODEREG = 1;
503 parameter integer AREG = 1;
504 parameter AUTORESET_PATDET = "NO_RESET";
505 parameter A_INPUT = "DIRECT";
506 parameter integer BCASCREG = 1;
507 parameter integer BREG = 1;
508 parameter B_INPUT = "DIRECT";
509 parameter integer CARRYINREG = 1;
510 parameter integer CARRYINSELREG = 1;
511 parameter integer CREG = 1;
512 parameter integer DREG = 1;
513 parameter integer INMODEREG = 1;
514 parameter integer MREG = 1;
515 parameter integer OPMODEREG = 1;
516 parameter integer PREG = 1;
517 parameter SEL_MASK = "MASK";
518 parameter SEL_PATTERN = "PATTERN";
519 parameter USE_DPORT = "FALSE";
520 parameter USE_MULT = "MULTIPLY";
521 parameter USE_PATTERN_DETECT = "NO_PATDET";
522 parameter USE_SIMD = "ONE48";
523 parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
524 parameter [47:0] PATTERN = 48'h000000000000;
525 parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
526 parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
527 parameter [0:0] IS_CLK_INVERTED = 1'b0;
528 parameter [4:0] IS_INMODE_INVERTED = 5'b0;
529 parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
530
531 initial begin
532 `ifdef __ICARUS__
533 if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
534 //if (PREG != 0) $fatal(1, "Unsupported PREG value");
535 if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
536 if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
537 if (USE_PATTERN_DETECT != "NO_PATDET") $fatal(1, "Unsupported USE_PATTERN_DETECT value");
538 if (USE_SIMD != "ONE48" && USE_SIMD != "TWO24" && USE_SIMD != "FOUR12") $fatal(1, "Unsupported USE_SIMD value");
539 if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value");
540 if (IS_CARRYIN_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CARRYIN_INVERTED value");
541 if (IS_CLK_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CLK_INVERTED value");
542 if (IS_INMODE_INVERTED != 5'b0) $fatal(1, "Unsupported IS_INMODE_INVERTED value");
543 if (IS_OPMODE_INVERTED != 7'b0) $fatal(1, "Unsupported IS_OPMODE_INVERTED value");
544 `endif
545 end
546
547 wire signed [29:0] A_muxed;
548 wire signed [17:0] B_muxed;
549
550 generate
551 if (A_INPUT == "CASCADE") assign A_muxed = ACIN;
552 else assign A_muxed = A;
553
554 if (B_INPUT == "CASCADE") assign B_muxed = BCIN;
555 else assign B_muxed = B;
556 endgenerate
557
558 reg signed [29:0] Ar1 = 30'b0, Ar2 = 30'b0;
559 reg signed [24:0] Dr = 25'b0;
560 reg signed [17:0] Br1 = 18'b0, Br2 = 18'b0;
561 reg signed [47:0] Cr = 48'b0;
562 reg [4:0] INMODEr = 5'b0;
563 reg [6:0] OPMODEr = 7'b0;
564 reg [3:0] ALUMODEr = 4'b0;
565 reg [2:0] CARRYINSELr = 3'b0;
566
567 generate
568 // Configurable A register
569 if (AREG == 2) begin
570 always @(posedge CLK)
571 if (RSTA) begin
572 Ar1 <= 30'b0;
573 Ar2 <= 30'b0;
574 end else begin
575 if (CEA1) Ar1 <= A_muxed;
576 if (CEA2) Ar2 <= Ar1;
577 end
578 end else if (AREG == 1) begin
579 always @(posedge CLK)
580 if (RSTA) begin
581 Ar1 <= 30'b0;
582 Ar2 <= 30'b0;
583 end else begin
584 if (CEA1) Ar1 <= A_muxed;
585 if (CEA2) Ar2 <= A_muxed;
586 end
587 end else begin
588 always @* Ar1 <= A_muxed;
589 always @* Ar2 <= A_muxed;
590 end
591
592 // Configurable B register
593 if (BREG == 2) begin
594 always @(posedge CLK)
595 if (RSTB) begin
596 Br1 <= 18'b0;
597 Br2 <= 18'b0;
598 end else begin
599 if (CEB1) Br1 <= B_muxed;
600 if (CEB2) Br2 <= Br1;
601 end
602 end else if (BREG == 1) begin
603 always @(posedge CLK)
604 if (RSTB) begin
605 Br1 <= 18'b0;
606 Br2 <= 18'b0;
607 end else begin
608 if (CEB1) Br1 <= B_muxed;
609 if (CEB2) Br2 <= B_muxed;
610 end
611 end else begin
612 always @* Br1 <= B_muxed;
613 always @* Br2 <= B_muxed;
614 end
615
616 // C and D registers
617 if (CREG == 1) begin always @(posedge CLK) if (RSTC) Cr <= 48'b0; else if (CEC) Cr <= C; end
618 else always @* Cr <= C;
619
620 if (DREG == 1) begin always @(posedge CLK) if (RSTD) Dr <= 25'b0; else if (CED) Dr <= D; end
621 else always @* Dr <= D;
622
623 // Control registers
624 if (INMODEREG == 1) begin always @(posedge CLK) if (RSTINMODE) INMODEr <= 5'b0; else if (CEINMODE) INMODEr <= INMODE; end
625 else always @* INMODEr <= INMODE;
626 if (OPMODEREG == 1) begin always @(posedge CLK) if (RSTCTRL) OPMODEr <= 7'b0; else if (CECTRL) OPMODEr <= OPMODE; end
627 else always @* OPMODEr <= OPMODE;
628 if (ALUMODEREG == 1) begin always @(posedge CLK) if (RSTALUMODE) ALUMODEr <= 4'b0; else if (CEALUMODE) ALUMODEr <= ALUMODE; end
629 else always @* ALUMODEr <= ALUMODE;
630 if (CARRYINSELREG == 1) begin always @(posedge CLK) if (RSTCTRL) CARRYINSELr <= 3'b0; else if (CECTRL) CARRYINSELr <= CARRYINSEL; end
631 else always @* CARRYINSELr <= CARRYINSEL;
632 endgenerate
633
634 // A and B cascsde
635 generate
636 if (ACASCREG == 1 && AREG == 2) assign ACOUT = Ar1;
637 else assign ACOUT = Ar2;
638 if (BCASCREG == 1 && BREG == 2) assign BCOUT = Br1;
639 else assign BCOUT = Br2;
640 endgenerate
641
642 // A/D input selection and pre-adder
643 wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2;
644 wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed;
645 wire signed [24:0] Dr_gated = INMODEr[2] ? Dr : 25'b0;
646 wire signed [24:0] AD_result = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated);
647 reg signed [24:0] ADr = 25'b0;
648
649 generate
650 if (ADREG == 1) begin always @(posedge CLK) if (RSTD) ADr <= 25'b0; else if (CEAD) ADr <= AD_result; end
651 else always @* ADr <= AD_result;
652 endgenerate
653
654 // 25x18 multiplier
655 wire signed [24:0] A_MULT;
656 wire signed [17:0] B_MULT = INMODEr[4] ? Br1 : Br2;
657 generate
658 if (USE_DPORT == "TRUE") assign A_MULT = ADr;
659 else assign A_MULT = Ar12_gated;
660 endgenerate
661
662 wire signed [42:0] M = A_MULT * B_MULT;
663 wire signed [42:0] Mx = (CARRYINSEL == 3'b010) ? 43'bx : M;
664 reg signed [42:0] Mr = 43'b0;
665
666 // Multiplier result register
667 generate
668 if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= Mx; end
669 else always @* Mr <= Mx;
670 endgenerate
671
672 wire signed [42:0] Mrx = (CARRYINSELr == 3'b010) ? 43'bx : Mr;
673
674 // X, Y and Z ALU inputs
675 reg signed [47:0] X, Y, Z;
676
677 always @* begin
678 // X multiplexer
679 case (OPMODEr[1:0])
680 2'b00: X = 48'b0;
681 2'b01: begin X = $signed(Mrx);
682 `ifdef __ICARUS__
683 if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
684 `endif
685 end
686 2'b10: begin X = P;
687 `ifdef __ICARUS__
688 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
689 `endif
690 end
691 2'b11: X = $signed({Ar2, Br2});
692 default: X = 48'bx;
693 endcase
694
695 // Y multiplexer
696 case (OPMODEr[3:2])
697 2'b00: Y = 48'b0;
698 2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
699 `ifdef __ICARUS__
700 if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
701 `endif
702 end
703 2'b10: Y = {48{1'b1}};
704 2'b11: Y = Cr;
705 default: Y = 48'bx;
706 endcase
707
708 // Z multiplexer
709 case (OPMODEr[6:4])
710 3'b000: Z = 48'b0;
711 3'b001: Z = PCIN;
712 3'b010: begin Z = P;
713 `ifdef __ICARUS__
714 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
715 `endif
716 end
717 3'b011: Z = Cr;
718 3'b100: begin Z = P;
719 `ifdef __ICARUS__
720 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
721 if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
722 `endif
723 end
724 3'b101: Z = $signed(PCIN[47:17]);
725 3'b110: Z = $signed(P[47:17]);
726 default: Z = 48'bx;
727 endcase
728 end
729
730 // Carry in
731 wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
732 reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0;
733 generate
734 if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
735 else always @* CARRYINr = CARRYIN;
736
737 if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end
738 else always @* A24_xnor_B17 = A24_xnor_B17d;
739 endgenerate
740
741 reg cin_muxed;
742
743 always @(*) begin
744 case (CARRYINSELr)
745 3'b000: cin_muxed = CARRYINr;
746 3'b001: cin_muxed = ~PCIN[47];
747 3'b010: cin_muxed = CARRYCASCIN;
748 3'b011: cin_muxed = PCIN[47];
749 3'b100: cin_muxed = CARRYCASCOUT;
750 3'b101: cin_muxed = ~P[47];
751 3'b110: cin_muxed = A24_xnor_B17;
752 3'b111: cin_muxed = P[47];
753 default: cin_muxed = 1'bx;
754 endcase
755 end
756
757 wire alu_cin = (ALUMODEr[3] || ALUMODEr[2]) ? 1'b0 : cin_muxed;
758
759 // ALU core
760 wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
761 wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
762 wire [47:0] maj_xyz = (X & Y) | (X & Z_muxinv) | (Y & Z_muxinv);
763
764 wire [47:0] xor_xyz_muxed = ALUMODEr[3] ? maj_xyz : xor_xyz;
765 wire [47:0] maj_xyz_gated = ALUMODEr[2] ? 48'b0 : maj_xyz;
766
767 wire [48:0] maj_xyz_simd_gated;
768 wire [3:0] int_carry_in, int_carry_out, ext_carry_out;
769 wire [47:0] alu_sum;
770 assign int_carry_in[0] = 1'b0;
771 wire [3:0] carryout_reset;
772
773 generate
774 if (USE_SIMD == "FOUR12") begin
775 assign maj_xyz_simd_gated = {
776 maj_xyz_gated[47:36],
777 1'b0, maj_xyz_gated[34:24],
778 1'b0, maj_xyz_gated[22:12],
779 1'b0, maj_xyz_gated[10:0],
780 alu_cin
781 };
782 assign int_carry_in[3:1] = 3'b000;
783 assign ext_carry_out = {
784 int_carry_out[3],
785 maj_xyz_gated[35] ^ int_carry_out[2],
786 maj_xyz_gated[23] ^ int_carry_out[1],
787 maj_xyz_gated[11] ^ int_carry_out[0]
788 };
789 assign carryout_reset = 4'b0000;
790 end else if (USE_SIMD == "TWO24") begin
791 assign maj_xyz_simd_gated = {
792 maj_xyz_gated[47:24],
793 1'b0, maj_xyz_gated[22:0],
794 alu_cin
795 };
796 assign int_carry_in[3:1] = {int_carry_out[2], 1'b0, int_carry_out[0]};
797 assign ext_carry_out = {
798 int_carry_out[3],
799 1'bx,
800 maj_xyz_gated[23] ^ int_carry_out[1],
801 1'bx
802 };
803 assign carryout_reset = 4'b0x0x;
804 end else begin
805 assign maj_xyz_simd_gated = {maj_xyz_gated, alu_cin};
806 assign int_carry_in[3:1] = int_carry_out[2:0];
807 assign ext_carry_out = {
808 int_carry_out[3],
809 3'bxxx
810 };
811 assign carryout_reset = 4'b0xxx;
812 end
813
814 genvar i;
815 for (i = 0; i < 4; i = i + 1)
816 assign {int_carry_out[i], alu_sum[i*12 +: 12]} = {1'b0, maj_xyz_simd_gated[i*12 +: ((i == 3) ? 13 : 12)]}
817 + xor_xyz_muxed[i*12 +: 12] + int_carry_in[i];
818 endgenerate
819
820 wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
821 initial P = 48'b0;
822 initial CARRYOUT = carryout_reset;
823 initial CARRYCASCOUT = 1'b0;
824 initial MULTSIGNOUT = 1'b0;
825 wire [3:0] CARRYOUTd = (OPMODEr[3:0] == 4'b0101 || ALUMODEr[3:2] != 2'b00) ? 4'bxxxx :
826 ((ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out);
827 wire CARRYCASCOUTd = ext_carry_out[3];
828 wire MULTSIGNOUTd = Mrx[42];
829
830 generate
831 if (PREG == 1) begin
832 always @(posedge CLK)
833 if (RSTP) begin
834 P <= 48'b0;
835 CARRYOUT <= carryout_reset;
836 CARRYCASCOUT <= 1'b0;
837 MULTSIGNOUT <= 1'b0;
838 end else if (CEP) begin
839 P <= Pd;
840 CARRYOUT <= CARRYOUTd;
841 CARRYCASCOUT <= CARRYCASCOUTd;
842 MULTSIGNOUT <= MULTSIGNOUTd;
843 end
844 end else begin
845 always @* begin
846 P = Pd;
847 CARRYOUT = CARRYOUTd;
848 CARRYCASCOUT = CARRYCASCOUTd;
849 MULTSIGNOUT = MULTSIGNOUTd;
850 end
851 end
852 endgenerate
853
854 assign PCOUT = P;
855
856 endmodule