From e0fb0c0cb11e2e8c2c9c0bd6ebab8d1e70e3cddb Mon Sep 17 00:00:00 2001 From: Jake Mercer Date: Sun, 27 Oct 2019 12:19:23 +0000 Subject: [PATCH] FUZZER - DSP - Refactor Refactor the DSP Python scripts to be easier to manage. Use JSON instead of CSV. Signed-off-by: Jake Mercer --- fuzzers/100-dsp-mskpat/generate.py | 213 ++++++++++++----------------- fuzzers/100-dsp-mskpat/top.py | 177 +++++++----------------- prjxray/verilog.py | 30 ++++ 3 files changed, 171 insertions(+), 249 deletions(-) diff --git a/fuzzers/100-dsp-mskpat/generate.py b/fuzzers/100-dsp-mskpat/generate.py index 63ddb7fb..6f879a88 100644 --- a/fuzzers/100-dsp-mskpat/generate.py +++ b/fuzzers/100-dsp-mskpat/generate.py @@ -1,154 +1,123 @@ #!/usr/bin/env python3 from prjxray.segmaker import Segmaker -import csv +from prjxray.verilog import to_int +from prjxray.verilog import quote +import json -segmk = Segmaker("design.bits", verbose=True) +def bits_in(value, width): + bits = [] + for i in range(width): + bits.append(value & 1) + value >>= 1 + return bits -print("Loading tags") -with open('params.csv', 'r') as f: - for d in csv.DictReader(f): - dsp = "DSP_0" if d['SITE'][-1] in "02468" else "DSP_1" - acascreg = int(d['ACASCREG']) - segmk.add_site_tag( - d['SITE'], "%s.ZACASCREG[0]" % (dsp), ~(acascreg >> 0) & 1) - segmk.add_site_tag( - d['SITE'], "%s.ZACASCREG[1]" % (dsp), ~(acascreg >> 1) & 1) +def add(segmk, site, dsp, tag, bit, value, invert): + tag = dsp + '.' + '%s' % ('Z' if invert else '') + tag + '[%u]' % bit + value = (~value if invert else value) + value >>= bit + return segmk.add_site_tag(site, tag, value & 1) - adreg = int(d['ADREG']) - segmk.add_site_tag(d['SITE'], "%s.ADREG[0]" % (dsp), adreg & 1) - alumodereg = int(d['ALUMODEREG']) - segmk.add_site_tag( - d['SITE'], "%s.ZALUMODEREG[0]" % (dsp), ~alumodereg & 1) +def run(): + segmk = Segmaker("design.bits", verbose=True) - areg = int(d['AREG']) - segmk.add_site_tag(d['SITE'], "%s.ZAREG[0]" % (dsp), ~(areg >> 0) & 1) - segmk.add_site_tag(d['SITE'], "%s.ZAREG[1]" % (dsp), ~(areg >> 1) & 1) + print("Loading tags") + with open('params.json', 'r') as fp: + data = json.load(fp) - bcascreg = int(d['BCASCREG']) - segmk.add_site_tag( - d['SITE'], "%s.ZBCASCREG[0]" % (dsp), ~(bcascreg >> 0) & 1) - segmk.add_site_tag( - d['SITE'], "%s.ZBCASCREG[1]" % (dsp), ~(bcascreg >> 1) & 1) + for params in data['instances']: + dsp = "DSP_0" if params['SITE'][-1] in "02468" else "DSP_1" + site = params['SITE'] - breg = int(d['BREG']) - segmk.add_site_tag(d['SITE'], "%s.ZBREG[0]" % (dsp), ~(breg >> 0) & 1) - segmk.add_site_tag(d['SITE'], "%s.ZBREG[1]" % (dsp), ~(breg >> 1) & 1) + add(segmk, site, dsp, 'ADREG', 0, to_int(params['ADREG']), 0) + add(segmk, site, dsp, 'ALUMODEREG', 0, to_int(params['ALUMODEREG']), 1) - carryinreg = int(d['CARRYINREG']) - segmk.add_site_tag(d['SITE'], "%s.ZCARRYINREG[0]" % (dsp), ~carryinreg) + for i in range(2): + add(segmk, site, dsp, 'AREG', i, to_int(params['AREG']), 1) - carryinselreg = int(d['CARRYINSELREG']) - segmk.add_site_tag( - d['SITE'], "%s.ZCARRYINSELREG[0]" % (dsp), ~carryinselreg) + for i in range(2): + add(segmk, site, dsp, 'ACASCREG', i, to_int(params['ACASCREG']), 1) - creg = int(d['CREG']) - segmk.add_site_tag(d['SITE'], "%s.ZCREG[0]" % (dsp), ~creg) + for i in range(2): + add(segmk, site, dsp, 'BREG', i, to_int(params['BREG']), 1) - dreg = int(d['DREG']) - segmk.add_site_tag(d['SITE'], "%s.DREG[0]" % (dsp), dreg) + for i in range(2): + add(segmk, site, dsp, 'BCASCREG', i, to_int(params['BCASCREG']), 1) - inmodereg = int(d['INMODEREG']) - segmk.add_site_tag(d['SITE'], "%s.ZINMODEREG[0]" % (dsp), ~inmodereg) + add(segmk, site, dsp, 'CARRYINREG', 0, to_int(params['CARRYINREG']), 1) + add(segmk, site, dsp, 'CARRYINSELREG', 0, to_int(params['CARRYINSELREG']), 1) + add(segmk, site, dsp, 'CREG', 0, to_int(params['CREG']), 1) - mreg = int(d['MREG']) - segmk.add_site_tag(d['SITE'], "%s.ZMREG[0]" % (dsp), ~mreg) + add(segmk, site, dsp, 'DREG', 0, to_int(params['DREG']), 0) + add(segmk, site, dsp, 'INMODEREG', 0, to_int(params['INMODEREG']), 1) + add(segmk, site, dsp, 'OPMODEREG', 0, to_int(params['OPMODEREG']), 1) + add(segmk, site, dsp, 'PREG', 0, to_int(params['PREG']), 1) - opmodereg = int(d['OPMODEREG']) - segmk.add_site_tag(d['SITE'], "%s.ZOPMODEREG[0]" % (dsp), ~opmodereg) + INPUT = {} + INPUT[quote('DIRECT')] = 0 + INPUT[quote('CASCADE')] = 1 - preg = int(d['PREG']) - segmk.add_site_tag(d['SITE'], "%s.ZPREG[0]" % (dsp), ~preg) + add(segmk, site, dsp, 'A_INPUT', 0, INPUT[params['A_INPUT']], 0) + add(segmk, site, dsp, 'B_INPUT', 0, INPUT[params['B_INPUT']], 0) - a_input = str(d['A_INPUT']) - segmk.add_site_tag( - d['SITE'], "%s.ZA_INPUT[0]" % (dsp), - (0 if a_input == "DIRECT" else 1)) + BOOL = {} + BOOL[quote('FALSE')] = 0 + BOOL[quote('TRUE')] = 1 - b_input = str(d['B_INPUT']) - segmk.add_site_tag( - d['SITE'], "%s.ZB_INPUT[0]" % (dsp), - (0 if b_input == "DIRECT" else 1)) + add(segmk, site, dsp, 'USE_DPORT', 0, BOOL[params['USE_DPORT']], 0) - use_dport = str(d['USE_DPORT']) - segmk.add_site_tag( - d['SITE'], "%s.USE_DPORT[0]" % (dsp), - (0 if use_dport == "FALSE" else 1)) + SIMD = {} + SIMD[quote('ONE48')] = 0 + SIMD[quote('TWO24')] = 1 + SIMD[quote('FOUR12')] = 2 - use_mult = str(d['USE_MULT']) - if use_mult == "NONE": - segmk.add_site_tag(d['SITE'], "%s.USE_MULT[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.ZUSE_MULT[1]" % (dsp), ~0) - elif use_mult == "MULTIPLY": - segmk.add_site_tag(d['SITE'], "%s.USE_MULT[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.ZUSE_MULT[1]" % (dsp), ~1) - elif use_mult == "DYNAMIC": - segmk.add_site_tag(d['SITE'], "%s.USE_MULT[0]" % (dsp), 1) - segmk.add_site_tag(d['SITE'], "%s.ZUSE_MULT[1]" % (dsp), ~1) + for i in range(2): + add(segmk, site, dsp, 'USE_SIMD', i, SIMD[params['USE_SIMD']], 0) - use_simd = str(d['USE_SIMD']) - if use_simd == "ONE48": - segmk.add_site_tag(d['SITE'], "%s.USE_SIMD[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.USE_SIMD[1]" % (dsp), 0) - elif use_simd == "TWO24": - segmk.add_site_tag(d['SITE'], "%s.USE_SIMD[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.USE_SIMD[1]" % (dsp), 1) - elif use_simd == "FOUR12": - segmk.add_site_tag(d['SITE'], "%s.USE_SIMD[0]" % (dsp), 1) - segmk.add_site_tag(d['SITE'], "%s.USE_SIMD[1]" % (dsp), 1) + MULT = {} + MULT[quote('NONE')] = 0 + MULT[quote('MULTIPLY')] = 1 + MULT[quote('DYNAMIC')] = 2 - autoreset_patdet = str(d['AUTORESET_PATDET']) - if autoreset_patdet == "RESET_MATCH": - segmk.add_site_tag(d['SITE'], "%s.AUTO_RESET_PATDET[0]" % (dsp), 0) - segmk.add_site_tag( - d['SITE'], "%s.ZAUTO_RESET_PATDET[1]" % (dsp), 1) - elif autoreset_patdet == "NO_RESET": - segmk.add_site_tag(d['SITE'], "%s.AUTO_RESET_PATDET[0]" % (dsp), 0) - segmk.add_site_tag( - d['SITE'], "%s.ZAUTO_RESET_PATDET[1]" % (dsp), 0) - elif autoreset_patdet == "RESET_NOT_MATCH": - segmk.add_site_tag(d['SITE'], "%s.AUTO_RESET_PATDET[0]" % (dsp), 1) - segmk.add_site_tag( - d['SITE'], "%s.ZAUTO_RESET_PATDET[1]" % (dsp), 1) + for i in range(2): + add(segmk, site, dsp, 'USE_MULT', i, MULT[params['USE_MULT']], 0) - mask = int(d['MASK']) - pattern = int(d['PATTERN']) + add(segmk, site, dsp, 'MREG', 0, to_int(params['MREG']), 1) + + AUTORESET = {} + AUTORESET[quote('NO_RESET')] = 0 + AUTORESET[quote('RESET_NOT_MATCH')] = 1 + AUTORESET[quote('RESET_MATCH')] = 2 + + add(segmk, site, dsp, 'AUTORESET_PATDET', 0, AUTORESET[params['AUTORESET_PATDET']], 0) + add(segmk, site, dsp, 'AUTORESET_PATDET', 1, AUTORESET[params['AUTORESET_PATDET']], 1) for i in range(48): - segmk.add_site_tag( - d['SITE'], "%s.MASK[%d]" % (dsp, i), (mask >> i) & 1) - segmk.add_site_tag( - d['SITE'], "%s.PATTERN[%d]" % (dsp, i), (pattern >> i) & 1) + add(segmk, site, dsp, 'MASK', i, to_int(params['MASK']), 0) - sel_mask = str(d['SEL_MASK']) - if sel_mask == "MASK": - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[1]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[2]" % (dsp), 0) - elif sel_mask == "C": - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[1]" % (dsp), 1) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[2]" % (dsp), 0) - elif sel_mask == "ROUNDING_MODE1": - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[0]" % (dsp), 1) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[1]" % (dsp), 1) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[2]" % (dsp), 0) - elif sel_mask == "ROUNDING_MODE2": - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[0]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[1]" % (dsp), 0) - segmk.add_site_tag(d['SITE'], "%s.SEL_MASK[2]" % (dsp), 1) + for i in range(48): + add(segmk, site, dsp, 'PATTERN', i, to_int(params['PATTERN']), 0) - sel_pattern = str(d['SEL_PATTERN']) - segmk.add_site_tag( - d['SITE'], "%s.ZSEL_PATTERN[0]" % (dsp), - (0 if sel_pattern == "PATTERN" else 1)) + SEL_MASK = {} + SEL_MASK[quote('MASK')] = 0 + SEL_MASK[quote('C')] = 1 + SEL_MASK[quote('ROUNDING_MODE1')] = 2 + SEL_MASK[quote('ROUNDING_MODE2')] = 3 - use_pattern_detect = str(d['USE_PATTERN_DETECT']) - segmk.add_site_tag( - d['SITE'], "%s.USE_PATTERN_DETECT[0]" % (dsp), - (0 if use_pattern_detect == "PATDET" else 1)) + for i in range(2): + add(segmk, site, dsp, 'SEL_MASK', i, SEL_MASK[params['SEL_MASK']], 0) -segmk.compile() -segmk.write() + USE_PATTERN_DETECT = {} + USE_PATTERN_DETECT[quote('NO_PATDET')] = 0 + USE_PATTERN_DETECT[quote('PATDET')] = 1 + + add(segmk, site, dsp, 'USE_PATTERN_DETECT', 0, USE_PATTERN_DETECT[params['USE_PATTERN_DETECT']], 0) + + segmk.compile() + segmk.write() + + +if __name__ == '__main__': + run() diff --git a/fuzzers/100-dsp-mskpat/top.py b/fuzzers/100-dsp-mskpat/top.py index 01c4e42c..66a119ba 100644 --- a/fuzzers/100-dsp-mskpat/top.py +++ b/fuzzers/100-dsp-mskpat/top.py @@ -1,8 +1,9 @@ import os import random -import csv +import json random.seed(int(os.getenv("SEED"), 16)) from prjxray import util +from prjxray import verilog from prjxray.db import Database @@ -29,146 +30,68 @@ def fuzz(*args): def run(): - # Attributes list: - # Attribute name - # Verilog parameter value prefix - # Arguments to `fuzz` - # Verilog parameter value suffix - attributes = [] - attributes.append(('ADREG', '', (0, 1), '')) - attributes.append(('ALUMODEREG', '', (0, 1), '')) - # AREG/BREG requires inputs to be connected when configured with a value of - # 2, contstraining to 0 and 1 for now. - attributes.append(('AREG', '', (0, 1), '')) - attributes.append(('BREG', '', (0, 1), '')) - attributes.append(('CARRYINREG', '', (0, 1), '')) - attributes.append(('CARRYINSELREG', '', (0, 1), '')) - attributes.append(('CREG', '', (0, 1), '')) - attributes.append(('DREG', '', (0, 1), '')) - attributes.append(('INMODEREG', '', (0, 1), '')) - attributes.append(('OPMODEREG', '', (0, 1), '')) - attributes.append(('PREG', '', (0, 1), '')) - attributes.append(('A_INPUT', '"', ('DIRECT', 'CASCADE'), '"')) - attributes.append(('B_INPUT', '"', ('DIRECT', 'CASCADE'), '"')) - attributes.append(('USE_DPORT', '"', ('TRUE', 'FALSE'), '"')) - attributes.append(('USE_SIMD', '"', ('ONE48', 'TWO24', 'FOUR12'), '"')) - attributes.append( - ( - 'AUTORESET_PATDET', '"', - ('NO_RESET', 'RESET_MATCH', 'RESET_NOT_MATCH'), '"')) - attributes.append(('MASK', '48\'d', (48), '')) - attributes.append(('PATTERN', '48\'d', (48), '')) - attributes.append( - ( - 'SEL_MASK', '"', ('MASK', 'C', 'ROUNDING_MODE1', 'ROUNDING_MODE2'), - '"')) - attributes.append(('SEL_PATTERN', '"', ('PATTERN', 'C'), '"')) - attributes.append( - ('USE_PATTERN_DETECT', '"', ('NO_PATDET', 'PATDET'), '"')) - - # CSV headings - headings = [] - headings.append('TILE') - headings.append('SITE') - - for attribute in attributes: - headings.append(attribute[0]) - - # ACASCREG dependent on AREG - if attribute[0] == 'AREG': - headings.append('ACASCREG') - - # BCASCREG dependent on BREG - if attribute[0] == 'BREG': - headings.append('BCASCREG') - - # USE_MULT dependent on USE_SIMD - if attribute[0] == 'USE_SIMD': - headings.append('USE_MULT') - # MREG dependent on USE_MULT - headings.append('MREG') - - # CSV rows - rows = [] - rows.append(headings) + data = {} + data['instances'] = [] print('module top();') sites = list(gen_sites()) - # For every DSP site: - # Add an instance to top.v with fuzzed attributes - # Add a row for params.csv for (tile, site) in sites: - row = [] - row.append(tile) - row.append(site) - print('\t(* KEEP, DONT_TOUCH, LOC = "{0}" *)'.format(site)) - print('\tDSP48E1 #(') + synthesis = '(* KEEP, DONT_TOUCH, LOC = "%s" *)' % (site) + module = 'DSP48E1' + instance = 'INST_%s' % (site) + ports = {} + params = {} - for attr in attributes[:-1]: - val = fuzz(attr[2]) - row.append(val) - print( - '\t\t.{0}({1}{2}{3}),'.format(attr[0], attr[1], val, attr[3])) + params['ADREG'] = fuzz((0, 1)) + params['ALUMODEREG'] = fuzz((0, 1)) + # AREG/BREG requires inputs to be connected when configured with a value + # of 2, constraining to 0 and 1 for now. + params['AREG'] = fuzz((0, 1)) + params['ACASCREG'] = params['AREG'] if params[ + 'AREG'] == 0 or params['AREG'] == 1 else fuzz((1, 2)) + params['BREG'] = fuzz((0, 1)) + params['BCASCREG'] = params['BREG'] if params[ + 'BREG'] == 0 or params['BREG'] == 1 else fuzz((1, 2)) + params['CARRYINREG'] = fuzz((0, 1)) + params['CARRYINSELREG'] = fuzz((0, 1)) + params['CREG'] = fuzz((0, 1)) + params['DREG'] = fuzz((0, 1)) + params['INMODEREG'] = fuzz((0, 1)) + params['OPMODEREG'] = fuzz((0, 1)) + params['PREG'] = fuzz((0, 1)) + params['A_INPUT'] = verilog.quote(fuzz(('DIRECT', 'CASCADE'))) + params['B_INPUT'] = verilog.quote(fuzz(('DIRECT', 'CASCADE'))) + params['USE_DPORT'] = verilog.quote(fuzz(('TRUE', 'FALSE'))) + params['USE_SIMD'] = verilog.quote( + fuzz(('ONE48', 'TWO24', 'FOUR12'))) + params['USE_MULT'] = verilog.quote( + 'NONE' if params['USE_SIMD'] != verilog.quote('ONE48') else + fuzz(('NONE', 'MULTIPLY', 'DYNAMIC'))) + params['MREG'] = 0 if params['USE_MULT'] == verilog.quote( + 'NONE') else fuzz((0, 1)) + params['AUTORESET_PATDET'] = verilog.quote( + fuzz(('NO_RESET', 'RESET_MATCH', 'RESET_NOT_MATCH'))) + params['MASK'] = '48\'d%s' % fuzz(48) + params['PATTERN'] = '48\'d%s' % fuzz(48) + params['SEL_MASK'] = verilog.quote( + fuzz(('MASK', 'C', 'ROUNDING_MODE1', 'ROUNDING_MODE2'))) + params['USE_PATTERN_DETECT'] = verilog.quote( + fuzz(('NO_PATDET', 'PATDET'))) - # ACASCREG dependent on AREG - if attr[0] == 'AREG': - if val == 0 or val == 1: - print('\t\t.ACASCREG({0}),'.format(val)) - elif val == 2: - val = fuzz((1, 2)) - print('\t\t.ACASCREG({0}),'.format(val)) + verilog.instance(synthesis + ' ' + module, instance, ports, params) - row.append(val) + params['TILE'] = tile + params['SITE'] = site - # BCASCREG dependent on BREG - elif attr[0] == 'BREG': - if val == 0 or val == 1: - print('\t\t.BCASCREG({0}),'.format(val)) - elif val == 2: - val = fuzz((1, 2)) - print('\t\t.BCASCREG({0}),'.format(val)) + data['instances'].append(params) - row.append(val) - - # USE_MULT dependent on USE_SIMD - elif attr[0] == 'USE_SIMD': - if val != "ONE48": - val = 'NONE' - print('\t\t.USE_MULT("{0}"),'.format(val)) - else: - val = fuzz(('NONE', 'MULTIPLY', 'DYNAMIC')) - print('\t\t.USE_MULT("{0}"),'.format(val)) - - row.append(val) - - # MREG dependent on USE_MULT - if val == 'NONE': - val = 0 - print('\t\t.MREG("{0}"),'.format(val)) - else: - val = fuzz((0, 1)) - print('\t\t.MREG("{0}"),'.format(val)) - - row.append(val) - - attr = attributes[-1] - val = fuzz(attr[2]) - row.append(val) - print('\t\t.{0}({1}{2}{3})'.format(attr[0], attr[1], val, attr[3])) - - rows.append(row) - print('\t) dsp_{0} ();\n'.format(site)) + with open('params.json', 'w') as fp: + json.dump(data, fp) print("endmodule") - # Generate params.csv - with open('params.csv', 'w') as writeFile: - writer = csv.writer(writeFile) - writer.writerows(rows) - writeFile.close() - if __name__ == '__main__': run() diff --git a/prjxray/verilog.py b/prjxray/verilog.py index 3e3af277..0ca4f6f4 100644 --- a/prjxray/verilog.py +++ b/prjxray/verilog.py @@ -1,5 +1,6 @@ import sys import random +import re def top_harness(DIN_N, DOUT_N, f=sys.stdout): @@ -64,6 +65,35 @@ def unquote(s): assert s[0] == '"' and s[-1] == '"' return s[1:-1] +def to_int(s): + value = 0 + + match = re.search(r'^(\d+)\'([sS]*)([bBoOdDhH])(.*)', str(s)) + + if match: + width = int(match.group(1)) + signed = match.group(2) + radix = match.group(3) + value = match.group(4) + + # Convert to int type + if re.match(r'[bB]', radix): + value = int(value, 2) + elif re.match(r'[oO]', radix): + value = int(value, 8) + elif re.match(r'[dD]', radix): + value = int(value, 10) + elif re.match(r'[hH]', radix): + value = int(value, 16) + else: + raise ValueError('Don\'t know how to interpret input %s' % (s)) + + # Truncate to `width` bits + value &= 2**width - 1 + else: + value = int(s) + + return value def parsei(s): if s == "1'b0":