| #!/usr/bin/env python |
| |
| ############################### blif_splicer.py ################################ |
| # |
| # Generate the k largest circuits (by total # of logic blocks or occurrences |
| # of '.names') which can be formed by concatenating n of the MCNC 20 circuits. |
| # Gives an error for circuits with multiple .model sections. |
| # |
| # Author: Michael Wainberg |
| |
| ################################### Settings ################################### |
| |
| k = 10 |
| n = 2 |
| blifdir = "../benchmarks/blif" |
| |
| ################################################################################ |
| |
| import os |
| import sys |
| import glob |
| import itertools |
| |
| os.chdir(blifdir) |
| |
| # Get the name of each circuit (without the '.blif') and its # of logic blocks |
| |
| circuits = [] |
| for filename in glob.glob('*.blif'): |
| if '+' in filename: |
| continue # don't use outputs from previous script runs as inputs |
| with open(filename) as infile: |
| name = os.path.splitext(filename)[0] # remove '.blif' |
| circuits.append((name, infile.read().count('.names'))) |
| |
| # Iterate over the first k combinations of n circuits in decreasing order, |
| # sorted by the total number of logic blocks, and stitch them together. |
| # Note: this could be optimized further by storing the processed version |
| # of each circuit after it is read in for the first time, since the largest |
| # circuits will likely be reused often. |
| |
| nonNetChars = '0123456789\\-\n' # a valid net name can't use only these |
| |
| for tupleIndex, nTuple in enumerate(sorted(itertools.combinations(circuits, n), |
| key=lambda item: sum(circuit[1] for circuit in item), reverse=True)): |
| |
| # Parse each input blif into the following strings, which represent |
| # different sections of the output file. |
| |
| sections = ['.inputs ', '.outputs ', ''] |
| |
| for circuitIndex, circuit in enumerate(nTuple): |
| name = circuit[0] |
| sectionNumber = 0 # 0 = .inputs, 1 = .outputs, 2 = body |
| modelFlag = False |
| with open(name + '.blif') as infile: |
| # After each circuit, replace the last newline of .inputs and |
| # .outputs lines with a line continuation '\' then a newline. |
| if circuitIndex > 0: |
| sections[0] = sections[0][:-1] + ' \\\n' |
| sections[1] = sections[1][:-1] + ' \\\n' |
| for line in infile: |
| if not line or line[0] == '\n': |
| continue # empty line |
| if line[0] == '.': |
| if line[1] == 'm': # .model |
| if modelFlag: |
| sys.exit('Multiple .model sections in circuit ' + |
| name + ': aborting') |
| modelFlag = True |
| continue |
| if line[1] == 'e': # .end |
| continue |
| split = line.split(' ', 1) |
| if line[1] == 'o': # .outputs |
| sectionNumber = 1 |
| elif line[1] != 'i': # .inputs |
| sectionNumber = 2 |
| sections[2] += split[0] + ' ' # copy 1st word |
| line = split[1] # skip 1st word |
| |
| # Add this line to the appropriate section, after mangling |
| # each net name (one which does not contain only nonNetChars |
| # and is not 're') with the name of the circuit. |
| |
| sections[sectionNumber] += ' '.join(name + '_' + word if word |
| != 're' and any(char not in nonNetChars for char in word) |
| else word for word in line.split(' ')) |
| |
| # Write the concatenation of all sections to the output file. |
| # The format of the output filename is 'file1+file2+...+fileN.blif' |
| |
| filename = '+'.join(circuit[0] for circuit in nTuple) + '.blif' |
| with open(filename, 'wb') as outfile: |
| outfile.write('.model top\n' + ''.join(sections) + '.end\n') |
| print 'Created ' + filename + '...' |
| |
| if tupleIndex == k-1: |
| break |