prjxray/tools/fasm2frame.py

227 lines
6.6 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
import os
import re
import sys
import json
# Based on segprint function
# Modified to return dict instead of list
segbitsdb = dict()
def get_database(segtype):
if segtype in segbitsdb:
return segbitsdb[segtype]
segbitsdb[segtype] = {}
with open("%s/%s/segbits_%s.db" % (os.getenv("XRAY_DATABASE_DIR"),
os.getenv("XRAY_DATABASE"), segtype),
"r") as f:
for line in f:
# CLBLM_L.SLICEL_X1.ALUT.INIT[10] 29_14
parts = line.split()
name = parts[0]
vals = parts[1:]
segbitsdb[segtype][name] = vals
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:
# CLBLM_L.SLICEL_X1.ALUT.INIT[10] 29_14
parts = line.split()
name = parts[0]
vals = parts[1:]
segbitsdb[segtype][name] = vals
return segbitsdb[segtype]
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 run(f_in, f_out, sparse=False, debug=False):
# address to array of 101 32 bit words
frames = {}
def frames_init():
'''Set all frames to 0'''
for segj in grid['segments'].values():
seg_baseaddr, seg_word_base = segj['baseaddr']
seg_baseaddr = int(seg_baseaddr, 0)
for coli in range(segj['frames']):
frame_init(seg_baseaddr + coli)
def frame_init(addr):
'''Set given frame to 0'''
if not addr in frames:
frames[addr] = [0 for _i in range(101)]
def frame_set(frame_addr, word_addr, bit_index):
'''Set given bit in given frame address and word'''
frames[frame_addr][word_addr] |= 1 << bit_index
with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"),
os.getenv("XRAY_DATABASE")), "r") as f:
grid = json.load(f)
if not sparse:
# Initiaize bitstream to 0
frames_init()
for l in f_in:
# Comment
# Remove all text including and after #
i = l.rfind('#')
if i >= 0:
l = l[0:i]
l = l.strip()
# Ignore blank lines
if not l:
continue
# tile.site.stuff value
# INT_L_X10Y102.CENTER_INTER_L.IMUX_L1 EE2END0
m = re.match(
r'([a-zA-Z0-9_]+)[.]([a-zA-Z0-9_]+)[.]([a-zA-Z0-9_.\[\]]+)[ ](.+)',
l)
if not m:
raise Exception("Bad line: %s" % l)
tile = m.group(1)
site = m.group(2)
suffix = m.group(3)
value = m.group(4)
tilej = grid['tiles'][tile]
seg = tilej['segment']
segj = grid['segments'][seg]
seg_baseaddr, seg_word_base = segj['baseaddr']
seg_baseaddr = int(seg_baseaddr, 0)
# Ensure that all frames exist for this segment
# FIXME: type dependent
for coli in range(segj['frames']):
frame_init(seg_baseaddr + coli)
# Now lets look up the bits we need frames for
segdb = get_database(segj['type'])
def clb2dbkey(tile, tilej, site, suffix, value):
db_k = '%s.%s.%s' % (tilej['type'], site, suffix)
return db_k
def int2dbkey(tile, tilej, site, suffix, value):
return '%s.%s.%s' % (tilej['type'], suffix, value)
tile2dbkey = {
'CLBLL_L': clb2dbkey,
'CLBLL_R': clb2dbkey,
'CLBLM_L': clb2dbkey,
'CLBLM_R': clb2dbkey,
'INT_L': int2dbkey,
'INT_R': int2dbkey,
'HCLK_L': int2dbkey,
'HCLK_R': int2dbkey,
}
f = tile2dbkey.get(tilej['type'], None)
if f is None:
raise Exception("Unhandled segment type %s" % tilej['type'])
db_k = f(tile, tilej, site, suffix, value)
try:
db_vals = segdb[db_k]
except KeyError:
raise Exception(
"Key %s (from line '%s') not found in segment DB %s" %
(db_k, l, segj['type']))
for val in db_vals:
# Default is 0. Skip explicit call outs
if val[0] == '!':
continue
# 28_05 => 28, 05
seg_word_column, word_bit_n = val.split('_')
seg_word_column, word_bit_n = int(seg_word_column), int(word_bit_n)
# Now we have the word column and word bit index
# Combine with the segments relative frame position to fully get the position
frame_addr = seg_baseaddr + seg_word_column
# 2 words per segment
word_addr = seg_word_base + word_bit_n // 32
bit_index = word_bit_n % 32
frame_set(frame_addr, word_addr, bit_index)
if debug:
#dump_frames_verbose(frames)
dump_frames_sparse(frames)
dump_frm(f_out, frames)
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(
description=
'Convert FPGA configuration description ("FPGA assembly") into binary frame equivalent'
)
parser.add_argument(
'--sparse', action='store_true', help="Don't zero fill all frames")
parser.add_argument(
'--debug', action='store_true', help="Print debug dump")
parser.add_argument(
'fn_in',
default='/dev/stdin',
nargs='?',
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(
open(args.fn_in, 'r'),
open(args.fn_out, 'w'),
sparse=args.sparse,
debug=args.debug)