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
8module GP_2LUT(input IN0, IN1, output OUT);
9	parameter [3:0] INIT = 0;
10	assign OUT = INIT[{IN1, IN0}];
11endmodule
12
13module GP_3LUT(input IN0, IN1, IN2, output OUT);
14	parameter [7:0] INIT = 0;
15	assign OUT = INIT[{IN2, IN1, IN0}];
16endmodule
17
18module 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}];
27endmodule
28
29module GP_CLKBUF(input wire IN, output wire OUT);
30	assign OUT = IN;
31endmodule
32
33module 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_COUNT14");
106					$finish;
107				end
108			end
109
110		endcase
111	endgenerate
112
113endmodule
114
115module 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
252endmodule
253
254module 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
392endmodule
393
394module 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
479endmodule
480
481module GP_DCMPREF(output reg[7:0]OUT);
482	parameter[7:0] REF_VAL = 8'h00;
483	initial OUT = REF_VAL;
484endmodule
485
486module 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
512endmodule
513
514module 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
547endmodule
548
549module 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
555endmodule
556
557module 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
563endmodule
564
565module 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
574endmodule
575
576module 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
585endmodule
586
587module 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
596endmodule
597
598module 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
607endmodule
608
609module 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
619endmodule
620
621module 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
631endmodule
632
633module 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
640endmodule
641
642module 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
649endmodule
650
651module 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
660endmodule
661
662module 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
671endmodule
672
673module 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
682endmodule
683
684module 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
693endmodule
694
695module 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
705endmodule
706
707module 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
717endmodule
718
719module GP_IBUF(input IN, output OUT);
720	assign OUT = IN;
721endmodule
722
723module GP_IOBUF(input IN, input OE, output OUT, inout IO);
724	assign OUT = IO;
725	assign IO = OE ? IN : 1'bz;
726endmodule
727
728module GP_INV(input IN, output OUT);
729	assign OUT = ~IN;
730endmodule
731
732module GP_OBUF(input IN, output OUT);
733	assign OUT = IN;
734endmodule
735
736module GP_OBUFT(input IN, input OE, output OUT);
737	assign OUT = OE ? IN : 1'bz;
738endmodule
739
740module 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
763endmodule
764
765module 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
786endmodule
787
788module GP_VDD(output OUT);
789       assign OUT = 1;
790endmodule
791
792module GP_VSS(output OUT);
793       assign OUT = 0;
794endmodule
795