Skip to content

Commit 9e15ca1

Browse files
committed
Allow specifying family aliases (ie NR parts)
1 parent a4f04e0 commit 9e15ca1

File tree

8 files changed

+114
-17
lines changed

8 files changed

+114
-17
lines changed

.github/workflows/chipdb.yml

+13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ on:
1111
pull_request:
1212

1313
jobs:
14+
family_info:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v3
18+
- name: Build family_info.json
19+
run: |
20+
docker pull pepijndevos/apicula:1.9.8
21+
docker run -v $(pwd):/usr/src/apicula pepijndevos/apicula:1.9.8 make apycula/family_info.json
22+
- name: Archive artifact
23+
uses: actions/upload-artifact@v3
24+
with:
25+
name: family_info.json
26+
path: apycula/family_info.json
1427
gw1n1:
1528
runs-on: ubuntu-latest
1629
steps:

Makefile

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ endif
66
.PHONY: all clean
77
all: apycula/GW1N-1.pickle apycula/GW1N-9.pickle apycula/GW1N-4.pickle \
88
apycula/GW1NS-2.pickle apycula/GW1NS-4.pickle apycula/GW1N-9C.pickle \
9-
apycula/GW1NZ-1.pickle apycula/GW2A-18.pickle apycula/GW2A-18C.pickle
9+
apycula/GW1NZ-1.pickle apycula/GW2A-18.pickle apycula/GW2A-18C.pickle \
10+
family_info.json
1011

1112
%.json: apycula/dat19_h4x.py
1213
python3 -m apycula.dat19_h4x $*
@@ -20,7 +21,12 @@ all: apycula/GW1N-1.pickle apycula/GW1N-9.pickle apycula/GW1N-4.pickle \
2021
apycula/%.pickle: %_stage2.pickle
2122
gzip -c $< > $@
2223

24+
apycula/family_info.json: apycula/build_family_info.py
25+
python3 -m apycula.build_family_info
26+
cp family_info.json apycula/
27+
2328
clean:
2429
rm *.json
2530
rm *.pickle
2631
rm apycula/*.pickle
32+
rm apycula/family_info.json

apycula/build_family_info.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import json
2+
import os
3+
import subprocess
4+
from collections import defaultdict
5+
6+
def build_family_aliases():
7+
db_hashes = defaultdict(list)
8+
9+
family_info = defaultdict(dict)
10+
11+
# load IDCODEs from programmer.json
12+
with open("/usr/src/gowin/IDE/bin/programmer.json") as f:
13+
data = json.loads(f.read())
14+
for device_data in data["DEVICE_CONFIG"]:
15+
if device_data["DEVICE"] == "JTAG_NOP":
16+
continue
17+
18+
family_info[device_data["DEVICE"]]["idcode"] = device_data["IDCODE"]
19+
20+
# if devices have the same *.fse hash, assume they are the same family
21+
md5_exec = subprocess.run("md5sum /usr/src/gowin/IDE/share/device/*/*.fse",
22+
shell=True, check=True, capture_output=True,
23+
encoding='utf-8')
24+
25+
for line in md5_exec.stdout.splitlines():
26+
computed_hash, path = line.split(" ")
27+
family = os.path.split(path)[-1].replace(".fse", "")
28+
db_hashes[computed_hash].append(family)
29+
30+
for computed_hash, families in db_hashes.items():
31+
# arbitrarily use the shortest family as the "true" family
32+
families.sort(key=lambda x: (len(x), x))
33+
34+
for family in families:
35+
base_family = families[0]
36+
family_info[family]["base_family"] = base_family
37+
38+
# if the family has no IDCODE, try to inherit from the base family
39+
if "idcode" not in family_info[family] and "idcode" in family_info[base_family]:
40+
family_info[family]["idcode"] = family_info[families[0]]["idcode"]
41+
42+
return family_info
43+
44+
45+
if __name__ == "__main__":
46+
family_aliases = build_family_aliases()
47+
with open("family_info.json", "w") as f:
48+
f.write(json.dumps(dict(family_aliases), indent=2))

apycula/family_aliases.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import importlib.resources
2+
import json
3+
4+
def replace_family_alias(family):
5+
with importlib.resources.path('apycula', f'family_info.json') as path:
6+
with open(path, 'r') as f:
7+
family_info = json.load(f)
8+
9+
if family in family_info:
10+
return family_info[family]["base_family"]
11+
else:
12+
return family
13+

