From 209e59f9a94a6c02aab9dc6dfc77f13903d0f70e Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 11:21:49 -0700 Subject: [PATCH 01/42] tilegrid: database["segments"] => segments Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 147 +++++++++++++++---------------- 1 file changed, 73 insertions(+), 74 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 59e83346..fb5e5487 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -24,8 +24,8 @@ for arg in sys.argv[1:]: # Create initial database database = dict() -database["tiles"] = dict() -database["segments"] = dict() +database = dict() +segments = dict() tiles_by_grid = dict() for record in tiles: @@ -34,7 +34,7 @@ for record in tiles: tiles_by_grid[(grid_x, grid_y)] = tile_name framebaseaddr = None - database["tiles"][tile_name] = { + database[tile_name] = { "type": tile_type, "sites": dict(), "grid_x": grid_x, @@ -46,7 +46,7 @@ for record in tiles: site_type, site_name = record[i:i + 2] if site_name in site_baseaddr: framebaseaddr = site_baseaddr[site_name] - database["tiles"][tile_name]["sites"][site_name] = site_type + database[tile_name]["sites"][site_name] = site_type if framebaseaddr is not None: tile_baseaddr[tile_name] = [framebaseaddr, 0] @@ -54,7 +54,7 @@ for record in tiles: ####################################### # Add Segments -for tile_name, tile_data in database["tiles"].items(): +for tile_name, tile_data in database.items(): tile_type = tile_data["type"] grid_x = tile_data["grid_x"] grid_y = tile_data["grid_y"] @@ -68,31 +68,31 @@ for tile_name, tile_data in database["tiles"].items(): segment_name = "SEG_" + tile_name segtype = tile_type.lower() - database["segments"][segment_name] = dict() - database["segments"][segment_name]["tiles"] = [ + segments[segment_name] = dict() + segments[segment_name]["tiles"] = [ tile_name, int_tile_name ] - database["segments"][segment_name]["type"] = segtype - database["segments"][segment_name]["frames"] = 36 - database["segments"][segment_name]["words"] = 2 + segments[segment_name]["type"] = segtype + segments[segment_name]["frames"] = 36 + segments[segment_name]["words"] = 2 if tile_name in tile_baseaddr: - database["segments"][segment_name]["baseaddr"] = tile_baseaddr[ + segments[segment_name]["baseaddr"] = tile_baseaddr[ tile_name] - database["tiles"][tile_name]["segment"] = segment_name - database["tiles"][int_tile_name]["segment"] = segment_name + database[tile_name]["segment"] = segment_name + database[int_tile_name]["segment"] = segment_name if tile_type in ["HCLK_L", "HCLK_R"]: segment_name = "SEG_" + tile_name segtype = tile_type.lower() - database["segments"][segment_name] = dict() - database["segments"][segment_name]["tiles"] = [tile_name] - database["segments"][segment_name]["type"] = segtype - database["segments"][segment_name]["frames"] = 26 - database["segments"][segment_name]["words"] = 1 - database["tiles"][tile_name]["segment"] = segment_name + segments[segment_name] = dict() + segments[segment_name]["tiles"] = [tile_name] + segments[segment_name]["type"] = segtype + segments[segment_name]["frames"] = 26 + segments[segment_name]["words"] = 1 + database[tile_name]["segment"] = segment_name if tile_type in ["BRAM_L", "DSP_L", "BRAM_R", "DSP_R"]: for k in range(5): @@ -106,41 +106,41 @@ for tile_name, tile_data in database["tiles"].items(): segment_name = "SEG_" + tile_name.replace("_", "%d_" % k, 1) segtype = tile_type.lower().replace("_", "%d_" % k, 1) - database["segments"][segment_name] = dict() - database["segments"][segment_name]["type"] = segtype - database["segments"][segment_name]["frames"] = 28 - database["segments"][segment_name]["words"] = 2 + segments[segment_name] = dict() + segments[segment_name]["type"] = segtype + segments[segment_name]["frames"] = 28 + segments[segment_name]["words"] = 2 if k == 0: - database["segments"][segment_name]["tiles"] = [ + segments[segment_name]["tiles"] = [ tile_name, interface_tile_name, int_tile_name ] - database["tiles"][tile_name]["segment"] = segment_name - database["tiles"][interface_tile_name][ + database[tile_name]["segment"] = segment_name + database[interface_tile_name][ "segment"] = segment_name - database["tiles"][int_tile_name]["segment"] = segment_name + database[int_tile_name]["segment"] = segment_name else: - database["segments"][segment_name]["tiles"] = [ + segments[segment_name]["tiles"] = [ interface_tile_name, int_tile_name ] - database["tiles"][interface_tile_name][ + database[interface_tile_name][ "segment"] = segment_name - database["tiles"][int_tile_name]["segment"] = segment_name + database[int_tile_name]["segment"] = segment_name ####################################### # Populate segment base addresses: L/R along INT column -for segment_name in database["segments"].keys(): - if "baseaddr" in database["segments"][segment_name]: - framebase, wordbase = database["segments"][segment_name]["baseaddr"] +for segment_name in segments.keys(): + if "baseaddr" in segments[segment_name]: + framebase, wordbase = segments[segment_name]["baseaddr"] inttile = [ - tile for tile in database["segments"][segment_name]["tiles"] - if database["tiles"][tile]["type"] in ["INT_L", "INT_R"] + tile for tile in segments[segment_name]["tiles"] + if database[tile]["type"] in ["INT_L", "INT_R"] ][0] - grid_x = database["tiles"][inttile]["grid_x"] - grid_y = database["tiles"][inttile]["grid_y"] + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] - if database["tiles"][inttile]["type"] == "INT_L": + if database[inttile]["type"] == "INT_L": grid_x += 1 framebase = "0x%08x" % (int(framebase, 16) + 0x80) else: @@ -152,41 +152,41 @@ for segment_name in database["segments"].keys(): tile = tiles_by_grid[(grid_x, grid_y)] - if database["tiles"][inttile]["type"] == "INT_L": - assert database["tiles"][tile]["type"] == "INT_R" - elif database["tiles"][inttile]["type"] == "INT_R": - assert database["tiles"][tile]["type"] == "INT_L" + if database[inttile]["type"] == "INT_L": + assert database[tile]["type"] == "INT_R" + elif database[inttile]["type"] == "INT_R": + assert database[tile]["type"] == "INT_L" else: assert 0 - assert "segment" in database["tiles"][tile] + assert "segment" in database[tile] - seg = database["tiles"][tile]["segment"] + seg = database[tile]["segment"] - if "baseaddr" in database["segments"][seg]: - assert database["segments"][seg]["baseaddr"] == [ + if "baseaddr" in segments[seg]: + assert segments[seg]["baseaddr"] == [ framebase, wordbase ] else: - database["segments"][seg]["baseaddr"] = [framebase, wordbase] + segments[seg]["baseaddr"] = [framebase, wordbase] ####################################### # Populate segment base addresses: Up along INT/HCLK columns start_segments = list() -for segment_name in database["segments"].keys(): - if "baseaddr" in database["segments"][segment_name]: +for segment_name in segments.keys(): + if "baseaddr" in segments[segment_name]: start_segments.append(segment_name) for segment_name in start_segments: - framebase, wordbase = database["segments"][segment_name]["baseaddr"] + framebase, wordbase = segments[segment_name]["baseaddr"] inttile = [ - tile for tile in database["segments"][segment_name]["tiles"] - if database["tiles"][tile]["type"] in ["INT_L", "INT_R"] + tile for tile in segments[segment_name]["tiles"] + if database[tile]["type"] in ["INT_L", "INT_R"] ][0] - grid_x = database["tiles"][inttile]["grid_x"] - grid_y = database["tiles"][inttile]["grid_y"] + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] for i in range(50): grid_y -= 1 @@ -196,33 +196,33 @@ for segment_name in start_segments: else: wordbase += 2 - segname = database["tiles"][tiles_by_grid[(grid_x, grid_y)]]["segment"] - database["segments"][segname]["baseaddr"] = [framebase, wordbase] + segname = database[tiles_by_grid[(grid_x, grid_y)]]["segment"] + segments[segname]["baseaddr"] = [framebase, wordbase] ####################################### # Transfer segment data into tiles -for segment_name in database["segments"].keys(): +for segment_name in segments.keys(): try: - baseaddr, offset = database["segments"][segment_name]["baseaddr"] + baseaddr, offset = segments[segment_name]["baseaddr"] except: print('Failed on segment name %s' % segment_name) raise - for tile_name in database["segments"][segment_name]["tiles"]: - tile_type = database["tiles"][tile_name]["type"] + for tile_name in segments[segment_name]["tiles"]: + tile_type = database[tile_name]["type"] if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R", "INT_L", "INT_R"]: - database["tiles"][tile_name]["baseaddr"] = baseaddr - database["tiles"][tile_name]["offset"] = offset - database["tiles"][tile_name]["height"] = 2 + database[tile_name]["baseaddr"] = baseaddr + database[tile_name]["offset"] = offset + database[tile_name]["height"] = 2 elif tile_type in ["HCLK_L", "HCLK_R"]: - database["tiles"][tile_name]["baseaddr"] = baseaddr - database["tiles"][tile_name]["offset"] = offset - database["tiles"][tile_name]["height"] = 1 + database[tile_name]["baseaddr"] = baseaddr + database[tile_name]["offset"] = offset + database[tile_name]["height"] = 1 elif tile_type in ["BRAM_L", "BRAM_R", "DSP_L", "DSP_R"]: - database["tiles"][tile_name]["baseaddr"] = baseaddr - database["tiles"][tile_name]["offset"] = offset - database["tiles"][tile_name]["height"] = 10 + database[tile_name]["baseaddr"] = baseaddr + database[tile_name]["offset"] = offset + database[tile_name]["height"] = 10 elif tile_type in ["INT_INTERFACE_L", "INT_INTERFACE_R", "BRAM_INT_INTERFACE_L", "BRAM_INT_INTERFACE_R"]: continue @@ -233,14 +233,13 @@ for segment_name in database["segments"].keys(): # TODO: Migrate to new tilegrid format via library. This data is added for # compability with unconverted tools. Update tools then remove this data from # tilegrid.json. -for tiledata in database['tiles'].values(): +for tiledata in database.values(): if "segment" in tiledata: segment = tiledata['segment'] - tiledata['frames'] = database['segments'][segment]['frames'] - tiledata['words'] = database['segments'][segment]['words'] - tiledata['segment_type'] = database['segments'][segment]['type'] + tiledata['frames'] = segments[segment]['frames'] + tiledata['words'] = segments[segment]['words'] + tiledata['segment_type'] = segments[segment]['type'] -database = database["tiles"] ####################################### # Write From 63d872d5392ccba6f43b75f93a162512756bfe5e Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 11:28:16 -0700 Subject: [PATCH 02/42] tilegrid: quote consistency Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index fb5e5487..f0b3221b 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -23,7 +23,6 @@ for arg in sys.argv[1:]: ####################################### # Create initial database -database = dict() database = dict() segments = dict() tiles_by_grid = dict() @@ -235,10 +234,10 @@ for segment_name in segments.keys(): # tilegrid.json. for tiledata in database.values(): if "segment" in tiledata: - segment = tiledata['segment'] - tiledata['frames'] = segments[segment]['frames'] - tiledata['words'] = segments[segment]['words'] - tiledata['segment_type'] = segments[segment]['type'] + segment = tiledata["segment"] + tiledata["frames"] = segments[segment]["frames"] + tiledata["words"] = segments[segment]["words"] + tiledata["segment_type"] = segments[segment]["type"] ####################################### From 875081dbc2383b59686a35b85274945aaf4900f1 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 15:23:51 -0700 Subject: [PATCH 03/42] tilegrid: break into functions, add main() Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 491 ++++++++++++++++++------------- 1 file changed, 288 insertions(+), 203 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index f0b3221b..5783d11f 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -1,136 +1,201 @@ #!/usr/bin/env python3 +''' +Historically we grouped data into "segments" +These were a region of the bitstream that encoded one or more tiles +However, this didn't scale with certain tiles like BRAM +Some sites had multiple bitstream areas and also occupied multiple tiles + +Decoding was then shifted to instead describe how each title is encoded +A post processing step verifies that two tiles don't reference the same bitstream area +''' import os, sys, json, re -####################################### -# Read +# matches lib/include/prjxray/xilinx/xc7series/block_type.h +block_type_i2s = { + 0: 'CLB_IO_CLK', + 1: 'BLOCK_RAM', + 2: 'CFG_CLB', + # special...maybe should error until we know what it is? + # 3: 'RESERVED', +} -tiles = list() -site_baseaddr = dict() -tile_baseaddr = dict() -with open("tiles.txt") as f: - for line in f: - tiles.append(line.split()) +def load_tiles(): + tiles = list() + site_baseaddr = dict() + tile_baseaddr = dict() -for arg in sys.argv[1:]: - with open(arg) as f: - line = f.read().strip() - site = arg[7:-6] - frame = int(line[5:5 + 8], 16) - site_baseaddr[site] = "0x%08x" % (frame & ~0x7f) + with open("tiles.txt") as f: + for line in f: + tiles.append(line.split()) -####################################### -# Create initial database + for arg in sys.argv[1:]: + with open(arg) as f: + line = f.read().strip() + site = arg[7:-6] + frame = int(line[5:5 + 8], 16) + site_baseaddr[site] = "0x%08x" % (frame & ~0x7f) -database = dict() -segments = dict() -tiles_by_grid = dict() + return tiles, site_baseaddr, tile_baseaddr -for record in tiles: - tile_type, tile_name, grid_x, grid_y = record[0:4] - grid_x, grid_y = int(grid_x), int(grid_y) - tiles_by_grid[(grid_x, grid_y)] = tile_name - framebaseaddr = None - database[tile_name] = { - "type": tile_type, - "sites": dict(), - "grid_x": grid_x, - "grid_y": grid_y - } +def make_database(tiles, site_baseaddr, tile_baseaddr): + database = dict() + tiles_by_grid = dict() - if len(record) > 4: - for i in range(4, len(record), 2): - site_type, site_name = record[i:i + 2] - if site_name in site_baseaddr: - framebaseaddr = site_baseaddr[site_name] - database[tile_name]["sites"][site_name] = site_type + for record in tiles: + tile_type, tile_name, grid_x, grid_y = record[0:4] + grid_x, grid_y = int(grid_x), int(grid_y) + tiles_by_grid[(grid_x, grid_y)] = tile_name + framebaseaddr = None - if framebaseaddr is not None: - tile_baseaddr[tile_name] = [framebaseaddr, 0] + database[tile_name] = { + "type": tile_type, + "sites": dict(), + "grid_x": grid_x, + "grid_y": grid_y + } -####################################### -# Add Segments + if len(record) > 4: + for i in range(4, len(record), 2): + site_type, site_name = record[i:i + 2] + if site_name in site_baseaddr: + framebaseaddr = site_baseaddr[site_name] + database[tile_name]["sites"][site_name] = site_type -for tile_name, tile_data in database.items(): - tile_type = tile_data["type"] - grid_x = tile_data["grid_x"] - grid_y = tile_data["grid_y"] + if framebaseaddr is not None: + tile_baseaddr[tile_name] = [framebaseaddr, 0] - if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R"]: - if tile_type in ["CLBLL_L", "CLBLM_L"]: - int_tile_name = tiles_by_grid[(grid_x + 1, grid_y)] - else: - int_tile_name = tiles_by_grid[(grid_x - 1, grid_y)] + return database, tiles_by_grid - segment_name = "SEG_" + tile_name - segtype = tile_type.lower() - segments[segment_name] = dict() - segments[segment_name]["tiles"] = [ - tile_name, int_tile_name - ] - segments[segment_name]["type"] = segtype - segments[segment_name]["frames"] = 36 - segments[segment_name]["words"] = 2 +def make_segments(database, tiles_by_grid, tile_baseaddr): + segments = dict() - if tile_name in tile_baseaddr: - segments[segment_name]["baseaddr"] = tile_baseaddr[ - tile_name] + for tile_name, tile_data in database.items(): + tile_type = tile_data["type"] + grid_x = tile_data["grid_x"] + grid_y = tile_data["grid_y"] - database[tile_name]["segment"] = segment_name - database[int_tile_name]["segment"] = segment_name - - if tile_type in ["HCLK_L", "HCLK_R"]: - segment_name = "SEG_" + tile_name - segtype = tile_type.lower() - - segments[segment_name] = dict() - segments[segment_name]["tiles"] = [tile_name] - segments[segment_name]["type"] = segtype - segments[segment_name]["frames"] = 26 - segments[segment_name]["words"] = 1 - database[tile_name]["segment"] = segment_name - - if tile_type in ["BRAM_L", "DSP_L", "BRAM_R", "DSP_R"]: - for k in range(5): - if tile_type in ["BRAM_L", "DSP_L"]: - interface_tile_name = tiles_by_grid[(grid_x + 1, grid_y - k)] - int_tile_name = tiles_by_grid[(grid_x + 2, grid_y - k)] + if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R"]: + if tile_type in ["CLBLL_L", "CLBLM_L"]: + int_tile_name = tiles_by_grid[(grid_x + 1, grid_y)] else: - interface_tile_name = tiles_by_grid[(grid_x - 1, grid_y - k)] - int_tile_name = tiles_by_grid[(grid_x - 2, grid_y - k)] + int_tile_name = tiles_by_grid[(grid_x - 1, grid_y)] - segment_name = "SEG_" + tile_name.replace("_", "%d_" % k, 1) - segtype = tile_type.lower().replace("_", "%d_" % k, 1) + segment_name = "SEG_" + tile_name + segtype = tile_type.lower() segments[segment_name] = dict() + segments[segment_name]["tiles"] = [tile_name, int_tile_name] segments[segment_name]["type"] = segtype - segments[segment_name]["frames"] = 28 + segments[segment_name]["frames"] = 36 segments[segment_name]["words"] = 2 - if k == 0: - segments[segment_name]["tiles"] = [ - tile_name, interface_tile_name, int_tile_name - ] - database[tile_name]["segment"] = segment_name - database[interface_tile_name][ - "segment"] = segment_name - database[int_tile_name]["segment"] = segment_name + if tile_name in tile_baseaddr: + segments[segment_name]["baseaddr"] = tile_baseaddr[tile_name] + + database[tile_name]["segment"] = segment_name + database[int_tile_name]["segment"] = segment_name + + if tile_type in ["HCLK_L", "HCLK_R"]: + segment_name = "SEG_" + tile_name + segtype = tile_type.lower() + + segments[segment_name] = dict() + segments[segment_name]["tiles"] = [tile_name] + segments[segment_name]["type"] = segtype + segments[segment_name]["frames"] = 26 + segments[segment_name]["words"] = 1 + database[tile_name]["segment"] = segment_name + + if tile_type in ["BRAM_L", "DSP_L", "BRAM_R", "DSP_R"]: + for k in range(5): + if tile_type in ["BRAM_L", "DSP_L"]: + interface_tile_name = tiles_by_grid[( + grid_x + 1, grid_y - k)] + int_tile_name = tiles_by_grid[(grid_x + 2, grid_y - k)] + else: + interface_tile_name = tiles_by_grid[( + grid_x - 1, grid_y - k)] + int_tile_name = tiles_by_grid[(grid_x - 2, grid_y - k)] + + segment_name = "SEG_" + tile_name.replace("_", "%d_" % k, 1) + segtype = tile_type.lower().replace("_", "%d_" % k, 1) + + segments[segment_name] = dict() + segments[segment_name]["type"] = segtype + segments[segment_name]["frames"] = 28 + segments[segment_name]["words"] = 2 + + if k == 0: + segments[segment_name]["tiles"] = [ + tile_name, interface_tile_name, int_tile_name + ] + database[tile_name]["segment"] = segment_name + database[interface_tile_name]["segment"] = segment_name + database[int_tile_name]["segment"] = segment_name + else: + segments[segment_name]["tiles"] = [ + interface_tile_name, int_tile_name + ] + database[interface_tile_name]["segment"] = segment_name + database[int_tile_name]["segment"] = segment_name + + return segments + + +def seg_base_addr_lr_INT(database, segments, tiles_by_grid): + '''Populate segment base addresses: L/R along INT column''' + for segment_name in segments.keys(): + if "baseaddr" in segments[segment_name]: + framebase, wordbase = segments[segment_name]["baseaddr"] + inttile = [ + tile for tile in segments[segment_name]["tiles"] + if database[tile]["type"] in ["INT_L", "INT_R"] + ][0] + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] + + if database[inttile]["type"] == "INT_L": + grid_x += 1 + framebase = "0x%08x" % (int(framebase, 16) + 0x80) else: - segments[segment_name]["tiles"] = [ - interface_tile_name, int_tile_name - ] - database[interface_tile_name][ - "segment"] = segment_name - database[int_tile_name]["segment"] = segment_name + grid_x -= 1 + framebase = "0x%08x" % (int(framebase, 16) - 0x80) -####################################### -# Populate segment base addresses: L/R along INT column + if (grid_x, grid_y) not in tiles_by_grid: + continue -for segment_name in segments.keys(): - if "baseaddr" in segments[segment_name]: + tile = tiles_by_grid[(grid_x, grid_y)] + + if database[inttile]["type"] == "INT_L": + assert database[tile]["type"] == "INT_R" + elif database[inttile]["type"] == "INT_R": + assert database[tile]["type"] == "INT_L" + else: + assert 0 + + assert "segment" in database[tile] + + seg = database[tile]["segment"] + + if "baseaddr" in segments[seg]: + assert segments[seg]["baseaddr"] == [framebase, wordbase] + else: + segments[seg]["baseaddr"] = [framebase, wordbase] + + +def seg_base_addr_up_INT(database, segments, tiles_by_grid): + '''Populate segment base addresses: Up along INT/HCLK columns''' + start_segments = list() + + for segment_name in segments.keys(): + if "baseaddr" in segments[segment_name]: + start_segments.append(segment_name) + + for segment_name in start_segments: framebase, wordbase = segments[segment_name]["baseaddr"] inttile = [ tile for tile in segments[segment_name]["tiles"] @@ -139,108 +204,128 @@ for segment_name in segments.keys(): grid_x = database[inttile]["grid_x"] grid_y = database[inttile]["grid_y"] - if database[inttile]["type"] == "INT_L": - grid_x += 1 - framebase = "0x%08x" % (int(framebase, 16) + 0x80) - else: - grid_x -= 1 - framebase = "0x%08x" % (int(framebase, 16) - 0x80) + for i in range(50): + grid_y -= 1 - if (grid_x, grid_y) not in tiles_by_grid: - continue + if wordbase == 50: + wordbase += 1 + else: + wordbase += 2 - tile = tiles_by_grid[(grid_x, grid_y)] - - if database[inttile]["type"] == "INT_L": - assert database[tile]["type"] == "INT_R" - elif database[inttile]["type"] == "INT_R": - assert database[tile]["type"] == "INT_L" - else: - assert 0 - - assert "segment" in database[tile] - - seg = database[tile]["segment"] - - if "baseaddr" in segments[seg]: - assert segments[seg]["baseaddr"] == [ - framebase, wordbase - ] - else: - segments[seg]["baseaddr"] = [framebase, wordbase] - -####################################### -# Populate segment base addresses: Up along INT/HCLK columns - -start_segments = list() - -for segment_name in segments.keys(): - if "baseaddr" in segments[segment_name]: - start_segments.append(segment_name) - -for segment_name in start_segments: - framebase, wordbase = segments[segment_name]["baseaddr"] - inttile = [ - tile for tile in segments[segment_name]["tiles"] - if database[tile]["type"] in ["INT_L", "INT_R"] - ][0] - grid_x = database[inttile]["grid_x"] - grid_y = database[inttile]["grid_y"] - - for i in range(50): - grid_y -= 1 - - if wordbase == 50: - wordbase += 1 - else: - wordbase += 2 - - segname = database[tiles_by_grid[(grid_x, grid_y)]]["segment"] - segments[segname]["baseaddr"] = [framebase, wordbase] - -####################################### -# Transfer segment data into tiles - -for segment_name in segments.keys(): - try: - baseaddr, offset = segments[segment_name]["baseaddr"] - except: - print('Failed on segment name %s' % segment_name) - raise - for tile_name in segments[segment_name]["tiles"]: - tile_type = database[tile_name]["type"] - if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R", "INT_L", - "INT_R"]: - database[tile_name]["baseaddr"] = baseaddr - database[tile_name]["offset"] = offset - database[tile_name]["height"] = 2 - elif tile_type in ["HCLK_L", "HCLK_R"]: - database[tile_name]["baseaddr"] = baseaddr - database[tile_name]["offset"] = offset - database[tile_name]["height"] = 1 - elif tile_type in ["BRAM_L", "BRAM_R", "DSP_L", "DSP_R"]: - database[tile_name]["baseaddr"] = baseaddr - database[tile_name]["offset"] = offset - database[tile_name]["height"] = 10 - elif tile_type in ["INT_INTERFACE_L", "INT_INTERFACE_R", - "BRAM_INT_INTERFACE_L", "BRAM_INT_INTERFACE_R"]: - continue - else: - # print(tile_type, offset) - assert False - -# TODO: Migrate to new tilegrid format via library. This data is added for -# compability with unconverted tools. Update tools then remove this data from -# tilegrid.json. -for tiledata in database.values(): - if "segment" in tiledata: - segment = tiledata["segment"] - tiledata["frames"] = segments[segment]["frames"] - tiledata["words"] = segments[segment]["words"] - tiledata["segment_type"] = segments[segment]["type"] + segname = database[tiles_by_grid[(grid_x, grid_y)]]["segment"] + segments[segname]["baseaddr"] = [framebase, wordbase] -####################################### -# Write +def base_addr_2_block_type(base_addr): + ''' + Table 5-24: Frame Address Register Description + Bit Index: [25:23] + https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + "Valid block types are CLB, I/O, CLK ( 000 ), block RAM content ( 001 ), and CFG_CLB ( 010 ). A normal bitstream does not include type 011 ." + ''' + block_type_i = (base_addr >> 23) & 0x7 + return block_type_i2s[block_type_i] -print(json.dumps(database, sort_keys=True, indent="\t")) + +def add_tile_bits(tile_db, baseaddr, offset, height): + ''' + Record data structure geometry for the given tile baseaddr + For most tiles there is only one baseaddr, but some like BRAM have multiple + + Notes on multiple block types: + https://github.com/SymbiFlow/prjxray/issues/145 + ''' + ''' + bits = tile_db.setdefault('bits', {}) + block_type = base_addr_2_block_type(int(baseaddr, 0)) + + assert block_type not in bits + block = bits.setdefault(block_type, {}) + ''' + # TODO: remove, just make compatible for initial cleanup commit + block = tile_db + + block["baseaddr"] = baseaddr + block["offset"] = offset + block["height"] = height + + +def add_bits(database, segments): + '''Transfer segment data into tiles''' + for segment_name in segments.keys(): + try: + baseaddr, offset = segments[segment_name]["baseaddr"] + except: + print('Failed on segment name %s' % segment_name) + raise + + for tile_name in segments[segment_name]["tiles"]: + tile_type = database[tile_name]["type"] + if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R", + "INT_L", "INT_R"]: + add_tile_bits(database[tile_name], baseaddr, offset, 2) + elif tile_type in ["HCLK_L", "HCLK_R"]: + add_tile_bits(database[tile_name], baseaddr, offset, 1) + elif tile_type in ["BRAM_L", "BRAM_R", "DSP_L", "DSP_R"]: + add_tile_bits(database[tile_name], baseaddr, offset, 10) + elif tile_type in ["INT_INTERFACE_L", "INT_INTERFACE_R", + "BRAM_INT_INTERFACE_L", "BRAM_INT_INTERFACE_R"]: + continue + else: + # print(tile_type, offset) + assert False + + +def annotate_segments(database, segments): + # TODO: Migrate to new tilegrid format via library. This data is added for + # compability with unconverted tools. Update tools then remove this data from + # tilegrid.json. + for tiledata in database.values(): + if "segment" in tiledata: + segment = tiledata["segment"] + tiledata["frames"] = segments[segment]["frames"] + tiledata["words"] = segments[segment]["words"] + tiledata["segment_type"] = segments[segment]["type"] + + +def run(tiles_fn, json_fn, deltas_fns): + tiles, site_baseaddr, tile_baseaddr = load_tiles() + database, tiles_by_grid = make_database( + tiles, site_baseaddr, tile_baseaddr) + segments = make_segments(database, tiles_by_grid, tile_baseaddr) + seg_base_addr_lr_INT(database, segments, tiles_by_grid) + seg_base_addr_up_INT(database, segments, tiles_by_grid) + add_bits(database, segments) + annotate_segments(database, segments) + json.dump( + database, + open(json_fn, 'w'), + sort_keys=True, + indent=4, + separators=(',', ': ')) + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description= + 'Generate a simple wrapper to test synthesizing an arbitrary verilog module' + ) + + parser.add_argument('--verbose', action='store_true', help='') + parser.add_argument('--out', default='/dev/stdout', help='Output JSON') + parser.add_argument( + 'tiles', + default='tiles.txt', + nargs='?', + help='Input tiles.txt tcl output') + parser.add_argument( + 'deltas', nargs='+', help='.bit diffs to create base addresses from') + args = parser.parse_args() + + run(args.tiles, args.out, args.deltas) + + +if __name__ == '__main__': + main() From fd03be7868982c6206a7077e0147cf5ad58ea651 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 16:31:53 -0700 Subject: [PATCH 04/42] tilegrid: cleanup make_segments, bug fixes Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 107 ++++++++++++++++--------------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 5783d11f..2682bb2d 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -21,16 +21,16 @@ block_type_i2s = { } -def load_tiles(): +def load_tiles(tiles_fn, deltas_fns): tiles = list() site_baseaddr = dict() tile_baseaddr = dict() - with open("tiles.txt") as f: + with open(tiles_fn) as f: for line in f: tiles.append(line.split()) - for arg in sys.argv[1:]: + for arg in deltas_fns: with open(arg) as f: line = f.read().strip() site = arg[7:-6] @@ -71,6 +71,15 @@ def make_database(tiles, site_baseaddr, tile_baseaddr): def make_segments(database, tiles_by_grid, tile_baseaddr): + ''' + Create segments data structure + Indicates how tiles are related to bitstream locations + Also modify database to annotate which segment the tiles belong to + + segments key examples: + SEG_CLBLM_R_X13Y72 + SEG_BRAM3_L_X6Y85 + ''' segments = dict() for tile_name, tile_data in database.items(): @@ -78,7 +87,20 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): grid_x = tile_data["grid_x"] grid_y = tile_data["grid_y"] - if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R"]: + def add_segment(name, tiles, segtype, frames, words, baseaddr=None): + assert name not in segments + segment = segments.setdefault(name, {}) + segment["tiles"] = tiles + segment["type"] = segtype + segment["frames"] = frames + segment["words"] = words + if baseaddr: + segment["baseaddr"] = baseaddr + + for tile_name in tiles: + database[tile_name]["segment"] = name + + def process_clb(): if tile_type in ["CLBLL_L", "CLBLM_L"]: int_tile_name = tiles_by_grid[(grid_x + 1, grid_y)] else: @@ -86,62 +108,54 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): segment_name = "SEG_" + tile_name segtype = tile_type.lower() + add_segment( + segment_name, [tile_name, int_tile_name], + segtype, + 36, + 2, + baseaddr=tile_baseaddr.get(tile_name, None)) - segments[segment_name] = dict() - segments[segment_name]["tiles"] = [tile_name, int_tile_name] - segments[segment_name]["type"] = segtype - segments[segment_name]["frames"] = 36 - segments[segment_name]["words"] = 2 - - if tile_name in tile_baseaddr: - segments[segment_name]["baseaddr"] = tile_baseaddr[tile_name] - - database[tile_name]["segment"] = segment_name - database[int_tile_name]["segment"] = segment_name - - if tile_type in ["HCLK_L", "HCLK_R"]: + def process_hclk(): segment_name = "SEG_" + tile_name segtype = tile_type.lower() - segments[segment_name] = dict() - segments[segment_name]["tiles"] = [tile_name] - segments[segment_name]["type"] = segtype - segments[segment_name]["frames"] = 26 - segments[segment_name]["words"] = 1 - database[tile_name]["segment"] = segment_name + add_segment(segment_name, [tile_name], segtype, 26, 1) - if tile_type in ["BRAM_L", "DSP_L", "BRAM_R", "DSP_R"]: + def process_bram_dsp(): for k in range(5): if tile_type in ["BRAM_L", "DSP_L"]: interface_tile_name = tiles_by_grid[( grid_x + 1, grid_y - k)] int_tile_name = tiles_by_grid[(grid_x + 2, grid_y - k)] - else: + elif tile_type in ["BRAM_R", "DSP_R"]: interface_tile_name = tiles_by_grid[( grid_x - 1, grid_y - k)] int_tile_name = tiles_by_grid[(grid_x - 2, grid_y - k)] + else: + assert 0 segment_name = "SEG_" + tile_name.replace("_", "%d_" % k, 1) segtype = tile_type.lower().replace("_", "%d_" % k, 1) - segments[segment_name] = dict() - segments[segment_name]["type"] = segtype - segments[segment_name]["frames"] = 28 - segments[segment_name]["words"] = 2 - if k == 0: - segments[segment_name]["tiles"] = [ - tile_name, interface_tile_name, int_tile_name - ] - database[tile_name]["segment"] = segment_name - database[interface_tile_name]["segment"] = segment_name - database[int_tile_name]["segment"] = segment_name + tiles = [tile_name, interface_tile_name, int_tile_name] else: - segments[segment_name]["tiles"] = [ - interface_tile_name, int_tile_name - ] - database[interface_tile_name]["segment"] = segment_name - database[int_tile_name]["segment"] = segment_name + tiles = [interface_tile_name, int_tile_name] + + add_segment(segment_name, tiles, segtype, 28, 2) + + { + "CLBLL_L": process_clb, + "CLBLL_R": process_clb, + "CLBLM_L": process_clb, + "CLBLM_R": process_clb, + "HCLK_L": process_hclk, + "HCLK_R": process_hclk, + "BRAM_L": process_bram_dsp, + "DSP_L": process_bram_dsp, + "BRAM_R": process_bram_dsp, + "DSP_R": process_bram_dsp, + }.get(tile_type, lambda: None)() return segments @@ -235,15 +249,11 @@ def add_tile_bits(tile_db, baseaddr, offset, height): Notes on multiple block types: https://github.com/SymbiFlow/prjxray/issues/145 ''' - ''' bits = tile_db.setdefault('bits', {}) block_type = base_addr_2_block_type(int(baseaddr, 0)) assert block_type not in bits block = bits.setdefault(block_type, {}) - ''' - # TODO: remove, just make compatible for initial cleanup commit - block = tile_db block["baseaddr"] = baseaddr block["offset"] = offset @@ -289,7 +299,7 @@ def annotate_segments(database, segments): def run(tiles_fn, json_fn, deltas_fns): - tiles, site_baseaddr, tile_baseaddr = load_tiles() + tiles, site_baseaddr, tile_baseaddr = load_tiles(tiles_fn, deltas_fns) database, tiles_by_grid = make_database( tiles, site_baseaddr, tile_baseaddr) segments = make_segments(database, tiles_by_grid, tile_baseaddr) @@ -316,10 +326,7 @@ def main(): parser.add_argument('--verbose', action='store_true', help='') parser.add_argument('--out', default='/dev/stdout', help='Output JSON') parser.add_argument( - 'tiles', - default='tiles.txt', - nargs='?', - help='Input tiles.txt tcl output') + '--tiles', default='tiles.txt', help='Input tiles.txt tcl output') parser.add_argument( 'deltas', nargs='+', help='.bit diffs to create base addresses from') args = parser.parse_args() From 38df1bad48e9aa9b881f68bd5f6bb481b2d6d208 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 16:34:52 -0700 Subject: [PATCH 05/42] tilegrid: add_segment() explicit keys Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 2682bb2d..31f3503b 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -106,20 +106,21 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): else: int_tile_name = tiles_by_grid[(grid_x - 1, grid_y)] - segment_name = "SEG_" + tile_name - segtype = tile_type.lower() add_segment( - segment_name, [tile_name, int_tile_name], - segtype, - 36, - 2, + name="SEG_" + tile_name, + tiles=[tile_name, int_tile_name], + segtype=tile_type.lower(), + frames=36, + words=2, baseaddr=tile_baseaddr.get(tile_name, None)) def process_hclk(): - segment_name = "SEG_" + tile_name - segtype = tile_type.lower() - - add_segment(segment_name, [tile_name], segtype, 26, 1) + add_segment( + name="SEG_" + tile_name, + tiles=[tile_name], + segtype=tile_type.lower(), + frames=26, + words=1) def process_bram_dsp(): for k in range(5): @@ -134,15 +135,17 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): else: assert 0 - segment_name = "SEG_" + tile_name.replace("_", "%d_" % k, 1) - segtype = tile_type.lower().replace("_", "%d_" % k, 1) - if k == 0: tiles = [tile_name, interface_tile_name, int_tile_name] else: tiles = [interface_tile_name, int_tile_name] - add_segment(segment_name, tiles, segtype, 28, 2) + add_segment( + name="SEG_" + tile_name.replace("_", "%d_" % k, 1), + tiles=tiles, + segtype=tile_type.lower().replace("_", "%d_" % k, 1), + frames=28, + words=2) { "CLBLL_L": process_clb, From f7a3d8bf94b2109ccde68ac9ab09d914a8c52bdf Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 17:30:46 -0700 Subject: [PATCH 06/42] tilegrid: move tile_baseaddr closer to where its created Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 82 ++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 31f3503b..6c61d871 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -22,12 +22,16 @@ block_type_i2s = { def load_tiles(tiles_fn, deltas_fns): + ''' + "$type $tile $grid_x $grid_y $typed_sites" + typed_sites: foreach t $site_types s $sites + ''' tiles = list() site_baseaddr = dict() - tile_baseaddr = dict() with open(tiles_fn) as f: for line in f: + # CLBLM_L CLBLM_L_X10Y98 30 106 SLICEL SLICE_X13Y98 SLICEM SLICE_X12Y98 tiles.append(line.split()) for arg in deltas_fns: @@ -37,12 +41,13 @@ def load_tiles(tiles_fn, deltas_fns): frame = int(line[5:5 + 8], 16) site_baseaddr[site] = "0x%08x" % (frame & ~0x7f) - return tiles, site_baseaddr, tile_baseaddr + return tiles, site_baseaddr -def make_database(tiles, site_baseaddr, tile_baseaddr): +def make_database(tiles, site_baseaddr): database = dict() tiles_by_grid = dict() + tile_baseaddr = dict() for record in tiles: tile_type, tile_name, grid_x, grid_y = record[0:4] @@ -67,7 +72,7 @@ def make_database(tiles, site_baseaddr, tile_baseaddr): if framebaseaddr is not None: tile_baseaddr[tile_name] = [framebaseaddr, 0] - return database, tiles_by_grid + return database, tiles_by_grid, tile_baseaddr def make_segments(database, tiles_by_grid, tile_baseaddr): @@ -141,8 +146,10 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): tiles = [interface_tile_name, int_tile_name] add_segment( + # BRAM_L_X6Y70 => SEG_BRAM4_L_X6Y70 name="SEG_" + tile_name.replace("_", "%d_" % k, 1), tiles=tiles, + # BRAM_L => bram4_l segtype=tile_type.lower().replace("_", "%d_" % k, 1), frames=28, words=2) @@ -166,42 +173,45 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): def seg_base_addr_lr_INT(database, segments, tiles_by_grid): '''Populate segment base addresses: L/R along INT column''' for segment_name in segments.keys(): - if "baseaddr" in segments[segment_name]: - framebase, wordbase = segments[segment_name]["baseaddr"] - inttile = [ - tile for tile in segments[segment_name]["tiles"] - if database[tile]["type"] in ["INT_L", "INT_R"] - ][0] - grid_x = database[inttile]["grid_x"] - grid_y = database[inttile]["grid_y"] + # As of this writing only CLBs, but soon to be BRAM data + if "baseaddr" not in segments[segment_name]: + continue - if database[inttile]["type"] == "INT_L": - grid_x += 1 - framebase = "0x%08x" % (int(framebase, 16) + 0x80) - else: - grid_x -= 1 - framebase = "0x%08x" % (int(framebase, 16) - 0x80) + framebase, wordbase = segments[segment_name]["baseaddr"] + inttile = [ + tile for tile in segments[segment_name]["tiles"] + if database[tile]["type"] in ["INT_L", "INT_R"] + ][0] + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] - if (grid_x, grid_y) not in tiles_by_grid: - continue + if database[inttile]["type"] == "INT_L": + grid_x += 1 + framebase = "0x%08x" % (int(framebase, 16) + 0x80) + else: + grid_x -= 1 + framebase = "0x%08x" % (int(framebase, 16) - 0x80) - tile = tiles_by_grid[(grid_x, grid_y)] + if (grid_x, grid_y) not in tiles_by_grid: + continue - if database[inttile]["type"] == "INT_L": - assert database[tile]["type"] == "INT_R" - elif database[inttile]["type"] == "INT_R": - assert database[tile]["type"] == "INT_L" - else: - assert 0 + tile = tiles_by_grid[(grid_x, grid_y)] - assert "segment" in database[tile] + if database[inttile]["type"] == "INT_L": + assert database[tile]["type"] == "INT_R" + elif database[inttile]["type"] == "INT_R": + assert database[tile]["type"] == "INT_L" + else: + assert 0 - seg = database[tile]["segment"] + assert "segment" in database[tile] - if "baseaddr" in segments[seg]: - assert segments[seg]["baseaddr"] == [framebase, wordbase] - else: - segments[seg]["baseaddr"] = [framebase, wordbase] + seg = database[tile]["segment"] + + if "baseaddr" in segments[seg]: + assert segments[seg]["baseaddr"] == [framebase, wordbase] + else: + segments[seg]["baseaddr"] = [framebase, wordbase] def seg_base_addr_up_INT(database, segments, tiles_by_grid): @@ -302,9 +312,9 @@ def annotate_segments(database, segments): def run(tiles_fn, json_fn, deltas_fns): - tiles, site_baseaddr, tile_baseaddr = load_tiles(tiles_fn, deltas_fns) - database, tiles_by_grid = make_database( - tiles, site_baseaddr, tile_baseaddr) + tiles, site_baseaddr = load_tiles(tiles_fn, deltas_fns) + database, tiles_by_grid, tile_baseaddr = make_database( + tiles, site_baseaddr) segments = make_segments(database, tiles_by_grid, tile_baseaddr) seg_base_addr_lr_INT(database, segments, tiles_by_grid) seg_base_addr_up_INT(database, segments, tiles_by_grid) From d682523456de83d038db6c8772119d96a33e431f Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 17:46:41 -0700 Subject: [PATCH 07/42] tilegrid: clean up load_tiles() Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 70 +++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 6c61d871..caf6a95c 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -21,19 +21,37 @@ block_type_i2s = { } -def load_tiles(tiles_fn, deltas_fns): +def load_tiles(tiles_fn): ''' "$type $tile $grid_x $grid_y $typed_sites" typed_sites: foreach t $site_types s $sites ''' tiles = list() - site_baseaddr = dict() with open(tiles_fn) as f: for line in f: # CLBLM_L CLBLM_L_X10Y98 30 106 SLICEL SLICE_X13Y98 SLICEM SLICE_X12Y98 - tiles.append(line.split()) + record = line.split() + tile_type, tile_name, grid_x, grid_y = record[0:4] + grid_x, grid_y = int(grid_x), int(grid_y) + sites = {} + for i in range(4, len(record), 2): + site_type, site_name = record[i:i + 2] + sites[site_name] = site_type + tile = { + 'type': tile_type, + 'name': tile_name, + 'grid_x': grid_x, + 'grid_y': grid_y, + 'sites': sites, + } + tiles.append(tile) + return tiles + + +def load_baseaddrs(deltas_fns): + site_baseaddr = dict() for arg in deltas_fns: with open(arg) as f: line = f.read().strip() @@ -41,36 +59,32 @@ def load_tiles(tiles_fn, deltas_fns): frame = int(line[5:5 + 8], 16) site_baseaddr[site] = "0x%08x" % (frame & ~0x7f) - return tiles, site_baseaddr + return site_baseaddr def make_database(tiles, site_baseaddr): + # tile database with X, Y, and list of sites + # tile name as keys database = dict() + # lookup tile names by (X, Y) tiles_by_grid = dict() + # Look up a base address by tile name tile_baseaddr = dict() - for record in tiles: - tile_type, tile_name, grid_x, grid_y = record[0:4] - grid_x, grid_y = int(grid_x), int(grid_y) - tiles_by_grid[(grid_x, grid_y)] = tile_name - framebaseaddr = None + for tile in tiles: + tiles_by_grid[(tile['grid_x'], tile['grid_y'])] = tile["name"] - database[tile_name] = { - "type": tile_type, - "sites": dict(), - "grid_x": grid_x, - "grid_y": grid_y + database[tile['name']] = { + "type": tile['type'], + "sites": tile['sites'], + "grid_x": tile['grid_x'], + "grid_y": tile['grid_y'], } - if len(record) > 4: - for i in range(4, len(record), 2): - site_type, site_name = record[i:i + 2] - if site_name in site_baseaddr: - framebaseaddr = site_baseaddr[site_name] - database[tile_name]["sites"][site_name] = site_type - - if framebaseaddr is not None: - tile_baseaddr[tile_name] = [framebaseaddr, 0] + for site_name in tile['sites'].keys(): + if site_name in site_baseaddr: + framebaseaddr = site_baseaddr[site_name] + tile_baseaddr[tile['name']] = [framebaseaddr, 0] return database, tiles_by_grid, tile_baseaddr @@ -312,14 +326,22 @@ def annotate_segments(database, segments): def run(tiles_fn, json_fn, deltas_fns): - tiles, site_baseaddr = load_tiles(tiles_fn, deltas_fns) + # Load input files + tiles = load_tiles(tiles_fn) + site_baseaddr = load_baseaddrs(deltas_fns) + database, tiles_by_grid, tile_baseaddr = make_database( tiles, site_baseaddr) segments = make_segments(database, tiles_by_grid, tile_baseaddr) + + # Reference adjacent CLBs to locate adjacent tiles by known offsets seg_base_addr_lr_INT(database, segments, tiles_by_grid) seg_base_addr_up_INT(database, segments, tiles_by_grid) + add_bits(database, segments) annotate_segments(database, segments) + + # Save json.dump( database, open(json_fn, 'w'), From 7053663aa621f06e76f9bb950bf2b9a5d7c25e23 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 17:52:19 -0700 Subject: [PATCH 08/42] tilegrid: split make_database() Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 35 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index caf6a95c..1149c0f4 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -62,18 +62,12 @@ def load_baseaddrs(deltas_fns): return site_baseaddr -def make_database(tiles, site_baseaddr): +def make_database(tiles): # tile database with X, Y, and list of sites # tile name as keys database = dict() - # lookup tile names by (X, Y) - tiles_by_grid = dict() - # Look up a base address by tile name - tile_baseaddr = dict() for tile in tiles: - tiles_by_grid[(tile['grid_x'], tile['grid_y'])] = tile["name"] - database[tile['name']] = { "type": tile['type'], "sites": tile['sites'], @@ -81,12 +75,30 @@ def make_database(tiles, site_baseaddr): "grid_y": tile['grid_y'], } + return database + + +def make_tile_baseaddr(tiles, site_baseaddr): + # Look up a base address by tile name + tile_baseaddr = dict() + + for tile in tiles: for site_name in tile['sites'].keys(): if site_name in site_baseaddr: framebaseaddr = site_baseaddr[site_name] tile_baseaddr[tile['name']] = [framebaseaddr, 0] - return database, tiles_by_grid, tile_baseaddr + return tile_baseaddr + + +def make_tiles_by_grid(tiles): + # lookup tile names by (X, Y) + tiles_by_grid = dict() + + for tile in tiles: + tiles_by_grid[(tile['grid_x'], tile['grid_y'])] = tile["name"] + + return tiles_by_grid def make_segments(database, tiles_by_grid, tile_baseaddr): @@ -330,8 +342,11 @@ def run(tiles_fn, json_fn, deltas_fns): tiles = load_tiles(tiles_fn) site_baseaddr = load_baseaddrs(deltas_fns) - database, tiles_by_grid, tile_baseaddr = make_database( - tiles, site_baseaddr) + # Index input + database = make_database(tiles) + tile_baseaddr = make_tile_baseaddr(tiles, site_baseaddr) + tiles_by_grid = make_tiles_by_grid(tiles) + segments = make_segments(database, tiles_by_grid, tile_baseaddr) # Reference adjacent CLBs to locate adjacent tiles by known offsets From 7c84e3ccc99f89c0263d6d4868ce4381c83fddef Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 9 Oct 2018 19:00:39 -0700 Subject: [PATCH 09/42] tilegrid: BRAM partial support Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.tcl | 213 ++++++++++++++++++------------ fuzzers/005-tilegrid/top.v | 43 +++++- 2 files changed, 166 insertions(+), 90 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.tcl b/fuzzers/005-tilegrid/generate.tcl index d1bb7df2..6a32c1e4 100644 --- a/fuzzers/005-tilegrid/generate.tcl +++ b/fuzzers/005-tilegrid/generate.tcl @@ -1,100 +1,143 @@ -create_project -force -part $::env(XRAY_PART) design design +proc make_project {} { + create_project -force -part $::env(XRAY_PART) design design -read_verilog ../top.v -synth_design -top top + read_verilog ../top.v + synth_design -top top -set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] -set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports di] -set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports do] -set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports stb] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports di] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports do] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports stb] -create_pblock roi -add_cells_to_pblock [get_pblocks roi] [get_cells roi] -resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" + create_pblock roi + add_cells_to_pblock [get_pblocks roi] [get_cells roi] + resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" -set_property CFGBVS VCCO [current_design] -set_property CONFIG_VOLTAGE 3.3 [current_design] -set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] -set_param tcl.collectionResultDisplayLimit 0 + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + set_param tcl.collectionResultDisplayLimit 0 -set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] - -set luts [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ LUT*} */A6LUT] -set selected_luts {} -set lut_index 0 - -if 0 { - set grid_min_x -1 - set grid_max_x -1 - set grid_min_y -1 - set grid_max_y -1 -} { - set grid_min_x $::env(XRAY_ROI_GRID_X1) - set grid_max_x $::env(XRAY_ROI_GRID_X2) - set grid_min_y $::env(XRAY_ROI_GRID_Y1) - set grid_max_y $::env(XRAY_ROI_GRID_Y2) + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] } -# LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per column) -# Also, if GRID_MIN/MAX is not defined, automatically create it based on used CLBs -# See caveat in README on automatic creation -foreach lut $luts { - set tile [get_tile -of_objects $lut] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] +proc loc_luts {} { + set luts [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ LUT*} */A6LUT] + set selected_luts {} + set lut_index 0 - if [expr $grid_min_x < 0 || $grid_x < $grid_min_x] {set grid_min_x $grid_x} - if [expr $grid_max_x < 0 || $grid_x > $grid_max_x] {set grid_max_x $grid_x} + # LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per CMT column) + foreach lut $luts { + set tile [get_tile -of_objects $lut] + set grid_x [get_property GRID_POINT_X $tile] + set grid_y [get_property GRID_POINT_Y $tile] - if [expr $grid_min_y < 0 || $grid_y < $grid_min_y] {set grid_min_y $grid_y} - if [expr $grid_max_y < 0 || $grid_y > $grid_max_y] {set grid_max_y $grid_y} - - # 50 per column => 50, 100, 150, etc - if [regexp "Y(0|[0-9]*[05]0)/" $lut] { - set cell [get_cells roi/is[$lut_index].lut] - set_property LOC [get_sites -of_objects $lut] $cell - set lut_index [expr $lut_index + 1] - lappend selected_luts $lut - } + # 50 per column => 50, 100, 150, etc + # ex: SLICE_X2Y50/A6LUT + if [regexp "Y.*[05]0/" $lut] { + set cell [get_cells roi/luts[$lut_index].lut] + set_property LOC [get_sites -of_objects $lut] $cell + set lut_index [expr $lut_index + 1] + lappend selected_luts $lut + } + } + return $selected_luts } -place_design -route_design +proc loc_brams {} { + # XXX: for some reason this doesn't work if there is a cell already there + # but LUTs don't have this issue + set brams [get_bels -of_objects [get_sites -of_objects [get_pblocks roi]] -filter {TYPE =~ RAMBFIFO36E1*}] + set selected_brams {} + set bram_index 0 -write_checkpoint -force design.dcp -write_bitstream -force design.bit + # LOC one BRAM (a "selected_lut") into each BRAM segment configuration column (ie 10 per CMT column) + foreach bram $brams { + set tile [get_tile -of_objects $bram] + set grid_x [get_property GRID_POINT_X $tile] + set grid_y [get_property GRID_POINT_Y $tile] -# Get all tiles in ROI, ie not just the selected LUTs -set tiles [get_tiles -filter "GRID_POINT_X >= $grid_min_x && GRID_POINT_X <= $grid_max_x && GRID_POINT_Y >= $grid_min_y && GRID_POINT_Y <= $grid_max_y"] - -# Write tiles.txt with site metadata -set fp [open "tiles.txt" w] -foreach tile $tiles { - set type [get_property TYPE $tile] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] - set sites [get_sites -quiet -of_objects $tile] - set typed_sites {} - - if [llength $sites] { - set site_types [get_property SITE_TYPE $sites] - foreach t $site_types s $sites { - lappend typed_sites $t $s - } - } - - puts $fp "$type $tile $grid_x $grid_y $typed_sites" -} -close $fp - -# Toggle one bit in each selected LUT to generate base addresses -for {set i 0} {$i < $lut_index} {incr i} { - set cell [get_cells roi/is[$i].lut] - set orig_init [get_property INIT $cell] - # Flip a bit by changing MSB 0 => 1 - set new_init [regsub "h8" $orig_init "h0"] - set_property INIT $new_init $cell - write_bitstream -force design_[get_sites -of_objects [lindex $selected_luts $i]].bit - set_property INIT $orig_init $cell + # 10 per column => 10, 20, ,etc + # ex: RAMB36_X0Y10/RAMBFIFO36E1 + if [regexp "Y.*0/" $bram] { + set cell [get_cells roi/brams[$bram_index].bram] + set_property LOC [get_sites -of_objects $bram] $cell + set bram_index [expr $bram_index + 1] + lappend selected_brams $bram + } + } + return $selected_brams } +proc write_tiles_txt {} { + # Get all tiles in ROI, ie not just the selected LUTs + set grid_min_x $::env(XRAY_ROI_GRID_X1) + set grid_max_x $::env(XRAY_ROI_GRID_X2) + set grid_min_y $::env(XRAY_ROI_GRID_Y1) + set grid_max_y $::env(XRAY_ROI_GRID_Y2) + set tiles [get_tiles -filter "GRID_POINT_X >= $grid_min_x && GRID_POINT_X <= $grid_max_x && GRID_POINT_Y >= $grid_min_y && GRID_POINT_Y <= $grid_max_y"] + + # Write tiles.txt with site metadata + set fp [open "tiles.txt" w] + foreach tile $tiles { + set type [get_property TYPE $tile] + set grid_x [get_property GRID_POINT_X $tile] + set grid_y [get_property GRID_POINT_Y $tile] + set sites [get_sites -quiet -of_objects $tile] + set typed_sites {} + + if [llength $sites] { + set site_types [get_property SITE_TYPE $sites] + foreach t $site_types s $sites { + lappend typed_sites $t $s + } + } + + puts $fp "$type $tile $grid_x $grid_y $typed_sites" + } + close $fp +} + +proc write_clbs { selected_luts } { + # Toggle one bit in each selected LUT to generate base addresses + for {set i 0} {$i < [llength $selected_luts]} {incr i} { + set cell [get_cells roi/luts[$i].lut] + set orig_init [get_property INIT $cell] + # Flip a bit by changing MSB 0 => 1 + set new_init [regsub "h8" $orig_init "h0"] + set_property INIT $new_init $cell + write_bitstream -force design_[get_sites -of_objects [lindex $selected_luts $i]].bit + set_property INIT $orig_init $cell + } +} + +proc write_brams { selected_brams } { + # Toggle one bit in each selected BRAM to generate base addresses + for {set i 0} {$i < [llength $selected_brams]} {incr i} { + set cell [get_cells roi/brams[$i].bram] + set orig_init [get_property INIT_00 $cell] + # Flip a bit by changing MSB 0 => 1 + set new_init [regsub "h8" $orig_init "h0"] + set_property INIT_00 $new_init $cell + write_bitstream -force design_[get_sites -of_objects [lindex $selected_brams $i]].bit + set_property INIT_00 $orig_init $cell + } +} + +proc run {} { + make_project + set selected_luts [loc_luts] + set selected_brams [loc_brams] + + place_design + route_design + write_checkpoint -force design.dcp + write_bitstream -force design.bit + + write_tiles_txt + write_clbs $selected_luts + write_brams $selected_brams +} + +run + diff --git a/fuzzers/005-tilegrid/top.v b/fuzzers/005-tilegrid/top.v index 5fd239b5..55edc442 100644 --- a/fuzzers/005-tilegrid/top.v +++ b/fuzzers/005-tilegrid/top.v @@ -1,9 +1,10 @@ //Need at least one LUT per frame base address we want -`define N 100 +`define N_LUT 100 +`define N_BRAM 8 module top(input clk, stb, di, output do); - localparam integer DIN_N = 6; - localparam integer DOUT_N = `N; + localparam integer DIN_N = 8; + localparam integer DOUT_N = `N_LUT + `N_BRAM; reg [DIN_N-1:0] din; wire [DOUT_N-1:0] dout; @@ -29,10 +30,10 @@ module top(input clk, stb, di, output do); ); endmodule -module roi(input clk, input [5:0] din, output [`N-1:0] dout); +module roi(input clk, input [7:0] din, output [`N_LUT + `N_BRAM-1:0] dout); genvar i; generate - for (i = 0; i < `N; i = i+1) begin:is + for (i = 0; i < `N_LUT; i = i+1) begin:luts LUT6 #( .INIT(64'h8000_0000_0000_0001 + (i << 16)) ) lut ( @@ -46,4 +47,36 @@ module roi(input clk, input [5:0] din, output [`N-1:0] dout); ); end endgenerate + + genvar j; + generate + for (j = 0; j < `N_BRAM; j = j+1) begin:brams + (* KEEP, DONT_TOUCH *) + RAMB36E1 #( + .INIT_00(256'h8000000000000000000000000000000000000000000000000000000000000000 + (j << 16)) + ) bram ( + .CLKARDCLK(din[0]), + .CLKBWRCLK(din[1]), + .ENARDEN(din[2]), + .ENBWREN(din[3]), + .REGCEAREGCE(din[4]), + .REGCEB(din[5]), + .RSTRAMARSTRAM(din[6]), + .RSTRAMB(din[7]), + .RSTREGARSTREG(din[0]), + .RSTREGB(din[1]), + .ADDRARDADDR(din[2]), + .ADDRBWRADDR(din[3]), + .DIADI(din[4]), + .DIBDI(din[5]), + .DIPADIP(din[6]), + .DIPBDIP(din[7]), + .WEA(din[0]), + .WEBWE(din[1]), + .DOADO(dout[j + `N_LUT]), + .DOBDO(), + .DOPADOP(), + .DOPBDOP()); + end + endgenerate endmodule From 2070c94e68703ba3e21b4247749ac223408cc85a Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 10 Oct 2018 14:44:56 -0700 Subject: [PATCH 10/42] tilegrid generate: simplify if / tables Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 57 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 1149c0f4..c5445947 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -21,6 +21,19 @@ block_type_i2s = { } +def nolr(tile_type): + ''' + Remove _L or _R suffix tile_type suffix, if present + Ex: BRAM_INT_INTERFACE_L => BRAM_INT_INTERFACE + Ex: VBRK => VBRK + ''' + postfix = tile_type[-2:] + if postfix in ('_L', '_R'): + return tile_type[:-2] + else: + return tile_type + + def load_tiles(tiles_fn): ''' "$type $tile $grid_x $grid_y $typed_sites" @@ -181,17 +194,12 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): words=2) { - "CLBLL_L": process_clb, - "CLBLL_R": process_clb, - "CLBLM_L": process_clb, - "CLBLM_R": process_clb, - "HCLK_L": process_hclk, - "HCLK_R": process_hclk, - "BRAM_L": process_bram_dsp, - "DSP_L": process_bram_dsp, - "BRAM_R": process_bram_dsp, - "DSP_R": process_bram_dsp, - }.get(tile_type, lambda: None)() + "CLBLL": process_clb, + "CLBLM": process_clb, + "HCLK": process_hclk, + "BRAM": process_bram_dsp, + "DSP": process_bram_dsp, + }.get(nolr(tile_type), lambda: None)() return segments @@ -310,19 +318,20 @@ def add_bits(database, segments): for tile_name in segments[segment_name]["tiles"]: tile_type = database[tile_name]["type"] - if tile_type in ["CLBLL_L", "CLBLL_R", "CLBLM_L", "CLBLM_R", - "INT_L", "INT_R"]: - add_tile_bits(database[tile_name], baseaddr, offset, 2) - elif tile_type in ["HCLK_L", "HCLK_R"]: - add_tile_bits(database[tile_name], baseaddr, offset, 1) - elif tile_type in ["BRAM_L", "BRAM_R", "DSP_L", "DSP_R"]: - add_tile_bits(database[tile_name], baseaddr, offset, 10) - elif tile_type in ["INT_INTERFACE_L", "INT_INTERFACE_R", - "BRAM_INT_INTERFACE_L", "BRAM_INT_INTERFACE_R"]: - continue - else: - # print(tile_type, offset) - assert False + height = { + "CLBLL": 2, + "CLBLM": 2, + "INT": 2, + "HCLK": 1, + "BRAM": 10, + "DSP": 10, + "INT_INTERFACE": 0, + "BRAM_INT_INTERFACE": 0, + }.get(nolr(tile_type), None) + if height is None: + raise ValueError("Unknown tile type %s" % tile_type) + if height: + add_tile_bits(database[tile_name], baseaddr, offset, height) def annotate_segments(database, segments): From e62d722003c9194f04e20cde14f54bac5df6a411 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 10 Oct 2018 14:46:19 -0700 Subject: [PATCH 11/42] tilegrid generate.tcl: more debug output, consistent tab/space Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.tcl | 100 ++++++++++++++++-------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.tcl b/fuzzers/005-tilegrid/generate.tcl index 6a32c1e4..eb1e49f7 100644 --- a/fuzzers/005-tilegrid/generate.tcl +++ b/fuzzers/005-tilegrid/generate.tcl @@ -28,18 +28,18 @@ proc loc_luts {} { # LOC one LUT (a "selected_lut") into each CLB segment configuration column (ie 50 per CMT column) foreach lut $luts { - set tile [get_tile -of_objects $lut] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] + set tile [get_tile -of_objects $lut] + set grid_x [get_property GRID_POINT_X $tile] + set grid_y [get_property GRID_POINT_Y $tile] - # 50 per column => 50, 100, 150, etc - # ex: SLICE_X2Y50/A6LUT - if [regexp "Y.*[05]0/" $lut] { - set cell [get_cells roi/luts[$lut_index].lut] - set_property LOC [get_sites -of_objects $lut] $cell - set lut_index [expr $lut_index + 1] - lappend selected_luts $lut - } + # 50 per column => 50, 100, 150, etc + # ex: SLICE_X2Y50/A6LUT + if [regexp "Y.*[05]0/" $lut] { + set cell [get_cells roi/luts[$lut_index].lut] + set_property LOC [get_sites -of_objects $lut] $cell + set lut_index [expr $lut_index + 1] + lappend selected_luts $lut + } } return $selected_luts } @@ -53,18 +53,18 @@ proc loc_brams {} { # LOC one BRAM (a "selected_lut") into each BRAM segment configuration column (ie 10 per CMT column) foreach bram $brams { - set tile [get_tile -of_objects $bram] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] + set tile [get_tile -of_objects $bram] + set grid_x [get_property GRID_POINT_X $tile] + set grid_y [get_property GRID_POINT_Y $tile] # 10 per column => 10, 20, ,etc # ex: RAMB36_X0Y10/RAMBFIFO36E1 - if [regexp "Y.*0/" $bram] { - set cell [get_cells roi/brams[$bram_index].bram] - set_property LOC [get_sites -of_objects $bram] $cell - set bram_index [expr $bram_index + 1] - lappend selected_brams $bram - } + if [regexp "Y.*0/" $bram] { + set cell [get_cells roi/brams[$bram_index].bram] + set_property LOC [get_sites -of_objects $bram] $cell + set bram_index [expr $bram_index + 1] + lappend selected_brams $bram + } } return $selected_brams } @@ -80,20 +80,20 @@ proc write_tiles_txt {} { # Write tiles.txt with site metadata set fp [open "tiles.txt" w] foreach tile $tiles { - set type [get_property TYPE $tile] - set grid_x [get_property GRID_POINT_X $tile] - set grid_y [get_property GRID_POINT_Y $tile] - set sites [get_sites -quiet -of_objects $tile] - set typed_sites {} + set type [get_property TYPE $tile] + set grid_x [get_property GRID_POINT_X $tile] + set grid_y [get_property GRID_POINT_Y $tile] + set sites [get_sites -quiet -of_objects $tile] + set typed_sites {} - if [llength $sites] { - set site_types [get_property SITE_TYPE $sites] - foreach t $site_types s $sites { - lappend typed_sites $t $s - } - } + if [llength $sites] { + set site_types [get_property SITE_TYPE $sites] + foreach t $site_types s $sites { + lappend typed_sites $t $s + } + } - puts $fp "$type $tile $grid_x $grid_y $typed_sites" + puts $fp "$type $tile $grid_x $grid_y $typed_sites" } close $fp } @@ -101,33 +101,41 @@ proc write_tiles_txt {} { proc write_clbs { selected_luts } { # Toggle one bit in each selected LUT to generate base addresses for {set i 0} {$i < [llength $selected_luts]} {incr i} { - set cell [get_cells roi/luts[$i].lut] - set orig_init [get_property INIT $cell] - # Flip a bit by changing MSB 0 => 1 - set new_init [regsub "h8" $orig_init "h0"] - set_property INIT $new_init $cell - write_bitstream -force design_[get_sites -of_objects [lindex $selected_luts $i]].bit - set_property INIT $orig_init $cell + puts "" + set cell [get_cells roi/luts[$i].lut] + puts "LUT $cell" + set orig_init [get_property INIT $cell] + # Flip a bit by changing MSB 0 => 1 + set new_init [regsub "h8" $orig_init "h0"] + puts "INIT $orig_init => $new_init" + set_property INIT $new_init $cell + write_bitstream -force design_[get_sites -of_objects [lindex $selected_luts $i]].bit + set_property INIT $orig_init $cell } } proc write_brams { selected_brams } { # Toggle one bit in each selected BRAM to generate base addresses for {set i 0} {$i < [llength $selected_brams]} {incr i} { - set cell [get_cells roi/brams[$i].bram] - set orig_init [get_property INIT_00 $cell] - # Flip a bit by changing MSB 0 => 1 - set new_init [regsub "h8" $orig_init "h0"] - set_property INIT_00 $new_init $cell - write_bitstream -force design_[get_sites -of_objects [lindex $selected_brams $i]].bit - set_property INIT_00 $orig_init $cell + puts "" + set cell [get_cells roi/brams[$i].bram] + puts "BRAM $cell" + set orig_init [get_property INIT_00 $cell] + # Flip a bit by changing MSB 0 => 1 + set new_init [regsub "h8" $orig_init "h0"] + puts "INIT_00 $orig_init => $new_init" + set_property INIT_00 $new_init $cell + write_bitstream -force design_[get_sites -of_objects [lindex $selected_brams $i]].bit + set_property INIT_00 $orig_init $cell } } proc run {} { make_project set selected_luts [loc_luts] + puts "Selected LUTs: [llength $selected_luts]" set selected_brams [loc_brams] + puts "Selected LUTs: [llength $selected_brams]" place_design route_design From 9f3443a8a025659e6ccbeb73ae5f4c6883ddb12d Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 10 Oct 2018 16:40:41 -0700 Subject: [PATCH 12/42] tilegrid: misc cleanup Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 302 +++++++++++++++++++----------- fuzzers/005-tilegrid/generate.tcl | 3 +- 2 files changed, 196 insertions(+), 109 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index c5445947..28e0f134 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -21,6 +21,19 @@ block_type_i2s = { } +def addr2btype(base_addr): + ''' + Convert integer address to block type + + Table 5-24: Frame Address Register Description + Bit Index: [25:23] + https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + "Valid block types are CLB, I/O, CLK ( 000 ), block RAM content ( 001 ), and CFG_CLB ( 010 ). A normal bitstream does not include type 011 ." + ''' + block_type_i = (base_addr >> 23) & 0x7 + return block_type_i2s[block_type_i] + + def nolr(tile_type): ''' Remove _L or _R suffix tile_type suffix, if present @@ -70,7 +83,8 @@ def load_baseaddrs(deltas_fns): line = f.read().strip() site = arg[7:-6] frame = int(line[5:5 + 8], 16) - site_baseaddr[site] = "0x%08x" % (frame & ~0x7f) + # was "0x%08x" + site_baseaddr[site] = frame & ~0x7f return site_baseaddr @@ -81,27 +95,39 @@ def make_database(tiles): database = dict() for tile in tiles: - database[tile['name']] = { - "type": tile['type'], - "sites": tile['sites'], - "grid_x": tile['grid_x'], - "grid_y": tile['grid_y'], + database[tile["name"]] = { + "type": tile["type"], + "sites": tile["sites"], + "grid_x": tile["grid_x"], + "grid_y": tile["grid_y"], } return database -def make_tile_baseaddr(tiles, site_baseaddr): +def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False): # Look up a base address by tile name - tile_baseaddr = dict() + tile_baseaddrs = dict() + verbose and print('') for tile in tiles: - for site_name in tile['sites'].keys(): - if site_name in site_baseaddr: - framebaseaddr = site_baseaddr[site_name] - tile_baseaddr[tile['name']] = [framebaseaddr, 0] + for site_name in tile["sites"].keys(): + if site_name not in site_baseaddr: + continue + framebaseaddr = site_baseaddr[site_name] + bt = addr2btype(framebaseaddr) + tile_baseaddr = tile_baseaddrs.setdefault(tile["name"], {}) + if bt in tile_baseaddr: + # actually lets just fail these, better to remove at tcl level to speed up processing + assert 0, 'duplicate base address' + assert tile_baseaddr[bt] == [framebaseaddr, 0] + else: + tile_baseaddr[bt] = [framebaseaddr, 0] + verbose and print( + "baseaddr: %s.%s @ %s.0x%08x" % + (tile["name"], site_name, bt, framebaseaddr)) - return tile_baseaddr + return tile_baseaddrs def make_tiles_by_grid(tiles): @@ -109,12 +135,12 @@ def make_tiles_by_grid(tiles): tiles_by_grid = dict() for tile in tiles: - tiles_by_grid[(tile['grid_x'], tile['grid_y'])] = tile["name"] + tiles_by_grid[(tile["grid_x"], tile["grid_y"])] = tile["name"] return tiles_by_grid -def make_segments(database, tiles_by_grid, tile_baseaddr): +def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): ''' Create segments data structure Indicates how tiles are related to bitstream locations @@ -126,6 +152,7 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): ''' segments = dict() + verbose and print('') for tile_name, tile_data in database.items(): tile_type = tile_data["type"] grid_x = tile_data["grid_x"] @@ -139,6 +166,11 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): segment["frames"] = frames segment["words"] = words if baseaddr: + verbose and print( + 'make_segment: %s baseaddr %s' % ( + name, + baseaddr, + )) segment["baseaddr"] = baseaddr for tile_name in tiles: @@ -156,7 +188,7 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): segtype=tile_type.lower(), frames=36, words=2, - baseaddr=tile_baseaddr.get(tile_name, None)) + baseaddr=tile_baseaddrs.get(tile_name, None)) def process_hclk(): add_segment( @@ -178,7 +210,11 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): int_tile_name = tiles_by_grid[(grid_x - 2, grid_y - k)] else: assert 0 - + ''' + BRAM/DSP itself is at the base y address + There is one huge switchbox on the right for the 5 tiles + These fan into 5 BRAM_INT_INTERFACE tiles each which feed into their own CENTER_INTER (just like a CLB has) + ''' if k == 0: tiles = [tile_name, interface_tile_name, int_tile_name] else: @@ -193,99 +229,148 @@ def make_segments(database, tiles_by_grid, tile_baseaddr): frames=28, words=2) + def process_default(): + #verbose and nolr(tile_type) not in ('VBRK', 'INT', 'NULL') and print('make_segment: drop %s' % (tile_type,)) + pass + { "CLBLL": process_clb, "CLBLM": process_clb, "HCLK": process_hclk, "BRAM": process_bram_dsp, "DSP": process_bram_dsp, - }.get(nolr(tile_type), lambda: None)() + }.get(nolr(tile_type), process_default)() return segments -def seg_base_addr_lr_INT(database, segments, tiles_by_grid): +def get_inttile(database, segment): + '''Return interconnect tile for given segment''' + inttiles = [ + tile for tile in segment["tiles"] + if database[tile]["type"] in ["INT_L", "INT_R"] + ] + assert len(inttiles) == 1 + return inttiles[0] + + +def seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=False): '''Populate segment base addresses: L/R along INT column''' - for segment_name in segments.keys(): - # As of this writing only CLBs, but soon to be BRAM data - if "baseaddr" not in segments[segment_name]: + ''' + Create BRAM base addresses based on nearby CLBs + ie if we have a BRAM_L, compute as nearby CLB_R base address + offset + ''' + + verbose and print('') + for segment_name in sorted(segments.keys()): + segment = segments[segment_name] + baseaddrs = segment.get("baseaddr", None) + if not baseaddrs: continue - framebase, wordbase = segments[segment_name]["baseaddr"] - inttile = [ - tile for tile in segments[segment_name]["tiles"] - if database[tile]["type"] in ["INT_L", "INT_R"] - ][0] - grid_x = database[inttile]["grid_x"] - grid_y = database[inttile]["grid_y"] + for block_type, (framebase, wordbase) in sorted(baseaddrs.items()): + verbose and print( + 'lr_INT: %s: %s.0x%08X:%u' % + (segment_name, block_type, framebase, wordbase)) + if block_type != 'CLB_IO_CLK': + verbose and print(' Skip non CLB') + continue - if database[inttile]["type"] == "INT_L": - grid_x += 1 - framebase = "0x%08x" % (int(framebase, 16) + 0x80) - else: - grid_x -= 1 - framebase = "0x%08x" % (int(framebase, 16) - 0x80) + inttile = get_inttile(database, segment) + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] - if (grid_x, grid_y) not in tiles_by_grid: - continue + if database[inttile]["type"] == "INT_L": + grid_x += 1 + framebase = framebase + 0x80 + elif database[inttile]["type"] == "INT_R": + grid_x -= 1 + framebase = framebase - 0x80 + else: + assert 0 - tile = tiles_by_grid[(grid_x, grid_y)] + # ROI at edge? + if (grid_x, grid_y) not in tiles_by_grid: + verbose and print(' Skip edge') + continue - if database[inttile]["type"] == "INT_L": - assert database[tile]["type"] == "INT_R" - elif database[inttile]["type"] == "INT_R": - assert database[tile]["type"] == "INT_L" - else: - assert 0 + tile = tiles_by_grid[(grid_x, grid_y)] - assert "segment" in database[tile] + if database[inttile]["type"] == "INT_L": + assert database[tile]["type"] == "INT_R" + elif database[inttile]["type"] == "INT_R": + assert database[tile]["type"] == "INT_L" + else: + assert 0 - seg = database[tile]["segment"] + assert "segment" in database[tile] - if "baseaddr" in segments[seg]: - assert segments[seg]["baseaddr"] == [framebase, wordbase] - else: - segments[seg]["baseaddr"] = [framebase, wordbase] + seg = database[tile]["segment"] + + seg_baseaddrs = segments[seg].setdefault("baseaddr", {}) + # At least one duplicate when we re-compute the entry for the base address + # should give the same address + if block_type in seg_baseaddrs: + assert seg_baseaddrs[block_type] == [ + framebase, wordbase + ], (seg_baseaddrs[block_type], [framebase, wordbase]) + verbose and print(' Existing OK') + else: + seg_baseaddrs[block_type] = [framebase, wordbase] + verbose and print(' Add new') -def seg_base_addr_up_INT(database, segments, tiles_by_grid): +def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): '''Populate segment base addresses: Up along INT/HCLK columns''' - start_segments = list() + verbose and print('') + ''' + All baseaddrs so far have 50 tiles above them to be derived + However, once we start deriving, this is no longer true + Copy the initial list so that any baseaddr encountered can safely be swept up + ''' + src_segment_names = list() for segment_name in segments.keys(): if "baseaddr" in segments[segment_name]: - start_segments.append(segment_name) + src_segment_names.append(segment_name) - for segment_name in start_segments: - framebase, wordbase = segments[segment_name]["baseaddr"] - inttile = [ - tile for tile in segments[segment_name]["tiles"] - if database[tile]["type"] in ["INT_L", "INT_R"] - ][0] - grid_x = database[inttile]["grid_x"] - grid_y = database[inttile]["grid_y"] + verbose and print('up_INT: %u base addresses' % len(src_segment_names)) + #verbose and print('\n'.join(sorted(src_segment_names))) - for i in range(50): - grid_y -= 1 + for src_segment_name in sorted(src_segment_names): + src_segment = segments[src_segment_name] - if wordbase == 50: - wordbase += 1 - else: - wordbase += 2 + for block_type, (framebase, + wordbase) in sorted(src_segment["baseaddr"].items()): + verbose and print( + 'up_INT: %s: %s.0x%08X:%u' % + (src_segment_name, block_type, framebase, wordbase)) + # Ignore BRAM base addresses + # TODO: BRAM data needs to be populated in its own special way + if block_type != 'CLB_IO_CLK': + verbose and print(' Skip non CLB') + continue - segname = database[tiles_by_grid[(grid_x, grid_y)]]["segment"] - segments[segname]["baseaddr"] = [framebase, wordbase] + inttile = get_inttile(database, src_segment) + verbose and print( + ' up_INT: %s => inttile %s' % (src_segment_name, inttile)) + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] + for i in range(50): + grid_y -= 1 + dst_tile = database[tiles_by_grid[(grid_x, grid_y)]] -def base_addr_2_block_type(base_addr): - ''' - Table 5-24: Frame Address Register Description - Bit Index: [25:23] - https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf - "Valid block types are CLB, I/O, CLK ( 000 ), block RAM content ( 001 ), and CFG_CLB ( 010 ). A normal bitstream does not include type 011 ." - ''' - block_type_i = (base_addr >> 23) & 0x7 - return block_type_i2s[block_type_i] + if wordbase == 50: + wordbase += 1 + else: + wordbase += 2 + + #verbose and print(' dst_tile', dst_tile) + dst_segment_name = dst_tile["segment"] + #verbose and print('up_INT: %s => %s' % (src_segment_name, dst_segment_name)) + segments[dst_segment_name].setdefault( + "baseaddr", {})[block_type] = [framebase, wordbase] def add_tile_bits(tile_db, baseaddr, offset, height): @@ -297,12 +382,12 @@ def add_tile_bits(tile_db, baseaddr, offset, height): https://github.com/SymbiFlow/prjxray/issues/145 ''' bits = tile_db.setdefault('bits', {}) - block_type = base_addr_2_block_type(int(baseaddr, 0)) + block_type = addr2btype(baseaddr) assert block_type not in bits block = bits.setdefault(block_type, {}) - block["baseaddr"] = baseaddr + block["baseaddr"] = '0x%08X' % baseaddr block["offset"] = offset block["height"] = height @@ -310,28 +395,26 @@ def add_tile_bits(tile_db, baseaddr, offset, height): def add_bits(database, segments): '''Transfer segment data into tiles''' for segment_name in segments.keys(): - try: - baseaddr, offset = segments[segment_name]["baseaddr"] - except: - print('Failed on segment name %s' % segment_name) - raise - - for tile_name in segments[segment_name]["tiles"]: - tile_type = database[tile_name]["type"] - height = { - "CLBLL": 2, - "CLBLM": 2, - "INT": 2, - "HCLK": 1, - "BRAM": 10, - "DSP": 10, - "INT_INTERFACE": 0, - "BRAM_INT_INTERFACE": 0, - }.get(nolr(tile_type), None) - if height is None: - raise ValueError("Unknown tile type %s" % tile_type) - if height: - add_tile_bits(database[tile_name], baseaddr, offset, height) + for _block_type, ( + baseaddr, + offset) in segments[segment_name]["baseaddr"].items(): + for tile_name in segments[segment_name]["tiles"]: + tile_type = database[tile_name]["type"] + height = { + "CLBLL": 2, + "CLBLM": 2, + "INT": 2, + "HCLK": 1, + "BRAM": 10, + "DSP": 10, + "INT_INTERFACE": 0, + "BRAM_INT_INTERFACE": 0, + }.get(nolr(tile_type), None) + if height is None: + raise ValueError("Unknown tile type %s" % tile_type) + if height: + add_tile_bits( + database[tile_name], baseaddr, offset, height) def annotate_segments(database, segments): @@ -346,25 +429,28 @@ def annotate_segments(database, segments): tiledata["segment_type"] = segments[segment]["type"] -def run(tiles_fn, json_fn, deltas_fns): +def run(tiles_fn, json_fn, deltas_fns, verbose=False): # Load input files tiles = load_tiles(tiles_fn) site_baseaddr = load_baseaddrs(deltas_fns) # Index input database = make_database(tiles) - tile_baseaddr = make_tile_baseaddr(tiles, site_baseaddr) + tile_baseaddrs = make_tile_baseaddrs(tiles, site_baseaddr, verbose=verbose) tiles_by_grid = make_tiles_by_grid(tiles) - segments = make_segments(database, tiles_by_grid, tile_baseaddr) + segments = make_segments( + database, tiles_by_grid, tile_baseaddrs, verbose=verbose) # Reference adjacent CLBs to locate adjacent tiles by known offsets - seg_base_addr_lr_INT(database, segments, tiles_by_grid) - seg_base_addr_up_INT(database, segments, tiles_by_grid) + seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=verbose) + seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=verbose) add_bits(database, segments) annotate_segments(database, segments) + #database = {'BRAM_L_X6Y50': database["BRAM_L_X6Y50"]} + # Save json.dump( database, @@ -390,7 +476,7 @@ def main(): 'deltas', nargs='+', help='.bit diffs to create base addresses from') args = parser.parse_args() - run(args.tiles, args.out, args.deltas) + run(args.tiles, args.out, args.deltas, verbose=args.verbose) if __name__ == '__main__': diff --git a/fuzzers/005-tilegrid/generate.tcl b/fuzzers/005-tilegrid/generate.tcl index eb1e49f7..943c71fe 100644 --- a/fuzzers/005-tilegrid/generate.tcl +++ b/fuzzers/005-tilegrid/generate.tcl @@ -34,7 +34,8 @@ proc loc_luts {} { # 50 per column => 50, 100, 150, etc # ex: SLICE_X2Y50/A6LUT - if [regexp "Y.*[05]0/" $lut] { + # Only take one of the CLBs within a slice + if [regexp "X.*[02468]Y.*[05]0/" $lut] { set cell [get_cells roi/luts[$lut_index].lut] set_property LOC [get_sites -of_objects $lut] $cell set lut_index [expr $lut_index + 1] From 9e664fa5bd0013f072f4b873790338f41e7ed98d Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 10 Oct 2018 18:10:31 -0700 Subject: [PATCH 13/42] tilegrid BRAM: base BLOCK_RAM entry Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 28e0f134..ba8cef09 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -217,8 +217,10 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): ''' if k == 0: tiles = [tile_name, interface_tile_name, int_tile_name] + baseaddr = tile_baseaddrs.get(tile_name, None) else: tiles = [interface_tile_name, int_tile_name] + baseaddr = None add_segment( # BRAM_L_X6Y70 => SEG_BRAM4_L_X6Y70 @@ -227,7 +229,8 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): # BRAM_L => bram4_l segtype=tile_type.lower().replace("_", "%d_" % k, 1), frames=28, - words=2) + words=2, + baseaddr=baseaddr) def process_default(): #verbose and nolr(tile_type) not in ('VBRK', 'INT', 'NULL') and print('make_segment: drop %s' % (tile_type,)) @@ -449,8 +452,6 @@ def run(tiles_fn, json_fn, deltas_fns, verbose=False): add_bits(database, segments) annotate_segments(database, segments) - #database = {'BRAM_L_X6Y50': database["BRAM_L_X6Y50"]} - # Save json.dump( database, From b99ed31ba1113e4fb7961d8ab8d36050c63bf6d5 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 10 Oct 2018 18:44:44 -0700 Subject: [PATCH 14/42] tilegrid: BRAM loosely working, needs real offsets Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 94 ++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 22 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index ba8cef09..5411792b 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -257,6 +257,15 @@ def get_inttile(database, segment): return inttiles[0] +def get_bramtile(database, segment): + inttiles = [ + tile for tile in segment["tiles"] + if database[tile]["type"] in ["BRAM_L", "BRAM_R"] + ] + assert len(inttiles) == 1 + return inttiles[0] + + def seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=False): '''Populate segment base addresses: L/R along INT column''' ''' @@ -348,32 +357,71 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): verbose and print( 'up_INT: %s: %s.0x%08X:%u' % (src_segment_name, block_type, framebase, wordbase)) - # Ignore BRAM base addresses - # TODO: BRAM data needs to be populated in its own special way - if block_type != 'CLB_IO_CLK': - verbose and print(' Skip non CLB') - continue - inttile = get_inttile(database, src_segment) - verbose and print( - ' up_INT: %s => inttile %s' % (src_segment_name, inttile)) - grid_x = database[inttile]["grid_x"] - grid_y = database[inttile]["grid_y"] + def process_CLB_IO_CLK(wordbase): + ''' + Lookup interconnect tile associated with this segment + Use it to locate in the grid, and find other segments related by tile offset + ''' - for i in range(50): - grid_y -= 1 - dst_tile = database[tiles_by_grid[(grid_x, grid_y)]] + inttile = get_inttile(database, src_segment) + verbose and print( + ' up_INT CLK_IO_CLK: %s => inttile %s' % + (src_segment_name, inttile)) + grid_x = database[inttile]["grid_x"] + grid_y = database[inttile]["grid_y"] - if wordbase == 50: - wordbase += 1 - else: - wordbase += 2 + for i in range(50): + grid_y -= 1 + dst_tile = database[tiles_by_grid[(grid_x, grid_y)]] - #verbose and print(' dst_tile', dst_tile) - dst_segment_name = dst_tile["segment"] - #verbose and print('up_INT: %s => %s' % (src_segment_name, dst_segment_name)) - segments[dst_segment_name].setdefault( - "baseaddr", {})[block_type] = [framebase, wordbase] + if wordbase == 50: + wordbase += 1 + else: + wordbase += 2 + + #verbose and print(' dst_tile', dst_tile) + dst_segment_name = dst_tile["segment"] + #verbose and print('up_INT: %s => %s' % (src_segment_name, dst_segment_name)) + segments[dst_segment_name].setdefault( + "baseaddr", {})[block_type] = [framebase, wordbase] + + def process_BLOCK_RAM(wordbase): + ''' + Lookup BRAM0 tile associated with this segment + Use it to locate in the grid, and find other BRAM0 related by tile offset + ''' + src_tile_name = get_bramtile(database, src_segment) + verbose and print( + ' up_INT BLOCK_RAM: %s => %s' % + (src_segment_name, src_tile_name)) + grid_x = database[src_tile_name]["grid_x"] + grid_y = database[src_tile_name]["grid_y"] + + for i in range(9): + grid_y -= 5 + if i == 4: + grid_y -= 1 + + dst_tile = database[tiles_by_grid[(grid_x, grid_y)]] + assert nolr(dst_tile['type']) == 'BRAM', dst_tile + + # FIXME: get actual numbers + if i == 4: + wordbase += 1 + else: + wordbase += 2 + + dst_segment_name = dst_tile["segment"] + assert 'BRAM0' in dst_segment_name + segments[dst_segment_name].setdefault( + "baseaddr", {})[block_type] = [framebase, wordbase] + + { + 'CLB_IO_CLK': process_CLB_IO_CLK, + 'BLOCK_RAM': process_BLOCK_RAM, + }[block_type]( + wordbase) def add_tile_bits(tile_db, baseaddr, offset, height): @@ -452,6 +500,8 @@ def run(tiles_fn, json_fn, deltas_fns, verbose=False): add_bits(database, segments) annotate_segments(database, segments) + #database = {'BRAM_L_X6Y50': database["BRAM_L_X6Y50"], 'BRAM_L_X6Y80': database["BRAM_L_X6Y80"]} + # Save json.dump( database, From 833fa503c03307069a7f784e384145be8ca5de9b Mon Sep 17 00:00:00 2001 From: John McMaster Date: Mon, 15 Oct 2018 16:21:04 -0700 Subject: [PATCH 15/42] tilegrid: add comments Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 61 ++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 5411792b..76617834 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -213,7 +213,7 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): ''' BRAM/DSP itself is at the base y address There is one huge switchbox on the right for the 5 tiles - These fan into 5 BRAM_INT_INTERFACE tiles each which feed into their own CENTER_INTER (just like a CLB has) + These fan into 5 BRAM_INT_INTERFACE tiles each which feed into their own CENTER_INTER (just like a CLB has) ''' if k == 0: tiles = [tile_name, interface_tile_name, int_tile_name] @@ -270,7 +270,7 @@ def seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=False): '''Populate segment base addresses: L/R along INT column''' ''' Create BRAM base addresses based on nearby CLBs - ie if we have a BRAM_L, compute as nearby CLB_R base address + offset + ie if we have a BRAM_L, compute as nearby CLB_R base address + offset ''' verbose and print('') @@ -336,18 +336,14 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): '''Populate segment base addresses: Up along INT/HCLK columns''' verbose and print('') - ''' - All baseaddrs so far have 50 tiles above them to be derived - However, once we start deriving, this is no longer true - Copy the initial list so that any baseaddr encountered can safely be swept up - ''' + # Copy the initial list containing only base addresses + # and soon to have derived addresses src_segment_names = list() for segment_name in segments.keys(): if "baseaddr" in segments[segment_name]: src_segment_names.append(segment_name) verbose and print('up_INT: %u base addresses' % len(src_segment_names)) - #verbose and print('\n'.join(sorted(src_segment_names))) for src_segment_name in sorted(src_segment_names): src_segment = segments[src_segment_name] @@ -390,6 +386,24 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): ''' Lookup BRAM0 tile associated with this segment Use it to locate in the grid, and find other BRAM0 related by tile offset + + + From minitest: + + build/roi_bramd_bit01.diff (lowest BRAM coordinate) + > bit_00c00000_000_00 + + build/roi_bramds_bit01.diff + > bit_00c00000_000_00 + > bit_00c00000_010_00 + > bit_00c00000_020_00 + > bit_00c00000_030_00 + > bit_00c00000_040_00 + > bit_00c00000_051_00 + > bit_00c00000_061_00 + > bit_00c00000_071_00 + > bit_00c00000_081_00 + > bit_00c00000_091_00 ''' src_tile_name = get_bramtile(database, src_segment) verbose and print( @@ -400,18 +414,15 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): for i in range(9): grid_y -= 5 + wordbase += 0x10 + # Skip HCLK if i == 4: grid_y -= 1 + wordbase += 1 dst_tile = database[tiles_by_grid[(grid_x, grid_y)]] assert nolr(dst_tile['type']) == 'BRAM', dst_tile - # FIXME: get actual numbers - if i == 4: - wordbase += 1 - else: - wordbase += 2 - dst_segment_name = dst_tile["segment"] assert 'BRAM0' in dst_segment_name segments[dst_segment_name].setdefault( @@ -438,10 +449,14 @@ def add_tile_bits(tile_db, baseaddr, offset, height): assert block_type not in bits block = bits.setdefault(block_type, {}) + # FDRI base address block["baseaddr"] = '0x%08X' % baseaddr + # FDRI offset from baseaddr block["offset"] = offset + # Number of words consumed (was: "words") block["height"] = height - + # Number of frames this entry is sretched across + #block["frames"] = frames def add_bits(database, segments): '''Transfer segment data into tiles''' @@ -452,14 +467,14 @@ def add_bits(database, segments): for tile_name in segments[segment_name]["tiles"]: tile_type = database[tile_name]["type"] height = { - "CLBLL": 2, - "CLBLM": 2, - "INT": 2, - "HCLK": 1, - "BRAM": 10, - "DSP": 10, - "INT_INTERFACE": 0, - "BRAM_INT_INTERFACE": 0, + "CLBLL": 2, + "CLBLM": 2, + "INT": 2, + "HCLK": 1, + "BRAM": 10, + "DSP": 10, + "INT_INTERFACE": 0, + "BRAM_INT_INTERFACE": 0, }.get(nolr(tile_type), None) if height is None: raise ValueError("Unknown tile type %s" % tile_type) From 8763438cff8681b5b08ffbc7d8c29f498f8a49d6 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Mon, 15 Oct 2018 17:39:13 -0700 Subject: [PATCH 16/42] tilegrid: consolidate setting frames, words, heights Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 85 +++++++++++++++++++------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 76617834..81fcfdfd 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -158,13 +158,11 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): grid_x = tile_data["grid_x"] grid_y = tile_data["grid_y"] - def add_segment(name, tiles, segtype, frames, words, baseaddr=None): + def add_segment(name, tiles, segtype, baseaddr=None): assert name not in segments segment = segments.setdefault(name, {}) segment["tiles"] = tiles segment["type"] = segtype - segment["frames"] = frames - segment["words"] = words if baseaddr: verbose and print( 'make_segment: %s baseaddr %s' % ( @@ -186,17 +184,13 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): name="SEG_" + tile_name, tiles=[tile_name, int_tile_name], segtype=tile_type.lower(), - frames=36, - words=2, baseaddr=tile_baseaddrs.get(tile_name, None)) def process_hclk(): add_segment( name="SEG_" + tile_name, tiles=[tile_name], - segtype=tile_type.lower(), - frames=26, - words=1) + segtype=tile_type.lower()) def process_bram_dsp(): for k in range(5): @@ -228,8 +222,6 @@ def make_segments(database, tiles_by_grid, tile_baseaddrs, verbose=False): tiles=tiles, # BRAM_L => bram4_l segtype=tile_type.lower().replace("_", "%d_" % k, 1), - frames=28, - words=2, baseaddr=baseaddr) def process_default(): @@ -414,7 +406,7 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): for i in range(9): grid_y -= 5 - wordbase += 0x10 + wordbase += 10 # Skip HCLK if i == 4: grid_y -= 1 @@ -435,7 +427,7 @@ def seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=False): wordbase) -def add_tile_bits(tile_db, baseaddr, offset, height): +def add_tile_bits(tile_db, baseaddr, offset, frames, words, height=None): ''' Record data structure geometry for the given tile baseaddr For most tiles there is only one baseaddr, but some like BRAM have multiple @@ -443,47 +435,69 @@ def add_tile_bits(tile_db, baseaddr, offset, height): Notes on multiple block types: https://github.com/SymbiFlow/prjxray/issues/145 ''' + bits = tile_db.setdefault('bits', {}) block_type = addr2btype(baseaddr) + assert 0 <= offset <= 100, offset + assert 1 <= words <= 101 + assert offset + words <= 101, ( + tile_db, offset + words, offset, words, block_type) + assert block_type not in bits block = bits.setdefault(block_type, {}) - # FDRI base address + # FDRI address block["baseaddr"] = '0x%08X' % baseaddr - # FDRI offset from baseaddr - block["offset"] = offset - # Number of words consumed (was: "words") - block["height"] = height # Number of frames this entry is sretched across - #block["frames"] = frames + # that is the following FDRI addresses are used: range(baseaddr, baseaddr + frames) + block["frames"] = frames + + # Index of first word used within each frame + block["offset"] = offset + # Number of words consumed in each frame + block["words"] = words + + # related to words... + # deprecated field? Don't worry about for now + if height is not None: + block["height"] = height + def add_bits(database, segments): '''Transfer segment data into tiles''' for segment_name in segments.keys(): - for _block_type, ( - baseaddr, - offset) in segments[segment_name]["baseaddr"].items(): + for block_type, (baseaddr, + offset) in segments[segment_name]["baseaddr"].items(): for tile_name in segments[segment_name]["tiles"]: tile_type = database[tile_name]["type"] - height = { - "CLBLL": 2, - "CLBLM": 2, - "INT": 2, - "HCLK": 1, - "BRAM": 10, - "DSP": 10, - "INT_INTERFACE": 0, - "BRAM_INT_INTERFACE": 0, - }.get(nolr(tile_type), None) - if height is None: - raise ValueError("Unknown tile type %s" % tile_type) - if height: + entry = { + # (tile_type, block_type): (frames, words, height) + ("CLBLL", "CLB_IO_CLK"): (36, 2, 2), + ("CLBLM", "CLB_IO_CLK"): (36, 2, 2), + ("HCLK", "CLB_IO_CLK"): (26, 1, 1), + ("INT", "CLB_IO_CLK"): (28, 2, 2), + ("BRAM", "CLB_IO_CLK"): (28, 2, None), + ("BRAM", "BLOCK_RAM"): (128, 5, None), + ("DSP", "CLB_IO_CLK"): (28, 2, 10), + ("INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None), + ("BRAM_INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None), + }.get((nolr(tile_type), block_type), None) + if entry is None: + if block_type == "CLB_IO_CLK": + raise ValueError("Unknown tile type %s" % tile_type) + continue + frames, words, height = entry + if frames: + # if we have a width, we should have a height + assert frames and words add_tile_bits( - database[tile_name], baseaddr, offset, height) + database[tile_name], baseaddr, offset, frames, words, + height) def annotate_segments(database, segments): + ''' # TODO: Migrate to new tilegrid format via library. This data is added for # compability with unconverted tools. Update tools then remove this data from # tilegrid.json. @@ -493,6 +507,7 @@ def annotate_segments(database, segments): tiledata["frames"] = segments[segment]["frames"] tiledata["words"] = segments[segment]["words"] tiledata["segment_type"] = segments[segment]["type"] + ''' def run(tiles_fn, json_fn, deltas_fns, verbose=False): From 538344f192bc126a82cdad5b221e9776ea86d951 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Mon, 15 Oct 2018 17:46:21 -0700 Subject: [PATCH 17/42] Remove 070-tileconn, favoring 074-dump_all Signed-off-by: John McMaster --- fuzzers/070-tileconn/.gitignore | 3 - fuzzers/070-tileconn/Makefile | 26 ------- fuzzers/070-tileconn/generate.py | 117 ------------------------------ fuzzers/070-tileconn/generate.sh | 8 -- fuzzers/070-tileconn/generate.tcl | 29 -------- fuzzers/070-tileconn/top.v | 3 - 6 files changed, 186 deletions(-) delete mode 100644 fuzzers/070-tileconn/.gitignore delete mode 100644 fuzzers/070-tileconn/Makefile delete mode 100644 fuzzers/070-tileconn/generate.py delete mode 100644 fuzzers/070-tileconn/generate.sh delete mode 100644 fuzzers/070-tileconn/generate.tcl delete mode 100644 fuzzers/070-tileconn/top.v diff --git a/fuzzers/070-tileconn/.gitignore b/fuzzers/070-tileconn/.gitignore deleted file mode 100644 index 6e99ca40..00000000 --- a/fuzzers/070-tileconn/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/specimen_*/ -/tileconn.json -/run.ok diff --git a/fuzzers/070-tileconn/Makefile b/fuzzers/070-tileconn/Makefile deleted file mode 100644 index 73b0a649..00000000 --- a/fuzzers/070-tileconn/Makefile +++ /dev/null @@ -1,26 +0,0 @@ - -N := 1 -SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) -SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) - -database: $(SPECIMENS_OK) - cp specimen_001/tileconn.json tileconn.json - -pushdb: - cp tileconn.json ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/tileconn.json - -$(SPECIMENS_OK): - bash generate.sh $(subst /OK,,$@) - touch $@ - -run: - $(MAKE) clean - $(MAKE) database - $(MAKE) pushdb - touch run.ok - -clean: - rm -rf specimen_[0-9][0-9][0-9]/ tileconn.json run.ok - -.PHONY: database pushdb run clean - diff --git a/fuzzers/070-tileconn/generate.py b/fuzzers/070-tileconn/generate.py deleted file mode 100644 index 7a707ac8..00000000 --- a/fuzzers/070-tileconn/generate.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python3 - -import os, sys, json, re - -tilenodes = dict() -grid2tile = dict() -database = dict() - -print("Loading %s grid." % os.getenv("XRAY_DATABASE")) -with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"), - os.getenv("XRAY_DATABASE")), "r") as f: - grid = json.load(f) - -for tile, tiledata in grid.items(): - grid_xy = (tiledata["grid_x"], tiledata["grid_y"]) - grid2tile[grid_xy] = tile - -print("Loading nodewires.txt.") -with open("nodewires.txt") as f: - for line in f: - node, *wires = line.split() - for wire in wires: - wire_tile, wire_name = wire.split("/") - if wire_tile not in tilenodes: - tilenodes[wire_tile] = dict() - tilenodes[wire_tile][node] = wire_name - - -def filter_pair(type1, type2, wire1, wire2, delta_x, delta_y): - if type1 in ["HCLK_L", "HCLK_R"]: - is_vertical_wire = False - if wire1.startswith("HCLK_S"): is_vertical_wire = True - if wire1.startswith("HCLK_N"): is_vertical_wire = True - if wire1.startswith("HCLK_W"): is_vertical_wire = True - if wire1.startswith("HCLK_E"): is_vertical_wire = True - if wire1.startswith("HCLK_LV"): is_vertical_wire = True - if wire1.startswith("HCLK_BYP"): is_vertical_wire = True - if wire1.startswith("HCLK_FAN"): is_vertical_wire = True - if wire1.startswith("HCLK_LEAF_CLK_"): is_vertical_wire = True - - is_horizontal_wire = False - if wire1.startswith("HCLK_CK_"): is_horizontal_wire = True - if wire1.startswith("HCLK_INT_"): is_horizontal_wire = True - - assert is_vertical_wire != is_horizontal_wire - if is_vertical_wire and delta_y == 0: return True - if is_horizontal_wire and delta_x == 0: return True - - if type1 in ["INT_L", "INT_R"]: - # the wires with underscore after BEG/END all connect vertically - if (("BEG_" in wire1) or ("END_" in wire1)) and delta_y == 0: - return True - - if type1 in ["BRKH_INT", "BRKH_B_TERM_INT", "T_TERM_INT"]: - if delta_y == 0: return True - - return False - - -def handle_pair(tile1, tile2): - if tile1 not in tilenodes: return - if tile2 not in tilenodes: return - - tile1data = grid[tile1] - tile2data = grid[tile2] - - grid1_xy = (tile1data["grid_x"], tile1data["grid_y"]) - grid2_xy = (tile2data["grid_x"], tile2data["grid_y"]) - - if grid1_xy > grid2_xy: - return handle_pair(tile2, tile1) - - key = ( - tile1data["type"], tile2data["type"], grid2_xy[0] - grid1_xy[0], - grid2_xy[1] - grid1_xy[1]) - - wire_pairs = set() - - for node, wire1 in tilenodes[tile1].items(): - if node in tilenodes[tile2]: - wire2 = tilenodes[tile2][node] - if filter_pair(key[0], key[1], wire1, wire2, key[2], key[3]): - continue - if filter_pair(key[1], key[0], wire2, wire1, -key[2], -key[3]): - continue - wire_pairs.add((wire1, wire2)) - - if key not in database: - database[key] = wire_pairs - else: - database[key] &= wire_pairs - - -for tile, tiledata in grid.items(): - grid_right_xy = (tiledata["grid_x"] + 1, tiledata["grid_y"]) - grid_below_xy = (tiledata["grid_x"], tiledata["grid_y"] + 1) - - if grid_right_xy in grid2tile: - handle_pair(tile, grid2tile[grid_right_xy]) - - if grid_below_xy in grid2tile: - handle_pair(tile, grid2tile[grid_below_xy]) - -print("Converting database.") -json_db = list() -for key in sorted(database.keys()): - (t1, t2, dx, dy) = key - entry = dict() - entry["tile_types"] = [t1, t2] - entry["grid_deltas"] = [dx, dy] - entry["wire_pairs"] = list(sorted(database[key])) - if len(entry["wire_pairs"]): - json_db.append(entry) - -print("Writing tileconn.json.") -with open("tileconn.json", "w") as f: - print(json.dumps(json_db, sort_keys=True, indent="\t"), file=f) diff --git a/fuzzers/070-tileconn/generate.sh b/fuzzers/070-tileconn/generate.sh deleted file mode 100644 index f639d561..00000000 --- a/fuzzers/070-tileconn/generate.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -x - -source ${XRAY_GENHEADER} - -vivado -mode batch -source ../generate.tcl - -python3 ../generate.py - diff --git a/fuzzers/070-tileconn/generate.tcl b/fuzzers/070-tileconn/generate.tcl deleted file mode 100644 index 71ea0321..00000000 --- a/fuzzers/070-tileconn/generate.tcl +++ /dev/null @@ -1,29 +0,0 @@ -create_project -force -part $::env(XRAY_PART) design design - -read_verilog ../top.v -synth_design -top top - -set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports a] -set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports y] - -create_pblock roi -resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" - -set_property CFGBVS VCCO [current_design] -set_property CONFIG_VOLTAGE 3.3 [current_design] -set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] -set_param tcl.collectionResultDisplayLimit 0 - -place_design -route_design - -write_checkpoint -force design.dcp -# write_bitstream -force design.bit - -source ../../../utils/utils.tcl - -set fp [open "nodewires.txt" w] -foreach node [get_nodes -of_objects [roi_tiles]] { - puts $fp "$node [get_wires -of_objects $node]" -} -close $fp diff --git a/fuzzers/070-tileconn/top.v b/fuzzers/070-tileconn/top.v deleted file mode 100644 index 5a70fc18..00000000 --- a/fuzzers/070-tileconn/top.v +++ /dev/null @@ -1,3 +0,0 @@ -module top(input a, output y); - assign y = a; -endmodule From 7cfd30483fdce0b404694fe42cb72be8843d6785 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Mon, 15 Oct 2018 18:39:06 -0700 Subject: [PATCH 18/42] segmaker: split site / tile tags Signed-off-by: John McMaster --- fuzzers/010-lutinit/generate.py | 2 +- utils/segmaker.py | 90 +++++++++++++++++---------------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/fuzzers/010-lutinit/generate.py b/fuzzers/010-lutinit/generate.py index b023af44..4b92c86d 100644 --- a/fuzzers/010-lutinit/generate.py +++ b/fuzzers/010-lutinit/generate.py @@ -18,7 +18,7 @@ with open("design_%s.txt" % sys.argv[1], "r") as f: for i in range(64): bitname = "%s.INIT[%02d]" % (bel, i) bitname = bitname.replace("6LUT", "LUT") - segmk.addtag(site, bitname, ((init >> i) & 1) != 0) + segmk.add_site_tag(site, bitname, ((init >> i) & 1) != 0) segmk.compile() segmk.write(sys.argv[1]) diff --git a/utils/segmaker.py b/utils/segmaker.py index 3d43dec2..b1a7339b 100644 --- a/utils/segmaker.py +++ b/utils/segmaker.py @@ -15,6 +15,8 @@ import os, json, re XRAY_DATABASE = os.getenv("XRAY_DATABASE") XRAY_DIR = os.getenv("XRAY_DIR") +BLOCK_TYPES = set(('CLB_IO_CLK', 'BLOCK_RAM', 'CFG_CLB')) + def recurse_sum(x): '''Count number of nested iterable occurances''' @@ -46,7 +48,8 @@ class segmaker: -site: ex 'SLICE_X13Y101' -name: ex 'CLB.SLICE_X0.AFF.DMUX.CY' ''' - self.tags = dict() + self.site_tags = dict() + self.tile_tags = dict() # output after compiling self.segments_by_type = None @@ -94,7 +97,7 @@ class segmaker: 'Loaded bits: %u bits in %u base frames' % (recurse_sum(self.bits), len(self.bits))) - def addtag(self, site_tile, name, value): + def add_site_tag(self, site, name, value): ''' XXX: can add tags in two ways: -By site name @@ -107,7 +110,10 @@ class segmaker: self.addtag('SLICE_X13Y101', 'CLB.SLICE_X0.AFF.DMUX.CY', 1) Indicates that the SLICE_X13Y101 site has an element called 'CLB.SLICE_X0.AFF.DMUX.CY' ''' - self.tags.setdefault(site_tile, dict())[name] = value + self.site_tags.setdefault(site, dict())[name] = value + + def add_site_tag(self, tile, name, value): + self.tile_tags.setdefault(tile, dict())[name] = value def compile(self, bitfilter=None): print("Compiling segment data.") @@ -131,26 +137,34 @@ class segmaker: tiledata: tilegrid info for this tile ''' assert segname not in segments - segments[segname] = {"bits": set(), "tags": dict()} + segment = segments.setdefault( + segment, { + "bits": {}, + "tags": dict() + }) - base_frame = json_hex2i(tiledata["baseaddr"]) - for wordidx in range(tiledata["offset"], - tiledata["offset"] + tiledata["height"]): - if base_frame not in self.bits: - continue - if wordidx not in self.bits[base_frame]: - continue - for bit_frame, bit_wordidx, bit_bitidx in self.bits[ - base_frame][wordidx]: - bitname_frame = bit_frame - base_frame - bitname_bit = 32 * ( - bit_wordidx - tiledata["offset"]) + bit_bitidx - # some bits are hard to de-correlate - # allow force dropping some bits from search space for practicality - if bitfilter is None or bitfilter(bitname_frame, - bitname_bit): - bitname = "%02d_%02d" % (bitname_frame, bitname_bit) - segments[segname]["bits"].add(bitname) + for block_type, bitj in segment['bits'].items(): + segment["bits"][block_type] = set() + + base_frame = json_hex2i(bitj["baseaddr"]) + for wordidx in range(bitj["offset"], + bitj["offset"] + bitj["height"]): + if base_frame not in self.bits: + continue + if wordidx not in self.bits[base_frame]: + continue + for bit_frame, bit_wordidx, bit_bitidx in self.bits[ + base_frame][wordidx]: + bitname_frame = bit_frame - base_frame + bitname_bit = 32 * ( + bit_wordidx - bitj["offset"]) + bit_bitidx + # some bits are hard to de-correlate + # allow force dropping some bits from search space for practicality + if bitfilter is None or bitfilter(bitname_frame, + bitname_bit): + bitname = "%02d_%02d" % ( + bitname_frame, bitname_bit) + segment["bits"][block_type].add(bitname) ''' XXX: wouldn't it be better to iterate over tags? Easy to drop tags @@ -163,7 +177,7 @@ class segmaker: add_segbits( segments, segname, tiledata, bitfilter=bitfilter) - for name, value in self.tags[tilename].items(): + for name, value in self.tile_tags[tilename].items(): tags_used.add((tilename, name)) tag = "%s.%s" % (tile_type_norm, name) segments[segname]["tags"][tag] = value @@ -188,7 +202,7 @@ class segmaker: else: assert 0, 'Unhandled site type' - for name, value in self.tags[site].items(): + for name, value in self.site_tags[site].items(): tags_used.add((site, name)) tag = "%s.%s.%s" % (tile_type_norm, sitekey, name) # XXX: does this come from name? @@ -197,7 +211,7 @@ class segmaker: segments[segname]["tags"][tag] = value # ignore dummy tiles (ex: VBRK) - if "baseaddr" not in tiledata: + if "bits" not in tiledata: continue tile_type = tiledata["type"] @@ -216,12 +230,12 @@ class segmaker: tiledata["offset"]) # process tile name tags - if tilename in self.tags: + if tilename in self.tile_tags: add_tilename_tags() # process site name tags for site in tiledata["sites"]: - if site not in self.tags: + if site not in self.site_tags: continue add_site_tags() @@ -244,19 +258,9 @@ class segmaker: with open(filename, "w") as f: segments = self.segments_by_type[segtype] - if True: - for segname, segdata in sorted(segments.items()): - print("seg %s" % segname, file=f) - for bitname in sorted(segdata["bits"]): - print("bit %s" % bitname, file=f) - for tagname, tagval in sorted(segdata["tags"].items()): - print("tag %s %d" % (tagname, tagval), file=f) - else: - print("seg roi", file=f) - for segname, segdata in sorted(segments.items()): - for bitname in sorted(segdata["bits"]): - print("bit %s_%s" % (segname, bitname), file=f) - for tagname, tagval in sorted(segdata["tags"].items()): - print( - "tag %s_%s %d" % (segname, tagname, tagval), - file=f) + for segname, segdata in sorted(segments.items()): + print("seg %s" % segname, file=f) + for bitname in sorted(segdata["bits"]): + print("bit %s" % bitname, file=f) + for tagname, tagval in sorted(segdata["tags"].items()): + print("tag %s %d" % (tagname, tagval), file=f) From e851f414075180870f896b972a0fc1a5ba2f38bb Mon Sep 17 00:00:00 2001 From: John McMaster Date: Mon, 15 Oct 2018 19:10:20 -0700 Subject: [PATCH 19/42] segmaker: tilegrid fixes Signed-off-by: John McMaster --- utils/segmaker.py | 84 +++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/utils/segmaker.py b/utils/segmaker.py index b1a7339b..daf68302 100644 --- a/utils/segmaker.py +++ b/utils/segmaker.py @@ -1,4 +1,6 @@ ''' +NOTE: "segments" as used in this file is mostly unrelated to tilegrid.json usage +ie tilegrid.json has names like SEG_CLBLL_L_X2Y50 where as here they are tile based and named like seg_00400100_02 Sample segdata.txt output (from 015-clbnffmux/specimen_001/segdata_clbll_r.txt): seg 00020880_048 @@ -38,7 +40,9 @@ def json_hex2i(s): class segmaker: - def __init__(self, bitsfile, verbose=False): + def __init__(self, bitsfile, verbose=None): + self.verbose = verbose if verbose is not None else os.getenv( + 'VERBOSE', 'N') == 'Y' self.verbose = verbose self.load_grid() self.load_bits(bitsfile) @@ -112,7 +116,7 @@ class segmaker: ''' self.site_tags.setdefault(site, dict())[name] = value - def add_site_tag(self, tile, name, value): + def add_tile_tag(self, tile, name, value): self.tile_tags.setdefault(tile, dict())[name] = value def compile(self, bitfilter=None): @@ -138,33 +142,29 @@ class segmaker: ''' assert segname not in segments segment = segments.setdefault( - segment, { - "bits": {}, + segname, { + "bits": set(), "tags": dict() }) - for block_type, bitj in segment['bits'].items(): - segment["bits"][block_type] = set() - - base_frame = json_hex2i(bitj["baseaddr"]) - for wordidx in range(bitj["offset"], - bitj["offset"] + bitj["height"]): - if base_frame not in self.bits: - continue - if wordidx not in self.bits[base_frame]: - continue - for bit_frame, bit_wordidx, bit_bitidx in self.bits[ - base_frame][wordidx]: - bitname_frame = bit_frame - base_frame - bitname_bit = 32 * ( - bit_wordidx - bitj["offset"]) + bit_bitidx - # some bits are hard to de-correlate - # allow force dropping some bits from search space for practicality - if bitfilter is None or bitfilter(bitname_frame, - bitname_bit): - bitname = "%02d_%02d" % ( - bitname_frame, bitname_bit) - segment["bits"][block_type].add(bitname) + base_frame = json_hex2i(bitj["baseaddr"]) + for wordidx in range(bitj["offset"], + bitj["offset"] + bitj["height"]): + if base_frame not in self.bits: + continue + if wordidx not in self.bits[base_frame]: + continue + for bit_frame, bit_wordidx, bit_bitidx in self.bits[ + base_frame][wordidx]: + bitname_frame = bit_frame - base_frame + bitname_bit = 32 * ( + bit_wordidx - bitj["offset"]) + bit_bitidx + # some bits are hard to de-correlate + # allow force dropping some bits from search space for practicality + if bitfilter is None or bitfilter(bitname_frame, + bitname_bit): + bitname = "%02d_%02d" % (bitname_frame, bitname_bit) + segment["bits"].add(bitname) ''' XXX: wouldn't it be better to iterate over tags? Easy to drop tags @@ -224,23 +224,25 @@ class segmaker: ''' tile_type_norm = re.sub("(LL|LM)?_[LR]$", "", tile_type) - segname = "%s_%03d" % ( - # truncate 0x to leave hex string - tiledata["baseaddr"][2:], - tiledata["offset"]) + for block_type, bitj in tiledata['bits'].items(): + # NOTE: multiple tiles may have the same base addr + offset + segname = "%s_%03d" % ( + # truncate 0x to leave hex string + bitj["baseaddr"][2:], + bitj["offset"]) - # process tile name tags - if tilename in self.tile_tags: - add_tilename_tags() + # process tile name tags + if tilename in self.tile_tags: + add_tilename_tags() - # process site name tags - for site in tiledata["sites"]: - if site not in self.site_tags: - continue - add_site_tags() + # process site name tags + for site in tiledata["sites"]: + if site not in self.site_tags: + continue + add_site_tags() if self.verbose: - ntags = recurse_sum(self.tags) + ntags = recurse_sum(self.site_tags) + recurse_sum(self.tile_tags) print("Used %u / %u tags" % (len(tags_used), ntags)) print("Grid DB had %u tile types" % len(tile_types_found)) assert ntags and ntags == len(tags_used) @@ -248,6 +250,10 @@ class segmaker: def write(self, suffix=None, roi=False): assert self.segments_by_type, 'No data to write' + assert sum( + [len(segments) for segments in self.segments_by_type.values() + ]) != 0 + for segtype in self.segments_by_type.keys(): if suffix is not None: filename = "segdata_%s_%s.txt" % (segtype.lower(), suffix) From a5c281a4db0055f062ab76c0700d6f9f780ff271 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Mon, 15 Oct 2018 19:20:24 -0700 Subject: [PATCH 20/42] segmaker: assert segment definitions are consistent Signed-off-by: John McMaster --- utils/segmaker.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/utils/segmaker.py b/utils/segmaker.py index daf68302..dc85541b 100644 --- a/utils/segmaker.py +++ b/utils/segmaker.py @@ -1,6 +1,7 @@ ''' NOTE: "segments" as used in this file is mostly unrelated to tilegrid.json usage ie tilegrid.json has names like SEG_CLBLL_L_X2Y50 where as here they are tile based and named like seg_00400100_02 +Instead of using tilegrid.json "segments, segments are formed by looking for tiles that use the same address + offset Sample segdata.txt output (from 015-clbnffmux/specimen_001/segdata_clbll_r.txt): seg 00020880_048 @@ -43,7 +44,6 @@ class segmaker: def __init__(self, bitsfile, verbose=None): self.verbose = verbose if verbose is not None else os.getenv( 'VERBOSE', 'N') == 'Y' - self.verbose = verbose self.load_grid() self.load_bits(bitsfile) ''' @@ -142,9 +142,14 @@ class segmaker: ''' assert segname not in segments segment = segments.setdefault( - segname, { + segname, + { "bits": set(), - "tags": dict() + "tags": dict(), + # verify new entries match this + "offset": bitj["offset"], + "words": bitj["words"], + "frames": bitj["frames"], }) base_frame = json_hex2i(bitj["baseaddr"]) @@ -165,6 +170,7 @@ class segmaker: bitname_bit): bitname = "%02d_%02d" % (bitname_frame, bitname_bit) segment["bits"].add(bitname) + return segment ''' XXX: wouldn't it be better to iterate over tags? Easy to drop tags @@ -172,20 +178,27 @@ class segmaker: ''' for tilename, tiledata in self.grid.items(): - def add_tilename_tags(): + def getseg(segname): if not segname in segments: - add_segbits( + return add_segbits( segments, segname, tiledata, bitfilter=bitfilter) + else: + segment = segments[segname] + assert segment["offset"] == bitj["offset"] + assert segment["words"] == bitj["words"] + assert segment["frames"] == bitj["frames"] + return segment + + def add_tilename_tags(): + segment = getseg(segname) for name, value in self.tile_tags[tilename].items(): tags_used.add((tilename, name)) tag = "%s.%s" % (tile_type_norm, name) - segments[segname]["tags"][tag] = value + segment["tags"][tag] = value def add_site_tags(): - if not segname in segments: - add_segbits( - segments, segname, tiledata, bitfilter=bitfilter) + segment = getseg(segname) if 'SLICE_' in site: ''' From 86fce0fee3b47215e87feec60ccc126fe00e9931 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 14:36:59 -0700 Subject: [PATCH 21/42] segprint: cleanup, fix Signed-off-by: John McMaster --- utils/segprint.py | 357 +++++++++++++++++++++++++++------------------- 1 file changed, 208 insertions(+), 149 deletions(-) diff --git a/utils/segprint.py b/utils/segprint.py index cbc73403..ef0f9d49 100755 --- a/utils/segprint.py +++ b/utils/segprint.py @@ -1,89 +1,13 @@ #!/usr/bin/env python3 -import getopt, sys, os, json, re - -flag_z = False -flag_b = False -flag_d = False -flag_D = False +import sys, os, json, re -def usage(): - print("Usage: %s [options] [segments/tiles]" % sys.argv[0]) - print("") - print(" -z") - print(" do not print a 'seg' header for empty segments") - print("") - print(" -b") - print(" print bits outside of known segments") - print("") - print(" -d") - print(" decode known segment bits and write them as tags") - print("") - print(" -D") - print(" decode known segment bits and omit them in the output") - print("") - sys.exit(0) +class NoDB(Exception): + pass -try: - opts, args = getopt.getopt(sys.argv[1:], "zbdD") -except: - usage() - -if len(args) == 0: - usage() - -for o, a in opts: - if o == "-z": - flag_z = True - elif o == "-b": - flag_b = True - elif o == "-d": - flag_d = True - elif o == "-D": - flag_D = True - else: - usage() - -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 in grid['tiles'].values(): - if 'segment' in tile: - segment = tile['segment'] - grid['segments'][segment] = { - 'baseaddr': [ - tile['baseaddr'], - tile['offset'], - ], - 'type': tile['segment_type'], - 'frames': tile['frames'], - 'words': tile['words'], - } - -bitdata = dict() - -# print("Loading %s." % sys.argv[1]) -with open(args[0], "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) - +# cache segbitsdb = dict() @@ -91,18 +15,24 @@ 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("%s/%s/segbits_%s.db" % (os.getenv("XRAY_DATABASE_DIR"), - os.getenv("XRAY_DATABASE"), segtype), - "r") as f: + with open(main_fn, "r") as f: for line in f: line = line.split() segbitsdb[segtype].append(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: line = line.split() segbitsdb[segtype].append(line) @@ -110,73 +40,50 @@ def get_database(segtype): return segbitsdb[segtype] -def handle_segment(segname): - if segname is None: - segframes = dict() - for segname, segdata in grid["segments"].items(): - framebase = int(segdata["baseaddr"][0], 16) - for i in range(segdata["frames"]): - if (framebase + i) not in segframes: - segframes[framebase + i] = set() - for j in range(segdata["baseaddr"][1], - segdata["baseaddr"][1] + segdata["words"]): - segframes[framebase + i].add(j) - for frame in sorted(bitdata.keys()): - for wordidx in sorted(bitdata[frame].keys()): - if frame in segframes and wordidx in segframes[frame]: - continue - for bitidx in sorted(bitdata[frame][wordidx]): - print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx)) - return - if ":" in segname: - seg1, seg2 = segname.split(":") +def handle_split_segment( + segname, grid, bitdata, flag_d, flag_D, omit_empty_segs): + seg1, seg2 = segname.split(":") - if seg1 in grid["tiles"]: - seg1 = grid["tiles"][seg1]["segment"] + if seg1 in grid["tiles"]: + seg1 = grid["tiles"][seg1]["segment"] - if seg2 in grid["tiles"]: - seg2 = grid["tiles"][seg2]["segment"] + if seg2 in grid["tiles"]: + seg2 = grid["tiles"][seg2]["segment"] - seginfo1 = grid["segments"][seg1] - seginfo2 = grid["segments"][seg2] + seginfo1 = grid["segments"][seg1] + seginfo2 = grid["segments"][seg2] - frame1 = int(seginfo1["baseaddr"][0], 16) - word1 = int(seginfo1["baseaddr"][1]) + frame1 = int(seginfo1["baseaddr"][0], 16) + word1 = int(seginfo1["baseaddr"][1]) - frame2 = int(seginfo2["baseaddr"][0], 16) - word2 = int(seginfo2["baseaddr"][1]) + frame2 = int(seginfo2["baseaddr"][0], 16) + word2 = int(seginfo2["baseaddr"][1]) - if frame1 > frame2: - frame1, frame2 = frame2, frame1 + if frame1 > frame2: + frame1, frame2 = frame2, frame1 - if word1 > word2: - word1, word2 = word2, word1 + if word1 > word2: + word1, word2 = word2, word1 - segs = list() + segs = list() - for seg, seginfo in sorted(grid["segments"].items()): - frame = int(seginfo["baseaddr"][0], 16) - word = int(seginfo["baseaddr"][1]) - if frame1 <= frame <= frame2 and word1 <= word <= word2: - segs.append((frame, word, seg)) + for seg, seginfo in sorted(grid["segments"].items()): + frame = int(seginfo["baseaddr"][0], 16) + word = int(seginfo["baseaddr"][1]) + if frame1 <= frame <= frame2 and word1 <= word <= word2: + segs.append((frame, word, seg)) - for _, _, seg in sorted(segs): - handle_segment(seg) - return + for _, _, seg in sorted(segs): + handle_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs) - if segname in grid["tiles"]: - segname = grid["tiles"][segname]["segment"] - - seginfo = grid["segments"][segname] +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() - segtags = set() - for frame in range(baseframe, baseframe + numframes): if frame not in bitdata: continue @@ -187,8 +94,38 @@ def handle_segment(segname): segbits.add( "%02d_%02d" % (frame - baseframe, 32 * (wordidx - basewordidx) + bitidx)) + return segbits - if flag_d or flag_D: + +def print_unknown_bits(grid, bitdata): + ''' + Print bits not covered by known tiles + ''' + + # Index all known locations + # seggrames[address] = set() + # where set contains word numbers + segframes = dict() + for segname, segdata in grid["segments"].items(): + framebase = int(segdata["baseaddr"][0], 16) + for i in range(segdata["frames"]): + words = segframes.setdefault(framebase + i, set()) + for j in range(segdata["baseaddr"][1], + segdata["baseaddr"][1] + segdata["words"]): + words.add(j) + + # print uncovered locations + print('Non-database bits:') + for frame in sorted(bitdata.keys()): + for wordidx in sorted(bitdata[frame].keys()): + if frame in segframes and wordidx in segframes[frame]: + continue + for bitidx in sorted(bitdata[frame][wordidx]): + print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx)) + + +def seg_decode(flag_d, seginfo, segbits, segtags): + try: for entry in get_database(seginfo["type"]): match_entry = True for bit in entry[1:]: @@ -202,10 +139,42 @@ def handle_segment(segname): segbits.remove(bit) if flag_d: segtags.add(entry[0]) + except NoDB: + print("WARNING: failed to load DB for %s" % seginfo["type"]) - if not flag_z or len(segbits) > 0 or len(segtags) > 0: + +def handle_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs): + ''' + segname: tile name + ''' + + assert segname + + # ? probably legacy + #if ":" in segname: + # handle_split_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs) + # return + + # compatibility? + # now dealing only with tile names...? + #if segname in grid["tiles"]: + # segname = grid["tiles"][segname]["segment"] + + # only print bitstream tiles + if segname not in grid["segments"]: + return + seginfo = grid["segments"][segname] + + segtags = set() + segbits = mk_segbits(seginfo, bitdata) + + if flag_d or flag_D: + seg_decode(flag_d, seginfo, segbits, segtags) + + # Found something to print? + if not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0: print() - print("seg %s" % segname) + print("tile %s" % segname) for bit in sorted(segbits): print("bit %s" % bit) @@ -214,15 +183,105 @@ def handle_segment(segname): print("tag %s" % tag) -if flag_b: - handle_segment(None) +def load_bitdata(bits_file): + bitdata = dict() -if len(args) == 1: - seglist = list() - for seg, seginfo in grid["segments"].items(): - seglist.append((seginfo["baseaddr"][0], -seginfo["baseaddr"][1], seg)) - for _, _, seg in sorted(seglist): - handle_segment(seg) -else: - for arg in args[1:]: - handle_segment(arg) + 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(): + 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 + block = bits.get('CLB_IO_CLK', None) + if not block: + continue + + grid['segments'][tile_name] = { + 'baseaddr': [ + block['baseaddr'], + block['offset'], + ], + 'type': tile['type'], + 'frames': block['frames'], + 'words': block['words'], + } + return grid + + +def run( + bits_file, + segments, + omit_empty_segs=False, + flag_b=False, + flag_d=False, + flag_D=False): + grid = mk_grid() + + bitdata = load_bitdata(bits_file) + + if flag_b: + print_unknown_bits(grid, bitdata) + + if segments: + for segment in segments: + handle_segment( + segment, grid, bitdata, flag_d, flag_D, omit_empty_segs) + else: + for segname in sorted(grid['tiles'].keys()): + handle_segment( + segname, grid, bitdata, flag_d, flag_D, omit_empty_segs) + + +def main(): + import argparse + + parser = argparse.ArgumentParser(description='') + + parser.add_argument('--verbose', action='store_true', help='') + parser.add_argument( + '-z', + action='store_true', + help="do not print a 'seg' header for empty segments") + parser.add_argument( + '-b', action='store_true', help='print bits outside of known segments') + parser.add_argument( + '-d', + action='store_true', + help='decode known segment bits and write them as tags') + # XXX: possibly broken, or we have missing DB data + parser.add_argument( + '-D', + action='store_true', + help='decode known segment bits and omit them in the output') + parser.add_argument('bits_file', help='') + parser.add_argument('segments', nargs='*', help='') + args = parser.parse_args() + + run(args.bits_file, args.segments, args.z, args.b, args.d, args.D) + + +if __name__ == '__main__': + main() From 5e2164f4b190c00556ea707cc51d5604a715c5cc Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 15:31:17 -0700 Subject: [PATCH 22/42] Move tools .py files to utils to be consistent Signed-off-by: John McMaster --- {tools => utils}/fasm2frame.py | 0 {tools => utils}/quick_test.py | 0 {tools => utils}/segprint2fasm.py | 0 {tools => utils}/simpleroute.py | 0 {tools => utils}/test_data/ff_int.fasm | 0 {tools => utils}/test_data/ff_int/.gitignore | 0 {tools => utils}/test_data/ff_int/design.bits | 0 {tools => utils}/test_data/ff_int/design.segp | 0 {tools => utils}/test_data/ff_int/top.v | 0 {tools => utils}/test_data/ff_int_0s.fasm | 0 {tools => utils}/test_data/ff_int_op1.fasm | 0 {tools => utils}/test_data/lut.fasm | 0 {tools => utils}/test_data/lut_int.fasm | 0 {tools => utils}/test_data/lut_int/.gitignore | 0 {tools => utils}/test_data/lut_int/design.bits | 0 {tools => utils}/test_data/lut_int/design.segp | 0 {tools => utils}/test_data/lut_int/top.v | 0 {tools => utils}/test_fasm2frame.py | 0 {tools => utils}/test_segprint2fasm.py | 0 {tools => utils}/verify_tile_connections.py | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename {tools => utils}/fasm2frame.py (100%) rename {tools => utils}/quick_test.py (100%) rename {tools => utils}/segprint2fasm.py (100%) rename {tools => utils}/simpleroute.py (100%) rename {tools => utils}/test_data/ff_int.fasm (100%) rename {tools => utils}/test_data/ff_int/.gitignore (100%) rename {tools => utils}/test_data/ff_int/design.bits (100%) rename {tools => utils}/test_data/ff_int/design.segp (100%) rename {tools => utils}/test_data/ff_int/top.v (100%) rename {tools => utils}/test_data/ff_int_0s.fasm (100%) rename {tools => utils}/test_data/ff_int_op1.fasm (100%) rename {tools => utils}/test_data/lut.fasm (100%) rename {tools => utils}/test_data/lut_int.fasm (100%) rename {tools => utils}/test_data/lut_int/.gitignore (100%) rename {tools => utils}/test_data/lut_int/design.bits (100%) rename {tools => utils}/test_data/lut_int/design.segp (100%) rename {tools => utils}/test_data/lut_int/top.v (100%) rename {tools => utils}/test_fasm2frame.py (100%) rename {tools => utils}/test_segprint2fasm.py (100%) rename {tools => utils}/verify_tile_connections.py (100%) diff --git a/tools/fasm2frame.py b/utils/fasm2frame.py similarity index 100% rename from tools/fasm2frame.py rename to utils/fasm2frame.py diff --git a/tools/quick_test.py b/utils/quick_test.py similarity index 100% rename from tools/quick_test.py rename to utils/quick_test.py diff --git a/tools/segprint2fasm.py b/utils/segprint2fasm.py similarity index 100% rename from tools/segprint2fasm.py rename to utils/segprint2fasm.py diff --git a/tools/simpleroute.py b/utils/simpleroute.py similarity index 100% rename from tools/simpleroute.py rename to utils/simpleroute.py diff --git a/tools/test_data/ff_int.fasm b/utils/test_data/ff_int.fasm similarity index 100% rename from tools/test_data/ff_int.fasm rename to utils/test_data/ff_int.fasm diff --git a/tools/test_data/ff_int/.gitignore b/utils/test_data/ff_int/.gitignore similarity index 100% rename from tools/test_data/ff_int/.gitignore rename to utils/test_data/ff_int/.gitignore diff --git a/tools/test_data/ff_int/design.bits b/utils/test_data/ff_int/design.bits similarity index 100% rename from tools/test_data/ff_int/design.bits rename to utils/test_data/ff_int/design.bits diff --git a/tools/test_data/ff_int/design.segp b/utils/test_data/ff_int/design.segp similarity index 100% rename from tools/test_data/ff_int/design.segp rename to utils/test_data/ff_int/design.segp diff --git a/tools/test_data/ff_int/top.v b/utils/test_data/ff_int/top.v similarity index 100% rename from tools/test_data/ff_int/top.v rename to utils/test_data/ff_int/top.v diff --git a/tools/test_data/ff_int_0s.fasm b/utils/test_data/ff_int_0s.fasm similarity index 100% rename from tools/test_data/ff_int_0s.fasm rename to utils/test_data/ff_int_0s.fasm diff --git a/tools/test_data/ff_int_op1.fasm b/utils/test_data/ff_int_op1.fasm similarity index 100% rename from tools/test_data/ff_int_op1.fasm rename to utils/test_data/ff_int_op1.fasm diff --git a/tools/test_data/lut.fasm b/utils/test_data/lut.fasm similarity index 100% rename from tools/test_data/lut.fasm rename to utils/test_data/lut.fasm diff --git a/tools/test_data/lut_int.fasm b/utils/test_data/lut_int.fasm similarity index 100% rename from tools/test_data/lut_int.fasm rename to utils/test_data/lut_int.fasm diff --git a/tools/test_data/lut_int/.gitignore b/utils/test_data/lut_int/.gitignore similarity index 100% rename from tools/test_data/lut_int/.gitignore rename to utils/test_data/lut_int/.gitignore diff --git a/tools/test_data/lut_int/design.bits b/utils/test_data/lut_int/design.bits similarity index 100% rename from tools/test_data/lut_int/design.bits rename to utils/test_data/lut_int/design.bits diff --git a/tools/test_data/lut_int/design.segp b/utils/test_data/lut_int/design.segp similarity index 100% rename from tools/test_data/lut_int/design.segp rename to utils/test_data/lut_int/design.segp diff --git a/tools/test_data/lut_int/top.v b/utils/test_data/lut_int/top.v similarity index 100% rename from tools/test_data/lut_int/top.v rename to utils/test_data/lut_int/top.v diff --git a/tools/test_fasm2frame.py b/utils/test_fasm2frame.py similarity index 100% rename from tools/test_fasm2frame.py rename to utils/test_fasm2frame.py diff --git a/tools/test_segprint2fasm.py b/utils/test_segprint2fasm.py similarity index 100% rename from tools/test_segprint2fasm.py rename to utils/test_segprint2fasm.py diff --git a/tools/verify_tile_connections.py b/utils/verify_tile_connections.py similarity index 100% rename from tools/verify_tile_connections.py rename to utils/verify_tile_connections.py From 0a6aa3c3746d80b533f68bd918554154e2ea2f14 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 17:45:03 -0700 Subject: [PATCH 23/42] tilegrid: always add bits field Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 81fcfdfd..4eb09f44 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -100,6 +100,7 @@ def make_database(tiles): "sites": tile["sites"], "grid_x": tile["grid_x"], "grid_y": tile["grid_y"], + "bits": {}, } return database @@ -436,7 +437,7 @@ def add_tile_bits(tile_db, baseaddr, offset, frames, words, height=None): https://github.com/SymbiFlow/prjxray/issues/145 ''' - bits = tile_db.setdefault('bits', {}) + bits = tile_db['bits'] block_type = addr2btype(baseaddr) assert 0 <= offset <= 100, offset @@ -484,9 +485,11 @@ def add_bits(database, segments): ("BRAM_INT_INTERFACE", "CLB_IO_CLK"): (28, 2, None), }.get((nolr(tile_type), block_type), None) if entry is None: + # Other types are rare, not expected to have these if block_type == "CLB_IO_CLK": raise ValueError("Unknown tile type %s" % tile_type) continue + frames, words, height = entry if frames: # if we have a width, we should have a height From 7998b77ee3a21d2643305fb5f83ae7f9ff62dc5e Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 17:48:04 -0700 Subject: [PATCH 24/42] segprint: include all tile memory spaces, not just IO Signed-off-by: John McMaster --- utils/segprint.py | 112 +++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/utils/segprint.py b/utils/segprint.py index ef0f9d49..d5d4d6be 100755 --- a/utils/segprint.py +++ b/utils/segprint.py @@ -1,4 +1,12 @@ #!/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 @@ -40,8 +48,9 @@ def get_database(segtype): return segbitsdb[segtype] +''' def handle_split_segment( - segname, grid, bitdata, flag_d, flag_D, omit_empty_segs): + segname, grid, bitdata, flag_decode_emit, flag_decode_omit, omit_empty_segs): seg1, seg2 = segname.split(":") if seg1 in grid["tiles"]: @@ -74,7 +83,8 @@ def handle_split_segment( segs.append((frame, word, seg)) for _, _, seg in sorted(segs): - handle_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs) + handle_segment(segname, grid, bitdata, flag_decode_emit, flag_decode_omit, omit_empty_segs) +''' def mk_segbits(seginfo, bitdata): @@ -124,7 +134,7 @@ def print_unknown_bits(grid, bitdata): print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx)) -def seg_decode(flag_d, seginfo, segbits, segtags): +def seg_decode(flag_decode_emit, seginfo, segbits, segtags): try: for entry in get_database(seginfo["type"]): match_entry = True @@ -137,13 +147,15 @@ def seg_decode(flag_d, seginfo, segbits, segtags): for bit in entry[1:]: if bit[0] != "!": segbits.remove(bit) - if flag_d: + if flag_decode_emit: segtags.add(entry[0]) except NoDB: print("WARNING: failed to load DB for %s" % seginfo["type"]) -def handle_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs): +def handle_segment( + segname, grid, bitdata, flag_decode_emit, flag_decode_omit, + omit_empty_segs): ''' segname: tile name ''' @@ -152,7 +164,7 @@ def handle_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs): # ? probably legacy #if ":" in segname: - # handle_split_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs) + # handle_split_segment(segname, grid, bitdata, flag_decode_emit, flag_decode_omit, omit_empty_segs) # return # compatibility? @@ -168,13 +180,13 @@ def handle_segment(segname, grid, bitdata, flag_d, flag_D, omit_empty_segs): segtags = set() segbits = mk_segbits(seginfo, bitdata) - if flag_d or flag_D: - seg_decode(flag_d, seginfo, segbits, segtags) + if flag_decode_emit or flag_decode_omit: + seg_decode(flag_decode_emit, seginfo, segbits, segtags) # Found something to print? if not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0: print() - print("tile %s" % segname) + print("seg %s" % (segname, )) for bit in sorted(segbits): print("bit %s" % bit) @@ -204,6 +216,8 @@ def load_bitdata(bits_file): 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) @@ -215,50 +229,74 @@ def mk_grid(): bits = tile.get('bits', None) if not bits: continue - block = bits.get('CLB_IO_CLK', None) - if not block: - continue - - grid['segments'][tile_name] = { - 'baseaddr': [ - block['baseaddr'], - block['offset'], - ], - 'type': tile['type'], - 'frames': block['frames'], - 'words': block['words'], - } + 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, - segments, + segnames, omit_empty_segs=False, - flag_b=False, - flag_d=False, - flag_D=False): + flag_unknown_bits=False, + flag_decode_emit=False, + flag_decode_omit=False): grid = mk_grid() bitdata = load_bitdata(bits_file) - if flag_b: + if flag_unknown_bits: print_unknown_bits(grid, bitdata) - if segments: - for segment in segments: - handle_segment( - segment, grid, bitdata, flag_d, flag_D, omit_empty_segs) + # 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: - for segname in sorted(grid['tiles'].keys()): - handle_segment( - segname, grid, bitdata, flag_d, flag_D, omit_empty_segs) + segnames = sorted(tile_segnames(grid)) + print('Segments: %u' % len(segnames)) + + # XXX: previously this was sorted by address, not name + # revisit? + for segname in segnames: + handle_segment( + segname, grid, bitdata, flag_decode_emit, flag_decode_omit, + omit_empty_segs) def main(): import argparse - parser = argparse.ArgumentParser(description='') + # 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( @@ -277,10 +315,10 @@ 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('segments', nargs='*', help='') + parser.add_argument('tiles', nargs='*', help='') args = parser.parse_args() - run(args.bits_file, args.segments, args.z, args.b, args.d, args.D) + run(args.bits_file, args.tiles, args.z, args.b, args.d, args.D) if __name__ == '__main__': From e3cd270e167c6f034a6b11e097fd69c3468e3d8f Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 19:53:15 -0700 Subject: [PATCH 25/42] segprint2fasm -> bits2fasm Signed-off-by: John McMaster --- utils/bits2fasm.py | 241 +++++++++++++++++++++++++++++++++++++++++ utils/environment.sh | 4 + utils/segprint.py | 55 ++++++---- utils/segprint2fasm.py | 139 ------------------------ 4 files changed, 280 insertions(+), 159 deletions(-) create mode 100755 utils/bits2fasm.py delete mode 100755 utils/segprint2fasm.py diff --git a/utils/bits2fasm.py b/utils/bits2fasm.py new file mode 100755 index 00000000..bb0cd52c --- /dev/null +++ b/utils/bits2fasm.py @@ -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() diff --git a/utils/environment.sh b/utils/environment.sh index a8e20cf5..b90cc09a 100644 --- a/utils/environment.sh +++ b/utils/environment.sh @@ -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" + + diff --git a/utils/segprint.py b/utils/segprint.py index d5d4d6be..5c9f6029 100755 --- a/utils/segprint.py +++ b/utils/segprint.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__': diff --git a/utils/segprint2fasm.py b/utils/segprint2fasm.py deleted file mode 100755 index 6620c6d9..00000000 --- a/utils/segprint2fasm.py +++ /dev/null @@ -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')) From 178c76f74dafcd1deedb95b248e527a1af9a681e Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 20:17:39 -0700 Subject: [PATCH 26/42] bits2fasm: format enums correctly Signed-off-by: John McMaster --- utils/bits2fasm.py | 89 ++++++++++++++++++++++++++++++++++++++++------ utils/segprint.py | 20 +++++------ 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/utils/bits2fasm.py b/utils/bits2fasm.py index bb0cd52c..1b0b6c33 100755 --- a/utils/bits2fasm.py +++ b/utils/bits2fasm.py @@ -23,38 +23,104 @@ def comment(s): print('# %s' % s) +enumdb = dict() + + +def get_enums(tile_type): + if tile_type in enumdb: + return enumdb[tile_type] + + enumdb[tile_type] = {} + + 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[tile_type][name] = len(bit_vals) != 1 + + 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 NoDB(tile_type) + + with open(main_fn, "r") as f: + for line in f: + process(line) + + with open(int_fn, "r") as f: + for line in f: + process(line) + + return enumdb[tile_type] + + +def isenum(tilename, tag): + return get_enums(tilename)[tag] + + # cache segbitsdb = dict() # TODO: migrate to library -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] main_fn = "%s/%s/segbits_%s.db" % ( os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), - segtype.lower()) + tile_type.lower()) int_fn = "%s/%s/segbits_int_%s.db" % ( os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), - segtype[-1].lower()) + tile_type[-1].lower()) if not os.path.exists(main_fn) or not os.path.exists(int_fn): - raise NoDB(segtype) + raise NoDB(tile_type) - segbitsdb[segtype] = list() + segbitsdb[tile_type] = list() with open(main_fn, "r") as f: for line in f: line = line.split() - segbitsdb[segtype].append(line) + segbitsdb[tile_type].append(line) with open(int_fn, "r") as f: for line in f: line = line.split() - segbitsdb[segtype].append(line) + segbitsdb[tile_type].append(line) - return segbitsdb[segtype] + return segbitsdb[tile_type] + + +def mk_fasm(segj, entry): + tile_name = segj['tile_name'] + + # ex: CLBLL_L.SLICEL_X0.AFF.DMUX.O6 + tag = entry[0] + m = re.match(r'([A-Za-z0-9_]+)[.](.*)', tag) + # tile_type = m.group(1) + # the postfix, O6 in the above example + tag_post = m.group(2) + + if not isenum(segj['type'], tag): + return '%s.%s 1' % (tile_name, 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_name, which, value) def mk_segbits(seginfo, bitdata): @@ -100,7 +166,8 @@ def seg_decode(seginfo, segbits): if not tagmatch(entry, segbits): continue tag_matched(entry, segbits) - fasms.add('%s.%s 1' % (seginfo['tile_name'], entry[0])) + #fasms.add('%s.%s 1' % (seginfo['tile_name'], entry[0])) + fasms.add(mk_fasm(seginfo, entry)) except NoDB: print("WARNING: failed to load DB for %s" % seginfo["type"]) return fasms diff --git a/utils/segprint.py b/utils/segprint.py index 5c9f6029..a5e13bd5 100755 --- a/utils/segprint.py +++ b/utils/segprint.py @@ -20,33 +20,33 @@ segbitsdb = dict() # TODO: migrate to library -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] main_fn = "%s/%s/segbits_%s.db" % ( os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), - segtype.lower()) + tile_type.lower()) int_fn = "%s/%s/segbits_int_%s.db" % ( os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), - segtype[-1].lower()) + tile_type[-1].lower()) if not os.path.exists(main_fn) or not os.path.exists(int_fn): - raise NoDB(segtype) + raise NoDB(tile_type) - segbitsdb[segtype] = list() + segbitsdb[tile_type] = list() with open(main_fn, "r") as f: for line in f: line = line.split() - segbitsdb[segtype].append(line) + segbitsdb[tile_type].append(line) with open(int_fn, "r") as f: for line in f: line = line.split() - segbitsdb[segtype].append(line) + segbitsdb[tile_type].append(line) - return segbitsdb[segtype] + return segbitsdb[tile_type] ''' From e7e010179b1a3520f00c11a7a3af23ed42969ad0 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 22:09:00 -0700 Subject: [PATCH 27/42] fasm2frame => fasm2bits Signed-off-by: John McMaster --- utils/{fasm2frame.py => fasm2bits.py} | 0 .../{test_fasm2frame.py => test_fasm2bits.py} | 26 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) rename utils/{fasm2frame.py => fasm2bits.py} (100%) rename utils/{test_fasm2frame.py => test_fasm2bits.py} (89%) diff --git a/utils/fasm2frame.py b/utils/fasm2bits.py similarity index 100% rename from utils/fasm2frame.py rename to utils/fasm2bits.py diff --git a/utils/test_fasm2frame.py b/utils/test_fasm2bits.py similarity index 89% rename from utils/test_fasm2frame.py rename to utils/test_fasm2bits.py index 27c2815c..729632e1 100644 --- a/utils/test_fasm2frame.py +++ b/utils/test_fasm2bits.py @@ -1,6 +1,6 @@ # TODO: need better coverage for different tile types -import fasm2frame +import fasm2bits import unittest import StringIO @@ -52,11 +52,11 @@ class TestStringMethods(unittest.TestCase): def test_lut(self): '''Simple smoke test on just the LUTs''' fout = StringIO.StringIO() - fasm2frame.run(open('test_data/lut.fasm', 'r'), fout) + fasm2bits.run(open('test_data/lut.fasm', 'r'), fout) def bitread_frm_equals(self, frm_fn, bitread_fn): fout = StringIO.StringIO() - fasm2frame.run(open(frm_fn, 'r'), fout) + fasm2bits.run(open(frm_fn, 'r'), fout) # Build a list of output used bits bits_out = frm2bits(fout.getvalue()) @@ -86,12 +86,12 @@ class TestStringMethods(unittest.TestCase): '''Optional key with binary omitted value should produce valid result''' fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX") fout = StringIO.StringIO() - fasm2frame.run(fin, fout) + fasm2bits.run(fin, fout) def test_opkey_01_1(self): fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1") fout = StringIO.StringIO() - fasm2frame.run(fin, fout) + fasm2bits.run(fin, fout) def test_opkey_enum(self): '''Optional key with enumerated value should produce syntax error''' @@ -99,9 +99,9 @@ class TestStringMethods(unittest.TestCase): fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.AMUX.O6") fout = StringIO.StringIO() try: - fasm2frame.run(fin, fout) + fasm2bits.run(fin, fout) self.fail("Expected syntax error") - except fasm2frame.FASMSyntaxError: + except fasm2bits.FASMSyntaxError: pass def test_ff_int_0s(self): @@ -114,9 +114,9 @@ class TestStringMethods(unittest.TestCase): fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 2") fout = StringIO.StringIO() try: - fasm2frame.run(fin, fout) + fasm2bits.run(fin, fout) self.fail("Expected syntax error") - except fasm2frame.FASMSyntaxError: + except fasm2bits.FASMSyntaxError: pass def test_dupkey(self): @@ -128,9 +128,9 @@ CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1 """) fout = StringIO.StringIO() try: - fasm2frame.run(fin, fout) + fasm2bits.run(fin, fout) self.fail("Expected syntax error") - except fasm2frame.FASMSyntaxError: + except fasm2bits.FASMSyntaxError: pass def test_sparse(self): @@ -138,12 +138,12 @@ CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1 frm_fn = 'test_data/lut_int.fasm' fout_sparse = StringIO.StringIO() - fasm2frame.run(open(frm_fn, 'r'), fout_sparse, sparse=True) + fasm2bits.run(open(frm_fn, 'r'), fout_sparse, sparse=True) fout_sparse_txt = fout_sparse.getvalue() bits_sparse = frm2bits(fout_sparse_txt) fout_full = StringIO.StringIO() - fasm2frame.run(open(frm_fn, 'r'), fout_full, sparse=False) + fasm2bits.run(open(frm_fn, 'r'), fout_full, sparse=False) fout_full_txt = fout_full.getvalue() bits_full = frm2bits(fout_full_txt) From c8ee9d4f1645adcc8d63f3c671cdd9d475f56474 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 23:39:41 -0700 Subject: [PATCH 28/42] 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) From 3588f278c1b5d2767c562d7eadf1a4751ac09e55 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 23:41:05 -0700 Subject: [PATCH 29/42] fasm2bits -> fasm2frames Signed-off-by: John McMaster --- utils/{fasm2bits.py => fasm2frames.py} | 0 ...{test_fasm2bits.py => test_fasm2frames.py} | 26 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) rename utils/{fasm2bits.py => fasm2frames.py} (100%) rename utils/{test_fasm2bits.py => test_fasm2frames.py} (88%) diff --git a/utils/fasm2bits.py b/utils/fasm2frames.py similarity index 100% rename from utils/fasm2bits.py rename to utils/fasm2frames.py diff --git a/utils/test_fasm2bits.py b/utils/test_fasm2frames.py similarity index 88% rename from utils/test_fasm2bits.py rename to utils/test_fasm2frames.py index 729632e1..e0f35f61 100644 --- a/utils/test_fasm2bits.py +++ b/utils/test_fasm2frames.py @@ -1,6 +1,6 @@ # TODO: need better coverage for different tile types -import fasm2bits +import fasm2frames import unittest import StringIO @@ -52,11 +52,11 @@ class TestStringMethods(unittest.TestCase): def test_lut(self): '''Simple smoke test on just the LUTs''' fout = StringIO.StringIO() - fasm2bits.run(open('test_data/lut.fasm', 'r'), fout) + fasm2frames.run(open('test_data/lut.fasm', 'r'), fout) def bitread_frm_equals(self, frm_fn, bitread_fn): fout = StringIO.StringIO() - fasm2bits.run(open(frm_fn, 'r'), fout) + fasm2frames.run(open(frm_fn, 'r'), fout) # Build a list of output used bits bits_out = frm2bits(fout.getvalue()) @@ -86,12 +86,12 @@ class TestStringMethods(unittest.TestCase): '''Optional key with binary omitted value should produce valid result''' fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX") fout = StringIO.StringIO() - fasm2bits.run(fin, fout) + fasm2frames.run(fin, fout) def test_opkey_01_1(self): fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1") fout = StringIO.StringIO() - fasm2bits.run(fin, fout) + fasm2frames.run(fin, fout) def test_opkey_enum(self): '''Optional key with enumerated value should produce syntax error''' @@ -99,9 +99,9 @@ class TestStringMethods(unittest.TestCase): fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.AMUX.O6") fout = StringIO.StringIO() try: - fasm2bits.run(fin, fout) + fasm2frames.run(fin, fout) self.fail("Expected syntax error") - except fasm2bits.FASMSyntaxError: + except fasm2frames.FASMSyntaxError: pass def test_ff_int_0s(self): @@ -114,9 +114,9 @@ class TestStringMethods(unittest.TestCase): fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 2") fout = StringIO.StringIO() try: - fasm2bits.run(fin, fout) + fasm2frames.run(fin, fout) self.fail("Expected syntax error") - except fasm2bits.FASMSyntaxError: + except fasm2frames.FASMSyntaxError: pass def test_dupkey(self): @@ -128,9 +128,9 @@ CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1 """) fout = StringIO.StringIO() try: - fasm2bits.run(fin, fout) + fasm2frames.run(fin, fout) self.fail("Expected syntax error") - except fasm2bits.FASMSyntaxError: + except fasm2frames.FASMSyntaxError: pass def test_sparse(self): @@ -138,12 +138,12 @@ CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1 frm_fn = 'test_data/lut_int.fasm' fout_sparse = StringIO.StringIO() - fasm2bits.run(open(frm_fn, 'r'), fout_sparse, sparse=True) + fasm2frames.run(open(frm_fn, 'r'), fout_sparse, sparse=True) fout_sparse_txt = fout_sparse.getvalue() bits_sparse = frm2bits(fout_sparse_txt) fout_full = StringIO.StringIO() - fasm2bits.run(open(frm_fn, 'r'), fout_full, sparse=False) + fasm2frames.run(open(frm_fn, 'r'), fout_full, sparse=False) fout_full_txt = fout_full.getvalue() bits_full = frm2bits(fout_full_txt) From 98300b801eb1fcdefd2256a20aea1eb113564a1c Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 23:42:36 -0700 Subject: [PATCH 30/42] Remove obsolete test_segprint2fasm Signed-off-by: John McMaster --- utils/test_data/ff_int/design.segp | 17 ----------- utils/test_data/lut_int/design.segp | 22 --------------- utils/test_segprint2fasm.py | 44 ----------------------------- 3 files changed, 83 deletions(-) delete mode 100644 utils/test_data/ff_int/design.segp delete mode 100644 utils/test_data/lut_int/design.segp delete mode 100644 utils/test_segprint2fasm.py diff --git a/utils/test_data/ff_int/design.segp b/utils/test_data/ff_int/design.segp deleted file mode 100644 index 2e0bd01d..00000000 --- a/utils/test_data/ff_int/design.segp +++ /dev/null @@ -1,17 +0,0 @@ - -seg SEG_HCLK_L_X31Y130 -tag HCLK_L.ENABLE_BUFFER.HCLK_CK_BUFHCLK8 -tag HCLK_L.HCLK_LEAF_CLK_B_BOTL5.HCLK_CK_BUFHCLK8 - -seg SEG_CLBLM_L_X10Y102 -tag CLBLM_L.SLICEM_X0.AFF.DMUX.AX -tag CLBLM_L.SLICEM_X0.AFF.ZINI -tag CLBLM_L.SLICEM_X0.AFF.ZRST -tag CLBLM_L.SLICEM_X0.CEUSEDMUX -tag CLBLM_L.SLICEM_X0.SRUSEDMUX -tag INT_L.BYP_ALT0.EE2END0 -tag INT_L.BYP_ALT1.EL1END1 -tag INT_L.CLK_L1.GCLK_L_B11_WEST -tag INT_L.CTRL_L1.ER1END2 -tag INT_L.FAN_ALT7.BYP_BOUNCE0 -tag INT_L.WW2BEG0.LOGIC_OUTS_L4 diff --git a/utils/test_data/lut_int/design.segp b/utils/test_data/lut_int/design.segp deleted file mode 100644 index 371afecd..00000000 --- a/utils/test_data/lut_int/design.segp +++ /dev/null @@ -1,22 +0,0 @@ - -seg SEG_CLBLM_L_X10Y102 -tag CLBLM_L.SLICEM_X0.ALUT.INIT[00] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[08] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[10] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[11] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[13] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[14] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[15] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[41] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[43] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[44] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[46] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[47] -tag CLBLM_L.SLICEM_X0.ALUT.INIT[63] -tag INT_L.IMUX_L1.EE2END0 -tag INT_L.IMUX_L11.EL1END1 -tag INT_L.IMUX_L2.EE2END1 -tag INT_L.IMUX_L4.EE2END2 -tag INT_L.IMUX_L7.EE2END3 -tag INT_L.IMUX_L8.EL1END0 -tag INT_L.WW2BEG0.LOGIC_OUTS_L12 diff --git a/utils/test_segprint2fasm.py b/utils/test_segprint2fasm.py deleted file mode 100644 index 9865c9f4..00000000 --- a/utils/test_segprint2fasm.py +++ /dev/null @@ -1,44 +0,0 @@ -import segprint2fasm - -import unittest -import StringIO -import re - - -class TestStringMethods(unittest.TestCase): - def check_segprint_fasm_equiv(self, segp_fn, fasm_fn): - fout = StringIO.StringIO() - segprint2fasm.run(open(segp_fn, 'r'), fout) - fasm_out = fout.getvalue() - - fasm_ref = open(fasm_fn, 'r').read() - - def normalize(fasm): - '''Remove all comments and sort''' - ret = [] - for l in fasm.split('\n'): - # Remove comments - i = l.rfind('#') - if i >= 0: - l = l[0:i] - l = l.strip() - if not l: - continue - ret.append(l) - return sorted(ret) - - fasm_out = normalize(fasm_out) - fasm_ref = normalize(fasm_ref) - self.assertEquals(fasm_ref, fasm_out) - - def test_lut_int(self): - self.check_segprint_fasm_equiv( - 'test_data/lut_int/design.segp', 'test_data/lut_int.fasm') - - def test_ff_int(self): - self.check_segprint_fasm_equiv( - 'test_data/ff_int/design.segp', 'test_data/ff_int.fasm') - - -if __name__ == '__main__': - unittest.main() From d5fd573d30ff7fad5b05758879229fa868a68786 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 23:47:19 -0700 Subject: [PATCH 31/42] python3, formatting Signed-off-by: John McMaster --- utils/fasm2frames.py | 27 +++++++++++++++++++-------- utils/test_fasm2frames.py | 33 +++++++++++++++++---------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/utils/fasm2frames.py b/utils/fasm2frames.py index 6744f7a7..72cab3ed 100755 --- a/utils/fasm2frames.py +++ b/utils/fasm2frames.py @@ -163,11 +163,13 @@ def mk_grid(): } return grid + def frame_init(frames, addr): '''Set given frame to 0''' if not addr in frames: frames[addr] = [0 for _i in range(101)] + def frames_init(frames, grid): '''Set all frames to 0''' for segj in grid['segments'].values(): @@ -176,10 +178,12 @@ def frames_init(frames, grid): 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) @@ -209,6 +213,7 @@ def parse_line(l): 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) @@ -219,7 +224,10 @@ def check_duplicate(used_names, tile, name, l, line_number): (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): + +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 @@ -232,6 +240,7 @@ def update_segbit(frames, seg_word_column, word_bit_n, isset, seg_baseaddr, seg_ 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'): @@ -256,15 +265,15 @@ def process_line(line_number, l, grid, frames, used_names): 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(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] @@ -272,10 +281,10 @@ def process_line(line_number, l, grid, frames, used_names): raise FASMSyntaxError( "Segment DB %s, key %s not found from line '%s'" % (segj['type'], db_k, l)) from None - + if not value: value = default_value(db_vals, name) - + # Get the specific entry we need try: db_vals = db_vals[value] @@ -283,9 +292,11 @@ def process_line(line_number, l, grid, frames, used_names): 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(frames, seg_word_column, word_bit_n, isset, seg_baseaddr, seg_word_base) + 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): diff --git a/utils/test_fasm2frames.py b/utils/test_fasm2frames.py index e0f35f61..9dd547e8 100644 --- a/utils/test_fasm2frames.py +++ b/utils/test_fasm2frames.py @@ -1,9 +1,10 @@ +#!/usr/bin/env python3 # TODO: need better coverage for different tile types import fasm2frames import unittest -import StringIO +from io import StringIO import re @@ -23,7 +24,7 @@ def frm2bits(txt): assert (101 == len(words)) for wordi, word in enumerate(words): word = int(word, 0) - for biti in xrange(32): + for biti in range(32): val = word & (1 << biti) if val: bits_out.add((addr, wordi, biti)) @@ -51,11 +52,11 @@ def bitread2bits(txt): class TestStringMethods(unittest.TestCase): def test_lut(self): '''Simple smoke test on just the LUTs''' - fout = StringIO.StringIO() + fout = StringIO() fasm2frames.run(open('test_data/lut.fasm', 'r'), fout) def bitread_frm_equals(self, frm_fn, bitread_fn): - fout = StringIO.StringIO() + fout = StringIO() fasm2frames.run(open(frm_fn, 'r'), fout) # Build a list of output used bits @@ -84,20 +85,20 @@ class TestStringMethods(unittest.TestCase): # Same check as above, but isolated test case def test_opkey_01_default(self): '''Optional key with binary omitted value should produce valid result''' - fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX") - fout = StringIO.StringIO() + fin = StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX") + fout = StringIO() fasm2frames.run(fin, fout) def test_opkey_01_1(self): - fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1") - fout = StringIO.StringIO() + fin = StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1") + fout = StringIO() fasm2frames.run(fin, fout) def test_opkey_enum(self): '''Optional key with enumerated value should produce syntax error''' # CLBLM_L.SLICEM_X0.AMUX.O6 !30_06 !30_07 !30_08 30_11 - fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.AMUX.O6") - fout = StringIO.StringIO() + fin = StringIO("CLBLM_L_X10Y102.SLICEM_X0.AMUX.O6") + fout = StringIO() try: fasm2frames.run(fin, fout) self.fail("Expected syntax error") @@ -111,8 +112,8 @@ class TestStringMethods(unittest.TestCase): def test_badkey(self): '''Bad key should throw syntax error''' - fin = StringIO.StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 2") - fout = StringIO.StringIO() + fin = StringIO("CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 2") + fout = StringIO() try: fasm2frames.run(fin, fout) self.fail("Expected syntax error") @@ -121,12 +122,12 @@ class TestStringMethods(unittest.TestCase): def test_dupkey(self): '''Duplicate key should throw syntax error''' - fin = StringIO.StringIO( + fin = StringIO( """\ CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 0 CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1 """) - fout = StringIO.StringIO() + fout = StringIO() try: fasm2frames.run(fin, fout) self.fail("Expected syntax error") @@ -137,12 +138,12 @@ CLBLM_L_X10Y102.SLICEM_X0.SRUSEDMUX 1 '''Verify sparse equivilent to normal encoding''' frm_fn = 'test_data/lut_int.fasm' - fout_sparse = StringIO.StringIO() + fout_sparse = StringIO() fasm2frames.run(open(frm_fn, 'r'), fout_sparse, sparse=True) fout_sparse_txt = fout_sparse.getvalue() bits_sparse = frm2bits(fout_sparse_txt) - fout_full = StringIO.StringIO() + fout_full = StringIO() fasm2frames.run(open(frm_fn, 'r'), fout_full, sparse=False) fout_full_txt = fout_full.getvalue() bits_full = frm2bits(fout_full_txt) From 697f83c97a616796c607c2fcff845b79f397714a Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 16 Oct 2018 23:48:43 -0700 Subject: [PATCH 32/42] fasm2frames env fix Signed-off-by: John McMaster --- utils/environment.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/environment.sh b/utils/environment.sh index 62cf4019..375c5f15 100644 --- a/utils/environment.sh +++ b/utils/environment.sh @@ -23,6 +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" +export XRAY_FASM2FRAMES="python3 ${XRAY_UTILS_DIR}/fasm2frames.py" From 62d89d67760cc3a5abe3c4d716de1989a917e19c Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 17 Oct 2018 12:00:10 -0700 Subject: [PATCH 33/42] tilegrid: add segment for tilegrid, glob deltas by default Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 4eb09f44..71d527e8 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -111,6 +111,8 @@ def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False): tile_baseaddrs = dict() verbose and print('') + verbose and print('%u tiles' % len(tiles)) + added = 0 for tile in tiles: for site_name in tile["sites"].keys(): if site_name not in site_baseaddr: @@ -127,7 +129,9 @@ def make_tile_baseaddrs(tiles, site_baseaddr, verbose=False): verbose and print( "baseaddr: %s.%s @ %s.0x%08x" % (tile["name"], site_name, bt, framebaseaddr)) + added += 1 + assert added return tile_baseaddrs @@ -465,7 +469,7 @@ def add_tile_bits(tile_db, baseaddr, offset, frames, words, height=None): block["height"] = height -def add_bits(database, segments): +def db_add_bits(database, segments): '''Transfer segment data into tiles''' for segment_name in segments.keys(): for block_type, (baseaddr, @@ -499,18 +503,15 @@ def add_bits(database, segments): height) -def annotate_segments(database, segments): - ''' +def db_add_segments(database, segments): # TODO: Migrate to new tilegrid format via library. This data is added for # compability with unconverted tools. Update tools then remove this data from # tilegrid.json. + # looks like only htmlgen is using this? for tiledata in database.values(): if "segment" in tiledata: segment = tiledata["segment"] - tiledata["frames"] = segments[segment]["frames"] - tiledata["words"] = segments[segment]["words"] tiledata["segment_type"] = segments[segment]["type"] - ''' def run(tiles_fn, json_fn, deltas_fns, verbose=False): @@ -530,10 +531,8 @@ def run(tiles_fn, json_fn, deltas_fns, verbose=False): seg_base_addr_lr_INT(database, segments, tiles_by_grid, verbose=verbose) seg_base_addr_up_INT(database, segments, tiles_by_grid, verbose=verbose) - add_bits(database, segments) - annotate_segments(database, segments) - - #database = {'BRAM_L_X6Y50': database["BRAM_L_X6Y50"], 'BRAM_L_X6Y80': database["BRAM_L_X6Y80"]} + db_add_bits(database, segments) + db_add_segments(database, segments) # Save json.dump( @@ -546,6 +545,7 @@ def run(tiles_fn, json_fn, deltas_fns, verbose=False): def main(): import argparse + import glob parser = argparse.ArgumentParser( description= @@ -557,10 +557,14 @@ def main(): parser.add_argument( '--tiles', default='tiles.txt', help='Input tiles.txt tcl output') parser.add_argument( - 'deltas', nargs='+', help='.bit diffs to create base addresses from') + 'deltas', nargs='*', help='.bit diffs to create base addresses from') args = parser.parse_args() - run(args.tiles, args.out, args.deltas, verbose=args.verbose) + deltas = args.deltas + if not args.deltas: + deltas = glob.glob('*.delta') + + run(args.tiles, args.out, deltas, verbose=args.verbose) if __name__ == '__main__': From 3d55b76b349f9319fe0de6b19abde4e7a6170a92 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 17 Oct 2018 12:02:31 -0700 Subject: [PATCH 34/42] tilegrid: fix help message Signed-off-by: John McMaster --- fuzzers/005-tilegrid/generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 71d527e8..c69db241 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -549,7 +549,7 @@ def main(): parser = argparse.ArgumentParser( description= - 'Generate a simple wrapper to test synthesizing an arbitrary verilog module' + 'Generate tilegrid.json from bitstream deltas' ) parser.add_argument('--verbose', action='store_true', help='') From 664f5868229d183f7edc09783150356a41ffa127 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 17 Oct 2018 12:03:21 -0700 Subject: [PATCH 35/42] htmlgen: use newer tilegrid format, misc cleanup Signed-off-by: John McMaster --- htmlgen/htmlgen.py | 954 ++++++++++++++++++++++++--------------------- 1 file changed, 518 insertions(+), 436 deletions(-) diff --git a/htmlgen/htmlgen.py b/htmlgen/htmlgen.py index 93063a72..01f945ab 100755 --- a/htmlgen/htmlgen.py +++ b/htmlgen/htmlgen.py @@ -1,126 +1,49 @@ #!/usr/bin/env python3 +# https://symbiflow.github.io/prjxray-db/ +# https://symbiflow.github.io/prjxray-db/artix7/ import os, sys, json, re from io import StringIO -import argparse -parser = argparse.ArgumentParser( - description="Generate a pretty HTML version of the documentation.") -parser.add_argument( - '--output', - default=os.path.join(os.path.curdir, 'html'), - help='Put the generated files in this directory (default current dir).') -parser.add_argument( - '--settings', - default=None, - help='Read the settings from file (default to environment).') +def mk_get_setting(settings_filename): + if settings_filename: + settings = { + 'XRAY_DATABASE_DIR': + os.path.abspath( + os.path.join(os.path.dirname(settings_filename), '..')), + } + with open(settings_filename) as f: + for line in f: + line = line.strip() + if not line.startswith("export "): + continue + key, value = line[7:].split('=', 1) + settings[key] = value[1:-1] -args = parser.parse_args() - -if args.settings: - settings_filename = args.settings - - settings = { - 'XRAY_DATABASE_DIR': - os.path.abspath( - os.path.join(os.path.dirname(settings_filename), '..')), - } - with open(settings_filename) as f: - for line in f: - line = line.strip() - if not line.startswith("export "): - continue - key, value = line[7:].split('=', 1) - settings[key] = value[1:-1] - - def get_setting(name): - return settings[name] -else: - - def get_setting(name): - return os.getenv(name) + return lambda name: settings[name] + else: + return os.getenv -db_dir = os.path.join( - get_setting("XRAY_DATABASE_DIR"), get_setting("XRAY_DATABASE")) +get_setting = mk_get_setting(None) -def db_open(fn): +def db_open(fn, db_dir): filename = os.path.join(db_dir, fn) if not os.path.exists(filename): return StringIO("") return open(os.path.join(db_dir, fn)) -def out_open(fn): - out_dir = os.path.join(args.output, get_setting("XRAY_DATABASE")) +def out_open(fn, output): + out_dir = os.path.join(output, get_setting("XRAY_DATABASE")) os.makedirs(out_dir, exist_ok=True) fp = os.path.join(out_dir, fn) print("Writing %s" % fp) return open(fp, "w") -clb_bitgroups_db = [ - # copy&paste from zero_db in dbfixup.py - "00_21 00_22 00_26 01_28|00_25 01_20 01_21 01_24", - "00_23 00_30 01_22 01_25|00_27 00_29 01_26 01_29", - "01_12 01_14 01_16 01_18|00_10 00_11 01_09 01_10", - "00_13 01_17 00_15 00_17|00_18 00_19 01_13 00_14", - "00_34 00_38 01_33 01_37|00_35 00_39 01_38 01_40", - "00_33 00_41 01_32 01_34|00_37 00_42 01_36 01_41", - - # other manual groupings for individual bits - "00_02 00_05 00_09 01_04|00_07 01_05 01_06", - "00_01 00_06 01_00 01_08|00_03 01_01 01_02", - "00_59 01_54 01_58 01_61|00_57 00_58 01_56", - "00_55 00_63 01_57 01_62|00_61 00_62 01_60", - "00_43 00_47 00_50 00_53 00_54 01_42|00_51 01_50 01_52", - "00_49 01_44 01_45 01_48 01_49 01_53|00_45 00_46 01_46", -] - -hclk_bitgroups_db = [ - # manual groupings - "03_14 03_15 04_14 04_15|00_15 00_16 01_14 01_15", - "02_16 03_16 04_16 05_16|02_14 02_15 05_14 05_15", - "02_18 02_19 05_18 05_19|00_17 00_18 01_16 01_17", - "03_18 03_19 04_18 04_19|02_17 03_17 04_17 05_17", - "02_20 02_21 05_20 05_21|02_22 03_22 04_22 05_22", - "02_29 03_29 04_29 05_29|03_30 03_31 04_30 04_31", - "02_26 02_27 05_26 05_27|02_28 03_28 04_28 05_28", - "02_23 03_23 04_23 05_23|03_24 03_25 04_24 04_25", -] - -# groupings for SNWE bits in frames 2..7 -for i in range(0, 64, 4): - clb_bitgroups_db.append( - "02_%02d 03_%02d 05_%02d 06_%02d 07_%02d|05_%02d 03_%02d 04_%02d 04_%02d" - % (i + 1, i, i, i, i + 1, i + 3, i + 1, i + 1, i + 2)) - clb_bitgroups_db.append( - "02_%02d 04_%02d 05_%02d 05_%02d 06_%02d|02_%02d 03_%02d 04_%02d 07_%02d" - % (i + 2, i, i + 1, i + 2, i + 2, i + 3, i + 2, i + 3, i + 3)) - -clb_left_bits = set() -clb_right_bits = set() - -for entry in clb_bitgroups_db: - a, b = entry.split("|") - for bit in a.split(): - clb_left_bits.add(bit) - for bit in b.split(): - clb_right_bits.add(bit) - -hclk_left_bits = set() -hclk_right_bits = set() - -for entry in hclk_bitgroups_db: - a, b = entry.split("|") - for bit in a.split(): - hclk_left_bits.add(bit) - for bit in b.split(): - hclk_right_bits.add(bit) - - class UnionFind: def __init__(self): self.parents = dict() @@ -143,64 +66,38 @@ class UnionFind: self.parents[a] = b -################################################# -# Loading Raw Source Data - -grid = None -cfgbits = dict() -cfgbits_r = dict() -maskbits = dict() -ppips = dict() -routebits = dict() -routezbits = dict() - -print("Loading tilegrid.") -with db_open("tilegrid.json") as f: - data = f.read() - if not data: - grid = { - "NULL": { - "grid_x": 0, - "grid_y": 0, - "type": "NULL", - } - } - else: - grid = json.loads(data) - - -def db_read(tiletype): - cfgbits[tiletype] = dict() - cfgbits_r[tiletype] = dict() - maskbits[tiletype] = set() - ppips[tiletype] = dict() - routebits[tiletype] = dict() - routezbits[tiletype] = dict() +def db_read(dbstate, tiletype, db_dir): + dbstate.cfgbits[tiletype] = dict() + dbstate.cfgbits_r[tiletype] = dict() + dbstate.maskbits[tiletype] = set() + dbstate.ppips[tiletype] = dict() + dbstate.routebits[tiletype] = dict() + dbstate.routezbits[tiletype] = dict() def add_pip_bits(tag, bits): - if tag not in routebits[tiletype]: - routebits[tiletype][tag] = set() - routezbits[tiletype][tag] = set() + if tag not in dbstate.routebits[tiletype]: + dbstate.routebits[tiletype][tag] = set() + dbstate.routezbits[tiletype][tag] = set() for bit in bits: if bit[0] == "!": - if bit[1:] not in routezbits[tiletype]: - routezbits[tiletype][bit[1:]] = set() - routezbits[tiletype][bit[1:]].add(tag) + if bit[1:] not in dbstate.routezbits[tiletype]: + dbstate.routezbits[tiletype][bit[1:]] = set() + dbstate.routezbits[tiletype][bit[1:]].add(tag) else: - if bit not in routebits[tiletype]: - routebits[tiletype][bit] = set() - routebits[tiletype][bit].add(tag) + if bit not in dbstate.routebits[tiletype]: + dbstate.routebits[tiletype][bit] = set() + dbstate.routebits[tiletype][bit].add(tag) def add_cfg_bits(tag, bits): - if tag not in cfgbits[tiletype]: - cfgbits[tiletype][tag] = set() + if tag not in dbstate.cfgbits[tiletype]: + dbstate.cfgbits[tiletype][tag] = set() for bit in bits: - cfgbits[tiletype][tag].add(bit) - if bit not in cfgbits_r[tiletype]: - cfgbits_r[tiletype][bit] = set() - cfgbits_r[tiletype][bit].add(tag) + dbstate.cfgbits[tiletype][tag].add(bit) + if bit not in dbstate.cfgbits_r[tiletype]: + dbstate.cfgbits_r[tiletype][bit] = set() + dbstate.cfgbits_r[tiletype][bit].add(tag) - with db_open("segbits_%s.db" % tiletype) as f: + with db_open("segbits_%s.db" % tiletype, db_dir) as f: for line in f: line = line.split() tag, bits = line[0], line[1:] @@ -215,67 +112,157 @@ def db_read(tiletype): else: add_cfg_bits(tag, bits) - with db_open("ppips_%s.db" % tiletype) as f: + with db_open("ppips_%s.db" % tiletype, db_dir) as f: for line in f: tag, typ = line.split() - ppips[tiletype][tag] = typ + dbstate.ppips[tiletype][tag] = typ if tiletype not in ["int_l", "int_r"]: - with db_open("mask_%s.db" % tiletype) as f: + with db_open("mask_%s.db" % tiletype, db_dir) as f: for line in f: tag, bit = line.split() assert tag == "bit" - maskbits[tiletype].add(bit) + dbstate.maskbits[tiletype].add(bit) else: for t in ["clbll_l", "clbll_r", "clblm_l", "clblm_r", "dsp_l", "dsp_r", "bram_l", "bram_r"]: - with db_open("mask_%s.db" % t) as f: + with db_open("mask_%s.db" % t, db_dir) as f: for line in f: tag, bit = line.split() assert tag == "bit" frameidx, bitidx = bit.split("_") - maskbits[tiletype].add( + dbstate.maskbits[tiletype].add( "%02d_%02d" % (int(frameidx), int(bitidx) % 64)) -db_read("int_l") -db_read("int_r") +def init_bitdb(): + clb_bitgroups_db = [ + # copy&paste from zero_db in dbfixup.py + "00_21 00_22 00_26 01_28|00_25 01_20 01_21 01_24", + "00_23 00_30 01_22 01_25|00_27 00_29 01_26 01_29", + "01_12 01_14 01_16 01_18|00_10 00_11 01_09 01_10", + "00_13 01_17 00_15 00_17|00_18 00_19 01_13 00_14", + "00_34 00_38 01_33 01_37|00_35 00_39 01_38 01_40", + "00_33 00_41 01_32 01_34|00_37 00_42 01_36 01_41", -db_read("hclk_l") -db_read("hclk_r") + # other manual groupings for individual bits + "00_02 00_05 00_09 01_04|00_07 01_05 01_06", + "00_01 00_06 01_00 01_08|00_03 01_01 01_02", + "00_59 01_54 01_58 01_61|00_57 00_58 01_56", + "00_55 00_63 01_57 01_62|00_61 00_62 01_60", + "00_43 00_47 00_50 00_53 00_54 01_42|00_51 01_50 01_52", + "00_49 01_44 01_45 01_48 01_49 01_53|00_45 00_46 01_46", + ] -db_read("clbll_l") -db_read("clbll_r") + hclk_bitgroups_db = [ + # manual groupings + "03_14 03_15 04_14 04_15|00_15 00_16 01_14 01_15", + "02_16 03_16 04_16 05_16|02_14 02_15 05_14 05_15", + "02_18 02_19 05_18 05_19|00_17 00_18 01_16 01_17", + "03_18 03_19 04_18 04_19|02_17 03_17 04_17 05_17", + "02_20 02_21 05_20 05_21|02_22 03_22 04_22 05_22", + "02_29 03_29 04_29 05_29|03_30 03_31 04_30 04_31", + "02_26 02_27 05_26 05_27|02_28 03_28 04_28 05_28", + "02_23 03_23 04_23 05_23|03_24 03_25 04_24 04_25", + ] -db_read("clblm_l") -db_read("clblm_r") + # groupings for SNWE bits in frames 2..7 + for i in range(0, 64, 4): + clb_bitgroups_db.append( + "02_%02d 03_%02d 05_%02d 06_%02d 07_%02d|05_%02d 03_%02d 04_%02d 04_%02d" + % (i + 1, i, i, i, i + 1, i + 3, i + 1, i + 1, i + 2)) + clb_bitgroups_db.append( + "02_%02d 04_%02d 05_%02d 05_%02d 06_%02d|02_%02d 03_%02d 04_%02d 07_%02d" + % (i + 2, i, i + 1, i + 2, i + 2, i + 3, i + 2, i + 3, i + 3)) -db_read("dsp_l") -db_read("dsp_r") + return clb_bitgroups_db, hclk_bitgroups_db -db_read("bram_l") -db_read("bram_r") -################################################# -# Create Tilegrid Page +def init_hclk_bits(hclk_bitgroups_db): + hclk_left_bits = set() + hclk_right_bits = set() -grid_range = None -grid_map = dict() + for entry in hclk_bitgroups_db: + a, b = entry.split("|") + for bit in a.split(): + hclk_left_bits.add(bit) + for bit in b.split(): + hclk_right_bits.add(bit) -with out_open("index.html") as f: - print( - "X-Ray %s Database" % - get_setting("XRAY_DATABASE").upper(), - file=f) - print( - "

