From 065bd6588b472f742e24f979f7bc859decac6061 Mon Sep 17 00:00:00 2001 From: Tomasz Michalak Date: Tue, 8 Jan 2019 13:14:02 +0100 Subject: [PATCH 1/6] 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 26bbede67..0d83b036a 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 2/6] 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 24fdc074b..751997565 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 3/6] 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 000000000..1c2bc8da0 --- /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 000000000..e69de29bb diff --git a/fuzzers/034-iob-stag/generate.py b/fuzzers/034-iob-stag/generate.py new file mode 100644 index 000000000..3667d5a76 --- /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 000000000..f42f840c1 --- /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 000000000..556d58143 --- /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 000000000..8c2001f7c --- /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 4/6] 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 16f284557..7baa127ca 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 000000000..db658ff1a --- /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 5/6] 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 1c2bc8da0..4e3685f8a 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 e69de29bb..000000000 diff --git a/fuzzers/034-iob-stag/groups.grp b/fuzzers/034-iob-stag/groups.grp new file mode 100644 index 000000000..f9cca48f6 --- /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 6/6] 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 000000000..ae38255b4 --- /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 7be4a9a43..93011e513 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"