aboutsummaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2019-04-17 11:00:23 +0100
committerDavid Shah <dave@ds0.me>2019-04-17 11:00:23 +0100
commit48c4c1ed0561e643a591ed7fca21c69954abd8d2 (patch)
treee5a91b0f2f5b090a0109a278343c54e34b5dada0 /generic
parent90ceb829f347372975310d40d2bb6bade0352890 (diff)
downloadnextpnr-48c4c1ed0561e643a591ed7fca21c69954abd8d2.tar.gz
nextpnr-48c4c1ed0561e643a591ed7fca21c69954abd8d2.tar.bz2
nextpnr-48c4c1ed0561e643a591ed7fca21c69954abd8d2.zip
generic/examples: Add FASM writer Python script
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'generic')
-rw-r--r--generic/examples/.gitignore4
-rw-r--r--generic/examples/README.md5
-rw-r--r--generic/examples/__init__.py0
-rw-r--r--generic/examples/bitstream.py17
-rw-r--r--generic/examples/report.py13
-rw-r--r--generic/examples/simple.py22
-rwxr-xr-xgeneric/examples/simple.sh2
-rw-r--r--generic/examples/simple_config.py15
-rw-r--r--generic/examples/write_fasm.py52
9 files changed, 92 insertions, 38 deletions
diff --git a/generic/examples/.gitignore b/generic/examples/.gitignore
index 83d79a7d..38e95de5 100644
--- a/generic/examples/.gitignore
+++ b/generic/examples/.gitignore
@@ -1 +1,3 @@
-blinky.txt
+blinky.fasm
+__pycache__
+*.pyc
diff --git a/generic/examples/README.md b/generic/examples/README.md
index dd154a51..9fd106d9 100644
--- a/generic/examples/README.md
+++ b/generic/examples/README.md
@@ -7,7 +7,8 @@ This contains a simple, artificial, example of the nextpnr generic API.
- simple_timing.py annotates cells with timing data (this is a separate script that must be run after packing)
- - report.py stores design information after place-and-route to blinky.txt in place
- of real bitstream generation
+ - write_fasm.py uses the nextpnr Python API to write a FASM file for a design
+
+ - bitstream.py uses write_fasm.py to create a FASM ("FPGA assembly") file for the place-and-routed design
- Run simple.sh to build an example design on the FPGA above \ No newline at end of file
diff --git a/generic/examples/__init__.py b/generic/examples/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/generic/examples/__init__.py
diff --git a/generic/examples/bitstream.py b/generic/examples/bitstream.py
new file mode 100644
index 00000000..1ab94f0c
--- /dev/null
+++ b/generic/examples/bitstream.py
@@ -0,0 +1,17 @@
+from write_fasm import *
+from simple_config import K
+
+# Need to tell FASM generator how to write parameters
+# (celltype, parameter) -> ParameterConfig
+param_map = {
+ ("GENERIC_SLICE", "K"): ParameterConfig(write=False),
+ ("GENERIC_SLICE", "INIT"): ParameterConfig(write=True, numeric=True, width=2**K),
+ ("GENERIC_SLICE", "FF_USED"): ParameterConfig(write=True, numeric=True, width=1),
+
+ ("GENERIC_IOB", "INPUT_USED"): ParameterConfig(write=True, numeric=True, width=1),
+ ("GENERIC_IOB", "OUTPUT_USED"): ParameterConfig(write=True, numeric=True, width=1),
+ ("GENERIC_IOB", "ENABLE_USED"): ParameterConfig(write=True, numeric=True, width=1),
+}
+
+with open("blinky.fasm", "w") as f:
+ write_fasm(ctx, param_map, f) \ No newline at end of file
diff --git a/generic/examples/report.py b/generic/examples/report.py
deleted file mode 100644
index c43367fa..00000000
--- a/generic/examples/report.py
+++ /dev/null
@@ -1,13 +0,0 @@
-with open("blinky.txt", "w") as f:
- for nname, net in ctx.nets:
- print("# Net %s" % nname, file=f)
- # FIXME: Pip ordering
- for wire, pip in net.wires:
- if pip.pip != "":
- print("%s" % pip.pip, file=f)
- print("", file=f)
- for cname, cell in ctx.cells:
- print("# Cell %s at %s" % (cname, cell.bel), file=f)
- for param, val in cell.params:
- print("%s.%s %s" % (cell.bel, param, val), file=f)
- print("", file=f) \ No newline at end of file
diff --git a/generic/examples/simple.py b/generic/examples/simple.py
index f87a6049..9339b68a 100644
--- a/generic/examples/simple.py
+++ b/generic/examples/simple.py
@@ -1,22 +1,4 @@
-# Grid size including IOBs at edges
-X = 12
-Y = 12
-# SLICEs per tile
-N = 8
-# LUT input count
-K = 4
-# Number of local wires
-Wl = N*(K+1) + 8
-# 1/Fc for bel input wire pips
-Si = 4
-# 1/Fc for Q to local wire pips
-Sq = 4
-# ~1/Fc local to neighbour local wire pips
-Sl = 8
-
-# Create graphic elements
-# Bels
-ctx.addDecalGraphic("bel", GraphicElement(type=TYPE_BOX, style=STYLE_INACTIVE, x1=0, y1=0, x2=0.2, y2=(1/(N+1))-0.02, z=0))
+from simple_config import *
def is_io(x, y):
return x == 0 or x == X-1 or y == 0 or y == Y-1
@@ -41,7 +23,6 @@ for x in range(X):
ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="I", wire="X%dY%dZ%d_I0" % (x, y, z))
ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="EN", wire="X%dY%dZ%d_I1" % (x, y, z))
ctx.addBelOutput(bel="X%dY%d_IO%d" % (x, y, z), name="O", wire="X%dY%dZ%d_Q" % (x, y, z))
- ctx.setBelDecal(bel="X%dY%d_IO%d" % (x, y, z), decalxy=ctx.DecalXY("bel", 0.6, z * (1/(N+1))))
else:
for z in range(N):
ctx.addBel(name="X%dY%d_SLICE%d" % (x, y, z), type="GENERIC_SLICE", loc=Loc(x, y, z), gb=False)
@@ -49,7 +30,6 @@ for x in range(X):
for k in range(K):
ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="I[%d]" % k, wire="X%dY%dZ%d_I%d" % (x, y, z, k))
ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="Q", wire="X%dY%dZ%d_Q" % (x, y, z))
- ctx.setBelDecal(bel="X%dY%d_SLICE%d" % (x, y, z), decalxy=ctx.DecalXY("bel", 0.6, z * (1/(N+1))))
for x in range(X):
for y in range(Y):
diff --git a/generic/examples/simple.sh b/generic/examples/simple.sh
index 2e8d6180..576a6418 100755
--- a/generic/examples/simple.sh
+++ b/generic/examples/simple.sh
@@ -1,4 +1,4 @@
#!/usr/bin/bash
set -ex
yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v
-../../nextpnr-generic --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route report.py \ No newline at end of file
+../../nextpnr-generic --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py \ No newline at end of file
diff --git a/generic/examples/simple_config.py b/generic/examples/simple_config.py
new file mode 100644
index 00000000..dfb38f1c
--- /dev/null
+++ b/generic/examples/simple_config.py
@@ -0,0 +1,15 @@
+# Grid size including IOBs at edges
+X = 12
+Y = 12
+# SLICEs per tile
+N = 8
+# LUT input count
+K = 4
+# Number of local wires
+Wl = N*(K+1) + 8
+# 1/Fc for bel input wire pips
+Si = 4
+# 1/Fc for Q to local wire pips
+Sq = 4
+# ~1/Fc local to neighbour local wire pips
+Sl = 8 \ No newline at end of file
diff --git a/generic/examples/write_fasm.py b/generic/examples/write_fasm.py
new file mode 100644
index 00000000..fb55c41d
--- /dev/null
+++ b/generic/examples/write_fasm.py
@@ -0,0 +1,52 @@
+from collections import namedtuple
+
+"""
+ write: set to True to enable writing this parameter to FASM
+
+ numeric: set to True to write this parameter as a bit array (width>1) or
+ single bit (width==1) named after the parameter. Otherwise this
+ parameter will be written as `name.value`
+
+ width: width of numeric parameter (ignored for non-numeric parameters)
+
+ alias: an alternative name for this parameter (parameter name used if alias
+ is None)
+"""
+ParameterConfig = namedtuple('ParameterConfig', 'write numeric width alias')
+
+# FIXME use defaults= once Python 3.7 is standard
+ParameterConfig.__new__.__defaults__ = (False, True, 1, None)
+
+
+"""
+Write a design as FASM
+
+ ctx: nextpnr context
+ paramCfg: ParameterConfig describing how to write parameters
+ f: output file
+"""
+def write_fasm(ctx, paramCfg, f):
+ for nname, net in sorted(ctx.nets, key=lambda x: str(x[1].name)):
+ print("# Net %s" % nname, file=f)
+ for wire, pip in sorted(net.wires, key=lambda x: str(x[1])):
+ if pip.pip != "":
+ print("%s" % pip.pip, file=f)
+ print("", file=f)
+ for cname, cell in sorted(ctx.cells, key=lambda x: str(x[1].name)):
+ print("# Cell %s at %s" % (cname, cell.bel), file=f)
+ for param, val in sorted(cell.params, key=lambda x: str(x)):
+ cfg = paramCfg[(cell.type, param)]
+ if not cfg.write:
+ continue
+ fasm_name = cfg.alias if cfg.alias is not None else param
+ if cfg.numeric:
+ if cfg.width == 1:
+ if int(val) != 0:
+ print("%s.%s" % (cell.bel, fasm_name), file=f)
+ else:
+ # Parameters with width >32 are direct binary, otherwise denary
+ binval = val if cfg.width > 32 else "{:0{}b}".format(int(val), cfg.width)
+ print("%s.%s[%d:0] = %d'b%s" % (cell.bel, fasm_name, cfg.width-1, cfg.width, binval), file=f)
+ else:
+ print("%s.%s.%s" % (cell.bel, fasm_name, val), file=f)
+ print("", file=f) \ No newline at end of file