mirror of https://github.com/openXC7/prjxray.git
Merge pull request #650 from litghost/add_fasm_features_to_harness
Add required FASM features to harness
This commit is contained in:
commit
7f7c3bb564
|
|
@ -2,6 +2,7 @@ import json
|
||||||
import csv
|
import csv
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
import fasm
|
||||||
from prjxray.db import Database
|
from prjxray.db import Database
|
||||||
from prjxray.roi import Roi
|
from prjxray.roi import Roi
|
||||||
from prjxray.util import get_db_root
|
from prjxray.util import get_db_root
|
||||||
|
|
@ -24,31 +25,32 @@ def main():
|
||||||
parser.add_argument('--design_txt', required=True)
|
parser.add_argument('--design_txt', required=True)
|
||||||
parser.add_argument('--design_info_txt', required=True)
|
parser.add_argument('--design_info_txt', required=True)
|
||||||
parser.add_argument('--pad_wires', required=True)
|
parser.add_argument('--pad_wires', required=True)
|
||||||
|
parser.add_argument('--design_fasm', required=True)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
j = {}
|
design_json = {}
|
||||||
j['ports'] = []
|
design_json['ports'] = []
|
||||||
j['info'] = {}
|
design_json['info'] = {}
|
||||||
with open(args.design_txt) as f:
|
with open(args.design_txt) as f:
|
||||||
for d in csv.DictReader(f, delimiter=' '):
|
for d in csv.DictReader(f, delimiter=' '):
|
||||||
j['ports'].append(d)
|
design_json['ports'].append(d)
|
||||||
|
|
||||||
with open(args.design_info_txt) as f:
|
with open(args.design_info_txt) as f:
|
||||||
for l in f:
|
for l in f:
|
||||||
name, value = l.strip().split(' = ')
|
name, value = l.strip().split(' = ')
|
||||||
|
|
||||||
j['info'][name] = int(value)
|
design_json['info'][name] = int(value)
|
||||||
|
|
||||||
db = Database(get_db_root())
|
db = Database(get_db_root())
|
||||||
grid = db.grid()
|
grid = db.grid()
|
||||||
|
|
||||||
roi = Roi(
|
roi = Roi(
|
||||||
db=db,
|
db=db,
|
||||||
x1=j['info']['GRID_X_MIN'],
|
x1=design_json['info']['GRID_X_MIN'],
|
||||||
y1=j['info']['GRID_Y_MIN'],
|
y1=design_json['info']['GRID_Y_MIN'],
|
||||||
x2=j['info']['GRID_X_MAX'],
|
x2=design_json['info']['GRID_X_MAX'],
|
||||||
y2=j['info']['GRID_Y_MAX'],
|
y2=design_json['info']['GRID_Y_MAX'],
|
||||||
)
|
)
|
||||||
|
|
||||||
with open(args.pad_wires) as f:
|
with open(args.pad_wires) as f:
|
||||||
|
|
@ -68,9 +70,49 @@ def main():
|
||||||
if not roi.tile_in_roi(loc):
|
if not roi.tile_in_roi(loc):
|
||||||
wires_outside_roi.append(wire)
|
wires_outside_roi.append(wire)
|
||||||
|
|
||||||
set_port_wires(j['ports'], name, pin, wires_outside_roi)
|
set_port_wires(design_json['ports'], name, pin, wires_outside_roi)
|
||||||
|
|
||||||
json.dump(j, sys.stdout, indent=2, sort_keys=True)
|
frames_in_use = set()
|
||||||
|
for tile in roi.gen_tiles():
|
||||||
|
gridinfo = grid.gridinfo_at_tilename(tile)
|
||||||
|
|
||||||
|
for bit in gridinfo.bits.values():
|
||||||
|
frames_in_use.add(bit.base_address)
|
||||||
|
|
||||||
|
required_features = []
|
||||||
|
for fasm_line in fasm.parse_fasm_filename(args.design_fasm):
|
||||||
|
if fasm_line.annotations:
|
||||||
|
for annotation in fasm_line.annotations:
|
||||||
|
if annotation.name != 'unknown_segment':
|
||||||
|
continue
|
||||||
|
|
||||||
|
unknown_base_address = int(annotation.value, 0)
|
||||||
|
|
||||||
|
assert unknown_base_address not in frames_in_use, "Found unknown bit in base address 0x{:08x}".format(
|
||||||
|
unknown_base_address)
|
||||||
|
|
||||||
|
if not fasm_line.set_feature:
|
||||||
|
continue
|
||||||
|
|
||||||
|
tile = fasm_line.set_feature.feature.split('.')[0]
|
||||||
|
|
||||||
|
loc = grid.loc_of_tilename(tile)
|
||||||
|
gridinfo = grid.gridinfo_at_tilename(tile)
|
||||||
|
|
||||||
|
base_address_in_roi = False
|
||||||
|
for bit in gridinfo.bits.values():
|
||||||
|
if bit.base_address in frames_in_use:
|
||||||
|
base_address_in_roi = True
|
||||||
|
|
||||||
|
not_in_roi = not roi.tile_in_roi(loc)
|
||||||
|
|
||||||
|
if not_in_roi and base_address_in_roi:
|
||||||
|
required_features.append(fasm_line)
|
||||||
|
|
||||||
|
design_json['required_features'] = fasm.fasm_tuple_to_string(
|
||||||
|
required_features, canonical=True)
|
||||||
|
|
||||||
|
json.dump(design_json, sys.stdout, indent=2, sort_keys=True)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,13 @@ ${XRAY_VIVADO} -mode batch -source ../runme.tcl
|
||||||
test -z "$(fgrep CRITICAL vivado.log)"
|
test -z "$(fgrep CRITICAL vivado.log)"
|
||||||
|
|
||||||
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o design.bits -z -y design.bit
|
${XRAY_BITREAD} -F $XRAY_ROI_FRAMES -o design.bits -z -y design.bit
|
||||||
${XRAY_SEGPRINT} -zd design.bits >design.segp
|
|
||||||
python3 ${XRAY_DIR}/utils/bit2fasm.py --verbose design.bit > design.fasm
|
python3 ${XRAY_DIR}/utils/bit2fasm.py --verbose design.bit > design.fasm
|
||||||
python3 ${XRAY_DIR}/utils/fasm2frames.py design.fasm design.frm
|
python3 ${XRAY_DIR}/utils/fasm2frames.py design.fasm design.frm
|
||||||
python3 ../create_design_json.py --design_info_txt design_info.txt --design_txt design.txt --pad_wires design_pad_wires.txt > design.json
|
python3 ../create_design_json.py \
|
||||||
|
--design_info_txt design_info.txt \
|
||||||
|
--design_txt design.txt \
|
||||||
|
--pad_wires design_pad_wires.txt \
|
||||||
|
--design_fasm design.fasm > design.json
|
||||||
|
|
||||||
# Hack to get around weird clock error related to clk net not found
|
# Hack to get around weird clock error related to clk net not found
|
||||||
# Remove following lines:
|
# Remove following lines:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import fasm
|
import fasm
|
||||||
from prjxray import bitstream
|
from prjxray import bitstream
|
||||||
from prjxray import grid
|
|
||||||
|
|
||||||
|
|
||||||
class FasmLookupError(Exception):
|
class FasmLookupError(Exception):
|
||||||
|
|
@ -142,34 +141,50 @@ class FasmAssembler(object):
|
||||||
bits.base_address + bits.frames):
|
bits.base_address + bits.frames):
|
||||||
self.frames_in_use.add(frame)
|
self.frames_in_use.add(frame)
|
||||||
|
|
||||||
def parse_fasm_filename(self, filename):
|
def add_fasm_line(self, line, missing_features):
|
||||||
|
if not line.set_feature:
|
||||||
|
return
|
||||||
|
|
||||||
|
line_strs = tuple(fasm.fasm_line_to_string(line))
|
||||||
|
assert len(line_strs) == 1
|
||||||
|
line_str = line_strs[0]
|
||||||
|
|
||||||
|
parts = line.set_feature.feature.split('.')
|
||||||
|
tile = parts[0]
|
||||||
|
feature = '.'.join(parts[1:])
|
||||||
|
|
||||||
|
# canonical_features flattens multibit feature enables to only
|
||||||
|
# single bit features, which is what enable_feature expects.
|
||||||
|
#
|
||||||
|
# canonical_features also filters out features that are not enabled,
|
||||||
|
# which are no-ops.
|
||||||
|
for flat_set_feature in fasm.canonical_features(line.set_feature):
|
||||||
|
address = 0
|
||||||
|
if flat_set_feature.start is not None:
|
||||||
|
address = flat_set_feature.start
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.enable_feature(tile, feature, address, line_str)
|
||||||
|
except FasmLookupError as e:
|
||||||
|
missing_features.append(str(e))
|
||||||
|
|
||||||
|
def parse_fasm_filename(self, filename, extra_features=[]):
|
||||||
missing_features = []
|
missing_features = []
|
||||||
for line in fasm.parse_fasm_filename(filename):
|
for line in fasm.parse_fasm_filename(filename):
|
||||||
if not line.set_feature:
|
self.add_fasm_line(line, missing_features)
|
||||||
continue
|
|
||||||
|
|
||||||
line_strs = tuple(fasm.fasm_line_to_string(line))
|
for line in extra_features:
|
||||||
assert len(line_strs) == 1
|
self.add_fasm_line(line, missing_features)
|
||||||
line_str = line_strs[0]
|
|
||||||
|
|
||||||
parts = line.set_feature.feature.split('.')
|
|
||||||
tile = parts[0]
|
|
||||||
feature = '.'.join(parts[1:])
|
|
||||||
|
|
||||||
# canonical_features flattens multibit feature enables to only
|
|
||||||
# single bit features, which is what enable_feature expects.
|
|
||||||
#
|
|
||||||
# canonical_features also filters out features that are not enabled,
|
|
||||||
# which are no-ops.
|
|
||||||
for flat_set_feature in fasm.canonical_features(line.set_feature):
|
|
||||||
address = 0
|
|
||||||
if flat_set_feature.start is not None:
|
|
||||||
address = flat_set_feature.start
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.enable_feature(tile, feature, address, line_str)
|
|
||||||
except FasmLookupError as e:
|
|
||||||
missing_features.append(str(e))
|
|
||||||
|
|
||||||
if missing_features:
|
if missing_features:
|
||||||
raise FasmLookupError('\n'.join(missing_features))
|
raise FasmLookupError('\n'.join(missing_features))
|
||||||
|
|
||||||
|
def mark_roi_frames(self, roi):
|
||||||
|
for tile in roi.gen_tiles():
|
||||||
|
gridinfo = self.grid.gridinfo_at_tilename(tile)
|
||||||
|
|
||||||
|
for block_type in gridinfo.bits:
|
||||||
|
bits = gridinfo.bits[block_type]
|
||||||
|
for frame in range(bits.base_address,
|
||||||
|
bits.base_address + bits.frames):
|
||||||
|
self.frames_in_use.add(frame)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export XRAY_ROI_TILEGRID="SLICE_X0Y0:SLICE_X65Y99 SLICE_X0Y100:SLICE_X57Y149 RAM
|
||||||
# These settings must remain in sync
|
# These settings must remain in sync
|
||||||
export XRAY_ROI="SLICE_X0Y100:SLICE_X35Y149 RAMB18_X0Y40:RAMB18_X0Y59 RAMB36_X0Y20:RAMB36_X0Y29 DSP48_X0Y40:DSP48_X0Y59 IOB_X0Y100:IOB_X0Y149"
|
export XRAY_ROI="SLICE_X0Y100:SLICE_X35Y149 RAMB18_X0Y40:RAMB18_X0Y59 RAMB36_X0Y20:RAMB36_X0Y29 DSP48_X0Y40:DSP48_X0Y59 IOB_X0Y100:IOB_X0Y149"
|
||||||
# Most of CMT X0Y2.
|
# Most of CMT X0Y2.
|
||||||
export XRAY_ROI_GRID_X1="0"
|
export XRAY_ROI_GRID_X1="10"
|
||||||
export XRAY_ROI_GRID_X2="58"
|
export XRAY_ROI_GRID_X2="58"
|
||||||
# Include VBRK / VTERM
|
# Include VBRK / VTERM
|
||||||
export XRAY_ROI_GRID_Y1="0"
|
export XRAY_ROI_GRID_Y1="0"
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,15 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import fasm
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from prjxray import fasm_assembler
|
from prjxray import fasm_assembler
|
||||||
from prjxray import db
|
from prjxray.db import Database
|
||||||
|
from prjxray.roi import Roi
|
||||||
|
|
||||||
|
|
||||||
class FASMSyntaxError(SyntaxError):
|
class FASMSyntaxError(SyntaxError):
|
||||||
|
|
@ -51,9 +54,25 @@ def dump_frm(f, frames):
|
||||||
'0x%08X ' % addr + ','.join(['0x%08X' % w for w in words]) + '\n')
|
'0x%08X ' % addr + ','.join(['0x%08X' % w for w in words]) + '\n')
|
||||||
|
|
||||||
|
|
||||||
def run(db_root, filename_in, f_out, sparse=False, debug=False):
|
def run(db_root, filename_in, f_out, sparse=False, roi=None, debug=False):
|
||||||
assembler = fasm_assembler.FasmAssembler(db.Database(db_root))
|
db = Database(db_root)
|
||||||
assembler.parse_fasm_filename(filename_in)
|
assembler = fasm_assembler.FasmAssembler(db)
|
||||||
|
|
||||||
|
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(roi_j['required_features'])
|
||||||
|
|
||||||
|
assembler.parse_fasm_filename(filename_in, extra_features=extra_features)
|
||||||
frames = assembler.get_frames(sparse=sparse)
|
frames = assembler.get_frames(sparse=sparse)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -80,6 +99,9 @@ def main():
|
||||||
parser.add_argument('--db-root', help="Database root.", **db_root_kwargs)
|
parser.add_argument('--db-root', help="Database root.", **db_root_kwargs)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--sparse', action='store_true', help="Don't zero fill all frames")
|
'--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(
|
parser.add_argument(
|
||||||
'--debug', action='store_true', help="Print debug dump")
|
'--debug', action='store_true', help="Print debug dump")
|
||||||
parser.add_argument('fn_in', help='Input FPGA assembly (.fasm) file')
|
parser.add_argument('fn_in', help='Input FPGA assembly (.fasm) file')
|
||||||
|
|
@ -95,6 +117,7 @@ def main():
|
||||||
filename_in=args.fn_in,
|
filename_in=args.fn_in,
|
||||||
f_out=open(args.fn_out, 'w'),
|
f_out=open(args.fn_out, 'w'),
|
||||||
sparse=args.sparse,
|
sparse=args.sparse,
|
||||||
|
roi=args.roi,
|
||||||
debug=args.debug)
|
debug=args.debug)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ def get_database(db, tile_type, bit_only=False, verbose=False):
|
||||||
parts = l.split()
|
parts = l.split()
|
||||||
name = parts[0]
|
name = parts[0]
|
||||||
|
|
||||||
if parts[1] == 'always' or parts[1] == 'hint':
|
if parts[1] == 'always' or parts[1] == 'hint' or parts[1] == 'default':
|
||||||
if bit_only:
|
if bit_only:
|
||||||
return
|
return
|
||||||
tagbits = []
|
tagbits = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue