`timescale 1ns/1ps /* This file contains simulation models for GreenPAK cells which are possible to fully model using synthesizeable behavioral Verilog constructs only. */ module GP_2LUT(input IN0, IN1, output OUT); parameter [3:0] INIT = 0; assign OUT = INIT[{IN1, IN0}]; endmodule module GP_3LUT(input IN0, IN1, IN2, output OUT); parameter [7:0] INIT = 0; assign OUT = INIT[{IN2, IN1, IN0}]; endmodule module GP_4LUT( input wire IN0, input wire IN1, input wire IN2, input wire IN3, output wire OUT); parameter [15:0] INIT = 0; assign OUT = INIT[{IN3, IN2, IN1, IN0}]; endmodule module GP_CLKBUF(input wire IN, output wire OUT); assign OUT = IN; endmodule module GP_COUNT14(input CLK, input wire RST, output reg OUT); parameter RESET_MODE = "RISING"; parameter COUNT_TO = 14'h1; parameter CLKIN_DIVIDE = 1; reg[13:0] count = COUNT_TO; initial begin if(CLKIN_DIVIDE != 1) begin $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented"); $finish; end end //Combinatorially output underflow flag whenever we wrap low always @(*) begin OUT <= (count == 14'h0); end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now. generate case(RESET_MODE) "RISING": begin always @(posedge CLK, posedge RST) begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; if(RST) count <= 0; end end "FALLING": begin always @(posedge CLK, negedge RST) begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; if(!RST) count <= 0; end end "BOTH": begin initial begin $display("Both-edge reset mode for GP_COUNT14 not implemented"); $finish; end end "LEVEL": begin always @(posedge CLK, posedge RST) begin if(RST) count <= 0; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end end end default: begin initial begin $display("Invalid RESET_MODE on GP_COUNT8"); $finish; end end endcase endgenerate endmodule module GP_COUNT14_ADV(input CLK, input RST, output reg OUT, input UP, input KEEP, output reg[7:0] POUT); parameter RESET_MODE = "RISING"; parameter RESET_VALUE = "ZERO"; parameter COUNT_TO = 14'h1; parameter CLKIN_DIVIDE = 1; initial begin if(CLKIN_DIVIDE != 1) begin $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented"); $finish; end end reg[13:0] count = COUNT_TO; //Combinatorially output underflow flag whenever we wrap low always @(*) begin if(UP) OUT <= (count == 14'h3fff); else OUT <= (count == 14'h0); POUT <= count[7:0]; end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now. generate case(RESET_MODE) "RISING": begin always @(posedge CLK, posedge RST) begin if(KEEP) begin end else if(UP) count <= count + 1'd1; if(count == 14'h3fff) count <= COUNT_TO; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end //Resets if(RST) begin if(RESET_VALUE == "ZERO") count <= 0; else count <= COUNT_TO; end end end "FALLING": begin always @(posedge CLK, negedge RST) begin if(KEEP) begin end else if(UP) count <= count + 1'd1; if(count == 14'h3fff) count <= COUNT_TO; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end //Resets if(!RST) begin if(RESET_VALUE == "ZERO") count <= 0; else count <= COUNT_TO; end end end "BOTH": begin initial begin $display("Both-edge reset mode for GP_COUNT14_ADV not implemented"); $finish; end end "LEVEL": begin always @(posedge CLK, posedge RST) begin //Resets if(RST) begin if(RESET_VALUE == "ZERO") count <= 0; else count <= COUNT_TO; end else begin if(KEEP) begin end else if(UP) count <= count + 1'd1; if(count == 14'h3fff) count <= COUNT_TO; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end end end end default: begin initial begin $display("Invalid RESET_MODE on GP_COUNT14_ADV"); $finish; end end endcase endgenerate endmodule module GP_COUNT8_ADV(input CLK, input RST, output reg OUT, input UP, input KEEP, output reg[7:0] POUT); parameter RESET_MODE = "RISING"; parameter RESET_VALUE = "ZERO"; parameter COUNT_TO = 8'h1; parameter CLKIN_DIVIDE = 1; reg[7:0] count = COUNT_TO; initial begin if(CLKIN_DIVIDE != 1) begin $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented"); $finish; end end //Combinatorially output underflow flag whenever we wrap low always @(*) begin if(UP) OUT <= (count == 8'hff); else OUT <= (count == 8'h0); POUT <= count; end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now. generate case(RESET_MODE) "RISING": begin always @(posedge CLK, posedge RST) begin //Main counter if(KEEP) begin end else if(UP) count <= count + 1'd1; if(count == 8'hff) count <= COUNT_TO; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end //Resets if(RST) begin if(RESET_VALUE == "ZERO") count <= 0; else count <= COUNT_TO; end end end "FALLING": begin always @(posedge CLK, negedge RST) begin //Main counter if(KEEP) begin end else if(UP) count <= count + 1'd1; if(count == 8'hff) count <= COUNT_TO; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end //Resets if(!RST) begin if(RESET_VALUE == "ZERO") count <= 0; else count <= COUNT_TO; end end end "BOTH": begin initial begin $display("Both-edge reset mode for GP_COUNT8_ADV not implemented"); $finish; end end "LEVEL": begin always @(posedge CLK, posedge RST) begin //Resets if(RST) begin if(RESET_VALUE == "ZERO") count <= 0; else count <= COUNT_TO; end else begin if(KEEP) begin end else if(UP) count <= count + 1'd1; if(count == 8'hff) count <= COUNT_TO; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end end end end default: begin initial begin $display("Invalid RESET_MODE on GP_COUNT8_ADV"); $finish; end end endcase endgenerate endmodule module GP_COUNT8( input wire CLK, input wire RST, output reg OUT, output reg[7:0] POUT); parameter RESET_MODE = "RISING"; parameter COUNT_TO = 8'h1; parameter CLKIN_DIVIDE = 1; initial begin if(CLKIN_DIVIDE != 1) begin $display("ERROR: CLKIN_DIVIDE values other than 1 not implemented"); $finish; end end reg[7:0] count = COUNT_TO; //Combinatorially output underflow flag whenever we wrap low always @(*) begin OUT <= (count == 8'h0); POUT <= count; end //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now. generate case(RESET_MODE) "RISING": begin always @(posedge CLK, posedge RST) begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; if(RST) count <= 0; end end "FALLING": begin always @(posedge CLK, negedge RST) begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; if(!RST) count <= 0; end end "BOTH": begin initial begin $display("Both-edge reset mode for GP_COUNT8 not implemented"); $finish; end end "LEVEL": begin always @(posedge CLK, posedge RST) begin if(RST) count <= 0; else begin count <= count - 1'd1; if(count == 0) count <= COUNT_TO; end end end default: begin initial begin $display("Invalid RESET_MODE on GP_COUNT8"); $finish; end end endcase endgenerate endmodule module GP_DCMPREF(output reg[7:0]OUT); parameter[7:0] REF_VAL = 8'h00; initial OUT = REF_VAL; endmodule 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); always @(*) begin case(SEL) 2'd00: begin OUTA <= IN0; OUTB <= IN3; end 2'd01: begin OUTA <= IN1; OUTB <= IN2; end 2'd02: begin OUTA <= IN2; OUTB <= IN1; end 2'd03: begin OUTA <= IN3; OUTB <= IN0; end endcase end endmodule module GP_DELAY(input IN, output reg OUT); parameter DELAY_STEPS = 1; parameter GLITCH_FILTER = 0; initial OUT = 0; generate if(GLITCH_FILTER) begin initial begin $display("ERROR: GP_DELAY glitch filter mode not implemented"); $finish; end end //TODO: These delays are PTV dependent! For now, hard code 3v3 timing //Change simulation-mode delay depending on global Vdd range (how to specify this?) always @(*) begin case(DELAY_STEPS) 1: #166 OUT = IN; 2: #318 OUT = IN; 2: #471 OUT = IN; 3: #622 OUT = IN; default: begin $display("ERROR: GP_DELAY must have DELAY_STEPS in range [1,4]"); $finish; end endcase end endgenerate endmodule module GP_DFF(input D, CLK, output reg Q); parameter [0:0] INIT = 1'bx; initial Q = INIT; always @(posedge CLK) begin Q <= D; end endmodule module GP_DFFI(input D, CLK, output reg nQ); parameter [0:0] INIT = 1'bx; initial nQ = INIT; always @(posedge CLK) begin nQ <= ~D; end endmodule module GP_DFFR(input D, CLK, nRST, output reg Q); parameter [0:0] INIT = 1'bx; initial Q = INIT; always @(posedge CLK, negedge nRST) begin if (!nRST) Q <= 1'b0; else Q <= D; end endmodule module GP_DFFRI(input D, CLK, nRST, output reg nQ); parameter [0:0] INIT = 1'bx; initial nQ = INIT; always @(posedge CLK, negedge nRST) begin if (!nRST) nQ <= 1'b1; else nQ <= ~D; end endmodule module GP_DFFS(input D, CLK, nSET, output reg Q); parameter [0:0] INIT = 1'bx; initial Q = INIT; always @(posedge CLK, negedge nSET) begin if (!nSET) Q <= 1'b1; else Q <= D; end endmodule module GP_DFFSI(input D, CLK, nSET, output reg nQ); parameter [0:0] INIT = 1'bx; initial nQ = INIT; always @(posedge CLK, negedge nSET) begin if (!nSET) nQ <= 1'b0; else nQ <= ~D; end endmodule module GP_DFFSR(input D, CLK, nSR, output reg Q); parameter [0:0] INIT = 1'bx; parameter [0:0] SRMODE = 1'bx; initial Q = INIT; always @(posedge CLK, negedge nSR) begin if (!nSR) Q <= SRMODE; else Q <= D; end endmodule module GP_DFFSRI(input D, CLK, nSR, output reg nQ); parameter [0:0] INIT = 1'bx; parameter [0:0] SRMODE = 1'bx; initial nQ = INIT; always @(posedge CLK, negedge nSR) begin if (!nSR) nQ <= ~SRMODE; else nQ <= ~D; end endmodule module GP_DLATCH(input D, input nCLK, output reg Q); parameter [0:0] INIT = 1'bx; initial Q = INIT; always @(*) begin if(!nCLK) Q <= D; end endmodule module GP_DLATCHI(input D, input nCLK, output reg nQ); parameter [0:0] INIT = 1'bx; initial nQ = INIT; always @(*) begin if(!nCLK) nQ <= ~D; end endmodule module GP_DLATCHR(input D, input nCLK, input nRST, output reg Q); parameter [0:0] INIT = 1'bx; initial Q = INIT; always @(*) begin if(!nRST) Q <= 1'b0; else if(!nCLK) Q <= D; end endmodule module GP_DLATCHRI(input D, input nCLK, input nRST, output reg nQ); parameter [0:0] INIT = 1'bx; initial nQ = INIT; always @(*) begin if(!nRST) nQ <= 1'b1; else if(!nCLK) nQ <= ~D; end endmodule module GP_DLATCHS(input D, input nCLK, input nSET, output reg Q); parameter [0:0] INIT = 1'bx; initial Q = INIT; always @(*) begin if(!nSET) Q <= 1'b1; else if(!nCLK) Q <= D; end endmodule module GP_DLATCHSI(input D, input nCLK, input nSET, output reg nQ); parameter [0:0] INIT = 1'bx; initial nQ = INIT; always @(*) begin if(!nSET) nQ <= 1'b0; else if(!nCLK) nQ <= ~D; end endmodule module GP_DLATCHSR(input D, input nCLK, input nSR, output reg Q); parameter [0:0] INIT = 1'bx; parameter[0:0] SRMODE = 1'bx; initial Q = INIT; always @(*) begin if(!nSR) Q <= SRMODE; else if(!nCLK) Q <= D; end endmodule module GP_DLATCHSRI(input D, input nCLK, input nSR, output reg nQ); parameter [0:0] INIT = 1'bx; parameter[0:0] SRMODE = 1'bx; initial nQ = INIT; always @(*) begin if(!nSR) nQ <= ~SRMODE; else if(!nCLK) nQ <= ~D; end endmodule module GP_IBUF(input IN, output OUT); assign OUT = IN; endmodule module GP_IOBUF(input IN, input OE, output OUT, inout IO); assign OUT = IO; assign IO = OE ? IN : 1'bz; endmodule module GP_INV(input IN, output OUT); assign OUT = ~IN; endmodule module GP_OBUF(input IN, output OUT); assign OUT = IN; endmodule module GP_OBUFT(input IN, input OE, output OUT); assign OUT = OE ? IN : 1'bz; endmodule module GP_PGEN(input wire nRST, input wire CLK, output reg OUT); initial OUT = 0; parameter PATTERN_DATA = 16'h0; parameter PATTERN_LEN = 5'd16; localparam COUNT_MAX = PATTERN_LEN - 1'h1; reg[3:0] count = 0; always @(posedge CLK) begin if(!nRST) begin count <= COUNT_MAX; end else begin count <= count - 1'h1; if(count == 0) count <= COUNT_MAX; end end always @(*) OUT = PATTERN_DATA[count]; endmodule module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB); parameter OUTA_TAP = 1; parameter OUTA_INVERT = 0; parameter OUTB_TAP = 1; reg[15:0] shreg = 0; always @(posedge CLK, negedge nRST) begin if(!nRST) shreg = 0; else shreg <= {shreg[14:0], IN}; end assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1]; assign OUTB = shreg[OUTB_TAP - 1]; endmodule module GP_VDD(output OUT); assign OUT = 1; endmodule module GP_VSS(output OUT); assign OUT = 0; endmodule