#!/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)