Skip to content

Commit

Permalink
Merge with master
Browse files Browse the repository at this point in the history
  • Loading branch information
yrabbit committed Aug 13, 2024
2 parents 6889998 + 1c507c2 commit 5af24fd
Show file tree
Hide file tree
Showing 19 changed files with 1,348 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/chipdb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ jobs:
strategy:
fail-fast: false
matrix:
yosys: [main, yosys-0.39]
yosys: [main, yosys-0.44]
nextpnr: [master, nextpnr-0.7]
steps:
- uses: actions/checkout@v4
Expand Down
32 changes: 32 additions & 0 deletions apycula/attrids.py
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,38 @@
'SET': 16,
'RESET': 17
}

# DCS
# just quadrant index
dcs_attrids = {
'1': 1,
'2': 0,
'3': 2,
'4': 3,
}
# There are no combinations here since the DCS primitive has only one
# parameter, so by specifying the value of this parameter and generating the
# image it is easy to find the number in this table.
dcs_attrvals = {
'UNKNOWN': 0,
'FALLING': 1,
'RISING': 2,
'CLK0': 3,
'CLK1': 4,
'CLK2': 5,
'CLK3': 6,
'CLK0_VCC': 13,
'CLK1_VCC': 14,
'CLK2_GND': 15,
'CLK2_VCC': 16,
'CLK3_VCC': 17,
'CLK0_GND': 18,
'CLK1_GND': 19,
'CLK3_GND': 20,
'GND': 21,
'VCC': 22,
}

