generic/examples: Add FASM writer Python script
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
90ceb829f3
commit
48c4c1ed05
4
generic/examples/.gitignore
vendored
4
generic/examples/.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
blinky.txt
|
blinky.fasm
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
@ -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)
|
- 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
|
- write_fasm.py uses the nextpnr Python API to write a FASM file for a design
|
||||||
of real bitstream generation
|
|
||||||
|
- 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
|
- Run simple.sh to build an example design on the FPGA above
|
0
generic/examples/__init__.py
Normal file
0
generic/examples/__init__.py
Normal file
17
generic/examples/bitstream.py
Normal file
17
generic/examples/bitstream.py
Normal file
@ -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)
|
@ -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)
|
|
@ -1,22 +1,4 @@
|
|||||||
# Grid size including IOBs at edges
|
from simple_config import *
|
||||||
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))
|
|
||||||
|
|
||||||
def is_io(x, y):
|
def is_io(x, y):
|
||||||
return x == 0 or x == X-1 or y == 0 or y == Y-1
|
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="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.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.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:
|
else:
|
||||||
for z in range(N):
|
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)
|
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):
|
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.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.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 x in range(X):
|
||||||
for y in range(Y):
|
for y in range(Y):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
set -ex
|
set -ex
|
||||||
yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v
|
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
|
../../nextpnr-generic --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py
|
15
generic/examples/simple_config.py
Normal file
15
generic/examples/simple_config.py
Normal file
@ -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
|
52
generic/examples/write_fasm.py
Normal file
52
generic/examples/write_fasm.py
Normal file
@ -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)
|
Loading…
Reference in New Issue
Block a user