diff --git a/fuzzers/030-iob/Makefile b/fuzzers/030-iob/Makefile index bb17e295..ab0a0168 100644 --- a/fuzzers/030-iob/Makefile +++ b/fuzzers/030-iob/Makefile @@ -13,7 +13,8 @@ build/segbits_xiob33.rdb: $(SPECIMENS_OK) build/segbits_xiob33.db: build/segbits_xiob33.rdb process_rdb.py bits.dbf python3 process_rdb.py build/segbits_xiob33.rdb > build/segbits_xiob33_processed.rdb - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in build/segbits_xiob33_processed.rdb --seg-fn-out $@ + python3 group.py -g tag_groups.txt -i build/segbits_xiob33_processed.rdb -o build/segbits_xiob33_processed.rdb2 + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf --seg-fn-in build/segbits_xiob33_processed.rdb2 --seg-fn-out $@ ${XRAY_MASKMERGE} build/mask_xiob33.db $$(find -name segdata_liob33.txt) $$(find -name segdata_riob33.txt) build/segbits_hclk_ioi3.rdb: $(SPECIMENS_OK) diff --git a/fuzzers/030-iob/bits.dbf b/fuzzers/030-iob/bits.dbf index 09d2e838..e69de29b 100644 --- a/fuzzers/030-iob/bits.dbf +++ b/fuzzers/030-iob/bits.dbf @@ -1,4 +0,0 @@ -38_92 39_93 38_94,IOB33.IOB_Y0.PULLTYPE.PULLDOWN -38_106 39_107 39_111 38_106 38_110 39_105 39_109,IOB33.IOB_Y0.SLEW.FAST -39_33 38_34 39_35,IOB33.IOB_Y1.PULLTYPE.PULLDOWN -39_21 38_16 38_20 38_18 38_22 39_17,IOB33.IOB_Y1.SLEW.FAST diff --git a/fuzzers/030-iob/group.py b/fuzzers/030-iob/group.py new file mode 100755 index 00000000..8a27cf18 --- /dev/null +++ b/fuzzers/030-iob/group.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +""" + +This script Reads tag group definition from a file and applies the tag grouping. +First a set of common bits for each group is found (logical OR among all tags +belonging to the group). Then in each tag belonging to the group those bits are +set to 0 but only if they are not already present there. + +The resulting data is written into a segbits file. +""" +import argparse +import re +import itertools + +# ============================================================================= + + +def load_tag_groups(file_name): + """ + Loads tag groups from a text file. + + A tag group is defined by specifying a space separated list of tags within + a single line. Lines that are empty or start with '#' are ignored. + """ + tag_groups = [] + + # Load tag group specifications + with open(file_name, "r") as fp: + for line in fp: + line = line.strip() + + if len(line) == 0 or line.startswith("#"): + continue + + group = set(line.split()) + if len(group): + tag_groups.append(group) + + # Check if all tag groups are exclusive + for tag_group_a, tag_group_b in itertools.combinations(tag_groups, 2): + + tags = tag_group_a & tag_group_b + if len(tags): + raise RuntimeError( + "Tag(s) {} are present in multiple groups".format( + " ".join(tags))) + + return tag_groups + + +# ============================================================================= + + +def parse_bit(bit): + """ + Decodes string describing a bit. Returns a tuple (frame, bit, value) + """ + match = re.match("^(!?)([0-9]+)_([0-9]+)$", bit) + assert match != None, bit + + val = int(match.group(1) != "!") + frm = int(match.group(2)) + bit = int(match.group(3)) + + return frm, bit, val + + +def bit_to_str(bit): + """ + Converts a tuple (frame, bit, value) to its string representation. + """ + s = "!" if not bit[2] else "" + return "{}{}_{:02d}".format(s, bit[0], bit[1]) + + +def load_segbits(file_name): + """ + Loads a segbits file. + """ + + segbits = {} + + with open(file_name, "r") as fp: + for line in fp: + line = line.strip() + fields = line.split() + + if len(fields) < 2: + raise RuntimeError("Malformed line: '%s'" % line) + + tag = fields[0] + + if "<" in line or ">" in line: + segbits[tag] = " ".join(fields[1:]) + + else: + bits = set([parse_bit(bit) for bit in fields[1:]]) + segbits[tag] = bits + + return segbits + + +def save_segbits(file_name, segbits): + """ + Save segbits to a .db or .rdb file + """ + + with open(file_name, "w") as fp: + for tag, bits in segbits.items(): + + if isinstance(bits, str): + line = tag + " " + bits + + elif isinstance(bits, set): + line = tag + " " + line += " ".join( + [bit_to_str(bit) for bit in sorted(list(bits))]) + + fp.write(line + "\n") + + +# ============================================================================= + + +def mask_out_bits(segbits, mask, tags_to_mask=None): + """ + Given a set of bits and a list of tags to affect (optional) removes all + the bits from each tag that are present (and equal) in the masking set. + """ + + if tags_to_mask is None: + tags_to_mask = segbits.keys() + + # Mask out matching bits + for tag in tags_to_mask: + bits = segbits[tag] + + bits = set(bits) - set(mask) + segbits[tag] = bits + + return segbits + + +def find_common_bits_for_tag_groups(segbits, tag_groups): + """ + For each tag group finds a common set of bits that have value of one. + """ + + bit_groups = [] + + for tag_group in tag_groups: + bit_group = set() + + for tag, bits in segbits.items(): + if tag in tag_group and isinstance(bits, set): + ones = set([b for b in bits if b[2]]) + bit_group |= ones + + bit_groups.append(bit_group) + + return bit_groups + + +def group_tags(segbits, tag_groups, bit_groups): + """ + Implements tag grouping. If a tag belongs to a group then the common bits + of that group are added to is as zeros. + """ + + for tag_group, bit_group in zip(tag_groups, bit_groups): + zeros = set([(b[0], b[1], 0) for b in bit_group]) + for tag in tag_group: + + # Insert zero bits + if tag in segbits.keys(): + bits = segbits[tag] + + if not isinstance(bits, set): + bits = set() + segbits[tag] = bits + + for z in zeros: + if not (z[0], z[1], 1) in bits: + bits.add(z) + + return segbits + + +# ============================================================================= + + +def main(): + + # Parse arguments + parser = argparse.ArgumentParser() + + parser.add_argument("-i", required=True, type=str, help="Input .rdb file") + parser.add_argument( + "-g", required=True, type=str, help="Input tag group definition file") + parser.add_argument("-o", required=True, type=str, help="Output .rdb file") + + args = parser.parse_args() + + # Load tag groups + tag_groups = load_tag_groups(args.g) + + # Load raw database file + segbits = load_segbits(args.i) + + # Find common bits + bit_groups = find_common_bits_for_tag_groups(segbits, tag_groups) + # Apply tag grouping + segbits = group_tags(segbits, tag_groups, bit_groups) + + # Save fixed database file + save_segbits(args.o, segbits) + + +if __name__ == "__main__": + main() diff --git a/fuzzers/030-iob/tag_groups.txt b/fuzzers/030-iob/tag_groups.txt new file mode 100644 index 00000000..388934fe --- /dev/null +++ b/fuzzers/030-iob/tag_groups.txt @@ -0,0 +1,5 @@ +IOB33.IOB_Y0.IN_TERM.NONE IOB33.IOB_Y0.IN_TERM.UNTUNED_SPLIT_40 IOB33.IOB_Y0.IN_TERM.UNTUNED_SPLIT_50 IOB33.IOB_Y0.IN_TERM.UNTUNED_SPLIT_60 +IOB33.IOB_Y1.IN_TERM.NONE IOB33.IOB_Y1.IN_TERM.UNTUNED_SPLIT_40 IOB33.IOB_Y1.IN_TERM.UNTUNED_SPLIT_50 IOB33.IOB_Y1.IN_TERM.UNTUNED_SPLIT_60 + +IOB33.IOB_Y0.PULLTYPE.KEEPER IOB33.IOB_Y0.PULLTYPE.NONE IOB33.IOB_Y0.PULLTYPE.PULLDOWN IOB33.IOB_Y0.PULLTYPE.PULLUP +IOB33.IOB_Y1.PULLTYPE.KEEPER IOB33.IOB_Y1.PULLTYPE.NONE IOB33.IOB_Y1.PULLTYPE.PULLDOWN IOB33.IOB_Y1.PULLTYPE.PULLUP