Merge pull request #1080 from JakeMercer/dsp

DSP - Add Attribute Fuzzing
This commit is contained in:
litghost 2019-11-04 08:16:53 -08:00 committed by GitHub
commit 4cec0817ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 280 additions and 41 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ database
run.ok run.ok
__pycache__ __pycache__
*.pyc *.pyc
*.swp

View File

@ -1,23 +1,126 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from prjxray.segmaker import Segmaker 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") def add(segmk, site, dsp, tag, bit, value, invert):
with open('params.csv', 'r') as f: tag = "%s.%s%s[%u]" % (dsp, ('Z' if invert else ''), tag, bit)
for d in csv.DictReader(f): value = (~value if invert else value)
dsp = "DSP_0" if d['site'][-1] in "02468" else "DSP_1" 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): for i in range(48):
segmk.add_site_tag( add(segmk, site, dsp, 'MASK', i, to_int(params['MASK']), 0)
d['site'], "%s.MASK[%d]" % (dsp, i), (mask >> i) & 1)
segmk.add_site_tag(
d['site'], "%s.PATTERN[%d]" % (dsp, i), (pattern >> i) & 1)
segmk.compile() for i in range(48):
segmk.write() 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()

View File

@ -5,10 +5,19 @@ proc run {} {
read_verilog top.v read_verilog top.v
synth_design -top top 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 CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design] set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.PERFRAMECRC YES [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 place_design
route_design route_design

View File

@ -1,55 +1,149 @@
import os import os
import random import random
import json
random.seed(int(os.getenv("SEED"), 16)) random.seed(int(os.getenv("SEED"), 16))
from prjxray import util from prjxray import util
from prjxray import verilog
from prjxray.db import Database from prjxray.db import Database
def gen_sites(): def gen_sites():
db = Database(util.get_db_root()) db = Database(util.get_db_root())
grid = db.grid() grid = db.grid()
for tile_name in sorted(grid.tiles()): for tile in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name) loc = grid.loc_of_tilename(tile)
gridinfo = grid.gridinfo_at_loc(loc) gridinfo = grid.gridinfo_at_loc(loc)
if gridinfo.tile_type in ['DSP_L', 'DSP_R']: if gridinfo.tile_type in ['DSP_L', 'DSP_R']:
for site in sorted(gridinfo.sites.keys()): for site in sorted(gridinfo.sites.keys()):
if gridinfo.sites[site] == 'DSP48E1': if gridinfo.sites[site] == 'DSP48E1':
yield tile_name, site yield tile, site
def write_params(lines): def fuzz(*args):
pinstr = 'tile,site,mask,pattern\n' if len(args) == 1 and isinstance(args[0], int):
for tile, site, mask, pattern in lines: # Argument indicates that we should generate a random integer with
pinstr += '%s,%s,%s,%s\n' % (tile, site, mask, pattern) # args[0] number of bits.
return random.getrandbits(args[0])
open('params.csv', 'w').write(pinstr) else:
# Otherwise make a random choice
return random.choice(*args)
def run(): def run():
print(''' verilog.top_harness(48, 48)
module top();
''')
lines = [] print('module roi(input clk, input [47:0] din, output [47:0] dout);')
data = {}
data['instances'] = []
sites = list(gen_sites()) 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( for i, (tile, site) in enumerate(sites):
''' synthesis = '(* KEEP, DONT_TOUCH, LOC = "%s" *)' % (site)
(* KEEP, DONT_TOUCH, LOC = "{0}" *) module = 'DSP48E1'
DSP48E1 #( instance = 'INST_%s' % (site)
.MASK(48'h{1:x}), ports = {}
.PATTERN(48'h{2:x}) params = {}
) dsp_{0} (
); ports['A'] = '{30{1\'b1}}'
'''.format(site_name, mask, pattern)) 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") print("endmodule")
write_params(lines)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,5 +1,6 @@
import sys import sys
import random import random
import re
def top_harness(DIN_N, DOUT_N, f=sys.stdout): def top_harness(DIN_N, DOUT_N, f=sys.stdout):
@ -65,6 +66,37 @@ def unquote(s):
return s[1:-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): def parsei(s):
if s == "1'b0": if s == "1'b0":
return 0 return 0