diff --git a/fuzzers/000-init-db/Makefile b/fuzzers/000-init-db/Makefile index 54be7358..e9294083 100644 --- a/fuzzers/000-init-db/Makefile +++ b/fuzzers/000-init-db/Makefile @@ -23,14 +23,29 @@ SEGBITS=\ hclk \ int \ -DB_SIMPLE=$(addprefix mask_,$(MASKS)) $(addprefix ppips_,$(PPIPS)) $(addprefix segbits_,$(SEGBITS)) +SEGBITS_R=\ + clk_bufg_top \ + clk_bufg_bot \ + $(SEGBITS) -# Extra (segbits|mask)_bram_(l|r).block_ram.db files -# FIXME: Are these things also needed for the DSP blocks? -BLOCK_RAM_EXTRA_FOR=mask_bram segbits_bram -BLOCK_RAM_EXTRA_DB_FILES=$(addsuffix .block_ram.db,$(addsuffix _l,$(BLOCK_RAM_EXTRA_FOR)) $(addsuffix _r,$(BLOCK_RAM_EXTRA_FOR))) +SEGBITS_L=\ + $(SEGBITS) -DB_FILES=$(sort $(addsuffix _l.db,$(DB_SIMPLE)) $(addsuffix _r.db,$(DB_SIMPLE)) $(BLOCK_RAM_EXTRA_DB_FILES)) +DB_SIMPLE_LR=$(addprefix mask_,$(MASKS)) $(addprefix ppips_,$(PPIPS)) +DB_SIMPLE_L=$(addprefix segbits_,$(SEGBITS_L)) +DB_SIMPLE_R=$(addprefix segbits_,$(SEGBITS_R)) +DB_SIMPLE=\ + $(addsuffix _l, $(DB_SIMPLE_LR) $(DB_SIMPLE_L)) \ + $(addsuffix _r, $(DB_SIMPLE_LR) $(DB_SIMPLE_R)) + +BLOCK_RAM_EXTRA_FOR=\ + mask_bram \ + segbits_bram +BLOCK_RAM_EXTRA_DB_FILES=\ + $(addsuffix .block_ram.db,$(addsuffix _l,$(BLOCK_RAM_EXTRA_FOR)) $(addsuffix _r,$(BLOCK_RAM_EXTRA_FOR))) + + +DB_FILES=$(sort $(addsuffix .origin_info.db,$(DB_SIMPLE)) $(addsuffix .db,$(DB_SIMPLE)) $(BLOCK_RAM_EXTRA_DB_FILES)) DB_FILES_PATH=$(addprefix $(XRAY_DATABASE_DIR)/$(XRAY_DATABASE)/,$(DB_FILES)) check: diff --git a/fuzzers/011-clb-ffconfig/Makefile b/fuzzers/011-clb-ffconfig/Makefile index f5f5a631..273ae54d 100644 --- a/fuzzers/011-clb-ffconfig/Makefile +++ b/fuzzers/011-clb-ffconfig/Makefile @@ -1,3 +1,4 @@ N := 1 +CLB_DBFIXUP=Y include ../clb.mk diff --git a/fuzzers/011-clb-ffconfig/bits.dbf b/fuzzers/011-clb-ffconfig/bits.dbf new file mode 100644 index 00000000..47b4084a --- /dev/null +++ b/fuzzers/011-clb-ffconfig/bits.dbf @@ -0,0 +1,3 @@ +# NOCLKINV is inverse of CLKINV +CLB.SLICE_X0.CLKINV ^ CLB.SLICE_X0.NOCLKINV +CLB.SLICE_X1.CLKINV ^ CLB.SLICE_X1.NOCLKINV diff --git a/fuzzers/011-clb-ffconfig/generate.py b/fuzzers/011-clb-ffconfig/generate.py index d27a3497..9f740481 100644 --- a/fuzzers/011-clb-ffconfig/generate.py +++ b/fuzzers/011-clb-ffconfig/generate.py @@ -94,8 +94,10 @@ with open("design.txt", "r") as f: # CLKINV turns out to be more complicated than origianlly thought if isff(cel_prim): segmk.add_site_tag(site, "CLKINV", cinv) + segmk.add_site_tag(site, "NOCLKINV", 1 ^ cinv) else: segmk.add_site_tag(site, "CLKINV", 1 ^ cinv) + segmk.add_site_tag(site, "NOCLKINV", cinv) # Synchronous vs asynchronous FF # Unlike most bits, shared between all CLB FFs diff --git a/fuzzers/019-clb-ndi1mux/Makefile b/fuzzers/019-clb-ndi1mux/Makefile index ba58ecde..79723295 100644 --- a/fuzzers/019-clb-ndi1mux/Makefile +++ b/fuzzers/019-clb-ndi1mux/Makefile @@ -1,4 +1,5 @@ N := 3 SLICEL ?= N +CLB_DBFIXUP=Y include ../clb.mk diff --git a/fuzzers/019-clb-ndi1mux/bits.dbf b/fuzzers/019-clb-ndi1mux/bits.dbf new file mode 100644 index 00000000..8c8d18ec --- /dev/null +++ b/fuzzers/019-clb-ndi1mux/bits.dbf @@ -0,0 +1,3 @@ +CLB.SLICE_X0.ALUT.DI1MUX.AI ^ CLB.SLICE_X0.ALUT.DI1MUX.BDI1_BMC31 +CLB.SLICE_X0.BLUT.DI1MUX.BI ^ CLB.SLICE_X0.BLUT.DI1MUX.DI_CMC31 +CLB.SLICE_X0.CLUT.DI1MUX.CI ^ CLB.SLICE_X0.CLUT.DI1MUX.DI_DMC31 diff --git a/fuzzers/019-clb-ndi1mux/generate.py b/fuzzers/019-clb-ndi1mux/generate.py index 0471484c..e0ae1d2e 100644 --- a/fuzzers/019-clb-ndi1mux/generate.py +++ b/fuzzers/019-clb-ndi1mux/generate.py @@ -25,8 +25,11 @@ for l in f: b31 = int(b31) a31 = int(a31) segmk.add_site_tag(loc, "ALUT.DI1MUX.AI", 1 ^ a31) + segmk.add_site_tag(loc, "ALUT.DI1MUX.BDI1_BMC31", a31) segmk.add_site_tag(loc, "BLUT.DI1MUX.BI", 1 ^ b31) + segmk.add_site_tag(loc, "BLUT.DI1MUX.DI_CMC31", b31) segmk.add_site_tag(loc, "CLUT.DI1MUX.CI", 1 ^ c31) + segmk.add_site_tag(loc, "CLUT.DI1MUX.DI_DMC31", c31) segmk.compile() segmk.write() diff --git a/utils/dbfixup.py b/utils/dbfixup.py index 3c949cd7..4e74a2e7 100755 --- a/utils/dbfixup.py +++ b/utils/dbfixup.py @@ -51,57 +51,152 @@ def bits_str(bits): return ' '.join(sorted(list(bits))) -def zero_groups(tag, bits, zero_db, strict=True, verbose=False): - """ - See if a line occurs within a bit group - If it does, add 0 bits +class ZeroGroups(object): + def __init__(self, zero_db): + self.groups = [] + self.bit_to_group = {} + self.tag_to_groups = {} + self.zero_tag_to_group = {} + self.parse_zero_db(zero_db) - Ex: 01_02 04_05 - Means find a line that has either of these bits - If either of them occurs, default bits in that set to zero + def print_groups(self): + print('Zero groups:') + for bits in self.groups: + print(bits_str(bits)) - Ex: 01_02 04_05|07_08 10_11 - If any bits from the first group occur, - default bits in the second group to zero + print('Zero tags:') + for tag in self.zero_tag_to_group: + print(tag, bits_str(self.zero_tag_to_group[tag])) - Ex: 01_02 04_05,ALL_ZERO - ALL_ZERO is an enum that is part of the group but is all 0 - It must have 0 candidates + def parse_zero_db(self, zero_db): + """ Convert zero db format into data structure - strict: assert that the size of the given group is the size of the given mask - """ - for zdb in zero_db: - allzero_tag = None - if "," in zdb: - zdb, allzero_tag = zdb.split(",") + Zero db format examples: - if "|" in zdb: - a, b = zdb.split("|") - a = a.split() - b = b.split() - else: - a = zdb.split() - b = a + Ex: 01_02 04_05 + Means find a line that has either of these bits + If either of them occurs, default bits in that set to zero - bitmatch = False - for bit in a: - if bit in bits: - bitmatch = True + Ex: 01_02 04_05|07_08 10_11 + If any bits from the first group occur, + default bits in the second group to zero - if not (bitmatch or allzero_tag == tag): - continue + Ex: 01_02 04_05,ALL_ZERO + ALL_ZERO is an enum that is part of the group but is all 0 + It must have 0 candidates - bits_orig = set(bits) - for bit in b: - if bit not in bits: + Ex: CLB.SLICE_X0.CLKINV ^ CLB.SLICE_X0.NOCLKINV + CLB.SLICE_X0.NOCLKINV is all bits in CLB.SLICE_X0.CLKINV unset + + Ex: A | B ^ C + C is all bits in (A)|(B) unset + + + """ + for zdb in zero_db: + + if "^" in zdb: + self.groups.append(set()) + zero_group = self.groups[-1] + + other_tags, allzero_tag = zdb.split('^') + allzero_tag = allzero_tag.strip() + + for tag in other_tags.split(): + self.tag_to_groups[tag.strip()] = [zero_group] + + self.zero_tag_to_group[allzero_tag] = zero_group + continue + + allzero_tag = None + if "," in zdb: + zdb, allzero_tag = zdb.split(",") + + if "|" in zdb: + a, b = zdb.split("|") + a = a.split() + b = b.split() + + self.groups.append(set(b)) + zero_group = self.groups[-1] + else: + a = zdb.split() + self.groups.append(set(a)) + zero_group = self.groups[-1] + + if allzero_tag is not None: + self.zero_tag_to_group[allzero_tag] = zero_group + + for bit in a: + self.bit_to_group[bit] = zero_group + + def add_tag_bits(self, tag, bits): + if tag in self.zero_tag_to_group: + return + + group_ids = set() + groups = [] + + if tag in self.tag_to_groups: + assert len(self.tag_to_groups[tag]) == 1 + + self.tag_to_groups[tag][0] |= bits + + for bit in bits: + if bit in self.bit_to_group: + # Make sure each bit only belongs to one group + assert id(self.bit_to_group[bit]) == id( + self.tag_to_groups[tag]) + else: + self.bit_to_group[bit] = self.tag_to_groups[tag] + + group_ids.add(id(self.tag_to_groups[tag])) + groups = self.tag_to_groups[tag] + + for bit in bits: + if bit in self.bit_to_group: + if id(self.bit_to_group[bit]) not in group_ids: + group_ids.add(id(self.bit_to_group[bit])) + groups.append(self.bit_to_group[bit]) + + self.tag_to_groups[tag] = groups + + def add_bits_from_zero_groups(self, tag, bits, strict=True, verbose=False): + """ Add bits from a zero group, if needed + + Arguments + --------- + tag : str + Tag being to examine for zero group + bits : set of str + Set of bits set on this tag + strict : bool + Assert that the size of the given group is the size of the given + mask. + verbose : bool + Print to stdout grouping being made + """ + + tag_is_masked = tag in self.tag_to_groups + tag_is_zero = tag in self.zero_tag_to_group + + # Should not have a tag that is both masked and a zero tag. + assert not (tag_is_masked and tag_is_zero) + + if tag_is_masked: + for b in self.tag_to_groups[tag]: + bits_orig = set(bits) + for bit in b: + if bit not in bits: + bits.add("!" + bit) + + verbose and print( + "Grouped %s: %s => %s" % + (tag, bits_str(bits_orig), bits_str(bits))) + + if tag_is_zero: + for bit in self.zero_tag_to_group[tag]: bits.add("!" + bit) - verbose and print( - "Grouped %s: %s => %s" % - (tag, bits_str(bits_orig), bits_str(bits))) - if a == b and strict: - assert len(bits) == len( - a), "Mask size %u != DB entry size %u: %s" % ( - len(a), len(bits), bits_str(bits)) def add_zero_bits(fn_in, zero_db, clb_int=False, strict=True, verbose=False): @@ -111,11 +206,15 @@ def add_zero_bits(fn_in, zero_db, clb_int=False, strict=True, verbose=False): If an entry has any of the ''' + zero_groups = ZeroGroups(zero_db) + + lines = [] new_lines = set() changes = 0 llast = None drops = 0 + with open(fn_in, "r") as f: for line in f: # Hack: skip duplicate lines @@ -124,53 +223,64 @@ def add_zero_bits(fn_in, zero_db, clb_int=False, strict=True, verbose=False): if line == llast: continue + lines.append(line) + tag, bits, mode, _ = util.parse_db_line(line) - # an enum that needs masking - # check below asserts that a mask was actually applied - if mode and mode != "<0 candidates>" and not strict: + + if bits is not None and mode is None: + zero_groups.add_tag_bits(tag, bits) + + if verbose: + zero_groups.print_groups() + + for line in lines: + tag, bits, mode, _ = util.parse_db_line(line) + # an enum that needs masking + # check below asserts that a mask was actually applied + if mode and mode != "<0 candidates>" and not strict: + verbose and print("WARNING: dropping unresolved line: %s" % line) + drops += 1 + continue + + assert mode not in ( + "", + ""), "Entries must be resolved. line: %s" % (line, ) + + if mode == "always": + new_line = line + else: + if mode: + assert mode == "<0 candidates>", line + bits = set() + else: + bits = set(bits) + """ + This appears to be a large range of one hot interconnect bits + They are immediately before the first CLB real bits + """ + if clb_int: + zero_range(tag, bits, 22, 25) + zero_groups.add_bits_from_zero_groups( + tag, bits, strict=strict, verbose=verbose) + + if strict: + assert len(bits) > 0, 'Line {} found no bits.'.format(line) + elif len(bits) == 0: verbose and print( "WARNING: dropping unresolved line: %s" % line) drops += 1 continue - assert mode not in ( - "", - ""), "Entries must be resolved. line: %s" % (line, ) + new_line = " ".join([tag] + sorted(bits)) - if mode == "always": - new_line = line - else: - if mode: - assert mode == "<0 candidates>", line - bits = set() - else: - bits = set(bits) - """ - This appears to be a large range of one hot interconnect bits - They are immediately before the first CLB real bits - """ - if clb_int: - zero_range(tag, bits, 22, 25) - zero_groups(tag, bits, zero_db, strict=strict, verbose=verbose) + if re.match(r'.*<.*>.*', new_line): + print("Original line: %s" % line) + assert 0, "Failed to remove line mode: %s" % (new_line) - if strict: - assert len(bits) > 0, 'Line {} found no bits.'.format(line) - elif len(bits) == 0: - verbose and print( - "WARNING: dropping unresolved line: %s" % line) - drops += 1 - continue - - new_line = " ".join([tag] + sorted(bits)) - - if re.match(r'.*<.*>.*', new_line): - print("Original line: %s" % line) - assert 0, "Failed to remove line mode: %s" % (new_line) - - if new_line != line: - changes += 1 - new_lines.add(new_line) - llast = line + if new_line != line: + changes += 1 + new_lines.add(new_line) + llast = line if drops: print("WARNING: %s dropped %s unresolved lines" % (fn_in, drops))