Skip to content

Commit

Permalink
Himbaechel. Improve dedicated clock router
Browse files Browse the repository at this point in the history
Added buffers for the global clock network.
We indicate that the network is CLOCK by placing the following
construction in the file of restrictions:

CLOCK_LOC "net_name" BUFG;

As a result, the specified network is cut into two parts: the part from
the source to the buffer is routed using any available PIPs, while the
part from the buffer to the sink is routed through the global clock
network.

This will slightly improve the situation with Tangnano20k, since now it
is possible to declare its pin, on which the simple external generator
is located, as a clock, which will lead to routing through the buffer
without any clock glitches.

All examples for Tangnano20k, which previously used the PLL as a buffer,
are no longer needed and use the same files as for the rest of the
boards.

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit committed Sep 4, 2023
1 parent 180dfef commit 0f3cab7
Show file tree
Hide file tree
Showing 23 changed files with 95 additions and 1,056 deletions.
92 changes: 86 additions & 6 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class Device:
# - OSER16/IDES16
# - ref to hclk_pips
# - disabled blocks
# - BUF(G)
extra_func: Dict[Tuple[int, int], Dict[str, Any]] = field(default_factory=dict)

@property
Expand Down Expand Up @@ -154,6 +155,40 @@ def bank_tiles(self):
res.update({ bel[4:] : pos })
return res

# XXX GW1N-4 and GW1NS-4 have next data in dat['CmuxIns']:
# 62 [11, 1, 126]
# 63 [11, 1, 126]
# this means that the same wire (11, 1, 126) is connected implicitly to two
# other logical wires. Let's remember such connections.
# If suddenly a command is given to assign an already used wire to another
# node, then all the contents of this node are combined with the existing one,
# and the node itself is destroyed. only for HCLK and clock nets for now
wire2node = {}
def add_node(dev, node_name, wire_type, row, col, wire):
if (row, col, wire) not in wire2node:
wire2node[row, col, wire] = node_name
dev.nodes.setdefault(node_name, (wire_type, set()))[1].add((row, col, wire))
else:
if node_name != wire2node[row, col, wire] and node_name in dev.nodes:
#print(f'{node_name} -> {wire2node[row, col, wire]} share ({row}, {col}, {wire})')
dev.nodes[wire2node[row, col, wire]][1].update(dev.nodes[node_name][1])
del dev.nodes[node_name]

# create bels for entry potints to the global clock nets
def add_buf_bel(dev, row, col, wire, buf_type = 'BUFG'):
# clock pins
if not wire.startswith('CLK'):
return
extra_func = dev.extra_func.setdefault((row, col), {})
if 'buf' not in extra_func or buf_type not in extra_func['buf']:
extra_func.update({'buf': {buf_type: [wire]}})
else:
# dups not allowed for now
if wire in extra_func['buf'][buf_type]:
#print(f'extra buf dup ({row}, {col}) {buf_type}/{wire}')
return
extra_func['buf'][buf_type].append(wire)

def unpad(fuses, pad=-1):
try:
return fuses[:fuses.index(pad)]
Expand Down Expand Up @@ -962,7 +997,10 @@ def fse_create_hclk_nodes(dev, device, fse, dat):
# entries to the HCLK from logic
for hclk_idx, row, col, wire_idx in {(i, dat['CmuxIns'][str(i - 80)][0] - 1, dat['CmuxIns'][str(i - 80)][1] - 1, dat['CmuxIns'][str(i - 80)][2]) for i in range(hclknumbers['TBDHCLK0'], hclknumbers['RBDHCLK3'] + 1)}:
if row != -2:
dev.nodes.setdefault(hclknames[hclk_idx], ("HCLK", set()))[1].add((row, col, wirenames[wire_idx]))
add_node(dev, hclknames[hclk_idx], "HCLK", row, col, wirenames[wire_idx])
# XXX clock router is doing fine with HCLK w/o any buffering
# may be placement suffers a bit
#add_buf_bel(dev, row, col, wirenames[wire_idx], buf_type = 'BUFH')

