Merge pull request #397 from azonenberg/gpak-libfixes
[yosys.git] / techlibs / greenpak4 / cells_sim_digital.v
1 `timescale 1ns/1ps
2
3 /*
4 This file contains simulation models for GreenPAK cells which are possible to fully model using synthesizeable
5 behavioral Verilog constructs only.
6 */
7
8 module GP_2LUT(input IN0, IN1, output OUT);
9 parameter [3:0] INIT = 0;
10 assign OUT = INIT[{IN1, IN0}];
11 endmodule
12
13 module GP_3LUT(input IN0, IN1, IN2, output OUT);
14 parameter [7:0] INIT = 0;
15 assign OUT = INIT[{IN2, IN1, IN0}];
16 endmodule
17
18 module GP_4LUT(
19 input wire IN0,
20 input wire IN1,
21 input wire IN2,
22 input wire IN3,
23 output wire OUT);
24
25 parameter [15:0] INIT = 0;
26 assign OUT = INIT[{IN3, IN2, IN1, IN0}];
27 endmodule
28
29 module GP_CLKBUF(input wire IN, output wire OUT);
30 assign OUT = IN;
31 endmodule
32
33 module GP_COUNT14(input CLK, input wire RST, output reg OUT);
34
35 parameter RESET_MODE = "RISING";
36
37 parameter COUNT_TO = 14'h1;
38 parameter CLKIN_DIVIDE = 1;
39
40 reg[13:0] count = COUNT_TO;
41
42 initial begin
43 if(CLKIN_DIVIDE != 1) begin
44 $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
45 $finish;
46 end
47 end
48
49 //Combinatorially output underflow flag whenever we wrap low
50 always @(*) begin
51 OUT <= (count == 14'h0);
52 end
53
54 //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
55 //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
56 generate
57 case(RESET_MODE)
58
59 "RISING": begin
60 always @(posedge CLK, posedge RST) begin
61 if(RST)
62 count <= 0;
63 else begin
64 count <= count - 1'd1;
65 if(count == 0)
66 count <= COUNT_TO;
67 end
68 end
69 end
70
71 "FALLING": begin
72 always @(posedge CLK, negedge RST) begin
73 if(!RST)
74 count <= 0;
75 else begin
76 count <= count - 1'd1;
77 if(count == 0)
78 count <= COUNT_TO;
79 end
80 end
81 end
82
83 "BOTH": begin
84 initial begin
85 $display("Both-edge reset mode for GP_COUNT14 not implemented");
86 $finish;
87 end
88 end
89
90 "LEVEL": begin
91 always @(posedge CLK, posedge RST) begin
92 if(RST)
93 count <= 0;
94
95 else begin
96 count <= count - 1'd1;
97 if(count == 0)
98 count <= COUNT_TO;
99 end
100 end
101 end
102
103 default: begin
104 initial begin
105 $display("Invalid RESET_MODE on GP_COUNT8");
106 $finish;
107 end
108 end
109
110 endcase
111 endgenerate
112
113 endmodule
114
115 module GP_COUNT14_ADV(input CLK, input RST, output reg OUT,
116 input UP, input KEEP, output reg[7:0] POUT);
117
118 parameter RESET_MODE = "RISING";
119 parameter RESET_VALUE = "ZERO";
120
121 parameter COUNT_TO = 14'h1;
122 parameter CLKIN_DIVIDE = 1;
123
124 initial begin
125 if(CLKIN_DIVIDE != 1) begin
126 $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
127 $finish;
128 end
129 end
130
131 reg[13:0] count = COUNT_TO;
132
133 //Combinatorially output underflow flag whenever we wrap low
134 always @(*) begin
135 if(UP)
136 OUT <= (count == 14'h3fff);
137 else
138 OUT <= (count == 14'h0);
139 POUT <= count[7:0];
140 end
141
142 //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
143 //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
144 generate
145 case(RESET_MODE)
146
147 "RISING": begin
148 always @(posedge CLK, posedge RST) begin
149
150 //Resets
151 if(RST) begin
152 if(RESET_VALUE == "ZERO")
153 count <= 0;
154 else
155 count <= COUNT_TO;
156 end
157
158 else if(KEEP) begin
159 end
160 else if(UP) begin
161 count <= count + 1'd1;
162 if(count == 14'h3fff)
163 count <= COUNT_TO;
164 end
165 else begin
166 count <= count - 1'd1;
167
168 if(count == 0)
169 count <= COUNT_TO;
170 end
171
172 end
173 end
174
175 "FALLING": begin
176 always @(posedge CLK, negedge RST) begin
177
178 //Resets
179 if(!RST) begin
180 if(RESET_VALUE == "ZERO")
181 count <= 0;
182 else
183 count <= COUNT_TO;
184 end
185
186 else if(KEEP) begin
187 end
188 else if(UP) begin
189 count <= count + 1'd1;
190 if(count == 14'h3fff)
191 count <= COUNT_TO;
192 end
193 else begin
194 count <= count - 1'd1;
195
196 if(count == 0)
197 count <= COUNT_TO;
198 end
199
200 end
201 end
202
203 "BOTH": begin
204 initial begin
205 $display("Both-edge reset mode for GP_COUNT14_ADV not implemented");
206 $finish;
207 end
208 end
209
210 "LEVEL": begin
211 always @(posedge CLK, posedge RST) begin
212
213 //Resets
214 if(RST) begin
215 if(RESET_VALUE == "ZERO")
216 count <= 0;
217 else
218 count <= COUNT_TO;
219 end
220
221 else begin
222
223 if(KEEP) begin
224 end
225 else if(UP) begin
226 count <= count + 1'd1;
227 if(count == 14'h3fff)
228 count <= COUNT_TO;
229 end
230 else begin
231 count <= count - 1'd1;
232
233 if(count == 0)
234 count <= COUNT_TO;
235 end
236
237 end
238
239 end
240 end
241
242 default: begin
243 initial begin
244 $display("Invalid RESET_MODE on GP_COUNT14_ADV");
245 $finish;
246 end
247 end
248
249 endcase
250 endgenerate
251
252 endmodule
253
254 module GP_COUNT8_ADV(input CLK, input RST, output reg OUT,
255 input UP, input KEEP, output reg[7:0] POUT);
256
257 parameter RESET_MODE = "RISING";
258 parameter RESET_VALUE = "ZERO";
259
260 parameter COUNT_TO = 8'h1;
261 parameter CLKIN_DIVIDE = 1;
262
263 reg[7:0] count = COUNT_TO;
264
265 initial begin
266 if(CLKIN_DIVIDE != 1) begin
267 $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
268 $finish;
269 end
270 end
271
272 //Combinatorially output underflow flag whenever we wrap low
273 always @(*) begin
274 if(UP)
275 OUT <= (count == 8'hff);
276 else
277 OUT <= (count == 8'h0);
278 POUT <= count;
279 end
280
281 //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
282 //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
283 generate
284 case(RESET_MODE)
285
286 "RISING": begin
287 always @(posedge CLK, posedge RST) begin
288
289 //Resets
290 if(RST) begin
291 if(RESET_VALUE == "ZERO")
292 count <= 0;
293 else
294 count <= COUNT_TO;
295 end
296
297 //Main counter
298 else if(KEEP) begin
299 end
300 else if(UP) begin
301 count <= count + 1'd1;
302 if(count == 8'hff)
303 count <= COUNT_TO;
304 end
305 else begin
306 count <= count - 1'd1;
307
308 if(count == 0)
309 count <= COUNT_TO;
310 end
311
312 end
313 end
314
315 "FALLING": begin
316 always @(posedge CLK, negedge RST) begin
317
318 //Resets
319 if(!RST) begin
320 if(RESET_VALUE == "ZERO")
321 count <= 0;
322 else
323 count <= COUNT_TO;
324 end
325
326 //Main counter
327 else if(KEEP) begin
328 end
329 else if(UP) begin
330 count <= count + 1'd1;
331 if(count == 8'hff)
332 count <= COUNT_TO;
333 end
334 else begin
335 count <= count - 1'd1;
336
337 if(count == 0)
338 count <= COUNT_TO;
339 end
340
341 end
342 end
343
344 "BOTH": begin
345 initial begin
346 $display("Both-edge reset mode for GP_COUNT8_ADV not implemented");
347 $finish;
348 end
349 end
350
351 "LEVEL": begin
352 always @(posedge CLK, posedge RST) begin
353
354 //Resets
355 if(RST) begin
356 if(RESET_VALUE == "ZERO")
357 count <= 0;
358 else
359 count <= COUNT_TO;
360 end
361
362 else begin
363
364 if(KEEP) begin
365 end
366 else if(UP) begin
367 count <= count + 1'd1;
368 if(count == 8'hff)
369 count <= COUNT_TO;
370 end
371 else begin
372 count <= count - 1'd1;
373
374 if(count == 0)
375 count <= COUNT_TO;
376 end
377 end
378
379 end
380 end
381
382 default: begin
383 initial begin
384 $display("Invalid RESET_MODE on GP_COUNT8_ADV");
385 $finish;
386 end
387 end
388
389 endcase
390 endgenerate
391
392 endmodule
393
394 module GP_COUNT8(
395 input wire CLK,
396 input wire RST,
397 output reg OUT,
398 output reg[7:0] POUT);
399
400 parameter RESET_MODE = "RISING";
401
402 parameter COUNT_TO = 8'h1;
403 parameter CLKIN_DIVIDE = 1;
404
405 initial begin
406 if(CLKIN_DIVIDE != 1) begin
407 $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented");
408 $finish;
409 end
410 end
411
412 reg[7:0] count = COUNT_TO;
413
414 //Combinatorially output underflow flag whenever we wrap low
415 always @(*) begin
416 OUT <= (count == 8'h0);
417 POUT <= count;
418 end
419
420 //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm.
421 //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now.
422 generate
423 case(RESET_MODE)
424
425 "RISING": begin
426 always @(posedge CLK, posedge RST) begin
427 if(RST)
428 count <= 0;
429 else begin
430 count <= count - 1'd1;
431 if(count == 0)
432 count <= COUNT_TO;
433 end
434 end
435 end
436
437 "FALLING": begin
438 always @(posedge CLK, negedge RST) begin
439 if(!RST)
440 count <= 0;
441 else begin
442 count <= count - 1'd1;
443 if(count == 0)
444 count <= COUNT_TO;
445 end
446 end
447 end
448
449 "BOTH": begin
450 initial begin
451 $display("Both-edge reset mode for GP_COUNT8 not implemented");
452 $finish;
453 end
454 end
455
456 "LEVEL": begin
457 always @(posedge CLK, posedge RST) begin
458 if(RST)
459 count <= 0;
460
461 else begin
462 count <= count - 1'd1;
463 if(count == 0)
464 count <= COUNT_TO;
465 end
466 end
467 end
468
469 default: begin
470 initial begin
471 $display("Invalid RESET_MODE on GP_COUNT8");
472 $finish;
473 end
474 end
475
476 endcase
477 endgenerate
478
479 endmodule
480
481 module GP_DCMPREF(output reg[7:0]OUT);
482 parameter[7:0] REF_VAL = 8'h00;
483 initial OUT = REF_VAL;
484 endmodule
485
486 module GP_DCMPMUX(input[1:0] SEL, input[7:0] IN0, input[7:0] IN1, input[7:0] IN2, input[7:0] IN3, output reg[7:0] OUTA, output reg[7:0] OUTB);
487
488 always @(*) begin
489 case(SEL)
490 2'd00: begin
491 OUTA <= IN0;
492 OUTB <= IN3;
493 end
494
495 2'd01: begin
496 OUTA <= IN1;
497 OUTB <= IN2;
498 end
499
500 2'd02: begin
501 OUTA <= IN2;
502 OUTB <= IN1;
503 end
504
505 2'd03: begin
506 OUTA <= IN3;
507 OUTB <= IN0;
508 end
509
510 endcase
511 end
512 endmodule
513
514 module GP_DELAY(input IN, output reg OUT);
515
516 parameter DELAY_STEPS = 1;
517 parameter GLITCH_FILTER = 0;
518
519 initial OUT = 0;
520
521 generate
522
523 if(GLITCH_FILTER) begin
524 initial begin
525 $display("ERROR: GP_DELAY glitch filter mode not implemented");
526 $finish;
527 end
528 end
529
530 //TODO: These delays are PTV dependent! For now, hard code 3v3 timing
531 //Change simulation-mode delay depending on global Vdd range (how to specify this?)
532 always @(*) begin
533 case(DELAY_STEPS)
534 1: #166 OUT = IN;
535 2: #318 OUT = IN;
536 2: #471 OUT = IN;
537 3: #622 OUT = IN;
538 default: begin
539 $display("ERROR: GP_DELAY must have DELAY_STEPS in range [1,4]");
540 $finish;
541 end
542 endcase
543 end
544
545 endgenerate
546
547 endmodule
548
549 module GP_DFF(input D, CLK, output reg Q);
550 parameter [0:0] INIT = 1'bx;
551 initial Q = INIT;
552 always @(posedge CLK) begin
553 Q <= D;
554 end
555 endmodule
556
557 module GP_DFFI(input D, CLK, output reg nQ);
558 parameter [0:0] INIT = 1'bx;
559 initial nQ = INIT;
560 always @(posedge CLK) begin
561 nQ <= ~D;
562 end
563 endmodule
564
565 module GP_DFFR(input D, CLK, nRST, output reg Q);
566 parameter [0:0] INIT = 1'bx;
567 initial Q = INIT;
568 always @(posedge CLK, negedge nRST) begin
569 if (!nRST)
570 Q <= 1'b0;
571 else
572 Q <= D;
573 end
574 endmodule
575
576 module GP_DFFRI(input D, CLK, nRST, output reg nQ);
577 parameter [0:0] INIT = 1'bx;
578 initial nQ = INIT;
579 always @(posedge CLK, negedge nRST) begin
580 if (!nRST)
581 nQ <= 1'b1;
582 else
583 nQ <= ~D;
584 end
585 endmodule
586
587 module GP_DFFS(input D, CLK, nSET, output reg Q);
588 parameter [0:0] INIT = 1'bx;
589 initial Q = INIT;
590 always @(posedge CLK, negedge nSET) begin
591 if (!nSET)
592 Q <= 1'b1;
593 else
594 Q <= D;
595 end
596 endmodule
597
598 module GP_DFFSI(input D, CLK, nSET, output reg nQ);
599 parameter [0:0] INIT = 1'bx;
600 initial nQ = INIT;
601 always @(posedge CLK, negedge nSET) begin
602 if (!nSET)
603 nQ <= 1'b0;
604 else
605 nQ <= ~D;
606 end
607 endmodule
608
609 module GP_DFFSR(input D, CLK, nSR, output reg Q);
610 parameter [0:0] INIT = 1'bx;
611 parameter [0:0] SRMODE = 1'bx;
612 initial Q = INIT;
613 always @(posedge CLK, negedge nSR) begin
614 if (!nSR)
615 Q <= SRMODE;
616 else
617 Q <= D;
618 end
619 endmodule
620
621 module GP_DFFSRI(input D, CLK, nSR, output reg nQ);
622 parameter [0:0] INIT = 1'bx;
623 parameter [0:0] SRMODE = 1'bx;
624 initial nQ = INIT;
625 always @(posedge CLK, negedge nSR) begin
626 if (!nSR)
627 nQ <= ~SRMODE;
628 else
629 nQ <= ~D;
630 end
631 endmodule
632
633 module GP_DLATCH(input D, input nCLK, output reg Q);
634 parameter [0:0] INIT = 1'bx;
635 initial Q = INIT;
636 always @(*) begin
637 if(!nCLK)
638 Q <= D;
639 end
640 endmodule
641
642 module GP_DLATCHI(input D, input nCLK, output reg nQ);
643 parameter [0:0] INIT = 1'bx;
644 initial nQ = INIT;
645 always @(*) begin
646 if(!nCLK)
647 nQ <= ~D;
648 end
649 endmodule
650
651 module GP_DLATCHR(input D, input nCLK, input nRST, output reg Q);
652 parameter [0:0] INIT = 1'bx;
653 initial Q = INIT;
654 always @(*) begin
655 if(!nRST)
656 Q <= 1'b0;
657 else if(!nCLK)
658 Q <= D;
659 end
660 endmodule
661
662 module GP_DLATCHRI(input D, input nCLK, input nRST, output reg nQ);
663 parameter [0:0] INIT = 1'bx;
664 initial nQ = INIT;
665 always @(*) begin
666 if(!nRST)
667 nQ <= 1'b1;
668 else if(!nCLK)
669 nQ <= ~D;
670 end
671 endmodule
672
673 module GP_DLATCHS(input D, input nCLK, input nSET, output reg Q);
674 parameter [0:0] INIT = 1'bx;
675 initial Q = INIT;
676 always @(*) begin
677 if(!nSET)
678 Q <= 1'b1;
679 else if(!nCLK)
680 Q <= D;
681 end
682 endmodule
683
684 module GP_DLATCHSI(input D, input nCLK, input nSET, output reg nQ);
685 parameter [0:0] INIT = 1'bx;
686 initial nQ = INIT;
687 always @(*) begin
688 if(!nSET)
689 nQ <= 1'b0;
690 else if(!nCLK)
691 nQ <= ~D;
692 end
693 endmodule
694
695 module GP_DLATCHSR(input D, input nCLK, input nSR, output reg Q);
696 parameter [0:0] INIT = 1'bx;
697 parameter[0:0] SRMODE = 1'bx;
698 initial Q = INIT;
699 always @(*) begin
700 if(!nSR)
701 Q <= SRMODE;
702 else if(!nCLK)
703 Q <= D;
704 end
705 endmodule
706
707 module GP_DLATCHSRI(input D, input nCLK, input nSR, output reg nQ);
708 parameter [0:0] INIT = 1'bx;
709 parameter[0:0] SRMODE = 1'bx;
710 initial nQ = INIT;
711 always @(*) begin
712 if(!nSR)
713 nQ <= ~SRMODE;
714 else if(!nCLK)
715 nQ <= ~D;
716 end
717 endmodule
718
719 module GP_IBUF(input IN, output OUT);
720 assign OUT = IN;
721 endmodule
722
723 module GP_IOBUF(input IN, input OE, output OUT, inout IO);
724 assign OUT = IO;
725 assign IO = OE ? IN : 1'bz;
726 endmodule
727
728 module GP_INV(input IN, output OUT);
729 assign OUT = ~IN;
730 endmodule
731
732 module GP_OBUF(input IN, output OUT);
733 assign OUT = IN;
734 endmodule
735
736 module GP_OBUFT(input IN, input OE, output OUT);
737 assign OUT = OE ? IN : 1'bz;
738 endmodule
739
740 module GP_PGEN(input wire nRST, input wire CLK, output reg OUT);
741 initial OUT = 0;
742 parameter PATTERN_DATA = 16'h0;
743 parameter PATTERN_LEN = 5'd16;
744
745 localparam COUNT_MAX = PATTERN_LEN - 1'h1;
746
747 reg[3:0] count = 0;
748 always @(posedge CLK, negedge nRST) begin
749
750 if(!nRST)
751 count <= 0;
752
753 else begin
754 count <= count - 1'h1;
755 if(count == 0)
756 count <= COUNT_MAX;
757 end
758 end
759
760 always @(*)
761 OUT = PATTERN_DATA[count];
762
763 endmodule
764
765 module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB);
766
767 parameter OUTA_TAP = 1;
768 parameter OUTA_INVERT = 0;
769 parameter OUTB_TAP = 1;
770
771 reg[15:0] shreg = 0;
772
773 always @(posedge CLK, negedge nRST) begin
774
775 if(!nRST)
776 shreg = 0;
777
778 else
779 shreg <= {shreg[14:0], IN};
780
781 end
782
783 assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1];
784 assign OUTB = shreg[OUTB_TAP - 1];
785
786 endmodule
787
788 module GP_VDD(output OUT);
789 assign OUT = 1;
790 endmodule
791
792 module GP_VSS(output OUT);
793 assign OUT = 0;
794 endmodule