X-Ray %s Database

" % get_setting("XRAY_DATABASE").upper(), - file=f) + return hclk_left_bits, hclk_right_bits - print( - "

Part: %s
ROI: %s
ROI Frames: %s

" % ( - get_setting("XRAY_PART"), get_setting("XRAY_ROI"), - get_setting("XRAY_ROI_FRAMES")), - file=f) + +def init_clb_bits(clb_bitgroups_db): + clb_left_bits = set() + clb_right_bits = set() + + for entry in clb_bitgroups_db: + a, b = entry.split("|") + for bit in a.split(): + clb_left_bits.add(bit) + for bit in b.split(): + clb_right_bits.add(bit) + + return clb_left_bits, clb_right_bits + + +class DBState(): + def __init__(self): + self.cfgbits = dict() + self.cfgbits_r = dict() + self.maskbits = dict() + self.ppips = dict() + self.routebits = dict() + self.routezbits = dict() + + +class Tweaks(): + def __init__(self): + pass + + +def load_tilegrid(db_dir, verbose=False): + print("Loading tilegrid.") + with db_open("tilegrid.json", db_dir) as f: + data = f.read() + if not data: + print('WARNING: loading fake tilegrid') + grid = { + "NULL": { + "grid_x": 0, + "grid_y": 0, + "type": "NULL", + } + } + else: + grid = json.loads(data) + return grid + + +def db_reads(dbstate, db_dir): + + db_read(dbstate, "int_l", db_dir) + db_read(dbstate, "int_r", db_dir) + + db_read(dbstate, "hclk_l", db_dir) + db_read(dbstate, "hclk_r", db_dir) + + db_read(dbstate, "clbll_l", db_dir) + db_read(dbstate, "clbll_r", db_dir) + + db_read(dbstate, "clblm_l", db_dir) + db_read(dbstate, "clblm_r", db_dir) + + db_read(dbstate, "dsp_l", db_dir) + db_read(dbstate, "dsp_r", db_dir) + + db_read(dbstate, "bram_l", db_dir) + db_read(dbstate, "bram_r", db_dir) + + +def place_tiles(grid): + grid_map = dict() + grid_range = None for tilename, tiledata in grid.items(): grid_x = tiledata["grid_x"] @@ -289,111 +276,140 @@ with out_open("index.html") as f: grid_range[1] = min(grid_range[1], grid_y) grid_range[2] = max(grid_range[2], grid_x) grid_range[3] = max(grid_range[3], grid_y) + return grid_map, grid_range - print("", file=f) - for grid_y in range(grid_range[1], grid_range[3] + 1): - print("", file=f) +def tile_bgcolor(tiledata): + bgcolor = "#aaaaaa" + if tiledata["type"] in ["INT_L", "INT_R"]: bgcolor = "#aaaaff" + if tiledata["type"] in ["CLBLL_L", "CLBLL_R"]: bgcolor = "#ffffaa" + if tiledata["type"] in ["CLBLM_L", "CLBLM_R"]: bgcolor = "#ffaaaa" + if tiledata["type"] in ["HCLK_L", "HCLK_R"]: bgcolor = "#aaffaa" - for grid_x in range(grid_range[0], grid_range[2] + 1): - tilename = grid_map[(grid_x, grid_y)] - tiledata = grid[tilename] - segdata = None + if tiledata["type"] in ["BRAM_INT_INTERFACE_L", "BRAM_L"]: + bgcolor = "#aaffff" + if tiledata["type"] in ["BRAM_INT_INTERFACE_R", "BRAM_R"]: + bgcolor = "#aaffff" - bgcolor = "#aaaaaa" - if tiledata["type"] in ["INT_L", "INT_R"]: bgcolor = "#aaaaff" - if tiledata["type"] in ["CLBLL_L", "CLBLL_R"]: bgcolor = "#ffffaa" - if tiledata["type"] in ["CLBLM_L", "CLBLM_R"]: bgcolor = "#ffaaaa" - if tiledata["type"] in ["HCLK_L", "HCLK_R"]: bgcolor = "#aaffaa" + if tiledata["type"] in ["INT_INTERFACE_L", "DSP_L"]: + bgcolor = "#ffaaff" + if tiledata["type"] in ["INT_INTERFACE_R", "DSP_R"]: + bgcolor = "#ffaaff" - if tiledata["type"] in ["BRAM_INT_INTERFACE_L", "BRAM_L"]: - bgcolor = "#aaffff" - if tiledata["type"] in ["BRAM_INT_INTERFACE_R", "BRAM_R"]: - bgcolor = "#aaffff" + return bgcolor - if tiledata["type"] in ["INT_INTERFACE_L", "DSP_L"]: - bgcolor = "#ffaaff" - if tiledata["type"] in ["INT_INTERFACE_R", "DSP_R"]: - bgcolor = "#ffaaff" - title = [tilename] +def tile_print_td(f, title, tilename, bgcolor, tiledata, dbstate): + tilename = tilename.replace("INT_INTERFACE_", "INTF_") + tilename = tilename.replace("_X", "
X") + tilename = tilename.replace("B_TERM", "B
TERM") - if "segment" in tiledata: - segdata = grid["segments"][tiledata["segment"]] - title.append(tiledata["segment"]) + print( + "" + % (tiledata["type"].lower(), tilename.replace("_X", "
X")), + file=f) + else: + print( + "%s" % tilename.replace("_X", "
X").replace( + "B_TERM", "B
TERM"), + file=f) - title.append("GRID_POSITION: %d %d" % (grid_x, grid_y)) - if "sites" in tiledata: - for sitename, sitetype in tiledata["sites"].items(): - title.append("%s site: %s" % (sitetype, sitename)) +def tile_title(tilename, tiledata, grid_x, grid_y, grid): + title = [tilename] + segdata = None - if "segment" in tiledata: - if "baseaddr" in segdata: - title.append( - "Baseaddr: %s %d" % tuple(segdata["baseaddr"])) - else: - print( - "Warning: no baseaddr in segment %s (via tile %s)." % - (tiledata["segment"], tilename)) + if "segment" in tiledata: + # FIXME: BRAM support + segdata = grid[tilename]['bits'].get('CLB_IO_CLK', None) + title.append(tiledata["segment"]) - tilename = tilename.replace("INT_INTERFACE_", "INTF_") - tilename = tilename.replace("_X", "
X") - tilename = tilename.replace("B_TERM", "B
TERM") + title.append("GRID_POSITION: %d %d" % (grid_x, grid_y)) + if "sites" in tiledata: + for sitename, sitetype in tiledata["sites"].items(): + title.append("%s site: %s" % (sitetype, sitename)) + + if "segment" in tiledata: + if "baseaddr" in segdata: + #title.append("Baseaddr: %s %d" % tuple(segdata["baseaddr"])) + title.append("Baseaddr: %s" % segdata["baseaddr"]) + else: print( - "" - % ( - tiledata["type"].lower(), - tilename.replace("_X", "
X")), - file=f) - else: - print( - "%s" % tilename.replace( - "_X", "
X").replace("B_TERM", "B
TERM"), - file=f) + "Warning: no baseaddr in segment %s (via tile %s)." % + (tiledata["segment"], tilename)) - print("", file=f) - - print("
" + % (bgcolor, "\n".join(title)), + file=f) + if tiledata["type"].lower() in dbstate.cfgbits: + print( + "%s" - % (bgcolor, "\n".join(title)), - file=f) - if tiledata["type"].lower() in cfgbits: - print( - "%s
", file=f) - print("", file=f) - -################################################# -# Create Segment Pages + return title -def get_bit_info(frameidx, bitidx, tiletype): - bit_pos = "%02d_%02d" % (frameidx, bitidx) - bit_name = cfgbits_r[tiletype][bit_pos] if bit_pos in cfgbits_r[ - tiletype] else None +def mk_tilegrid_page(dbstate, output, grid): + with out_open("index.html", output) as f: + print( + "X-Ray %s Database" % + get_setting("XRAY_DATABASE").upper(), + file=f) + print( + "

