DSP48E1 model: test CE inputs
[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 <= C; 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 wire signed [42:0] Mx = (CARRYINSEL == 3'b010) ? 43'bx : M;
597 reg signed [42:0] Mr = 43'b0;
598
599 // Multiplier result register
600 generate
601 if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= Mx; end
602 else always @* Mr <= Mx;
603 endgenerate
604
605 wire signed [42:0] Mrx = (CARRYINSELr == 3'b010) ? 43'bx : Mr;
606
607 // X, Y and Z ALU inputs
608 reg signed [47:0] X, Y, Z;
609
610 always @* begin
611 // X multiplexer
612 case (OPMODEr[1:0])
613 2'b00: X = 48'b0;
614 2'b01: begin X = $signed(Mrx);
615 `ifdef __ICARUS__
616 if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
617 `endif
618 end
619 2'b10: begin X = P;
620 `ifdef __ICARUS__
621 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
622 `endif
623 end
624 2'b11: X = $signed({Ar2, Br2});
625 default: X = 48'bx;
626 endcase
627
628 // Y multiplexer
629 case (OPMODEr[3:2])
630 2'b00: Y = 48'b0;
631 2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling?
632 `ifdef __ICARUS__
633 if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
634 `endif
635 end
636 2'b10: Y = {48{1'b1}};
637 2'b11: Y = Cr;
638 default: Y = 48'bx;
639 endcase
640
641 // Z multiplexer
642 case (OPMODEr[6:4])
643 3'b000: Z = 48'b0;
644 3'b001: Z = PCIN;
645 3'b010: begin Z = P;
646 `ifdef __ICARUS__
647 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
648 `endif
649 end
650 3'b011: Z = Cr;
651 3'b100: begin Z = P;
652 `ifdef __ICARUS__
653 if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
654 if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
655 `endif
656 end
657 3'b101: Z = $signed(PCIN[47:17]);
658 3'b110: Z = $signed(P[47:17]);
659 default: Z = 48'bx;
660 endcase
661 end
662
663 // Carry in
664 wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17];
665 reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0;
666 generate
667 if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end
668 else always @* CARRYINr = CARRYIN;
669
670 if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end
671 else always @* A24_xnor_B17 = A24_xnor_B17d;
672 endgenerate
673
674 reg cin_muxed;
675
676 always @(*) begin
677 case (CARRYINSELr)
678 3'b000: cin_muxed = CARRYINr;
679 3'b001: cin_muxed = ~PCIN[47];
680 3'b010: cin_muxed = CARRYCASCIN;
681 3'b011: cin_muxed = PCIN[47];
682 3'b100: cin_muxed = CARRYCASCOUT;
683 3'b101: cin_muxed = ~P[47];
684 3'b110: cin_muxed = A24_xnor_B17;
685 3'b111: cin_muxed = P[47];
686 default: cin_muxed = 1'bx;
687 endcase
688 end
689
690 wire alu_cin = (ALUMODEr[3] || ALUMODEr[2]) ? 1'b0 : cin_muxed;
691
692 // ALU core
693 wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
694 wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
695 wire [47:0] maj_xyz = (X & Y) | (X & Z_muxinv) | (Y & Z_muxinv);
696
697 wire [47:0] xor_xyz_muxed = ALUMODEr[3] ? maj_xyz : xor_xyz;
698 wire [47:0] maj_xyz_gated = ALUMODEr[2] ? 48'b0 : maj_xyz;
699
700 wire [48:0] maj_xyz_simd_gated;
701 wire [3:0] int_carry_in, int_carry_out, ext_carry_out;
702 wire [47:0] alu_sum;
703 assign int_carry_in[0] = 1'b0;
704 wire [3:0] carryout_reset;
705
706 generate
707 if (USE_SIMD == "FOUR12") begin
708 assign maj_xyz_simd_gated = {
709 maj_xyz_gated[47:36],
710 1'b0, maj_xyz_gated[34:24],
711 1'b0, maj_xyz_gated[22:12],
712 1'b0, maj_xyz_gated[10:0],
713 alu_cin
714 };
715 assign int_carry_in[3:1] = 3'b000;
716 assign ext_carry_out = {
717 int_carry_out[3],
718 maj_xyz_gated[35] ^ int_carry_out[2],
719 maj_xyz_gated[23] ^ int_carry_out[1],
720 maj_xyz_gated[11] ^ int_carry_out[0]
721 };
722 assign carryout_reset = 4'b0000;
723 end else if (USE_SIMD == "TWO24") begin
724 assign maj_xyz_simd_gated = {
725 maj_xyz_gated[47:24],
726 1'b0, maj_xyz_gated[22:0],
727 alu_cin
728 };
729 assign int_carry_in[3:1] = {int_carry_out[2], 1'b0, int_carry_out[0]};
730 assign ext_carry_out = {
731 int_carry_out[3],
732 1'bx,
733 maj_xyz_gated[23] ^ int_carry_out[1],
734 1'bx
735 };
736 assign carryout_reset = 4'b0x0x;
737 end else begin
738 assign maj_xyz_simd_gated = {maj_xyz_gated, alu_cin};
739 assign int_carry_in[3:1] = int_carry_out[2:0];
740 assign ext_carry_out = {
741 int_carry_out[3],
742 3'bxxx
743 };
744 assign carryout_reset = 4'b0xxx;
745 end
746
747 genvar i;
748 for (i = 0; i < 4; i = i + 1)
749 assign {int_carry_out[i], alu_sum[i*12 +: 12]} = {1'b0, maj_xyz_simd_gated[i*12 +: ((i == 3) ? 13 : 12)]}
750 + xor_xyz_muxed[i*12 +: 12] + int_carry_in[i];
751 endgenerate
752
753 wire signed [47:0] Pd = ALUMODEr[1] ? ~alu_sum : alu_sum;
754 initial P = 48'b0;
755 initial CARRYOUT = carryout_reset;
756 initial CARRYCASCOUT = 1'b0;
757 initial MULTSIGNOUT = 1'b0;
758 wire [3:0] CARRYOUTd = (OPMODEr[3:0] == 4'b0101 || ALUMODEr[3:2] != 2'b00) ? 4'bxxxx :
759 ((ALUMODEr[0] & ALUMODEr[1]) ? ~ext_carry_out : ext_carry_out);
760 wire CARRYCASCOUTd = ext_carry_out[3];
761 wire MULTSIGNOUTd = Mrx[42];
762
763 generate
764 if (PREG == 1) begin
765 always @(posedge CLK)
766 if (RSTP) begin
767 P <= 48'b0;
768 CARRYOUT <= carryout_reset;
769 CARRYCASCOUT <= 1'b0;
770 MULTSIGNOUT <= 1'b0;
771 end else if (CEP) begin
772 P <= Pd;
773 CARRYOUT <= CARRYOUTd;
774 CARRYCASCOUT <= CARRYCASCOUTd;
775 MULTSIGNOUT <= MULTSIGNOUTd;
776 end
777 end else begin
778 always @* begin
779 P = Pd;
780 CARRYOUT = CARRYOUTd;
781 CARRYCASCOUT = CARRYCASCOUTd;
782 MULTSIGNOUT = MULTSIGNOUTd;
783 end
784 end
785 endgenerate
786
787 endmodule