Skip to content

Commit

Permalink
add magic sdram pin constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
pepijndevos committed Sep 20, 2024
1 parent 4f87247 commit 9550b93
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 3 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ all: apycula/GW1N-1.pickle apycula/GW1N-9.pickle apycula/GW1N-4.pickle \
%_stage2.pickle: apycula/clock_fuzzer.py %_stage1.pickle
python3 -m apycula.clock_fuzzer $*

apycula/%.pickle: %_stage2.pickle
%_stage3.pickle: apycula/find_sdram_pins.py %_stage2.pickle
python3 -m apycula.find_sdram_pins $*

apycula/%.pickle: %_stage3.pickle
gzip -c $< > $@

clean:
Expand Down
2 changes: 2 additions & 0 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class Device:
packages: Dict[str, Tuple[str, str, str]] = field(default_factory=dict)
# {variant: {package: {pin#: (pin_name, [cfgs])}}}
pinout: Dict[str, Dict[str, Dict[str, Tuple[str, List[str]]]]] = field(default_factory=dict)
# {variant: {package: (net, row, col, AB)}}
sip_cst: Dict[str, Dict[str, Tuple[str, int, int, str]]] = field(default_factory=dict)
pin_bank: Dict[str, int] = field(default_factory = dict)
cmd_hdr: List[ByteString] = field(default_factory=list)
cmd_ftr: List[ByteString] = field(default_factory=list)
Expand Down
6 changes: 4 additions & 2 deletions apycula/codegen.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from itertools import chain
import re

class Module:
def __init__(self):
Expand Down Expand Up @@ -26,7 +27,8 @@ def write(self, f):
if not first:
f.write(", ")
first = False
f.write(port)
bare = re.sub(r" *\[.*\] *", "", port)
f.write(bare)
f.write(");\n")

for port in self.inputs:
Expand Down Expand Up @@ -135,7 +137,7 @@ def write(self, f):
"""

device_desc = self.partnumber
if self.device in ['GW1N-9', 'GW1N-4', 'GW1N-9C', 'GW2A-18', 'GW2A-18C']:
if self.device in ['GW1NR-9', 'GW1N-9', 'GW1N-4', 'GW1N-9C', 'GW2A-18', 'GW2A-18C']:
device_desc = f'-name {self.device} {device_desc}'

f.write(template.format(
Expand Down
106 changes: 106 additions & 0 deletions apycula/find_sdram_pins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/python3

import pickle
from multiprocessing.dummy import Pool

from apycula import codegen, tiled_fuzzer, gowin_unpack, chipdb

def run_script(pinName : str, idx=None):
if idx == None:
port = pinName
idxName = pinName
else:
port = f"[{idx}:{idx}] {pinName}"
idxName = f"{pinName}[{idx}]"

mod = codegen.Module()
cst = codegen.Constraints()

name = "iobased"
if pinName.startswith("IO"):
mod.inouts.add(port)
iob = codegen.Primitive("TBUF", name)
iob.portmap["O"] = idxName
iob.portmap["I"] = ""
iob.portmap["OEN"] = ""
mod.primitives[name] = iob
elif pinName.startswith("O"):
mod.outputs.add(port)
iob = codegen.Primitive("OBUF", name)
iob.portmap["O"] = idxName
iob.portmap["I"] = ""
mod.primitives[name] = iob
elif pinName.startswith("I"):
mod.inputs.add(port)
iob = codegen.Primitive("IBUF", name)
iob.portmap["I"] = idxName
iob.portmap["O"] = ""
mod.primitives[name] = iob
else:
raise ValueError(pinName)

pnr_result = tiled_fuzzer.run_pnr(mod, cst, {})
tiles = chipdb.tile_bitmap(db, pnr_result.bitmap)

for (i, j), tile in tiles.items():
bels, _, _ = gowin_unpack.parse_tile_(db, i, j, tile)
iob_location = f"R{i}C{j}"
print(iob_location, bels)
if bels and ("IOBA" in bels or "IOBB" in bels):
bel = next(iter(bels))
belname = tiled_fuzzer.rc2tbrl(db, i+1, j+1, bel[-1])
print(db.rows, db.cols)
print(idxName, belname)
return (idxName, i, j, bel[-1])

raise Exception(f"No IOB found for {port}")

# these are all system in package variants with magic wire names connected interally
params = {
"GW1N-9": [{
"package": "QFN88",
"device": "GW1NR-9",
"partnumber": "GW1NR-UV9QN88C6/I5",
"pins": [
["IO_sdram_dq", 16],
["O_sdram_clk", 0],
["O_sdram_cke", 0],
["O_sdram_cs_n", 0],
["O_sdram_cas_n", 0],
["O_sdram_ras_n", 0],
["O_sdram_wen_n", 0],
["O_sdram_addr", 12],
["O_sdram_dqm", 2],
["O_sdram_ba", 2]
],
}],
}
# pin name, bus width

with open(f"{tiled_fuzzer.device}_stage2.pickle", 'rb') as f:
db = pickle.load(f)

pool = Pool()

if tiled_fuzzer.device in params:
devices = params[tiled_fuzzer.device]
for device in devices:
tiled_fuzzer.params = device
pins = device["pins"]

runs = []
for pinName, pinBuswidth in pins:
if (pinBuswidth == 0):
runs.append((pinName, None))
else:
for pinIdx in range(0, pinBuswidth):
runs.append((pinName, pinIdx))

print(runs)

pinmap = pool.map(lambda params: run_script(*params), runs)

db.sip_cst.setdefault(device["device"], {})[device["package"]] = pinmap

with open(f"{tiled_fuzzer.device}_stage3.pickle", 'wb') as f:
pickle.dump(db, f)
13 changes: 13 additions & 0 deletions apycula/tiled_fuzzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ def tbrl2rc(fse, side, num):
col = len(fse['header']['grid'][61][0])-1
return (row, col)

def rc2tbrl(db, row, col, num):
edge = 'T'
idx = col
if row == db.rows:
edge = 'B'
elif col == 1:
edge = 'L'
idx = row
elif col == db.cols:
edge = 'R'
idx = row
return f"IO{edge}{idx}{num}"

# Read the packer vendor log to identify problem with primitives/attributes
# returns dictionary {(primitive name, error code) : [full error text]}
_err_parser = re.compile(r"(\w+) +\(([\w\d]+)\).*'(inst[^\']+)\'.*")
Expand Down

0 comments on commit 9550b93

Please sign in to comment.