Skip to content

Commit

Permalink
Implement power saving primitive BANDGAP
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
yrabbit committed Jul 6, 2024
1 parent f19de52 commit 7efc24e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
10 changes: 10 additions & 0 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -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*)")

Expand Down Expand Up @@ -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":
Expand All @@ -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'])
Expand Down
49 changes: 49 additions & 0 deletions examples/himbaechel/bandgap.v
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 7efc24e

Please sign in to comment.