diff --git a/.gitignore b/.gitignore index b8811137..ec469db3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ database run.ok __pycache__ *.pyc +*.swp diff --git a/fuzzers/100-dsp-mskpat/generate.py b/fuzzers/100-dsp-mskpat/generate.py index ead33cd5..fe0d3271 100644 --- a/fuzzers/100-dsp-mskpat/generate.py +++ b/fuzzers/100-dsp-mskpat/generate.py @@ -1,23 +1,126 @@ #!/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) -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" +def add(segmk, site, dsp, tag, bit, value, invert): + tag = "%s.%s%s[%u]" % (dsp, ('Z' if invert else ''), tag, bit) + value = (~value if invert else value) + value >>= bit + return segmk.add_site_tag(site, tag, value & 1) - mask = int(d['mask']) - pattern = int(d['pattern']) + +def run(): + segmk = Segmaker("design.bits", verbose=True) + + print("Loading tags") + with open('params.json', 'r') as fp: + data = json.load(fp) + + for params in data['instances']: + dsp = "DSP_0" if params['SITE'][-1] in "02468" else "DSP_1" + site = params['SITE'] + + add(segmk, site, dsp, 'ADREG', 0, to_int(params['ADREG']), 0) + add(segmk, site, dsp, 'ALUMODEREG', 0, to_int(params['ALUMODEREG']), 1) + + for i in range(2): + add(segmk, site, dsp, 'AREG', i, to_int(params['AREG']), 1) + + for i in range(2): + add(segmk, site, dsp, 'ACASCREG', i, to_int(params['ACASCREG']), 1) + + for i in range(2): + add(segmk, site, dsp, 'BREG', i, to_int(params['BREG']), 1) + + for i in range(2): + add(segmk, site, dsp, 'BCASCREG', i, to_int(params['BCASCREG']), 1) + + 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) + + 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) + + INPUT = {} + INPUT[quote('DIRECT')] = 0 + INPUT[quote('CASCADE')] = 1 + + add(segmk, site, dsp, 'A_INPUT', 0, INPUT[params['A_INPUT']], 0) + add(segmk, site, dsp, 'B_INPUT', 0, INPUT[params['B_INPUT']], 0) + + BOOL = {} + BOOL[quote('FALSE')] = 0 + BOOL[quote('TRUE')] = 1 + + add(segmk, site, dsp, 'USE_DPORT', 0, BOOL[params['USE_DPORT']], 0) + + SIMD = {} + SIMD[quote('ONE48')] = 0 + SIMD[quote('TWO24')] = 1 + SIMD[quote('FOUR12')] = 2 + + for i in range(2): + add(segmk, site, dsp, 'USE_SIMD', i, SIMD[params['USE_SIMD']], 0) + + MULT = {} + MULT[quote('NONE')] = 0 + MULT[quote('MULTIPLY')] = 1 + MULT[quote('DYNAMIC')] = 2 + + for i in range(2): + add(segmk, site, dsp, 'USE_MULT', i, MULT[params['USE_MULT']], 0) + + 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) -segmk.compile() -segmk.write() + for i in range(48): + add(segmk, site, dsp, 'PATTERN', i, to_int(params['PATTERN']), 0) + + SEL_MASK = {} + SEL_MASK[quote('MASK')] = 0 + SEL_MASK[quote('C')] = 1 + SEL_MASK[quote('ROUNDING_MODE1')] = 2 + SEL_MASK[quote('ROUNDING_MODE2')] = 3 + + for i in range(2): + add( + segmk, site, dsp, 'SEL_MASK', i, SEL_MASK[params['SEL_MASK']], + 0) + + 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/generate.tcl b/fuzzers/100-dsp-mskpat/generate.tcl index 9e8cab8a..ee2542fe 100644 --- a/fuzzers/100-dsp-mskpat/generate.tcl +++ b/fuzzers/100-dsp-mskpat/generate.tcl @@ -5,10 +5,19 @@ proc run {} { read_verilog top.v synth_design -top top + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports clk] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports di] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_02) IOSTANDARD LVCMOS33" [get_ports do] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_03) IOSTANDARD LVCMOS33" [get_ports stb] + 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 + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + place_design route_design diff --git a/fuzzers/100-dsp-mskpat/top.py b/fuzzers/100-dsp-mskpat/top.py index a64915cb..a480ebb6 100644 --- a/fuzzers/100-dsp-mskpat/top.py +++ b/fuzzers/100-dsp-mskpat/top.py @@ -1,55 +1,149 @@ import os import random +import json random.seed(int(os.getenv("SEED"), 16)) from prjxray import util +from prjxray import verilog from prjxray.db import Database def gen_sites(): db = Database(util.get_db_root()) grid = db.grid() - for tile_name in sorted(grid.tiles()): - loc = grid.loc_of_tilename(tile_name) + for tile in sorted(grid.tiles()): + loc = grid.loc_of_tilename(tile) gridinfo = grid.gridinfo_at_loc(loc) if gridinfo.tile_type in ['DSP_L', 'DSP_R']: for site in sorted(gridinfo.sites.keys()): if gridinfo.sites[site] == 'DSP48E1': - yield tile_name, site + yield tile, site -def write_params(lines): - pinstr = 'tile,site,mask,pattern\n' - for tile, site, mask, pattern in lines: - pinstr += '%s,%s,%s,%s\n' % (tile, site, mask, pattern) - - open('params.csv', 'w').write(pinstr) +def fuzz(*args): + if len(args) == 1 and isinstance(args[0], int): + # Argument indicates that we should generate a random integer with + # args[0] number of bits. + return random.getrandbits(args[0]) + else: + # Otherwise make a random choice + return random.choice(*args) def run(): - print(''' -module top(); - ''') + verilog.top_harness(48, 48) - lines = [] + print('module roi(input clk, input [47:0] din, output [47:0] dout);') + + data = {} + data['instances'] = [] sites = list(gen_sites()) - for (tile_name, site_name) in sites: - mask = random.randint(0, 2**48 - 1) - pattern = random.randint(0, 2**48 - 1) - lines.append((tile_name, site_name, mask, pattern)) - print( - ''' - (* KEEP, DONT_TOUCH, LOC = "{0}" *) - DSP48E1 #( - .MASK(48'h{1:x}), - .PATTERN(48'h{2:x}) - ) dsp_{0} ( - ); -'''.format(site_name, mask, pattern)) + for i, (tile, site) in enumerate(sites): + synthesis = '(* KEEP, DONT_TOUCH, LOC = "%s" *)' % (site) + module = 'DSP48E1' + instance = 'INST_%s' % (site) + ports = {} + params = {} + + ports['A'] = '{30{1\'b1}}' + ports['ACIN'] = '{30{1\'b1}}' + ports['ACOUT'] = '30\'b0' + ports['ALUMODE'] = '4\'b1' + ports['B'] = '{18{1\'b1}}' + ports['BCIN'] = '{18{1\'b1}}' + ports['BCOUT'] = '18\'b0' + ports['C'] = '{48{1\'b1}}' + ports['CARRYCASCIN'] = '1\'b1' + ports['CARRYCASCOUT'] = '1\'b0' + ports['CARRYIN'] = '1\'b1' + ports['CARRYINSEL'] = '3\'b000' + ports['CARRYOUT'] = '4\'b0' + ports['CEA1'] = '1\'b1' + ports['CEA2'] = '1\'b1' + ports['CEAD'] = '1\'b1' + ports['CEALUMODE'] = '1\'b1' + ports['CEB1'] = '1\'b1' + ports['CEB2'] = '1\'b1' + ports['CEC'] = '1\'b1' + ports['CECARRYIN'] = '1\'b1' + ports['CECTRL'] = '1\'b1' + ports['CED'] = '1\'b1' + ports['CEINMODE'] = '1\'b1' + ports['CEM'] = '1\'b1' + ports['CEP'] = '1\'b1' + ports['CLK'] = '1\'b1' + ports['D'] = '{25{1\'b1}}' + ports['INMODE'] = '5\'b11111' + #ports['MULTISIGNIN'] = '1\'b1' + #ports['MULTISIGNOUT'] = '1\'b0' + ports['OPMODE'] = '7\'b1111111' + ports['OVERFLOW'] = '1\'b0' + ports['P'] = '48\'b0' + ports['PATTERNBDETECT'] = '1\'b0' + ports['PATTERNDETECT'] = '1\'b0' + ports['PCIN'] = '{48{1\'b1}}' + ports['PCOUT'] = '48\'b0' + ports['RSTA'] = '1\'b1' + ports['RSTALLCARRYIN'] = '1\'b1' + ports['RSTALUMODE'] = '1\'b1' + ports['RSTB'] = '1\'b1' + ports['RSTC'] = '1\'b1' + ports['RSTCTRL'] = '1\'b1' + ports['RSTD'] = '1\'b1' + ports['RSTINMODE'] = '1\'b1' + ports['RSTM'] = '1\'b1' + ports['RSTP'] = '1\'b1' + ports['UNDERFLOW'] = '1\'b0' + + params['ADREG'] = fuzz((0, 1)) + params['ALUMODEREG'] = fuzz((0, 1)) + params['AREG'] = fuzz((0, 1, 2)) + if params['AREG'] == 0 or params['AREG'] == 1: + params['ACASCREG'] = params['AREG'] + else: + params['ACASCREG'] = fuzz((1, 2)) + params['BREG'] = fuzz((0, 1, 2)) + if params['BREG'] == 0 or params['BREG'] == 1: + params['BCASCREG'] = params['BREG'] + else: + params['BCASCREG'] = 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'))) + + verilog.instance(synthesis + ' ' + module, instance, ports, params) + + params['TILE'] = tile + params['SITE'] = site + + data['instances'].append(params) + + with open('params.json', 'w') as fp: + json.dump(data, fp) print("endmodule") - write_params(lines) if __name__ == '__main__': diff --git a/prjxray/verilog.py b/prjxray/verilog.py index 3e3af277..de3895e9 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): @@ -65,6 +66,37 @@ def unquote(s): 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": return 0