ddc7fe3be5f8d3ed5d1a11390a9c9dc821131c23
[yosys.git] / techlibs / common / simlib.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 * 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 module \$not (A, Y);
37
38 parameter A_SIGNED = 0;
39 parameter A_WIDTH = 0;
40 parameter Y_WIDTH = 0;
41
42 input [A_WIDTH-1:0] A;
43 output [Y_WIDTH-1:0] Y;
44
45 generate
46 if (A_SIGNED) begin:BLOCK1
47 assign Y = ~$signed(A);
48 end else begin:BLOCK2
49 assign Y = ~A;
50 end
51 endgenerate
52
53 endmodule
54
55
56 // --------------------------------------------------------
57
58 module \$pos (A, Y);
59
60 parameter A_SIGNED = 0;
61 parameter A_WIDTH = 0;
62 parameter Y_WIDTH = 0;
63
64 input [A_WIDTH-1:0] A;
65 output [Y_WIDTH-1:0] Y;
66
67 generate
68 if (A_SIGNED) begin:BLOCK1
69 assign Y = $signed(A);
70 end else begin:BLOCK2
71 assign Y = A;
72 end
73 endgenerate
74
75 endmodule
76
77 // --------------------------------------------------------
78
79 module \$neg (A, Y);
80
81 parameter A_SIGNED = 0;
82 parameter A_WIDTH = 0;
83 parameter Y_WIDTH = 0;
84
85 input [A_WIDTH-1:0] A;
86 output [Y_WIDTH-1:0] Y;
87
88 generate
89 if (A_SIGNED) begin:BLOCK1
90 assign Y = -$signed(A);
91 end else begin:BLOCK2
92 assign Y = -A;
93 end
94 endgenerate
95
96 endmodule
97
98 // --------------------------------------------------------
99
100 module \$and (A, B, Y);
101
102 parameter A_SIGNED = 0;
103 parameter B_SIGNED = 0;
104 parameter A_WIDTH = 0;
105 parameter B_WIDTH = 0;
106 parameter Y_WIDTH = 0;
107
108 input [A_WIDTH-1:0] A;
109 input [B_WIDTH-1:0] B;
110 output [Y_WIDTH-1:0] Y;
111
112 generate
113 if (A_SIGNED && B_SIGNED) begin:BLOCK1
114 assign Y = $signed(A) & $signed(B);
115 end else begin:BLOCK2
116 assign Y = A & B;
117 end
118 endgenerate
119
120 endmodule
121
122 // --------------------------------------------------------
123
124 module \$or (A, B, Y);
125
126 parameter A_SIGNED = 0;
127 parameter B_SIGNED = 0;
128 parameter A_WIDTH = 0;
129 parameter B_WIDTH = 0;
130 parameter Y_WIDTH = 0;
131
132 input [A_WIDTH-1:0] A;
133 input [B_WIDTH-1:0] B;
134 output [Y_WIDTH-1:0] Y;
135
136 generate
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
142 endgenerate
143
144 endmodule
145
146 // --------------------------------------------------------
147
148 module \$xor (A, B, Y);
149
150 parameter A_SIGNED = 0;
151 parameter B_SIGNED = 0;
152 parameter A_WIDTH = 0;
153 parameter B_WIDTH = 0;
154 parameter Y_WIDTH = 0;
155
156 input [A_WIDTH-1:0] A;
157 input [B_WIDTH-1:0] B;
158 output [Y_WIDTH-1:0] Y;
159
160 generate
161 if (A_SIGNED && B_SIGNED) begin:BLOCK1
162 assign Y = $signed(A) ^ $signed(B);
163 end else begin:BLOCK2
164 assign Y = A ^ B;
165 end
166 endgenerate
167
168 endmodule
169
170 // --------------------------------------------------------
171
172 module \$xnor (A, B, Y);
173
174 parameter A_SIGNED = 0;
175 parameter B_SIGNED = 0;
176 parameter A_WIDTH = 0;
177 parameter B_WIDTH = 0;
178 parameter Y_WIDTH = 0;
179
180 input [A_WIDTH-1:0] A;
181 input [B_WIDTH-1:0] B;
182 output [Y_WIDTH-1:0] Y;
183
184 generate
185 if (A_SIGNED && B_SIGNED) begin:BLOCK1
186 assign Y = $signed(A) ~^ $signed(B);
187 end else begin:BLOCK2
188 assign Y = A ~^ B;
189 end
190 endgenerate
191
192 endmodule
193
194 // --------------------------------------------------------
195
196 module \$reduce_and (A, Y);
197
198 parameter A_SIGNED = 0;
199 parameter A_WIDTH = 0;
200 parameter Y_WIDTH = 0;
201
202 input [A_WIDTH-1:0] A;
203 output [Y_WIDTH-1:0] Y;
204
205 generate
206 if (A_SIGNED) begin:BLOCK1
207 assign Y = &$signed(A);
208 end else begin:BLOCK2
209 assign Y = &A;
210 end
211 endgenerate
212
213 endmodule
214
215 // --------------------------------------------------------
216
217 module \$reduce_or (A, Y);
218
219 parameter A_SIGNED = 0;
220 parameter A_WIDTH = 0;
221 parameter Y_WIDTH = 0;
222
223 input [A_WIDTH-1:0] A;
224 output [Y_WIDTH-1:0] Y;
225
226 generate
227 if (A_SIGNED) begin:BLOCK1
228 assign Y = |$signed(A);
229 end else begin:BLOCK2
230 assign Y = |A;
231 end
232 endgenerate
233
234 endmodule
235
236 // --------------------------------------------------------
237
238 module \$reduce_xor (A, Y);
239
240 parameter A_SIGNED = 0;
241 parameter A_WIDTH = 0;
242 parameter Y_WIDTH = 0;
243
244 input [A_WIDTH-1:0] A;
245 output [Y_WIDTH-1:0] Y;
246
247 generate
248 if (A_SIGNED) begin:BLOCK1
249 assign Y = ^$signed(A);
250 end else begin:BLOCK2
251 assign Y = ^A;
252 end
253 endgenerate
254
255 endmodule
256
257 // --------------------------------------------------------
258
259 module \$reduce_xnor (A, Y);
260
261 parameter A_SIGNED = 0;
262 parameter A_WIDTH = 0;
263 parameter Y_WIDTH = 0;
264
265 input [A_WIDTH-1:0] A;
266 output [Y_WIDTH-1:0] Y;
267
268 generate
269 if (A_SIGNED) begin:BLOCK1
270 assign Y = ~^$signed(A);
271 end else begin:BLOCK2
272 assign Y = ~^A;
273 end
274 endgenerate
275
276 endmodule
277
278 // --------------------------------------------------------
279
280 module \$reduce_bool (A, Y);
281
282 parameter A_SIGNED = 0;
283 parameter A_WIDTH = 0;
284 parameter Y_WIDTH = 0;
285
286 input [A_WIDTH-1:0] A;
287 output [Y_WIDTH-1:0] Y;
288
289 generate
290 if (A_SIGNED) begin:BLOCK1
291 assign Y = !(!$signed(A));
292 end else begin:BLOCK2
293 assign Y = !(!A);
294 end
295 endgenerate
296
297 endmodule
298
299 // --------------------------------------------------------
300
301 module \$shl (A, B, Y);
302
303 parameter A_SIGNED = 0;
304 parameter B_SIGNED = 0;
305 parameter A_WIDTH = 0;
306 parameter B_WIDTH = 0;
307 parameter Y_WIDTH = 0;
308
309 input [A_WIDTH-1:0] A;
310 input [B_WIDTH-1:0] B;
311 output [Y_WIDTH-1:0] Y;
312
313 generate
314 if (A_SIGNED) begin:BLOCK1
315 assign Y = $signed(A) << B;
316 end else begin:BLOCK2
317 assign Y = A << B;
318 end
319 endgenerate
320
321 endmodule
322
323 // --------------------------------------------------------
324
325 module \$shr (A, B, Y);
326
327 parameter A_SIGNED = 0;
328 parameter B_SIGNED = 0;
329 parameter A_WIDTH = 0;
330 parameter B_WIDTH = 0;
331 parameter Y_WIDTH = 0;
332
333 input [A_WIDTH-1:0] A;
334 input [B_WIDTH-1:0] B;
335 output [Y_WIDTH-1:0] Y;
336
337 generate
338 if (A_SIGNED) begin:BLOCK1
339 assign Y = $signed(A) >> B;
340 end else begin:BLOCK2
341 assign Y = A >> B;
342 end
343 endgenerate
344
345 endmodule
346
347 // --------------------------------------------------------
348
349 module \$sshl (A, B, Y);
350
351 parameter A_SIGNED = 0;
352 parameter B_SIGNED = 0;
353 parameter A_WIDTH = 0;
354 parameter B_WIDTH = 0;
355 parameter Y_WIDTH = 0;
356
357 input [A_WIDTH-1:0] A;
358 input [B_WIDTH-1:0] B;
359 output [Y_WIDTH-1:0] Y;
360
361 generate
362 if (A_SIGNED) begin:BLOCK1
363 assign Y = $signed(A) <<< B;
364 end else begin:BLOCK2
365 assign Y = A <<< B;
366 end
367 endgenerate
368
369 endmodule
370
371 // --------------------------------------------------------
372
373 module \$sshr (A, B, Y);
374
375 parameter A_SIGNED = 0;
376 parameter B_SIGNED = 0;
377 parameter A_WIDTH = 0;
378 parameter B_WIDTH = 0;
379 parameter Y_WIDTH = 0;
380
381 input [A_WIDTH-1:0] A;
382 input [B_WIDTH-1:0] B;
383 output [Y_WIDTH-1:0] Y;
384
385 generate
386 if (A_SIGNED) begin:BLOCK1
387 assign Y = $signed(A) >>> B;
388 end else begin:BLOCK2
389 assign Y = A >>> B;
390 end
391 endgenerate
392
393 endmodule
394
395 // --------------------------------------------------------
396
397 module \$shift (A, B, Y);
398
399 parameter A_SIGNED = 0;
400 parameter B_SIGNED = 0;
401 parameter A_WIDTH = 0;
402 parameter B_WIDTH = 0;
403 parameter Y_WIDTH = 0;
404
405 input [A_WIDTH-1:0] A;
406 input [B_WIDTH-1:0] B;
407 output [Y_WIDTH-1:0] Y;
408
409 generate
410 if (B_SIGNED) begin:BLOCK1
411 assign Y = $signed(B) < 0 ? A << -B : A >> B;
412 end else begin:BLOCK2
413 assign Y = A >> B;
414 end
415 endgenerate
416
417 endmodule
418
419 // --------------------------------------------------------
420
421 module \$shiftx (A, B, Y);
422
423 parameter A_SIGNED = 0;
424 parameter B_SIGNED = 0;
425 parameter A_WIDTH = 0;
426 parameter B_WIDTH = 0;
427 parameter Y_WIDTH = 0;
428
429 input [A_WIDTH-1:0] A;
430 input [B_WIDTH-1:0] B;
431 output [Y_WIDTH-1:0] Y;
432
433 generate
434 if (Y_WIDTH > 0)
435 if (B_SIGNED) begin:BLOCK1
436 assign Y = A[$signed(B) +: Y_WIDTH];
437 end else begin:BLOCK2
438 assign Y = A[B +: Y_WIDTH];
439 end
440 endgenerate
441
442 endmodule
443
444 // --------------------------------------------------------
445
446 module \$fa (A, B, C, X, Y);
447
448 parameter WIDTH = 1;
449
450 input [WIDTH-1:0] A, B, C;
451 output [WIDTH-1:0] X, Y;
452
453 wire [WIDTH-1:0] t1, t2, t3;
454
455 assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
456 assign Y = t1 ^ C, X = (t2 | t3) ^ (Y ^ Y);
457
458 endmodule
459
460 // --------------------------------------------------------
461
462 module \$lcu (P, G, CI, CO);
463
464 parameter WIDTH = 1;
465
466 input [WIDTH-1:0] P, G;
467 input CI;
468
469 output reg [WIDTH-1:0] CO;
470
471 integer i;
472 always @* begin
473 CO = 'bx;
474 if (^{P, G, CI} !== 1'bx) begin
475 CO[0] = G[0] || (P[0] && CI);
476 for (i = 1; i < WIDTH; i = i+1)
477 CO[i] = G[i] || (P[i] && CO[i-1]);
478 end
479 end
480
481 endmodule
482
483 // --------------------------------------------------------
484
485 module \$alu (A, B, CI, BI, X, Y, CO);
486
487 parameter A_SIGNED = 0;
488 parameter B_SIGNED = 0;
489 parameter A_WIDTH = 1;
490 parameter B_WIDTH = 1;
491 parameter Y_WIDTH = 1;
492
493 input [A_WIDTH-1:0] A;
494 input [B_WIDTH-1:0] B;
495 output [Y_WIDTH-1:0] X, Y;
496
497 input CI, BI;
498 output [Y_WIDTH-1:0] CO;
499
500 wire [Y_WIDTH-1:0] AA, BB;
501
502 generate
503 if (A_SIGNED && B_SIGNED) begin:BLOCK1
504 assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B);
505 end else begin:BLOCK2
506 assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B);
507 end
508 endgenerate
509
510 // this is 'x' if Y and CO should be all 'x', and '0' otherwise
511 wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI};
512
513 assign X = AA ^ BB;
514 assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}};
515
516 function get_carry;
517 input a, b, c;
518 get_carry = (a&b) | (a&c) | (b&c);
519 endfunction
520
521 genvar i;
522 generate
523 assign CO[0] = get_carry(AA[0], BB[0], CI) ^ y_co_undef;
524 for (i = 1; i < Y_WIDTH; i = i+1) begin:BLOCK3
525 assign CO[i] = get_carry(AA[i], BB[i], CO[i-1]) ^ y_co_undef;
526 end
527 endgenerate
528
529 endmodule
530
531 // --------------------------------------------------------
532
533 module \$lt (A, B, Y);
534
535 parameter A_SIGNED = 0;
536 parameter B_SIGNED = 0;
537 parameter A_WIDTH = 0;
538 parameter B_WIDTH = 0;
539 parameter Y_WIDTH = 0;
540
541 input [A_WIDTH-1:0] A;
542 input [B_WIDTH-1:0] B;
543 output [Y_WIDTH-1:0] Y;
544
545 generate
546 if (A_SIGNED && B_SIGNED) begin:BLOCK1
547 assign Y = $signed(A) < $signed(B);
548 end else begin:BLOCK2
549 assign Y = A < B;
550 end
551 endgenerate
552
553 endmodule
554
555 // --------------------------------------------------------
556
557 module \$le (A, B, Y);
558
559 parameter A_SIGNED = 0;
560 parameter B_SIGNED = 0;
561 parameter A_WIDTH = 0;
562 parameter B_WIDTH = 0;
563 parameter Y_WIDTH = 0;
564
565 input [A_WIDTH-1:0] A;
566 input [B_WIDTH-1:0] B;
567 output [Y_WIDTH-1:0] Y;
568
569 generate
570 if (A_SIGNED && B_SIGNED) begin:BLOCK1
571 assign Y = $signed(A) <= $signed(B);
572 end else begin:BLOCK2
573 assign Y = A <= B;
574 end
575 endgenerate
576
577 endmodule
578
579 // --------------------------------------------------------
580
581 module \$eq (A, B, Y);
582
583 parameter A_SIGNED = 0;
584 parameter B_SIGNED = 0;
585 parameter A_WIDTH = 0;
586 parameter B_WIDTH = 0;
587 parameter Y_WIDTH = 0;
588
589 input [A_WIDTH-1:0] A;
590 input [B_WIDTH-1:0] B;
591 output [Y_WIDTH-1:0] Y;
592
593 generate
594 if (A_SIGNED && B_SIGNED) begin:BLOCK1
595 assign Y = $signed(A) == $signed(B);
596 end else begin:BLOCK2
597 assign Y = A == B;
598 end
599 endgenerate
600
601 endmodule
602
603 // --------------------------------------------------------
604
605 module \$ne (A, B, Y);
606
607 parameter A_SIGNED = 0;
608 parameter B_SIGNED = 0;
609 parameter A_WIDTH = 0;
610 parameter B_WIDTH = 0;
611 parameter Y_WIDTH = 0;
612
613 input [A_WIDTH-1:0] A;
614 input [B_WIDTH-1:0] B;
615 output [Y_WIDTH-1:0] Y;
616
617 generate
618 if (A_SIGNED && B_SIGNED) begin:BLOCK1
619 assign Y = $signed(A) != $signed(B);
620 end else begin:BLOCK2
621 assign Y = A != B;
622 end
623 endgenerate
624
625 endmodule
626
627 // --------------------------------------------------------
628
629 module \$eqx (A, B, Y);
630
631 parameter A_SIGNED = 0;
632 parameter B_SIGNED = 0;
633 parameter A_WIDTH = 0;
634 parameter B_WIDTH = 0;
635 parameter Y_WIDTH = 0;
636
637 input [A_WIDTH-1:0] A;
638 input [B_WIDTH-1:0] B;
639 output [Y_WIDTH-1:0] Y;
640
641 generate
642 if (A_SIGNED && B_SIGNED) begin:BLOCK1
643 assign Y = $signed(A) === $signed(B);
644 end else begin:BLOCK2
645 assign Y = A === B;
646 end
647 endgenerate
648
649 endmodule
650
651 // --------------------------------------------------------
652
653 module \$nex (A, B, Y);
654
655 parameter A_SIGNED = 0;
656 parameter B_SIGNED = 0;
657 parameter A_WIDTH = 0;
658 parameter B_WIDTH = 0;
659 parameter Y_WIDTH = 0;
660
661 input [A_WIDTH-1:0] A;
662 input [B_WIDTH-1:0] B;
663 output [Y_WIDTH-1:0] Y;
664
665 generate
666 if (A_SIGNED && B_SIGNED) begin:BLOCK1
667 assign Y = $signed(A) !== $signed(B);
668 end else begin:BLOCK2
669 assign Y = A !== B;
670 end
671 endgenerate
672
673 endmodule
674
675 // --------------------------------------------------------
676
677 module \$ge (A, B, Y);
678
679 parameter A_SIGNED = 0;
680 parameter B_SIGNED = 0;
681 parameter A_WIDTH = 0;
682 parameter B_WIDTH = 0;
683 parameter Y_WIDTH = 0;
684
685 input [A_WIDTH-1:0] A;
686 input [B_WIDTH-1:0] B;
687 output [Y_WIDTH-1:0] Y;
688
689 generate
690 if (A_SIGNED && B_SIGNED) begin:BLOCK1
691 assign Y = $signed(A) >= $signed(B);
692 end else begin:BLOCK2
693 assign Y = A >= B;
694 end
695 endgenerate
696
697 endmodule
698
699 // --------------------------------------------------------
700
701 module \$gt (A, B, Y);
702
703 parameter A_SIGNED = 0;
704 parameter B_SIGNED = 0;
705 parameter A_WIDTH = 0;
706 parameter B_WIDTH = 0;
707 parameter Y_WIDTH = 0;
708
709 input [A_WIDTH-1:0] A;
710 input [B_WIDTH-1:0] B;
711 output [Y_WIDTH-1:0] Y;
712
713 generate
714 if (A_SIGNED && B_SIGNED) begin:BLOCK1
715 assign Y = $signed(A) > $signed(B);
716 end else begin:BLOCK2
717 assign Y = A > B;
718 end
719 endgenerate
720
721 endmodule
722
723 // --------------------------------------------------------
724
725 module \$add (A, B, Y);
726
727 parameter A_SIGNED = 0;
728 parameter B_SIGNED = 0;
729 parameter A_WIDTH = 0;
730 parameter B_WIDTH = 0;
731 parameter Y_WIDTH = 0;
732
733 input [A_WIDTH-1:0] A;
734 input [B_WIDTH-1:0] B;
735 output [Y_WIDTH-1:0] Y;
736
737 generate
738 if (A_SIGNED && B_SIGNED) begin:BLOCK1
739 assign Y = $signed(A) + $signed(B);
740 end else begin:BLOCK2
741 assign Y = A + B;
742 end
743 endgenerate
744
745 endmodule
746
747 // --------------------------------------------------------
748
749 module \$sub (A, B, Y);
750
751 parameter A_SIGNED = 0;
752 parameter B_SIGNED = 0;
753 parameter A_WIDTH = 0;
754 parameter B_WIDTH = 0;
755 parameter Y_WIDTH = 0;
756
757 input [A_WIDTH-1:0] A;
758 input [B_WIDTH-1:0] B;
759 output [Y_WIDTH-1:0] Y;
760
761 generate
762 if (A_SIGNED && B_SIGNED) begin:BLOCK1
763 assign Y = $signed(A) - $signed(B);
764 end else begin:BLOCK2
765 assign Y = A - B;
766 end
767 endgenerate
768
769 endmodule
770
771 // --------------------------------------------------------
772
773 module \$mul (A, B, Y);
774
775 parameter A_SIGNED = 0;
776 parameter B_SIGNED = 0;
777 parameter A_WIDTH = 0;
778 parameter B_WIDTH = 0;
779 parameter Y_WIDTH = 0;
780
781 input [A_WIDTH-1:0] A;
782 input [B_WIDTH-1:0] B;
783 output [Y_WIDTH-1:0] Y;
784
785 generate
786 if (A_SIGNED && B_SIGNED) begin:BLOCK1
787 assign Y = $signed(A) * $signed(B);
788 end else begin:BLOCK2
789 assign Y = A * B;
790 end
791 endgenerate
792
793 endmodule
794
795 // --------------------------------------------------------
796
797 module \$macc (A, B, Y);
798
799 parameter A_WIDTH = 0;
800 parameter B_WIDTH = 0;
801 parameter Y_WIDTH = 0;
802 parameter CONFIG = 4'b0000;
803 parameter CONFIG_WIDTH = 4;
804
805 input [A_WIDTH-1:0] A;
806 input [B_WIDTH-1:0] B;
807 output reg [Y_WIDTH-1:0] Y;
808
809 // Xilinx XSIM does not like $clog2() below..
810 function integer my_clog2;
811 input integer v;
812 begin
813 if (v > 0)
814 v = v - 1;
815 my_clog2 = 0;
816 while (v) begin
817 v = v >> 1;
818 my_clog2 = my_clog2 + 1;
819 end
820 end
821 endfunction
822
823 localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1;
824 localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits);
825 localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1;
826
827 function [2*num_ports*num_abits-1:0] get_port_offsets;
828 input [CONFIG_WIDTH-1:0] cfg;
829 integer i, cursor;
830 begin
831 cursor = 0;
832 get_port_offsets = 0;
833 for (i = 0; i < num_ports; i = i+1) begin
834 get_port_offsets[(2*i + 0)*num_abits +: num_abits] = cursor;
835 cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 +: num_bits];
836 get_port_offsets[(2*i + 1)*num_abits +: num_abits] = cursor;
837 cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits];
838 end
839 end
840 endfunction
841
842 localparam [2*num_ports*num_abits-1:0] port_offsets = get_port_offsets(CONFIG);
843
844 `define PORT_IS_SIGNED (0 + CONFIG[4 + i*(2 + 2*num_bits)])
845 `define PORT_DO_SUBTRACT (0 + CONFIG[4 + i*(2 + 2*num_bits) + 1])
846 `define PORT_SIZE_A (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 +: num_bits])
847 `define PORT_SIZE_B (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits])
848 `define PORT_OFFSET_A (0 + port_offsets[2*i*num_abits +: num_abits])
849 `define PORT_OFFSET_B (0 + port_offsets[2*i*num_abits + num_abits +: num_abits])
850
851 integer i, j;
852 reg [Y_WIDTH-1:0] tmp_a, tmp_b;
853
854 always @* begin
855 Y = 0;
856 for (i = 0; i < num_ports; i = i+1)
857 begin
858 tmp_a = 0;
859 tmp_b = 0;
860
861 for (j = 0; j < `PORT_SIZE_A; j = j+1)
862 tmp_a[j] = A[`PORT_OFFSET_A + j];
863
864 if (`PORT_IS_SIGNED && `PORT_SIZE_A > 0)
865 for (j = `PORT_SIZE_A; j < Y_WIDTH; j = j+1)
866 tmp_a[j] = tmp_a[`PORT_SIZE_A-1];
867
868 for (j = 0; j < `PORT_SIZE_B; j = j+1)
869 tmp_b[j] = A[`PORT_OFFSET_B + j];
870
871 if (`PORT_IS_SIGNED && `PORT_SIZE_B > 0)
872 for (j = `PORT_SIZE_B; j < Y_WIDTH; j = j+1)
873 tmp_b[j] = tmp_b[`PORT_SIZE_B-1];
874
875 if (`PORT_SIZE_B > 0)
876 tmp_a = tmp_a * tmp_b;
877
878 if (`PORT_DO_SUBTRACT)
879 Y = Y - tmp_a;
880 else
881 Y = Y + tmp_a;
882 end
883 for (i = 0; i < B_WIDTH; i = i+1) begin
884 Y = Y + B[i];
885 end
886 end
887
888 `undef PORT_IS_SIGNED
889 `undef PORT_DO_SUBTRACT
890 `undef PORT_SIZE_A
891 `undef PORT_SIZE_B
892 `undef PORT_OFFSET_A
893 `undef PORT_OFFSET_B
894
895 endmodule
896
897 // --------------------------------------------------------
898
899 module \$div (A, B, Y);
900
901 parameter A_SIGNED = 0;
902 parameter B_SIGNED = 0;
903 parameter A_WIDTH = 0;
904 parameter B_WIDTH = 0;
905 parameter Y_WIDTH = 0;
906
907 input [A_WIDTH-1:0] A;
908 input [B_WIDTH-1:0] B;
909 output [Y_WIDTH-1:0] Y;
910
911 generate
912 if (A_SIGNED && B_SIGNED) begin:BLOCK1
913 assign Y = $signed(A) / $signed(B);
914 end else begin:BLOCK2
915 assign Y = A / B;
916 end
917 endgenerate
918
919 endmodule
920
921 // --------------------------------------------------------
922
923 module \$mod (A, B, Y);
924
925 parameter A_SIGNED = 0;
926 parameter B_SIGNED = 0;
927 parameter A_WIDTH = 0;
928 parameter B_WIDTH = 0;
929 parameter Y_WIDTH = 0;
930
931 input [A_WIDTH-1:0] A;
932 input [B_WIDTH-1:0] B;
933 output [Y_WIDTH-1:0] Y;
934
935 generate
936 if (A_SIGNED && B_SIGNED) begin:BLOCK1
937 assign Y = $signed(A) % $signed(B);
938 end else begin:BLOCK2
939 assign Y = A % B;
940 end
941 endgenerate
942
943 endmodule
944
945 // --------------------------------------------------------
946 `ifndef SIMLIB_NOPOW
947
948 module \$pow (A, B, Y);
949
950 parameter A_SIGNED = 0;
951 parameter B_SIGNED = 0;
952 parameter A_WIDTH = 0;
953 parameter B_WIDTH = 0;
954 parameter Y_WIDTH = 0;
955
956 input [A_WIDTH-1:0] A;
957 input [B_WIDTH-1:0] B;
958 output [Y_WIDTH-1:0] Y;
959
960 generate
961 if (A_SIGNED && B_SIGNED) begin:BLOCK1
962 assign Y = $signed(A) ** $signed(B);
963 end else if (A_SIGNED) begin:BLOCK2
964 assign Y = $signed(A) ** B;
965 end else if (B_SIGNED) begin:BLOCK3
966 assign Y = A ** $signed(B);
967 end else begin:BLOCK4
968 assign Y = A ** B;
969 end
970 endgenerate
971
972 endmodule
973
974 `endif
975 // --------------------------------------------------------
976
977 module \$logic_not (A, Y);
978
979 parameter A_SIGNED = 0;
980 parameter A_WIDTH = 0;
981 parameter Y_WIDTH = 0;
982
983 input [A_WIDTH-1:0] A;
984 output [Y_WIDTH-1:0] Y;
985
986 generate
987 if (A_SIGNED) begin:BLOCK1
988 assign Y = !$signed(A);
989 end else begin:BLOCK2
990 assign Y = !A;
991 end
992 endgenerate
993
994 endmodule
995
996 // --------------------------------------------------------
997
998 module \$logic_and (A, B, Y);
999
1000 parameter A_SIGNED = 0;
1001 parameter B_SIGNED = 0;
1002 parameter A_WIDTH = 0;
1003 parameter B_WIDTH = 0;
1004 parameter Y_WIDTH = 0;
1005
1006 input [A_WIDTH-1:0] A;
1007 input [B_WIDTH-1:0] B;
1008 output [Y_WIDTH-1:0] Y;
1009
1010 generate
1011 if (A_SIGNED && B_SIGNED) begin:BLOCK1
1012 assign Y = $signed(A) && $signed(B);
1013 end else begin:BLOCK2
1014 assign Y = A && B;
1015 end
1016 endgenerate
1017
1018 endmodule
1019
1020 // --------------------------------------------------------
1021
1022 module \$logic_or (A, B, Y);
1023
1024 parameter A_SIGNED = 0;
1025 parameter B_SIGNED = 0;
1026 parameter A_WIDTH = 0;
1027 parameter B_WIDTH = 0;
1028 parameter Y_WIDTH = 0;
1029
1030 input [A_WIDTH-1:0] A;
1031 input [B_WIDTH-1:0] B;
1032 output [Y_WIDTH-1:0] Y;
1033
1034 generate
1035 if (A_SIGNED && B_SIGNED) begin:BLOCK1
1036 assign Y = $signed(A) || $signed(B);
1037 end else begin:BLOCK2
1038 assign Y = A || B;
1039 end
1040 endgenerate
1041
1042 endmodule
1043
1044 // --------------------------------------------------------
1045
1046 module \$slice (A, Y);
1047
1048 parameter OFFSET = 0;
1049 parameter A_WIDTH = 0;
1050 parameter Y_WIDTH = 0;
1051
1052 input [A_WIDTH-1:0] A;
1053 output [Y_WIDTH-1:0] Y;
1054
1055 assign Y = A >> OFFSET;
1056
1057 endmodule
1058
1059 // --------------------------------------------------------
1060
1061 module \$concat (A, B, Y);
1062
1063 parameter A_WIDTH = 0;
1064 parameter B_WIDTH = 0;
1065
1066 input [A_WIDTH-1:0] A;
1067 input [B_WIDTH-1:0] B;
1068 output [A_WIDTH+B_WIDTH-1:0] Y;
1069
1070 assign Y = {B, A};
1071
1072 endmodule
1073
1074 // --------------------------------------------------------
1075
1076 module \$mux (A, B, S, Y);
1077
1078 parameter WIDTH = 0;
1079
1080 input [WIDTH-1:0] A, B;
1081 input S;
1082 output reg [WIDTH-1:0] Y;
1083
1084 always @* begin
1085 if (S)
1086 Y = B;
1087 else
1088 Y = A;
1089 end
1090
1091 endmodule
1092
1093 // --------------------------------------------------------
1094
1095 module \$pmux (A, B, S, Y);
1096
1097 parameter WIDTH = 0;
1098 parameter S_WIDTH = 0;
1099
1100 input [WIDTH-1:0] A;
1101 input [WIDTH*S_WIDTH-1:0] B;
1102 input [S_WIDTH-1:0] S;
1103 output reg [WIDTH-1:0] Y;
1104
1105 integer i;
1106 reg found_active_sel_bit;
1107
1108 always @* begin
1109 Y = A;
1110 found_active_sel_bit = 0;
1111 for (i = 0; i < S_WIDTH; i = i+1)
1112 if (S[i]) begin
1113 Y = found_active_sel_bit ? 'bx : B >> (WIDTH*i);
1114 found_active_sel_bit = 1;
1115 end
1116 end
1117
1118 endmodule
1119
1120 // --------------------------------------------------------
1121 `ifndef SIMLIB_NOLUT
1122
1123 module \$lut (A, Y);
1124
1125 parameter WIDTH = 0;
1126 parameter LUT = 0;
1127
1128 input [WIDTH-1:0] A;
1129 output reg Y;
1130
1131 wire lut0_out, lut1_out;
1132
1133 generate
1134 if (WIDTH <= 1) begin:simple
1135 assign {lut1_out, lut0_out} = LUT;
1136 end else begin:complex
1137 \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) );
1138 \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) );
1139 end
1140
1141 if (WIDTH > 0) begin:lutlogic
1142 always @* begin
1143 casez ({A[WIDTH-1], lut0_out, lut1_out})
1144 3'b?11: Y = 1'b1;
1145 3'b?00: Y = 1'b0;
1146 3'b0??: Y = lut0_out;
1147 3'b1??: Y = lut1_out;
1148 default: Y = 1'bx;
1149 endcase
1150 end
1151 end
1152 endgenerate
1153
1154 endmodule
1155
1156 `endif
1157 // --------------------------------------------------------
1158
1159 module \$assert (A, EN);
1160
1161 input A, EN;
1162
1163 `ifndef SIMLIB_NOCHECKS
1164 always @* begin
1165 if (A !== 1'b1 && EN === 1'b1) begin
1166 $display("Assertation %m failed!");
1167 $stop;
1168 end
1169 end
1170 `endif
1171
1172 endmodule
1173
1174 // --------------------------------------------------------
1175
1176 module \$assume (A, EN);
1177
1178 input A, EN;
1179
1180 `ifndef SIMLIB_NOCHECKS
1181 always @* begin
1182 if (A !== 1'b1 && EN === 1'b1) begin
1183 $display("Assumption %m failed!");
1184 $stop;
1185 end
1186 end
1187 `endif
1188
1189 endmodule
1190
1191 // --------------------------------------------------------
1192
1193 module \$equiv (A, B, Y);
1194
1195 input A, B;
1196 output Y;
1197
1198 assign Y = (A !== 1'bx && A !== B) ? 1'bx : A;
1199
1200 `ifndef SIMLIB_NOCHECKS
1201 always @* begin
1202 if (A !== 1'bx && A !== B) begin
1203 $display("Equivalence failed!");
1204 $stop;
1205 end
1206 end
1207 `endif
1208
1209 endmodule
1210
1211 // --------------------------------------------------------
1212 `ifndef SIMLIB_NOSR
1213
1214 module \$sr (SET, CLR, Q);
1215
1216 parameter WIDTH = 0;
1217 parameter SET_POLARITY = 1'b1;
1218 parameter CLR_POLARITY = 1'b1;
1219
1220 input [WIDTH-1:0] SET, CLR;
1221 output reg [WIDTH-1:0] Q;
1222
1223 wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
1224 wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
1225
1226 genvar i;
1227 generate
1228 for (i = 0; i < WIDTH; i = i+1) begin:bit
1229 always @(posedge pos_set[i], posedge pos_clr[i])
1230 if (pos_clr[i])
1231 Q[i] <= 0;
1232 else if (pos_set[i])
1233 Q[i] <= 1;
1234 end
1235 endgenerate
1236
1237 endmodule
1238
1239 `endif
1240 // --------------------------------------------------------
1241
1242 module \$dff (CLK, D, Q);
1243
1244 parameter WIDTH = 0;
1245 parameter CLK_POLARITY = 1'b1;
1246
1247 input CLK;
1248 input [WIDTH-1:0] D;
1249 output reg [WIDTH-1:0] Q;
1250 wire pos_clk = CLK == CLK_POLARITY;
1251
1252 always @(posedge pos_clk) begin
1253 Q <= D;
1254 end
1255
1256 endmodule
1257
1258 // --------------------------------------------------------
1259
1260 module \$dffe (CLK, EN, D, Q);
1261
1262 parameter WIDTH = 0;
1263 parameter CLK_POLARITY = 1'b1;
1264 parameter EN_POLARITY = 1'b1;
1265
1266 input CLK, EN;
1267 input [WIDTH-1:0] D;
1268 output reg [WIDTH-1:0] Q;
1269 wire pos_clk = CLK == CLK_POLARITY;
1270
1271 always @(posedge pos_clk) begin
1272 if (EN == EN_POLARITY) Q <= D;
1273 end
1274
1275 endmodule
1276
1277 // --------------------------------------------------------
1278 `ifndef SIMLIB_NOSR
1279
1280 module \$dffsr (CLK, SET, CLR, D, Q);
1281
1282 parameter WIDTH = 0;
1283 parameter CLK_POLARITY = 1'b1;
1284 parameter SET_POLARITY = 1'b1;
1285 parameter CLR_POLARITY = 1'b1;
1286
1287 input CLK;
1288 input [WIDTH-1:0] SET, CLR, D;
1289 output reg [WIDTH-1:0] Q;
1290
1291 wire pos_clk = CLK == CLK_POLARITY;
1292 wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
1293 wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
1294
1295 genvar i;
1296 generate
1297 for (i = 0; i < WIDTH; i = i+1) begin:bit
1298 always @(posedge pos_set[i], posedge pos_clr[i], posedge pos_clk)
1299 if (pos_clr[i])
1300 Q[i] <= 0;
1301 else if (pos_set[i])
1302 Q[i] <= 1;
1303 else
1304 Q[i] <= D[i];
1305 end
1306 endgenerate
1307
1308 endmodule
1309
1310 `endif
1311 // --------------------------------------------------------
1312
1313 module \$adff (CLK, ARST, D, Q);
1314
1315 parameter WIDTH = 0;
1316 parameter CLK_POLARITY = 1'b1;
1317 parameter ARST_POLARITY = 1'b1;
1318 parameter ARST_VALUE = 0;
1319
1320 input CLK, ARST;
1321 input [WIDTH-1:0] D;
1322 output reg [WIDTH-1:0] Q;
1323 wire pos_clk = CLK == CLK_POLARITY;
1324 wire pos_arst = ARST == ARST_POLARITY;
1325
1326 always @(posedge pos_clk, posedge pos_arst) begin
1327 if (pos_arst)
1328 Q <= ARST_VALUE;
1329 else
1330 Q <= D;
1331 end
1332
1333 endmodule
1334
1335 // --------------------------------------------------------
1336
1337 module \$dlatch (EN, D, Q);
1338
1339 parameter WIDTH = 0;
1340 parameter EN_POLARITY = 1'b1;
1341
1342 input EN;
1343 input [WIDTH-1:0] D;
1344 output reg [WIDTH-1:0] Q;
1345
1346 always @* begin
1347 if (EN == EN_POLARITY)
1348 Q = D;
1349 end
1350
1351 endmodule
1352
1353 // --------------------------------------------------------
1354 `ifndef SIMLIB_NOSR
1355
1356 module \$dlatchsr (EN, SET, CLR, D, Q);
1357
1358 parameter WIDTH = 0;
1359 parameter EN_POLARITY = 1'b1;
1360 parameter SET_POLARITY = 1'b1;
1361 parameter CLR_POLARITY = 1'b1;
1362
1363 input EN;
1364 input [WIDTH-1:0] SET, CLR, D;
1365 output reg [WIDTH-1:0] Q;
1366
1367 wire pos_en = EN == EN_POLARITY;
1368 wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET;
1369 wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR;
1370
1371 genvar i;
1372 generate
1373 for (i = 0; i < WIDTH; i = i+1) begin:bit
1374 always @*
1375 if (pos_clr[i])
1376 Q[i] = 0;
1377 else if (pos_set[i])
1378 Q[i] = 1;
1379 else if (pos_en)
1380 Q[i] = D[i];
1381 end
1382 endgenerate
1383
1384 endmodule
1385
1386 `endif
1387 // --------------------------------------------------------
1388
1389 module \$fsm (CLK, ARST, CTRL_IN, CTRL_OUT);
1390
1391 parameter NAME = "";
1392
1393 parameter CLK_POLARITY = 1'b1;
1394 parameter ARST_POLARITY = 1'b1;
1395
1396 parameter CTRL_IN_WIDTH = 1;
1397 parameter CTRL_OUT_WIDTH = 1;
1398
1399 parameter STATE_BITS = 1;
1400 parameter STATE_NUM = 1;
1401 parameter STATE_NUM_LOG2 = 1;
1402 parameter STATE_RST = 0;
1403 parameter STATE_TABLE = 1'b0;
1404
1405 parameter TRANS_NUM = 1;
1406 parameter TRANS_TABLE = 4'b0x0x;
1407
1408 input CLK, ARST;
1409 input [CTRL_IN_WIDTH-1:0] CTRL_IN;
1410 output reg [CTRL_OUT_WIDTH-1:0] CTRL_OUT;
1411
1412 wire pos_clk = CLK == CLK_POLARITY;
1413 wire pos_arst = ARST == ARST_POLARITY;
1414
1415 reg [STATE_BITS-1:0] state;
1416 reg [STATE_BITS-1:0] state_tmp;
1417 reg [STATE_BITS-1:0] next_state;
1418
1419 reg [STATE_BITS-1:0] tr_state_in;
1420 reg [STATE_BITS-1:0] tr_state_out;
1421 reg [CTRL_IN_WIDTH-1:0] tr_ctrl_in;
1422 reg [CTRL_OUT_WIDTH-1:0] tr_ctrl_out;
1423
1424 integer i;
1425
1426 task tr_fetch;
1427 input [31:0] tr_num;
1428 reg [31:0] tr_pos;
1429 reg [STATE_NUM_LOG2-1:0] state_num;
1430 begin
1431 tr_pos = (2*STATE_NUM_LOG2+CTRL_IN_WIDTH+CTRL_OUT_WIDTH)*tr_num;
1432 tr_ctrl_out = TRANS_TABLE >> tr_pos;
1433 tr_pos = tr_pos + CTRL_OUT_WIDTH;
1434 state_num = TRANS_TABLE >> tr_pos;
1435 tr_state_out = STATE_TABLE >> (STATE_BITS*state_num);
1436 tr_pos = tr_pos + STATE_NUM_LOG2;
1437 tr_ctrl_in = TRANS_TABLE >> tr_pos;
1438 tr_pos = tr_pos + CTRL_IN_WIDTH;
1439 state_num = TRANS_TABLE >> tr_pos;
1440 tr_state_in = STATE_TABLE >> (STATE_BITS*state_num);
1441 tr_pos = tr_pos + STATE_NUM_LOG2;
1442 end
1443 endtask
1444
1445 always @(posedge pos_clk, posedge pos_arst) begin
1446 if (pos_arst) begin
1447 state_tmp = STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST];
1448 for (i = 0; i < STATE_BITS; i = i+1)
1449 if (state_tmp[i] === 1'bz)
1450 state_tmp[i] = 0;
1451 state <= state_tmp;
1452 end else begin
1453 state_tmp = next_state;
1454 for (i = 0; i < STATE_BITS; i = i+1)
1455 if (state_tmp[i] === 1'bz)
1456 state_tmp[i] = 0;
1457 state <= state_tmp;
1458 end
1459 end
1460
1461 always @(state, CTRL_IN) begin
1462 next_state <= STATE_TABLE[STATE_BITS*(STATE_RST+1)-1:STATE_BITS*STATE_RST];
1463 CTRL_OUT <= 'bx;
1464 // $display("---");
1465 // $display("Q: %b %b", state, CTRL_IN);
1466 for (i = 0; i < TRANS_NUM; i = i+1) begin
1467 tr_fetch(i);
1468 // $display("T: %b %b -> %b %b [%d]", tr_state_in, tr_ctrl_in, tr_state_out, tr_ctrl_out, i);
1469 casez ({state, CTRL_IN})
1470 {tr_state_in, tr_ctrl_in}: begin
1471 // $display("-> %b %b <- MATCH", state, CTRL_IN);
1472 {next_state, CTRL_OUT} <= {tr_state_out, tr_ctrl_out};
1473 end
1474 endcase
1475 end
1476 end
1477
1478 endmodule
1479
1480 // --------------------------------------------------------
1481 `ifndef SIMLIB_NOMEM
1482
1483 module \$memrd (CLK, ADDR, DATA);
1484
1485 parameter MEMID = "";
1486 parameter ABITS = 8;
1487 parameter WIDTH = 8;
1488
1489 parameter CLK_ENABLE = 0;
1490 parameter CLK_POLARITY = 0;
1491 parameter TRANSPARENT = 0;
1492
1493 input CLK;
1494 input [ABITS-1:0] ADDR;
1495 output [WIDTH-1:0] DATA;
1496
1497 initial begin
1498 if (MEMID != "") begin
1499 $display("ERROR: Found non-simulatable instance of $memrd!");
1500 $finish;
1501 end
1502 end
1503
1504 endmodule
1505
1506 // --------------------------------------------------------
1507
1508 module \$memwr (CLK, EN, ADDR, DATA);
1509
1510 parameter MEMID = "";
1511 parameter ABITS = 8;
1512 parameter WIDTH = 8;
1513
1514 parameter CLK_ENABLE = 0;
1515 parameter CLK_POLARITY = 0;
1516 parameter PRIORITY = 0;
1517
1518 input CLK;
1519 input [WIDTH-1:0] EN;
1520 input [ABITS-1:0] ADDR;
1521 input [WIDTH-1:0] DATA;
1522
1523 initial begin
1524 if (MEMID != "") begin
1525 $display("ERROR: Found non-simulatable instance of $memwr!");
1526 $finish;
1527 end
1528 end
1529
1530 endmodule
1531
1532 // --------------------------------------------------------
1533
1534 module \$meminit (ADDR, DATA);
1535
1536 parameter MEMID = "";
1537 parameter ABITS = 8;
1538 parameter WIDTH = 8;
1539
1540 parameter PRIORITY = 0;
1541
1542 input [ABITS-1:0] ADDR;
1543 input [WIDTH-1:0] DATA;
1544
1545 initial begin
1546 if (MEMID != "") begin
1547 $display("ERROR: Found non-simulatable instance of $meminit!");
1548 $finish;
1549 end
1550 end
1551
1552 endmodule
1553
1554 // --------------------------------------------------------
1555
1556 module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA);
1557
1558 parameter MEMID = "";
1559 parameter signed SIZE = 4;
1560 parameter signed OFFSET = 0;
1561 parameter signed ABITS = 2;
1562 parameter signed WIDTH = 8;
1563 parameter signed INIT = 1'bx;
1564
1565 parameter signed RD_PORTS = 1;
1566 parameter RD_CLK_ENABLE = 1'b1;
1567 parameter RD_CLK_POLARITY = 1'b1;
1568 parameter RD_TRANSPARENT = 1'b1;
1569
1570 parameter signed WR_PORTS = 1;
1571 parameter WR_CLK_ENABLE = 1'b1;
1572 parameter WR_CLK_POLARITY = 1'b1;
1573
1574 input [RD_PORTS-1:0] RD_CLK;
1575 input [RD_PORTS*ABITS-1:0] RD_ADDR;
1576 output reg [RD_PORTS*WIDTH-1:0] RD_DATA;
1577
1578 input [WR_PORTS-1:0] WR_CLK;
1579 input [WR_PORTS*WIDTH-1:0] WR_EN;
1580 input [WR_PORTS*ABITS-1:0] WR_ADDR;
1581 input [WR_PORTS*WIDTH-1:0] WR_DATA;
1582
1583 reg [WIDTH-1:0] memory [SIZE-1:0];
1584
1585 integer i, j;
1586 reg [WR_PORTS-1:0] LAST_WR_CLK;
1587 reg [RD_PORTS-1:0] LAST_RD_CLK;
1588
1589 function port_active;
1590 input clk_enable;
1591 input clk_polarity;
1592 input last_clk;
1593 input this_clk;
1594 begin
1595 casez ({clk_enable, clk_polarity, last_clk, this_clk})
1596 4'b0???: port_active = 1;
1597 4'b1101: port_active = 1;
1598 4'b1010: port_active = 1;
1599 default: port_active = 0;
1600 endcase
1601 end
1602 endfunction
1603
1604 initial begin
1605 for (i = 0; i < SIZE; i = i+1)
1606 memory[i] = INIT >>> (i*WIDTH);
1607 end
1608
1609 always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin
1610 `ifdef SIMLIB_MEMDELAY
1611 #`SIMLIB_MEMDELAY;
1612 `endif
1613 for (i = 0; i < RD_PORTS; i = i+1) begin
1614 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
1615 // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
1616 RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
1617 end
1618 end
1619
1620 for (i = 0; i < WR_PORTS; i = i+1) begin
1621 if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i]))
1622 for (j = 0; j < WIDTH; j = j+1)
1623 if (WR_EN[i*WIDTH+j]) begin
1624 // $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]);
1625 memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j];
1626 end
1627 end
1628
1629 for (i = 0; i < RD_PORTS; i = i+1) begin
1630 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
1631 // $display("Transparent read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]);
1632 RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET];
1633 end
1634 end
1635
1636 LAST_RD_CLK <= RD_CLK;
1637 LAST_WR_CLK <= WR_CLK;
1638 end
1639
1640 endmodule
1641
1642 `endif
1643 // --------------------------------------------------------