From 12c02c347b7929238f0e7ef7d88d4eb1dcc95e97 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 11:41:36 +0100 Subject: [PATCH 01/16] block_type_s2i Signed-off-by: John McMaster --- prjxray/util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/prjxray/util.py b/prjxray/util.py index 6fbe2bd8..16f28455 100644 --- a/prjxray/util.py +++ b/prjxray/util.py @@ -137,6 +137,9 @@ block_type_i2s = { # special...maybe should error until we know what it is? # 3: 'RESERVED', } +block_type_s2i = {} +for k, v in block_type_i2s.items(): + block_type_s2i[v] = k def addr2btype(base_addr): From b8c5af805282e1e0f472e81a039b84128afa78d0 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 11:42:01 +0100 Subject: [PATCH 02/16] partgen py utilities (gen_part_base_addrs) Signed-off-by: John McMaster --- prjxray/bitstream.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/prjxray/bitstream.py b/prjxray/bitstream.py index e0d7d123..74818159 100644 --- a/prjxray/bitstream.py +++ b/prjxray/bitstream.py @@ -1,3 +1,7 @@ +import json +import os +from prjxray import util + # Break frames into WORD_SIZE bit words. WORD_SIZE_BITS = 32 @@ -71,3 +75,40 @@ def load_bitdata2(f): bitdata[frame][wordidx].add(bitidx) return bitdata + + +def gen_part_base_addrs(): + """ + Return (block_type, top_bottom, cfg_row, cfg_col, frame_count) + Where: + -block_type ("bus"): typically CLB_IO_CLK, sometimes BLOCK_RAM + -top_bottom: either "top" or "bottom" + -cfg_row: a relative row + -cfg_col: a relative column + -frame_count: number of frames to fully configure this minor address + + Example: + ('CLB_IO_CLK', 'bottom', 0, 3, 36) + ('BLOCK_RAM', 'top', 0, 1, 128) + ('CLB_IO_CLK', 'top', 1, 34, 28) + """ + fn = os.getenv("XRAY_PART_YAML").replace(".yaml", ".json") + j = json.load(open(fn, "r")) + for tbk, tbv in j["global_clock_regions"].items(): + for rowk, rowv in tbv["rows"].items(): + for busk, busv in rowv["configuration_buses"].items(): + for colk, colv in busv["configuration_columns"].items(): + yield ( + busk, tbk, int(rowk), int(colk), colv["frame_count"]) + + +def addr_bits2word(block_type, top_bottom, cfg_row, cfg_col, minor_addr): + """Convert a deconstructed address to a 32 bit word""" + # https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + ret = 0 + ret |= util.block_type_s2i[block_type] << 23 + ret |= {"top": 0, "bottom": 1}[top_bottom] << 22 + ret |= cfg_row << 17 + ret |= cfg_col << 7 + ret |= minor_addr + return ret From 06347fdd3a36ba85b691f6ce9546d93da93a021c Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 11:42:40 +0100 Subject: [PATCH 03/16] addrwidth utility Signed-off-by: John McMaster --- utils/addrwidth.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 utils/addrwidth.py diff --git a/utils/addrwidth.py b/utils/addrwidth.py new file mode 100755 index 00000000..7b499f84 --- /dev/null +++ b/utils/addrwidth.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import json +from prjxray import bitstream + + +def gen_addrs(): + for block_type, top_bottom, cfg_row, cfg_col, frame_count in bitstream.gen_part_base_addrs( + ): + yield bitstream.addr_bits2word( + block_type, top_bottom, cfg_row, cfg_col, 0), frame_count + + +def run(verbose=False): + for addr, frame_count in sorted(gen_addrs()): + print("0x%08X: %u" % (addr, frame_count)) + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description='Print number of frames at a base address') + args = parser.parse_args() + + run(verbose=False) + + +if __name__ == '__main__': + main() From 4ddf516d98bd9656486536595429bda6096ee518 Mon Sep 17 00:00:00 2001 From: Tomasz Michalak Date: Tue, 8 Jan 2019 13:14:02 +0100 Subject: [PATCH 04/16] Fix htmlgen #173 Signed-off-by: Tomasz Michalak --- htmlgen/htmlgen.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/htmlgen/htmlgen.py b/htmlgen/htmlgen.py index 26bbede6..0d83b036 100755 --- a/htmlgen/htmlgen.py +++ b/htmlgen/htmlgen.py @@ -425,10 +425,6 @@ 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] @@ -490,7 +486,7 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype): else: bgcolor = "#ff0000" - m = re.search(r"\.([ABCD])DI1MUX\.", bit_name) + m = re.search(r"\.([ABCD])LUT.DI1MUX\.", bit_name) if m: bgcolor = "#ffffaa" label = m.group(1) + "DI1" @@ -581,11 +577,11 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype): bgcolor = "#4466bb" label = "LH" - if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]FF.DMUX", bit_name): + if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]5?FFMUX", bit_name): bgcolor = "#88aaff" label = "DMX" - if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]MUX", bit_name): + if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]OUTMUX", bit_name): bgcolor = "#aa88ff" label = "OMX" From 065bd6588b472f742e24f979f7bc859decac6061 Mon Sep 17 00:00:00 2001 From: Tomasz Michalak Date: Tue, 8 Jan 2019 13:14:02 +0100 Subject: [PATCH 05/16] Fix htmlgen #173 Signed-off-by: Tomasz Michalak --- htmlgen/htmlgen.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/htmlgen/htmlgen.py b/htmlgen/htmlgen.py index 26bbede6..0d83b036 100755 --- a/htmlgen/htmlgen.py +++ b/htmlgen/htmlgen.py @@ -425,10 +425,6 @@ 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] @@ -490,7 +486,7 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype): else: bgcolor = "#ff0000" - m = re.search(r"\.([ABCD])DI1MUX\.", bit_name) + m = re.search(r"\.([ABCD])LUT.DI1MUX\.", bit_name) if m: bgcolor = "#ffffaa" label = m.group(1) + "DI1" @@ -581,11 +577,11 @@ def get_bit_info(dbstate, frameidx, bitidx, tiletype): bgcolor = "#4466bb" label = "LH" - if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]FF.DMUX", bit_name): + if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]5?FFMUX", bit_name): bgcolor = "#88aaff" label = "DMX" - if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]MUX", bit_name): + if re.match("^CLBL[LM]_[LR].SLICE[LM]_X[01].[ABCD]OUTMUX", bit_name): bgcolor = "#aa88ff" label = "OMX" From 075a939ffc421d9f33cc88b01b540aa7d8036fed Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 10:57:41 +0100 Subject: [PATCH 06/16] add_site_group_zero() allow unused zero_val for empty tile Signed-off-by: John McMaster --- prjxray/segmaker.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/prjxray/segmaker.py b/prjxray/segmaker.py index 24fdc074..75199756 100644 --- a/prjxray/segmaker.py +++ b/prjxray/segmaker.py @@ -53,8 +53,8 @@ def add_site_group_zero(segmk, site, prefix, vals, zero_val, val): vals: all possible tag enum vals zero_val: tag value known to have no bits set ''' - assert zero_val in vals, "Got %s, need %s" % (zero_val, vals) - assert val in vals, "Got %s, need %s" % (val, vals) + # assert zero_val in vals, "Got %s, need %s" % (zero_val, vals) + assert val in vals or val == zero_val, "Got %s, need %s" % (val, vals) if val == zero_val: # Zero symbol occured, none of the others did @@ -64,10 +64,11 @@ def add_site_group_zero(segmk, site, prefix, vals, zero_val, val): else: # Only add the occured symbol tag = prefix + val - segmk.add_site_tag(site, tag, 1) - # And zero so that it has something to solve against - tag = prefix + zero_val - segmk.add_site_tag(site, tag, 0) + segmk.add_site_tag(site, tag, True) + if zero_val in vals: + # And zero so that it has something to solve against + tag = prefix + zero_val + segmk.add_site_tag(site, tag, False) class Segmaker: From f3fade68bdad9b474cc82cd93ca5587b74384250 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 00:41:06 +0100 Subject: [PATCH 07/16] iob-stag: IOB supertag Signed-off-by: John McMaster --- fuzzers/034-iob-stag/Makefile | 20 ++++ fuzzers/034-iob-stag/bits.dbf | 0 fuzzers/034-iob-stag/generate.py | 18 ++++ fuzzers/034-iob-stag/generate.sh | 5 + fuzzers/034-iob-stag/generate.tcl | 90 ++++++++++++++++++ fuzzers/034-iob-stag/top.py | 152 ++++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+) create mode 100644 fuzzers/034-iob-stag/Makefile create mode 100644 fuzzers/034-iob-stag/bits.dbf create mode 100644 fuzzers/034-iob-stag/generate.py create mode 100644 fuzzers/034-iob-stag/generate.sh create mode 100644 fuzzers/034-iob-stag/generate.tcl create mode 100644 fuzzers/034-iob-stag/top.py diff --git a/fuzzers/034-iob-stag/Makefile b/fuzzers/034-iob-stag/Makefile new file mode 100644 index 00000000..1c2bc8da --- /dev/null +++ b/fuzzers/034-iob-stag/Makefile @@ -0,0 +1,20 @@ +N := 1 +include ../fuzzer.mk + +SEGDATAS=$(addsuffix /segdata_liob33.txt,$(SPECIMENS)) + +database: build/segbits_liob33.db + +build/segbits_liob33.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -c -1 -o build/segbits_liob33.rdb $(SEGDATAS) + +build/segbits_liob33.db: build/segbits_liob33.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@ + ${XRAY_MASKMERGE} build/mask_liob33.db $(SEGDATAS) + +pushdb: + ${XRAY_MERGEDB} liob33 build/segbits_liob33.db + ${XRAY_MERGEDB} mask_liob33 build/mask_liob33.db + +.PHONY: database pushdb + diff --git a/fuzzers/034-iob-stag/bits.dbf b/fuzzers/034-iob-stag/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/034-iob-stag/generate.py b/fuzzers/034-iob-stag/generate.py new file mode 100644 index 00000000..3667d5a7 --- /dev/null +++ b/fuzzers/034-iob-stag/generate.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +from prjxray import segmaker + +segmk = Segmaker("design.bits") + +print("Loading params") +f = open('params.csv', 'r') +f.readline() +for l in f: + l = l.strip() + site, name, dir_, cell = l.split(',') + segmaker.add_site_group_zero( + segmk, site, "MACRO.", ("INPUT", "OUTPUT"), "", dir_.upper()) + +segmk.compile() +segmk.write() diff --git a/fuzzers/034-iob-stag/generate.sh b/fuzzers/034-iob-stag/generate.sh new file mode 100644 index 00000000..f42f840c --- /dev/null +++ b/fuzzers/034-iob-stag/generate.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -ex +source ${XRAY_DIR}/utils/top_generate.sh + diff --git a/fuzzers/034-iob-stag/generate.tcl b/fuzzers/034-iob-stag/generate.tcl new file mode 100644 index 00000000..556d5814 --- /dev/null +++ b/fuzzers/034-iob-stag/generate.tcl @@ -0,0 +1,90 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc make_io_pin_sites {} { + # get all possible IOB pins + foreach pad [get_package_pins -filter "IS_GENERAL_PURPOSE == 1"] { + set site [get_sites -of_objects $pad] + if {[llength $site] == 0} { + continue + } + if [string match IOB33* [get_property SITE_TYPE $site]] { + dict append io_pin_sites $site $pad + } + } + return $io_pin_sites +} + +proc load_pin_lines {} { + # IOB_X0Y103 clk input + # IOB_X0Y129 do[0] output + + set fp [open "params.csv" r] + set pin_lines {} + for {gets $fp line} {$line != ""} {gets $fp line} { + lappend pin_lines [split $line ","] + } + close $fp + return $pin_lines +} + +proc loc_pins {} { + set pin_lines [load_pin_lines] + set io_pin_sites [make_io_pin_sites] + + set fp [open "design.csv" w] + puts $fp "port,site,tile,pin,val" + + puts "Looping" + for {set idx 1} {$idx < [llength $pin_lines]} {incr idx} { + set line [lindex $pin_lines $idx] + puts "$line" + + set site_str [lindex $line 0] + set pin_str [lindex $line 1] + set io [lindex $line 2] + set cell_str [lindex $line 3] + # Skip unused site + if {"$pin_str" == ""} { + continue + } + + # Have: site + # Want: pin for site + set site [get_sites $site_str] + set pad_bel [get_bels -of_objects $site -filter {TYPE =~ PAD && NAME =~ IOB_*}] + set port [get_ports $pin_str] + set tile [get_tiles -of_objects $site] + set pin [dict get $io_pin_sites $site] + + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" $port + + puts $fp "$port,$site,$tile,$pin" + } + close $fp +} + +proc run {} { + create_project -force -part $::env(XRAY_PART) design design + read_verilog top.v + synth_design -top top + + # Mostly doesn't matter since IOB are special, but add anyway + create_pblock roi + add_cells_to_pblock [get_pblocks roi] [get_cells roi] + resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" + + loc_pins + + 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 +} + +run diff --git a/fuzzers/034-iob-stag/top.py b/fuzzers/034-iob-stag/top.py new file mode 100644 index 00000000..8c2001f7 --- /dev/null +++ b/fuzzers/034-iob-stag/top.py @@ -0,0 +1,152 @@ +''' +Generate a primitive to place at every I/O +Unlike CLB tests, the LFSR for this is inside the ROI, not driving it +''' + +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray import verilog + + +def gen_iobs(): + ''' + IOB33S: main IOB of a diff pair + IOB33M: secondary IOB of a diff pair + IOB33: not a diff pair. Relatively rare (at least in ROI...2 of them?) + Focus on IOB33S to start + ''' + for _tile_name, site_name, site_type in util.get_roi().gen_sites( + #['IOB33', 'IOB33S', 'IOB33M']): + ['IOB33S']): + yield site_name, site_type + + +def write_pins(ports): + pinstr = 'site,name,dir,cell\n' + for site, (name, dir_, cell) in sorted(ports.items(), key=lambda x: x[1]): + # pinstr += 'set_property -dict "PACKAGE_PIN %s IOSTANDARD LVCMOS33" [get_ports %s]' % (packpin, port) + pinstr += '%s,%s,%s,%s\n' % (site, name, dir_, cell) + open('params.csv', 'w').write(pinstr) + + +def run(): + # All possible values + iosites = {} + for site_name, site_type in gen_iobs(): + iosites[site_name] = site_type + + # Assigned in this design + ports = {} + DIN_N = 0 + DOUT_N = 0 + + def remain_sites(): + return set(iosites.keys()) - set(ports.keys()) + + def rand_site(): + '''Get a random, unused site''' + return random.choice(list(remain_sites())) + + def assign_i(site, name): + nonlocal DIN_N + + assert site not in ports + cell = "di_bufs[%u].ibuf" % DIN_N + DIN_N += 1 + ports[site] = (name, 'input', cell) + + def assign_o(site, name): + nonlocal DOUT_N + + assert site not in ports + cell = "do_bufs[%u].obuf" % DOUT_N + DOUT_N += 1 + ports[site] = (name, 'output', cell) + + # Assign at least one di and one do + assign_i(rand_site(), 'di[0]') + assign_o(rand_site(), 'do[0]') + # Now assign the rest randomly + while len(remain_sites()): + site = rand_site() + choice = random.randint(0, 2) + if choice == 0: + assign_i(site, 'di[%u]' % DIN_N) + elif choice == 1: + assign_o(site, 'do[%u]' % DOUT_N) + # Empty to provide a reference for no instance + else: + ports[site] = ("", "", "") + + write_pins(ports) + + print( + ''' +`define N_DI %u +`define N_DO %u + +module top(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); + genvar i; + + //Instantiate BUFs so we can LOC them + + wire [`N_DI-1:0] di_buf; + generate + for (i = 0; i < `N_DI; i = i+1) begin:di_bufs + IBUF ibuf(.I(di[i]), .O(di_buf[i])); + end + endgenerate + + wire [`N_DO-1:0] do_unbuf; + generate + for (i = 0; i < `N_DO; i = i+1) begin:do_bufs + OBUF obuf(.I(do_unbuf[i]), .O(do[i])); + end + endgenerate + + roi roi(.di(di_buf), .do(do_unbuf)); +endmodule + +//Arbitrary terminate into LUTs +module roi(input wire [`N_DI-1:0] di, output wire [`N_DO-1:0] do); + genvar i; + + generate + for (i = 0; i < `N_DI; i = i+1) begin:dis + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'h8000_0000_0000_0001) + ) lut ( + .I0(di[i]), + .I1(di[i]), + .I2(di[i]), + .I3(di[i]), + .I4(di[i]), + .I5(di[i]), + .O()); + end + endgenerate + + generate + for (i = 0; i < `N_DO; i = i+1) begin:dos + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'h8000_0000_0000_0001) + ) lut ( + .I0(), + .I1(), + .I2(), + .I3(), + .I4(), + .I5(), + .O(do[i])); + end + endgenerate +endmodule + ''' % (DIN_N, DOUT_N)) + + +if __name__ == '__main__': + run() From 1f431903e25231433f6fc31eee09f0692f64a618 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 14:21:04 +0100 Subject: [PATCH 08/16] groupmask utility Signed-off-by: John McMaster --- prjxray/util.py | 31 +++++++++++++----- utils/groupmask.py | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 utils/groupmask.py diff --git a/prjxray/util.py b/prjxray/util.py index 16f28455..7baa127c 100644 --- a/prjxray/util.py +++ b/prjxray/util.py @@ -103,6 +103,23 @@ def parse_db_line(line): return tag, bits, None +def parse_db_lines(fn): + with open(fn, "r") as f: + for line in f: + yield line, parse_db_line(line) + + +def write_db_lines(fn, entries): + new_lines = [] + for tag, bits in entries.items(): + new_line = " ".join([tag] + sorted(bits)) + new_lines.append(new_line) + + with open(fn, "w") as f: + for line in sorted(new_lines): + print(line, file=f) + + def parse_tagbit(x): # !30_07 if x[0] == '!': @@ -186,14 +203,12 @@ def gen_tile_bits(db_root, tilej, strict=False, verbose=False): elif not os.path.exists(fn): continue - with open(fn, "r") as f: - for line in f: - tag, bits, mode = parse_db_line(line) - assert mode is None - for bitstr in bits: - # 31_06 - _bit_inv, (bit_addroff, bit_bitoff) = parse_tagbit(bitstr) - yield (baseaddr + bit_addroff, bitbase + bit_bitoff, tag) + for line, (tag, bits, mode) in parse_db_lines(fn): + assert mode is None + for bitstr in bits: + # 31_06 + _bit_inv, (bit_addroff, bit_bitoff) = parse_tagbit(bitstr) + yield (baseaddr + bit_addroff, bitbase + bit_bitoff, tag) def specn(): diff --git a/utils/groupmask.py b/utils/groupmask.py new file mode 100644 index 00000000..db658ff1 --- /dev/null +++ b/utils/groupmask.py @@ -0,0 +1,81 @@ +#/usr/bin/env python3 + +import sys, os, re +from prjxray import util + + +def index_masks(fn_in, groups_in): + """Return a dictionary with the bits active in each group for the specified list of groups""" + # Only analyze the given groups + groups = {} + for group in groups_in: + groups[group] = set() + + # Index bits + for line, (tag, bits, mode) in util.parse_db_lines(fn_in): + assert not mode, "Unresolved tag: %s" % (line, ) + prefix = tag[0:tag.rfind(".")] + group = groups.get(prefix, None) + # Drop groups we aren't interested in + if group is None: + continue + for bit in bits: + bit = bit.replace("!", "") + group.add(bit) + + # Verify we were able to find all groups + for groupk, groupv in groups.items(): + assert len(groupv), "Bad group %s" % groupk + + return groups + + +def apply_masks(fn_in, groups): + """Add 0 entries ("!") to .db entries based on groups definition""" + new_db = {} + for line, (tag, bits, mode) in util.parse_db_lines(fn_in): + assert not mode, "Unresolved tag: %s" % (line, ) + prefix = tag[0:tag.rfind(".")] + group = groups.get(prefix, None) + if group: + bits = set(bits) + for bit in group: + if bit not in bits: + bits.add("!" + bit) + bits = frozenset(bits) + new_db[tag] = bits + return new_db + + +def load_groups(fn): + ret = [] + for l in open(fn, "r"): + ret.append(l.strip()) + return ret + + +def run(fn_in, fn_out, groups_fn, verbose=False): + groups_in = load_groups(groups_fn) + groups = index_masks(fn_in, groups_in) + new_db = apply_masks(fn_in, groups) + util.write_db_lines(fn_out, new_db) + + +def main(): + import argparse + + parser = argparse.ArgumentParser(description='Create multi-bit entries') + parser.add_argument('--verbose', action='store_true', help='') + parser.add_argument( + '--groups-fn', + default="groups.grp", + help='File containing one group per line to parse') + parser.add_argument('fn_in', help='') + parser.add_argument('fn_out', help='') + args = parser.parse_args() + + run(args.fn_in, args.fn_out, args.groups_fn, verbose=args.verbose) + + +if __name__ == '__main__': + main() From 6d9d1687a3a3e40b699c7c793b5a46a62568ab7a Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 14:19:52 +0100 Subject: [PATCH 09/16] iob-stag: groups.grp file Signed-off-by: John McMaster --- fuzzers/034-iob-stag/Makefile | 2 +- fuzzers/034-iob-stag/bits.dbf | 0 fuzzers/034-iob-stag/groups.grp | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 fuzzers/034-iob-stag/bits.dbf create mode 100644 fuzzers/034-iob-stag/groups.grp diff --git a/fuzzers/034-iob-stag/Makefile b/fuzzers/034-iob-stag/Makefile index 1c2bc8da..4e3685f8 100644 --- a/fuzzers/034-iob-stag/Makefile +++ b/fuzzers/034-iob-stag/Makefile @@ -9,7 +9,7 @@ build/segbits_liob33.rdb: $(SPECIMENS_OK) ${XRAY_SEGMATCH} -c -1 -o build/segbits_liob33.rdb $(SEGDATAS) build/segbits_liob33.db: build/segbits_liob33.rdb - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in $^ --seg-fn-out $@ + python3 ${XRAY_DIR}/utils/groupmask.py $^ $@ ${XRAY_MASKMERGE} build/mask_liob33.db $(SEGDATAS) pushdb: diff --git a/fuzzers/034-iob-stag/bits.dbf b/fuzzers/034-iob-stag/bits.dbf deleted file mode 100644 index e69de29b..00000000 diff --git a/fuzzers/034-iob-stag/groups.grp b/fuzzers/034-iob-stag/groups.grp new file mode 100644 index 00000000..f9cca48f --- /dev/null +++ b/fuzzers/034-iob-stag/groups.grp @@ -0,0 +1 @@ +LIOB33.IOB_Y1.MACRO From d0d67788267f8407e77b653cccf6a7bc6eb0e74c Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 15:08:30 +0100 Subject: [PATCH 10/16] mergedb: proper merge script Signed-off-by: John McMaster --- utils/mergedb.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ utils/mergedb.sh | 9 ++++++- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100755 utils/mergedb.py diff --git a/utils/mergedb.py b/utils/mergedb.py new file mode 100755 index 00000000..ae38255b --- /dev/null +++ b/utils/mergedb.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import sys, re +import os +from prjxray import util + + +def run(fn_ins, fn_out, strict=False, verbose=False): + # tag to bits + entries = {} + # tag to (bits, line) + tags = dict() + # bits to (tag, line) + bitss = dict() + + for fn_in in fn_ins: + for line, (tag, bits, mode) in util.parse_db_lines(fn_in): + line = line.strip() + assert mode is not None or mode != "always", "strict: got ill defined line: %s" % ( + line, ) + + if tag in tags: + orig_bits, orig_line = tags[tag] + if orig_bits != bits: + print("WARNING: got duplicate tag %s" % (tag, )) + print(" Orig line: %s" % orig_line) + print(" New line : %s" % line) + assert not strict, "strict: got duplicate tag" + if bits in bitss: + orig_tag, orig_line = bitss[bits] + if orig_tag != tag: + print("WARNING: got duplicate bits %s" % (bits, )) + print(" Orig line: %s" % orig_line) + print(" New line : %s" % line) + assert not strict, "strict: got duplicate bits" + + entries[tag] = bits + tags[tag] = (bits, line) + if bits != None: + bitss[bits] = (tag, line) + + util.write_db_lines(fn_out, entries) + + +def main(): + import argparse + + parser = argparse.ArgumentParser(description="Combine multiple .db files") + + util.db_root_arg(parser) + parser.add_argument('--verbose', action='store_true', help='') + parser.add_argument('--out', help='') + parser.add_argument('ins', nargs='+', help='Last takes precedence') + args = parser.parse_args() + + run( + args.ins, + args.out, + strict=int(os.getenv("MERGEDB_STRICT", "1")), + verbose=args.verbose) + + +if __name__ == '__main__': + main() diff --git a/utils/mergedb.sh b/utils/mergedb.sh index 7be4a9a4..93011e51 100755 --- a/utils/mergedb.sh +++ b/utils/mergedb.sh @@ -29,6 +29,7 @@ ${XRAY_PARSEDB} --strict "$2" # However, expand back to L/R to make downstream tools not depend on this # in case we later find exceptions +ismask=false case "$1" in clbll_l) sed < "$2" > "$tmp1" \ @@ -77,6 +78,7 @@ case "$1" in mask_*) db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db + ismask=true cp "$2" "$tmp1" ;; *) @@ -86,7 +88,12 @@ case "$1" in esac touch "$db" -sort -u "$tmp1" "$db" | grep -v '<.*>' > "$tmp2" || true +if $ismask ; then + sort -u "$tmp1" "$db" | grep -v '<.*>' > "$tmp2" || true +else + # tmp1 must be placed second to take precedence over old bad entries + python3 ${XRAY_DIR}/utils/mergedb.py --out "$tmp2" "$db" "$tmp1" +fi # Check aggregate db for consistency and make canonical ${XRAY_PARSEDB} --strict "$tmp2" "$db" From 3b142499ea0e50f8d384697ce9540e1be7653121 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Tue, 8 Jan 2019 09:00:22 -0800 Subject: [PATCH 11/16] docker: Don't use -j on fuzzers. Signed-off-by: Tim 'mithro' Ansell --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 499c4a63..8228417a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ARG NUM_PARALLEL_JOBS=1 COPY . /source RUN cd /source && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables build -RUN bash -c ". /source/database/artix7/settings.sh; cd /source/fuzzers && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables" +RUN bash -c ". /source/database/artix7/settings.sh; cd /source/fuzzers && make --output-sync=target --warn-undefined-variables" #RUN find /source/database -mindepth 1 -maxdepth 1 -type d -exec /source/htmlgen/htmlgen.py --settings={}/settings.sh --output=/output/html \; RUN mkdir -p /output/raw && find /source/database -mindepth 1 -maxdepth 1 -type d -exec cp -R {} /output/raw \; From 4cbf7fa75203429c8f18d465dddbc458d4b668f9 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Tue, 8 Jan 2019 10:05:34 -0800 Subject: [PATCH 12/16] docker: Run `make env` Signed-off-by: Tim 'mithro' Ansell --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8228417a..d90cf860 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM ${DEV_ENV_IMAGE} AS db_builder ARG NUM_PARALLEL_JOBS=1 COPY . /source -RUN cd /source && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables build +RUN cd /source && make -j${NUM_PARALLEL_JOBS} --output-sync=target --warn-undefined-variables build && make env RUN bash -c ". /source/database/artix7/settings.sh; cd /source/fuzzers && make --output-sync=target --warn-undefined-variables" #RUN find /source/database -mindepth 1 -maxdepth 1 -type d -exec /source/htmlgen/htmlgen.py --settings={}/settings.sh --output=/output/html \; RUN mkdir -p /output/raw && find /source/database -mindepth 1 -maxdepth 1 -type d -exec cp -R {} /output/raw \; From 955759020d2fc8b598094429e3119a229021aa97 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Tue, 8 Jan 2019 19:05:39 +0100 Subject: [PATCH 13/16] segprint: fix -b flag, working on tilegrid directly Signed-off-by: John McMaster --- utils/segprint.py | 53 +++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/utils/segprint.py b/utils/segprint.py index fc5fe9f6..7075ca77 100755 --- a/utils/segprint.py +++ b/utils/segprint.py @@ -7,6 +7,7 @@ Ex: BRAM_L_X6Y100:CLB_IO_CLK ''' import sys, os, json, re +import copy from prjxray import bitstream from prjxray import db as prjxraydb from prjxray import util @@ -93,31 +94,42 @@ def mk_segbits(seginfo, bitdata): return segbits -def print_unknown_bits(segments, bitdata): +def gen_tilegrid_masks(tiles): + """yield (addr_min, addr_max + 1, word_min, word_max + 1)""" + for tilek, tilev in tiles.items(): + for block_type, blockj in tilev["bits"].items(): + baseaddr = int(blockj["baseaddr"], 0) + frames = blockj["frames"] + offset = blockj["offset"] + words = blockj["words"] + yield (baseaddr, baseaddr + frames, offset, offset + words) + + +def print_unknown_bits(tiles, bitdata): ''' Print bits not covered by known tiles - ''' - # Index all known locations - # seggrames[address] = set() - # where set contains word numbers - segframes = dict() - for segname, segment in segments.items(): - block = segment["block"] - framebase = int(block["baseaddr"][0], 16) - for i in range(block["frames"]): - words = segframes.setdefault(framebase + i, set()) - for j in range(int(block["baseaddr"], 16), - int(block["baseaddr"], 16) + block["words"]): - words.add(j) + tiles: tilegrid json + bitdata[addr][word] = set of bit indices (0 to 31) + ''' + # Start with an open set and remove elements as we find them + tocheck = copy.deepcopy(bitdata) + + for addr_min, addr_max_p1, word_min, word_max_p1 in gen_tilegrid_masks( + tiles): + for addr in range(addr_min, addr_max_p1): + if addr not in tocheck: + continue + for word in range(word_min, word_max_p1): + if word not in tocheck[addr]: + continue + del tocheck[addr][word] # 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]): + for frame in sorted(tocheck.keys()): + for wordidx in sorted(tocheck[frame].keys()): + for bitidx in sorted(tocheck[frame][wordidx]): print("bit_%08x_%03d_%02d" % (frame, wordidx, bitidx)) @@ -409,7 +421,8 @@ def run( bitdata = bitstream.load_bitdata2(open(bits_file, "r")) if flag_unknown_bits: - print_unknown_bits(segments, bitdata) + print_unknown_bits(tiles, bitdata) + print("") # Default: print all if segnames: From a4dd142bb9cad9a0db516109b07a9b4c6056344d Mon Sep 17 00:00:00 2001 From: Mehdi Khairy Date: Tue, 8 Jan 2019 20:01:38 +0100 Subject: [PATCH 14/16] Bug #171: Fixing build directory for Fuzzers 071 Signed-off-by: Mehdi Khairy --- fuzzers/071-ppips/Makefile | 28 ++++++++++++++-------------- fuzzers/071-ppips/generate.sh | 2 +- fuzzers/071-ppips/generate.tcl | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/fuzzers/071-ppips/Makefile b/fuzzers/071-ppips/Makefile index d6583293..29ae84b2 100644 --- a/fuzzers/071-ppips/Makefile +++ b/fuzzers/071-ppips/Makefile @@ -1,23 +1,23 @@ N := 1 -SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS := $(addprefix build/specimen_,$(shell seq -f '%03.0f' $(N))) SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) database: $(SPECIMENS_OK) - cp specimen_001/ppips_clblm_l.txt . - cp specimen_001/ppips_clblm_r.txt . - cp specimen_001/ppips_clbll_l.txt . - cp specimen_001/ppips_clbll_r.txt . - cp specimen_001/ppips_int_l.txt . - cp specimen_001/ppips_int_r.txt . + cp build/specimen_001/ppips_clblm_l.txt build/ + cp build/specimen_001/ppips_clblm_r.txt build/ + cp build/specimen_001/ppips_clbll_l.txt build/ + cp build/specimen_001/ppips_clbll_r.txt build/ + cp build/specimen_001/ppips_int_l.txt build/ + cp build/specimen_001/ppips_int_r.txt build/ pushdb: - cp ppips_clblm_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_l.db - cp ppips_clblm_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_r.db - cp ppips_clbll_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_l.db - cp ppips_clbll_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_r.db - cp ppips_int_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_l.db - cp ppips_int_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_r.db + cp build/ppips_clblm_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_l.db + cp build/ppips_clblm_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clblm_r.db + cp build/ppips_clbll_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_l.db + cp build/ppips_clbll_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_clbll_r.db + cp build/ppips_int_l.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_l.db + cp build/ppips_int_r.txt ${XRAY_DATABASE_DIR}/$(XRAY_DATABASE)/ppips_int_r.db $(SPECIMENS_OK): bash generate.sh $(subst /OK,,$@) @@ -30,7 +30,7 @@ run: touch run.ok clean: - rm -rf specimen_[0-9][0-9][0-9]/ ppips_clbl[ml]_[lr].txt ppips_int_[lr].txt run.ok + rm -rf build run.ok .PHONY: database pushdb run clean diff --git a/fuzzers/071-ppips/generate.sh b/fuzzers/071-ppips/generate.sh index ccc5a065..e6b0e2c6 100644 --- a/fuzzers/071-ppips/generate.sh +++ b/fuzzers/071-ppips/generate.sh @@ -2,5 +2,5 @@ source ${XRAY_GENHEADER} -${XRAY_VIVADO} -mode batch -source ../generate.tcl +${XRAY_VIVADO} -mode batch -source $FUZDIR/generate.tcl diff --git a/fuzzers/071-ppips/generate.tcl b/fuzzers/071-ppips/generate.tcl index 9692b4fc..354a7e4e 100644 --- a/fuzzers/071-ppips/generate.tcl +++ b/fuzzers/071-ppips/generate.tcl @@ -1,6 +1,6 @@ create_project -force -part $::env(XRAY_PART) design design -read_verilog ../top.v +read_verilog $::env(FUZDIR)/top.v synth_design -top top set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports a] From 3b13f8734fb51d876494d44377986da9e81fcfcd Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Tue, 8 Jan 2019 18:23:25 -0800 Subject: [PATCH 15/16] Fix indenting in mergedb.py Fixes #467. Signed-off-by: Tim 'mithro' Ansell --- utils/mergedb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/mergedb.py b/utils/mergedb.py index ae38255b..70088dda 100755 --- a/utils/mergedb.py +++ b/utils/mergedb.py @@ -34,10 +34,10 @@ def run(fn_ins, fn_out, strict=False, verbose=False): print(" New line : %s" % line) assert not strict, "strict: got duplicate bits" - entries[tag] = bits - tags[tag] = (bits, line) - if bits != None: - bitss[bits] = (tag, line) + entries[tag] = bits + tags[tag] = (bits, line) + if bits != None: + bitss[bits] = (tag, line) util.write_db_lines(fn_out, entries) From 010a2eb5dabb90826e6ca519cab33bcbedd34d7c Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 9 Jan 2019 18:35:34 +0100 Subject: [PATCH 16/16] segprint: --bit-only Signed-off-by: John McMaster --- utils/segprint.py | 59 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/utils/segprint.py b/utils/segprint.py index 7075ca77..47d32fe9 100755 --- a/utils/segprint.py +++ b/utils/segprint.py @@ -35,7 +35,7 @@ def process_db(db, tile_type, process, verbose): process(line) -def get_database(db, tile_type, verbose=False): +def get_database(db, tile_type, bit_only=False, verbose=False): tags = list() if tile_type in segbitsdb: @@ -48,6 +48,8 @@ def get_database(db, tile_type, verbose=False): name = parts[0] if parts[1] == 'always' or parts[1] == 'hint': + if bit_only: + return tagbits = [] else: tagbits = [util.parse_tagbit(x) for x in parts[1:]] @@ -157,7 +159,7 @@ def tag_matched(entry, segbits): decode_warnings = set() -def seg_decode(db, seginfo, segbits, segments, verbose=False): +def seg_decode(db, seginfo, segbits, segments, bit_only=False, verbose=False): ''' Remove matched tags from segbits Returns a list of all matched tags @@ -181,7 +183,8 @@ def seg_decode(db, seginfo, segbits, segments, verbose=False): return try: - entries = get_database(db, tile_type, verbose=verbose) + entries = get_database( + db, tile_type, bit_only=bit_only, verbose=verbose) except NoDB: verbose and print("WARNING: failed to load DB for %s" % tile_type) assert tile_type != 'BRAM_L' @@ -259,10 +262,19 @@ def seg_decode(db, seginfo, segbits, segments, verbose=False): return segtags -def print_seg(segname, segbits, segtags, decode_emit): +def print_seg( + segname, seginfo, nbits, segbits, segtags, decode_emit, verbose=False): '''Print segment like used by segmaker/segmatch''' print("seg %s" % (segname, )) + if verbose: + print("Bits: %s" % nbits) + print( + "Address: %s, +%s" % + (seginfo["block"]["baseaddr"], seginfo["block"]["frames"])) + print( + "Words: %s, +%s" % + (seginfo["block"]["offset"], seginfo["block"]["words"])) # Bits that weren't decoded for bit in sorted(segbits): @@ -281,27 +293,34 @@ def handle_segment( decode_omit, omit_empty_segs, segments, + bit_only=False, verbose=False): seginfo = segments[segname] - # only print bitstream tiles - #if segname not in segments: - # return - segbits = mk_segbits(seginfo, bitdata) + nbits = len(segbits) if decode_emit or decode_omit: - segtags = seg_decode(db, seginfo, segbits, segments, verbose=verbose) + segtags = seg_decode( + db, seginfo, segbits, segments, bit_only=bit_only, verbose=verbose) else: segtags = set() # Found something to print? - if not (not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0): + keep = not omit_empty_segs or len(segbits) > 0 or len(segtags) > 0 + if not keep: return print() - print_seg(segname, segbits, segtags, decode_emit) + print_seg( + segname, + seginfo, + nbits, + segbits, + segtags, + decode_emit, + verbose=verbose) def overlap(a, b): @@ -414,6 +433,7 @@ def run( flag_unknown_bits=False, flag_decode_emit=False, flag_decode_omit=False, + bit_only=False, verbose=False): db = prjxraydb.Database(db_root) tiles = load_tiles(db_root) @@ -445,6 +465,7 @@ def run( flag_decode_omit, omit_empty_segs, segments, + bit_only=bit_only, verbose=verbose) @@ -466,19 +487,29 @@ def main(): '-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( + '--bit-only', + action='store_true', + help='only decode real bitstream directives') 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.db_root, args.bits_file, args.segnames, args.z, args.b, args.d, - args.D, args.verbose) + args.db_root, + args.bits_file, + args.segnames, + args.z, + args.b, + args.d, + args.D, + bit_only=args.bit_only, + verbose=args.verbose) if __name__ == '__main__':