1/*
2 *  yosys -- Yosys Open SYnthesis Suite
3 *
4 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
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 *  The Simulation Library.
21 *
22 *  This Verilog library contains simple simulation models for the internal
23 *  cells ($not, ...) generated by the frontends and used in most passes.
24 *
25 *  This library can be used to verify the internal netlists as generated
26 *  by the different frontends and passes.
27 *
28 *  Note that memory can only be simulated when all $memrd and $memwr cells
29 *  have been merged to stand-alone $mem cells (this is what the "memory_collect"
30 *  pass is doing).
31 *
32 */
33
34// --------------------------------------------------------
35
36//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
37//-
38//-     $not (A, Y)
39//-
40//- A bit-wise inverter. This corresponds to the Verilog unary prefix '~' operator.
41//-
42module \$not (A, Y);
43
44parameter A_SIGNED = 0;
45parameter A_WIDTH = 0;
46parameter Y_WIDTH = 0;
47
48input [A_WIDTH-1:0] A;
49output [Y_WIDTH-1:0] Y;
50
51generate
52	if (A_SIGNED) begin:BLOCK1
53		assign Y = ~$signed(A);
54	end else begin:BLOCK2
55		assign Y = ~A;
56	end
57endgenerate
58
59endmodule
60
61
62// --------------------------------------------------------
63
64//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
65//-
66//-     $pos (A, Y)
67//-
68//- A buffer. This corresponds to the Verilog unary prefix '+' operator.
69//-
70module \$pos (A, Y);
71
72parameter A_SIGNED = 0;
73parameter A_WIDTH = 0;
74parameter Y_WIDTH = 0;
75
76input [A_WIDTH-1:0] A;
77output [Y_WIDTH-1:0] Y;
78
79generate
80	if (A_SIGNED) begin:BLOCK1
81		assign Y = $signed(A);
82	end else begin:BLOCK2
83		assign Y = A;
84	end
85endgenerate
86
87endmodule
88
89// --------------------------------------------------------
90
91//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
92//-
93//-     $neg (A, Y)
94//-
95//- An arithmetic inverter. This corresponds to the Verilog unary prefix '-' operator.
96//-
97module \$neg (A, Y);
98
99parameter A_SIGNED = 0;
100parameter A_WIDTH = 0;
101parameter Y_WIDTH = 0;
102
103input [A_WIDTH-1:0] A;
104output [Y_WIDTH-1:0] Y;
105
106generate
107	if (A_SIGNED) begin:BLOCK1
108		assign Y = -$signed(A);
109	end else begin:BLOCK2
110		assign Y = -A;
111	end
112endgenerate
113
114endmodule
115
116// --------------------------------------------------------
117
118//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
119//-
120//-     $and (A, B, Y)
121//-
122//- A bit-wise AND. This corresponds to the Verilog '&' operator.
123//-
124module \$and (A, B, Y);
125
126parameter A_SIGNED = 0;
127parameter B_SIGNED = 0;
128parameter A_WIDTH = 0;
129parameter B_WIDTH = 0;
130parameter Y_WIDTH = 0;
131
132input [A_WIDTH-1:0] A;
133input [B_WIDTH-1:0] B;
134output [Y_WIDTH-1:0] Y;
135
136generate
137	if (A_SIGNED && B_SIGNED) begin:BLOCK1
138		assign Y = $signed(A) & $signed(B);
139	end else begin:BLOCK2
140		assign Y = A & B;
141	end
142endgenerate
143
144endmodule
145
146// --------------------------------------------------------
147
148//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
149//-
150//-     $or (A, B, Y)
151//-
152//- A bit-wise OR. This corresponds to the Verilog '|' operator.
153//-
154module \$or (A, B, Y);
155
156parameter A_SIGNED = 0;
157parameter B_SIGNED = 0;
158parameter A_WIDTH = 0;
159parameter B_WIDTH = 0;
160parameter Y_WIDTH = 0;
161
162input [A_WIDTH-1:0] A;
163input [B_WIDTH-1:0] B;
164output [Y_WIDTH-1:0] Y;
165
166generate
167	if (A_SIGNED && B_SIGNED) begin:BLOCK1
168		assign Y = $signed(A) | $signed(B);
169	end else begin:BLOCK2
170		assign Y = A | B;
171	end
172endgenerate
173
174endmodule
175
176// --------------------------------------------------------
177
178//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
179//-
180//-     $xor (A, B, Y)
181//-
182//- A bit-wise XOR. This corresponds to the Verilog '^' operator.
183//-
184module \$xor (A, B, Y);
185
186parameter A_SIGNED = 0;
187parameter B_SIGNED = 0;
188parameter A_WIDTH = 0;
189parameter B_WIDTH = 0;
190parameter Y_WIDTH = 0;
191
192input [A_WIDTH-1:0] A;
193input [B_WIDTH-1:0] B;
194output [Y_WIDTH-1:0] Y;
195
196generate
197	if (A_SIGNED && B_SIGNED) begin:BLOCK1
198		assign Y = $signed(A) ^ $signed(B);
199	end else begin:BLOCK2
200		assign Y = A ^ B;
201	end
202endgenerate
203
204endmodule
205
206// --------------------------------------------------------
207
208//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
209//-
210//-     $xnor (A, B, Y)
211//-
212//- A bit-wise XNOR. This corresponds to the Verilog '~^' operator.
213//-
214module \$xnor (A, B, Y);
215
216parameter A_SIGNED = 0;
217parameter B_SIGNED = 0;
218parameter A_WIDTH = 0;
219parameter B_WIDTH = 0;
220parameter Y_WIDTH = 0;
221
222input [A_WIDTH-1:0] A;
223input [B_WIDTH-1:0] B;
224output [Y_WIDTH-1:0] Y;
225
226generate
227	if (A_SIGNED && B_SIGNED) begin:BLOCK1
228		assign Y = $signed(A) ~^ $signed(B);
229	end else begin:BLOCK2
230		assign Y = A ~^ B;
231	end
232endgenerate
233
234endmodule
235
236// --------------------------------------------------------
237
238//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
239//-
240//-     $reduce_and (A, Y)
241//-
242//- An AND reduction. This corresponds to the Verilog unary prefix '&' operator.
243//-
244module \$reduce_and (A, Y);
245
246parameter A_SIGNED = 0;
247parameter A_WIDTH = 0;
248parameter Y_WIDTH = 0;
249
250input [A_WIDTH-1:0] A;
251output [Y_WIDTH-1:0] Y;
252
253generate
254	if (A_SIGNED) begin:BLOCK1
255		assign Y = &$signed(A);
256	end else begin:BLOCK2
257		assign Y = &A;
258	end
259endgenerate
260
261endmodule
262
263// --------------------------------------------------------
264
265//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
266//-
267//-     $reduce_or (A, Y)
268//-
269//- An OR reduction. This corresponds to the Verilog unary prefix '|' operator.
270//-
271module \$reduce_or (A, Y);
272
273parameter A_SIGNED = 0;
274parameter A_WIDTH = 0;
275parameter Y_WIDTH = 0;
276
277input [A_WIDTH-1:0] A;
278output [Y_WIDTH-1:0] Y;
279
280generate
281	if (A_SIGNED) begin:BLOCK1
282		assign Y = |$signed(A);
283	end else begin:BLOCK2
284		assign Y = |A;
285	end
286endgenerate
287
288endmodule
289
290// --------------------------------------------------------
291
292//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
293//-
294//-     $reduce_xor (A, Y)
295//-
296//- A XOR reduction. This corresponds to the Verilog unary prefix '^' operator.
297//-
298module \$reduce_xor (A, Y);
299
300parameter A_SIGNED = 0;
301parameter A_WIDTH = 0;
302parameter Y_WIDTH = 0;
303
304input [A_WIDTH-1:0] A;
305output [Y_WIDTH-1:0] Y;
306
307generate
308	if (A_SIGNED) begin:BLOCK1
309		assign Y = ^$signed(A);
310	end else begin:BLOCK2
311		assign Y = ^A;
312	end
313endgenerate
314
315endmodule
316
317// --------------------------------------------------------
318
319//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
320//-
321//-     $reduce_xnor (A, Y)
322//-
323//- A XNOR reduction. This corresponds to the Verilog unary prefix '~^' operator.
324//-
325module \$reduce_xnor (A, Y);
326
327parameter A_SIGNED = 0;
328parameter A_WIDTH = 0;
329parameter Y_WIDTH = 0;
330
331input [A_WIDTH-1:0] A;
332output [Y_WIDTH-1:0] Y;
333
334generate
335	if (A_SIGNED) begin:BLOCK1
336		assign Y = ~^$signed(A);
337	end else begin:BLOCK2
338		assign Y = ~^A;
339	end
340endgenerate
341
342endmodule
343
344// --------------------------------------------------------
345
346//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
347//-
348//-     $reduce_bool (A, Y)
349//-
350//- An OR reduction. This cell type is used instead of $reduce_or when a signal is
351//- implicitly converted to a boolean signal, e.g. for operands of '&&' and '||'.
352//-
353module \$reduce_bool (A, Y);
354
355parameter A_SIGNED = 0;
356parameter A_WIDTH = 0;
357parameter Y_WIDTH = 0;
358
359input [A_WIDTH-1:0] A;
360output [Y_WIDTH-1:0] Y;
361
362generate
363	if (A_SIGNED) begin:BLOCK1
364		assign Y = !(!$signed(A));
365	end else begin:BLOCK2
366		assign Y = !(!A);
367	end
368endgenerate
369
370endmodule
371
372// --------------------------------------------------------
373
374module \$shl (A, B, Y);
375
376parameter A_SIGNED = 0;
377parameter B_SIGNED = 0;
378parameter A_WIDTH = 0;
379parameter B_WIDTH = 0;
380parameter Y_WIDTH = 0;
381
382input [A_WIDTH-1:0] A;
383input [B_WIDTH-1:0] B;
384output [Y_WIDTH-1:0] Y;
385
386generate
387	if (A_SIGNED) begin:BLOCK1
388		assign Y = $signed(A) << B;
389	end else begin:BLOCK2
390		assign Y = A << B;
391	end
392endgenerate
393
394endmodule
395
396// --------------------------------------------------------
397
398module \$shr (A, B, Y);
399
400parameter A_SIGNED = 0;
401parameter B_SIGNED = 0;
402parameter A_WIDTH = 0;
403parameter B_WIDTH = 0;
404parameter Y_WIDTH = 0;
405
406input [A_WIDTH-1:0] A;
407input [B_WIDTH-1:0] B;
408output [Y_WIDTH-1:0] Y;
409
410generate
411	if (A_SIGNED) begin:BLOCK1
412		assign Y = $signed(A) >> B;
413	end else begin:BLOCK2
414		assign Y = A >> B;
415	end
416endgenerate
417
418endmodule
419
420// --------------------------------------------------------
421
422module \$sshl (A, B, Y);
423
424parameter A_SIGNED = 0;
425parameter B_SIGNED = 0;
426parameter A_WIDTH = 0;
427parameter B_WIDTH = 0;
428parameter Y_WIDTH = 0;
429
430input [A_WIDTH-1:0] A;
431input [B_WIDTH-1:0] B;
432output [Y_WIDTH-1:0] Y;
433
434generate
435	if (A_SIGNED) begin:BLOCK1
436		assign Y = $signed(A) <<< B;
437	end else begin:BLOCK2
438		assign Y = A <<< B;
439	end
440endgenerate
441
442endmodule
443
444// --------------------------------------------------------
445
446module \$sshr (A, B, Y);
447
448parameter A_SIGNED = 0;
449parameter B_SIGNED = 0;
450parameter A_WIDTH = 0;
451parameter B_WIDTH = 0;
452parameter Y_WIDTH = 0;
453
454input [A_WIDTH-1:0] A;
455input [B_WIDTH-1:0] B;
456output [Y_WIDTH-1:0] Y;
457
458generate
459	if (A_SIGNED) begin:BLOCK1
460		assign Y = $signed(A) >>> B;
461	end else begin:BLOCK2
462		assign Y = A >>> B;
463	end
464endgenerate
465
466endmodule
467
468// --------------------------------------------------------
469
470module \$shift (A, B, Y);
471
472parameter A_SIGNED = 0;
473parameter B_SIGNED = 0;
474parameter A_WIDTH = 0;
475parameter B_WIDTH = 0;
476parameter Y_WIDTH = 0;
477
478input [A_WIDTH-1:0] A;
479input [B_WIDTH-1:0] B;
480output [Y_WIDTH-1:0] Y;
481
482generate
483	if (A_SIGNED) begin:BLOCK1
484		if (B_SIGNED) begin:BLOCK2
485			assign Y = $signed(B) < 0 ? $signed(A) << -B : $signed(A) >> B;
486		end else begin:BLOCK3
487			assign Y = $signed(A) >> B;
488		end
489	end else begin:BLOCK4
490		if (B_SIGNED) begin:BLOCK5
491			assign Y = $signed(B) < 0 ? A << -B : A >> B;
492		end else begin:BLOCK6
493			assign Y = A >> B;
494		end
495	end
496endgenerate
497
498endmodule
499
500// --------------------------------------------------------
501
502module \$shiftx (A, B, Y);
503
504parameter A_SIGNED = 0;
505parameter B_SIGNED = 0;
506parameter A_WIDTH = 0;
507parameter B_WIDTH = 0;
508parameter Y_WIDTH = 0;
509
510input [A_WIDTH-1:0] A;
511input [B_WIDTH-1:0] B;
512output [Y_WIDTH-1:0] Y;
513
514generate
515	if (Y_WIDTH > 0)
516		if (B_SIGNED) begin:BLOCK1
517			assign Y = A[$signed(B) +: Y_WIDTH];
518		end else begin:BLOCK2
519			assign Y = A[B +: Y_WIDTH];
520		end
521endgenerate
522
523endmodule
524
525// --------------------------------------------------------
526
527module \$fa (A, B, C, X, Y);
528
529parameter WIDTH = 1;
530
531input [WIDTH-1:0] A, B, C;
532output [WIDTH-1:0] X, Y;
533
534wire [WIDTH-1:0] t1, t2, t3;
535
536assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
537assign Y = t1 ^ C, X = (t2 | t3) ^ (Y ^ Y);
538
539endmodule
540
541// --------------------------------------------------------
542
543//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
544//-
545//-     $lcu (P, G, CI, CO)
546//-
547//- Lookahead carry unit
548//- A building block dedicated to fast computation of carry-bits used in binary
549//- arithmetic operations. By replacing the ripple carry structure used in full-adder
550//- blocks, the more significant  bits of the sum can be expected to be computed more
551//- quickly.
552//- Typically created during `techmap` of $alu cells (see the "_90_alu" rule in
553//- +/techmap.v).
554module \$lcu (P, G, CI, CO);
555
556parameter WIDTH = 1;
557
558input [WIDTH-1:0] P;    // Propagate
559input [WIDTH-1:0] G;    // Generate
560input CI;               // Carry-in
561
562output reg [WIDTH-1:0] CO; // Carry-out
563
564integer i;
565always @* begin
566	CO = 'bx;
567	if (^{P, G, CI} !== 1'bx) begin
568		CO[0] = G[0] || (P[0] && CI);
569		for (i = 1; i < WIDTH; i = i+1)
570			CO[i] = G[i] || (P[i] && CO[i-1]);
571	end
572end
573
574endmodule
575
576// --------------------------------------------------------
577
578//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
579//-
580//-     $alu (A, B, CI, BI, X, Y, CO)
581//-
582//- Arithmetic logic unit.
583//- A building block supporting both binary addition/subtraction operations, and
584//- indirectly, comparison operations.
585//- Typically created by the `alumacc` pass, which transforms:
586//-   $add, $sub, $lt, $le, $ge, $gt, $eq, $eqx, $ne, $nex
587//- cells into this $alu cell.
588//-
589module \$alu (A, B, CI, BI, X, Y, CO);
590
591parameter A_SIGNED = 0;
592parameter B_SIGNED = 0;
593parameter A_WIDTH = 1;
594parameter B_WIDTH = 1;
595parameter Y_WIDTH = 1;
596
597input [A_WIDTH-1:0] A;      // Input operand
598input [B_WIDTH-1:0] B;      // Input operand
599output [Y_WIDTH-1:0] X;     // A xor B (sign-extended, optional B inversion,
600                            //          used in combination with
601                            //          reduction-AND for $eq/$ne ops)
602output [Y_WIDTH-1:0] Y;     // Sum
603
604input CI;                   // Carry-in (set for $sub)
605input BI;                   // Invert-B (set for $sub)
606output [Y_WIDTH-1:0] CO;    // Carry-out
607
608wire [Y_WIDTH-1:0] AA, BB;
609
610generate
611	if (A_SIGNED && B_SIGNED) begin:BLOCK1
612		assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B);
613	end else begin:BLOCK2
614		assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B);
615	end
616endgenerate
617
618// this is 'x' if Y and CO should be all 'x', and '0' otherwise
619wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI};
620
621assign X = AA ^ BB;
622// Full adder
623assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}};
624
625function get_carry;
626	input a, b, c;
627	get_carry = (a&b) | (a&c) | (b&c);
628endfunction
629
630genvar i;
631generate
632	assign CO[0] = get_carry(AA[0], BB[0], CI) ^ y_co_undef;
633	for (i = 1; i < Y_WIDTH; i = i+1) begin:BLOCK3
634		assign CO[i] = get_carry(AA[i], BB[i], CO[i-1]) ^ y_co_undef;
635	end
636endgenerate
637
638endmodule
639
640// --------------------------------------------------------
641
642module \$lt (A, B, Y);
643
644parameter A_SIGNED = 0;
645parameter B_SIGNED = 0;
646parameter A_WIDTH = 0;
647parameter B_WIDTH = 0;
648parameter Y_WIDTH = 0;
649
650input [A_WIDTH-1:0] A;
651input [B_WIDTH-1:0] B;
652output [Y_WIDTH-1:0] Y;
653
654generate
655	if (A_SIGNED && B_SIGNED) begin:BLOCK1
656		assign Y = $signed(A) < $signed(B);
657	end else begin:BLOCK2
658		assign Y = A < B;
659	end
660endgenerate
661
662endmodule
663
664// --------------------------------------------------------
665
666module \$le (A, B, Y);
667
668parameter A_SIGNED = 0;
669parameter B_SIGNED = 0;
670parameter A_WIDTH = 0;
671parameter B_WIDTH = 0;
672parameter Y_WIDTH = 0;
673
674input [A_WIDTH-1:0] A;
675input [B_WIDTH-1:0] B;
676output [Y_WIDTH-1:0] Y;
677
678generate
679	if (A_SIGNED && B_SIGNED) begin:BLOCK1
680		assign Y = $signed(A) <= $signed(B);
681	end else begin:BLOCK2
682		assign Y = A <= B;
683	end
684endgenerate
685
686endmodule
687
688// --------------------------------------------------------
689
690module \$eq (A, B, Y);
691
692parameter A_SIGNED = 0;
693parameter B_SIGNED = 0;
694parameter A_WIDTH = 0;
695parameter B_WIDTH = 0;
696parameter Y_WIDTH = 0;
697
698input [A_WIDTH-1:0] A;
699input [B_WIDTH-1:0] B;
700output [Y_WIDTH-1:0] Y;
701
702generate
703	if (A_SIGNED && B_SIGNED) begin:BLOCK1
704		assign Y = $signed(A) == $signed(B);
705	end else begin:BLOCK2
706		assign Y = A == B;
707	end
708endgenerate
709
710endmodule
711
712// --------------------------------------------------------
713
714module \$ne (A, B, Y);
715
716parameter A_SIGNED = 0;
717parameter B_SIGNED = 0;
718parameter A_WIDTH = 0;
719parameter B_WIDTH = 0;
720parameter Y_WIDTH = 0;
721
722input [A_WIDTH-1:0] A;
723input [B_WIDTH-1:0] B;
724output [Y_WIDTH-1:0] Y;
725
726generate
727	if (A_SIGNED && B_SIGNED) begin:BLOCK1
728		assign Y = $signed(A) != $signed(B);
729	end else begin:BLOCK2
730		assign Y = A != B;
731	end
732endgenerate
733
734endmodule
735
736// --------------------------------------------------------
737
738module \$eqx (A, B, Y);
739
740parameter A_SIGNED = 0;
741parameter B_SIGNED = 0;
742parameter A_WIDTH = 0;
743parameter B_WIDTH = 0;
744parameter Y_WIDTH = 0;
745
746input [A_WIDTH-1:0] A;
747input [B_WIDTH-1:0] B;
748output [Y_WIDTH-1:0] Y;
749
750generate
751	if (A_SIGNED && B_SIGNED) begin:BLOCK1
752		assign Y = $signed(A) === $signed(B);
753	end else begin:BLOCK2
754		assign Y = A === B;
755	end
756endgenerate
757
758endmodule
759
760// --------------------------------------------------------
761
762module \$nex (A, B, Y);
763
764parameter A_SIGNED = 0;
765parameter B_SIGNED = 0;
766parameter A_WIDTH = 0;
767parameter B_WIDTH = 0;
768parameter Y_WIDTH = 0;
769
770input [A_WIDTH-1:0] A;
771input [B_WIDTH-1:0] B;
772output [Y_WIDTH-1:0] Y;
773
774generate
775	if (A_SIGNED && B_SIGNED) begin:BLOCK1
776		assign Y = $signed(A) !== $signed(B);
777	end else begin:BLOCK2
778		assign Y = A !== B;
779	end
780endgenerate
781
782endmodule
783
784// --------------------------------------------------------
785
786module \$ge (A, B, Y);
787
788parameter A_SIGNED = 0;
789parameter B_SIGNED = 0;
790parameter A_WIDTH = 0;
791parameter B_WIDTH = 0;
792parameter Y_WIDTH = 0;
793
794input [A_WIDTH-1:0] A;
795input [B_WIDTH-1:0] B;
796output [Y_WIDTH-1:0] Y;
797
798generate
799	if (A_SIGNED && B_SIGNED) begin:BLOCK1
800		assign Y = $signed(A) >= $signed(B);
801	end else begin:BLOCK2
802		assign Y = A >= B;
803	end
804endgenerate
805
806endmodule
807
808// --------------------------------------------------------
809
810module \$gt (A, B, Y);
811
812parameter A_SIGNED = 0;
813parameter B_SIGNED = 0;
814parameter A_WIDTH = 0;
815parameter B_WIDTH = 0;
816parameter Y_WIDTH = 0;
817
818input [A_WIDTH-1:0] A;
819input [B_WIDTH-1:0] B;
820output [Y_WIDTH-1:0] Y;
821
822generate
823	if (A_SIGNED && B_SIGNED) begin:BLOCK1
824		assign Y = $signed(A) > $signed(B);
825	end else begin:BLOCK2
826		assign Y = A > B;
827	end
828endgenerate
829
830endmodule
831
832// --------------------------------------------------------
833
834module \$add (A, B, Y);
835
836parameter A_SIGNED = 0;
837parameter B_SIGNED = 0;
838parameter A_WIDTH = 0;
839parameter B_WIDTH = 0;
840parameter Y_WIDTH = 0;
841
842input [A_WIDTH-1:0] A;
843input [B_WIDTH-1:0] B;
844output [Y_WIDTH-1:0] Y;
845
846generate
847	if (A_SIGNED && B_SIGNED) begin:BLOCK1
848		assign Y = $signed(A) + $signed(B);
849	end else begin:BLOCK2
850		assign Y = A + B;
851	end
852endgenerate
853
854endmodule
855
856// --------------------------------------------------------
857
858module \$sub (A, B, Y);
859
860parameter A_SIGNED = 0;
861parameter B_SIGNED = 0;
862parameter A_WIDTH = 0;
863parameter B_WIDTH = 0;
864parameter Y_WIDTH = 0;
865
866input [A_WIDTH-1:0] A;
867input [B_WIDTH-1:0] B;
868output [Y_WIDTH-1:0] Y;
869
870generate
871	if (A_SIGNED && B_SIGNED) begin:BLOCK1
872		assign Y = $signed(A) - $signed(B);
873	end else begin:BLOCK2
874		assign Y = A - B;
875	end
876endgenerate
877
878endmodule
879
880// --------------------------------------------------------
881
882module \$mul (A, B, Y);
883
884parameter A_SIGNED = 0;
885parameter B_SIGNED = 0;
886parameter A_WIDTH = 0;
887parameter B_WIDTH = 0;
888parameter Y_WIDTH = 0;
889
890input [A_WIDTH-1:0] A;
891input [B_WIDTH-1:0] B;
892output [Y_WIDTH-1:0] Y;
893
894generate
895	if (A_SIGNED && B_SIGNED) begin:BLOCK1
896		assign Y = $signed(A) * $signed(B);
897	end else begin:BLOCK2
898		assign Y = A * B;
899	end
900endgenerate
901
902endmodule
903
904// --------------------------------------------------------
905
906module \$macc (A, B, Y);
907
908parameter A_WIDTH = 0;
909parameter B_WIDTH = 0;
910parameter Y_WIDTH = 0;
911parameter CONFIG = 4'b0000;
912parameter CONFIG_WIDTH = 4;
913
914input [A_WIDTH-1:0] A;
915input [B_WIDTH-1:0] B;
916output reg [Y_WIDTH-1:0] Y;
917
918// Xilinx XSIM does not like $clog2() below..
919function integer my_clog2;
920	input integer v;
921	begin
922		if (v > 0)
923			v = v - 1;
924		my_clog2 = 0;
925		while (v) begin
926			v = v >> 1;
927			my_clog2 = my_clog2 + 1;
928		end
929	end
930endfunction
931
932localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1;
933localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits);
934localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1;
935
936function [2*num_ports*num_abits-1:0] get_port_offsets;
937	input [CONFIG_WIDTH-1:0] cfg;
938	integer i, cursor;
939	begin
940		cursor = 0;
941		get_port_offsets = 0;
942		for (i = 0; i < num_ports; i = i+1) begin
943			get_port_offsets[(2*i + 0)*num_abits +: num_abits] = cursor;
944			cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 +: num_bits];
945			get_port_offsets[(2*i + 1)*num_abits +: num_abits] = cursor;
946			cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits];
947		end
948	end
949endfunction
950
951localparam [2*num_ports*num_abits-1:0] port_offsets = get_port_offsets(CONFIG);
952
953`define PORT_IS_SIGNED   (0 + CONFIG[4 + i*(2 + 2*num_bits)])
954`define PORT_DO_SUBTRACT (0 + CONFIG[4 + i*(2 + 2*num_bits) + 1])
955`define PORT_SIZE_A      (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 +: num_bits])
956`define PORT_SIZE_B      (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits])
957`define PORT_OFFSET_A    (0 + port_offsets[2*i*num_abits +: num_abits])
958`define PORT_OFFSET_B    (0 + port_offsets[2*i*num_abits + num_abits +: num_abits])
959
960integer i, j;
961reg [Y_WIDTH-1:0] tmp_a, tmp_b;
962
963always @* begin
964	Y = 0;
965	for (i = 0; i < num_ports; i = i+1)
966	begin
967		tmp_a = 0;
968		tmp_b = 0;
969
970		for (j = 0; j < `PORT_SIZE_A; j = j+1)
971			tmp_a[j] = A[`PORT_OFFSET_A + j];
972
973		if (`PORT_IS_SIGNED && `PORT_SIZE_A > 0)
974			for (j = `PORT_SIZE_A; j < Y_WIDTH; j = j+1)
975				tmp_a[j] = tmp_a[`PORT_SIZE_A-1];
976
977		for (j = 0; j < `PORT_SIZE_B; j = j+1)
978			tmp_b[j] = A[`PORT_OFFSET_B + j];
979
980		if (`PORT_IS_SIGNED && `PORT_SIZE_B > 0)
981			for (j = `PORT_SIZE_B; j < Y_WIDTH; j = j+1)
982				tmp_b[j] = tmp_b[`PORT_SIZE_B-1];
983
984		if (`PORT_SIZE_B > 0)
985			tmp_a = tmp_a * tmp_b;
986
987		if (`PORT_DO_SUBTRACT)
988			Y = Y - tmp_a;
989		else
990			Y = Y + tmp_a;
991	end
992	for (i = 0; i < B_WIDTH; i = i+1) begin
993		Y = Y + B[i];
994	end
995end
996
997`undef PORT_IS_SIGNED
998`undef PORT_DO_SUBTRACT
999`undef PORT_SIZE_A
1000`undef PORT_SIZE_B
1001`undef PORT_OFFSET_A
1002`undef PORT_OFFSET_B
1003
1004endmodule
1005
1006// --------------------------------------------------------
1007
1008//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1009//-
1010//-     $div (A, B, Y)
1011//-
1012//- Division with truncated result (rounded towards 0).
1013//-
1014module \$div (A, B, Y);
1015
1016parameter A_SIGNED = 0;
1017parameter B_SIGNED = 0;
1018parameter A_WIDTH = 0;
1019parameter B_WIDTH = 0;
1020parameter Y_WIDTH = 0;
1021
1022input [A_WIDTH-1:0] A;
1023input [B_WIDTH-1:0] B;
1024output [Y_WIDTH-1:0] Y;
1025
1026generate
1027	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1028		assign Y = $signed(A) / $signed(B);
1029	end else begin:BLOCK2
1030		assign Y = A / B;
1031	end
1032endgenerate
1033
1034endmodule
1035
1036// --------------------------------------------------------
1037
1038//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1039//-
1040//-     $mod (A, B, Y)
1041//-
1042//- Modulo/remainder of division with truncated result (rounded towards 0).
1043//-
1044//- Invariant: $div(A, B) * B + $mod(A, B) == A
1045//-
1046module \$mod (A, B, Y);
1047
1048parameter A_SIGNED = 0;
1049parameter B_SIGNED = 0;
1050parameter A_WIDTH = 0;
1051parameter B_WIDTH = 0;
1052parameter Y_WIDTH = 0;
1053
1054input [A_WIDTH-1:0] A;
1055input [B_WIDTH-1:0] B;
1056output [Y_WIDTH-1:0] Y;
1057
1058generate
1059	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1060		assign Y = $signed(A) % $signed(B);
1061	end else begin:BLOCK2
1062		assign Y = A % B;
1063	end
1064endgenerate
1065
1066endmodule
1067
1068// --------------------------------------------------------
1069
1070//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1071//-
1072//-     $divfloor (A, B, Y)
1073//-
1074//- Division with floored result (rounded towards negative infinity).
1075//-
1076module \$divfloor (A, B, Y);
1077
1078parameter A_SIGNED = 0;
1079parameter B_SIGNED = 0;
1080parameter A_WIDTH = 0;
1081parameter B_WIDTH = 0;
1082parameter Y_WIDTH = 0;
1083
1084input [A_WIDTH-1:0] A;
1085input [B_WIDTH-1:0] B;
1086output [Y_WIDTH-1:0] Y;
1087
1088generate
1089	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1090		localparam WIDTH =
1091				A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
1092				B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
1093		wire [WIDTH:0] A_buf, B_buf, N_buf;
1094		assign A_buf = $signed(A);
1095		assign B_buf = $signed(B);
1096		assign N_buf = (A[A_WIDTH-1] == B[B_WIDTH-1]) || A == 0 ? A_buf : $signed(A_buf - (B[B_WIDTH-1] ? B_buf+1 : B_buf-1));
1097		assign Y = $signed(N_buf) / $signed(B_buf);
1098	end else begin:BLOCK2
1099		assign Y = A / B;
1100	end
1101endgenerate
1102
1103endmodule
1104
1105// --------------------------------------------------------
1106
1107//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1108//-
1109//-     $modfloor (A, B, Y)
1110//-
1111//- Modulo/remainder of division with floored result (rounded towards negative infinity).
1112//-
1113//- Invariant: $divfloor(A, B) * B + $modfloor(A, B) == A
1114//-
1115module \$modfloor (A, B, Y);
1116
1117parameter A_SIGNED = 0;
1118parameter B_SIGNED = 0;
1119parameter A_WIDTH = 0;
1120parameter B_WIDTH = 0;
1121parameter Y_WIDTH = 0;
1122
1123input [A_WIDTH-1:0] A;
1124input [B_WIDTH-1:0] B;
1125output [Y_WIDTH-1:0] Y;
1126
1127generate
1128	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1129		localparam WIDTH = B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
1130		wire [WIDTH-1:0] B_buf, Y_trunc;
1131		assign B_buf = $signed(B);
1132		assign Y_trunc = $signed(A) % $signed(B);
1133		// flooring mod is the same as truncating mod for positive division results (A and B have
1134		// the same sign), as well as when there's no remainder.
1135		// For all other cases, they behave as `floor - trunc = B`
1136		assign Y = (A[A_WIDTH-1] == B[B_WIDTH-1]) || Y_trunc == 0 ? Y_trunc : $signed(B_buf) + $signed(Y_trunc);
1137	end else begin:BLOCK2
1138		// no difference between truncating and flooring for unsigned
1139		assign Y = A % B;
1140	end
1141endgenerate
1142
1143endmodule
1144
1145// --------------------------------------------------------
1146`ifndef SIMLIB_NOPOW
1147
1148module \$pow (A, B, Y);
1149
1150parameter A_SIGNED = 0;
1151parameter B_SIGNED = 0;
1152parameter A_WIDTH = 0;
1153parameter B_WIDTH = 0;
1154parameter Y_WIDTH = 0;
1155
1156input [A_WIDTH-1:0] A;
1157input [B_WIDTH-1:0] B;
1158output [Y_WIDTH-1:0] Y;
1159
1160generate
1161	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1162		assign Y = $signed(A) ** $signed(B);
1163	end else if (A_SIGNED) begin:BLOCK2
1164		assign Y = $signed(A) ** B;
1165	end else if (B_SIGNED) begin:BLOCK3
1166		assign Y = A ** $signed(B);
1167	end else begin:BLOCK4
1168		assign Y = A ** B;
1169	end
1170endgenerate
1171
1172endmodule
1173
1174`endif
1175// --------------------------------------------------------
1176
1177module \$logic_not (A, Y);
1178
1179parameter A_SIGNED = 0;
1180parameter A_WIDTH = 0;
1181parameter Y_WIDTH = 0;
1182
1183input [A_WIDTH-1:0] A;
1184output [Y_WIDTH-1:0] Y;
1185
1186generate
1187	if (A_SIGNED) begin:BLOCK1
1188		assign Y = !$signed(A);
1189	end else begin:BLOCK2
1190		assign Y = !A;
1191	end
1192endgenerate
1193
1194endmodule
1195
1196// --------------------------------------------------------
1197
1198module \$logic_and (A, B, Y);
1199
1200parameter A_SIGNED = 0;
1201parameter B_SIGNED = 0;
1202parameter A_WIDTH = 0;
1203parameter B_WIDTH = 0;
1204parameter Y_WIDTH = 0;
1205
1206input [A_WIDTH-1:0] A;
1207input [B_WIDTH-1:0] B;
1208output [Y_WIDTH-1:0] Y;
1209
1210generate
1211	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1212		assign Y = $signed(A) && $signed(B);
1213	end else begin:BLOCK2
1214		assign Y = A && B;
1215	end
1216endgenerate
1217
1218endmodule
1219
1220// --------------------------------------------------------
1221
1222module \$logic_or (A, B, Y);
1223
1224parameter A_SIGNED = 0;
1225parameter B_SIGNED = 0;
1226parameter A_WIDTH = 0;
1227parameter B_WIDTH = 0;
1228parameter Y_WIDTH = 0;
1229
1230input [A_WIDTH-1:0] A;
1231input [B_WIDTH-1:0] B;
1232output [Y_WIDTH-1:0] Y;
1233
1234generate
1235	if (A_SIGNED && B_SIGNED) begin:BLOCK1
1236		assign Y = $signed(A) || $signed(B);
1237	end else begin:BLOCK2
1238		assign Y = A || B;
1239	end
1240endgenerate
1241
1242endmodule
1243
1244// --------------------------------------------------------
1245
1246module \$slice (A, Y);
1247
1248parameter OFFSET = 0;
1249parameter A_WIDTH = 0;
1250parameter Y_WIDTH = 0;
1251
1252input [A_WIDTH-1:0] A;
1253output [Y_WIDTH-1:0] Y;
1254
1255assign Y = A >> OFFSET;
1256
1257endmodule
1258
1259// --------------------------------------------------------
1260
1261module \$concat (A, B, Y);
1262
1263parameter A_WIDTH = 0;
1264parameter B_WIDTH = 0;
1265
1266input [A_WIDTH-1:0] A;
1267input [B_WIDTH-1:0] B;
1268output [A_WIDTH+B_WIDTH-1:0] Y;
1269
1270assign Y = {B, A};
1271
1272endmodule
1273
1274// --------------------------------------------------------
1275
1276module \$mux (A, B, S, Y);
1277
1278parameter WIDTH = 0;
1279
1280input [WIDTH-1:0] A, B;
1281input S;
1282output reg [WIDTH-1:0] Y;
1283
1284always @* begin
1285	if (S)
1286		Y = B;
1287	else
1288		Y = A;
1289end
1290
1291endmodule
1292
1293// --------------------------------------------------------
1294
1295module \$pmux (A, B, S, Y);
1296
1297parameter WIDTH = 0;
1298parameter S_WIDTH = 0;
1299
1300input [WIDTH-1:0] A;
1301input [WIDTH*S_WIDTH-1:0] B;
1302input [S_WIDTH-1:0] S;
1303output reg [WIDTH-1:0] Y;
1304
1305integer i;
1306reg found_active_sel_bit;
1307
1308always @* begin
1309	Y = A;
1310	found_active_sel_bit = 0;
1311	for (i = 0; i < S_WIDTH; i = i+1)
1312		if (S[i]) begin
1313			Y = found_active_sel_bit ? 'bx : B >> (WIDTH*i);
1314			found_active_sel_bit = 1;
1315		end
1316end
1317
1318endmodule
1319
1320// --------------------------------------------------------
1321`ifndef SIMLIB_NOLUT
1322
1323module \$lut (A, Y);
1324
1325parameter WIDTH = 0;
1326parameter LUT = 0;
1327
1328input [WIDTH-1:0] A;
1329output reg Y;
1330
1331wire lut0_out, lut1_out;
1332
1333generate
1334	if (WIDTH <= 1) begin:simple
1335		assign {lut1_out, lut0_out} = LUT;
1336	end else begin:complex
1337		\$lut #( .WIDTH(WIDTH-1), .LUT(LUT                  ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) );
1338		\$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) );
1339	end
1340
1341	if (WIDTH > 0) begin:lutlogic
1342		always @* begin
1343			casez ({A[WIDTH-1], lut0_out, lut1_out})
1344				3'b?11: Y = 1'b1;
1345				3'b?00: Y = 1'b0;
1346				3'b0??: Y = lut0_out;
1347				3'b1??: Y = lut1_out;
1348				default: Y = 1'bx;
1349			endcase
1350		end
1351	end
1352endgenerate
1353
1354endmodule
1355
1356`endif
1357// --------------------------------------------------------
1358
1359module \$sop (A, Y);
1360
1361parameter WIDTH = 0;
1362parameter DEPTH = 0;
1363parameter TABLE = 0;
1364
1365input [WIDTH-1:0] A;
1366output reg Y;
1367
1368integer i, j;
1369reg match;
1370
1371always @* begin
1372	Y = 0;
1373	for (i = 0; i < DEPTH; i=i+1) begin
1374		match = 1;
1375		for (j = 0; j < WIDTH; j=j+1) begin
1376			if (TABLE[2*WIDTH*i + 2*j + 0] && A[j]) match = 0;
1377			if (TABLE[2*WIDTH*i + 2*j + 1] && !A[j]) match = 0;
1378		end
1379		if (match) Y = 1;
1380	end
1381end
1382
1383endmodule
1384
1385// --------------------------------------------------------
1386
1387module \$tribuf (A, EN, Y);
1388
1389parameter WIDTH = 0;
1390
1391input [WIDTH-1:0] A;
1392input EN;
1393output [WIDTH-1:0] Y;
1394
1395assign Y = EN ? A : 'bz;
1396
1397endmodule
1398
1399// --------------------------------------------------------
1400
1401module \$specify2 (EN, SRC, DST);
1402
1403parameter FULL = 0;
1404parameter SRC_WIDTH = 1;
1405parameter DST_WIDTH = 1;
1406
1407parameter SRC_DST_PEN = 0;
1408parameter SRC_DST_POL = 0;
1409
1410parameter T_RISE_MIN = 0;
1411parameter T_RISE_TYP = 0;
1412parameter T_RISE_MAX = 0;
1413
1414parameter T_FALL_MIN = 0;
1415parameter T_FALL_TYP = 0;
1416parameter T_FALL_MAX = 0;
1417
1418input EN;
1419input [SRC_WIDTH-1:0] SRC;
1420input [DST_WIDTH-1:0] DST;
1421
1422localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
1423
1424`ifdef SIMLIB_SPECIFY
1425specify
1426	if (EN && SD==0 && !FULL) (SRC  => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1427	if (EN && SD==0 &&  FULL) (SRC  *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1428	if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1429	if (EN && SD==1 &&  FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1430	if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1431	if (EN && SD==2 &&  FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1432endspecify
1433`endif
1434
1435endmodule
1436
1437// --------------------------------------------------------
1438
1439module \$specify3 (EN, SRC, DST, DAT);
1440
1441parameter FULL = 0;
1442parameter SRC_WIDTH = 1;
1443parameter DST_WIDTH = 1;
1444
1445parameter EDGE_EN = 0;
1446parameter EDGE_POL = 0;
1447
1448parameter SRC_DST_PEN = 0;
1449parameter SRC_DST_POL = 0;
1450
1451parameter DAT_DST_PEN = 0;
1452parameter DAT_DST_POL = 0;
1453
1454parameter T_RISE_MIN = 0;
1455parameter T_RISE_TYP = 0;
1456parameter T_RISE_MAX = 0;
1457
1458parameter T_FALL_MIN = 0;
1459parameter T_FALL_TYP = 0;
1460parameter T_FALL_MAX = 0;
1461
1462input EN;
1463input [SRC_WIDTH-1:0] SRC;
1464input [DST_WIDTH-1:0] DST, DAT;
1465
1466localparam ED = EDGE_EN     ? (EDGE_POL    ? 1 : 2) : 0;
1467localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
1468localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0;
1469
1470`ifdef SIMLIB_SPECIFY
1471specify
1472	// DD=0
1473
1474	if (EN && DD==0 && SD==0 && ED==0 && !FULL) (        SRC  => (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1475	if (EN && DD==0 && SD==0 && ED==0 &&  FULL) (        SRC  *> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1476	if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC  => (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1477	if (EN && DD==0 && SD==0 && ED==1 &&  FULL) (posedge SRC  *> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1478	if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC  => (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1479	if (EN && DD==0 && SD==0 && ED==2 &&  FULL) (negedge SRC  *> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1480
1481	if (EN && DD==0 && SD==1 && ED==0 && !FULL) (        SRC +=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1482	if (EN && DD==0 && SD==1 && ED==0 &&  FULL) (        SRC +*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1483	if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1484	if (EN && DD==0 && SD==1 && ED==1 &&  FULL) (posedge SRC +*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1485	if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1486	if (EN && DD==0 && SD==1 && ED==2 &&  FULL) (negedge SRC +*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1487
1488	if (EN && DD==0 && SD==2 && ED==0 && !FULL) (        SRC -=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1489	if (EN && DD==0 && SD==2 && ED==0 &&  FULL) (        SRC -*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1490	if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1491	if (EN && DD==0 && SD==2 && ED==1 &&  FULL) (posedge SRC -*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1492	if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1493	if (EN && DD==0 && SD==2 && ED==2 &&  FULL) (negedge SRC -*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1494
1495	// DD=1
1496
1497	if (EN && DD==1 && SD==0 && ED==0 && !FULL) (        SRC  => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1498	if (EN && DD==1 && SD==0 && ED==0 &&  FULL) (        SRC  *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1499	if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC  => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1500	if (EN && DD==1 && SD==0 && ED==1 &&  FULL) (posedge SRC  *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1501	if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC  => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1502	if (EN && DD==1 && SD==0 && ED==2 &&  FULL) (negedge SRC  *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1503
1504	if (EN && DD==1 && SD==1 && ED==0 && !FULL) (        SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1505	if (EN && DD==1 && SD==1 && ED==0 &&  FULL) (        SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1506	if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1507	if (EN && DD==1 && SD==1 && ED==1 &&  FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1508	if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1509	if (EN && DD==1 && SD==1 && ED==2 &&  FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1510
1511	if (EN && DD==1 && SD==2 && ED==0 && !FULL) (        SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1512	if (EN && DD==1 && SD==2 && ED==0 &&  FULL) (        SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1513	if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1514	if (EN && DD==1 && SD==2 && ED==1 &&  FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1515	if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1516	if (EN && DD==1 && SD==2 && ED==2 &&  FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1517
1518	// DD=2
1519
1520	if (EN && DD==2 && SD==0 && ED==0 && !FULL) (        SRC  => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1521	if (EN && DD==2 && SD==0 && ED==0 &&  FULL) (        SRC  *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1522	if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC  => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1523	if (EN && DD==2 && SD==0 && ED==1 &&  FULL) (posedge SRC  *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1524	if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC  => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1525	if (EN && DD==2 && SD==0 && ED==2 &&  FULL) (negedge SRC  *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1526
1527	if (EN && DD==2 && SD==1 && ED==0 && !FULL) (        SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1528	if (EN && DD==2 && SD==1 && ED==0 &&  FULL) (        SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1529	if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1530	if (EN && DD==2 && SD==1 && ED==1 &&  FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1531	if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1532	if (EN && DD==2 && SD==1 && ED==2 &&  FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1533
1534	if (EN && DD==2 && SD==2 && ED==0 && !FULL) (        SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1535	if (EN && DD==2 && SD==2 && ED==0 &&  FULL) (        SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1536	if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1537	if (EN && DD==2 && SD==2 && ED==1 &&  FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1538	if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1539	if (EN && DD==2 && SD==2 && ED==2 &&  FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
1540endspecify
1541`endif
1542
1543endmodule
1544
1545// --------------------------------------------------------
1546
1547module \$specrule (EN_SRC, EN_DST, SRC, DST);
1548
1549parameter TYPE = "";
1550parameter T_LIMIT = 0;
1551parameter T_LIMIT2 = 0;
1552
1553parameter SRC_WIDTH = 1;
1554parameter DST_WIDTH = 1;
1555
1556parameter SRC_PEN = 0;
1557parameter SRC_POL = 0;
1558
1559parameter DST_PEN = 0;
1560parameter DST_POL = 0;
1561
1562input EN_SRC, EN_DST;
1563input [SRC_WIDTH-1:0] SRC;
1564input [DST_WIDTH-1:0] DST;
1565
1566`ifdef SIMLIB_SPECIFY
1567specify
1568	// TBD
1569endspecify
1570`endif
1571
1572endmodule
1573
1574// --------------------------------------------------------
1575
1576module \$assert (A, EN);
1577
1578input A, EN;
1579
1580`ifndef SIMLIB_NOCHECKS
1581always @* begin
1582	if (A !== 1'b1 && EN === 1'b1) begin
1583		$display("Assertion %m failed!");
1584		$stop;
1585	end
1586end
1587`endif
1588
1589endmodule
1590
1591// --------------------------------------------------------
1592
1593module \$assume (A, EN);
1594
1595input A, EN;
1596
1597`ifndef SIMLIB_NOCHECKS
1598always @* begin
1599	if (A !== 1'b1 && EN === 1'b1) begin
1600		$display("Assumption %m failed!");
1601		$stop;
1602	end
1603end
1604`endif
1605
1606endmodule
1607
1608// --------------------------------------------------------
1609
1610module \$live (A, EN);
1611
1612input A, EN;
1613
1614endmodule
1615
1616// --------------------------------------------------------
1617
1618module \$fair (A, EN);
1619
1620input A, EN;
1621
1622endmodule
1623
1624// --------------------------------------------------------
1625
1626module \$cover (A, EN);
1627
1628input A, EN;
1629
1630endmodule
1631
1632// --------------------------------------------------------
1633
1634module \$initstate (Y);
1635
1636output reg Y = 1;
1637reg [3:0] cnt = 1;
1638reg trig = 0;
1639
1640initial trig <= 1;
1641
1642always @(cnt, trig) begin
1643	Y <= |cnt;
1644	cnt <= cnt + |cnt;
1645end
1646
1647endmodule
1648
1649// --------------------------------------------------------
1650
1651module \$anyconst (Y);
1652
1653parameter WIDTH = 0;
1654
1655output [WIDTH-1:0] Y;
1656
1657assign Y = 'bx;
1658
1659endmodule
1660
1661// --------------------------------------------------------
1662
1663module \$anyseq (Y);
1664
1665parameter WIDTH = 0;
1666
1667output [WIDTH-1:0] Y;
1668
1669assign Y = 'bx;
1670
1671endmodule
1672
1673// --------------------------------------------------------
1674
1675module \$allconst (Y);
1676
1677parameter WIDTH = 0;
1678
1679output [WIDTH-1:0] Y;
1680
1681assign Y = 'bx;
1682
1683endmodule
1684
1685// --------------------------------------------------------
1686
1687module \$allseq (Y);
1688
1689parameter WIDTH = 0;
1690
1691output [WIDTH-1:0] Y;
1692
1693assign Y = 'bx;
1694
1695endmodule
1696
1697// --------------------------------------------------------
1698
1699module \$equiv (A, B, Y);
1700
1701input A, B;
1702output Y;
1703
1704assign Y = (A !== 1'bx && A !== B) ? 1'bx : A;
1705
1706`ifndef SIMLIB_NOCHECKS
1707always @* begin
1708	if (A !== 1'bx && A !== B) begin
1709		$display("Equivalence failed!");
1710		$stop;
1711	end
1712end
1713`endif
1714
1715endmodule
1716
1717// --------------------------------------------------------
1718`ifndef SIMLIB_NOSR
1719
1720module \$sr (SET, CLR, Q);
1721
1722parameter WIDTH = 0;
1723parameter SET_POLARITY = 1'b1;
1724parameter CLR_POLARITY = 1'b1;
1725
1726input [WIDTH-1:0] SET, CLR;
1727output reg [WIDTH-1:0] Q;
1728
1729wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
1730wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
1731
1732genvar i;
1733generate
1734	for (i = 0; i < WIDTH; i = i+1) begin:bitslices
1735		always @*
1736			if (pos_clr[i])
1737				Q[i] <= 0;
1738			else if (pos_set[i])
1739				Q[i] <= 1;
1740	end
1741endgenerate
1742
1743endmodule
1744
1745`endif
1746// --------------------------------------------------------
1747`ifdef SIMLIB_FF
1748
1749module \$ff (D, Q);
1750
1751parameter WIDTH = 0;
1752
1753input [WIDTH-1:0] D;
1754output reg [WIDTH-1:0] Q;
1755
1756always @($global_clk) begin
1757	Q <= D;
1758end
1759
1760endmodule
1761
1762`endif
1763// --------------------------------------------------------
1764
1765module \$dff (CLK, D, Q);
1766
1767parameter WIDTH = 0;
1768parameter CLK_POLARITY = 1'b1;
1769
1770input CLK;
1771input [WIDTH-1:0] D;
1772output reg [WIDTH-1:0] Q;
1773wire pos_clk = CLK == CLK_POLARITY;
1774
1775always @(posedge pos_clk) begin
1776	Q <= D;
1777end
1778
1779endmodule
1780
1781// --------------------------------------------------------
1782
1783module \$dffe (CLK, EN, D, Q);
1784
1785parameter WIDTH = 0;
1786parameter CLK_POLARITY = 1'b1;
1787parameter EN_POLARITY = 1'b1;
1788
1789input CLK, EN;
1790input [WIDTH-1:0] D;
1791output reg [WIDTH-1:0] Q;
1792wire pos_clk = CLK == CLK_POLARITY;
1793
1794always @(posedge pos_clk) begin
1795	if (EN == EN_POLARITY) Q <= D;
1796end
1797
1798endmodule
1799
1800// --------------------------------------------------------
1801`ifndef SIMLIB_NOSR
1802
1803module \$dffsr (CLK, SET, CLR, D, Q);
1804
1805parameter WIDTH = 0;
1806parameter CLK_POLARITY = 1'b1;
1807parameter SET_POLARITY = 1'b1;
1808parameter CLR_POLARITY = 1'b1;
1809
1810input CLK;
1811input [WIDTH-1:0] SET, CLR, D;
1812output reg [WIDTH-1:0] Q;
1813
1814wire pos_clk = CLK == CLK_POLARITY;
1815wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
1816wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
1817
1818genvar i;
1819generate
1820	for (i = 0; i < WIDTH; i = i+1) begin:bitslices
1821		always @(posedge pos_set[i], posedge pos_clr[i], posedge pos_clk)
1822			if (pos_clr[i])
1823				Q[i] <= 0;
1824			else if (pos_set[i])
1825				Q[i] <= 1;
1826			else
1827				Q[i] <= D[i];
1828	end
1829endgenerate
1830
1831endmodule
1832
1833// --------------------------------------------------------
1834
1835module \$dffsre (CLK, SET, CLR, EN, D, Q);
1836
1837parameter WIDTH = 0;
1838parameter CLK_POLARITY = 1'b1;
1839parameter SET_POLARITY = 1'b1;
1840parameter CLR_POLARITY = 1'b1;
1841parameter EN_POLARITY = 1'b1;
1842
1843input CLK, EN;
1844input [WIDTH-1:0] SET, CLR, D;
1845output reg [WIDTH-1:0] Q;
1846
1847wire pos_clk = CLK == CLK_POLARITY;
1848wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
1849wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
1850
1851genvar i;
1852generate
1853	for (i = 0; i < WIDTH; i = i+1) begin:bitslices
1854		always @(posedge pos_set[i], posedge pos_clr[i], posedge pos_clk)
1855			if (pos_clr[i])
1856				Q[i] <= 0;
1857			else if (pos_set[i])
1858				Q[i] <= 1;
1859			else if (EN == EN_POLARITY)
1860				Q[i] <= D[i];
1861	end
1862endgenerate
1863
1864endmodule
1865
1866`endif
1867// --------------------------------------------------------
1868
1869module \$adff (CLK, ARST, D, Q);
1870
1871parameter WIDTH = 0;
1872parameter CLK_POLARITY = 1'b1;
1873parameter ARST_POLARITY = 1'b1;
1874parameter ARST_VALUE = 0;
1875
1876input CLK, ARST;
1877input [WIDTH-1:0] D;
1878output reg [WIDTH-1:0] Q;
1879wire pos_clk = CLK == CLK_POLARITY;
1880wire pos_arst = ARST == ARST_POLARITY;
1881
1882always @(posedge pos_clk, posedge pos_arst) begin
1883	if (pos_arst)
1884		Q <= ARST_VALUE;
1885	else
1886		Q <= D;
1887end
1888
1889endmodule
1890
1891// --------------------------------------------------------
1892
1893module \$aldff (CLK, ALOAD, AD, D, Q);
1894
1895parameter WIDTH = 0;
1896parameter CLK_POLARITY = 1'b1;
1897parameter ALOAD_POLARITY = 1'b1;
1898
1899input CLK, ALOAD;
1900input [WIDTH-1:0] AD;
1901input [WIDTH-1:0] D;
1902output reg [WIDTH-1:0] Q;
1903wire pos_clk = CLK == CLK_POLARITY;
1904wire pos_aload = ALOAD == ALOAD_POLARITY;
1905
1906always @(posedge pos_clk, posedge pos_aload) begin
1907	if (pos_aload)
1908		Q <= AD;
1909	else
1910		Q <= D;
1911end
1912
1913endmodule
1914
1915// --------------------------------------------------------
1916
1917module \$sdff (CLK, SRST, D, Q);
1918
1919parameter WIDTH = 0;
1920parameter CLK_POLARITY = 1'b1;
1921parameter SRST_POLARITY = 1'b1;
1922parameter SRST_VALUE = 0;
1923
1924input CLK, SRST;
1925input [WIDTH-1:0] D;
1926output reg [WIDTH-1:0] Q;
1927wire pos_clk = CLK == CLK_POLARITY;
1928wire pos_srst = SRST == SRST_POLARITY;
1929
1930always @(posedge pos_clk) begin
1931	if (pos_srst)
1932		Q <= SRST_VALUE;
1933	else
1934		Q <= D;
1935end
1936
1937endmodule
1938
1939// --------------------------------------------------------
1940
1941module \$adffe (CLK, ARST, EN, D, Q);
1942
1943parameter WIDTH = 0;
1944parameter CLK_POLARITY = 1'b1;
1945parameter EN_POLARITY = 1'b1;
1946parameter ARST_POLARITY = 1'b1;
1947parameter ARST_VALUE = 0;
1948
1949input CLK, ARST, EN;
1950input [WIDTH-1:0] D;
1951output reg [WIDTH-1:0] Q;
1952wire pos_clk = CLK == CLK_POLARITY;
1953wire pos_arst = ARST == ARST_POLARITY;
1954
1955always @(posedge pos_clk, posedge pos_arst) begin
1956	if (pos_arst)
1957		Q <= ARST_VALUE;
1958	else if (EN == EN_POLARITY)
1959		Q <= D;
1960end
1961
1962endmodule
1963
1964// --------------------------------------------------------
1965
1966module \$aldffe (CLK, ALOAD, AD, EN, D, Q);
1967
1968parameter WIDTH = 0;
1969parameter CLK_POLARITY = 1'b1;
1970parameter EN_POLARITY = 1'b1;
1971parameter ALOAD_POLARITY = 1'b1;
1972
1973input CLK, ALOAD, EN;
1974input [WIDTH-1:0] D;
1975input [WIDTH-1:0] AD;
1976output reg [WIDTH-1:0] Q;
1977wire pos_clk = CLK == CLK_POLARITY;
1978wire pos_aload = ALOAD == ALOAD_POLARITY;
1979
1980always @(posedge pos_clk, posedge pos_aload) begin
1981	if (pos_aload)
1982		Q <= AD;
1983	else if (EN == EN_POLARITY)
1984		Q <= D;
1985end
1986
1987endmodule
1988
1989// --------------------------------------------------------
1990
1991module \$sdffe (CLK, SRST, EN, D, Q);
1992
1993parameter WIDTH = 0;
1994parameter CLK_POLARITY = 1'b1;
1995parameter EN_POLARITY = 1'b1;
1996parameter SRST_POLARITY = 1'b1;
1997parameter SRST_VALUE = 0;
1998
1999input CLK, SRST, EN;
2000input [WIDTH-1:0] D;
2001output reg [WIDTH-1:0] Q;
2002wire pos_clk = CLK == CLK_POLARITY;
2003wire pos_srst = SRST == SRST_POLARITY;
2004
2005always @(posedge pos_clk) begin
2006	if (pos_srst)
2007		Q <= SRST_VALUE;
2008	else if (EN == EN_POLARITY)
2009		Q <= D;
2010end
2011
2012endmodule
2013
2014// --------------------------------------------------------
2015
2016module \$sdffce (CLK, SRST, EN, D, Q);
2017
2018parameter WIDTH = 0;
2019parameter CLK_POLARITY = 1'b1;
2020parameter EN_POLARITY = 1'b1;
2021parameter SRST_POLARITY = 1'b1;
2022parameter SRST_VALUE = 0;
2023
2024input CLK, SRST, EN;
2025input [WIDTH-1:0] D;
2026output reg [WIDTH-1:0] Q;
2027wire pos_clk = CLK == CLK_POLARITY;
2028wire pos_srst = SRST == SRST_POLARITY;
2029
2030always @(posedge pos_clk) begin
2031	if (EN == EN_POLARITY) begin
2032		if (pos_srst)
2033			Q <= SRST_VALUE;
2034		else
2035			Q <= D;
2036	end
2037end
2038
2039endmodule
2040
2041// --------------------------------------------------------
2042
2043module \$dlatch (EN, D, Q);
2044
2045parameter WIDTH = 0;
2046parameter EN_POLARITY = 1'b1;
2047
2048input EN;
2049input [WIDTH-1:0] D;
2050output reg [WIDTH-1:0] Q;
2051
2052always @* begin
2053	if (EN == EN_POLARITY)
2054		Q = D;
2055end
2056
2057endmodule
2058
2059// --------------------------------------------------------
2060
2061module \$adlatch (EN, ARST, D, Q);
2062
2063parameter WIDTH = 0;
2064parameter EN_POLARITY = 1'b1;
2065parameter ARST_POLARITY = 1'b1;
2066parameter ARST_VALUE = 0;
2067
2068input EN, ARST;
2069input [WIDTH-1:0] D;
2070output reg [WIDTH-1:0] Q;
2071
2072always @* begin
2073	if (ARST == ARST_POLARITY)
2074		Q = ARST_VALUE;
2075	else if (EN == EN_POLARITY)
2076		Q = D;
2077end
2078
2079endmodule
2080
2081// --------------------------------------------------------
2082`ifndef SIMLIB_NOSR
2083
2084module \$dlatchsr (EN, SET, CLR, D, Q);
2085
2086parameter WIDTH = 0;
2087parameter EN_POLARITY = 1'b1;
2088parameter SET_POLARITY = 1'b1;
2089parameter CLR_POLARITY = 1'b1;
2090
2091input EN;
2092input [WIDTH-1:0] SET, CLR, D;
2093output reg [WIDTH-1:0] Q;
2094
2095wire pos_en = EN == EN_POLARITY;
2096wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
2097wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
2098
2099genvar i;
2100generate
2101	for (i = 0; i < WIDTH; i = i+1) begin:bitslices
2102		always @*
2103			if (pos_clr[i])
2104				Q[i] = 0;
2105			else if (pos_set[i])
2106				Q[i] = 1;
2107			else if (pos_en)
2108				Q[i] = D[i];
2109	end
2110endgenerate
2111
2112endmodule
2113
2114`endif
2115// --------------------------------------------------------
2116
2117module \$fsm (CLK, ARST, CTRL_IN, CTRL_OUT);
2118
2119parameter NAME = "";
2120
2121parameter CLK_POLARITY = 1'b1;
2122parameter ARST_POLARITY = 1'b1;
2123
2124parameter CTRL_IN_WIDTH = 1;
2125parameter CTRL_OUT_WIDTH = 1;
2126
2127parameter STATE_BITS = 1;
2128parameter STATE_NUM = 1;
2129parameter STATE_NUM_LOG2 = 1;
2130parameter STATE_RST = 0;
2131parameter STATE_TABLE = 1'b0;
2132
2133parameter TRANS_NUM = 1;
2134parameter TRANS_TABLE = 4'b0x0x;
2135
2136input CLK, ARST;
2137input [CTRL_IN_WIDTH-1:0] CTRL_IN;
2138output reg [CTRL_OUT_WIDTH-1:0] CTRL_OUT;
2139
2140wire pos_clk = CLK == CLK_POLARITY;
2141wire pos_arst = ARST == ARST_POLARITY;
2142
2143reg [STATE_BITS-1:0] state;
2144reg [STATE_BITS-1:0] state_tmp;
2145reg [STATE_BITS-1:0] next_state;
2146
2147reg [STATE_BITS-1:0] tr_state_in;
2148reg [STATE_BITS-1:0] tr_state_out;
2149reg [CTRL_IN_WIDTH-1:0] tr_ctrl_in;
2150reg [CTRL_OUT_WIDTH-1:0] tr_ctrl_out;
2151
2152integer i;
2153
2154task tr_fetch;
2155	input [31:0] tr_num;
2156	reg [31:0] tr_pos;
2157	reg [STATE_NUM_LOG2-1:0] state_num;
2158	begin
2159		tr_pos = (2*STATE_NUM_LOG2+CTRL_IN_WIDTH+CTRL_OUT_WIDTH)*tr_num;
2160		tr_ctrl_out = TRANS_TABLE >> tr_pos;
2161		tr_pos = tr_pos + CTRL_OUT_WIDTH;
2162		state_num = TRANS_TABLE >> tr_pos;
2163		tr_state_out = STATE_TABLE >> (STATE_BITS*state_num);
2164		tr_pos = tr_pos + STATE_NUM_LOG2;
2165		tr_ctrl_in = TRANS_TABLE >> tr_pos;
2166		tr_pos = tr_pos + CTRL_IN_WIDTH;
2167		state_num = TRANS_TABLE >> tr_pos;
2168		tr_state_in = STATE_TABLE >> (STATE_BITS*state_num);
2169		tr_pos = tr_pos + STATE_NUM_LOG2;
2170	end
2171endtask
2172
2173always @(posedge pos_clk, posedge pos_arst) begin
2174	if (pos_arst) begin
2175		state_tmp = STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST];
2176		for (i = 0; i < STATE_BITS; i = i+1)
2177			if (state_tmp[i] === 1'bz)
2178				state_tmp[i] = 0;
2179		state <= state_tmp;
2180	end else begin
2181		state_tmp = next_state;
2182		for (i = 0; i < STATE_BITS; i = i+1)
2183			if (state_tmp[i] === 1'bz)
2184				state_tmp[i] = 0;
2185		state <= state_tmp;
2186	end
2187end
2188
2189always @(state, CTRL_IN) begin
2190	next_state <= STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST];
2191	CTRL_OUT <= 'bx;
2192	// $display("---");
2193	// $display("Q: %b %b", state, CTRL_IN);
2194	for (i = 0; i < TRANS_NUM; i = i+1) begin
2195		tr_fetch(i);
2196		// $display("T: %b %b -> %b %b [%d]", tr_state_in, tr_ctrl_in, tr_state_out, tr_ctrl_out, i);
2197		casez ({state, CTRL_IN})
2198			{tr_state_in, tr_ctrl_in}: begin
2199				// $display("-> %b %b <-   MATCH", state, CTRL_IN);
2200				{next_state, CTRL_OUT} <= {tr_state_out, tr_ctrl_out};
2201			end
2202		endcase
2203	end
2204end
2205
2206endmodule
2207
2208// --------------------------------------------------------
2209`ifndef SIMLIB_NOMEM
2210
2211module \$memrd (CLK, EN, ADDR, DATA);
2212
2213parameter MEMID = "";
2214parameter ABITS = 8;
2215parameter WIDTH = 8;
2216
2217parameter CLK_ENABLE = 0;
2218parameter CLK_POLARITY = 0;
2219parameter TRANSPARENT = 0;
2220
2221input CLK, EN;
2222input [ABITS-1:0] ADDR;
2223output [WIDTH-1:0] DATA;
2224
2225initial begin
2226	if (MEMID != "") begin
2227		$display("ERROR: Found non-simulatable instance of $memrd!");
2228		$finish;
2229	end
2230end
2231
2232endmodule
2233
2234module \$memrd_v2 (CLK, EN, ARST, SRST, ADDR, DATA);
2235
2236parameter MEMID = "";
2237parameter ABITS = 8;
2238parameter WIDTH = 8;
2239
2240parameter CLK_ENABLE = 0;
2241parameter CLK_POLARITY = 0;
2242parameter TRANSPARENCY_MASK = 0;
2243parameter COLLISION_X_MASK = 0;
2244parameter ARST_VALUE = 0;
2245parameter SRST_VALUE = 0;
2246parameter INIT_VALUE = 0;
2247parameter CE_OVER_SRST = 0;
2248
2249input CLK, EN, ARST, SRST;
2250input [ABITS-1:0] ADDR;
2251output [WIDTH-1:0] DATA;
2252
2253initial begin
2254	if (MEMID != "") begin
2255		$display("ERROR: Found non-simulatable instance of $memrd_v2!");
2256		$finish;
2257	end
2258end
2259
2260endmodule
2261
2262// --------------------------------------------------------
2263
2264module \$memwr (CLK, EN, ADDR, DATA);
2265
2266parameter MEMID = "";
2267parameter ABITS = 8;
2268parameter WIDTH = 8;
2269
2270parameter CLK_ENABLE = 0;
2271parameter CLK_POLARITY = 0;
2272parameter PRIORITY = 0;
2273
2274input CLK;
2275input [WIDTH-1:0] EN;
2276input [ABITS-1:0] ADDR;
2277input [WIDTH-1:0] DATA;
2278
2279initial begin
2280	if (MEMID != "") begin
2281		$display("ERROR: Found non-simulatable instance of $memwr!");
2282		$finish;
2283	end
2284end
2285
2286endmodule
2287
2288module \$memwr_v2 (CLK, EN, ADDR, DATA);
2289
2290parameter MEMID = "";
2291parameter ABITS = 8;
2292parameter WIDTH = 8;
2293
2294parameter CLK_ENABLE = 0;
2295parameter CLK_POLARITY = 0;
2296parameter PORTID = 0;
2297parameter PRIORITY_MASK = 0;
2298
2299input CLK;
2300input [WIDTH-1:0] EN;
2301input [ABITS-1:0] ADDR;
2302input [WIDTH-1:0] DATA;
2303
2304initial begin
2305	if (MEMID != "") begin
2306		$display("ERROR: Found non-simulatable instance of $memwr_v2!");
2307		$finish;
2308	end
2309end
2310
2311endmodule
2312
2313// --------------------------------------------------------
2314
2315module \$meminit (ADDR, DATA);
2316
2317parameter MEMID = "";
2318parameter ABITS = 8;
2319parameter WIDTH = 8;
2320parameter WORDS = 1;
2321
2322parameter PRIORITY = 0;
2323
2324input [ABITS-1:0] ADDR;
2325input [WORDS*WIDTH-1:0] DATA;
2326
2327initial begin
2328	if (MEMID != "") begin
2329		$display("ERROR: Found non-simulatable instance of $meminit!");
2330		$finish;
2331	end
2332end
2333
2334endmodule
2335
2336// --------------------------------------------------------
2337
2338module \$meminit_v2 (ADDR, DATA, EN);
2339
2340parameter MEMID = "";
2341parameter ABITS = 8;
2342parameter WIDTH = 8;
2343parameter WORDS = 1;
2344
2345parameter PRIORITY = 0;
2346
2347input [ABITS-1:0] ADDR;
2348input [WORDS*WIDTH-1:0] DATA;
2349input [WIDTH-1:0] EN;
2350
2351initial begin
2352	if (MEMID != "") begin
2353		$display("ERROR: Found non-simulatable instance of $meminit_v2!");
2354		$finish;
2355	end
2356end
2357
2358endmodule
2359
2360// --------------------------------------------------------
2361
2362module \$mem (RD_CLK, RD_EN, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
2363
2364parameter MEMID = "";
2365parameter signed SIZE = 4;
2366parameter signed OFFSET = 0;
2367parameter signed ABITS = 2;
2368parameter signed WIDTH = 8;
2369parameter signed INIT = 1'bx;
2370
2371parameter signed RD_PORTS = 1;
2372parameter RD_CLK_ENABLE = 1'b1;
2373parameter RD_CLK_POLARITY = 1'b1;
2374parameter RD_TRANSPARENT = 1'b1;
2375
2376parameter signed WR_PORTS = 1;
2377parameter WR_CLK_ENABLE = 1'b1;
2378parameter WR_CLK_POLARITY = 1'b1;
2379
2380input [RD_PORTS-1:0] RD_CLK;
2381input [RD_PORTS-1:0] RD_EN;
2382input [RD_PORTS*ABITS-1:0] RD_ADDR;
2383output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
2384
2385input [WR_PORTS-1:0] WR_CLK;
2386input [WR_PORTS*WIDTH-1:0] WR_EN;
2387input [WR_PORTS*ABITS-1:0] WR_ADDR;
2388input [WR_PORTS*WIDTH-1:0] WR_DATA;
2389
2390reg [WIDTH-1:0] memory [SIZE-1:0];
2391
2392integer i, j;
2393reg [WR_PORTS-1:0] LAST_WR_CLK;
2394reg [RD_PORTS-1:0] LAST_RD_CLK;
2395
2396function port_active;
2397	input clk_enable;
2398	input clk_polarity;
2399	input last_clk;
2400	input this_clk;
2401	begin
2402		casez ({clk_enable, clk_polarity, last_clk, this_clk})
2403			4'b0???: port_active = 1;
2404			4'b1101: port_active = 1;
2405			4'b1010: port_active = 1;
2406			default: port_active = 0;
2407		endcase
2408	end
2409endfunction
2410
2411initial begin
2412	for (i = 0; i < SIZE; i = i+1)
2413		memory[i] = INIT >>> (i*WIDTH);
2414end
2415
2416always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin
2417`ifdef SIMLIB_MEMDELAY
2418	#`SIMLIB_MEMDELAY;
2419`endif
2420	for (i = 0; i < RD_PORTS; i = i+1) begin
2421		if (!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i] && RD_EN[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
2422			// $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS],  memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
2423			RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
2424		end
2425	end
2426
2427	for (i = 0; i < WR_PORTS; i = i+1) begin
2428		if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i]))
2429			for (j = 0; j < WIDTH; j = j+1)
2430				if (WR_EN[i*WIDTH+j]) begin
2431					// $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]);
2432					memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j];
2433				end
2434	end
2435
2436	for (i = 0; i < RD_PORTS; i = i+1) begin
2437		if ((RD_TRANSPARENT[i] || !RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
2438			// $display("Transparent read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS],  memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
2439			RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
2440		end
2441	end
2442
2443	LAST_RD_CLK <= RD_CLK;
2444	LAST_WR_CLK <= WR_CLK;
2445end
2446
2447endmodule
2448
2449module \$mem_v2 (RD_CLK, RD_EN, RD_ARST, RD_SRST, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
2450
2451parameter MEMID = "";
2452parameter signed SIZE = 4;
2453parameter signed OFFSET = 0;
2454parameter signed ABITS = 2;
2455parameter signed WIDTH = 8;
2456parameter signed INIT = 1'bx;
2457
2458parameter signed RD_PORTS = 1;
2459parameter RD_CLK_ENABLE = 1'b1;
2460parameter RD_CLK_POLARITY = 1'b1;
2461parameter RD_TRANSPARENCY_MASK = 1'b0;
2462parameter RD_COLLISION_X_MASK = 1'b0;
2463parameter RD_WIDE_CONTINUATION = 1'b0;
2464parameter RD_CE_OVER_SRST = 1'b0;
2465parameter RD_ARST_VALUE = 1'b0;
2466parameter RD_SRST_VALUE = 1'b0;
2467parameter RD_INIT_VALUE = 1'b0;
2468
2469parameter signed WR_PORTS = 1;
2470parameter WR_CLK_ENABLE = 1'b1;
2471parameter WR_CLK_POLARITY = 1'b1;
2472parameter WR_PRIORITY_MASK = 1'b0;
2473parameter WR_WIDE_CONTINUATION = 1'b0;
2474
2475input [RD_PORTS-1:0] RD_CLK;
2476input [RD_PORTS-1:0] RD_EN;
2477input [RD_PORTS-1:0] RD_ARST;
2478input [RD_PORTS-1:0] RD_SRST;
2479input [RD_PORTS*ABITS-1:0] RD_ADDR;
2480output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
2481
2482input [WR_PORTS-1:0] WR_CLK;
2483input [WR_PORTS*WIDTH-1:0] WR_EN;
2484input [WR_PORTS*ABITS-1:0] WR_ADDR;
2485input [WR_PORTS*WIDTH-1:0] WR_DATA;
2486
2487reg [WIDTH-1:0] memory [SIZE-1:0];
2488
2489integer i, j, k;
2490reg [WR_PORTS-1:0] LAST_WR_CLK;
2491reg [RD_PORTS-1:0] LAST_RD_CLK;
2492
2493function port_active;
2494	input clk_enable;
2495	input clk_polarity;
2496	input last_clk;
2497	input this_clk;
2498	begin
2499		casez ({clk_enable, clk_polarity, last_clk, this_clk})
2500			4'b0???: port_active = 1;
2501			4'b1101: port_active = 1;
2502			4'b1010: port_active = 1;
2503			default: port_active = 0;
2504		endcase
2505	end
2506endfunction
2507
2508initial begin
2509	for (i = 0; i < SIZE; i = i+1)
2510		memory[i] = INIT >>> (i*WIDTH);
2511	RD_DATA = RD_INIT_VALUE;
2512end
2513
2514always @(RD_CLK, RD_ARST, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin
2515`ifdef SIMLIB_MEMDELAY
2516	#`SIMLIB_MEMDELAY;
2517`endif
2518	for (i = 0; i < RD_PORTS; i = i+1) begin
2519		if (RD_CLK_ENABLE[i] && RD_EN[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin
2520			// $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS],  memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
2521			RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
2522
2523			for (j = 0; j < WR_PORTS; j = j+1) begin
2524				if (RD_TRANSPARENCY_MASK[i*WR_PORTS + j] && port_active(WR_CLK_ENABLE[j], WR_CLK_POLARITY[j], LAST_WR_CLK[j], WR_CLK[j]) && RD_ADDR[i*ABITS +: ABITS] == WR_ADDR[j*ABITS +: ABITS])
2525					for (k = 0; k < WIDTH; k = k+1)
2526						if (WR_EN[j*WIDTH+k])
2527							RD_DATA[i*WIDTH+k] <= WR_DATA[j*WIDTH+k];
2528				if (RD_COLLISION_X_MASK[i*WR_PORTS + j] && port_active(WR_CLK_ENABLE[j], WR_CLK_POLARITY[j], LAST_WR_CLK[j], WR_CLK[j]) && RD_ADDR[i*ABITS +: ABITS] == WR_ADDR[j*ABITS +: ABITS])
2529					for (k = 0; k < WIDTH; k = k+1)
2530						if (WR_EN[j*WIDTH+k])
2531							RD_DATA[i*WIDTH+k] <= 1'bx;
2532			end
2533		end
2534	end
2535
2536	for (i = 0; i < WR_PORTS; i = i+1) begin
2537		if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i]))
2538			for (j = 0; j < WIDTH; j = j+1)
2539				if (WR_EN[i*WIDTH+j]) begin
2540					// $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]);
2541					memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j];
2542				end
2543	end
2544
2545	for (i = 0; i < RD_PORTS; i = i+1) begin
2546		if (!RD_CLK_ENABLE[i]) begin
2547			// $display("Combinatorial read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS],  memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
2548			RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
2549		end
2550	end
2551
2552	for (i = 0; i < RD_PORTS; i = i+1) begin
2553		if (RD_SRST[i] && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i]) && (RD_EN[i] || !RD_CE_OVER_SRST[i]))
2554			RD_DATA[i*WIDTH +: WIDTH] <= RD_SRST_VALUE[i*WIDTH +: WIDTH];
2555		if (RD_ARST[i])
2556			RD_DATA[i*WIDTH +: WIDTH] <= RD_ARST_VALUE[i*WIDTH +: WIDTH];
2557	end
2558
2559	LAST_RD_CLK <= RD_CLK;
2560	LAST_WR_CLK <= WR_CLK;
2561end
2562
2563endmodule
2564
2565`endif
2566
2567// --------------------------------------------------------
2568