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