X-Ray %s Database

" % + get_setting("XRAY_DATABASE").upper(), + file=f) - if bit_name is None and bit_pos in routebits[tiletype]: - bit_name = routebits[tiletype][bit_pos] + print( + "

Part: %s
ROI: %s
ROI Frames: %s

" % ( + get_setting("XRAY_PART"), get_setting("XRAY_ROI"), + get_setting("XRAY_ROI_FRAMES")), + file=f) - if bit_name is None and bit_pos in routezbits[tiletype]: - bit_name = routezbits[tiletype][bit_pos] + grid_map, grid_range = place_tiles(grid) + + print("", file=f) + + for grid_y in range(grid_range[1], grid_range[3] + 1): + print("", file=f) + + for grid_x in range(grid_range[0], grid_range[2] + 1): + tilename = grid_map[(grid_x, grid_y)] + tiledata = grid[tilename] + + bgcolor = tile_bgcolor(tiledata) + title = tile_title(tilename, tiledata, grid_x, grid_y, grid) + tile_print_td(f, title, tilename, bgcolor, tiledata, dbstate) + + print("", file=f) + + print("
", file=f) + print("", file=f) + + +def get_bit_name(dbstate, frameidx, bitidx, bit_pos, tiletype): + bit_name = dbstate.cfgbits_r[tiletype][ + bit_pos] if bit_pos in dbstate.cfgbits_r[tiletype] else None + + if bit_name is None and bit_pos in dbstate.routebits[tiletype]: + bit_name = dbstate.routebits[tiletype][bit_pos] + + if bit_name is None and bit_pos in dbstate.routezbits[tiletype]: + bit_name = dbstate.routezbits[tiletype][bit_pos] if bit_name is None and tiletype in ["clbll_l", "clbll_r", "clblm_l", "clblm_r", "dsp_l", "dsp_r", "bram_l", "bram_r"]: int_tile_type = "int_" + tiletype[-1] bit_int_pos = "%02d_%02d" % (frameidx, bitidx % 64) - bit_name = cfgbits_r[int_tile_type][ - bit_int_pos] if bit_int_pos in cfgbits_r[int_tile_type] else None + bit_name = dbstate.cfgbits_r[int_tile_type][ + bit_int_pos] if bit_int_pos in dbstate.cfgbits_r[ + int_tile_type] else None - if bit_name is None and bit_int_pos in routebits[int_tile_type]: - bit_name = routebits[int_tile_type][bit_int_pos] + if bit_name is None and bit_int_pos in dbstate.routebits[int_tile_type]: + bit_name = dbstate.routebits[int_tile_type][bit_int_pos] - if bit_name is None and bit_int_pos in routezbits[int_tile_type]: - bit_name = routezbits[int_tile_type][bit_int_pos] - - if bit_name is not None: - return bit_pos, "INT", [bit_pos], "#88aaff" + if bit_name is None and bit_int_pos in dbstate.routezbits[ + int_tile_type]: + bit_name = dbstate.routezbits[int_tile_type][bit_int_pos] if bit_name is not None: if len(bit_name) <= 1: @@ -402,11 +418,23 @@ def get_bit_info(frameidx, bitidx, tiletype): for n in bit_name: bit_name = ".".join(n.split(".")[:-1]) + return bit_name + + +def get_bit_info(dbstate, frameidx, bitidx, tiletype): + bit_pos = "%02d_%02d" % (frameidx, bitidx) + + bit_name = get_bit_name(dbstate, frameidx, bitidx, bit_pos, tiletype) + if tiletype in ["clbll_l", "clbll_r", "clblm_l", "clblm_r", "dsp_l", + "dsp_r", "bram_l", "bram_r"]: + if bit_name is not None: + return bit_pos, "INT", [bit_pos], "#88aaff" + label = None title = [bit_pos] bgcolor = "#aaaaaa" - if bit_pos not in maskbits[tiletype]: + if bit_pos not in dbstate.maskbits[tiletype]: label = " " bgcolor = "#444444" title.append("UNUSED ?") @@ -580,7 +608,7 @@ def get_bit_info(frameidx, bitidx, tiletype): return bit_pos, label, title, bgcolor -def gen_table(tiletype, f): +def gen_table(dbstate, tiletype, f): print( """ ", file=f) - - print("

