Different approach to timing
[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 (* invertible_pin = "IS_S0_INVERTED" *)
64 input S0,
65 (* invertible_pin = "IS_S1_INVERTED" *)
66 input S1,
67 (* invertible_pin = "IS_CE0_INVERTED" *)
68 input CE0,
69 (* invertible_pin = "IS_CE1_INVERTED" *)
70 input CE1,
71 (* invertible_pin = "IS_IGNORE0_INVERTED" *)
72 input IGNORE0,
73 (* invertible_pin = "IS_IGNORE1_INVERTED" *)
74 input IGNORE1);
75
76 parameter [0:0] INIT_OUT = 1'b0;
77 parameter PRESELECT_I0 = "FALSE";
78 parameter PRESELECT_I1 = "FALSE";
79 parameter [0:0] IS_CE0_INVERTED = 1'b0;
80 parameter [0:0] IS_CE1_INVERTED = 1'b0;
81 parameter [0:0] IS_S0_INVERTED = 1'b0;
82 parameter [0:0] IS_S1_INVERTED = 1'b0;
83 parameter [0:0] IS_IGNORE0_INVERTED = 1'b0;
84 parameter [0:0] IS_IGNORE1_INVERTED = 1'b0;
85
86 wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT);
87 wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT);
88 wire S0_true = (S0 ^ IS_S0_INVERTED);
89 wire S1_true = (S1 ^ IS_S1_INVERTED);
90
91 assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT);
92
93 endmodule
94
95 module BUFHCE(
96 (* clkbuf_driver *)
97 output O,
98 input I,
99 (* invertible_pin = "IS_CE_INVERTED" *)
100 input CE);
101
102 parameter [0:0] INIT_OUT = 1'b0;
103 parameter CE_TYPE = "SYNC";
104 parameter [0:0] IS_CE_INVERTED = 1'b0;
105
106 assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT);
107
108 endmodule
109
110 // module OBUFT(output O, input I, T);
111 // assign O = T ? 1'bz : I;
112 // endmodule
113
114 // module IOBUF(inout IO, output O, input I, T);
115 // assign O = IO, IO = T ? 1'bz : I;
116 // endmodule
117
118 module INV(output O, input I);
119 assign O = !I;
120 endmodule
121
122 module LUT1(output O, input I0);
123 parameter [1:0] INIT = 0;
124 assign O = I0 ? INIT[1] : INIT[0];
125 endmodule
126
127 module LUT2(output O, input I0, I1);
128 parameter [3:0] INIT = 0;
129 wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
130 assign O = I0 ? s1[1] : s1[0];
131 endmodule
132
133 module LUT3(output O, input I0, I1, I2);
134 parameter [7:0] INIT = 0;
135 wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
136 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
137 assign O = I0 ? s1[1] : s1[0];
138 endmodule
139
140 module LUT4(output O, input I0, I1, I2, I3);
141 parameter [15:0] INIT = 0;
142 wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
143 wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
144 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
145 assign O = I0 ? s1[1] : s1[0];
146 endmodule
147
148 module LUT5(output O, input I0, I1, I2, I3, I4);
149 parameter [31:0] INIT = 0;
150 wire [15: 0] s4 = I4 ? INIT[31:16] : INIT[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(output O, 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 O = I0 ? s1[1] : s1[0];
165 endmodule
166
167 module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5);
168 parameter [63:0] INIT = 0;
169 wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
170 wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
171 wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
172 wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
173 wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
174 assign O6 = I0 ? s1[1] : s1[0];
175
176 wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0];
177 wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0];
178 wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0];
179 wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0];
180 assign O5 = I0 ? s5_1[1] : s5_1[0];
181 endmodule
182
183 module MUXCY(output O, input CI, DI, S);
184 assign O = S ? CI : DI;
185 endmodule
186
187 (* abc_box_id = 1, lib_whitebox *)
188 module MUXF7(output O, input I0, I1, S);
189 assign O = S ? I1 : I0;
190 endmodule
191
192 (* abc_box_id = 2, lib_whitebox *)
193 module MUXF8(output O, input I0, I1, S);
194 assign O = S ? I1 : I0;
195 endmodule
196
197 module XORCY(output O, input CI, LI);
198 assign O = CI ^ LI;
199 endmodule
200
201 (* abc_box_id = 4, lib_whitebox *)
202 module CARRY4(
203 (* abc_carry *)
204 output [3:0] CO,
205 output [3:0] O,
206 (* abc_carry *)
207 input CI,
208 input CYINIT,
209 input [3:0] DI, S
210 );
211 assign O = S ^ {CO[2:0], CI | CYINIT};
212 assign CO[0] = S[0] ? CI | CYINIT : DI[0];
213 assign CO[1] = S[1] ? CO[0] : DI[1];
214 assign CO[2] = S[2] ? CO[1] : DI[2];
215 assign CO[3] = S[3] ? CO[2] : DI[3];
216 endmodule
217
218 `ifdef _EXPLICIT_CARRY
219
220 module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
221 parameter CYINIT_FABRIC = 0;
222 wire CI_COMBINE;
223 if(CYINIT_FABRIC) begin
224 assign CI_COMBINE = CI_INIT;
225 end else begin
226 assign CI_COMBINE = CI;
227 end
228 assign CO_CHAIN = S ? CI_COMBINE : DI;
229 assign CO_FABRIC = S ? CI_COMBINE : DI;
230 assign O = S ^ CI_COMBINE;
231 endmodule
232
233 module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
234 assign CO_CHAIN = S ? CI : DI;
235 assign CO_FABRIC = S ? CI : DI;
236 assign O = S ^ CI;
237 endmodule
238
239 `endif
240
241 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
242
243 module FDRE (
244 (* abc_arrival=303 *)
245 output reg Q,
246 (* clkbuf_sink *)
247 (* invertible_pin = "IS_C_INVERTED" *)
248 input C,
249 input CE,
250 (* invertible_pin = "IS_D_INVERTED" *)
251 input D,
252 (* invertible_pin = "IS_R_INVERTED" *)
253 input R
254 );
255 parameter [0:0] INIT = 1'b0;
256 parameter [0:0] IS_C_INVERTED = 1'b0;
257 parameter [0:0] IS_D_INVERTED = 1'b0;
258 parameter [0:0] IS_R_INVERTED = 1'b0;
259 initial Q <= INIT;
260 generate case (|IS_C_INVERTED)
261 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
262 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
263 endcase endgenerate
264 endmodule
265
266 module FDSE (
267 (* abc_arrival=303 *)
268 output reg Q,
269 (* clkbuf_sink *)
270 (* invertible_pin = "IS_C_INVERTED" *)
271 input C,
272 input CE,
273 (* invertible_pin = "IS_D_INVERTED" *)
274 input D,
275 (* invertible_pin = "IS_S_INVERTED" *)
276 input S
277 );
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_S_INVERTED = 1'b0;
282 initial Q <= INIT;
283 generate case (|IS_C_INVERTED)
284 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
285 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
286 endcase endgenerate
287 endmodule
288
289 module FDCE (
290 (* abc_arrival=303 *)
291 output reg Q,
292 (* clkbuf_sink *)
293 (* invertible_pin = "IS_C_INVERTED" *)
294 input C,
295 input CE,
296 (* invertible_pin = "IS_D_INVERTED" *)
297 input D,
298 (* invertible_pin = "IS_CLR_INVERTED" *)
299 input CLR
300 );
301 parameter [0:0] INIT = 1'b0;
302 parameter [0:0] IS_C_INVERTED = 1'b0;
303 parameter [0:0] IS_D_INVERTED = 1'b0;
304 parameter [0:0] IS_CLR_INVERTED = 1'b0;
305 initial Q <= INIT;
306 generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED})
307 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
308 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
309 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
310 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
311 endcase endgenerate
312 endmodule
313
314 module FDPE (
315 (* abc_arrival=303 *)
316 output reg Q,
317 (* clkbuf_sink *)
318 (* invertible_pin = "IS_C_INVERTED" *)
319 input C,
320 input CE,
321 (* invertible_pin = "IS_D_INVERTED" *)
322 input D,
323 (* invertible_pin = "IS_PRE_INVERTED" *)
324 input PRE
325 );
326 parameter [0:0] INIT = 1'b1;
327 parameter [0:0] IS_C_INVERTED = 1'b0;
328 parameter [0:0] IS_D_INVERTED = 1'b0;
329 parameter [0:0] IS_PRE_INVERTED = 1'b0;
330 initial Q <= INIT;
331 generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
332 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
333 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
334 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
335 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
336 endcase endgenerate
337 endmodule
338
339 module FDRE_1 (
340 (* abc_arrival=303 *)
341 output reg Q,
342 (* clkbuf_sink *)
343 input C,
344 input CE, D, R
345 );
346 parameter [0:0] INIT = 1'b0;
347 initial Q <= INIT;
348 always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
349 endmodule
350
351 module FDSE_1 (
352 (* abc_arrival=303 *)
353 output reg Q,
354 (* clkbuf_sink *)
355 input C,
356 input CE, D, S
357 );
358 parameter [0:0] INIT = 1'b1;
359 initial Q <= INIT;
360 always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
361 endmodule
362
363 module FDCE_1 (
364 (* abc_arrival=303 *)
365 output reg Q,
366 (* clkbuf_sink *)
367 input C,
368 input CE, D, CLR
369 );
370 parameter [0:0] INIT = 1'b0;
371 initial Q <= INIT;
372 always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
373 endmodule
374
375 module FDPE_1 (
376 (* abc_arrival=303 *)
377 output reg Q,
378 (* clkbuf_sink *)
379 input C,
380 input CE, D, PRE
381 );
382 parameter [0:0] INIT = 1'b1;
383 initial Q <= INIT;
384 always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
385 endmodule
386
387 module RAM32X1D (
388 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
389 (* abc_arrival=1153 *)
390 output DPO, SPO,
391 input D,
392 (* clkbuf_sink *)
393 (* invertible_pin = "IS_WCLK_INVERTED" *)
394 input WCLK,
395 input WE,
396 input A0, A1, A2, A3, A4,
397 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
398 );
399 parameter INIT = 32'h0;
400 parameter IS_WCLK_INVERTED = 1'b0;
401 wire [4:0] a = {A4, A3, A2, A1, A0};
402 wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
403 reg [31:0] mem = INIT;
404 assign SPO = mem[a];
405 assign DPO = mem[dpra];
406 wire clk = WCLK ^ IS_WCLK_INVERTED;
407 always @(posedge clk) if (WE) mem[a] <= D;
408 endmodule
409
410 module RAM64X1D (
411 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
412 (* abc_arrival=1153 *)
413 output DPO, SPO,
414 input D,
415 (* clkbuf_sink *)
416 (* invertible_pin = "IS_WCLK_INVERTED" *)
417 input WCLK,
418 input WE,
419 input A0, A1, A2, A3, A4, A5,
420 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
421 );
422 parameter INIT = 64'h0;
423 parameter IS_WCLK_INVERTED = 1'b0;
424 wire [5:0] a = {A5, A4, A3, A2, A1, A0};
425 wire [5:0] dpra = {DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
426 reg [63:0] mem = INIT;
427 assign SPO = mem[a];
428 assign DPO = mem[dpra];
429 wire clk = WCLK ^ IS_WCLK_INVERTED;
430 always @(posedge clk) if (WE) mem[a] <= D;
431 endmodule
432
433 module RAM128X1D (
434 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
435 (* abc_arrival=1153 *)
436 output DPO, SPO,
437 input D,
438 (* clkbuf_sink *)
439 (* invertible_pin = "IS_WCLK_INVERTED" *)
440 input WCLK,
441 input WE,
442 input [6:0] A, DPRA
443 );
444 parameter INIT = 128'h0;
445 parameter IS_WCLK_INVERTED = 1'b0;
446 reg [127:0] mem = INIT;
447 assign SPO = mem[A];
448 assign DPO = mem[DPRA];
449 wire clk = WCLK ^ IS_WCLK_INVERTED;
450 always @(posedge clk) if (WE) mem[A] <= D;
451 endmodule
452
453 module SRL16E (
454 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
455 (* abc_arrival=1472 *)
456 output Q,
457 input A0, A1, A2, A3, CE,
458 (* clkbuf_sink *)
459 (* invertible_pin = "IS_CLK_INVERTED" *)
460 input CLK,
461 input D
462 );
463 parameter [15:0] INIT = 16'h0000;
464 parameter [0:0] IS_CLK_INVERTED = 1'b0;
465
466 reg [15:0] r = INIT;
467 assign Q = r[{A3,A2,A1,A0}];
468 generate
469 if (IS_CLK_INVERTED) begin
470 always @(negedge CLK) if (CE) r <= { r[14:0], D };
471 end
472 else
473 always @(posedge CLK) if (CE) r <= { r[14:0], D };
474 endgenerate
475 endmodule
476
477 module SRLC16E (
478 output Q,
479 output Q15,
480 input A0, A1, A2, A3, CE,
481 (* clkbuf_sink *)
482 (* invertible_pin = "IS_CLK_INVERTED" *)
483 input CLK,
484 input D
485 );
486 parameter [15:0] INIT = 16'h0000;
487 parameter [0:0] IS_CLK_INVERTED = 1'b0;
488
489 reg [15:0] r = INIT;
490 assign Q15 = r[15];
491 assign Q = r[{A3,A2,A1,A0}];
492 generate
493 if (IS_CLK_INVERTED) begin
494 always @(negedge CLK) if (CE) r <= { r[14:0], D };
495 end
496 else
497 always @(posedge CLK) if (CE) r <= { r[14:0], D };
498 endgenerate
499 endmodule
500
501 module SRLC32E (
502 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
503 (* abc_arrival=1472 *)
504 output Q,
505 (* abc_arrival=1114 *)
506 output Q31,
507 input [4:0] A,
508 input CE,
509 (* clkbuf_sink *)
510 (* invertible_pin = "IS_CLK_INVERTED" *)
511 input CLK,
512 input D
513 );
514 parameter [31:0] INIT = 32'h00000000;
515 parameter [0:0] IS_CLK_INVERTED = 1'b0;
516
517 reg [31:0] r = INIT;
518 assign Q31 = r[31];
519 assign Q = r[A];
520 generate
521 if (IS_CLK_INVERTED) begin
522 always @(negedge CLK) if (CE) r <= { r[30:0], D };
523 end
524 else
525 always @(posedge CLK) if (CE) r <= { r[30:0], D };
526 endgenerate
527 endmodule
528
529 module DSP48E1 (
530 output [29:0] ACOUT,
531 output [17:0] BCOUT,
532 output reg CARRYCASCOUT,
533 output reg [3:0] CARRYOUT,
534 output reg MULTSIGNOUT,
535 output OVERFLOW,
536 output reg signed [47:0] P,
537 output reg PATTERNBDETECT,
538 output reg PATTERNDETECT,
539 output [47:0] PCOUT,
540 output UNDERFLOW,
541 input signed [29:0] A,
542 input [29:0] ACIN,
543 input [3:0] ALUMODE,
544 input signed [17:0] B,
545 input [17:0] BCIN,
546 input [47:0] C,
547 input CARRYCASCIN,
548 input CARRYIN,
549 input [2:0] CARRYINSEL,
550 input CEA1,
551 input CEA2,
552 input CEAD,
553 input CEALUMODE,
554 input CEB1,
555 input CEB2,
556 input CEC,
557 input CECARRYIN,
558 input CECTRL,
559 input CED,
560 input CEINMODE,
561 input CEM,
562 input CEP,
563 (* clkbuf_sink *) input CLK,
564 input [24:0] D,
565 input [4:0] INMODE,
566 input MULTSIGNIN,
567 input [6:0] OPMODE,
568 input [47:0] PCIN,
569 input RSTA,
570 input RSTALLCARRYIN,
571 input RSTALUMODE,
572 input RSTB,
573 input RSTC,
574 input RSTCTRL,
575 input RSTD,
576 input RSTINMODE,
577 input RSTM,
578 input RSTP
579 );
580 parameter integer ACASCREG = 1;
581 parameter integer ADREG = 1;
582 parameter integer ALUMODEREG = 1;
583 parameter integer AREG = 1;
584 parameter AUTORESET_PATDET = "NO_RESET";
585 parameter A_INPUT = "DIRECT";
586 parameter integer BCASCREG = 1;
587 parameter integer BREG = 1;
588 parameter B_INPUT = "DIRECT";
589 parameter integer CARRYINREG = 1;
590 parameter integer CARRYINSELREG = 1;
591 parameter integer CREG = 1;
592 parameter integer DREG = 1;
593 parameter integer INMODEREG = 1;
594 parameter integer MREG = 1;
595 parameter integer OPMODEREG = 1;
596 parameter integer PREG = 1;
597 parameter SEL_MASK = "MASK";
598 parameter SEL_PATTERN = "PATTERN";
599 parameter USE_DPORT = "FALSE";
600 parameter USE_MULT = "MULTIPLY";
601 parameter USE_PATTERN_DETECT = "NO_PATDET";
602 parameter USE_SIMD = "ONE48";
603 parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
604 parameter [47:0] PATTERN = 48'h000000000000;
605 parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
606 parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
607 parameter [0:0] IS_CLK_INVERTED = 1'b0;
608 parameter [4:0] IS_INMODE_INVERTED = 5'b0;
609 parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
610
611 initial begin
612 `ifdef __ICARUS__
613 if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
614 if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
615 if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
616 if (USE_SIMD != "ONE48" && USE_SIMD != "TWO24" && USE_SIMD != "FOUR12") $fatal(1, "Unsupported USE_SIMD value");
617 if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value");
618 if (IS_CARRYIN_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CARRYIN_INVERTED value");
619 if (IS_CLK_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CLK_INVERTED value");
620 if (IS_INMODE_INVERTED != 5'b0) $fatal(1, "Unsupported IS_INMODE_INVERTED value");
621 if (IS_OPMODE_INVERTED != 7'b0) $fatal(1, "Unsupported IS_OPMODE_INVERTED value");
622 `endif
623 end
624
625 wire signed [29:0] A_muxed;
626 wire signed [17:0] B_muxed;
627
628 generate
629 if (A_INPUT == "CASCADE") assign A_muxed = ACIN;
630 else assign A_muxed = A;
631
632 if (B_INPUT == "CASCADE") assign B_muxed = BCIN;
633 else assign B_muxed = B;
634 endgenerate
635
636 reg signed [29:0] Ar1, Ar2;
637 reg signed [24:0] Dr;
638 reg signed [17:0] Br1, Br2;
639 reg signed [47:0] Cr;
640 reg [4:0] INMODEr = 5'b0;
641 reg [6:0] OPMODEr = 7'b0;
642 reg [3:0] ALUMODEr = 4'b0;
643 reg [2:0] CARRYINSELr = 3'b0;
644
645 generate
646 // Configurable A register
647 if (AREG == 2) begin
648 initial Ar1 = 30'b0;
649 initial Ar2 = 30'b0;
650 always @(posedge CLK)
651 if (RSTA) begin
652 Ar1 <= 30'b0;
653 Ar2 <= 30'b0;
654 end else begin
655 if (CEA1) Ar1 <= A_muxed;
656 if (CEA2) Ar2 <= Ar1;
657 end
658 end else if (AREG == 1) begin
659 //initial Ar1 = 30'b0;
660 initial Ar2 = 30'b0;
661 always @(posedge CLK)
662 if (RSTA) begin
663 Ar1 <= 30'b0;
664 Ar2 <= 30'b0;
665 end else begin
666 if (CEA1) Ar1 <= A_muxed;
667 if (CEA2) Ar2 <= A_muxed;
668 end
669 end else begin
670 always @* Ar1 <= A_muxed;
671 always @* Ar2 <= A_muxed;
672 end
673
674 // Configurable B register
675 if (BREG == 2) begin
676 initial Br1 = 25'b0;
677 initial Br2 = 25'b0;
678 always @(posedge CLK)
679 if (RSTB) begin
680 Br1 <= 18'b0;
681 Br2 <= 18'b0;
682 end else begin
683 if (CEB1) Br1 <= B_muxed;
684 if (CEB2) Br2 <= Br1;
685 end
686 end else if (BREG == 1) begin
687 //initial Br1 = 25'b0;
688 initial Br2 = 25'b0;
689 always @(posedge CLK)
690 if (RSTB) begin
691 Br1 <= 18'b0;
692 Br2 <= 18'b0;
693 end else begin
694 if (CEB1) Br1 <= B_muxed;
695 if (CEB2) Br2 <= B_muxed;
696 end
697 end else begin
698 always @* Br1 <= B_muxed;
699 always @* Br2 <= B_muxed;
700 end
701
702 // C and D registers
703 if (CREG == 1) initial Cr = 48'b0;
704 if (CREG == 1) begin always @(posedge CLK) if (RSTC) Cr <= 48'b0; else if (CEC) Cr <= C; end
705 else always @* Cr <= C;
706
707 if (CREG == 1) initial Dr = 25'b0;
708 if (DREG == 1) begin always @(posedge CLK) if (RSTD) Dr <= 25'b0; else if (CED) Dr <= D; end
709 else always @* Dr <= D;
710
711 // Control registers
712 if (INMODEREG == 1) initial INMODEr = 5'b0;
713 if (INMODEREG == 1) begin always @(posedge CLK) if (RSTINMODE) INMODEr <= 5'b0; else if (CEINMODE) INMODEr <= INMODE; end
714 else always @* INMODEr <= INMODE;
715 if (OPMODEREG == 1) initial OPMODEr = 7'b0;
716 if (OPMODEREG == 1) begin always @(posedge CLK) if (RSTCTRL) OPMODEr <= 7'b0; else if (CECTRL) OPMODEr <= OPMODE; end
717 else always @* OPMODEr <= OPMODE;
718 if (ALUMODEREG == 1) initial ALUMODEr = 4'b0;
719 if (ALUMODEREG == 1) begin always @(posedge CLK) if (RSTALUMODE) ALUMODEr <= 4'b0; else if (CEALUMODE) ALUMODEr <= ALUMODE; end
720 else always @* ALUMODEr <= ALUMODE;
721 if (CARRYINSELREG == 1) initial CARRYINSELr = 3'b0;
722 if (CARRYINSELREG == 1) begin always @(posedge CLK) if (RSTCTRL) CARRYINSELr <= 3'b0; else if (CECTRL) CARRYINSELr <= CARRYINSEL; end
723 else always @* CARRYINSELr <= CARRYINSEL;
724 endgenerate
725
726 // A and B cascade
727 generate
728 if (ACASCREG == 1 && AREG == 2) assign ACOUT = Ar1;
729 else assign ACOUT = Ar2;
730 if (BCASCREG == 1 && BREG == 2) assign BCOUT = Br1;
731 else assign BCOUT = Br2;
732 endgenerate
733
734 // A/D input selection and pre-adder
735 wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2;
736 wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed;
737 wire signed [24:0] Dr_gated = INMODEr[2] ? Dr : 25'b0;
738 wire signed [24:0] AD_result = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated);
739 reg signed [24:0] ADr;
740
741 generate
742 if (ADREG == 1) initial ADr = 25'b0;
743 if (ADREG == 1) begin always @(posedge CLK) if (RSTD) ADr <= 25'b0; else if (CEAD) ADr <= AD_result; end
744 else always @* ADr <= AD_result;
745 endgenerate
746
747 // 25x18 multiplier
748 wire signed [24:0] A_MULT;
749 wire signed [17:0] B_MULT = INMODEr[4] ? Br1 : Br2;
750 generate
751 if (USE_DPORT == "TRUE") assign A_MULT = ADr;
752 else assign A_MULT = Ar12_gated;
753 endgenerate
754
755 wire signed [42:0] M = A_MULT * B_MULT;
756 wire signed [42:0] Mx = (CARRYINSEL == 3'b010) ? 43'bx : M;
757 reg signed [42:0] Mr = 43'b0;
758
759 // Multiplier result register
760 generate
761 if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= Mx; end
762 else always @* Mr <= Mx;
763 endgenerate
764
765 wire signed [42:0] Mrx = (CARRYINSELr == 3'b010) ? 43'bx : Mr;
766
767 // X, Y and Z ALU inputs
768 reg signed [47:0] X, Y, Z;
769
770 always @* begin
771 // X multiplexer
772 case (OPMODEr[1:0])
773 2'b00: X = 48'b0;
774 2'b01: begin X = $signed(Mrx);
775 `ifdef __ICARUS__
776 if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
777 `endif
778 end
779 2'b10: begin X = P;
780 `ifdef __ICARUS__
781 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
782 `endif
783 end
784 2'b11: X = $signed({Ar2, Br2});
785 default: X = 48'bx;
786 endcase
787
788 // Y multiplexer
789 case (OPMODEr[3:2])
790 2'b00: Y = 48'b0;
791 2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
792 `ifdef __ICARUS__
793 if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
794 `endif
795 end
796 2'b10: Y = {48{1'b1}};
797 2'b11: Y = Cr;
798 default: Y = 48'bx;
799 endcase
800
801 // Z multiplexer
802 case (OPMODEr[6:4])
803 3'b000: Z = 48'b0;
804 3'b001: Z = PCIN;
805 3'b010: begin Z = P;
806 `ifdef __ICARUS__
807 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
808 `endif
809 end
810 3'b011: Z = Cr;
811 3'b100: begin Z = P;
812 `ifdef __ICARUS__
813 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
814 if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
815 `endif
816 end
817 3'b101: Z = $signed(PCIN[47:17]);
818 3'b110: Z = $signed(P[47:17]);
819 default: Z = 48'bx;
820 endcase
821 end
822
823 // Carry in
824 wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
825 reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0;
826 generate
827 if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
828 else always @* CARRYINr = CARRYIN;
829
830 if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end
831 else always @* A24_xnor_B17 = A24_xnor_B17d;
832 endgenerate
833
834 reg cin_muxed;
835
836 always @(*) begin
837 case (CARRYINSELr)
838 3'b000: cin_muxed = CARRYINr;
839 3'b001: cin_muxed = ~PCIN[47];
840 3'b010: cin_muxed = CARRYCASCIN;
841 3'b011: cin_muxed = PCIN[47];
842 3'b100: cin_muxed = CARRYCASCOUT;
843 3'b101: cin_muxed = ~P[47];
844 3'b110: cin_muxed = A24_xnor_B17;
845 3'b111: cin_muxed = P[47];
846 default: cin_muxed = 1'bx;
847 endcase
848 end
849
850 wire alu_cin = (ALUMODEr[3] || ALUMODEr[2]) ? 1'b0 : cin_muxed;
851
852 // ALU core
853 wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
854 wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
855 wire [47:0] maj_xyz = (X & Y) | (X & Z_muxinv) | (Y & Z_muxinv);
856
857 wire [47:0] xor_xyz_muxed = ALUMODEr[3] ? maj_xyz : xor_xyz;
858 wire [47:0] maj_xyz_gated = ALUMODEr[2] ? 48'b0 : maj_xyz;
859
860 wire [48:0] maj_xyz_simd_gated;
861 wire [3:0] int_carry_in, int_carry_out, ext_carry_out;
862 wire [47:0] alu_sum;
863 assign int_carry_in[0] = 1'b0;
864 wire [3:0] carryout_reset;
865
866 generate
867 if (USE_SIMD == "FOUR12") begin
868 assign maj_xyz_simd_gated = {
869 maj_xyz_gated[47:36],
870 1'b0, maj_xyz_gated[34:24],
871 1'b0, maj_xyz_gated[22:12],
872 1'b0, maj_xyz_gated[10:0],
873 alu_cin
874 };
875 assign int_carry_in[3:1] = 3'b000;
876 assign ext_carry_out = {
877 int_carry_out[3],
878 maj_xyz_gated[35] ^ int_carry_out[2],
879 maj_xyz_gated[23] ^ int_carry_out[1],
880 maj_xyz_gated[11] ^ int_carry_out[0]
881 };
882 assign carryout_reset = 4'b0000;
883 end else if (USE_SIMD == "TWO24") begin
884 assign maj_xyz_simd_gated = {
885 maj_xyz_gated[47:24],
886 1'b0, maj_xyz_gated[22:0],
887 alu_cin
888 };
889 assign int_carry_in[3:1] = {int_carry_out[2], 1'b0, int_carry_out[0]};
890 assign ext_carry_out = {
891 int_carry_out[3],
892 1'bx,
893 maj_xyz_gated[23] ^ int_carry_out[1],
894 1'bx
895 };
896 assign carryout_reset = 4'b0x0x;
897 end else begin
898 assign maj_xyz_simd_gated = {maj_xyz_gated, alu_cin};
899 assign int_carry_in[3:1] = int_carry_out[2:0];
900 assign ext_carry_out = {
901 int_carry_out[3],
902 3'bxxx
903 };
904 assign carryout_reset = 4'b0xxx;
905 end
906
907 genvar i;
908 for (i = 0; i < 4; i = i + 1)
909 assign {int_carry_out[i], alu_sum[i*12 +: 12]} = {1'b0, maj_xyz_simd_gated[i*12 +: ((i == 3) ? 13 : 12)]}
910 + xor_xyz_muxed[i*12 +: 12] + int_carry_in[i];
911 endgenerate
912
913 wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
914 wire [3:0] CARRYOUTd = (OPMODEr[3:0] == 4'b0101 || ALUMODEr[3:2] != 2'b00) ? 4'bxxxx :
915 ((ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out);
916 wire CARRYCASCOUTd = ext_carry_out[3];
917 wire MULTSIGNOUTd = Mrx[42];
918
919 generate
920 if (PREG == 1) begin
921 initial P = 48'b0;
922 initial CARRYOUT = carryout_reset;
923 initial CARRYCASCOUT = 1'b0;
924 initial MULTSIGNOUT = 1'b0;
925 always @(posedge CLK)
926 if (RSTP) begin
927 P <= 48'b0;
928 CARRYOUT <= carryout_reset;
929 CARRYCASCOUT <= 1'b0;
930 MULTSIGNOUT <= 1'b0;
931 end else if (CEP) begin
932 P <= Pd;
933 CARRYOUT <= CARRYOUTd;
934 CARRYCASCOUT <= CARRYCASCOUTd;
935 MULTSIGNOUT <= MULTSIGNOUTd;
936 end
937 end else begin
938 always @* begin
939 P = Pd;
940 CARRYOUT = CARRYOUTd;
941 CARRYCASCOUT = CARRYCASCOUTd;
942 MULTSIGNOUT = MULTSIGNOUTd;
943 end
944 end
945 endgenerate
946
947 assign PCOUT = P;
948
949 generate
950 wire PATTERNDETECTd, PATTERNBDETECTd;
951
952 if (USE_PATTERN_DETECT == "PATDET") begin
953 // TODO: Support SEL_PATTERN != "PATTERN" and SEL_MASK != "MASK
954 assign PATTERNDETECTd = &(~(Pd ^ PATTERN) | MASK);
955 assign PATTERNBDETECTd = &((Pd ^ PATTERN) | MASK);
956 end else begin
957 assign PATTERNDETECTd = 1'b1;
958 assign PATTERNBDETECTd = 1'b1;
959 end
960
961 if (PREG == 1) begin
962 reg PATTERNDETECTPAST, PATTERNBDETECTPAST;
963 initial PATTERNDETECT = 1'b0;
964 initial PATTERNBDETECT = 1'b0;
965 initial PATTERNDETECTPAST = 1'b0;
966 initial PATTERNBDETECTPAST = 1'b0;
967 always @(posedge CLK)
968 if (RSTP) begin
969 PATTERNDETECT <= 1'b0;
970 PATTERNBDETECT <= 1'b0;
971 PATTERNDETECTPAST <= 1'b0;
972 PATTERNBDETECTPAST <= 1'b0;
973 end else if (CEP) begin
974 PATTERNDETECT <= PATTERNDETECTd;
975 PATTERNBDETECT <= PATTERNBDETECTd;
976 PATTERNDETECTPAST <= PATTERNDETECT;
977 PATTERNBDETECTPAST <= PATTERNBDETECT;
978 end
979 assign OVERFLOW = &{PATTERNDETECTPAST, ~PATTERNBDETECT, ~PATTERNDETECT};
980 assign UNDERFLOW = &{PATTERNBDETECTPAST, ~PATTERNBDETECT, ~PATTERNDETECT};
981 end else begin
982 always @* begin
983 PATTERNDETECT = PATTERNDETECTd;
984 PATTERNBDETECT = PATTERNBDETECTd;
985 end
986 assign OVERFLOW = 1'bx, UNDERFLOW = 1'bx;
987 end
988 endgenerate
989
990 endmodule