From c8ee9d4f1645adcc8d63f3c671cdd9d475f56474 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 23:39:41 -0700 Subject: [PATCH] fasm2bits: working Signed-off-by: John McMaster --- utils/environment.sh | 1 + utils/fasm2bits.py | 260 +++++++++++++++++++++++++------------------ 2 files changed, 153 insertions(+), 108 deletions(-) diff --git a/utils/environment.sh b/utils/environment.sh index b90cc09a..62cf4019 100644 --- a/utils/environment.sh +++ b/utils/environment.sh @@ -23,5 +23,6 @@ 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" +export XRAY_FASM2BITS="python3 ${XRAY_UTILS_DIR}/fasm2bits.py" diff --git a/utils/fasm2bits.py b/utils/fasm2bits.py index cf84e557..6744f7a7 100755 --- a/utils/fasm2bits.py +++ b/utils/fasm2bits.py @@ -37,11 +37,11 @@ Maybe better to return as two distinct dictionaries? segbitsdb = dict() -def get_database(segtype): - if segtype in segbitsdb: - return segbitsdb[segtype] +def get_database(tile_type): + if tile_type in segbitsdb: + return segbitsdb[tile_type] - segbitsdb[segtype] = {} + segbitsdb[tile_type] = {} def process(l): l = l.strip() @@ -59,7 +59,7 @@ def get_database(segtype): raise Exception( "Expect single bit DB entries to be set, got %s" % l) # Treat like an enumerated value with keys 0 or 1 - segbitsdb[segtype][name] = { + segbitsdb[tile_type][name] = { '0': [(seg_word_column, word_bit_n, 0)], '1': [(seg_word_column, word_bit_n, 1)], } @@ -71,22 +71,28 @@ def get_database(segtype): key = m.group(2) # May or may not be the first key encountered - bits_map = segbitsdb[segtype].setdefault(name, {}) + bits_map = segbitsdb[tile_type].setdefault(name, {}) bits_map[key] = [parsebit(x) for x in bit_vals] - with open("%s/%s/segbits_%s.db" % (os.getenv("XRAY_DATABASE_DIR"), - os.getenv("XRAY_DATABASE"), segtype), - "r") as f: + main_fn = "%s/%s/segbits_%s.db" % ( + os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), + tile_type.lower()) + int_fn = "%s/%s/segbits_int_%s.db" % ( + os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), + tile_type[-1].lower()) + + if not os.path.exists(main_fn) or not os.path.exists(int_fn): + raise Exception(tile_type) + + with open(main_fn, "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: + with open(int_fn, "r") as f: for line in f: process(line) - return segbitsdb[segtype] + return segbitsdb[tile_type] def dump_frames_verbose(frames): @@ -126,34 +132,13 @@ def dump_frm(f, frames): '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 = {} - # Directives we've seen so far - # Complain if there is a duplicate - # Contains line number of last entry - used_names = {} +def mksegment(tile_name, block_name): + '''Create a segment name''' + return '%s:%s' % (tile_name, block_name) - 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 - - def frame_clear(frame_addr, word_addr, bit_index): - '''Set given bit in given frame address and word''' - frames[frame_addr][word_addr] &= 0xFFFFFFFF ^ (1 << bit_index) +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: @@ -162,80 +147,124 @@ def run(f_in, f_out, sparse=False, debug=False): # TODO: Migrate to new tilegrid format via library. grid = {'tiles': new_grid, 'segments': {}} - for tile in grid['tiles'].values(): - if 'segment' in tile: - segment = tile['segment'] - grid['segments'][segment] = { + for tile_name, tile in grid['tiles'].items(): + for block_name, block in tile['bits'].items(): + segname = mksegment(tile_name, block_name) + grid['segments'][segname] = { 'baseaddr': [ - tile['baseaddr'], - tile['offset'], + block['baseaddr'], + block['offset'], ], - 'type': tile['segment_type'], - 'frames': tile['frames'], - 'words': tile['words'], + 'type': tile['type'], + 'frames': block['frames'], + 'words': block['words'], + 'tile_name': tile_name, + 'block_name': block_name, } + return grid - if not sparse: - # Initiaize bitstream to 0 - frames_init() +def frame_init(frames, addr): + '''Set given frame to 0''' + if not addr in frames: + frames[addr] = [0 for _i in range(101)] - for line_number, l in enumerate(f_in, 1): - # 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 - # Optional value - m = re.match(r'([a-zA-Z0-9_]+)[.]([a-zA-Z0-9_.\[\]]+)([ ](.+))?', l) - if not m: - raise FASMSyntaxError("Bad line: %s" % l) - tile = m.group(1) - name = m.group(2) - value = m.group(4) - - used_name = (tile, name) - old_line_number = used_names.get(used_name, None) - if old_line_number: - raise FASMSyntaxError( - "Duplicate name lines %d and %d, second line: %s" % - (old_line_number, line_number, l)) - used_names[used_name] = line_number - - tilej = grid['tiles'][tile] - seg = tilej['segment'] - segj = grid['segments'][seg] +def frames_init(frames, grid): + '''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(frames, seg_baseaddr + coli) +def frame_set(frames, frame_addr, word_addr, bit_index): + '''Set given bit in given frame address and word''' + frames[frame_addr][word_addr] |= 1 << bit_index + +def frame_clear(frames, frame_addr, word_addr, bit_index): + '''Set given bit in given frame address and word''' + frames[frame_addr][word_addr] &= 0xFFFFFFFF ^ (1 << bit_index) + + +def parse_line(l): + # 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: + return + + # tile.site.stuff value + # INT_L_X10Y102.CENTER_INTER_L.IMUX_L1 EE2END0 + # Optional value + m = re.match(r'([a-zA-Z0-9_]+)[.]([a-zA-Z0-9_.\[\]]+)([ ](.+))?', l) + if not m: + raise FASMSyntaxError("Bad line: %s" % l) + tile = m.group(1) + name = m.group(2) + value = m.group(4) + + return tile, name, value + +def check_duplicate(used_names, tile, name, l, line_number): + '''Throw an exception if a conflicting FASM directive was given''' + used_name = (tile, name) + old_line_number = used_names.get(used_name, None) + if old_line_number: + raise FASMSyntaxError( + "Duplicate name lines %d and %d, second line: %s" % + (old_line_number, line_number, l)) + used_names[used_name] = line_number + +def update_segbit(frames, seg_word_column, word_bit_n, isset, seg_baseaddr, seg_word_base): + '''Set or clear a single bit in a segment at the given word column and word bit position''' + # 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 + if isset: + frame_set(frames, frame_addr, word_addr, bit_index) + else: + frame_clear(frames, frame_addr, word_addr, bit_index) + +def default_value(db_vals, name): + # If its binary, allow omitted value default to 1 + if tuple(sorted(db_vals.keys())) == ('0', '1'): + return '1' + else: + raise FASMSyntaxError( + "Enumerable entry %s must have explicit value" % name) + + +def process_line(line_number, l, grid, frames, used_names): + parsed = parse_line(l) + # empty line + if not parsed: + return + tile_name, name, value = parsed + check_duplicate(used_names, tile_name, name, l, line_number) + + tilej = grid['tiles'][tile_name] + for block_name, block in tilej['bits'].items(): + segname = mksegment(tile_name, block_name) + + segj = grid['segments'][segname] + 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) - - def update_segbit(seg_word_column, word_bit_n, isset): - '''Set or clear a single bit in a segment at the given word column and word bit position''' - # 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 - if isset: - frame_set(frame_addr, word_addr, bit_index) - else: - frame_clear(frame_addr, word_addr, bit_index) - + frame_init(frames, seg_baseaddr + coli) + # Now lets look up the bits we need frames for segdb = get_database(segj['type']) - + db_k = '%s.%s' % (tilej['type'], name) try: db_vals = segdb[db_k] @@ -243,14 +272,10 @@ def run(f_in, f_out, sparse=False, debug=False): raise FASMSyntaxError( "Segment DB %s, key %s not found from line '%s'" % (segj['type'], db_k, l)) from None - + if not value: - # If its binary, allow omitted value default to 1 - if tuple(sorted(db_vals.keys())) == ('0', '1'): - value = '1' - else: - raise FASMSyntaxError( - "Enumerable entry %s must have explicit value" % name) + value = default_value(db_vals, name) + # Get the specific entry we need try: db_vals = db_vals[value] @@ -258,8 +283,27 @@ def run(f_in, f_out, sparse=False, debug=False): raise FASMSyntaxError( "Invalid entry %s. Valid entries are %s" % (value, db_vals.keys())) + for seg_word_column, word_bit_n, isset in db_vals: - update_segbit(seg_word_column, word_bit_n, isset) + update_segbit(frames, seg_word_column, word_bit_n, isset, seg_baseaddr, seg_word_base) + + +def run(f_in, f_out, sparse=False, debug=False): + # address to array of 101 32 bit words + frames = {} + # Directives we've seen so far + # Complain if there is a duplicate + # Contains line number of last entry + used_names = {} + + grid = mk_grid() + + if not sparse: + # Initiaize bitstream to 0 + frames_init(frames, grid) + + for line_number, l in enumerate(f_in, 1): + process_line(line_number, l, grid, frames, used_names) if debug: #dump_frames_verbose(frames)