| `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 |
| if(RST) |
| count <= 0; |
| else begin |
| count <= count - 1'd1; |
| if(count == 0) |
| count <= COUNT_TO; |
| end |
| end |
| end |
| |
| "FALLING": begin |
| always @(posedge CLK, negedge RST) begin |
| if(!RST) |
| count <= 0; |
| else begin |
| count <= count - 1'd1; |
| if(count == 0) |
| count <= COUNT_TO; |
| end |
| 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_COUNT14"); |
| $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 |
| |
| //Resets |
| if(RST) begin |
| if(RESET_VALUE == "ZERO") |
| count <= 0; |
| else |
| count <= COUNT_TO; |
| end |
| |
| else if(KEEP) begin |
| end |
| else if(UP) begin |
| count <= count + 1'd1; |
| if(count == 14'h3fff) |
| count <= COUNT_TO; |
| end |
| else begin |
| count <= count - 1'd1; |
| |
| if(count == 0) |
| count <= COUNT_TO; |
| end |
| |
| end |
| end |
| |
| "FALLING": begin |
| always @(posedge CLK, negedge RST) begin |
| |
| //Resets |
| if(!RST) begin |
| if(RESET_VALUE == "ZERO") |
| count <= 0; |
| else |
| count <= COUNT_TO; |
| end |
| |
| else if(KEEP) begin |
| end |
| else if(UP) begin |
| count <= count + 1'd1; |
| if(count == 14'h3fff) |
| count <= COUNT_TO; |
| end |
| else begin |
| count <= count - 1'd1; |
| |
| if(count == 0) |
| 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) begin |
| count <= count + 1'd1; |
| if(count == 14'h3fff) |
| count <= COUNT_TO; |
| end |
| 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 |
| |
| //Resets |
| if(RST) begin |
| if(RESET_VALUE == "ZERO") |
| count <= 0; |
| else |
| count <= COUNT_TO; |
| end |
| |
| //Main counter |
| else if(KEEP) begin |
| end |
| else if(UP) begin |
| count <= count + 1'd1; |
| if(count == 8'hff) |
| count <= COUNT_TO; |
| end |
| else begin |
| count <= count - 1'd1; |
| |
| if(count == 0) |
| count <= COUNT_TO; |
| end |
| |
| end |
| end |
| |
| "FALLING": begin |
| always @(posedge CLK, negedge RST) begin |
| |
| //Resets |
| if(!RST) begin |
| if(RESET_VALUE == "ZERO") |
| count <= 0; |
| else |
| count <= COUNT_TO; |
| end |
| |
| //Main counter |
| else if(KEEP) begin |
| end |
| else if(UP) begin |
| count <= count + 1'd1; |
| if(count == 8'hff) |
| count <= COUNT_TO; |
| end |
| else begin |
| count <= count - 1'd1; |
| |
| if(count == 0) |
| 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) begin |
| count <= count + 1'd1; |
| if(count == 8'hff) |
| count <= COUNT_TO; |
| end |
| 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 |
| if(RST) |
| count <= 0; |
| else begin |
| count <= count - 1'd1; |
| if(count == 0) |
| count <= COUNT_TO; |
| end |
| end |
| end |
| |
| "FALLING": begin |
| always @(posedge CLK, negedge RST) begin |
| if(!RST) |
| count <= 0; |
| else begin |
| count <= count - 1'd1; |
| if(count == 0) |
| count <= COUNT_TO; |
| end |
| 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, negedge nRST) begin |
| |
| if(!nRST) |
| count <= 0; |
| |
| 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 |