mirror of https://github.com/openXC7/prjxray.git
timfuz: pep8 reformat
Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
parent
c104e70724
commit
12978f8051
|
|
@ -6,6 +6,7 @@ Copyright 2010 John McMaster
|
|||
|
||||
import time
|
||||
|
||||
|
||||
def time_str(delta):
|
||||
fraction = delta % 1
|
||||
delta -= fraction
|
||||
|
|
@ -17,11 +18,12 @@ def time_str(delta):
|
|||
hours = delta
|
||||
return '%02d:%02d:%02d.%04d' % (hours, minutes, seconds, fraction * 10000)
|
||||
|
||||
|
||||
class Benchmark:
|
||||
start_time = None
|
||||
end_time = None
|
||||
|
||||
def __init__(self, max_items = None):
|
||||
|
||||
def __init__(self, max_items=None):
|
||||
# For the lazy
|
||||
self.start_time = time.time()
|
||||
self.end_time = None
|
||||
|
|
@ -35,19 +37,19 @@ class Benchmark:
|
|||
|
||||
def stop(self):
|
||||
self.end_time = time.time()
|
||||
|
||||
def advance(self, n = 1):
|
||||
|
||||
def advance(self, n=1):
|
||||
self.cur_items += n
|
||||
|
||||
def set_cur_items(self, n):
|
||||
self.cur_items = n
|
||||
|
||||
def delta_s(self):
|
||||
|
||||
def delta_s(self):
|
||||
if self.end_time:
|
||||
return self.end_time - self.start_time
|
||||
else:
|
||||
return time.time() - self.start_time
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.end_time:
|
||||
return time_str(self.end_time - self.start_time)
|
||||
|
|
@ -65,7 +67,7 @@ class Benchmark:
|
|||
eta_str = time_str(remaining)
|
||||
else:
|
||||
eta_str = "indeterminate"
|
||||
return '%d / %d, ETA: %s @ %s' % (self.cur_items, self.max_items, eta_str, rate_s)
|
||||
return '%d / %d, ETA: %s @ %s' % (
|
||||
self.cur_items, self.max_items, eta_str, rate_s)
|
||||
else:
|
||||
return time_str(time.time() - self.start_time)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import math
|
|||
from collections import OrderedDict
|
||||
from fractions import Fraction
|
||||
|
||||
|
||||
def Adi2matrix_random(A_ubd, b_ub, names):
|
||||
# random assignment
|
||||
# was making some empty rows
|
||||
|
|
@ -24,6 +25,7 @@ def Adi2matrix_random(A_ubd, b_ub, names):
|
|||
b_ret[dst_rowi] += b
|
||||
return A_ret, b_ret
|
||||
|
||||
|
||||
def Ads2matrix_linear(Ads, b):
|
||||
names, Adi = A_ds2di(Ads)
|
||||
cols = len(names)
|
||||
|
|
@ -41,16 +43,19 @@ def Ads2matrix_linear(Ads, b):
|
|||
dst_rowi = (dst_rowi + 1) % rows_out
|
||||
return A_ret, b_ret
|
||||
|
||||
|
||||
def pmatrix(Anp, s):
|
||||
import sympy
|
||||
msym = sympy.Matrix(Anp)
|
||||
print(s)
|
||||
sympy.pprint(msym)
|
||||
|
||||
|
||||
def pds(Ads, s):
|
||||
names, Anp = A_ds2np(Ads)
|
||||
pmatrix(Anp, s)
|
||||
print('Names: %s' % (names,))
|
||||
print('Names: %s' % (names, ))
|
||||
|
||||
|
||||
def run(fns_in, sub_json=None, verbose=False):
|
||||
# arbitrary...data is thrown away
|
||||
|
|
@ -76,7 +81,6 @@ def run(fns_in, sub_json=None, verbose=False):
|
|||
# A_ub2, b_ub2 = Adi2matrix_random(A_ubd, b, names)
|
||||
Amat, _bmat = Ads2matrix_linear(Ads, b)
|
||||
#pmatrix(Amat, 'Matrix')
|
||||
|
||||
'''
|
||||
The matrix must be fully ranked to even be considered reasonable
|
||||
Even then, floating point error *possibly* could make it fully ranked, although probably not since we have whole numbers
|
||||
|
|
@ -96,22 +100,19 @@ def run(fns_in, sub_json=None, verbose=False):
|
|||
else:
|
||||
print('slogdet :) : %s, %s' % (sign, logdet))
|
||||
if rank != len(names):
|
||||
raise Exception("Matrix not fully ranked w/ %u / %u" % (rank, len(names)))
|
||||
raise Exception(
|
||||
"Matrix not fully ranked w/ %u / %u" % (rank, len(names)))
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Check sub.json solution feasibility'
|
||||
)
|
||||
description='Check sub.json solution feasibility')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--sub-json', help='')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='*',
|
||||
help='timing3.csv input files')
|
||||
parser.add_argument('fns_in', nargs='*', help='timing3.csv input files')
|
||||
args = parser.parse_args()
|
||||
# Store options in dict to ease passing through functions
|
||||
bench = Benchmark()
|
||||
|
|
@ -125,10 +126,10 @@ def main():
|
|||
sub_json = load_sub(args.sub_json)
|
||||
|
||||
try:
|
||||
run(sub_json=sub_json,
|
||||
fns_in=fns_in, verbose=args.verbose)
|
||||
run(sub_json=sub_json, fns_in=fns_in, verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
from timfuz import Benchmark, simplify_rows, loadc_Ads_b
|
||||
import glob
|
||||
|
||||
|
||||
def run(fout, fns_in, corner, verbose=0):
|
||||
Ads, b = loadc_Ads_b(fns_in, corner, ico=True)
|
||||
Ads, b = simplify_rows(Ads, b, corner=corner)
|
||||
|
|
@ -18,22 +19,19 @@ def run(fout, fns_in, corner, verbose=0):
|
|||
items.append('%u %s' % (v, k))
|
||||
fout.write(','.join(items) + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Create a .csv with a single process corner'
|
||||
)
|
||||
description='Create a .csv with a single process corner')
|
||||
|
||||
parser.add_argument('--verbose', type=int, help='')
|
||||
parser.add_argument('--auto-name', action='store_true', help='timing3.csv => timing3c.csv')
|
||||
parser.add_argument(
|
||||
'--auto-name', action='store_true', help='timing3.csv => timing3c.csv')
|
||||
parser.add_argument('--out', default=None, help='Output csv')
|
||||
parser.add_argument('--corner', help='Output csv')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='*',
|
||||
help='timing3.csv input files')
|
||||
parser.add_argument('fns_in', nargs='*', help='timing3.csv input files')
|
||||
args = parser.parse_args()
|
||||
bench = Benchmark()
|
||||
|
||||
|
|
@ -53,8 +51,8 @@ def main():
|
|||
if not fns_in:
|
||||
fns_in = glob.glob('specimen_*/timing3.csv')
|
||||
|
||||
run(fout=fout,
|
||||
fns_in=fns_in, corner=args.corner, verbose=args.verbose)
|
||||
run(fout=fout, fns_in=fns_in, corner=args.corner, verbose=args.verbose)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from timfuz import Benchmark, loadc_Ads_bs, index_names, load_sub, run_sub_json, instances
|
||||
|
||||
|
||||
def gen_group(fnin, sub_json, strict=False, verbose=False):
|
||||
print('Loading data')
|
||||
Ads, bs = loadc_Ads_bs([fnin], ico=True)
|
||||
|
|
@ -17,6 +18,7 @@ def gen_group(fnin, sub_json, strict=False, verbose=False):
|
|||
for row_ds, row_bs in zip(Ads, bs):
|
||||
yield row_ds, row_bs
|
||||
|
||||
|
||||
def run(fns_in, fnout, sub_json, strict=False, verbose=False):
|
||||
with open(fnout, 'w') as fout:
|
||||
fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n')
|
||||
|
|
@ -28,23 +30,21 @@ def run(fns_in, fnout, sub_json, strict=False, verbose=False):
|
|||
items.append('%u %s' % (v, k))
|
||||
fout.write(','.join(items) + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Solve timing solution'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Solve timing solution')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--strict', action='store_true', help='')
|
||||
parser.add_argument('--sub-csv', help='')
|
||||
parser.add_argument('--sub-json', required=True, help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--out', help='Output sub.json substitution result')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='*',
|
||||
help='timing3.txt input files')
|
||||
'--sub-json',
|
||||
required=True,
|
||||
help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--out', help='Output sub.json substitution result')
|
||||
parser.add_argument('fns_in', nargs='*', help='timing3.txt input files')
|
||||
args = parser.parse_args()
|
||||
# Store options in dict to ease passing through functions
|
||||
bench = Benchmark()
|
||||
|
|
@ -52,9 +52,15 @@ def main():
|
|||
sub_json = load_sub(args.sub_json)
|
||||
|
||||
try:
|
||||
run(args.fns_in, args.out, sub_json=sub_json, strict=args.strict, verbose=args.verbose)
|
||||
run(
|
||||
args.fns_in,
|
||||
args.out,
|
||||
sub_json=sub_json,
|
||||
strict=args.strict,
|
||||
verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import datetime
|
|||
import os
|
||||
import time
|
||||
|
||||
|
||||
def gen_flat(fnin, sub_json, corner=None):
|
||||
Ads, bs = loadc_Ads_bs([fnin], ico=True)
|
||||
bounds = Ads2bounds(Ads, bs)
|
||||
|
|
@ -50,6 +51,7 @@ def gen_flat(fnin, sub_json, corner=None):
|
|||
for zero in zeros - violations:
|
||||
yield zero, zero_row
|
||||
|
||||
|
||||
def run(fnin, fnout, sub_json, corner=None, sort=False, verbose=False):
|
||||
if sort:
|
||||
sortf = sorted
|
||||
|
|
@ -65,18 +67,19 @@ def run(fnin, fnout, sub_json, corner=None, sort=False, verbose=False):
|
|||
items.append('%u %s' % (1, name))
|
||||
fout.write(','.join(items) + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Solve timing solution'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Solve timing solution')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--sort', action='store_true', help='')
|
||||
parser.add_argument('--sub-csv', help='')
|
||||
parser.add_argument('--sub-json', required=True, help='Group substitutions to make fully ranked')
|
||||
parser.add_argument(
|
||||
'--sub-json',
|
||||
required=True,
|
||||
help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--corner', default=None, help='')
|
||||
parser.add_argument('fnin', default=None, help='input timing delay .csv')
|
||||
parser.add_argument('fnout', default=None, help='output timing delay .csv')
|
||||
|
|
@ -87,9 +90,16 @@ def main():
|
|||
sub_json = load_sub(args.sub_json)
|
||||
|
||||
try:
|
||||
run(args.fnin, args.fnout, sub_json=sub_json, sort=args.sort, verbose=args.verbose, corner=args.corner)
|
||||
run(
|
||||
args.fnin,
|
||||
args.fnout,
|
||||
sub_json=sub_json,
|
||||
sort=args.sort,
|
||||
verbose=args.verbose,
|
||||
corner=args.corner)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Verifies that node timing info is unique
|
|||
|
||||
import re
|
||||
|
||||
|
||||
def gen_nodes(fin):
|
||||
for l in fin:
|
||||
lj = {}
|
||||
|
|
@ -22,8 +23,9 @@ def gen_nodes(fin):
|
|||
if name in ('COST_CODE', 'SPEED_CLASS'):
|
||||
value = int(value)
|
||||
lj[name] = value
|
||||
|
||||
tile_type, xy, wname = re.match(r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups()
|
||||
|
||||
tile_type, xy, wname = re.match(
|
||||
r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups()
|
||||
lj['tile_type'] = tile_type
|
||||
lj['xy'] = xy
|
||||
lj['wname'] = wname
|
||||
|
|
@ -32,10 +34,12 @@ def gen_nodes(fin):
|
|||
|
||||
yield lj
|
||||
|
||||
|
||||
def run(node_fin, verbose=0):
|
||||
refnodes = {}
|
||||
nodei = 0
|
||||
for nodei, anode in enumerate(gen_nodes(node_fin)):
|
||||
|
||||
def getk(anode):
|
||||
return anode['wname']
|
||||
#return (anode['tile_type'], anode['wname'])
|
||||
|
|
@ -52,22 +56,28 @@ def run(node_fin, verbose=0):
|
|||
# Verify equivilence
|
||||
for k in (
|
||||
'SPEED_CLASS',
|
||||
|
||||
'COST_CODE', 'COST_CODE_NAME',
|
||||
'IS_BAD', 'IS_COMPLETE', 'IS_GND', 'IS_VCC',
|
||||
):
|
||||
'COST_CODE',
|
||||
'COST_CODE_NAME',
|
||||
'IS_BAD',
|
||||
'IS_COMPLETE',
|
||||
'IS_GND',
|
||||
'IS_VCC',
|
||||
):
|
||||
if k in refnode and k in anode:
|
||||
|
||||
def fail():
|
||||
print 'Mismatch on %s' % k
|
||||
print refnode[k], anode[k]
|
||||
print refnode['l']
|
||||
print anode['l']
|
||||
#assert 0
|
||||
|
||||
if k == 'SPEED_CLASS':
|
||||
# Parameters known to effect SPEED_CLASS
|
||||
# Verify at least one parameter is different
|
||||
if refnode[k] != anode[k]:
|
||||
for k2 in ('IS_PIN', 'IS_INPUT_PIN', 'IS_OUTPUT_PIN', 'PIN_WIRE', 'NUM_WIRES'):
|
||||
for k2 in ('IS_PIN', 'IS_INPUT_PIN', 'IS_OUTPUT_PIN',
|
||||
'PIN_WIRE', 'NUM_WIRES'):
|
||||
if refnode[k2] != anode[k2]:
|
||||
break
|
||||
else:
|
||||
|
|
@ -81,19 +91,14 @@ def run(node_fin, verbose=0):
|
|||
elif k in refnode or k in anode:
|
||||
assert 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Timing fuzzer'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Timing fuzzer')
|
||||
|
||||
parser.add_argument('--verbose', type=int, help='')
|
||||
parser.add_argument(
|
||||
'node_fn_in',
|
||||
default='/dev/stdin',
|
||||
nargs='?',
|
||||
help='Input file')
|
||||
'node_fn_in', default='/dev/stdin', nargs='?', help='Input file')
|
||||
args = parser.parse_args()
|
||||
run(open(args.node_fn_in, 'r'), verbose=args.verbose)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
'''
|
||||
Triaging tool to help understand where we need more timing coverage
|
||||
Finds correlated variables to help make better test cases
|
||||
|
|
@ -16,6 +15,7 @@ from fractions import Fraction
|
|||
import random
|
||||
from sympy import Rational
|
||||
|
||||
|
||||
def intr(r):
|
||||
DELTA = 0.0001
|
||||
|
||||
|
|
@ -25,24 +25,30 @@ def intr(r):
|
|||
assert abs(xi - x) < DELTA
|
||||
r[i] = xi
|
||||
|
||||
|
||||
def fracr(r):
|
||||
intr(r)
|
||||
return [Fraction(x) for x in r]
|
||||
|
||||
|
||||
def fracm(m):
|
||||
return [fracr(r) for r in m]
|
||||
|
||||
|
||||
def symratr(r):
|
||||
intr(r)
|
||||
return [Rational(x) for x in r]
|
||||
|
||||
|
||||
def symratm(m):
|
||||
return [symratr(r) for r in m]
|
||||
|
||||
|
||||
def intm(m):
|
||||
[intr(r) for r in m]
|
||||
return m
|
||||
|
||||
|
||||
def create_matrix(rows, cols):
|
||||
ret = np.zeros((rows, cols))
|
||||
for rowi in range(rows):
|
||||
|
|
@ -50,6 +56,7 @@ def create_matrix(rows, cols):
|
|||
ret[rowi][coli] = random.randint(1, 10)
|
||||
return ret
|
||||
|
||||
|
||||
def create_matrix_sparse(rows, cols):
|
||||
ret = np.zeros((rows, cols))
|
||||
for rowi in range(rows):
|
||||
|
|
@ -58,7 +65,14 @@ def create_matrix_sparse(rows, cols):
|
|||
ret[rowi][coli] = random.randint(1, 10)
|
||||
return ret
|
||||
|
||||
def run(rows=35, cols=200, verbose=False, encoding='np', sparse=False, normalize_last=True):
|
||||
|
||||
def run(
|
||||
rows=35,
|
||||
cols=200,
|
||||
verbose=False,
|
||||
encoding='np',
|
||||
sparse=False,
|
||||
normalize_last=True):
|
||||
random.seed(0)
|
||||
if sparse:
|
||||
mnp = create_matrix_sparse(rows, cols)
|
||||
|
|
@ -85,7 +99,9 @@ def run(rows=35, cols=200, verbose=False, encoding='np', sparse=False, normalize
|
|||
print('Matrix')
|
||||
sympy.pprint(msym)
|
||||
|
||||
print('%s matrix, %u rows x %u cols, sparse: %s, normlast: %s' % (encoding, len(mnp), len(mnp[0]), sparse, normalize_last))
|
||||
print(
|
||||
'%s matrix, %u rows x %u cols, sparse: %s, normlast: %s' %
|
||||
(encoding, len(mnp), len(mnp[0]), sparse, normalize_last))
|
||||
bench = Benchmark()
|
||||
try:
|
||||
rref, pivots = msym.rref(normalize_last=normalize_last)
|
||||
|
|
@ -99,13 +115,11 @@ def run(rows=35, cols=200, verbose=False, encoding='np', sparse=False, normalize
|
|||
print('rref')
|
||||
sympy.pprint(rref)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Timing fuzzer'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Timing fuzzer')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--sparse', action='store_true', help='')
|
||||
|
|
@ -115,7 +129,14 @@ def main():
|
|||
parser.add_argument('--encoding', default='np', help='')
|
||||
args = parser.parse_args()
|
||||
|
||||
run(encoding=args.encoding, rows=args.rows, cols=args.cols, sparse=args.sparse, normalize_last=bool(args.normalize_last), verbose=args.verbose)
|
||||
run(
|
||||
encoding=args.encoding,
|
||||
rows=args.rows,
|
||||
cols=args.cols,
|
||||
sparse=args.sparse,
|
||||
normalize_last=bool(args.normalize_last),
|
||||
verbose=args.verbose)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Verifies that node timing info is unique
|
|||
|
||||
import re
|
||||
|
||||
|
||||
def gen_wires(fin):
|
||||
for l in fin:
|
||||
lj = {}
|
||||
|
|
@ -12,7 +13,8 @@ def gen_wires(fin):
|
|||
name, value = kvs.split(':')
|
||||
lj[name] = value
|
||||
|
||||
tile_type, xy, wname = re.match(r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups()
|
||||
tile_type, xy, wname = re.match(
|
||||
r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups()
|
||||
lj['tile_type'] = tile_type
|
||||
lj['xy'] = xy
|
||||
lj['wname'] = wname
|
||||
|
|
@ -21,10 +23,12 @@ def gen_wires(fin):
|
|||
|
||||
yield lj
|
||||
|
||||
|
||||
def run(node_fin, verbose=0):
|
||||
refnodes = {}
|
||||
nodei = 0
|
||||
for nodei, anode in enumerate(gen_wires(node_fin)):
|
||||
|
||||
def getk(anode):
|
||||
return anode['wname']
|
||||
return (anode['tile_type'], anode['wname'])
|
||||
|
|
@ -39,29 +43,29 @@ def run(node_fin, verbose=0):
|
|||
refnodes[getk(anode)] = anode
|
||||
continue
|
||||
k_invariant = (
|
||||
'CAN_INVERT',
|
||||
'IS_BUFFERED_2_0',
|
||||
'IS_BUFFERED_2_1',
|
||||
'IS_DIRECTIONAL',
|
||||
'IS_EXCLUDED_PIP',
|
||||
'IS_FIXED_INVERSION',
|
||||
'IS_INVERTED',
|
||||
'IS_PSEUDO',
|
||||
'IS_SITE_PIP',
|
||||
'IS_TEST_PIP',
|
||||
)
|
||||
k_varies = (
|
||||
'TILE',
|
||||
)
|
||||
'CAN_INVERT',
|
||||
'IS_BUFFERED_2_0',
|
||||
'IS_BUFFERED_2_1',
|
||||
'IS_DIRECTIONAL',
|
||||
'IS_EXCLUDED_PIP',
|
||||
'IS_FIXED_INVERSION',
|
||||
'IS_INVERTED',
|
||||
'IS_PSEUDO',
|
||||
'IS_SITE_PIP',
|
||||
'IS_TEST_PIP',
|
||||
)
|
||||
k_varies = ('TILE', )
|
||||
# Verify equivilence
|
||||
for k in k_invariant:
|
||||
if k in refnode and k in anode:
|
||||
|
||||
def fail():
|
||||
print 'Mismatch on %s' % k
|
||||
print refnode[k], anode[k]
|
||||
print refnode['l']
|
||||
print anode['l']
|
||||
#assert 0
|
||||
|
||||
if refnode[k] != anode[k]:
|
||||
print
|
||||
fail()
|
||||
|
|
@ -71,19 +75,14 @@ def run(node_fin, verbose=0):
|
|||
elif k not in k_varies:
|
||||
assert 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Timing fuzzer'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Timing fuzzer')
|
||||
|
||||
parser.add_argument('--verbose', type=int, help='')
|
||||
parser.add_argument(
|
||||
'node_fn_in',
|
||||
default='/dev/stdin',
|
||||
nargs='?',
|
||||
help='Input file')
|
||||
'node_fn_in', default='/dev/stdin', nargs='?', help='Input file')
|
||||
args = parser.parse_args()
|
||||
run(open(args.node_fn_in, 'r'), verbose=args.verbose)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ parser = argparse.ArgumentParser(description='')
|
|||
parser.add_argument('--sdx', default='8', help='')
|
||||
parser.add_argument('--sdy', default='4', help='')
|
||||
args = parser.parse_args()
|
||||
|
||||
'''
|
||||
Generate in pairs
|
||||
Fill up switchbox quad for now
|
||||
|
|
@ -26,15 +25,16 @@ nin = 6 * nlut
|
|||
nout = nlut
|
||||
|
||||
print('//placelut simple')
|
||||
print('//SBASE: %s' % (SBASE,))
|
||||
print('//SDX: %s' % (SDX,))
|
||||
print('//SDY: %s' % (SDX,))
|
||||
print('//nlut: %s' % (nlut,))
|
||||
print('''\
|
||||
print('//SBASE: %s' % (SBASE, ))
|
||||
print('//SDX: %s' % (SDX, ))
|
||||
print('//SDY: %s' % (SDX, ))
|
||||
print('//nlut: %s' % (nlut, ))
|
||||
print(
|
||||
'''\
|
||||
module roi (
|
||||
input wire clk,
|
||||
input wire [%u:0] ins,
|
||||
output wire [%u:0] outs);''') % (nin - 1, nout -1)
|
||||
output wire [%u:0] outs);''') % (nin - 1, nout - 1)
|
||||
|
||||
ini = 0
|
||||
outi = 0
|
||||
|
|
@ -43,7 +43,8 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
loc = "SLICE_X%uY%u" % (lutx, luty)
|
||||
for belc in 'ABCD':
|
||||
bel = '%c6LUT' % belc
|
||||
print('''\
|
||||
print(
|
||||
'''\
|
||||
|
||||
(* KEEP, DONT_TOUCH, LOC="%s", BEL="%s" *)
|
||||
LUT6 #(
|
||||
|
|
@ -54,12 +55,13 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
.I%u(ins[%u]),''' % (i, ini))
|
||||
ini += 1
|
||||
print('''\
|
||||
.O(outs[%u]));''') % (outi,)
|
||||
.O(outs[%u]));''') % (outi, )
|
||||
outi += 1
|
||||
assert nin == ini
|
||||
assert nout == outi
|
||||
|
||||
print('''
|
||||
print(
|
||||
'''
|
||||
endmodule
|
||||
|
||||
module top(input wire clk, input wire stb, input wire di, output wire do);
|
||||
|
|
@ -88,4 +90,3 @@ module top(input wire clk, input wire stb, input wire di, output wire do);
|
|||
.outs(dout)
|
||||
);
|
||||
endmodule''') % (nin, nout)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Note: vivado will (by default) fail bitgen DRC on LUT feedback loops
|
||||
Looks like can probably be disabled, but we actually don't need a bitstream for timing analysis
|
||||
|
|
@ -14,7 +13,6 @@ parser = argparse.ArgumentParser(description='')
|
|||
parser.add_argument('--sdx', default='8', help='')
|
||||
parser.add_argument('--sdy', default='4', help='')
|
||||
args = parser.parse_args()
|
||||
|
||||
'''
|
||||
Generate in pairs
|
||||
Fill up switchbox quad for now
|
||||
|
|
@ -34,15 +32,16 @@ nin = 6 * nlut
|
|||
nout = nlut
|
||||
|
||||
print('//placelut w/ feedback')
|
||||
print('//SBASE: %s' % (SBASE,))
|
||||
print('//SDX: %s' % (SDX,))
|
||||
print('//SDY: %s' % (SDX,))
|
||||
print('//nlut: %s' % (nlut,))
|
||||
print('''\
|
||||
print('//SBASE: %s' % (SBASE, ))
|
||||
print('//SDX: %s' % (SDX, ))
|
||||
print('//SDY: %s' % (SDX, ))
|
||||
print('//nlut: %s' % (nlut, ))
|
||||
print(
|
||||
'''\
|
||||
module roi (
|
||||
input wire clk,
|
||||
input wire [%u:0] ins,
|
||||
output wire [%u:0] outs);''') % (nin - 1, nout -1)
|
||||
output wire [%u:0] outs);''') % (nin - 1, nout - 1)
|
||||
|
||||
ini = 0
|
||||
outi = 0
|
||||
|
|
@ -51,7 +50,8 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
loc = "SLICE_X%uY%u" % (lutx, luty)
|
||||
for belc in 'ABCD':
|
||||
bel = '%c6LUT' % belc
|
||||
print('''\
|
||||
print(
|
||||
'''\
|
||||
|
||||
(* KEEP, DONT_TOUCH, LOC="%s", BEL="%s" *)
|
||||
LUT6 #(
|
||||
|
|
@ -66,12 +66,13 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
print('''\
|
||||
.I%u(%s),''' % (i, wfrom))
|
||||
print('''\
|
||||
.O(outs[%u]));''') % (outi,)
|
||||
.O(outs[%u]));''') % (outi, )
|
||||
outi += 1
|
||||
#assert nin == ini
|
||||
assert nout == outi
|
||||
|
||||
print('''
|
||||
print(
|
||||
'''
|
||||
endmodule
|
||||
|
||||
module top(input wire clk, input wire stb, input wire di, output wire do);
|
||||
|
|
@ -100,4 +101,3 @@ module top(input wire clk, input wire stb, input wire di, output wire do);
|
|||
.outs(dout)
|
||||
);
|
||||
endmodule''') % (nin, nout)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Note: vivado will (by default) fail bitgen DRC on LUT feedback loops
|
||||
Looks like can probably be disabled, but we actually don't need a bitstream for timing analysis
|
||||
|
|
@ -18,7 +17,6 @@ parser = argparse.ArgumentParser(description='')
|
|||
parser.add_argument('--sdx', default='8', help='')
|
||||
parser.add_argument('--sdy', default='4', help='')
|
||||
args = parser.parse_args()
|
||||
|
||||
'''
|
||||
Generate in pairs
|
||||
Fill up switchbox quad for now
|
||||
|
|
@ -38,15 +36,16 @@ nin = 6 * nlut
|
|||
nout = nlut
|
||||
|
||||
print('//placelut w/ FF + feedback')
|
||||
print('//SBASE: %s' % (SBASE,))
|
||||
print('//SDX: %s' % (SDX,))
|
||||
print('//SDY: %s' % (SDX,))
|
||||
print('//nlut: %s' % (nlut,))
|
||||
print('''\
|
||||
print('//SBASE: %s' % (SBASE, ))
|
||||
print('//SDX: %s' % (SDX, ))
|
||||
print('//SDY: %s' % (SDX, ))
|
||||
print('//nlut: %s' % (nlut, ))
|
||||
print(
|
||||
'''\
|
||||
module roi (
|
||||
input wire clk,
|
||||
input wire [%u:0] ins,
|
||||
output wire [%u:0] outs);''') % (nin - 1, nout -1)
|
||||
output wire [%u:0] outs);''') % (nin - 1, nout - 1)
|
||||
|
||||
ini = 0
|
||||
outi = 0
|
||||
|
|
@ -56,7 +55,8 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
for belc in 'ABCD':
|
||||
bel = '%c6LUT' % belc
|
||||
name = 'lut_x%uy%u_%c' % (lutx, luty, belc)
|
||||
print('''\
|
||||
print(
|
||||
'''\
|
||||
|
||||
(* KEEP, DONT_TOUCH, LOC="%s", BEL="%s" *)
|
||||
LUT6 #(
|
||||
|
|
@ -75,14 +75,15 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
.I%u(%s),''' % (i, wfrom))
|
||||
out_w = name + '_o'
|
||||
print('''\
|
||||
.O(%s));''') % (out_w,)
|
||||
.O(%s));''') % (out_w, )
|
||||
|
||||
outs_w = "outs[%u]" % outi
|
||||
if random.randint(0, 9) < 5:
|
||||
print(' assign %s = %s;' % (outs_w, out_w))
|
||||
else:
|
||||
out_r = name + '_or'
|
||||
print('''\
|
||||
print(
|
||||
'''\
|
||||
reg %s;
|
||||
assign %s = %s;
|
||||
always @(posedge clk) begin
|
||||
|
|
@ -94,7 +95,8 @@ for lutx in xrange(SBASE[0], SBASE[0] + SDX):
|
|||
#assert nin == ini
|
||||
assert nout == outi
|
||||
|
||||
print('''
|
||||
print(
|
||||
'''
|
||||
endmodule
|
||||
|
||||
module top(input wire clk, input wire stb, input wire di, output wire do);
|
||||
|
|
@ -123,4 +125,3 @@ module top(input wire clk, input wire stb, input wire di, output wire do);
|
|||
.outs(dout)
|
||||
);
|
||||
endmodule''') % (nin, nout)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
'''
|
||||
Triaging tool to help understand where we need more timing coverage
|
||||
Finds correlated variables to help make better test cases
|
||||
|
|
@ -14,6 +13,7 @@ import sympy
|
|||
from collections import OrderedDict
|
||||
from fractions import Fraction
|
||||
|
||||
|
||||
def fracr(r):
|
||||
DELTA = 0.0001
|
||||
|
||||
|
|
@ -24,12 +24,15 @@ def fracr(r):
|
|||
r[i] = xi
|
||||
return [Fraction(x) for x in r]
|
||||
|
||||
|
||||
def fracm(m):
|
||||
return [fracr(r) for r in m]
|
||||
|
||||
|
||||
def fracr_quick(r):
|
||||
return [Fraction(numerator=int(x), denominator=1) for x in r]
|
||||
|
||||
|
||||
# the way I'm doing thing they should all be even integers
|
||||
# hmm this was only slightly faster
|
||||
def fracm_quick(m):
|
||||
|
|
@ -37,6 +40,7 @@ def fracm_quick(m):
|
|||
print('fracm_quick type: %s' % t)
|
||||
return [fracr_quick(r) for r in m]
|
||||
|
||||
|
||||
class State(object):
|
||||
def __init__(self, Ads, drop_names=[]):
|
||||
self.Ads = Ads
|
||||
|
|
@ -57,9 +61,11 @@ class State(object):
|
|||
print("Stats")
|
||||
print(" Substitutions: %u" % len(self.subs))
|
||||
if self.subs:
|
||||
print(" Largest: %u" % max([len(x) for x in self.subs.values()]))
|
||||
print(
|
||||
" Largest: %u" % max([len(x) for x in self.subs.values()]))
|
||||
print(" Rows: %u" % len(self.Ads))
|
||||
print(" Cols (in): %u" % (len(self.base_names) + len(self.drop_names)))
|
||||
print(
|
||||
" Cols (in): %u" % (len(self.base_names) + len(self.drop_names)))
|
||||
print(" Cols (preprocessed): %u" % len(self.base_names))
|
||||
print(" Drop names: %u" % len(self.drop_names))
|
||||
print(" Cols (out): %u" % len(self.names))
|
||||
|
|
@ -70,10 +76,11 @@ class State(object):
|
|||
def load(fn_ins, simplify=False, corner=None):
|
||||
Ads, b = loadc_Ads_b(fn_ins, corner=corner, ico=True)
|
||||
if simplify:
|
||||
print('Simplifying corner %s' % (corner,))
|
||||
print('Simplifying corner %s' % (corner, ))
|
||||
Ads, b = simplify_rows(Ads, b, remove_zd=False, corner=corner)
|
||||
return State(Ads)
|
||||
|
||||
|
||||
def write_state(state, fout):
|
||||
j = {
|
||||
'names': dict([(x, None) for x in state.names]),
|
||||
|
|
@ -84,6 +91,7 @@ def write_state(state, fout):
|
|||
}
|
||||
json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
|
||||
def Anp2matrix(Anp):
|
||||
'''
|
||||
Original idea was to make into a square matrix
|
||||
|
|
@ -99,6 +107,7 @@ def Anp2matrix(Anp):
|
|||
dst_rowi = (dst_rowi + 1) % ncols
|
||||
return A_ub2
|
||||
|
||||
|
||||
def row_np2ds(rownp, names):
|
||||
ret = {}
|
||||
assert len(rownp) == len(names), (len(rownp), len(names))
|
||||
|
|
@ -108,6 +117,7 @@ def row_np2ds(rownp, names):
|
|||
ret[name] = v
|
||||
return ret
|
||||
|
||||
|
||||
def row_sym2dsf(rowsym, names):
|
||||
'''Convert a sympy row into a dictionary of keys to (numerator, denominator) tuples'''
|
||||
from sympy import fraction
|
||||
|
|
@ -121,6 +131,7 @@ def row_sym2dsf(rowsym, names):
|
|||
ret[name] = (int(num), int(den))
|
||||
return ret
|
||||
|
||||
|
||||
def state_rref(state, verbose=False):
|
||||
print('Converting rows to integer keys')
|
||||
names, Anp = A_ds2np(state.Ads)
|
||||
|
|
@ -195,6 +206,7 @@ def state_rref(state, verbose=False):
|
|||
|
||||
return state
|
||||
|
||||
|
||||
def run(fnout, fn_ins, simplify=False, corner=None, verbose=0):
|
||||
print('Loading data')
|
||||
|
||||
|
|
@ -205,24 +217,21 @@ def run(fnout, fn_ins, simplify=False, corner=None, verbose=0):
|
|||
with open(fnout, 'w') as fout:
|
||||
write_state(state, fout)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Timing fuzzer'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Timing fuzzer')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--simplify', action='store_true', help='')
|
||||
parser.add_argument('--corner', default="slow_max", help='')
|
||||
parser.add_argument('--speed-json', default='build_speed/speed.json',
|
||||
parser.add_argument(
|
||||
'--speed-json',
|
||||
default='build_speed/speed.json',
|
||||
help='Provides speed index to name translation')
|
||||
parser.add_argument('--out', help='Output sub.json substitution result')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='+',
|
||||
help='timing3.txt input files')
|
||||
parser.add_argument('fns_in', nargs='+', help='timing3.txt input files')
|
||||
args = parser.parse_args()
|
||||
bench = Benchmark()
|
||||
|
||||
|
|
@ -231,10 +240,15 @@ def main():
|
|||
fns_in = glob.glob('specimen_*/timing3.csv')
|
||||
|
||||
try:
|
||||
run(fnout=args.out,
|
||||
fn_ins=args.fns_in, simplify=args.simplify, corner=args.corner, verbose=args.verbose)
|
||||
run(
|
||||
fnout=args.out,
|
||||
fn_ins=args.fns_in,
|
||||
simplify=args.simplify,
|
||||
corner=args.corner,
|
||||
verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import timfuz_solve
|
|||
import scipy.optimize as optimize
|
||||
from scipy.optimize import least_squares
|
||||
|
||||
|
||||
def mkestimate(Anp, b):
|
||||
'''
|
||||
Ballpark upper bound estimate assuming variables contribute all of the delay in their respective row
|
||||
|
|
@ -33,6 +34,7 @@ def mkestimate(Anp, b):
|
|||
x0[coli] = min(x0[coli], ub)
|
||||
return x0
|
||||
|
||||
|
||||
def save(outfn, xvals, names, corner):
|
||||
# ballpark minimum actual observed delay is around 7 (carry chain)
|
||||
# anything less than one is probably a solver artifact
|
||||
|
|
@ -45,7 +47,7 @@ def save(outfn, xvals, names, corner):
|
|||
'fast_min': math.floor,
|
||||
'slow_max': math.ceil,
|
||||
'slow_min': math.floor,
|
||||
}[corner]
|
||||
}[corner]
|
||||
|
||||
print('Writing results')
|
||||
skips = 0
|
||||
|
|
@ -69,16 +71,18 @@ def save(outfn, xvals, names, corner):
|
|||
items = [str(row_ico), acorner2csv(roundf(xval), corneri)]
|
||||
items.append('%u %s' % (1, name))
|
||||
fout.write(','.join(items) + '\n')
|
||||
print('Wrote: skip %u => %u / %u valid delays' % (skips, keeps, len(names)))
|
||||
print(
|
||||
'Wrote: skip %u => %u / %u valid delays' % (skips, keeps, len(names)))
|
||||
assert keeps, 'Failed to estimate delay'
|
||||
|
||||
def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None):
|
||||
|
||||
def run_corner(
|
||||
Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None):
|
||||
# Given timing scores for above delays (-ps)
|
||||
assert type(Anp[0]) is np.ndarray, type(Anp[0])
|
||||
assert type(b) is np.ndarray, type(b)
|
||||
|
||||
#check_feasible(Anp, b)
|
||||
|
||||
'''
|
||||
Be mindful of signs
|
||||
Have something like
|
||||
|
|
@ -97,7 +101,6 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
print('Input paths')
|
||||
print(' # timing scores: %d' % len(b))
|
||||
print(' Rows: %d' % rows)
|
||||
|
||||
'''
|
||||
You must have at least as many things to optimize as variables
|
||||
That is, the system must be plausibly constrained for it to attempt a solve
|
||||
|
|
@ -110,10 +113,11 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
tlast = [None]
|
||||
iters = [0]
|
||||
printn = [0]
|
||||
|
||||
def progress_print():
|
||||
iters[0] += 1
|
||||
if tlast[0] is None:
|
||||
tlast[0]= time.time()
|
||||
tlast[0] = time.time()
|
||||
if time.time() - tlast[0] > 1.0:
|
||||
sys.stdout.write('I:%d ' % iters[0])
|
||||
tlast[0] = time.time()
|
||||
|
|
@ -143,23 +147,22 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
if outfn:
|
||||
save(outfn, res.x, names, corner)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Solve timing solution using least squares objective function'
|
||||
)
|
||||
'Solve timing solution using least squares objective function')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--massage', action='store_true', help='')
|
||||
parser.add_argument('--sub-json', help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--corner', default="slow_max", help='')
|
||||
parser.add_argument('--out', default=None, help='output timing delay .json')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='+',
|
||||
help='timing3.csv input files')
|
||||
'--sub-json', help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--corner', default="slow_max", help='')
|
||||
parser.add_argument(
|
||||
'--out', default=None, help='output timing delay .json')
|
||||
parser.add_argument('fns_in', nargs='+', help='timing3.csv input files')
|
||||
args = parser.parse_args()
|
||||
# Store options in dict to ease passing through functions
|
||||
bench = Benchmark()
|
||||
|
|
@ -169,10 +172,17 @@ def main():
|
|||
sub_json = load_sub(args.sub_json)
|
||||
|
||||
try:
|
||||
timfuz_solve.run(run_corner=run_corner, sub_json=sub_json,
|
||||
fns_in=args.fns_in, corner=args.corner, massage=args.massage, outfn=args.out, verbose=args.verbose)
|
||||
timfuz_solve.run(
|
||||
run_corner=run_corner,
|
||||
sub_json=sub_json,
|
||||
fns_in=args.fns_in,
|
||||
corner=args.corner,
|
||||
massage=args.massage,
|
||||
outfn=args.out,
|
||||
verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import os
|
|||
import time
|
||||
import timfuz_solve
|
||||
|
||||
|
||||
def save(outfn, xvals, names, corner):
|
||||
# ballpark minimum actual observed delay is around 7 (carry chain)
|
||||
# anything less than one is probably a solver artifact
|
||||
|
|
@ -23,7 +24,7 @@ def save(outfn, xvals, names, corner):
|
|||
'fast_min': math.floor,
|
||||
'slow_max': math.ceil,
|
||||
'slow_min': math.floor,
|
||||
}[corner]
|
||||
}[corner]
|
||||
|
||||
print('Writing results')
|
||||
zeros = 0
|
||||
|
|
@ -45,9 +46,13 @@ def save(outfn, xvals, names, corner):
|
|||
items.append('%u %s' % (1, name))
|
||||
fout.write(','.join(items) + '\n')
|
||||
nonzeros = len(names) - zeros
|
||||
print('Wrote: %u / %u constrained delays, %u zeros' % (nonzeros, len(names), zeros))
|
||||
print(
|
||||
'Wrote: %u / %u constrained delays, %u zeros' %
|
||||
(nonzeros, len(names), zeros))
|
||||
|
||||
def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None):
|
||||
|
||||
def run_corner(
|
||||
Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None):
|
||||
if len(Anp) == 0:
|
||||
print('WARNING: zero equations')
|
||||
if outfn:
|
||||
|
|
@ -58,14 +63,13 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
'slow_min': False,
|
||||
'fast_max': True,
|
||||
'fast_min': False,
|
||||
}[corner]
|
||||
}[corner]
|
||||
|
||||
# Given timing scores for above delays (-ps)
|
||||
assert type(Anp[0]) is np.ndarray, type(Anp[0])
|
||||
assert type(b) is np.ndarray, type(b)
|
||||
|
||||
#check_feasible(Anp, b)
|
||||
|
||||
'''
|
||||
Be mindful of signs
|
||||
t1, t2: total delay contants
|
||||
|
|
@ -133,6 +137,7 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
tlast = [time.time()]
|
||||
iters = [0]
|
||||
printn = [0]
|
||||
|
||||
def callback(xk, **kwargs):
|
||||
iters[0] = kwargs['nit']
|
||||
if time.time() - tlast[0] > 1.0:
|
||||
|
|
@ -147,8 +152,18 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
# Now find smallest values for delay constants
|
||||
# Due to input bounds (ex: column limit), some delay elements may get eliminated entirely
|
||||
print('Running linprog w/ %d r, %d c (%d name)' % (rows, cols, len(names)))
|
||||
res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, callback=callback,
|
||||
options={"disp": True, 'maxiter': maxiter, 'bland': True, 'tol': 1e-6,})
|
||||
res = linprog(
|
||||
c,
|
||||
A_ub=A_ub,
|
||||
b_ub=b_ub,
|
||||
bounds=bounds,
|
||||
callback=callback,
|
||||
options={
|
||||
"disp": True,
|
||||
'maxiter': maxiter,
|
||||
'bland': True,
|
||||
'tol': 1e-6,
|
||||
})
|
||||
nonzeros = 0
|
||||
print('Ran %d iters' % iters[0])
|
||||
if res.success:
|
||||
|
|
@ -159,31 +174,31 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non
|
|||
if nonzero:
|
||||
nonzeros += 1
|
||||
#if nonzero and (verbose >= 1 or xi > 30):
|
||||
if nonzero and (verbose or ((nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)):
|
||||
if nonzero and (verbose or (
|
||||
(nonzeros < 100 or nonzeros % 20 == 0) and nonzeros <= plim)):
|
||||
print(' % 4u % -80s % 10.1f' % (xi, name, x))
|
||||
print('Delay on %d / %d' % (nonzeros, len(res.x)))
|
||||
|
||||
if outfn:
|
||||
save(outfn, res.x, names, corner)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Solve timing solution using linear programming inequalities'
|
||||
)
|
||||
'Solve timing solution using linear programming inequalities')
|
||||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--massage', action='store_true', help='')
|
||||
parser.add_argument('--sub-csv', help='')
|
||||
parser.add_argument('--sub-json', help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--corner', default=None, required=True, help='')
|
||||
parser.add_argument('--out', default=None, help='output timing delay .json')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='*',
|
||||
help='timing3.csv input files')
|
||||
'--sub-json', help='Group substitutions to make fully ranked')
|
||||
parser.add_argument('--corner', default=None, required=True, help='')
|
||||
parser.add_argument(
|
||||
'--out', default=None, help='output timing delay .json')
|
||||
parser.add_argument('fns_in', nargs='*', help='timing3.csv input files')
|
||||
args = parser.parse_args()
|
||||
# Store options in dict to ease passing through functions
|
||||
bench = Benchmark()
|
||||
|
|
@ -197,10 +212,18 @@ def main():
|
|||
sub_json = load_sub(args.sub_json)
|
||||
|
||||
try:
|
||||
timfuz_solve.run(run_corner=run_corner, sub_json=sub_json, sub_csv=args.sub_csv,
|
||||
fns_in=fns_in, corner=args.corner, massage=args.massage, outfn=args.out, verbose=args.verbose)
|
||||
timfuz_solve.run(
|
||||
run_corner=run_corner,
|
||||
sub_json=sub_json,
|
||||
sub_csv=args.sub_csv,
|
||||
fns_in=fns_in,
|
||||
corner=args.corner,
|
||||
massage=args.massage,
|
||||
outfn=args.out,
|
||||
verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
|
||||
|
||||
def load_speed(fin):
|
||||
speed_models = {}
|
||||
speed_types = {}
|
||||
|
|
@ -9,9 +10,9 @@ def load_speed(fin):
|
|||
for kvs in l.split():
|
||||
name, value = kvs.split(':')
|
||||
name = name.lower()
|
||||
if name in ('class',):
|
||||
if name in ('class', ):
|
||||
continue
|
||||
if name in ('speed_index',):
|
||||
if name in ('speed_index', ):
|
||||
value = int(value)
|
||||
if name == 'type':
|
||||
speed_types.setdefault(value, {})
|
||||
|
|
@ -38,6 +39,7 @@ def load_speed(fin):
|
|||
speed_models[delayk] = delay
|
||||
return speed_models, speed_types
|
||||
|
||||
|
||||
def load_cost_code(fin):
|
||||
# COST_CODE:4 COST_CODE_NAME:SLOWSINGLE
|
||||
cost_codes = {}
|
||||
|
|
@ -53,11 +55,12 @@ def load_cost_code(fin):
|
|||
'code': int(lj['cost_code']),
|
||||
# Hmm is this unique per type?
|
||||
#'speed_class': int(lj['speed_class']),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cost_codes[cost_code['name']] = cost_code
|
||||
return cost_codes
|
||||
|
||||
|
||||
def run(speed_fin, node_fin, fout, verbose=0):
|
||||
print('Loading data')
|
||||
speed_models, speed_types = load_speed(speed_fin)
|
||||
|
|
@ -67,32 +70,25 @@ def run(speed_fin, node_fin, fout, verbose=0):
|
|||
'speed_model': speed_models,
|
||||
'speed_type': speed_types,
|
||||
'cost_code': cost_codes,
|
||||
}
|
||||
}
|
||||
json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Timing fuzzer'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Timing fuzzer')
|
||||
|
||||
parser.add_argument('--verbose', type=int, help='')
|
||||
parser.add_argument(
|
||||
'speed_fn_in',
|
||||
default='/dev/stdin',
|
||||
nargs='?',
|
||||
help='Input file')
|
||||
'speed_fn_in', default='/dev/stdin', nargs='?', help='Input file')
|
||||
parser.add_argument(
|
||||
'node_fn_in',
|
||||
default='/dev/stdin',
|
||||
nargs='?',
|
||||
help='Input file')
|
||||
'node_fn_in', default='/dev/stdin', nargs='?', help='Input file')
|
||||
parser.add_argument(
|
||||
'fn_out',
|
||||
default='/dev/stdout',
|
||||
nargs='?',
|
||||
help='Output file')
|
||||
'fn_out', default='/dev/stdout', nargs='?', help='Output file')
|
||||
args = parser.parse_args()
|
||||
run(open(args.speed_fn_in, 'r'), open(args.node_fn_in, 'r'), open(args.fn_out, 'w'), verbose=args.verbose)
|
||||
run(
|
||||
open(args.speed_fn_in, 'r'),
|
||||
open(args.node_fn_in, 'r'),
|
||||
open(args.fn_out, 'w'),
|
||||
verbose=args.verbose)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import sympy
|
|||
from collections import OrderedDict
|
||||
from fractions import Fraction
|
||||
|
||||
|
||||
def mlcm(xs):
|
||||
'''
|
||||
Find the LCM between elements in a group
|
||||
|
|
@ -20,6 +21,7 @@ def mlcm(xs):
|
|||
l = int(max(lthis, l))
|
||||
return ret
|
||||
|
||||
|
||||
def write_state(state, fout):
|
||||
j = {
|
||||
'names': dict([(x, None) for x in state.names]),
|
||||
|
|
@ -30,6 +32,7 @@ def write_state(state, fout):
|
|||
}
|
||||
json.dump(j, fout, sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
|
||||
def gen_rows(fn_ins):
|
||||
for fn_in in fn_ins:
|
||||
try:
|
||||
|
|
@ -52,7 +55,7 @@ def gen_rows(fn_ins):
|
|||
n = 1
|
||||
for _var, (_num, den) in sub.items():
|
||||
n *= den
|
||||
|
||||
|
||||
for var, (num, den) in sub.items():
|
||||
num2 = n * num
|
||||
assert num2 % den == 0
|
||||
|
|
@ -62,6 +65,7 @@ def gen_rows(fn_ins):
|
|||
print("Error processing %s" % fn_in)
|
||||
raise
|
||||
|
||||
|
||||
def run(fnout, fn_ins, verbose=0):
|
||||
print('Loading data')
|
||||
|
||||
|
|
@ -76,6 +80,7 @@ def run(fnout, fn_ins, verbose=0):
|
|||
items.append('%i %s' % (v, k))
|
||||
fout.write(','.join(items) + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
|
|
@ -86,20 +91,17 @@ def main():
|
|||
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
parser.add_argument('--out', help='Output csv')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='*',
|
||||
help='sub.json input files')
|
||||
parser.add_argument('fns_in', nargs='*', help='sub.json input files')
|
||||
args = parser.parse_args()
|
||||
bench = Benchmark()
|
||||
|
||||
fns_in = args.fns_in
|
||||
|
||||
try:
|
||||
run(fnout=args.out,
|
||||
fn_ins=args.fns_in, verbose=args.verbose)
|
||||
run(fnout=args.out, fn_ins=args.fns_in, verbose=args.verbose)
|
||||
finally:
|
||||
print('Exiting after %s' % bench)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import os
|
|||
import time
|
||||
import json
|
||||
|
||||
|
||||
# corner wokraround
|
||||
def quad(x):
|
||||
return [x for _ in range(4)]
|
||||
|
||||
|
||||
def run(fnin, fnout, tile_json_fn, verbose=False):
|
||||
# modified in place
|
||||
tilej = json.load(open(tile_json_fn, 'r'))
|
||||
|
|
@ -50,18 +52,26 @@ def run(fnin, fnout, tile_json_fn, verbose=False):
|
|||
|
||||
for corner, corneri in timfuz.corner_s2i.items():
|
||||
print('Corner %s' % corner)
|
||||
print(' Pips: %u / %u solved, %u / %u covered' % (pipn_solved[corneri], pipn_net, pipn_covered[corneri], pipn_net))
|
||||
print(' Wires: %u / %u solved, %u / %u covered' % (wiren_solved[corneri], wiren_net, wiren_covered[corneri], wiren_net))
|
||||
print(
|
||||
' Pips: %u / %u solved, %u / %u covered' %
|
||||
(pipn_solved[corneri], pipn_net, pipn_covered[corneri], pipn_net))
|
||||
print(
|
||||
' Wires: %u / %u solved, %u / %u covered' % (
|
||||
wiren_solved[corneri], wiren_net, wiren_covered[corneri],
|
||||
wiren_net))
|
||||
|
||||
json.dump(
|
||||
tilej,
|
||||
open(fnout, 'w'),
|
||||
sort_keys=True,
|
||||
indent=4,
|
||||
separators=(',', ': '))
|
||||
|
||||
json.dump(tilej, open(fnout, 'w'), sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
''
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='')
|
||||
parser.add_argument('--tile-json', default='tiles.json', help='')
|
||||
parser.add_argument('fnin', default=None, help='Flattened timing csv')
|
||||
parser.add_argument('fnout', default=None, help='output tile .json')
|
||||
|
|
@ -69,5 +79,6 @@ def main():
|
|||
|
||||
run(args.fnin, args.fnout, args.tile_json, verbose=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import time
|
|||
import json
|
||||
from collections import OrderedDict
|
||||
|
||||
corner_s2i = OrderedDict([
|
||||
('fast_max', 0),
|
||||
('fast_min', 1),
|
||||
('slow_max', 2),
|
||||
('slow_min', 3),
|
||||
corner_s2i = OrderedDict(
|
||||
[
|
||||
('fast_max', 0),
|
||||
('fast_min', 1),
|
||||
('slow_max', 2),
|
||||
('slow_min', 3),
|
||||
])
|
||||
|
||||
corner2minmax = {
|
||||
|
|
@ -18,7 +19,8 @@ corner2minmax = {
|
|||
'fast_min': min,
|
||||
'slow_max': max,
|
||||
'slow_min': min,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def build_tilejo(fnins):
|
||||
'''
|
||||
|
|
@ -45,6 +47,7 @@ def build_tilejo(fnins):
|
|||
tilejo['tiles'][tilek] = tilevi
|
||||
# Otherwise combine
|
||||
else:
|
||||
|
||||
def process_type(etype):
|
||||
for pipk, pipvi in tilevi[etype].items():
|
||||
pipvo = tilevo[etype][pipk]
|
||||
|
|
@ -61,10 +64,12 @@ def build_tilejo(fnins):
|
|||
else:
|
||||
minmax = corner2minmax[cornerk]
|
||||
pipvo[corneri] = minmax(cornervi, cornervo)
|
||||
|
||||
process_type('pips')
|
||||
process_type('wires')
|
||||
return tilejo
|
||||
|
||||
|
||||
def check_corner_minmax(tilej, verbose=False):
|
||||
# Post processing pass looking for min/max inconsistencies
|
||||
# Especially an issue due to complexities around under-constrained elements
|
||||
|
|
@ -73,12 +78,13 @@ def check_corner_minmax(tilej, verbose=False):
|
|||
checks = 0
|
||||
bad = 0
|
||||
for tilev in tilej['tiles'].values():
|
||||
|
||||
def process_type(etype):
|
||||
nonlocal checks
|
||||
nonlocal bad
|
||||
|
||||
for pipk, pipv in tilev[etype].items():
|
||||
for corner in ('slow', 'fast'):
|
||||
for corner in ('slow', 'fast'):
|
||||
mini = corner_s2i[corner + '_min']
|
||||
minv = pipv[mini]
|
||||
maxi = corner_s2i[corner + '_max']
|
||||
|
|
@ -87,7 +93,9 @@ def check_corner_minmax(tilej, verbose=False):
|
|||
checks += 1
|
||||
if minv > maxv:
|
||||
if verbose:
|
||||
print('WARNING: element %s %s min/max adjusted on corner %s' % (etype, pipk, corner))
|
||||
print(
|
||||
'WARNING: element %s %s min/max adjusted on corner %s'
|
||||
% (etype, pipk, corner))
|
||||
bad += 1
|
||||
pipv[mini] = maxv
|
||||
pipv[maxi] = minv
|
||||
|
|
@ -96,28 +104,35 @@ def check_corner_minmax(tilej, verbose=False):
|
|||
process_type('wires')
|
||||
print('minmax: %u / %u bad' % (bad, checks))
|
||||
|
||||
|
||||
def check_corners_minmax(tilej, verbose=False):
|
||||
# TODO: check fast vs slow
|
||||
pass
|
||||
|
||||
|
||||
def run(fnins, fnout, verbose=False):
|
||||
tilejo = build_tilejo(fnins)
|
||||
check_corner_minmax(tilejo)
|
||||
check_corners_minmax(tilejo)
|
||||
json.dump(tilejo, open(fnout, 'w'), sort_keys=True, indent=4, separators=(',', ': '))
|
||||
json.dump(
|
||||
tilejo,
|
||||
open(fnout, 'w'),
|
||||
sort_keys=True,
|
||||
indent=4,
|
||||
separators=(',', ': '))
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Combine multiple tile corners into one .json file'
|
||||
)
|
||||
description='Combine multiple tile corners into one .json file')
|
||||
parser.add_argument('--out', required=True, help='Combined .json file')
|
||||
parser.add_argument('fnins', nargs='+', help='Input .json files')
|
||||
args = parser.parse_args()
|
||||
|
||||
run(args.fnins, args.out, verbose=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -16,27 +16,30 @@ from fractions import Fraction
|
|||
|
||||
from benchmark import Benchmark
|
||||
|
||||
NAME_ZERO = set([
|
||||
"BSW_CLK_ZERO",
|
||||
"BSW_ZERO",
|
||||
"B_ZERO",
|
||||
"C_CLK_ZERO",
|
||||
"C_DSP_ZERO",
|
||||
"C_ZERO",
|
||||
"I_ZERO",
|
||||
"O_ZERO",
|
||||
"RC_ZERO",
|
||||
"R_ZERO",
|
||||
])
|
||||
NAME_ZERO = set(
|
||||
[
|
||||
"BSW_CLK_ZERO",
|
||||
"BSW_ZERO",
|
||||
"B_ZERO",
|
||||
"C_CLK_ZERO",
|
||||
"C_DSP_ZERO",
|
||||
"C_ZERO",
|
||||
"I_ZERO",
|
||||
"O_ZERO",
|
||||
"RC_ZERO",
|
||||
"R_ZERO",
|
||||
])
|
||||
|
||||
# csv index
|
||||
corner_s2i = OrderedDict([
|
||||
('fast_max', 0),
|
||||
('fast_min', 1),
|
||||
('slow_max', 2),
|
||||
('slow_min', 3),
|
||||
corner_s2i = OrderedDict(
|
||||
[
|
||||
('fast_max', 0),
|
||||
('fast_min', 1),
|
||||
('slow_max', 2),
|
||||
('slow_min', 3),
|
||||
])
|
||||
|
||||
|
||||
# Equations are filtered out until nothing is left
|
||||
class SimplifiedToZero(Exception):
|
||||
pass
|
||||
|
|
@ -45,6 +48,7 @@ class SimplifiedToZero(Exception):
|
|||
def allow_zero_eqns():
|
||||
return os.getenv('ALLOW_ZERO_EQN', 'N') == 'Y'
|
||||
|
||||
|
||||
def print_eqns(A_ubd, b_ub, verbose=0, lim=3, label=''):
|
||||
rows = len(b_ub)
|
||||
|
||||
|
|
@ -52,7 +56,8 @@ def print_eqns(A_ubd, b_ub, verbose=0, lim=3, label=''):
|
|||
prints = 0
|
||||
#verbose = 1
|
||||
for rowi, row in enumerate(A_ubd):
|
||||
if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and (not lim or prints < lim)):
|
||||
if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and
|
||||
(not lim or prints < lim)):
|
||||
line = ' EQN: p%u: ' % rowi
|
||||
for k, v in sorted(row.items()):
|
||||
line += '%u*t%d ' % (v, k)
|
||||
|
|
@ -60,6 +65,7 @@ def print_eqns(A_ubd, b_ub, verbose=0, lim=3, label=''):
|
|||
print(line)
|
||||
prints += 1
|
||||
|
||||
|
||||
def print_name_eqns(A_ubd, b_ub, names, verbose=0, lim=3, label=''):
|
||||
rows = len(b_ub)
|
||||
|
||||
|
|
@ -67,7 +73,8 @@ def print_name_eqns(A_ubd, b_ub, names, verbose=0, lim=3, label=''):
|
|||
prints = 0
|
||||
#verbose = 1
|
||||
for rowi, row in enumerate(A_ubd):
|
||||
if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and (not lim or prints < lim)):
|
||||
if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and
|
||||
(not lim or prints < lim)):
|
||||
line = ' EQN: p%u: ' % rowi
|
||||
for k, v in sorted(row.items()):
|
||||
line += '%u*%s ' % (v, names[k])
|
||||
|
|
@ -75,19 +82,23 @@ def print_name_eqns(A_ubd, b_ub, names, verbose=0, lim=3, label=''):
|
|||
print(line)
|
||||
prints += 1
|
||||
|
||||
|
||||
def print_names(names, verbose=1):
|
||||
print('Names: %d' % len(names))
|
||||
for xi, name in enumerate(names):
|
||||
print(' % 4u % -80s' % (xi, name))
|
||||
|
||||
|
||||
def invb(b_ub):
|
||||
#return [-b for b in b_ub]
|
||||
return -np.array(b_ub)
|
||||
|
||||
|
||||
def check_feasible_d(A_ubd, b_ub, names):
|
||||
A_ub, b_ub_inv = Ab_d2np(A_ubd, b_ub, names)
|
||||
check_feasible(A_ub, b_ub_inv)
|
||||
|
||||
|
||||
def check_feasible(A_ub, b_ub):
|
||||
sys.stdout.write('Check feasible ')
|
||||
sys.stdout.flush()
|
||||
|
|
@ -118,6 +129,7 @@ def check_feasible(A_ub, b_ub):
|
|||
this += A_ub[row][col] * xs[col]
|
||||
ret[row] = this
|
||||
return ret
|
||||
|
||||
b_res = my_mul(A_ub, xs)
|
||||
|
||||
# Verify bound was respected
|
||||
|
|
@ -126,10 +138,13 @@ def check_feasible(A_ub, b_ub):
|
|||
sys.stdout.write('.')
|
||||
sys.stdout.flush()
|
||||
if this_b >= this_b_ub or this_b > 0:
|
||||
print('% 4d Want res % 10.1f <= % 10.1f <= 0' % (rowi, this_b, this_b_ub))
|
||||
print(
|
||||
'% 4d Want res % 10.1f <= % 10.1f <= 0' %
|
||||
(rowi, this_b, this_b_ub))
|
||||
raise Exception("Bad ")
|
||||
print(' done')
|
||||
|
||||
|
||||
def Ab_ub_dt2d(eqns):
|
||||
'''Convert dict using the rows as keys into a list of dicts + b_ub list (ie return A_ub, b_ub)'''
|
||||
#return [dict(rowt) for rowt in eqns]
|
||||
|
|
@ -137,6 +152,7 @@ def Ab_ub_dt2d(eqns):
|
|||
A_ubd, b_ub = zip(*rows)
|
||||
return list(A_ubd), list(b_ub)
|
||||
|
||||
|
||||
# This significantly reduces runtime
|
||||
def simplify_rows(Ads, b_ub, remove_zd=False, corner=None):
|
||||
'''Remove duplicate equations, taking highest delay'''
|
||||
|
|
@ -150,14 +166,14 @@ def simplify_rows(Ads, b_ub, remove_zd=False, corner=None):
|
|||
'fast_min': min,
|
||||
'slow_max': max,
|
||||
'slow_min': min,
|
||||
}[corner]
|
||||
}[corner]
|
||||
# An outlier to make unknown values be ignored
|
||||
T_UNK = {
|
||||
'fast_max': 0,
|
||||
'fast_min': 10e9,
|
||||
'slow_max': 0,
|
||||
'slow_min': 10e9,
|
||||
}[corner]
|
||||
}[corner]
|
||||
|
||||
sys.stdout.write('SimpR ')
|
||||
sys.stdout.flush()
|
||||
|
|
@ -188,12 +204,15 @@ def simplify_rows(Ads, b_ub, remove_zd=False, corner=None):
|
|||
|
||||
print(' done')
|
||||
|
||||
print('Simplify rows: %d => %d rows w/ zd %d, ze %d' % (len(b_ub), len(eqns), zero_ds, zero_es))
|
||||
print(
|
||||
'Simplify rows: %d => %d rows w/ zd %d, ze %d' %
|
||||
(len(b_ub), len(eqns), zero_ds, zero_es))
|
||||
if len(eqns) == 0:
|
||||
raise SimplifiedToZero()
|
||||
A_ubd_ret, b_ub_ret = Ab_ub_dt2d(eqns)
|
||||
return A_ubd_ret, b_ub_ret
|
||||
|
||||
|
||||
def A_ubr_np2d(row):
|
||||
'''Convert a single row'''
|
||||
#d = {}
|
||||
|
|
@ -203,6 +222,7 @@ def A_ubr_np2d(row):
|
|||
d[coli] = val
|
||||
return d
|
||||
|
||||
|
||||
def A_ub_np2d(A_ub):
|
||||
'''Convert A_ub entries in numpy matrix to dictionary / sparse form'''
|
||||
Adi = [None] * len(A_ub)
|
||||
|
|
@ -210,6 +230,7 @@ def A_ub_np2d(A_ub):
|
|||
Adi[i] = A_ubr_np2d(row)
|
||||
return Adi
|
||||
|
||||
|
||||
def Ar_di2np(row_di, cols):
|
||||
rownp = np.zeros(cols)
|
||||
for coli, val in row_di.items():
|
||||
|
|
@ -217,37 +238,45 @@ def Ar_di2np(row_di, cols):
|
|||
rownp[coli] = val
|
||||
return rownp
|
||||
|
||||
|
||||
# NOTE: sign inversion
|
||||
def A_di2np(Adi, cols):
|
||||
'''Convert A_ub entries in dictionary / sparse to numpy matrix form'''
|
||||
return [Ar_di2np(row_di, cols) for row_di in Adi]
|
||||
|
||||
|
||||
def Ar_ds2t(rowd):
|
||||
'''Convert a dictionary row into a tuple with (column number, value) tuples'''
|
||||
return tuple(sorted(rowd.items()))
|
||||
|
||||
|
||||
def A_ubr_t2d(rowt):
|
||||
'''Convert a dictionary row into a tuple with (column number, value) tuples'''
|
||||
return OrderedDict(rowt)
|
||||
|
||||
|
||||
def A_ub_d2t(A_ubd):
|
||||
'''Convert rows as dicts to rows as tuples'''
|
||||
return [Ar_ds2t(rowd) for rowd in A_ubd]
|
||||
|
||||
|
||||
def A_ub_t2d(A_ubd):
|
||||
'''Convert rows as tuples to rows as dicts'''
|
||||
return [OrderedDict(rowt) for rowt in A_ubd]
|
||||
|
||||
|
||||
def Ab_d2np(A_ubd, b_ub, names):
|
||||
A_ub = A_di2np(A_ubd, len(names))
|
||||
b_ub_inv = invb(b_ub)
|
||||
return A_ub, b_ub_inv
|
||||
|
||||
|
||||
def Ab_np2d(A_ub, b_ub_inv):
|
||||
A_ubd = A_ub_np2d(A_ub)
|
||||
b_ub = invb(b_ub_inv)
|
||||
return A_ubd, b_ub
|
||||
|
||||
|
||||
def sort_equations(Ads, b):
|
||||
# Track rows with value column
|
||||
# Hmm can't sort against np arrays
|
||||
|
|
@ -257,6 +286,7 @@ def sort_equations(Ads, b):
|
|||
A_ubtr, b_ubr = zip(*res)
|
||||
return [OrderedDict(rowt) for rowt in A_ubtr], b_ubr
|
||||
|
||||
|
||||
def derive_eq_by_row(A_ubd, b_ub, verbose=0, col_lim=0, tweak=False):
|
||||
'''
|
||||
Derive equations by subtracting whole rows
|
||||
|
|
@ -348,10 +378,13 @@ def derive_eq_by_row(A_ubd, b_ub, verbose=0, col_lim=0, tweak=False):
|
|||
print(' done')
|
||||
|
||||
#A_ub_ret = A_di2np(A_ubd2, cols=cols)
|
||||
print('Derive row: %d => %d rows using %d lte, %d sc' % (len(b_ub), len(b_ub_ret), ltes, scs))
|
||||
print(
|
||||
'Derive row: %d => %d rows using %d lte, %d sc' %
|
||||
(len(b_ub), len(b_ub_ret), ltes, scs))
|
||||
assert len(A_ubd_ret) == len(b_ub_ret)
|
||||
return A_ubd_ret, b_ub_ret
|
||||
|
||||
|
||||
def derive_eq_by_col(A_ubd, b_ub, verbose=0):
|
||||
'''
|
||||
Derive equations by subtracting out all bounded constants (ie "known" columns)
|
||||
|
|
@ -380,7 +413,6 @@ def derive_eq_by_col(A_ubd, b_ub, verbose=0):
|
|||
print(' done')
|
||||
#knowns_set = set(knowns.keys())
|
||||
print('%d constrained' % len(knowns))
|
||||
|
||||
'''
|
||||
Now see what we can do
|
||||
Rows that are already constrained: eliminate
|
||||
|
|
@ -425,6 +457,7 @@ def derive_eq_by_col(A_ubd, b_ub, verbose=0):
|
|||
print('Derive col: %d => %d rows' % (len(b_ub), len(b_ub_ret)))
|
||||
return A_ubd_ret, b_ub_ret
|
||||
|
||||
|
||||
def col_dist(Ads, desc='of', names=[], lim=0):
|
||||
'''print(frequency distribution of number of elements in a given row'''
|
||||
rows = len(Ads)
|
||||
|
|
@ -435,7 +468,9 @@ def col_dist(Ads, desc='of', names=[], lim=0):
|
|||
this_cols = len(row)
|
||||
fs[this_cols] = fs.get(this_cols, 0) + 1
|
||||
|
||||
print('Col count distribution (%s) for %dr x %dc w/ %d freqs' % (desc, rows, cols, len(fs)))
|
||||
print(
|
||||
'Col count distribution (%s) for %dr x %dc w/ %d freqs' %
|
||||
(desc, rows, cols, len(fs)))
|
||||
prints = 0
|
||||
for i, (k, v) in enumerate(sorted(fs.items())):
|
||||
if lim == 0 or (lim and prints < lim or i == len(fs) - 1):
|
||||
|
|
@ -444,6 +479,7 @@ def col_dist(Ads, desc='of', names=[], lim=0):
|
|||
if lim and prints == lim:
|
||||
print(' ...')
|
||||
|
||||
|
||||
def name_dist(A_ubd, desc='of', names=[], lim=0):
|
||||
'''print(frequency distribution of number of times an element appears'''
|
||||
rows = len(A_ubd)
|
||||
|
|
@ -467,7 +503,7 @@ def name_dist(A_ubd, desc='of', names=[], lim=0):
|
|||
for v in fs.values():
|
||||
fs2[v] = fs2.get(v, 0) + 1
|
||||
prints = 0
|
||||
print('Distribution distribution (%d items)'% len(fs2))
|
||||
print('Distribution distribution (%d items)' % len(fs2))
|
||||
for i, (k, v) in enumerate(sorted(fs2.items())):
|
||||
if lim == 0 or (lim and prints < lim or i == len(fs2) - 1):
|
||||
print(' %s: %s' % (k, v))
|
||||
|
|
@ -479,6 +515,7 @@ def name_dist(A_ubd, desc='of', names=[], lim=0):
|
|||
if zeros:
|
||||
raise Exception("%d names without equation" % zeros)
|
||||
|
||||
|
||||
def filter_ncols(A_ubd, b_ub, cols_min=0, cols_max=0):
|
||||
'''Only keep equations with a few delay elements'''
|
||||
A_ubd_ret = []
|
||||
|
|
@ -486,26 +523,32 @@ def filter_ncols(A_ubd, b_ub, cols_min=0, cols_max=0):
|
|||
|
||||
#print('Removing large rows')
|
||||
for rowd, b in zip(A_ubd, b_ub):
|
||||
if (not cols_min or len(rowd) >= cols_min) and (not cols_max or len(rowd) <= cols_max):
|
||||
if (not cols_min or len(rowd) >= cols_min) and (not cols_max or
|
||||
len(rowd) <= cols_max):
|
||||
A_ubd_ret.append(rowd)
|
||||
b_ub_ret.append(b)
|
||||
|
||||
print('Filter ncols w/ %d <= cols <= %d: %d ==> %d rows' % (cols_min, cols_max, len(b_ub), len(b_ub_ret)))
|
||||
print(
|
||||
'Filter ncols w/ %d <= cols <= %d: %d ==> %d rows' %
|
||||
(cols_min, cols_max, len(b_ub), len(b_ub_ret)))
|
||||
assert len(b_ub_ret)
|
||||
return A_ubd_ret, b_ub_ret
|
||||
|
||||
|
||||
def Ar_di2ds(rowA, names):
|
||||
row = OrderedDict()
|
||||
for k, v in rowA.items():
|
||||
row[names[k]] = v
|
||||
return row
|
||||
|
||||
|
||||
def A_di2ds(Adi, names):
|
||||
rows = []
|
||||
for row_di in Adi:
|
||||
rows.append(Ar_di2ds(row_di, names))
|
||||
return rows
|
||||
|
||||
|
||||
def Ar_ds2di(row_ds, names):
|
||||
def keyi(name):
|
||||
if name not in names:
|
||||
|
|
@ -517,6 +560,7 @@ def Ar_ds2di(row_ds, names):
|
|||
row_di[keyi(k)] = v
|
||||
return row_di
|
||||
|
||||
|
||||
def A_ds2di(rows):
|
||||
names = OrderedDict()
|
||||
|
||||
|
|
@ -526,10 +570,12 @@ def A_ds2di(rows):
|
|||
|
||||
return list(names.keys()), A_ubd
|
||||
|
||||
|
||||
def A_ds2np(Ads):
|
||||
names, Adi = A_ds2di(Ads)
|
||||
return names, A_di2np(Adi, len(names))
|
||||
|
||||
|
||||
def loadc_Ads_mkb(fns, mkb, filt):
|
||||
bs = []
|
||||
Ads = []
|
||||
|
|
@ -548,10 +594,13 @@ def loadc_Ads_mkb(fns, mkb, filt):
|
|||
return None
|
||||
else:
|
||||
return int(bstr)
|
||||
|
||||
corners = [mkcorner(corner) for corner in corners.split()]
|
||||
|
||||
def mkvar(x):
|
||||
i, var = x.split()
|
||||
return (var, int(i))
|
||||
|
||||
vars = OrderedDict([mkvar(var) for var in vars])
|
||||
if not filt(ico, corners, vars):
|
||||
continue
|
||||
|
|
@ -561,6 +610,7 @@ def loadc_Ads_mkb(fns, mkb, filt):
|
|||
|
||||
return Ads, bs
|
||||
|
||||
|
||||
def loadc_Ads_b(fns, corner, ico=None):
|
||||
corner = corner or "slow_max"
|
||||
corneri = corner_s2i[corner]
|
||||
|
|
@ -572,8 +622,10 @@ def loadc_Ads_b(fns, corner, ico=None):
|
|||
|
||||
def mkb(val):
|
||||
return val[corneri]
|
||||
|
||||
return loadc_Ads_mkb(fns, mkb, filt)
|
||||
|
||||
|
||||
def loadc_Ads_bs(fns, ico=None):
|
||||
if ico is not None:
|
||||
filt = lambda ico_, corners, vars: ico_ == ico
|
||||
|
|
@ -582,15 +634,19 @@ def loadc_Ads_bs(fns, ico=None):
|
|||
|
||||
def mkb(val):
|
||||
return val
|
||||
|
||||
return loadc_Ads_mkb(fns, mkb, filt)
|
||||
|
||||
|
||||
def loadc_Ads_raw(fns):
|
||||
filt = lambda ico, corners, vars: True
|
||||
|
||||
def mkb(val):
|
||||
return val
|
||||
|
||||
return loadc_Ads_mkb(fns, mkb, filt)
|
||||
|
||||
|
||||
def index_names(Ads):
|
||||
names = set()
|
||||
for row_ds in Ads:
|
||||
|
|
@ -598,6 +654,7 @@ def index_names(Ads):
|
|||
names.add(k1)
|
||||
return names
|
||||
|
||||
|
||||
def load_sub(fn):
|
||||
j = json.load(open(fn, 'r'))
|
||||
|
||||
|
|
@ -607,6 +664,7 @@ def load_sub(fn):
|
|||
|
||||
return j
|
||||
|
||||
|
||||
def row_sub_syms(row, sub_json, strict=False, verbose=False):
|
||||
if 0 and verbose:
|
||||
print("")
|
||||
|
|
@ -669,6 +727,7 @@ def row_sub_syms(row, sub_json, strict=False, verbose=False):
|
|||
for k, v in sorted(row.items()):
|
||||
assert v > 0, (k, v)
|
||||
|
||||
|
||||
def run_sub_json(Ads, sub_json, strict=False, verbose=False):
|
||||
'''
|
||||
strict: complain if a sub doesn't go in evenly
|
||||
|
|
@ -709,13 +768,15 @@ def run_sub_json(Ads, sub_json, strict=False, verbose=False):
|
|||
print("Sub: %u / %u rows changed" % (nsubs, nrows))
|
||||
print("Sub: %u => %u non-zero row cols" % (ncols_old, ncols_new))
|
||||
|
||||
|
||||
def print_eqns(Ads, b, verbose=0, lim=3, label=''):
|
||||
rows = len(b)
|
||||
|
||||
print('Sample equations (%s) from %d r' % (label, rows))
|
||||
prints = 0
|
||||
for rowi, row in enumerate(Ads):
|
||||
if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and (not lim or prints < lim)):
|
||||
if verbose or ((rowi < 10 or rowi % max(1, (rows / 20)) == 0) and
|
||||
(not lim or prints < lim)):
|
||||
line = ' EQN: p%u: ' % rowi
|
||||
for k, v in sorted(row.items()):
|
||||
line += '%u*t%s ' % (v, k)
|
||||
|
|
@ -723,10 +784,12 @@ def print_eqns(Ads, b, verbose=0, lim=3, label=''):
|
|||
print(line)
|
||||
prints += 1
|
||||
|
||||
|
||||
def print_eqns_np(A_ub, b_ub, verbose=0):
|
||||
Adi = A_ub_np2d(A_ub)
|
||||
print_eqns(Adi, b_ub, verbose=verbose)
|
||||
|
||||
|
||||
def Ads2bounds(Ads, bs):
|
||||
ret = {}
|
||||
for row_ds, row_bs in zip(Ads, bs):
|
||||
|
|
@ -736,17 +799,20 @@ def Ads2bounds(Ads, bs):
|
|||
ret[k] = row_bs
|
||||
return ret
|
||||
|
||||
|
||||
def instances(Ads):
|
||||
ret = 0
|
||||
for row_ds in Ads:
|
||||
ret += sum(row_ds.values())
|
||||
return ret
|
||||
|
||||
|
||||
def acorner2csv(b, corneri):
|
||||
corners = ["None" for _ in range(4)]
|
||||
corners[corneri] = str(b)
|
||||
return ' '.join(corners)
|
||||
|
||||
|
||||
def corners2csv(bs):
|
||||
assert len(bs) == 4
|
||||
corners = ["None" if b is None else str(b) for b in bs]
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import time
|
|||
import copy
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
def lte_const(row_ref, row_cmp):
|
||||
'''Return true if all constants are smaller magnitude in row_cmp than row_ref'''
|
||||
#return False
|
||||
|
|
@ -22,6 +23,7 @@ def lte_const(row_ref, row_cmp):
|
|||
return False
|
||||
return True
|
||||
|
||||
|
||||
def shared_const(row_ref, row_cmp):
|
||||
'''Return true if more constants are equal than not equal'''
|
||||
#return False
|
||||
|
|
@ -43,6 +45,7 @@ def shared_const(row_ref, row_cmp):
|
|||
# Will equation reduce if subtracted?
|
||||
return matches > unmatches
|
||||
|
||||
|
||||
def reduce_const(row_ref, row_cmp):
|
||||
'''Subtract cmp constants from ref'''
|
||||
#ret = {}
|
||||
|
|
@ -57,6 +60,7 @@ def reduce_const(row_ref, row_cmp):
|
|||
ret[k] = res
|
||||
return ret
|
||||
|
||||
|
||||
def derive_eq_by_row(Ads, b, verbose=0, col_lim=0, tweak=False):
|
||||
'''
|
||||
Derive equations by subtracting whole rows
|
||||
|
|
@ -148,10 +152,13 @@ def derive_eq_by_row(Ads, b, verbose=0, col_lim=0, tweak=False):
|
|||
print(' done')
|
||||
|
||||
#A_ub_ret = A_di2np(Ads2, cols=cols)
|
||||
print('Derive row: %d => %d rows using %d lte, %d sc' % (len(b), len(b_ret), ltes, scs))
|
||||
print(
|
||||
'Derive row: %d => %d rows using %d lte, %d sc' %
|
||||
(len(b), len(b_ret), ltes, scs))
|
||||
assert len(Ads_ret) == len(b_ret)
|
||||
return Ads_ret, b_ret
|
||||
|
||||
|
||||
def derive_eq_by_near_row(Ads, b, verbose=0, col_lim=0, tweak=False):
|
||||
'''
|
||||
Derive equations by subtracting whole rows
|
||||
|
|
@ -199,7 +206,8 @@ def derive_eq_by_near_row(Ads, b, verbose=0, col_lim=0, tweak=False):
|
|||
continue
|
||||
|
||||
#for row_cmpi, row_cmp in enumerate(Ads):
|
||||
for row_cmpi in range(max(0, row_refi - rowdelta), min(len(Ads), row_refi + rowdelta)):
|
||||
for row_cmpi in range(max(0, row_refi - rowdelta),
|
||||
min(len(Ads), row_refi + rowdelta)):
|
||||
if row_refi == row_cmpi or col_lim and len(row_cmp) > col_lim:
|
||||
continue
|
||||
row_cmp = Ads[row_cmpi]
|
||||
|
|
@ -246,10 +254,13 @@ def derive_eq_by_near_row(Ads, b, verbose=0, col_lim=0, tweak=False):
|
|||
print(' done')
|
||||
|
||||
#A_ub_ret = A_di2np(Ads2, cols=cols)
|
||||
print('Derive row: %d => %d rows using %d lte, %d sc' % (len(b), len(b_ret), ltes, scs))
|
||||
print(
|
||||
'Derive row: %d => %d rows using %d lte, %d sc' %
|
||||
(len(b), len(b_ret), ltes, scs))
|
||||
assert len(Ads_ret) == len(b_ret)
|
||||
return Ads_ret, b_ret
|
||||
|
||||
|
||||
def derive_eq_by_col(Ads, b_ub, verbose=0):
|
||||
'''
|
||||
Derive equations by subtracting out all bounded constants (ie "known" columns)
|
||||
|
|
@ -277,7 +288,6 @@ def derive_eq_by_col(Ads, b_ub, verbose=0):
|
|||
print(' done')
|
||||
#knowns_set = set(knowns.keys())
|
||||
print('%d constrained' % len(knowns))
|
||||
|
||||
'''
|
||||
Now see what we can do
|
||||
Rows that are already constrained: eliminate
|
||||
|
|
@ -322,6 +332,7 @@ def derive_eq_by_col(Ads, b_ub, verbose=0):
|
|||
print('Derive col: %d => %d rows' % (len(b_ub), len(b_ret)))
|
||||
return Ads_ret, b_ret
|
||||
|
||||
|
||||
# keep derriving until solution is (probably) stable
|
||||
def massage_equations_old(Ads, b, verbose=False, derive_lim=3, corner=None):
|
||||
'''
|
||||
|
|
@ -357,7 +368,9 @@ def massage_equations_old(Ads, b, verbose=False, derive_lim=3, corner=None):
|
|||
debug("der_rows")
|
||||
# Run another simplify pass since new equations may have overlap with original
|
||||
Ads, b = simplify_rows(Ads, b, corner=corner)
|
||||
print('Derive row %d / %d: %d => %d equations' % (di + 1, derive_lim, n_orig, len(b)))
|
||||
print(
|
||||
'Derive row %d / %d: %d => %d equations' %
|
||||
(di + 1, derive_lim, n_orig, len(b)))
|
||||
debug("der_rows simp")
|
||||
|
||||
n_orig2 = len(b)
|
||||
|
|
@ -366,19 +379,19 @@ def massage_equations_old(Ads, b, verbose=False, derive_lim=3, corner=None):
|
|||
debug("der_cols")
|
||||
# Run another simplify pass since new equations may have overlap with original
|
||||
Ads, b = simplify_rows(Ads, b, corner=corner)
|
||||
print('Derive col %d / %d: %d => %d equations' % (di + 1, derive_lim, n_orig2, len(b)))
|
||||
print(
|
||||
'Derive col %d / %d: %d => %d equations' %
|
||||
(di + 1, derive_lim, n_orig2, len(b)))
|
||||
debug("der_cols simp")
|
||||
|
||||
if n_orig == len(b):
|
||||
break
|
||||
|
||||
|
||||
dend = len(b)
|
||||
print('')
|
||||
print('Derive net: %d => %d' % (dstart, dend))
|
||||
print('')
|
||||
# Was experimentting to see how much the higher order columns really help
|
||||
|
||||
'''
|
||||
cols_min_post = opts.get('cols_min_post', None)
|
||||
cols_max_post = opts.get('cols_max_post', None)
|
||||
|
|
@ -393,6 +406,7 @@ def massage_equations_old(Ads, b, verbose=False, derive_lim=3, corner=None):
|
|||
debug("final (sorted)")
|
||||
return Ads, b
|
||||
|
||||
|
||||
# iteratively increasing column limit until all columns are added
|
||||
def massage_equations_inc_col_lim(Ads, b, verbose=False, corner=None):
|
||||
'''
|
||||
|
|
@ -467,6 +481,7 @@ def massage_equations_inc_col_lim(Ads, b, verbose=False, corner=None):
|
|||
print('Massage final: %d => %d rows' % (dstart, dend))
|
||||
return Ads, b
|
||||
|
||||
|
||||
# only derive based on nearby equations
|
||||
# theory is they will be the best to diff
|
||||
def massage_equations_near(Ads, b, verbose=False, corner=None):
|
||||
|
|
@ -532,4 +547,5 @@ def massage_equations_near(Ads, b, verbose=False, corner=None):
|
|||
print('Massage final: %d => %d rows' % (dstart, dend))
|
||||
return Ads, b
|
||||
|
||||
|
||||
massage_equations = massage_equations_inc_col_lim
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import datetime
|
|||
import os
|
||||
import time
|
||||
|
||||
|
||||
def check_feasible(A_ub, b_ub):
|
||||
'''
|
||||
Put large timing constants into the equations
|
||||
|
|
@ -31,7 +32,6 @@ def check_feasible(A_ub, b_ub):
|
|||
cols = len(A_ub[0])
|
||||
|
||||
progress = max(1, rows / 100)
|
||||
|
||||
'''
|
||||
Delays should be in order of ns, so a 10 ns delay should be way above what anything should be
|
||||
Series can have several hundred delay elements
|
||||
|
|
@ -56,6 +56,7 @@ def check_feasible(A_ub, b_ub):
|
|||
this += A_ub[row][col] * xs[col]
|
||||
ret[row] = this
|
||||
return ret
|
||||
|
||||
b_res = my_mul(A_ub, xs)
|
||||
|
||||
# Verify bound was respected
|
||||
|
|
@ -64,10 +65,13 @@ def check_feasible(A_ub, b_ub):
|
|||
sys.stdout.write('.')
|
||||
sys.stdout.flush()
|
||||
if this_b >= this_b_ub or this_b > 0:
|
||||
print('% 4d Want res % 10.1f <= % 10.1f <= 0' % (rowi, this_b, this_b_ub))
|
||||
print(
|
||||
'% 4d Want res % 10.1f <= % 10.1f <= 0' %
|
||||
(rowi, this_b, this_b_ub))
|
||||
raise Exception("Bad ")
|
||||
print(' done')
|
||||
|
||||
|
||||
def filter_bounds(Ads, b, bounds, corner):
|
||||
'''Given min variable delays, remove rows that won't constrain solution'''
|
||||
#assert len(bounds) > 0
|
||||
|
|
@ -76,11 +80,13 @@ def filter_bounds(Ads, b, bounds, corner):
|
|||
# Keep delays possibly larger than current bound
|
||||
def keep(row_b, est):
|
||||
return row_b > est
|
||||
|
||||
T_UNK = 0
|
||||
elif 'min' in corner:
|
||||
# Keep delays possibly smaller than current bound
|
||||
def keep(row_b, est):
|
||||
return row_b < est
|
||||
|
||||
T_UNK = 1e9
|
||||
else:
|
||||
assert 0
|
||||
|
|
@ -96,7 +102,18 @@ def filter_bounds(Ads, b, bounds, corner):
|
|||
ret_b.append(row_b)
|
||||
return ret_Ads, ret_b
|
||||
|
||||
def run(fns_in, corner, run_corner, sub_json=None, sub_csv=None, dedup=True, massage=False, outfn=None, verbose=False, **kwargs):
|
||||
|
||||
def run(
|
||||
fns_in,
|
||||
corner,
|
||||
run_corner,
|
||||
sub_json=None,
|
||||
sub_csv=None,
|
||||
dedup=True,
|
||||
massage=False,
|
||||
outfn=None,
|
||||
verbose=False,
|
||||
**kwargs):
|
||||
print('Loading data')
|
||||
Ads, b = loadc_Ads_b(fns_in, corner, ico=True)
|
||||
|
||||
|
|
@ -120,7 +137,6 @@ def run(fns_in, corner, run_corner, sub_json=None, sub_csv=None, dedup=True, mas
|
|||
print('Sub: %u => %u instances' % (iold, instances(Ads)))
|
||||
else:
|
||||
names = index_names(Ads)
|
||||
|
||||
'''
|
||||
Substitution .csv
|
||||
Special .csv containing one variable per line
|
||||
|
|
@ -132,7 +148,9 @@ def run(fns_in, corner, run_corner, sub_json=None, sub_csv=None, dedup=True, mas
|
|||
assert len(bounds), 'Failed to load bounds'
|
||||
rows_old = len(Ads)
|
||||
Ads, b = filter_bounds(Ads, b, bounds, corner)
|
||||
print('Filter bounds: %s => %s + %s rows' % (rows_old, len(Ads), len(Ads2)))
|
||||
print(
|
||||
'Filter bounds: %s => %s + %s rows' %
|
||||
(rows_old, len(Ads), len(Ads2)))
|
||||
Ads = Ads + Ads2
|
||||
b = b + b2
|
||||
assert len(Ads) or allow_zero_eqns()
|
||||
|
|
@ -145,7 +163,6 @@ def run(fns_in, corner, run_corner, sub_json=None, sub_csv=None, dedup=True, mas
|
|||
#print
|
||||
#col_dist(A_ubd, 'final', names)
|
||||
print('b10', b[0:100])
|
||||
|
||||
'''
|
||||
Given:
|
||||
a >= 10
|
||||
|
|
@ -169,4 +186,11 @@ def run(fns_in, corner, run_corner, sub_json=None, sub_csv=None, dedup=True, mas
|
|||
|
||||
print('Converting to numpy...')
|
||||
names, Anp = A_ds2np(Ads)
|
||||
run_corner(Anp, np.asarray(b), names, corner, outfn=outfn, verbose=verbose, **kwargs)
|
||||
run_corner(
|
||||
Anp,
|
||||
np.asarray(b),
|
||||
names,
|
||||
corner,
|
||||
outfn=outfn,
|
||||
verbose=verbose,
|
||||
**kwargs)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import time
|
|||
import json
|
||||
|
||||
SI_NONE = 0xFFFF
|
||||
|
||||
|
||||
def load_speed_json(f):
|
||||
j = json.load(f)
|
||||
# Index speed indexes to names
|
||||
|
|
@ -16,6 +18,7 @@ def load_speed_json(f):
|
|||
speed_i2s[i] = k
|
||||
return j, speed_i2s
|
||||
|
||||
|
||||
def gen_tiles(fnin, speed_i2s):
|
||||
for l in open(fnin):
|
||||
# lappend items pip $name $speed_index
|
||||
|
|
@ -28,7 +31,7 @@ def gen_tiles(fnin, speed_i2s):
|
|||
pips = {}
|
||||
wires = {}
|
||||
for i in range(0, len(tuples), 3):
|
||||
ttype, name, speed_index = tuples[i:i+3]
|
||||
ttype, name, speed_index = tuples[i:i + 3]
|
||||
name_local = name.split('/')[1]
|
||||
{
|
||||
'pip': pips,
|
||||
|
|
@ -36,6 +39,7 @@ def gen_tiles(fnin, speed_i2s):
|
|||
}[ttype][name_local] = speed_i2s[int(speed_index)]
|
||||
yield (tile_type, tile_name, grid_x, grid_y, pips, wires)
|
||||
|
||||
|
||||
def run(fnin, fnout, speed_json_fn, verbose=False):
|
||||
speedj, speed_i2s = load_speed_json(open(speed_json_fn, 'r'))
|
||||
|
||||
|
|
@ -46,23 +50,24 @@ def run(fnin, fnout, speed_json_fn, verbose=False):
|
|||
if tile_type not in tiles:
|
||||
tiles[tile_type] = this_dat
|
||||
else:
|
||||
if tiles[tile_type] != this_dat:
|
||||
print(tile_name, tile_type)
|
||||
print(this_dat)
|
||||
print(tiles[tile_type])
|
||||
assert 0
|
||||
|
||||
if tiles[tile_type] != this_dat:
|
||||
print(tile_name, tile_type)
|
||||
print(this_dat)
|
||||
print(tiles[tile_type])
|
||||
assert 0
|
||||
|
||||
j = {'tiles': tiles}
|
||||
json.dump(j, open(fnout, 'w'), sort_keys=True, indent=4, separators=(',', ': '))
|
||||
json.dump(
|
||||
j, open(fnout, 'w'), sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Solve timing solution'
|
||||
)
|
||||
parser.add_argument('--speed-json', default='../../speed/build/speed.json',
|
||||
parser = argparse.ArgumentParser(description='Solve timing solution')
|
||||
parser.add_argument(
|
||||
'--speed-json',
|
||||
default='../../speed/build/speed.json',
|
||||
help='Provides speed index to name translation')
|
||||
parser.add_argument('fnin', default=None, help='input tcl output .txt')
|
||||
parser.add_argument('fnout', default=None, help='output .json')
|
||||
|
|
@ -70,5 +75,6 @@ def main():
|
|||
|
||||
run(args.fnin, args.fnout, speed_json_fn=args.speed_json, verbose=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@ SI_NONE = 0xFFFF
|
|||
|
||||
PREFIX_W = 'WIRE_'
|
||||
PREFIX_P = 'PIP_'
|
||||
|
||||
#PREFIX_W = ''
|
||||
#PREFIX_P = ''
|
||||
|
||||
|
||||
def parse_pip(s):
|
||||
# Entries like
|
||||
# CLK_BUFG_REBUF_X60Y117/CLK_BUFG_REBUF.CLK_BUFG_REBUF_R_CK_GCLK0_BOT<<->>CLK_BUFG_REBUF_R_CK_GCLK0_TOP
|
||||
|
|
@ -28,22 +30,26 @@ def parse_pip(s):
|
|||
#return (site, type, pip_junction, pip)
|
||||
return site, instance, int(speed_index)
|
||||
|
||||
|
||||
def parse_node(s):
|
||||
node, nwires = s.split(':')
|
||||
return node, int(nwires)
|
||||
|
||||
|
||||
def parse_wire(s):
|
||||
# CLBLM_R_X3Y80/CLBLM_M_D6:952
|
||||
wirestr, speed_index = s.split(':')
|
||||
site, instance = wirestr.split('/')
|
||||
return site, instance, int(speed_index)
|
||||
|
||||
|
||||
# FIXME: these actually have a delay element
|
||||
# Probably need to put these back in
|
||||
def remove_virtual_pips(pips):
|
||||
return pips
|
||||
return filter(lambda pip: not re.match(r'CLBL[LM]_[LR]_', pip[0]), pips)
|
||||
|
||||
|
||||
def load_timing3(f, name='file'):
|
||||
# src_bel dst_bel ico fast_max fast_min slow_max slow_min pips
|
||||
f.readline()
|
||||
|
|
@ -66,25 +72,27 @@ def load_timing3(f, name='file'):
|
|||
pips = pips.split('|')
|
||||
nodes = nodes.split('|')
|
||||
wires = wires.split('|')
|
||||
ret.append({
|
||||
'net': net,
|
||||
'src_bel': src_bel,
|
||||
'dst_bel': dst_bel,
|
||||
'ico': int(ico),
|
||||
# ps
|
||||
'fast_max': int(fast_max),
|
||||
'fast_min': int(fast_min),
|
||||
'slow_max': int(slow_max),
|
||||
'slow_min': int(slow_min),
|
||||
'pips': remove_virtual_pips([parse_pip(pip) for pip in pips]),
|
||||
'nodes': [parse_node(node) for node in nodes],
|
||||
'wires': [parse_wire(wire) for wire in wires],
|
||||
'line': l,
|
||||
ret.append(
|
||||
{
|
||||
'net': net,
|
||||
'src_bel': src_bel,
|
||||
'dst_bel': dst_bel,
|
||||
'ico': int(ico),
|
||||
# ps
|
||||
'fast_max': int(fast_max),
|
||||
'fast_min': int(fast_min),
|
||||
'slow_max': int(slow_max),
|
||||
'slow_min': int(slow_min),
|
||||
'pips': remove_virtual_pips([parse_pip(pip) for pip in pips]),
|
||||
'nodes': [parse_node(node) for node in nodes],
|
||||
'wires': [parse_wire(wire) for wire in wires],
|
||||
'line': l,
|
||||
})
|
||||
print(' load %s: %d bad, %d good' % (name, bads, len(ret)))
|
||||
#assert 0
|
||||
return ret
|
||||
|
||||
|
||||
def load_speed_json(f):
|
||||
j = json.load(f)
|
||||
# Index speed indexes to names
|
||||
|
|
@ -95,6 +103,7 @@ def load_speed_json(f):
|
|||
speed_i2s[i] = k
|
||||
return j, speed_i2s
|
||||
|
||||
|
||||
# Verify the nodes and wires really do line up
|
||||
def vals2Adi_check(vals, names):
|
||||
print('Checking')
|
||||
|
|
@ -106,12 +115,12 @@ def vals2Adi_check(vals, names):
|
|||
print('Done')
|
||||
assert 0
|
||||
|
||||
def vals2Adi(vals, speed_i2s,
|
||||
name_tr={}, name_drop=[],
|
||||
verbose=False):
|
||||
|
||||
def vals2Adi(vals, speed_i2s, name_tr={}, name_drop=[], verbose=False):
|
||||
def pip2speed(pip):
|
||||
_site, _name, speed_index = pip
|
||||
_site, _name, speed_index = pip
|
||||
return PREFIX_P + speed_i2s[speed_index]
|
||||
|
||||
def wire2speed(wire):
|
||||
_site, _name, speed_index = wire
|
||||
return PREFIX_W + speed_i2s[speed_index]
|
||||
|
|
@ -119,7 +128,8 @@ def vals2Adi(vals, speed_i2s,
|
|||
# Want this ordered
|
||||
names = OrderedDict()
|
||||
|
||||
print('Creating matrix w/ tr: %d, drop: %d' % (len(name_tr), len(name_drop)))
|
||||
print(
|
||||
'Creating matrix w/ tr: %d, drop: %d' % (len(name_tr), len(name_drop)))
|
||||
|
||||
# Take sites out entirely using handy "interconnect only" option
|
||||
#vals = filter(lambda x: str(x).find('SLICE') >= 0, vals)
|
||||
|
|
@ -171,6 +181,7 @@ def vals2Adi(vals, speed_i2s,
|
|||
print('Creating delay element matrix w/ %d names' % len(names))
|
||||
Adi = [None for _i in range(len(vals))]
|
||||
for vali, val in enumerate(vals):
|
||||
|
||||
def add_name(name):
|
||||
if name in name_drop:
|
||||
return
|
||||
|
|
@ -192,12 +203,14 @@ def vals2Adi(vals, speed_i2s,
|
|||
|
||||
return Adi, names
|
||||
|
||||
|
||||
# TODO: load directly as Ads
|
||||
# remove names_tr, names_drop
|
||||
def vals2Ads(vals, speed_i2s, verbose=False):
|
||||
Adi, names = vals2Adi(vals, speed_i2s, verbose=False)
|
||||
return A_di2ds(Adi, names)
|
||||
|
||||
|
||||
def load_Ads(speed_json_f, f_ins):
|
||||
|
||||
print('Loading data')
|
||||
|
|
@ -211,12 +224,15 @@ def load_Ads(speed_json_f, f_ins):
|
|||
Ads = vals2Ads(vals, speed_i2s)
|
||||
|
||||
def mkb(val):
|
||||
return (val['fast_max'], val['fast_min'], val['slow_max'], val['slow_min'])
|
||||
return (
|
||||
val['fast_max'], val['fast_min'], val['slow_max'], val['slow_min'])
|
||||
|
||||
b = [mkb(val) for val in vals]
|
||||
ico = [val['ico'] for val in vals]
|
||||
|
||||
return Ads, b, ico
|
||||
|
||||
|
||||
def run(speed_json_f, fout, f_ins, verbose=0, corner=None):
|
||||
Ads, bs, ico = load_Ads(speed_json_f, f_ins)
|
||||
|
||||
|
|
@ -229,6 +245,7 @@ def run(speed_json_f, fout, f_ins, verbose=0, corner=None):
|
|||
items.append('%u %s' % (v, k))
|
||||
fout.write(','.join(items) + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
|
|
@ -238,14 +255,14 @@ def main():
|
|||
)
|
||||
|
||||
parser.add_argument('--verbose', type=int, help='')
|
||||
parser.add_argument('--auto-name', action='store_true', help='timing3.txt => timing3.csv')
|
||||
parser.add_argument('--speed-json', default='build_speed/speed.json',
|
||||
parser.add_argument(
|
||||
'--auto-name', action='store_true', help='timing3.txt => timing3.csv')
|
||||
parser.add_argument(
|
||||
'--speed-json',
|
||||
default='build_speed/speed.json',
|
||||
help='Provides speed index to name translation')
|
||||
parser.add_argument('--out', default=None, help='Output csv')
|
||||
parser.add_argument(
|
||||
'fns_in',
|
||||
nargs='*',
|
||||
help='timing3.txt input files')
|
||||
parser.add_argument('fns_in', nargs='*', help='timing3.txt input files')
|
||||
args = parser.parse_args()
|
||||
bench = Benchmark()
|
||||
|
||||
|
|
@ -265,8 +282,12 @@ def main():
|
|||
if not fns_in:
|
||||
fns_in = glob.glob('specimen_*/timing3.txt')
|
||||
|
||||
run(speed_json_f=open(args.speed_json, 'r'), fout=fout,
|
||||
f_ins=[(open(fn_in, 'r'), fn_in) for fn_in in fns_in], verbose=args.verbose)
|
||||
run(
|
||||
speed_json_f=open(args.speed_json, 'r'),
|
||||
fout=fout,
|
||||
f_ins=[(open(fn_in, 'r'), fn_in) for fn_in in fns_in],
|
||||
verbose=args.verbose)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Verifies that node timing info is unique
|
|||
|
||||
import re
|
||||
|
||||
|
||||
def gen_wires(fin):
|
||||
for l in fin:
|
||||
lj = {}
|
||||
|
|
@ -12,7 +13,8 @@ def gen_wires(fin):
|
|||
name, value = kvs.split(':')
|
||||
lj[name] = value
|
||||
|
||||
tile_type, xy, wname = re.match(r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups()
|
||||
tile_type, xy, wname = re.match(
|
||||
r'(.*)_(X[0-9]*Y[0-9]*)/(.*)', lj['NAME']).groups()
|
||||
lj['tile_type'] = tile_type
|
||||
lj['xy'] = xy
|
||||
lj['wname'] = wname
|
||||
|
|
@ -21,10 +23,12 @@ def gen_wires(fin):
|
|||
|
||||
yield lj
|
||||
|
||||
|
||||
def run(node_fin, verbose=0):
|
||||
refnodes = {}
|
||||
nodei = 0
|
||||
for nodei, anode in enumerate(gen_wires(node_fin)):
|
||||
|
||||
def getk(anode):
|
||||
return anode['wname']
|
||||
#return (anode['tile_type'], anode['wname'])
|
||||
|
|
@ -39,32 +43,34 @@ def run(node_fin, verbose=0):
|
|||
refnodes[getk(anode)] = anode
|
||||
continue
|
||||
k_invariant = (
|
||||
'COST_CODE',
|
||||
'IS_INPUT_PIN',
|
||||
'IS_OUTPUT_PIN',
|
||||
'IS_PART_OF_BUS',
|
||||
'NUM_INTERSECTS',
|
||||
'NUM_TILE_PORTS',
|
||||
'SPEED_INDEX',
|
||||
'TILE_PATTERN_OFFSET',
|
||||
)
|
||||
'COST_CODE',
|
||||
'IS_INPUT_PIN',
|
||||
'IS_OUTPUT_PIN',
|
||||
'IS_PART_OF_BUS',
|
||||
'NUM_INTERSECTS',
|
||||
'NUM_TILE_PORTS',
|
||||
'SPEED_INDEX',
|
||||
'TILE_PATTERN_OFFSET',
|
||||
)
|
||||
k_varies = (
|
||||
'ID_IN_TILE_TYPE',
|
||||
'IS_CONNECTED',
|
||||
'NUM_DOWNHILL_PIPS',
|
||||
'NUM_PIPS',
|
||||
'NUM_UPHILL_PIPS',
|
||||
'TILE_NAME',
|
||||
)
|
||||
'ID_IN_TILE_TYPE',
|
||||
'IS_CONNECTED',
|
||||
'NUM_DOWNHILL_PIPS',
|
||||
'NUM_PIPS',
|
||||
'NUM_UPHILL_PIPS',
|
||||
'TILE_NAME',
|
||||
)
|
||||
# Verify equivilence
|
||||
for k in k_invariant:
|
||||
if k in refnode and k in anode:
|
||||
|
||||
def fail():
|
||||
print 'Mismatch on %s' % k
|
||||
print refnode[k], anode[k]
|
||||
print refnode['l']
|
||||
print anode['l']
|
||||
#assert 0
|
||||
|
||||
if refnode[k] != anode[k]:
|
||||
print
|
||||
fail()
|
||||
|
|
@ -74,19 +80,14 @@ def run(node_fin, verbose=0):
|
|||
elif k not in k_varies:
|
||||
assert 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=
|
||||
'Timing fuzzer'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description='Timing fuzzer')
|
||||
|
||||
parser.add_argument('--verbose', type=int, help='')
|
||||
parser.add_argument(
|
||||
'node_fn_in',
|
||||
default='/dev/stdin',
|
||||
nargs='?',
|
||||
help='Input file')
|
||||
'node_fn_in', default='/dev/stdin', nargs='?', help='Input file')
|
||||
args = parser.parse_args()
|
||||
run(open(args.node_fn_in, 'r'), verbose=args.verbose)
|
||||
|
|
|
|||
Loading…
Reference in New Issue