forked from f4pga/prjxray
-
Notifications
You must be signed in to change notification settings - Fork 1
/
fasm2frames.py
executable file
·199 lines (155 loc) · 5.71 KB
/
fasm2frames.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#!/usr/bin/env python3
from __future__ import print_function
import fasm
import argparse
import json
import os
import os.path
from prjxray import fasm_assembler
from prjxray.db import Database
from prjxray.roi import Roi
class FASMSyntaxError(SyntaxError):
pass
def dump_frames_verbose(frames):
print()
print("Frames: %d" % len(frames))
for addr in sorted(frames.keys()):
words = frames[addr]
print(
'0x%08X ' % addr + ', '.join(['0x%08X' % w for w in words]) +
'...')
def dump_frames_sparse(frames):
print()
print("Frames: %d" % len(frames))
for addr in sorted(frames.keys()):
words = frames[addr]
# Skip frames without filled words
for w in words:
if w:
break
else:
continue
print('Frame @ 0x%08X' % addr)
for i, w in enumerate(words):
if w:
print(' % 3d: 0x%08X' % (i, w))
def dump_frm(f, frames):
'''Write a .frm file given a list of frames, each containing a list of 101 32 bit words'''
for addr in sorted(frames.keys()):
words = frames[addr]
f.write(
'0x%08X ' % addr + ','.join(['0x%08X' % w for w in words]) + '\n')
def find_pudc_b(db):
""" Find PUDC_B pin func in grid, and return the tile and site prefix.
The PUDC_B pin is a special 7-series pin that controls unused pin pullup.
If the PUDC_B is unused, it is configured as an input with a PULLUP.
"""
grid = db.grid()
pudc_b_tile_site = None
for tile in grid.tiles():
gridinfo = grid.gridinfo_at_tilename(tile)
for site, pin_function in gridinfo.pin_functions.items():
if 'PUDC_B' in pin_function:
assert pudc_b_tile_site == None, (
pudc_b_tile_site, (tile, site))
iob_y = int(site[-1]) % 2
pudc_b_tile_site = (tile, 'IOB_Y{}'.format(iob_y))
return pudc_b_tile_site
def run(
db_root,
filename_in,
f_out,
sparse=False,
roi=None,
debug=False,
emit_pudc_b_pullup=False):
db = Database(db_root)
assembler = fasm_assembler.FasmAssembler(db)
if emit_pudc_b_pullup:
pudc_b_in_use = False
pudc_b_tile_site = find_pudc_b(db)
def check_for_pudc_b(set_feature):
parts = set_feature.feature.split('.')
if parts[0] == pudc_b_tile_site[0] and parts[
1] == pudc_b_tile_site[1]:
nonlocal pudc_b_in_use
pudc_b_in_use = True
if pudc_b_tile_site is not None:
assembler.set_feature_callback(check_for_pudc_b)
extra_features = []
if roi:
with open(roi) as f:
roi_j = json.load(f)
x1 = roi_j['info']['GRID_X_MIN']
x2 = roi_j['info']['GRID_X_MAX']
y1 = roi_j['info']['GRID_Y_MIN']
y2 = roi_j['info']['GRID_Y_MAX']
assembler.mark_roi_frames(Roi(db=db, x1=x1, x2=x2, y1=y1, y2=y2))
if 'required_features' in roi_j:
extra_features = fasm.parse_fasm_string(
'\n'.join(roi_j['required_features']))
assembler.parse_fasm_filename(filename_in, extra_features=extra_features)
if emit_pudc_b_pullup and not pudc_b_in_use and pudc_b_tile_site is not None:
# Enable IN-only and PULLUP on PUDC_B IOB.
#
# TODO: The following FASM string only works on Artix 50T and Zynq 10
# fabrics. It is known to be wrong for the K70T fabric, but it is
# unclear how to know which IOSTANDARD to use.
missing_features = []
for line in fasm.parse_fasm_string("""
{tile}.{site}.LVCMOS12_LVCMOS15_LVCMOS18_LVCMOS25_LVCMOS33_LVTTL_SSTL135.IN_ONLY
{tile}.{site}.LVCMOS25_LVCMOS33_LVTTL.IN
{tile}.{site}.PULLTYPE.PULLUP
""".format(
tile=pudc_b_tile_site[0],
site=pudc_b_tile_site[1],
)):
assembler.add_fasm_line(line, missing_features)
if missing_features:
raise fasm_assembler.FasmLookupError('\n'.join(missing_features))
frames = assembler.get_frames(sparse=sparse)
if debug:
dump_frames_sparse(frames)
dump_frm(f_out, frames)
def main():
parser = argparse.ArgumentParser(
description=
'Convert FPGA configuration description ("FPGA assembly") into binary frame equivalent'
)
database_dir = os.getenv("XRAY_DATABASE_DIR")
database = os.getenv("XRAY_DATABASE")
db_root_kwargs = {}
if database_dir is None or database is None:
db_root_kwargs['required'] = True
else:
db_root_kwargs['required'] = False
db_root_kwargs['default'] = os.path.join(database_dir, database)
parser.add_argument('--db-root', help="Database root.", **db_root_kwargs)
parser.add_argument(
'--sparse', action='store_true', help="Don't zero fill all frames")
parser.add_argument(
'--roi',
help="ROI design.json file defining which tiles are within the ROI.")
parser.add_argument(
'--emit_pudc_b_pullup',
help="Emit an IBUF and PULLUP on the PUDC_B pin if unused",
action='store_true')
parser.add_argument(
'--debug', action='store_true', help="Print debug dump")
parser.add_argument('fn_in', help='Input FPGA assembly (.fasm) file')
parser.add_argument(
'fn_out',
default='/dev/stdout',
nargs='?',
help='Output FPGA frame (.frm) file')
args = parser.parse_args()
run(
db_root=args.db_root,
filename_in=args.fn_in,
f_out=open(args.fn_out, 'w'),
sparse=args.sparse,
roi=args.roi,
debug=args.debug,
emit_pudc_b_pullup=args.emit_pudc_b_pullup)
if __name__ == '__main__':
main()