apycula/gowin_pack.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from apycula import attrids
1818
from apycula import bslib
1919
from apycula.wirenames import wirenames, wirenumbers
20+
from apycula.family_aliases import replace_family_alias
2021

2122
device = ""
2223
pnr = None
@@ -1029,12 +1030,25 @@ def route(db, tilemap, pips):
10291030
for row, col in bits:
10301031
tile[row][col] = 1
10311032

1032-
def header_footer(db, bs, compress):
1033+
def header_footer(db, bs, compress, family):
10331034
"""
10341035
Generate fs header and footer
10351036
Currently limited to checksum with
10361037
CRC_check and security_bit_enable set
10371038
"""
1039+
# override part IDCODE in header
1040+
assert db.cmd_hdr[3][0] == 0x06 # IDCODE data
1041+
1042+
with importlib.resources.path('apycula', f'family_info.json') as path:
1043+
with open(path, 'r') as f:
1044+
family_info = json.load(f)
1045+
1046+
if family in family_info and "idcode" in family_info[family]:
1047+
db.cmd_hdr[3][-4:] = bytes.fromhex(family_info[family]["idcode"])
1048+
else:
1049+
print("Not overriding IDCODE as it is not present in family_info.json")
1050+
1051+
# calculate checksum
10381052
bs = np.fliplr(bs)
10391053
bs=np.packbits(bs)
10401054
# configuration data checksum is computed on all
@@ -1157,7 +1171,7 @@ def main():
11571171
parser.add_argument('--png')
11581172

11591173
args = parser.parse_args()
1160-
device = args.device
1174+
device = replace_family_alias(args.device)
11611175

11621176
with open(args.netlist) as f:
11631177
pnr = json.load(f)
@@ -1173,7 +1187,9 @@ def main():
11731187
mods = m.group(1) or ""
11741188
luts = m.group(3)
11751189
device = f"GW1N{mods}-{luts}"
1176-
with importlib.resources.path('apycula', f'{args.device}.pickle') as path:
1190+
device = replace_family_alias(device)
1191+
1192+
with importlib.resources.path('apycula', f'{device}.pickle') as path:
11771193
with closing(gzip.open(path, 'rb')) as f:
11781194
db = pickle.load(f)
11791195

@@ -1206,7 +1222,7 @@ def main():
12061222
tile[row][col] = 0
12071223

12081224
res = chipdb.fuse_bitmap(db, tilemap)
1209-
header_footer(db, res, args.compress)
1225+
header_footer(db, res, args.compress, device)
12101226
if pil_available and args.png:
12111227
bslib.display(args.png, res)
12121228
bslib.write_bitstream(args.output, res, db.cmd_hdr, db.cmd_ftr, args.compress)

apycula/gowin_unpack.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from apycula import attrids
1515
from apycula.bslib import read_bitstream
1616
from apycula.wirenames import wirenames
17+
from apycula.family_aliases import replace_family_alias
1718

1819
_device = ""
1920
_pinout = ""
@@ -1074,7 +1075,7 @@ def main():
10741075
args = parser.parse_args()
10751076

10761077
global _device
1077-
_device = args.device
1078+
_device = replace_family_alias(args.device)
10781079
# For tool integration it is allowed to pass a full part number
10791080
m = re.match("GW1N(S?)[A-Z]*-(LV|UV|UX)([0-9])C?([A-Z]{2}[0-9]+P?)(C[0-9]/I[0-9])", _device)
10801081
if m:

examples/Makefile

+5-5
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,16 @@ pll-tangnano4k.json: pll-tangnano4k-synth.json tangnano4k.cst
121121
$(NEXTPNR) --json $< --write $@ --device GW1NSR-LV4CQN48PC7/I6 --cst tangnano4k.cst
122122

123123
%-tangnano9k.fs: %-tangnano9k.json
124-
gowin_pack -d GW1N-9C -o $@ $^
124+
gowin_pack -d GW1NR-9C -o $@ $^
125125

126126
pll-nanolcd-tangnano9k.fs: pll-nanolcd-tangnano9k.json
127-
gowin_pack -d GW1N-9C --sspi_as_gpio --mspi_as_gpio -o $@ $^
127+
gowin_pack -d GW1NR-9C --sspi_as_gpio --mspi_as_gpio -o $@ $^
128128

129129
%-tangnano9k.json: %-tangnano9k-synth.json tangnano9k.cst
130-
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1N-9C --cst tangnano9k.cst
130+
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1NR-9C --cst tangnano9k.cst
131131