", file=f) - print("

%s

" % title, file=f) - print("", file=f) - print("", file=f) - - for bit in grp_bits: - print("" % bit, file=f) - print("", file=f) - - lines = list() - for pip, bits in sorted(gdata.items()): - line = " -->" % (pip) - for bit in grp_bits: - c = "-" - if bit in routebits[tiletype] and pip in routebits[ - tiletype][bit]: - c = "1" - if bit in routezbits[tiletype] and pip in routezbits[ - tiletype][bit]: - c = "0" - line = "%s%s" % (c, line, c) - lines.append(line) - - trstyle = "" - for line in sorted(lines): - trstyle = " bgcolor=\"#dddddd\"" if trstyle == "" else "" - print("", file=f) - print("", file=f) - print("", file=f) + print("

", file=f) + print("

%s

" % title, file=f) + print("
PIP %s 
%s%s
", file=f) + print("", file=f) + + for bit in grp_bits: + print("" % bit, file=f) + print("", file=f) + + lines = list() + for pip, bits in sorted(gdata.items()): + line = " -->" % (pip) + for bit in grp_bits: + c = "-" + if bit in dbstate.routebits[ + tiletype] and pip in dbstate.routebits[ + tiletype][bit]: + c = "1" + if bit in dbstate.routezbits[ + tiletype] and pip in dbstate.routezbits[ + tiletype][bit]: + c = "0" + line = "%s%s" % ( + c, line, c) + lines.append(line) + + trstyle = "" + for line in sorted(lines): + trstyle = " bgcolor=\"#dddddd\"" if trstyle == "" else "" + print("
PIP %s 
%s%s