diff options
author | Clifford Wolf <clifford@clifford.at> | 2017-08-14 21:47:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-14 21:47:26 +0200 |
commit | 2cf0b5c1575b2ea4f8d949854eab7ab2bfdcd10e (patch) | |
tree | b0d55992c4ca97bad2716b364cd45a0fc933070f /techlibs | |
parent | 6d371f06ab3f883296730edbcffc24130ff2adc5 (diff) | |
parent | 348acbd968193d6daaf53a16147b9bea932c92fb (diff) | |
download | yosys-2cf0b5c1575b2ea4f8d949854eab7ab2bfdcd10e.tar.gz yosys-2cf0b5c1575b2ea4f8d949854eab7ab2bfdcd10e.tar.bz2 yosys-2cf0b5c1575b2ea4f8d949854eab7ab2bfdcd10e.zip |
Merge pull request #381 from azonenberg/countfix
Added better behavioral models for GreenPAK counters. Refactored cells_sim into two files so analog/mixed signal stuff is separate
Diffstat (limited to 'techlibs')
-rw-r--r-- | techlibs/greenpak4/Makefile.inc | 2 | ||||
-rw-r--r-- | techlibs/greenpak4/cells_sim.v | 507 | ||||
-rw-r--r-- | techlibs/greenpak4/cells_sim_ams.v | 110 | ||||
-rw-r--r-- | techlibs/greenpak4/cells_sim_digital.v | 785 |
4 files changed, 900 insertions, 504 deletions
diff --git a/techlibs/greenpak4/Makefile.inc b/techlibs/greenpak4/Makefile.inc index 7482af6c6..f9614e779 100644 --- a/techlibs/greenpak4/Makefile.inc +++ b/techlibs/greenpak4/Makefile.inc @@ -6,4 +6,6 @@ OBJS += techlibs/greenpak4/greenpak4_dffinv.o $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_latch.v)) $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_map.v)) $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim.v)) +$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim_ams.v)) +$(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim_digital.v)) $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/gp_dff.lib)) diff --git a/techlibs/greenpak4/cells_sim.v b/techlibs/greenpak4/cells_sim.v index 57f27b44e..2d7bed5cd 100644 --- a/techlibs/greenpak4/cells_sim.v +++ b/techlibs/greenpak4/cells_sim.v @@ -1,141 +1,9 @@ `timescale 1ns/1ps -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 IN0, IN1, IN2, IN3, output OUT); - parameter [15:0] INIT = 0; - assign OUT = INIT[{IN3, IN2, IN1, IN0}]; -endmodule - -module GP_ABUF(input wire IN, output wire OUT); - - assign OUT = IN; - - //must be 1, 5, 20, 50 - //values >1 only available with Vdd > 2.7V - parameter BANDWIDTH_KHZ = 1; - - //cannot simulate mixed signal IP - -endmodule - -module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT); - - parameter BANDWIDTH = "HIGH"; - parameter VIN_ATTEN = 1; - parameter VIN_ISRC_EN = 0; - parameter HYSTERESIS = 0; - - initial OUT = 0; - - //cannot simulate mixed signal IP - -endmodule - -module GP_BANDGAP(output reg OK); - parameter AUTO_PWRDN = 1; - parameter CHOPPER_EN = 1; - parameter OUT_DELAY = 100; - - //cannot simulate mixed signal IP - -endmodule - -module GP_CLKBUF(input wire IN, output wire OUT); - assign OUT = IN; -endmodule - -module GP_COUNT8(input 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; - - //more complex hard IP blocks are not supported for simulation yet - - reg[7:0] count = COUNT_TO; - - //Combinatorially output whenever we wrap low - always @(*) begin - OUT <= (count == 8'h0); - OUT <= 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. - //Datasheet seems to indicate that reset is asynchronous, but for now we model as sync due to Yosys issues... - always @(posedge CLK) begin - - count <= count - 1'd1; - - if(count == 0) - count <= COUNT_TO; - - /* - if((RESET_MODE == "RISING") && RST) - count <= 0; - if((RESET_MODE == "FALLING") && !RST) - count <= 0; - if((RESET_MODE == "BOTH") && RST) - count <= 0; - */ - end - -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; - - //more complex hard IP blocks are not supported for simulation yet - -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; - - //more complex hard IP blocks are not supported for simulation yet - -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; +`include "cells_sim_ams.v" +`include "cells_sim_digital.v" - //more complex hard IP blocks are not supported for simulation yet - -endmodule - -module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT); - - initial VOUT = 0; - - //analog hard IP is not supported for simulation - -endmodule +//Cells still in this file have INCOMPLETE simulation models, need to finish them module GP_DCMP(input[7:0] INP, input[7:0] INN, input CLK, input PWRDN, output reg GREATER, output reg EQUAL); parameter PWRDN_SYNC = 1'b0; @@ -159,237 +27,6 @@ module GP_DCMP(input[7:0] INP, input[7:0] INN, input CLK, input PWRDN, output re 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 - - //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_EDGEDET(input IN, output reg OUT); parameter EDGE_DIRECTION = "RISING"; @@ -400,107 +37,6 @@ module GP_EDGEDET(input IN, output reg OUT); 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_LFOSC(input PWRDN, output reg CLKOUT); - - parameter PWRDN_EN = 0; - parameter AUTO_PWRDN = 0; - parameter OUT_DIV = 1; - - initial CLKOUT = 0; - - //auto powerdown not implemented for simulation - //output dividers not implemented for simulation - - always begin - if(PWRDN) - CLKOUT = 0; - else begin - //half period of 1730 Hz - #289017; - CLKOUT = ~CLKOUT; - end - end - -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_PGA(input wire VIN_P, input wire VIN_N, input wire VIN_SEL, output reg VOUT); - - parameter GAIN = 1; - parameter INPUT_MODE = "SINGLE"; - - initial VOUT = 0; - - //cannot simulate mixed signal IP - -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; - - reg[3:0] count = 0; - always @(posedge CLK) begin - if(!nRST) - OUT <= PATTERN_DATA[0]; - - else begin - count <= count + 1; - OUT <= PATTERN_DATA[count]; - - if( (count + 1) == PATTERN_LEN) - count <= 0; - end - end - -endmodule - -module GP_PWRDET(output reg VDD_LOW); - initial VDD_LOW = 0; -endmodule - -module GP_POR(output reg RST_DONE); - parameter POR_TIME = 500; - - initial begin - RST_DONE = 0; - - if(POR_TIME == 4) - #4000; - else if(POR_TIME == 500) - #500000; - else begin - $display("ERROR: bad POR_TIME for GP_POR cell"); - $finish; - end - - RST_DONE = 1; - - end - -endmodule - module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC); parameter PWRDN_EN = 0; @@ -567,29 +103,6 @@ module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRI 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_SPI( input SCK, inout SDAT, @@ -625,17 +138,3 @@ module GP_SYSRESET(input RST); //cannot simulate whole system reset endmodule - -module GP_VDD(output OUT); - assign OUT = 1; -endmodule - -module GP_VREF(input VIN, output reg VOUT); - parameter VIN_DIV = 1; - parameter VREF = 0; - //cannot simulate mixed signal IP -endmodule - -module GP_VSS(output OUT); - assign OUT = 0; -endmodule diff --git a/techlibs/greenpak4/cells_sim_ams.v b/techlibs/greenpak4/cells_sim_ams.v new file mode 100644 index 000000000..7f8b3de3b --- /dev/null +++ b/techlibs/greenpak4/cells_sim_ams.v @@ -0,0 +1,110 @@ +`timescale 1ns/1ps + +/* + This file contains analog / mixed signal cells, or other things that are not possible to fully model + in behavioral Verilog. + + It also contains some stuff like oscillators that use non-synthesizeable constructs such as delays. + TODO: do we want a third file for those cells? + */ + +module GP_ABUF(input wire IN, output wire OUT); + + assign OUT = IN; + + //must be 1, 5, 20, 50 + //values >1 only available with Vdd > 2.7V + parameter BANDWIDTH_KHZ = 1; + +endmodule + +module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT); + + parameter BANDWIDTH = "HIGH"; + parameter VIN_ATTEN = 1; + parameter VIN_ISRC_EN = 0; + parameter HYSTERESIS = 0; + + initial OUT = 0; + +endmodule + +module GP_BANDGAP(output reg OK); + parameter AUTO_PWRDN = 1; + parameter CHOPPER_EN = 1; + parameter OUT_DELAY = 100; + +endmodule + +module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT); + + initial VOUT = 0; + + //analog hard IP is not supported for simulation + +endmodule + +module GP_LFOSC(input PWRDN, output reg CLKOUT); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter OUT_DIV = 1; + + initial CLKOUT = 0; + + //auto powerdown not implemented for simulation + //output dividers not implemented for simulation + + always begin + if(PWRDN) + CLKOUT = 0; + else begin + //half period of 1730 Hz + #289017; + CLKOUT = ~CLKOUT; + end + end + +endmodule + +module GP_PGA(input wire VIN_P, input wire VIN_N, input wire VIN_SEL, output reg VOUT); + + parameter GAIN = 1; + parameter INPUT_MODE = "SINGLE"; + + initial VOUT = 0; + + //cannot simulate mixed signal IP + +endmodule + +module GP_PWRDET(output reg VDD_LOW); + initial VDD_LOW = 0; +endmodule + +module GP_VREF(input VIN, output reg VOUT); + parameter VIN_DIV = 1; + parameter VREF = 0; + //cannot simulate mixed signal IP +endmodule + +module GP_POR(output reg RST_DONE); + parameter POR_TIME = 500; + + initial begin + RST_DONE = 0; + + if(POR_TIME == 4) + #4000; + else if(POR_TIME == 500) + #500000; + else begin + $display("ERROR: bad POR_TIME for GP_POR cell"); + $finish; + end + + RST_DONE = 1; + + end + +endmodule diff --git a/techlibs/greenpak4/cells_sim_digital.v b/techlibs/greenpak4/cells_sim_digital.v new file mode 100644 index 000000000..3ed80005b --- /dev/null +++ b/techlibs/greenpak4/cells_sim_digital.v @@ -0,0 +1,785 @@ +`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 + + //Main counter + if(KEEP) begin + end + else if(UP) + count <= count + 1'd1; + else + count <= count - 1'd1; + + //Wrapping + if(count == 0 && !UP) + count <= COUNT_TO; + if(count == 14'h3fff && UP) + count <= COUNT_TO; + + //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; + else + count <= count - 1'd1; + + //Wrapping + if(count == 0 && !UP) + count <= COUNT_TO; + if(count == 14'h3fff && UP) + count <= COUNT_TO; + + //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 + + //Main counter + if(KEEP) begin + end + else if(UP) + count <= count + 1'd1; + else + count <= count - 1'd1; + + //Wrapping + if(count == 0 && !UP) + count <= COUNT_TO; + if(count == 14'h3fff && UP) + count <= COUNT_TO; + + 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; + else + count <= count - 1'd1; + + //Wrapping + if(count == 0 && !UP) + count <= COUNT_TO; + if(count == 8'hff && UP) + count <= COUNT_TO; + + //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; + else + count <= count - 1'd1; + + //Wrapping + if(count == 0 && !UP) + count <= COUNT_TO; + if(count == 8'hff && UP) + count <= COUNT_TO; + + //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 + + //Main counter + if(KEEP) begin + end + else if(UP) + count <= count + 1'd1; + else + count <= count - 1'd1; + + //Wrapping + if(count == 0 && !UP) + count <= COUNT_TO; + if(count == 8'hff && UP) + count <= COUNT_TO; + + 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; + + reg[3:0] count = 0; + always @(posedge CLK) begin + if(!nRST) + OUT <= PATTERN_DATA[0]; + + else begin + count <= count + 1; + OUT <= PATTERN_DATA[count]; + + if( (count + 1) == PATTERN_LEN) + count <= 0; + end + end + +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 |