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
__pycache__
*.pyc
*.swp

View File

@ -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()

View File

@ -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

View File

@ -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__':

View File

@ -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