| #!/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 |