# DLL
dll_attrids = {
'CLKSEL': 0,
Expand Down
26 changes: 16 additions & 10 deletions apycula/bitmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,28 @@ def packbits(bmp, axis = None):
Returns a list of bytes.
"""
byte_list = []
byte = 0
bit_cnt = 0
if not axis:
for bmp_r in bmp:
for col in range(shape(bmp)[1] // 8):
bcol = col << 3
byte_list.append((bmp_r[bcol] << 7) + (bmp_r[bcol + 1] << 6) + (bmp_r[bcol + 2] << 5) +
(bmp_r[bcol + 3] << 4) + (bmp_r[bcol + 4] << 3) + (bmp_r[bcol + 5] << 2) +
(bmp_r[bcol + 6] << 1) + bmp_r[bcol + 7])
for col in range(shape(bmp)[1]):
byte = (byte << 1) + bmp_r[col]
bit_cnt += 1
if bit_cnt == 8:
byte_list.append(byte)
bit_cnt = 0
byte = 0
else:
for bmp_r in bmp:
byte_list.append([])
byte_list_r = byte_list[-1]
for col in range(shape(bmp)[1] // 8):
bcol = col << 3
byte_list_r.append((bmp_r[bcol] << 7) + (bmp_r[bcol + 1] << 6) + (bmp_r[bcol + 2] << 5) +
(bmp_r[bcol + 3] << 4) + (bmp_r[bcol + 4] << 3) + (bmp_r[bcol + 5] << 2) +
(bmp_r[bcol + 6] << 1) + bmp_r[bcol + 7])
for col in range(shape(bmp)[1]):
byte = (byte << 1) + bmp_r[col]
bit_cnt += 1
if bit_cnt == 8:
byte_list_r.append(byte)
bit_cnt = 0
byte = 0
return byte_list

def xor(bmp_0, bmp_1):
Expand Down
449 changes: 389 additions & 60 deletions apycula/chipdb.py

Large diffs are not rendered by default.

106 changes: 102 additions & 4 deletions apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from contextlib import closing
from apycula import codegen
from apycula import chipdb
from apycula.chipdb import add_attr_val, get_shortval_fuses, get_longval_fuses, get_bank_fuses
from apycula.chipdb import add_attr_val, get_shortval_fuses, get_longval_fuses, get_bank_fuses, get_long_fuses
from apycula import attrids
from apycula import bslib
from apycula import bitmatrix
Expand Down 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|BANDGAP|DHCEN)(\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|CLKDIV2|CLKDIV|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DQCE|DCS|DHCEN)(\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 @@ -376,7 +376,6 @@ def add_pll_default_attrs(attrs):
pll_inattrs[k] = v
return pll_inattrs


# typ - PLL type (RPLL, etc)
def set_pll_attrs(db, typ, idx, attrs):
pll_inattrs = add_pll_default_attrs(attrs)
Expand Down Expand Up @@ -503,6 +502,28 @@ def set_pll_attrs(db, typ, idx, attrs):
add_attr_val(db, 'PLL', fin_attrs, attrids.pll_attrids[attr], val)
return fin_attrs

_dcs_spine2quadrant_idx = {
'SPINE6' : ('1', 'DCS6'),
'SPINE7' : ('1', 'DCS7'),
'SPINE14' : ('2', 'DCS6'),
'SPINE15' : ('2', 'DCS7'),
'SPINE22' : ('3', 'DCS6'),
'SPINE23' : ('3', 'DCS7'),
'SPINE30' : ('4', 'DCS6'),
'SPINE31' : ('4', 'DCS7'),
}
def set_dcs_attrs(db, spine, attrs):
q, _ = _dcs_spine2quadrant_idx[spine]
dcs_attrs = {}
dcs_attrs[q] = attrs['DCS_MODE']

fin_attrs = set()
for attr, val in dcs_attrs.items():
if isinstance(val, str):
val = attrids.dcs_attrvals[val]
add_attr_val(db, 'DCS', fin_attrs, attrids.dcs_attrids[attr], val)
return fin_attrs

_bsram_bit_widths = { 1: '1', 2: '2', 4: '4', 8: '9', 9: '9', 16: '16', 18: '16', 32: 'X36', 36: 'X36'}
def set_bsram_attrs(db, typ, params):
bsram_attrs = {}
Expand Down Expand Up @@ -2005,6 +2026,52 @@ def set_fuse():
for row in range(db.rows):
set_fuse()

def bin_str_to_dec(str_val):
bin_pattern = r'^[0,1]+'
bin_str = re.findall(bin_pattern, str_val)
if bin_str:
dec_num = int(bin_str[0], 2)
return str(dec_num)
return None



_hclk_default_params ={"GSREN": "false", "DIV_MODE":"2"}
def set_hclk_attrs(db, params, num, typ, cell_name):
name_pattern = r'^_HCLK([0,1])_SECT([0,1])$'
params = dict(params or _hclk_default_params)
attrs = {}
pattern_match = re.findall(name_pattern, num)
if (not pattern_match):
raise Exception (f"Unknown HCLK Bel/HCLK Section: {typ}{num}")
hclk_idx, section_idx = pattern_match[0]

valid_div_modes = ["2", "3.5", "4", "5"]
if device in ["GW1N-1S","GW1N-2","GW1NR-2","GW1NS-4","GW1NS-4C","GW1NSR-4",\
"GW1NSR-4C","GW1NSER-4C","GW1N-9","GW1NR-9", "GW1N-9C","GW1NR-9C","GW1N-1P5"]:
valid_div_modes.append("8")

if (params["DIV_MODE"]) not in valid_div_modes:
bin_match = bin_str_to_dec(params["DIV_MODE"])
if bin_match is None or bin_match not in valid_div_modes:
raise Exception(f"Invalid DIV_MODE {bin_match or params['DIV_MODE']} for CLKDIV {cell_name} on device {device}")
params["DIV_MODE"] = str(bin_match[0])


if (typ == "CLKDIV2"):
attrs[f"BK{section_idx}MUX{hclk_idx}_OUTSEL"] = "DIV2"
elif (typ == "CLKDIV"):
attrs[f"HCLKDIV{hclk_idx}_DIV"] = params["DIV_MODE"]
if (section_idx == '1'):
attrs[f"HCLKDCS{hclk_idx}_SEL"] = f"HCLKBK{section_idx}{hclk_idx}"

fin_attrs = set()
for attr, val in attrs.items():
if isinstance(val, str):
val = attrids.hclk_attrvals[val]
add_attr_val(db, 'HCLK', fin_attrs, attrids.hclk_attrids[attr], val)
return fin_attrs

_iologic_default_attrs = {
'DUMMY': {},
'IOLOGIC': {},
Expand Down Expand Up @@ -2070,7 +2137,8 @@ def set_iologic_attrs(db, attrs, param):
in_attrs['ISI'] = 'ENABLE'
in_attrs['LSRIMUX_0'] = '0'
in_attrs['CLKOMUX'] = 'ENABLE'
#in_attrs['LSRMUX_LSR'] = 'INV'
# in_attrs['LSRMUX_LSR'] = 'INV'

if 'INMODE' in attrs:
if param['IOLOGIC_TYPE'] not in {'IDDR', 'IDDRC'}:
#in_attrs['CLKODDRMUX_WRCLK'] = 'ECLK0'
Expand Down Expand Up @@ -2476,6 +2544,36 @@ def place(db, tilemap, bels, cst, args):
# for the corresponding HCLK and set its fuses.
_, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['wire']
hclk_attrs = find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side)
elif typ in ["CLKDIV", "CLKDIV2"]:
hclk_attrs = set_hclk_attrs(db, parms, num, typ, cellname)
bits = get_shortval_fuses(db, tiledata.ttyp, hclk_attrs, "HCLK")
elif typ == 'DQCE':
# Himbaechel only
pipre = re.compile(r"X(\d+)Y(\d+)/([\w_]+)/([\w_]+)")
if 'DQCE_PIP' not in attrs:
continue
pip = attrs['DQCE_PIP']
res = pipre.fullmatch(pip)
if not res:
raise Exception(f"Bad DQCE pip {pip} at {cellname}")
pip_col, pip_row, dest, src = res.groups()
pip_row = int(pip_row)
pip_col = int(pip_col)

pip_tiledata = db.grid[pip_row][pip_col]
pip_tile = tilemap[(pip_row, pip_col)]
bits = pip_tiledata.clock_pips[dest][src]
for r, c in bits:
pip_tile[r][c] = 1
elif typ == 'DCS':
if 'DCS_MODE' not in attrs:
continue
spine = db.extra_func[row - 1, col - 1]['dcs'][int(num)]['clkout']
dcs_attrs = set_dcs_attrs(db, spine, attrs)
_, idx = _dcs_spine2quadrant_idx[spine]
bits = get_long_fuses(db, tiledata.ttyp, dcs_attrs, idx)
for r, c in bits:
tile[r][c] = 1
else:
print("unknown type", typ)

Expand Down
3 changes: 3 additions & 0 deletions apycula/tiled_fuzzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def fse_iob(fse, db, pin_locations, diff_cap_info, locations):
db = chipdb.from_fse(device, fse, dat)
chipdb.set_banks(fse, db)
db.timing = tm
chipdb.fse_wire_delays(db)
db.packages, db.pinout, db.pin_bank = chipdb.json_pinout(device)

corners = [
Expand Down Expand Up @@ -266,6 +267,8 @@ def fse_iob(fse, db, pin_locations, diff_cap_info, locations):
chipdb.pll_pads(db, device, pad_locs)

chipdb.dat_portmap(dat, db, device)
chipdb.add_hclk_bels(dat, db, device)


# XXX GW1NR-9 has interesting IOBA pins on the bottom side
if device == 'GW1N-9' :
Expand Down
23 changes: 21 additions & 2 deletions apycula/wirenames.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@
101: 'BRPLL0CLK0', 102: 'BRPLL0CLK1', 103: 'BRPLL0CLK2', 104: 'BRPLL0CLK3',
})
clknames.update({n: f"UNK{n}" for n in range(105, 121)})
# These are CLKDIV output nodes
# clknames.update({
# 106: 'THCLK0_CLKDIV_CLKOUT', 108:'THCLK1_CLKDIV_CLKOUT',
# 118: 'RHCLK0_CLKDIV_CLKOUT', 120:'RHCLK1_CLKDIV_CLKOUT',
# 110: 'BHCLK0_CLKDIV_CLKOUT', 112:'BHCLK1_CLKDIV_CLKOUT',
# 114: 'LHCLK0_CLKDIV_CLKOUT', 116:'LHCLK1_CLKDIV_CLKOUT',
# })
clknames.update({
106: 'THCLK0CLKDIV', 108:'THCLK1CLKDIV',
118: 'RHCLK0CLKDIV', 120:'RHCLK1CLKDIV',
110: 'BHCLK0CLKDIV', 112:'BHCLK1CLKDIV',
114: 'LHCLK0CLKDIV', 116:'LHCLK1CLKDIV',
})
# These are the external clock pins, one on each side
clknames.update({
121: 'PCLKT0', 122: 'PCLKT1', 123: 'PCLKB0', 124: 'PCLKB1',
Expand Down Expand Up @@ -128,14 +141,20 @@
2: 'HCLK_IN0', 3: 'HCLK_IN1', 4: 'HCLK_IN2', 5: 'HCLK_IN3', 8: 'HCLK_BANK_IN0', 9: 'HCLK_BANK_IN1'
})

# outputs
# HCLK section inputs
hclknames.update({
6: 'HCLK_BANK_OUT0', 7: 'HCLK_BANK_OUT1', 10: 'HCLK0_SECT0_IN', 11: 'HCLK0_SECT1_IN', 12: 'HCLK1_SECT0_IN', 13: 'HCLK1_SECT1_IN'
})
# these work as inputs in GW1N-9c

# Bypass connections from HCLK_IN to HCLK_OUT
hclknames.update({
16: 'HCLK_9IN0', 17: 'HCLK_9IN1', 18: 'HCLK_9IN2', 19: 'HCLK_9IN3'
})

# CLKDIV2 CLKOUT spurs on the GW1N-9C
hclknames.update({
20: 'HCLK_9_CLKDIV2_SECT0_OUT', 22:'HCLK_9_CLKDIV2_SECT2_OUT'
})


hclknumbers = {v: k for k, v in hclknames.items()}
24 changes: 24 additions & 0 deletions doc/fig/hclk.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions doc/hclk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# HCLK

The High-speed CLocK tiles house the `CLKDIV` and `CLKDIV2` bels, among other functions. `CLKDIV` can drive `IOLOGIC`'s `FCLK` (via `HCLK_OUT`) but can also be used as a generic clock source. In contrast, the output of `CLKDIV2` can not be used as a generic clock source; however it can drive `CLKDIV`'s `HCLKIN`, `IOLOGIC`'s `FCLK`, and (per Gowin's documentation), PLLs.

![Prototypical HCLK](fig/hclk.svg)


The above diagram shows a prototypical HCLK. The GW1N-9C notably bucks this trend, having some wires repurposed, presumably to enable more direct connections by bypassing some fuses and muxes. It is also worthy of note that in the GW1N-9C, CLKDIV's CLKOUT cannot be connected directly to HCLK_OUT, and must thus take a roundtrip through the centre tiles.

As a general rule, signals in one HCLK section are not allowd to connect to another HCLK section. As such, when the input to CLKDIV comes from one HCLK section, it's output must also go to the same section. For ease with following this rule in PnR, the current implementation of HCLK pretends that there are two `CLKDIVs` rather than one. The GW1N-9C once again breaks the norm, having special wires that connect the output of CLKDIV2 in the upper sections to HCLK_OUT in the lower sections.

`HCLKMUX` (for sharing input signals between HCLKs) and `HCLKEN` are currently undocumented and unsupported ;).
Loading

0 comments on commit 5af24fd

Please sign in to comment.