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