132132
%lvds-tangnano9k.json: %lvds-tangnano9k-synth.json lvds-tangnano9k.cst
133-
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1N-9C --cst lvds-tangnano9k.cst
133+
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1NR-9C --cst lvds-tangnano9k.cst
134134

135135
%-honeycomb.fs: %-honeycomb.json
136136
gowin_pack -d GW1NS-2 -o $@ $<
@@ -264,7 +264,7 @@ pll-%-honeycomb-synth.json: pll/GW1NS-2C-%.vh pll.v pll/rpll.v
264264
$(NEXTPNR) --json $< --write $@ --device GW1NSR-LV4CQN48PC7/I6 --cst longwires/tangnano4k.cst
265265

266266
%-lw-tangnano9k.json: %-tangnano9k-synth.json longwires/tangnano9k.cst
267-
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1N-9C --cst longwires/tangnano9k.cst
267+
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1NR-9C --cst longwires/tangnano9k.cst
268268

269269
%-lw-runber.json: %-runber-synth.json longwires/runber.cst
270270
$(NEXTPNR) --json $< --write $@ --device GW1N-UV4LQ144C6/I5 --cst longwires/runber.cst

examples/himbaechel/Makefile.himbaechel

+6-6
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,10 @@ clean:
141141
# ============================================================
142142
# Tangnano20k
143143
%-tangnano20k.fs: %-tangnano20k.json
144-
gowin_pack -d GW2A-18C -o $@ $<
144+
gowin_pack -d GW2AR-18C -o $@ $<
145145

146146
%-tangnano20k.json: %-tangnano20k-synth.json tangnano20k.cst
147-
$(NEXTPNR) --json $< --write $@ --device GW2AR-LV18QN88C8/I7 --vopt family=GW2A-18C --vopt cst=tangnano20k.cst
147+
$(NEXTPNR) --json $< --write $@ --device GW2AR-LV18QN88C8/I7 --vopt family=GW2AR-18C --vopt cst=tangnano20k.cst
148148

149149
%-tangnano20k-synth.json: %.v
150150
$(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSC -D INV_BTN=1 -p "read_verilog $^; synth_gowin -json $@"
@@ -223,7 +223,7 @@ blinky-pll-tangnano4k-synth.json: pll/GW1NS-4-dyn.vh blinky-pll-vr.v
223223
gowin_pack -d GW1N-9C -o $@ $^
224224

225225
%-tangnano9k.json: %-tangnano9k-synth.json tangnano9k.cst
226-
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --vopt family=GW1N-9C --vopt cst=tangnano9k.cst
226+
$(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --vopt family=GW1NR-9C --vopt cst=tangnano9k.cst
227227

228228
%-tangnano9k-synth.json: %.v
229229
$(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSC -D INV_BTN=0 -p "read_verilog $^; synth_gowin -json $@"
@@ -232,7 +232,7 @@ pll-nanolcd-tangnano9k-synth.json: pll/GW1N-9C-dyn.vh pll-nanolcd/TOP.v pll-nano
232232
$(YOSYS) -D INV_BTN=0 -p "read_verilog $^; synth_gowin -json $@"
233233

234234
pll-nanolcd-tangnano9k.fs: pll-nanolcd-tangnano9k.json
235-
gowin_pack -d GW1N-9C --sspi_as_gpio --mspi_as_gpio -o $@ $^
235+
gowin_pack -d GW1NR-9C --sspi_as_gpio --mspi_as_gpio -o $@ $^
236236

237237
# ============================================================
238238
# szfpga (GW1N-9)
@@ -288,10 +288,10 @@ blinky-pll-runber-synth.json: pll/GW1N-4-dyn.vh blinky-pll.v
288288
gowin_unpack -d GW1NS-4 -o $@ $^
289289

290290
%-tangnano9k-unpacked.v: %-tangnano9k.fs
291-
gowin_unpack -d GW1N-9C -o $@ $^
291+
gowin_unpack -d GW1NR-9C -o $@ $^
292292

293293
%-tangnano20k-unpacked.v: %-tangnano20k.fs
294-
gowin_unpack -d GW2A-18C -o $@ $^
294+
gowin_unpack -d GW2AR-18C -o $@ $^
295295

296296
%-runber-unpacked.v: %-runber.fs
297297
gowin_unpack -d GW1N-4 -o $@ $^

0 commit comments

Comments
 (0)