if 'hclk' in hclk_info[side]:
# create HCLK cells pips
Expand All @@ -975,7 +1013,7 @@ def fse_create_hclk_nodes(dev, device, fse, dat):
for src in srcs.keys():
for pfx in _global_wire_prefixes:
if src.startswith(pfx):
dev.nodes.setdefault(src, ('HCLK', set()))[1].add((row, col, src))
add_node(dev, src, "HCLK", row, col, src)
# strange GW1N-9C input-input aliases
for i in {0, 2}:
dev.nodes.setdefault(f'X{col}Y{row}/HCLK9-{i}', ('HCLK', {(row, col, f'HCLK_IN{i}')}))[1].add((row, col, f'HCLK_9IN{i}'))
Expand Down Expand Up @@ -1249,19 +1287,20 @@ def fse_create_clocks(dev, device, dat, fse):
# find center muxes
for clk_idx, row, col, wire_idx in {(i, dat['CmuxIns'][str(i - 80)][0] - 1, dat['CmuxIns'][str(i - 80)][1] - 1, dat['CmuxIns'][str(i - 80)][2]) for i in range(clknumbers['PCLKT0'], clknumbers['PCLKR1'] + 1)}:
if row != -2:
dev.nodes.setdefault(clknames[clk_idx], ("GLOBAL_CLK", set()))[1].add((row, col, wirenames[wire_idx]))
add_node(dev, clknames[clk_idx], "GLOBAL_CLK", row, col, wirenames[wire_idx])
add_buf_bel(dev, row, col, wirenames[wire_idx])

spines = {f'SPINE{i}' for i in range(32)}
for row, rd in enumerate(dev.grid):
for col, rc in enumerate(rd):
for dest, srcs in rc.pure_clock_pips.items():
for src in srcs.keys():
if src in spines and not dest.startswith('GT'):
dev.nodes.setdefault(src, ("GLOBAL_CLK", set()))[1].add((row, col, src))
add_node(dev, src, "GLOBAL_CLK", row, col, src)
if dest in spines:
dev.nodes.setdefault(dest, ("GLOBAL_CLK", set()))[1].add((row, col, dest))
add_node(dev, dest, "GLOBAL_CLK", row, col, dest)
for src in { wire for wire in srcs.keys() if wire not in {'VCC', 'VSS'}}:
dev.nodes.setdefault(src, ("GLOBAL_CLK", set()))[1].add((row, col, src))
add_node(dev, src, "GLOBAL_CLK", row, col, src)
# GBx0 <- GBOx
for spine_pair in range(4): # GB00/GB40, GB10/GB50, GB20/GB60, GB30/GB70
tap_start = _clock_data[device]['tap_start'][0]
Expand Down Expand Up @@ -1428,6 +1467,46 @@ def fse_create_io16(dev, device):
('OSCW', 'GW2AN-18'): ({'OSCOUT': 'Q4'}, {}),
}

# from logic to global clocks. An interesting piece of dat['CmuxIns'], it was
# found out experimentally that this range is responsible for the wires
# 129: 'TRBDCLK0' - 152: 'TRMDCLK1'. Again we have a shift of 80 from the wire number
# (see create clock aliases).
# 124-126 equal CLK0-CLK2 so these are clearly inputs to the clock system
# (GW1N-1 data)
# 49 [1, 11, 124]
# 50 [1, 11, 125]
# 51 [6, 20, 124]
# 52 [6, 20, 125]
# 53 [1, 10, 125]
# 54 [6, 1, 124]
# 55 [6, 1, 125]
# 56 [1, 10, 124]
# 57 [11, 11, 124]
# 58 [11, 11, 125]
# 59 [7, 20, 126]
# 60 [8, 20, 126]
# 61 [11, 10, 125]
# 62 [7, 1, 126]
# 63 [8, 1, 126]
# 64 [11, 10, 124]
# 65 [-1, -1, -1]
# 66 [-1, -1, -1]
# 67 [-1, -1, -1]
# 68 [-1, -1, -1]
# 69 [-1, -1, -1]
# 70 [-1, -1, -1]
# 71 [6, 10, 126]
# 72 [6, 11, 126]
# We don't need to worry about routing TRBDCLK0 and the family - this was
# already done when we created pure clock pips. But what we need to do is
# indicate that these CLKs at these coordinates are TRBDCLK0, etc. Therefore,
# we create Himbaechel nodes.
def fse_create_logic2clk(dev, device, dat):
for clkwire_idx, row, col, wire_idx in {(i, dat['CmuxIns'][str(i - 80)][0] - 1, dat['CmuxIns'][str(i - 80)][1] - 1, dat['CmuxIns'][str(i - 80)][2]) for i in range(clknumbers['TRBDCLK0'], clknumbers['TRMDCLK1'] + 1)}:
if row != -2:
add_node(dev, clknames[clkwire_idx], "GLOBAL_CLK", row, col, wirenames[wire_idx])
add_buf_bel(dev, row, col, wirenames[wire_idx])

