From 7efc24ebe44e18f608b9fb95a4bd8e08eeb6c0ba Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 6 Jul 2024 20:28:56 +1000 Subject: [PATCH] Implement power saving primitive BANDGAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the board on the GW1N-1 chip becomes a rarity, its replacement is the Tangnano1k board with the GW1NZ-1 chip. This chip has a unique mechanism for turning off power to important things such as OSC, PLL, etc. Here we introduce a primitive that allows energy saving to be controlled dynamically. Nextpnr will add this primitive automatically if we do not use it explicitly - this is done to explicitly connect the control input since its default connection is neither VCC nor GND. BANDGAP only has an input, but does not have a fuse - it is on all the time. Of course, a reasonable question arises - what are these magic numbers in line 2258-2259 of gowin_pack.py? I really don’t want to consider these BANDGAP fuses precisely because this primitive is not configurable - and these bits are fuses that appear in the db.shortval[49]['unknown_75'] and db.logicinfo['unknown_74'] tables , which clearly describe something with decent configuration capabilities. This could be some kind of adjustable voltage stabilizer, which has an input MUX for control signals and one of the combinations connects BANDGAP. But this is not part of BANDGAP and I think I'll leave it as it is. Signed-off-by: YRabbit --- apycula/chipdb.py | 10 +++++++ apycula/gowin_pack.py | 5 +++- examples/himbaechel/bandgap.v | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 examples/himbaechel/bandgap.v diff --git a/apycula/chipdb.py b/apycula/chipdb.py index e976942..ab8623d 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -1574,6 +1574,13 @@ def fse_create_gsr(dev, device): dev.extra_func.setdefault((row, col), {}).update( {'gsr': {'wire': 'C4'}}) +def fse_create_bandgap(dev, device): + # The cell and wire are found by a test compilation where the BGEN input is + # connected to a button - such wires are easily traced in a binary image. + if device in {'GW1NZ-1'}: + dev.extra_func.setdefault((10, 18), {}).update( + {'bandgap': {'wire': 'C1'}}) + def fse_bram(fse, aux = False): bels = {} name = 'BSRAM' @@ -1658,6 +1665,8 @@ def set_chip_flags(dev, device): dev.chip_flags.append("NEED_BSRAM_OUTREG_FIX") if device in {'GW1N-1', 'GW1NZ-1', 'GW1NS-2', 'GW1N-4', 'GW1NS-4', 'GW1N-9', 'GW1N-9C', 'GW2A-18', 'GW2A-18C'}: dev.chip_flags.append("NEED_BLKSEL_FIX") + if device in {'GW1NZ-1'}: + dev.chip_flags.append("HAS_BANDGAP") def from_fse(device, fse, dat: Datfile): dev = Device() @@ -1711,6 +1720,7 @@ def from_fse(device, fse, dat: Datfile): fse_create_io16(dev, device) fse_create_osc(dev, device, fse) fse_create_gsr(dev, device) + fse_create_bandgap(dev, device) fse_create_logic2clk(dev, device, dat) disable_plls(dev, device) sync_extra_func(dev) diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 02f7db2..af2815c 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -185,7 +185,7 @@ def get_bits(init_data): def get_bels(data): later = [] if is_himbaechel: - belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9)(\w*)") + belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP)(\w*)") else: belre = re.compile(r"R(\d+)C(\d+)_(?:GSR|SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8|ODDR|OSC[ZFHWO]?|BUFS|RAMW|rPLL|PLLVR|IOLOGIC)(\w*)") @@ -2236,6 +2236,8 @@ def place(db, tilemap, bels, cst, args): if typ == "GSR": pass + elif typ == "BANDGAP": + pass elif typ.startswith('MUX2_'): pass elif typ == "BUFS": @@ -2254,6 +2256,7 @@ def place(db, tilemap, bels, cst, args): en_tiledata = db.grid[db.rows - 1][db.cols - 1] en_tile = tilemap[(db.rows - 1, db.cols - 1)] en_tile[23][63] = 0 + en_tile[22][63] = 1 # clear powersave fuses clear_attrs = set() add_attr_val(db, 'OSC', clear_attrs, attrids.osc_attrids['POWER_SAVE'], attrids.osc_attrvals['ENABLE']) diff --git a/examples/himbaechel/bandgap.v b/examples/himbaechel/bandgap.v new file mode 100644 index 0000000..c59dec9 --- /dev/null +++ b/examples/himbaechel/bandgap.v @@ -0,0 +1,49 @@ +module top ( + input key_i, + output [`LEDS_NR-1:0] led +); + +wire clk; + +`ifdef OSC_TYPE_OSC +OSC osc( + .OSCOUT(clk) +); +`elsif OSC_TYPE_OSCZ +OSCZ osc( + .OSCEN(1'b1), + .OSCOUT(clk) +); +`elsif OSC_TYPE_OSCF +OSCF osc( + .OSCEN(1'b1), + .OSCOUT(clk), + .OSCOUT30M() +); +`elsif OSC_TYPE_OSCH +OSCH osc( + .OSCOUT(clk) +); +`endif +defparam osc.FREQ_DIV=16; + +wire key = key_i ^ `INV_BTN; + +reg [25:0] ctr_q; +wire [25:0] ctr_d; + +// Sequential code (flip-flop) +always @(posedge clk) begin + ctr_q <= ctr_d; +end + +BANDGAP bandgap( + .BGEN(key) +); + + +// Combinational code (boolean logic) +assign ctr_d = ctr_q + 1'b1; +assign led = {ctr_q[25:25-(`LEDS_NR - 2)], |ctr_q[25-(`LEDS_NR - 1):25-(`LEDS_NR)] }; + +endmodule