DSP48E1 sim model: Comb, no pre-adder, mode working
[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, abc_carry="CI,CO", lib_whitebox *)
185 module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
186 assign O = S ^ {CO[2:0], CI | CYINIT};
187 assign CO[0] = S[0] ? CI | CYINIT : DI[0];
188 assign CO[1] = S[1] ? CO[0] : DI[1];
189 assign CO[2] = S[2] ? CO[1] : DI[2];
190 assign CO[3] = S[3] ? CO[2] : DI[3];
191 endmodule
192
193 `ifdef _EXPLICIT_CARRY
194
195 module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
196 parameter CYINIT_FABRIC = 0;
197 wire CI_COMBINE;
198 if(CYINIT_FABRIC) begin
199 assign CI_COMBINE = CI_INIT;
200 end else begin
201 assign CI_COMBINE = CI;
202 end
203 assign CO_CHAIN = S ? CI_COMBINE : DI;
204 assign CO_FABRIC = S ? CI_COMBINE : DI;
205 assign O = S ^ CI_COMBINE;
206 endmodule
207
208 module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
209 assign CO_CHAIN = S ? CI : DI;
210 assign CO_FABRIC = S ? CI : DI;
211 assign O = S ^ CI;
212 endmodule
213
214 `endif
215
216 module FDRE (output reg Q, input C, CE, D, R);
217 parameter [0:0] INIT = 1'b0;
218 parameter [0:0] IS_C_INVERTED = 1'b0;
219 parameter [0:0] IS_D_INVERTED = 1'b0;
220 parameter [0:0] IS_R_INVERTED = 1'b0;
221 initial Q <= INIT;
222 generate case (|IS_C_INVERTED)
223 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
224 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
225 endcase endgenerate
226 endmodule
227
228 module FDSE (output reg Q, input C, CE, D, S);
229 parameter [0:0] INIT = 1'b1;
230 parameter [0:0] IS_C_INVERTED = 1'b0;
231 parameter [0:0] IS_D_INVERTED = 1'b0;
232 parameter [0:0] IS_S_INVERTED = 1'b0;
233 initial Q <= INIT;
234 generate case (|IS_C_INVERTED)
235 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
236 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
237 endcase endgenerate
238 endmodule
239
240 module FDCE (output reg Q, input C, CE, D, CLR);
241 parameter [0:0] INIT = 1'b0;
242 parameter [0:0] IS_C_INVERTED = 1'b0;
243 parameter [0:0] IS_D_INVERTED = 1'b0;
244 parameter [0:0] IS_CLR_INVERTED = 1'b0;
245 initial Q <= INIT;
246 generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED})
247 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
248 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
249 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
250 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED;
251 endcase endgenerate
252 endmodule
253
254 module FDPE (output reg Q, input C, CE, D, PRE);
255 parameter [0:0] INIT = 1'b1;
256 parameter [0:0] IS_C_INVERTED = 1'b0;
257 parameter [0:0] IS_D_INVERTED = 1'b0;
258 parameter [0:0] IS_PRE_INVERTED = 1'b0;
259 initial Q <= INIT;
260 generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
261 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
262 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
263 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
264 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
265 endcase endgenerate
266 endmodule
267
268 module FDRE_1 (output reg Q, input C, CE, D, R);
269 parameter [0:0] INIT = 1'b0;
270 initial Q <= INIT;
271 always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
272 endmodule
273
274 module FDSE_1 (output reg Q, input C, CE, D, S);
275 parameter [0:0] INIT = 1'b1;
276 initial Q <= INIT;
277 always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
278 endmodule
279
280 module FDCE_1 (output reg Q, input C, CE, D, CLR);
281 parameter [0:0] INIT = 1'b0;
282 initial Q <= INIT;
283 always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
284 endmodule
285
286 module FDPE_1 (output reg Q, input C, CE, D, PRE);
287 parameter [0:0] INIT = 1'b1;
288 initial Q <= INIT;
289 always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
290 endmodule
291
292 (* abc_box_id = 5, abc_scc_break="D,WE" *)
293 module RAM32X1D (
294 output DPO, SPO,
295 input D, WCLK, WE,
296 input A0, A1, A2, A3, A4,
297 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
298 );
299 parameter INIT = 32'h0;
300 parameter IS_WCLK_INVERTED = 1'b0;
301 wire [4:0] a = {A4, A3, A2, A1, A0};
302 wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
303 reg [31:0] mem = INIT;
304 assign SPO = mem[a];
305 assign DPO = mem[dpra];
306 wire clk = WCLK ^ IS_WCLK_INVERTED;
307 always @(posedge clk) if (WE) mem[a] <= D;
308 endmodule
309
310 (* abc_box_id = 6, abc_scc_break="D,WE" *)
311 module RAM64X1D (
312 output DPO, SPO,
313 input D, WCLK, WE,
314 input A0, A1, A2, A3, A4, A5,
315 input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
316 );
317 parameter INIT = 64'h0;
318 parameter IS_WCLK_INVERTED = 1'b0;
319 wire [5:0] a = {A5, A4, A3, A2, A1, A0};
320 wire [5:0] dpra = {DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0};
321 reg [63:0] mem = INIT;
322 assign SPO = mem[a];
323 assign DPO = mem[dpra];
324 wire clk = WCLK ^ IS_WCLK_INVERTED;
325 always @(posedge clk) if (WE) mem[a] <= D;
326 endmodule
327
328 (* abc_box_id = 7, abc_scc_break="D,WE" *)
329 module RAM128X1D (
330 output DPO, SPO,
331 input D, WCLK, WE,
332 input [6:0] A, DPRA
333 );
334 parameter INIT = 128'h0;
335 parameter IS_WCLK_INVERTED = 1'b0;
336 reg [127:0] mem = INIT;
337 assign SPO = mem[A];
338 assign DPO = mem[DPRA];
339 wire clk = WCLK ^ IS_WCLK_INVERTED;
340 always @(posedge clk) if (WE) mem[A] <= D;
341 endmodule
342
343 module SRL16E (
344 output Q,
345 input A0, A1, A2, A3, CE, CLK, D
346 );
347 parameter [15:0] INIT = 16'h0000;
348 parameter [0:0] IS_CLK_INVERTED = 1'b0;
349
350 reg [15:0] r = INIT;
351 assign Q = r[{A3,A2,A1,A0}];
352 generate
353 if (IS_CLK_INVERTED) begin
354 always @(negedge CLK) if (CE) r <= { r[14:0], D };
355 end
356 else
357 always @(posedge CLK) if (CE) r <= { r[14:0], D };
358 endgenerate
359 endmodule
360
361 module SRLC32E (
362 output Q,
363 output Q31,
364 input [4:0] A,
365 input CE, CLK, D
366 );
367 parameter [31:0] INIT = 32'h00000000;
368 parameter [0:0] IS_CLK_INVERTED = 1'b0;
369
370 reg [31:0] r = INIT;
371 assign Q31 = r[31];
372 assign Q = r[A];
373 generate
374 if (IS_CLK_INVERTED) begin
375 always @(negedge CLK) if (CE) r <= { r[30:0], D };
376 end
377 else
378 always @(posedge CLK) if (CE) r <= { r[30:0], D };
379 endgenerate
380 endmodule
381
382 module DSP48E1 (
383 output [29:0] ACOUT,
384 output [17:0] BCOUT,
385 output reg CARRYCASCOUT,
386 output reg [3:0] CARRYOUT,
387 output reg MULTSIGNOUT,
388 output OVERFLOW,
389 output reg signed [47:0] P,
390 output PATTERNBDETECT,
391 output PATTERNDETECT,
392 output [47:0] PCOUT,
393 output UNDERFLOW,
394 input signed [29:0] A,
395 input [29:0] ACIN,
396 input [3:0] ALUMODE,
397 input signed [17:0] B,
398 input [17:0] BCIN,
399 input [47:0] C,
400 input CARRYCASCIN,
401 input CARRYIN,
402 input [2:0] CARRYINSEL,
403 input CEA1,
404 input CEA2,
405 input CEAD,
406 input CEALUMODE,
407 input CEB1,
408 input CEB2,
409 input CEC,
410 input CECARRYIN,
411 input CECTRL,
412 input CED,
413 input CEINMODE,
414 input CEM,
415 input CEP,
416 input CLK,
417 input [24:0] D,
418 input [4:0] INMODE,
419 input MULTSIGNIN,
420 input [6:0] OPMODE,
421 input [47:0] PCIN,
422 input RSTA,
423 input RSTALLCARRYIN,
424 input RSTALUMODE,
425 input RSTB,
426 input RSTC,
427 input RSTCTRL,
428 input RSTD,
429 input RSTINMODE,
430 input RSTM,
431 input RSTP
432 );
433 parameter integer ACASCREG = 1;
434 parameter integer ADREG = 1;
435 parameter integer ALUMODEREG = 1;
436 parameter integer AREG = 1;
437 parameter AUTORESET_PATDET = "NO_RESET";
438 parameter A_INPUT = "DIRECT";
439 parameter integer BCASCREG = 1;
440 parameter integer BREG = 1;
441 parameter B_INPUT = "DIRECT";
442 parameter integer CARRYINREG = 1;
443 parameter integer CARRYINSELREG = 1;
444 parameter integer CREG = 1;
445 parameter integer DREG = 1;
446 parameter integer INMODEREG = 1;
447 parameter integer MREG = 1;
448 parameter integer OPMODEREG = 1;
449 parameter integer PREG = 1;
450 parameter SEL_MASK = "MASK";
451 parameter SEL_PATTERN = "PATTERN";
452 parameter USE_DPORT = "FALSE";
453 parameter USE_MULT = "MULTIPLY";
454 parameter USE_PATTERN_DETECT = "NO_PATDET";
455 parameter USE_SIMD = "ONE48";
456 parameter [47:0] MASK = 48'h3FFFFFFFFFFF;
457 parameter [47:0] PATTERN = 48'h000000000000;
458 parameter [3:0] IS_ALUMODE_INVERTED = 4'b0;
459 parameter [0:0] IS_CARRYIN_INVERTED = 1'b0;
460 parameter [0:0] IS_CLK_INVERTED = 1'b0;
461 parameter [4:0] IS_INMODE_INVERTED = 5'b0;
462 parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
463
464 initial begin
465 `ifdef __ICARUS__
466 if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value");
467 //if (PREG != 0) $fatal(1, "Unsupported PREG value");
468 if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value");
469 if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value");
470 if (USE_PATTERN_DETECT != "NO_PATDET") $fatal(1, "Unsupported USE_PATTERN_DETECT value");
471 if (USE_SIMD != "ONE48") $fatal(1, "Unsupported USE_SIMD value");
472 if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value");
473 if (IS_CARRYIN_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CARRYIN_INVERTED value");
474 if (IS_CLK_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CLK_INVERTED value");
475 if (IS_INMODE_INVERTED != 5'b0) $fatal(1, "Unsupported IS_INMODE_INVERTED value");
476 if (IS_OPMODE_INVERTED != 7'b0) $fatal(1, "Unsupported IS_OPMODE_INVERTED value");
477 `endif
478 end
479
480 wire signed [29:0] A_muxed;
481 wire signed [17:0] B_muxed;
482
483 generate
484 if (A_INPUT == "CASCADE") assign A_muxed = ACIN;
485 else assign A_muxed = A;
486
487 if (B_INPUT == "CASCADE") assign B_muxed = BCIN;
488 else assign B_muxed = B;
489 endgenerate
490
491 reg signed [29:0] Ar1 = 30'b0, Ar2 = 30'b0;
492 reg signed [24:0] Dr = 25'b0;
493 reg signed [17:0] Br1 = 18'b0, Br2 = 18'b0;
494 reg signed [47:0] Cr = 48'b0;
495 reg [4:0] INMODEr = 5'b0;
496 reg [6:0] OPMODEr = 7'b0;
497 reg [3:0] ALUMODEr = 4'b0;
498 reg [2:0] CARRYINSELr = 3'b0;
499
500 generate
501 // Configurable A register
502 if (AREG == 2) begin
503 always @(posedge CLK)
504 if (RSTA) begin
505 Ar1 <= 30'b0;
506 Ar2 <= 30'b0;
507 end else begin
508 if (CEA1) Ar1 <= A_muxed;
509 if (CEA2) Ar2 <= Ar1;
510 end
511 end else if (AREG == 1) begin
512 always @(posedge CLK)
513 if (RSTA) begin
514 Ar1 <= 30'b0;
515 Ar2 <= 30'b0;
516 end else begin
517 if (CEA1) Ar1 <= A_muxed;
518 if (CEA2) Ar2 <= A_muxed;
519 end
520 end else begin
521 always @* Ar1 <= A_muxed;
522 always @* Ar2 <= A_muxed;
523 end
524
525 // Configurable A register
526 if (BREG == 2) begin
527 always @(posedge CLK)
528 if (RSTB) begin
529 Br1 <= 18'b0;
530 Br2 <= 18'b0;
531 end else begin
532 if (CEB1) Br1 <= B_muxed;
533 if (CEB2) Br2 <= Br1;
534 end
535 end else if (AREG == 1) begin
536 always @(posedge CLK)
537 if (RSTB) begin
538 Br1 <= 18'b0;
539 Br2 <= 18'b0;
540 end else begin
541 if (CEB1) Br1 <= B_muxed;
542 if (CEB2) Br2 <= B_muxed;
543 end
544 end else begin
545 always @* Br1 <= B_muxed;
546 always @* Br2 <= B_muxed;
547 end
548
549 // C and D registers
550 if (CREG == 1) begin always @(posedge CLK) if (RSTC) Cr <= 48'b0; else if (CEC) Cr <= D; end
551 else always @* Cr <= C;
552
553 if (DREG == 1) begin always @(posedge CLK) if (RSTD) Dr <= 25'b0; else if (CED) Dr <= D; end
554 else always @* Dr <= D;
555
556 // Control registers
557 if (INMODEREG == 1) begin always @(posedge CLK) if (RSTINMODE) INMODEr <= 5'b0; else if (CEINMODE) INMODEr <= INMODE; end
558 else always @* INMODEr <= INMODE;
559 if (OPMODEREG == 1) begin always @(posedge CLK) if (RSTCTRL) OPMODEr <= 7'b0; else if (CECTRL) OPMODEr <= OPMODE; end
560 else always @* OPMODEr <= OPMODE;
561 if (ALUMODEREG == 1) begin always @(posedge CLK) if (RSTALUMODE) ALUMODEr <= 4'b0; else if (CEALUMODE) ALUMODEr <= ALUMODE; end
562 else always @* ALUMODEr <= ALUMODE;
563 if (CARRYINSELREG == 1) begin always @(posedge CLK) if (RSTCTRL) CARRYINSELr <= 3'b0; else if (CECTRL) CARRYINSELr <= CARRYINSEL; end
564 else always @* CARRYINSELr <= CARRYINSEL;
565 endgenerate
566
567 // A and B cascsde
568 generate
569 if (ACASCREG == 1 && AREG == 2) assign ACOUT = Ar1;
570 else assign ACOUT = Ar2;
571 if (BCASCREG == 1 && BREG == 2) assign BCOUT = Br1;
572 else assign BCOUT = Br2;
573 endgenerate
574
575 // A/D input selection and pre-adder
576 wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2;
577 wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed;
578 wire signed [24:0] Dr_gated = INMODEr[2] ? Dr : 25'b0;
579 wire signed [24:0] AD_result = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated);
580 reg signed [24:0] ADr = 25'b0;
581
582 generate
583 if (ADREG == 1) begin always @(posedge CLK) if (RSTD) ADr <= 25'b0; else if (CEAD) ADr <= AD_result; end
584 else always @* ADr <= AD_result;
585 endgenerate
586
587 // 25x18 multiplier
588 wire signed [24:0] A_MULT;
589 wire signed [17:0] B_MULT = INMODEr[4] ? Br1 : Br2;
590 generate
591 if (USE_DPORT == "TRUE") assign A_MULT = ADr;
592 else assign A_MULT = Ar12_gated;
593 endgenerate
594
595 wire signed [42:0] M = A_MULT * B_MULT;
596 reg signed [42:0] Mr = 43'b0;
597
598 // Multiplier result register
599 generate
600 if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= M; end
601 else always @* Mr <= M;
602 endgenerate
603
604 // X, Y and Z ALU inputs
605 reg signed [47:0] X, Y, Z;
606
607 always @* begin
608 // X multiplexer
609 case (OPMODEr[1:0])
610 2'b00: X = 48'b0;
611 2'b01: begin X = $signed(M);
612 `ifdef __ICARUS__
613 if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
614 `endif
615 end
616 2'b10: begin X = P;
617 `ifdef __ICARUS__
618 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
619 `endif
620 end
621 2'b11: X = $signed({Ar2, Br2});
622 default: X = 48'bx;
623 endcase
624
625 // Y multiplexer
626 case (OPMODEr[3:2])
627 2'b00: Y = 48'b0;
628 2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
629 `ifdef __ICARUS__
630 if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
631 `endif
632 end
633 2'b10: Y = {48{1'b1}};
634 2'b11: Y = C;
635 default: Y = 48'bx;
636 endcase
637
638 // Z multiplexer
639 case (OPMODEr[6:4])
640 3'b000: Z = 48'b0;
641 3'b001: Z = PCIN;
642 3'b010: begin Z = P;
643 `ifdef __ICARUS__
644 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
645 `endif
646 end
647 3'b011: Z = C;
648 3'b100: begin Z = P;
649 `ifdef __ICARUS__
650 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
651 if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
652 `endif
653 end
654 3'b101: Z = $signed(PCIN[47:17]);
655 3'b110: Z = $signed(P[47:17]);
656 default: Z = 48'bx;
657 endcase
658 end
659
660 // Carry in
661 wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
662 reg CARRYINr, A24_xnor_B17;
663 generate
664 if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
665 else always @* CARRYINr = CARRYIN;
666
667 if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CECARRYIN) A24_xnor_B17 <= A24_xnor_B17d; end
668 else always @* A24_xnor_B17 = A24_xnor_B17d;
669 endgenerate
670
671 reg cin_muxed;
672
673 always @(*) begin
674 case (CARRYINSELr)
675 3'b000: cin_muxed = CARRYINr;
676 3'b001: cin_muxed = ~PCIN[47];
677 3'b010: cin_muxed = CARRYCASCIN;
678 3'b011: cin_muxed = PCIN[47];
679 3'b100: cin_muxed = CARRYCASCOUT;
680 3'b101: cin_muxed = ~P[47];
681 3'b110: cin_muxed = A24_xnor_B17;
682 3'b111: cin_muxed = P[47];
683 default: cin_muxed = 1'bx;
684 endcase
685 end
686
687 wire alu_cin = (ALUMODEr[3] || ALUMODEr[2]) ? 1'b0 : cin_muxed;
688
689 // ALU core
690 wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
691 wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
692 wire [47:0] maj_xyz = (X & Y) | (X & Z_muxinv) | (Y & Z_muxinv);
693
694 wire [47:0] xor_xyz_muxed = ALUMODEr[3] ? maj_xyz : xor_xyz;
695 wire [47:0] maj_xyz_gated = ALUMODEr[2] ? 48'b0 : maj_xyz;
696
697 wire [48:0] maj_xyz_simd_gated;
698 wire [3:0] int_carry_in, int_carry_out, ext_carry_out;
699 wire [47:0] alu_sum;
700 assign int_carry_in[0] = 1'b0;
701
702 generate
703 if (USE_SIMD == "FOUR12") begin
704 assign maj_xyz_simd_gated = {
705 maj_xyz_gated[47:36],
706 1'b0, maj_xyz_gated[34:24],
707 1'b0, maj_xyz_gated[22:12],
708 1'b0, maj_xyz_gated[10:0],
709 alu_cin
710 };
711 assign int_carry_in[3:1] = 3'b000;
712 assign ext_carry_out = {
713 int_carry_out[3],
714 maj_xyz_gated[35] ^ int_carry_out[2],
715 maj_xyz_gated[23] ^ int_carry_out[1],
716 maj_xyz_gated[11] ^ int_carry_out[0]
717 };
718 end else if (USE_SIMD == "TWO24") begin
719 assign maj_xyz_simd_gated = {
720 maj_xyz_gated[47:24],
721 1'b0, maj_xyz_gated[22:0],
722 alu_cin
723 };
724 assign int_carry_in[3:1] = {int_carry_out[2], 1'b0, int_carry_out[0]};
725 assign ext_carry_out = {
726 int_carry_out[3],
727 1'bx,
728 maj_xyz_gated[23] ^ int_carry_out[1],
729 1'bx
730 };
731 end else begin
732 assign maj_xyz_simd_gated = {maj_xyz_gated, alu_cin};
733 assign int_carry_in[3:1] = int_carry_out[2:0];
734 assign ext_carry_out = {
735 int_carry_out[3],
736 3'bxxx
737 };
738 end
739
740 genvar i;
741 for (i = 0; i < 4; i = i + 1)
742 assign {int_carry_out[i], alu_sum[i*12 +: 12]} = {1'b0, maj_xyz_simd_gated[i*12 +: ((i == 3) ? 13 : 12)]}
743 + xor_xyz_muxed[i*12 +: 12] + int_carry_in[i];
744 endgenerate
745
746 wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
747 initial P = 48'b0;
748 wire [3:0] CARRYOUTd = (OPMODEr[3:0] == 4'b0101 || ALUMODEr[3:2] != 2'b00) ? 4'bxxxx :
749 ((ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out);
750 wire CARRYCASCOUTd = ext_carry_out[3];
751 wire MULTSIGNOUTd = Mr[42];
752
753 generate
754 if (PREG == 1) begin
755 always @(posedge CLK)
756 if (RSTP) begin
757 P <= 48'b0;
758 CARRYOUT <= 4'b0;
759 CARRYCASCOUT <= 1'b0;
760 MULTSIGNOUT <= 1'b0;
761 end else if (CEP) begin
762 P <= Pd;
763 CARRYOUT <= CARRYOUTd;
764 CARRYCASCOUT <= CARRYCASCOUTd;
765 MULTSIGNOUT <= MULTSIGNOUTd;
766 end
767 end else begin
768 always @* begin
769 P = Pd;
770 CARRYOUT = CARRYOUTd;
771 CARRYCASCOUT = CARRYCASCOUTd;
772 MULTSIGNOUT = MULTSIGNOUTd;
773 end
774 end
775 endgenerate
776
777 endmodule