FUZZER - DSP - Refactor

Refactor the DSP Python scripts to be easier to manage.  Use JSON
instead of CSV.

Signed-off-by: Jake Mercer <jake.mercer@civica.co.uk>
This commit is contained in:
Jake Mercer 2019-10-27 12:19:23 +00:00
parent 596bb27e3b
commit e0fb0c0cb1
3 changed files with 171 additions and 249 deletions

View File

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

View File

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

View File

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