From f4faa272437b91a3bcc59c7b912a7ed834c62406 Mon Sep 17 00:00:00 2001 From: John McMaster Date: Wed, 3 Oct 2018 16:27:07 -0700 Subject: [PATCH] timfuz: timing.txt "," delim, line_net procs (cleanup + bug fix) Signed-off-by: John McMaster --- fuzzers/007-timing/projects/project.tcl | 45 +++++++++-- fuzzers/007-timing/timfuz_massage.py | 11 +-- fuzzers/007-timing/timfuz_solve.py | 5 +- fuzzers/007-timing/timing_txt2json.py | 102 +++++++----------------- 4 files changed, 77 insertions(+), 86 deletions(-) diff --git a/fuzzers/007-timing/projects/project.tcl b/fuzzers/007-timing/projects/project.tcl index 84354794..38ba25ed 100644 --- a/fuzzers/007-timing/projects/project.tcl +++ b/fuzzers/007-timing/projects/project.tcl @@ -37,11 +37,32 @@ proc list_format {l delim} { } return $ret } + +proc line_net_external {fp net src_site src_site_type src_site_pin src_bel src_bel_pin dst_site dst_site_type dst_site_pin dst_bel dst_bel_pin ico fast_max fast_min slow_max slow_min pips_out nodes_out wires_out} { + puts $fp "NET,$net,$src_site,$src_site_type,$src_site_pin,$src_bel,$src_bel_pin,$dst_site,$dst_site_type,$dst_site_pin,$dst_bel,$dst_bel_pin,$ico,$fast_max,$fast_min,$slow_max,$slow_min,$pips_out,$nodes_out,$wires_out" +} + +proc line_net_internal {fp net site site_type src_bel src_bel_pin dst_bel dst_bel_pin ico fast_max fast_min slow_max slow_min} { + set src_site $site + set src_site_type $site_type + set src_site_pin "" + + set dst_site $site + set dst_site_type $site_type + set dst_site_pin "" + + set pips_out "" + set nodes_out "" + set wires_out "" + + puts $fp "NET,$net,$src_site,$src_site_type,$src_site_pin,$src_bel,$src_bel_pin,$dst_site,$dst_site_type,$dst_site_pin,$dst_bel,$dst_bel_pin,$ico,$fast_max,$fast_min,$slow_max,$slow_min,$pips_out,$nodes_out,$wires_out" +} + proc write_info4 {} { set outdir "." set fp [open "$outdir/timing4.txt" w] # bel as site/bel, so don't bother with site - puts $fp "linetype net src_site src_site_type src_site_pin src_bel src_bel_pin dst_site dst_site_type dst_site_pin dst_bel dst_bel_pin ico fast_max fast_min slow_max slow_min pips inodes wires" + puts $fp "linetype,net,src_site,src_site_type,src_site_pin,src_bel,src_bel_pin,dst_site,dst_site_type,dst_site_pin,dst_bel,dst_bel_pin,ico,fast_max,fast_min,slow_max,slow_min,pips,inodes,wires" set TIME_start [clock clicks -milliseconds] set equations 0 @@ -52,6 +73,7 @@ proc write_info4 {} { set neti 0 set nets [get_nets -hierarchical] #set nets [get_nets clk] + #set nets [get_nets roi/counter[0]_i_2_n_0] set nnets [llength $nets] foreach net $nets { incr neti @@ -105,7 +127,7 @@ proc write_info4 {} { # only increment on one of the paths set equations [expr "$equations + [llength $delays]"] } - puts $fp "GROUP $ico [llength $delays]" + puts $fp "GROUP,$ico,[llength $delays]" foreach delay $delays { #set delaystr [get_property NAME $delay] @@ -128,10 +150,19 @@ proc write_info4 {} { # No fabric on this net? # don't try querying sites and such if {[get_nodes -of_objects $net] eq ""} { + if {$src_site ne $dst_site} { + puts "ERROR: site mismatch" + return + } + if {$src_site_type ne $dst_site_type} { + puts "ERROR: site mismatch" + return + } + # Already have everything we could query # Just output incr lines_no_int - puts $fp "NET $net $src_site $src_site_type $src_site_pin $src_bel $src_bel_pin $dst_site $dst_site_type $dst_site_pin $dst_bel $dst_bel_pin $ico $fast_max $fast_min $slow_max $slow_min $pips_out $nodes_out $wires_out" + line_net_internal $fp $net $src_site $src_site_type $src_bel $src_bel_pin $dst_bel $dst_bel_pin $ico $fast_max $fast_min $slow_max $slow_min # At least some fabric exists # Does dest BEL exist but not source BEL? } elseif {$src_bel eq ""} { @@ -139,7 +170,7 @@ proc write_info4 {} { return # Ideally query from and to cell pins } else { - # Nested list delimination precedence: " |:" + # Nested list delimination precedence: ",|:" # Pips in between # Walk net, looking for interesting elements in between @@ -176,7 +207,7 @@ proc write_info4 {} { set wires_out [list_format "$wires_out" "|"] incr lines_some_int - puts $fp "NET $net $src_site $src_site_type $src_site_pin $src_bel $src_bel_pin $dst_site $dst_site_type $dst_site_pin $dst_bel $dst_bel_pin $ico $fast_max $fast_min $slow_max $slow_min $pips_out $nodes_out $wires_out" + line_net_external $fp $net $src_site $src_site_type $src_site_pin $src_bel $src_bel_pin $dst_site $dst_site_type $dst_site_pin $dst_bel $dst_bel_pin $ico $fast_max $fast_min $slow_max $slow_min $pips_out $nodes_out $wires_out } } } @@ -193,3 +224,7 @@ proc write_info4 {} { puts " Has interconnect: $lines_some_int" } +# for debugging +# source ../project.tcl +# write_info4 + diff --git a/fuzzers/007-timing/timfuz_massage.py b/fuzzers/007-timing/timfuz_massage.py index 90d318f3..d64853c2 100644 --- a/fuzzers/007-timing/timfuz_massage.py +++ b/fuzzers/007-timing/timfuz_massage.py @@ -220,7 +220,9 @@ def derive_eq_by_col(Ads, b_ub, verbose=0, keep_orig=True): # iteratively increasing column limit until all columns are added -def massage_equations(Ads, b, verbose=False, corner=None): +def massage_equations( + Ads, b, verbose=False, corner=None, iter_lim=1, col_lim=100000): + #col_lim = 15 ''' Subtract equations from each other to generate additional constraints Helps provide additional guidance to solver for realistic delays @@ -262,7 +264,6 @@ def massage_equations(Ads, b, verbose=False, corner=None): # Each iteration one more column is allowed until all columns are included # (and the system is stable) - col_lim = 15 di = 0 while True: print @@ -298,13 +299,13 @@ def massage_equations(Ads, b, verbose=False, corner=None): col_dist(Ads, 'derive done iter %d, lim %d' % (di, col_lim), lim=12) rows = len(Ads) + di += 1 + dend = len(b) # possible that a new equation was generated and taken away, but close enough - if n_orig == len(b) and col_lim >= cols: + if n_orig == len(b) and col_lim >= cols or di >= iter_lim: break col_lim += col_lim / 5 - di += 1 - dend = len(b) print('') print('Derive net: %d => %d' % (dstart, dend)) print('') diff --git a/fuzzers/007-timing/timfuz_solve.py b/fuzzers/007-timing/timfuz_solve.py index c37a6228..3e09cf07 100644 --- a/fuzzers/007-timing/timfuz_solve.py +++ b/fuzzers/007-timing/timfuz_solve.py @@ -150,7 +150,10 @@ def solve_save(outfn, xvals, names, corner, save_zero=True, verbose=False): print( 'Wrote: %u / %u constrained delays, %u zeros' % (nonzeros, len(names), zeros)) - assert nonzeros, 'Failed to estimate delay' + # max only...min corner seems to like 0 + # see https://github.com/SymbiFlow/prjxray/issues/136 + if 'max' in corner: + assert nonzeros, 'Failed to estimate delay' def run( diff --git a/fuzzers/007-timing/timing_txt2json.py b/fuzzers/007-timing/timing_txt2json.py index 97024985..b064b99b 100644 --- a/fuzzers/007-timing/timing_txt2json.py +++ b/fuzzers/007-timing/timing_txt2json.py @@ -23,11 +23,23 @@ def parse_pip(s, speed_i2s): return site, instance, speed_i2s[int(speed_index)] +def parse_pips(pips, speed_i2s): + if not pips: + return [] + return [parse_pip(pip, speed_i2s) for pip in pips.split('|')] + + def parse_node(s): node, nwires = s.split(':') return node, int(nwires) +def parse_nodes(nodes): + if not nodes: + return [] + return [parse_node(node) for node in nodes.split('|')] + + def parse_wire(s, speed_i2s): # CLBLM_R_X3Y80/CLBLM_M_D6:952 wirestr, speed_index = s.split(':') @@ -35,10 +47,16 @@ def parse_wire(s, speed_i2s): return site, instance, speed_i2s[int(speed_index)] +def parse_wires(wires, speed_i2s): + if not wires: + return [] + return [parse_wire(wire, speed_i2s) for wire in wires.split('|')] + + def gen_timing4(fn, speed_i2s): f = open(fn, 'r') - header_want = 'linetype net src_site src_site_type src_site_pin src_bel src_bel_pin dst_site dst_site_type dst_site_pin dst_bel dst_bel_pin ico fast_max fast_min slow_max slow_min pips inodes wires' - ncols = len(header_want.split()) + header_want = "linetype,net,src_site,src_site_type,src_site_pin,src_bel,src_bel_pin,dst_site,dst_site_type,dst_site_pin,dst_bel,dst_bel_pin,ico,fast_max,fast_min,slow_max,slow_min,pips,inodes,wires" + ncols = len(header_want.split(',')) # src_bel dst_bel ico fast_max fast_min slow_max slow_min pips header_got = f.readline().strip() @@ -52,17 +70,15 @@ def gen_timing4(fn, speed_i2s): for l in f: def group_line(): - ncols = len('lintype ico delays'.split()) + ncols = len('lintype,ico,delays'.split(',')) assert len(parts) == ncols _lintype, ico, delays = parts return int(ico), int(delays) def net_line(): - assert len(parts) == ncols + assert len(parts) == ncols, "Expected %u parts, got %u" % ( + ncols, len(parts)) _lintype, net, src_site, src_site_type, src_site_pin, src_bel, src_bel_pin, dst_site, dst_site_type, dst_site_pin, dst_bel, dst_bel_pin, ico, fast_max, fast_min, slow_max, slow_min, pips, nodes, wires = parts - pips = pips.split('|') - nodes = nodes.split('|') - wires = wires.split('|') return { 'net': net, 'src': { @@ -87,16 +103,16 @@ def gen_timing4(fn, speed_i2s): 'slow_min': int(slow_min), }, 'ico': int(ico), - 'pips': [parse_pip(pip, speed_i2s) for pip in pips], - 'nodes': [parse_node(node) for node in nodes], - 'wires': [parse_wire(wire, speed_i2s) for wire in wires], + 'pips': parse_pips(pips, speed_i2s), + 'nodes': parse_nodes(nodes), + 'wires': parse_wires(wires, speed_i2s), 'line': l, } l = l.strip() if not l: continue - parts = l.split(' ') + parts = l.split(',') lintype = parts[0] val = { @@ -180,67 +196,3 @@ def load_speed_json(f): if i != SI_NONE: speed_i2s[i] = k return j, speed_i2s - - -''' -def run(speed_json_f, fout, fns_in, verbose=0, corner=None): - print('Loading data') - _speedj, speed_i2s = load_speed_json(speed_json_f) - - fnout = open(fout, 'w') - - vals = [] - for fn_in in fns_in: - for j in load_timing4(fn_in, speed_i2s): - fnout.write(json.dumps(j) + '\n') - - -def main(): - import argparse - - parser = argparse.ArgumentParser( - description= - 'Convert obscure timing4.txt into more readable but roughly equivilent timing4.json' - ) - - parser.add_argument('--verbose', type=int, help='') - # made a bulk conversion easier...keep? - parser.add_argument( - '--auto-name', action='store_true', help='timing4.txt => timing4i.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 timing4i.csv file') - parser.add_argument('fns_in', nargs='+', help='Input timing4.txt files') - args = parser.parse_args() - bench = Benchmark() - - fnout = args.out - if fnout is None: - if args.auto_name: - assert len(args.fns_in) == 1 - fnin = args.fns_in[0] - fnout = fnin.replace('.txt', '.json') - assert fnout != fnin, 'Expect .txt in' - else: - # practically there are too many stray prints to make this work as expected - assert 0, 'File name required' - fnout = '/dev/stdout' - print("Writing to %s" % fnout) - fout = open(fnout, 'w') - - fns_in = args.fns_in - if not fns_in: - fns_in = glob.glob('specimen_*/timing4.txt') - - run( - speed_json_f=open(args.speed_json, 'r'), - fout=fout, - fns_in=fns_in, - verbose=args.verbose) - - -if __name__ == '__main__': - main() -'''