Merge pull request #650 from litghost/add_fasm_features_to_harness

Add required FASM features to harness
This commit is contained in:
litghost 2019-02-14 08:29:00 -08:00 committed by GitHub
commit 7f7c3bb564
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 45 deletions

View File

@ -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__':

View File

@ -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:

View File

@ -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)

View File

@ -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"

View File

@ -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)

View File

@ -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 = []