def fse_create_osc(dev, device, fse):
for row, rd in enumerate(dev.grid):
for col, rc in enumerate(rd):
Expand Down Expand Up @@ -1503,6 +1582,7 @@ def from_fse(device, fse, dat):
fse_create_io16(dev, device)
fse_create_osc(dev, device, fse)
fse_create_gsr(dev, device)
fse_create_logic2clk(dev, device, dat)
disable_plls(dev, device)
sync_extra_func(dev)
return dev
Expand Down
6 changes: 4 additions & 2 deletions apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def extra_pll_bels(cell, row, col, num, cellname):
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]?|BUFS|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC)(\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)(\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 @@ -572,7 +572,7 @@ def __init__(self, row, col, idx, attrs, flags, connections):
'TBUF': {'ODMUX_1': 'UNKNOWN', 'PULLMODE': 'UP', 'SLEWRATE': 'FAST',
'DRIVE': '8', 'HYSTERESIS': 'NONE', 'CLAMP': 'OFF', 'DIFFRESISTOR': 'OFF',
'SINGLERESISTOR': 'OFF', 'VCCIO': '1.8', 'LVDS_OUT': 'OFF', 'DDR_DYNTERM': 'NA',
'TO': 'INV', 'PERSISTENT': 'OFF', 'ODMUX': 'TRIMUX'},
'TO': 'INV', 'PERSISTENT': 'OFF', 'ODMUX': 'TRIMUX', 'OPENDRAIN': 'OFF'},
'IOBUF': {'ODMUX_1': 'UNKNOWN', 'PULLMODE': 'UP', 'SLEWRATE': 'FAST',
'DRIVE': '8', 'HYSTERESIS': 'NONE', 'CLAMP': 'OFF', 'DIFFRESISTOR': 'OFF',
'SINGLERESISTOR': 'OFF', 'VCCIO': '1.8', 'LVDS_OUT': 'OFF', 'DDR_DYNTERM': 'NA',
Expand Down Expand Up @@ -700,6 +700,8 @@ def place(db, tilemap, bels, cst, args):
bits2zero.update(tiledata.bels[f'BUFS{num}'].flags[fuses])
for r, c in bits2zero:
tile[r][c] = 0
elif typ.startswith("BUFG"):
continue

elif typ in {'OSC', 'OSCZ', 'OSCF', 'OSCH', 'OSCW', 'OSCO'}:
# XXX turn on (GW1NZ-1)
Expand Down
6 changes: 3 additions & 3 deletions examples/himbaechel/Makefile.himbaechel
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,13 @@ clean:
%-tangnano20k.json: %-tangnano20k-synth.json tangnano20k.cst
$(NEXTPNR) --json $< --write $@ --chipdb ${CHIPDB_PATH}/chipdb-GW2A-18C.bin --vopt partno=GW2AR-LV18QN88C8/I7 --vopt cst=tangnano20k.cst

%-tangnano20k-synth.json: tangnano20k/%.v
%-tangnano20k-synth.json: %.v
$(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSC -p "read_verilog $^; synth_gowin -json $@"

pll-nanolcd-tangnano20k-synth.json: pll/GW2A-18-dyn.vh tangnano20k/TOP.v pll-nanolcd/VGAMod.v
pll-nanolcd-tangnano20k-synth.json: pll/GW2A-18-dyn.vh pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v
$(YOSYS) -p "read_verilog $^; synth_gowin -json $@"

attosoc-tangnano20k-synth.json: tangnano20k/attosoc.v attosoc/picorv32.v
attosoc-tangnano20k-synth.json: attosoc/attosoc.v attosoc/picorv32.v
$(YOSYS) -p "read_verilog $^; synth_gowin -json $@"

# ============================================================
Expand Down
3 changes: 2 additions & 1 deletion examples/himbaechel/tangnano20k.cst
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
IO_LOC "clk" 4;
IO_LOC "clk_i" 4;

CLOCK_LOC "clk" BUFG;

IO_LOC "led[0]" 15;
IO_LOC "led[1]" 16;
Expand Down
106 changes: 0 additions & 106 deletions examples/himbaechel/tangnano20k/TOP.v

This file was deleted.

Loading

0 comments on commit 0f3cab7

Please sign in to comment.