mirror of https://github.com/openXC7/prjxray.git
segprint2fasm -> bits2fasm
Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
parent
7998b77ee3
commit
e3cd270e16
|
|
@ -0,0 +1,241 @@
|
|||
#!/usr/bin/env python3
|
||||
'''
|
||||
Take raw .bits files and decode them to higher level functionality
|
||||
This output is intended for debugging and not directly related to FASM
|
||||
However, as of 2018-10-16, the output is being parsed to create FASM,
|
||||
so be mindful when changing output format
|
||||
|
||||
TODO:
|
||||
'''
|
||||
|
||||
import sys, os, json, re
|
||||
|
||||
|
||||
class NoDB(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def line(s=''):
|
||||
print(s)
|
||||
|
||||
|
||||
def comment(s):
|
||||
print('# %s' % s)
|
||||
|
||||
|
||||
# cache
|
||||
segbitsdb = dict()
|
||||
|
||||
|
||||
# TODO: migrate to library
|
||||
def get_database(segtype):
|
||||
if segtype in segbitsdb:
|
||||
return segbitsdb[segtype]
|
||||
|
||||
main_fn = "%s/%s/segbits_%s.db" % (
|
||||
os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"),
|
||||
segtype.lower())
|
||||
int_fn = "%s/%s/segbits_int_%s.db" % (
|
||||
os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"),
|
||||
segtype[-1].lower())
|
||||
|
||||
if not os.path.exists(main_fn) or not os.path.exists(int_fn):
|
||||
raise NoDB(segtype)
|
||||
|
||||
segbitsdb[segtype] = list()
|
||||
|
||||
with open(main_fn, "r") as f:
|
||||
for line in f:
|
||||
line = line.split()
|
||||
segbitsdb[segtype].append(line)
|
||||
|
||||
with open(int_fn, "r") as f:
|
||||
for line in f:
|
||||
line = line.split()
|
||||
segbitsdb[segtype].append(line)
|
||||
|
||||
return segbitsdb[segtype]
|
||||
|
||||
|
||||
def mk_segbits(seginfo, bitdata):
|
||||
baseframe = int(seginfo["baseaddr"][0], 16)
|
||||
basewordidx = int(seginfo["baseaddr"][1])
|
||||
numframes = int(seginfo["frames"])
|
||||
numwords = int(seginfo["words"])
|
||||
|
||||
segbits = set()
|
||||
for frame in range(baseframe, baseframe + numframes):
|
||||
if frame not in bitdata:
|
||||
continue
|
||||
for wordidx in range(basewordidx, basewordidx + numwords):
|
||||
if wordidx not in bitdata[frame]:
|
||||
continue
|
||||
for bitidx in bitdata[frame][wordidx]:
|
||||
segbits.add(
|
||||
"%02d_%02d" %
|
||||
(frame - baseframe, 32 * (wordidx - basewordidx) + bitidx))
|
||||
return segbits
|
||||
|
||||
|
||||
def tagmatch(entry, segbits):
|
||||
for bit in entry[1:]:
|
||||
if bit[0] != "!" and bit not in segbits:
|
||||
return False
|
||||
if bit[0] == "!" and bit[1:] in segbits:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def tag_matched(entry, segbits):
|
||||
for bit in entry[1:]:
|
||||
if bit[0] != "!":
|
||||
segbits.remove(bit)
|
||||
|
||||
|
||||
def seg_decode(seginfo, segbits):
|
||||
fasms = set()
|
||||
|
||||
try:
|
||||
for entry in get_database(seginfo["type"]):
|
||||
if not tagmatch(entry, segbits):
|
||||
continue
|
||||
tag_matched(entry, segbits)
|
||||
fasms.add('%s.%s 1' % (seginfo['tile_name'], entry[0]))
|
||||
except NoDB:
|
||||
print("WARNING: failed to load DB for %s" % seginfo["type"])
|
||||
return fasms
|
||||
|
||||
|
||||
def handle_segment(segname, grid, bitdata):
|
||||
|
||||
assert segname
|
||||
|
||||
# only print bitstream tiles
|
||||
if segname not in grid["segments"]:
|
||||
return
|
||||
seginfo = grid["segments"][segname]
|
||||
|
||||
segbits = mk_segbits(seginfo, bitdata)
|
||||
|
||||
fasms = seg_decode(seginfo, segbits)
|
||||
|
||||
# Found something to print?
|
||||
if len(segbits) == 0 and len(fasms) == 0:
|
||||
return
|
||||
|
||||
line('')
|
||||
comment("seg %s" % (segname, ))
|
||||
|
||||
for fasm in sorted(fasms):
|
||||
print(fasm)
|
||||
|
||||
if len(segbits) > 0:
|
||||
comment('WARNING: %u unknown bits' % len(segbits))
|
||||
for bit in sorted(segbits):
|
||||
comment("bit %s" % bit)
|
||||
|
||||
|
||||
def load_bitdata(bits_file):
|
||||
bitdata = dict()
|
||||
|
||||
with open(bits_file, "r") as f:
|
||||
for line in f:
|
||||
line = line.split("_")
|
||||
frame = int(line[1], 16)
|
||||
wordidx = int(line[2], 10)
|
||||
bitidx = int(line[3], 10)
|
||||
|
||||
if frame not in bitdata:
|
||||
bitdata[frame] = dict()
|
||||
|
||||
if wordidx not in bitdata[frame]:
|
||||
bitdata[frame][wordidx] = set()
|
||||
|
||||
bitdata[frame][wordidx].add(bitidx)
|
||||
return bitdata
|
||||
|
||||
|
||||
def mk_grid():
|
||||
'''Load tilegrid, flattening all blocks into one dictionary'''
|
||||
|
||||
with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"),
|
||||
os.getenv("XRAY_DATABASE")), "r") as f:
|
||||
new_grid = json.load(f)
|
||||
|
||||
# TODO: Migrate to new tilegrid format via library.
|
||||
grid = {'tiles': new_grid, 'segments': {}}
|
||||
|
||||
for tile_name, tile in grid['tiles'].items():
|
||||
bits = tile.get('bits', None)
|
||||
if not bits:
|
||||
continue
|
||||
for block_name, block in bits.items():
|
||||
segname = mksegment(tile_name, block_name)
|
||||
grid['segments'][segname] = {
|
||||
'baseaddr': [
|
||||
block['baseaddr'],
|
||||
block['offset'],
|
||||
],
|
||||
'type': tile['type'],
|
||||
'frames': block['frames'],
|
||||
'words': block['words'],
|
||||
'tile_name': tile_name,
|
||||
'block_name': block_name,
|
||||
}
|
||||
return grid
|
||||
|
||||
|
||||
def mksegment(tile_name, block_name):
|
||||
'''Create a segment name'''
|
||||
return '%s:%s' % (tile_name, block_name)
|
||||
|
||||
|
||||
def tile_segnames(grid):
|
||||
ret = []
|
||||
for tile_name, tile in grid['tiles'].items():
|
||||
for block_name in tile['bits'].keys():
|
||||
ret.append(mksegment(tile_name, block_name))
|
||||
return ret
|
||||
|
||||
|
||||
def run(bits_file, segnames, verbose=False):
|
||||
grid = mk_grid()
|
||||
|
||||
bitdata = load_bitdata(bits_file)
|
||||
|
||||
# Default: print all
|
||||
if segnames:
|
||||
for i, segname in enumerate(segnames):
|
||||
# Default to common tile config area if tile given without explicit block
|
||||
if ':' not in segname:
|
||||
segnames[i] = mksegment(segname, 'CLB_IO_CLK')
|
||||
else:
|
||||
segnames = sorted(tile_segnames(grid))
|
||||
|
||||
comment('Segments: %u' % len(segnames))
|
||||
|
||||
# XXX: previously this was sorted by address, not name
|
||||
# revisit?
|
||||
for segname in segnames:
|
||||
handle_segment(segname, grid, bitdata)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
# XXX: tool still works, but not well
|
||||
# need to eliminate segments entirely
|
||||
parser = argparse.ArgumentParser(
|
||||
description='XXX: does not print all data?')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('bits_file', help='')
|
||||
parser.add_argument(
|
||||
'segnames', nargs='*', help='List of tile or tile:block to print')
|
||||
args = parser.parse_args()
|
||||
|
||||
run(args.bits_file, args.segnames, verbose=args.verbose)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -4,6 +4,7 @@ while [ -h "$XRAY_ENV_PATH" ]; do # resolve $XRAY_ENV_PATH until the file is no
|
|||
XRAY_ENV_PATH="$(readlink "$XRAY_ENV_PATH")"
|
||||
[[ $XRAY_ENV_PATH != /* ]] && XRAY_ENV_PATH="$XRAY_UTILS_DIR/$XRAY_ENV_PATH" # if $XRAY_ENV_PATH was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
export PYTHONPATH="${XRAY_DIR}:$PYTHONPATH"
|
||||
export XRAY_UTILS_DIR="$( cd -P "$( dirname "$XRAY_ENV_PATH" )" && pwd )"
|
||||
|
||||
export XRAY_DIR="$( dirname "$XRAY_UTILS_DIR" )"
|
||||
|
|
@ -21,3 +22,6 @@ export XRAY_DBCHECK="bash ${XRAY_UTILS_DIR}/dbcheck.sh"
|
|||
export XRAY_MASKMERGE="bash ${XRAY_UTILS_DIR}/maskmerge.sh"
|
||||
export XRAY_SEGMATCH="${XRAY_TOOLS_DIR}/segmatch"
|
||||
export XRAY_SEGPRINT="python3 ${XRAY_UTILS_DIR}/segprint.py"
|
||||
export XRAY_BITS2FASM="python3 ${XRAY_UTILS_DIR}/bits2fasm.py"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class NoDB(Exception):
|
|||
segbitsdb = dict()
|
||||
|
||||
|
||||
# TODO: migrate to library
|
||||
def get_database(segtype):
|
||||
if segtype in segbitsdb:
|
||||
return segbitsdb[segtype]
|
||||
|
|
@ -134,23 +135,33 @@ def print_unknown_bits(grid, bitdata):
|
|||
print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx))
|
||||
|
||||
|
||||
def seg_decode(flag_decode_emit, seginfo, segbits, segtags):
|
||||
def tagmatch(entry, segbits):
|
||||
for bit in entry[1:]:
|
||||
if bit[0] != "!" and bit not in segbits:
|
||||
return False
|
||||
if bit[0] == "!" and bit[1:] in segbits:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def tag_matched(entry, segbits):
|
||||
for bit in entry[1:]:
|
||||
if bit[0] != "!":
|
||||
segbits.remove(bit)
|
||||
|
||||
|
||||
def seg_decode(flag_decode_emit, seginfo, segbits):
|
||||
segtags = set()
|
||||
try:
|
||||
for entry in get_database(seginfo["type"]):
|
||||
match_entry = True
|
||||
for bit in entry[1:]:
|
||||
if bit[0] != "!" and bit not in segbits:
|
||||
match_entry = False
|
||||
if bit[0] == "!" and bit[1:] in segbits:
|
||||
match_entry = False
|
||||
if match_entry:
|
||||
for bit in entry[1:]:
|
||||
if bit[0] != "!":
|
||||
segbits.remove(bit)
|
||||
if flag_decode_emit:
|
||||
segtags.add(entry[0])
|
||||
if not tagmatch(entry, segbits):
|
||||
continue
|
||||
tag_matched(entry, segbits)
|
||||
if flag_decode_emit:
|
||||
segtags.add(entry[0])
|
||||
except NoDB:
|
||||
print("WARNING: failed to load DB for %s" % seginfo["type"])
|
||||
return segtags
|
||||
|
||||
|
||||
def handle_segment(
|
||||
|
|
@ -177,16 +188,19 @@ def handle_segment(
|
|||
return
|
||||
seginfo = grid["segments"][segname]
|
||||
|
||||
segtags = set()
|
||||
segbits = mk_segbits(seginfo, bitdata)
|
||||
|
||||
if flag_decode_emit or flag_decode_omit:
|
||||
seg_decode(flag_decode_emit, seginfo, segbits, segtags)
|
||||
segtags = seg_decode(flag_decode_emit, seginfo, segbits)
|
||||
else:
|
||||
segtags = set()
|
||||
|
||||
# Found something to print?
|
||||
if not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0:
|
||||
print()
|
||||
print("seg %s" % (segname, ))
|
||||
if not (not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0):
|
||||
return
|
||||
|
||||
print()
|
||||
print("seg %s" % (segname, ))
|
||||
|
||||
for bit in sorted(segbits):
|
||||
print("bit %s" % bit)
|
||||
|
|
@ -315,10 +329,11 @@ def main():
|
|||
action='store_true',
|
||||
help='decode known segment bits and omit them in the output')
|
||||
parser.add_argument('bits_file', help='')
|
||||
parser.add_argument('tiles', nargs='*', help='')
|
||||
parser.add_argument(
|
||||
'segnames', nargs='*', help='List of tile or tile:block to print')
|
||||
args = parser.parse_args()
|
||||
|
||||
run(args.bits_file, args.tiles, args.z, args.b, args.d, args.D)
|
||||
run(args.bits_file, args.segnames, args.z, args.b, args.d, args.D)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
|
||||
enumdb = dict()
|
||||
|
||||
|
||||
def get_enums(segtype):
|
||||
if segtype in enumdb:
|
||||
return enumdb[segtype]
|
||||
|
||||
enumdb[segtype] = {}
|
||||
|
||||
def process(l):
|
||||
l = l.strip()
|
||||
|
||||
# CLBLM_L.SLICEL_X1.ALUT.INIT[10] 29_14
|
||||
parts = line.split()
|
||||
name = parts[0]
|
||||
bit_vals = parts[1:]
|
||||
|
||||
# Assumption
|
||||
# only 1 bit => non-enumerated value
|
||||
enumdb[segtype][name] = len(bit_vals) != 1
|
||||
|
||||
with open("%s/%s/segbits_%s.db" % (os.getenv("XRAY_DATABASE_DIR"),
|
||||
os.getenv("XRAY_DATABASE"), segtype),
|
||||
"r") as f:
|
||||
for line in f:
|
||||
process(line)
|
||||
|
||||
with open("%s/%s/segbits_int_%s.db" %
|
||||
(os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"),
|
||||
segtype[-1]), "r") as f:
|
||||
for line in f:
|
||||
process(line)
|
||||
|
||||
return enumdb[segtype]
|
||||
|
||||
|
||||
def isenum(segtype, tag):
|
||||
return get_enums(segtype)[tag]
|
||||
|
||||
|
||||
def tag2fasm(grid, seg, tag):
|
||||
'''Given tilegrid, segment name and tag, return fasm directive'''
|
||||
segj = grid['segments'][seg]
|
||||
|
||||
m = re.match(r'([A-Za-z0-9_]+)[.](.*)', tag)
|
||||
tile_type = m.group(1)
|
||||
tag_post = m.group(2)
|
||||
|
||||
# Find associated tile
|
||||
for tile in segj['tiles']:
|
||||
if grid['tiles'][tile]['type'] == tile_type:
|
||||
break
|
||||
else:
|
||||
raise Exception("Couldn't find tile type %s" % tile_type)
|
||||
|
||||
if not isenum(segj['type'], tag):
|
||||
return '%s.%s 1' % (tile, tag_post)
|
||||
else:
|
||||
# Make the selection an argument of the configruation
|
||||
m = re.match(r'(.*)[.]([A-Za-z0-9_]+)', tag_post)
|
||||
which = m.group(1)
|
||||
value = m.group(2)
|
||||
return '%s.%s %s' % (tile, which, value)
|
||||
|
||||
|
||||
def run(f_in, f_out, sparse=False):
|
||||
with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"),
|
||||
os.getenv("XRAY_DATABASE")), "r") as f:
|
||||
new_grid = json.load(f)
|
||||
|
||||
# TODO: Migrate to new tilegrid format via library.
|
||||
grid = {'tiles': new_grid, 'segments': {}}
|
||||
|
||||
for tilename, tile in grid['tiles'].items():
|
||||
if 'segment' in tile:
|
||||
segment = tile['segment']
|
||||
|
||||
if segment not in grid['segments']:
|
||||
grid['segments'][segment] = {
|
||||
'baseaddr': (
|
||||
tile['baseaddr'],
|
||||
tile['offset'],
|
||||
),
|
||||
'type': tile['segment_type'],
|
||||
'frames': tile['frames'],
|
||||
'words': tile['words'],
|
||||
'tiles': [tilename]
|
||||
}
|
||||
else:
|
||||
assert grid['segments'][segment]['baseaddr'] == (
|
||||
tile['baseaddr'],
|
||||
tile['offset'],
|
||||
)
|
||||
assert grid['segments'][segment]['type'] == tile[
|
||||
'segment_type']
|
||||
assert grid['segments'][segment]['frames'] == tile['frames']
|
||||
assert grid['segments'][segment]['words'] == tile['words']
|
||||
|
||||
grid['segments'][segment]['tiles'].append(tilename)
|
||||
|
||||
seg = None
|
||||
for l in f_in:
|
||||
l = l.strip()
|
||||
if not l:
|
||||
continue
|
||||
# seg SEG_CLBLM_L_X10Y102
|
||||
# tag CLBLM_L.SLICEM_X0.ALUT.INIT[00]
|
||||
m = re.match('(seg|tag) (.*)', l)
|
||||
if not m:
|
||||
raise Exception("Invalid line %s" % l)
|
||||
type = m.group(1)
|
||||
if type == 'seg':
|
||||
seg = m.group(2)
|
||||
elif type == 'tag':
|
||||
f_out.write(tag2fasm(grid, seg, m.group(2)) + '\n')
|
||||
else:
|
||||
raise Exception("Invalid type %s" % type)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Convert segprint -d output to .fasm file (FPGA assembly)')
|
||||
|
||||
parser.add_argument(
|
||||
'fn_in', default='/dev/stdin', nargs='?', help='Input segment file')
|
||||
parser.add_argument(
|
||||
'fn_out', default='/dev/stdout', nargs='?', help='Output .fasm file')
|
||||
|
||||
args = parser.parse_args()
|
||||
run(open(args.fn_in, 'r'), open(args.fn_out, 'w'))
|
||||
Loading…
Reference in New Issue