From 01a0be316279c2b280e07b1232c69cd85c688a9a Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Wed, 19 Jun 2019 14:42:33 -0700 Subject: [PATCH] Add support to zero db to support simple groups. Previously these kinds of zero groups would require encoding the final bits, rather than tags. This is extends the dbfixup to construct groups via groups of tags, rather than groups of bits. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/011-clb-ffconfig/Makefile | 1 + fuzzers/011-clb-ffconfig/bits.dbf | 3 + fuzzers/011-clb-ffconfig/generate.py | 2 + fuzzers/019-clb-ndi1mux/Makefile | 1 + fuzzers/019-clb-ndi1mux/bits.dbf | 3 + fuzzers/019-clb-ndi1mux/generate.py | 3 + utils/dbfixup.py | 273 +++++++++++++++++++-------- 7 files changed, 205 insertions(+), 81 deletions(-) create mode 100644 fuzzers/011-clb-ffconfig/bits.dbf create mode 100644 fuzzers/019-clb-ndi1mux/bits.dbf 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..1dcf2aaf 100755 --- a/utils/dbfixup.py +++ b/utils/dbfixup.py @@ -51,57 +51,153 @@ 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: + assert len(bits) == 0 + 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 +207,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 +224,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))