-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
8,284 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
### COFFE: CIRCUIT OPTIMIZATION FOR FPGA EXPLORATION | ||
# Created by: Charles Chiasson ([email protected]) | ||
# at: University of Toronto | ||
# in: 2013 | ||
|
||
# | ||
# The big picture: | ||
# | ||
# COFFE will size the transistors of an FPGA based on some input architecture | ||
# parameters. COFFE will produce area and delay results that can be used to | ||
# create VPR architecture files for architecture exploration. By changing how | ||
# COFFE designs circuitry, one could also use COFFE to explore different FPGA | ||
# circuit designs. | ||
# | ||
# How it works (in a nutshell): | ||
# | ||
# We start off by creating an 'FPGA' object with the input architecture parameters. | ||
# This FPGA object contains other objects that each represent part of the FPGA | ||
# circuitry (like switch block, LUT, etc.). | ||
# We use the FPGA object to generate SPICE netlists of the circuitry | ||
# We also use it to calculate area and wire loads | ||
# | ||
# Once the FPGA object is created and the SPICE netlists are generated, | ||
# we pass the FPGA object to COFFE's transistor sizing engine. The following paper | ||
# explains COFFE's transistor sizing algorithm in detail. | ||
# | ||
# [1] C. Chiasson and V.Betz, "COFFE: Fully-Automated Transistor Sizing for FPGAs", FPT2013 | ||
# | ||
|
||
|
||
import os | ||
import sys | ||
import shutil | ||
import argparse | ||
import time | ||
import coffe.fpga as fpga | ||
import coffe.tran_sizing as tran_sizing | ||
import coffe.hspice_extract as hspice_extract | ||
import coffe.utils | ||
|
||
print "\nCOFFE 1.0\n" | ||
print "Man is a tool-using animal." | ||
print "Without tools he is nothing, with tools he is all." | ||
print " - Thomas Carlyle\n\n" | ||
|
||
# Parse the input arguments with argparse | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('arch_description') | ||
parser.add_argument('-n', '--no_sizing', help="don't perform transistor sizing", action='store_true') | ||
parser.add_argument('-o', '--opt_type', type=str, choices=["global", "local"], default="global", help="choose optimization type") | ||
parser.add_argument('-m', '--re_erf', type=int, default=1, help="choose how many sizing combos to re-erf") | ||
parser.add_argument('-a', '--area_opt_weight', type=int, default=1, help="area optimization weight") | ||
parser.add_argument('-d', '--delay_opt_weight', type=int, default=1, help="delay optimization weight") | ||
parser.add_argument('-i', '--max_iterations', type=int, default=6, help="max FPGA sizing iterations") | ||
args = parser.parse_args() | ||
arch_description_filename = args.arch_description | ||
is_size_transistors = not args.no_sizing | ||
opt_type = args.opt_type | ||
re_erf = args.re_erf | ||
area_opt_weight = args.area_opt_weight | ||
delay_opt_weight = args.delay_opt_weight | ||
max_iterations = args.max_iterations | ||
|
||
# Print the options | ||
print "RUN OPTIONS:" | ||
if is_size_transistors: | ||
print "Transistor sizing: on" | ||
else: | ||
print "Transistor sizing: off" | ||
if opt_type == "global": | ||
print "Optimization type: global" | ||
else: | ||
print "Optimization type: local" | ||
print "Number of top combos to re-ERF: " + str(re_erf) | ||
print "Area optimization weight: " + str(area_opt_weight) | ||
print "Delay optimization weight: " + str(delay_opt_weight) | ||
print "Maximum number of sizing iterations: " + str(max_iterations) | ||
print "" | ||
|
||
# Load the input architecture description file | ||
arch_params_dict = coffe.utils.load_arch_params(arch_description_filename) | ||
|
||
# Create some local variables | ||
N = arch_params_dict['N'] | ||
K = arch_params_dict['K'] | ||
W = arch_params_dict['W'] | ||
L = arch_params_dict['L'] | ||
I = arch_params_dict['I'] | ||
Fs = arch_params_dict['Fs'] | ||
Fcin = arch_params_dict['Fcin'] | ||
Fcout = arch_params_dict['Fcout'] | ||
Or = arch_params_dict['Or'] | ||
Ofb = arch_params_dict['Ofb'] | ||
Rsel = arch_params_dict['Rsel'] | ||
Rfb = arch_params_dict['Rfb'] | ||
Fclocal = arch_params_dict['Fclocal'] | ||
vdd = arch_params_dict['vdd'] | ||
vsram = arch_params_dict['vsram'] | ||
vsram_n = arch_params_dict['vsram_n'] | ||
gate_length = arch_params_dict['gate_length'] | ||
min_tran_width = arch_params_dict['min_tran_width'] | ||
min_width_tran_area = arch_params_dict['min_width_tran_area'] | ||
sram_cell_area = arch_params_dict['sram_cell_area'] | ||
model_path = arch_params_dict['model_path'] | ||
model_library = arch_params_dict['model_library'] | ||
metal_stack = arch_params_dict['metal'] | ||
|
||
# Record start time | ||
total_start_time = time.time() | ||
|
||
# Create an FPGA instance | ||
fpga_inst = fpga.FPGA(N, K, W, L, I, Fs, Fcin, Fcout, Fclocal, Or, Ofb, Rsel, Rfb, | ||
vdd, vsram, vsram_n, | ||
gate_length, | ||
min_tran_width, | ||
min_width_tran_area, | ||
sram_cell_area, | ||
model_path, | ||
model_library, | ||
metal_stack) | ||
|
||
# Print basic FPGA specs | ||
fpga_inst.print_specs() | ||
|
||
############################################################### | ||
## GENERATE FILES | ||
############################################################### | ||
|
||
# Make the top-level spice folder if it doesn't already exist | ||
arch_desc_words = arch_description_filename.split('.') | ||
arch_folder = arch_desc_words[0] | ||
if not os.path.exists(arch_folder): | ||
os.mkdir(arch_folder) | ||
else: | ||
# Delete contents of sub-directories | ||
# COFFE generates several 'intermediate results' files during sizing | ||
# so we delete them to avoid from having them pile up if we run COFFE | ||
# more than once. | ||
dir_contents = os.listdir(arch_folder) | ||
for content in dir_contents: | ||
if os.path.isdir(arch_folder + "/" + content): | ||
shutil.rmtree(arch_folder + "/" + content) | ||
|
||
# Change to the architecture directory | ||
os.chdir(arch_folder) | ||
|
||
# Generate FPGA and associated SPICE files | ||
fpga_inst.generate(is_size_transistors) | ||
|
||
# Print FPGA implementation details | ||
fpga_inst.print_details() | ||
|
||
############################################################### | ||
## TRANSISTOR SIZING | ||
############################################################### | ||
|
||
# Size FPGA transistors | ||
num_hspice_sims = 0 | ||
if is_size_transistors: | ||
num_hspice_sims = tran_sizing.size_fpga_transistors(fpga_inst, | ||
opt_type, | ||
re_erf, | ||
max_iterations, | ||
area_opt_weight, | ||
delay_opt_weight, | ||
num_hspice_sims) | ||
|
||
# Update subcircuit delays (these are the final values) | ||
num_hspice_sims = fpga_inst.update_delays(num_hspice_sims) | ||
|
||
print "|------------------------------------------------------------------------------|" | ||
print "| Area and Delay Report |" | ||
print "|------------------------------------------------------------------------------|" | ||
print "" | ||
|
||
# Print area and delay per subcircuit | ||
coffe.utils.print_area_and_delay(fpga_inst) | ||
|
||
# Print block areas | ||
coffe.utils.print_block_area(fpga_inst) | ||
|
||
# Print VPR delays (to be used to make architecture file) | ||
coffe.utils.print_vpr_delays(fpga_inst) | ||
|
||
# Print VPR areas (to be used to make architecture file) | ||
coffe.utils.print_vpr_areas(fpga_inst) | ||
|
||
# Print area and delay summary | ||
final_cost = fpga_inst.area_dict["tile"]*fpga_inst.delay_dict["rep_crit_path"] | ||
print " SUMMARY" | ||
print " -------" | ||
print " Tile Area " + str(round(fpga_inst.area_dict["tile"]/1e6,2)) + " um^2" | ||
print " Representative Critical Path Delay " + str(round(fpga_inst.delay_dict["rep_crit_path"]*1e12,2)) + " ps" | ||
print (" Cost (area^" + str(area_opt_weight) + " x delay^" + str(delay_opt_weight) + ") " | ||
+ str(round(final_cost,5))) | ||
|
||
print "" | ||
print "|------------------------------------------------------------------------------|" | ||
print "" | ||
|
||
# Come back to top level directory | ||
os.chdir("../") | ||
|
||
# Record end time | ||
total_end_time = time.time() | ||
total_time_elapsed = total_end_time - total_start_time | ||
total_hours_elapsed = int(total_time_elapsed/3600) | ||
total_minutes_elapsed = int((total_time_elapsed-3600*total_hours_elapsed)/60) | ||
total_seconds_elapsed = int(total_time_elapsed - 3600*total_hours_elapsed - 60*total_minutes_elapsed) | ||
|
||
print "Number of HSPICE simulations performed: " + str(num_hspice_sims) | ||
print "Total time elapsed: " + str(total_hours_elapsed) + " hours " + str(total_minutes_elapsed) + " minutes " + str(total_seconds_elapsed) + " seconds\n" |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
def inverter_generate(filename): | ||
""" Generates the SPICE subcircuit for an inverter. Appends it to file 'filename'. """ | ||
|
||
# Open the file for appending | ||
spice_file = open(filename, 'a') | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write("* Inverter\n") | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write(".SUBCKT inv n_in n_out n_vdd n_gnd Wn=45n Wp=45n\n") | ||
spice_file.write("MNDOWN n_out n_in n_gnd n_gnd nmos L=gate_length W=Wn\n") | ||
spice_file.write("MPUP n_out n_in n_vdd n_vdd pmos L=gate_length W=Wp\n") | ||
spice_file.write(".ENDS\n\n\n") | ||
spice_file.close() | ||
|
||
|
||
def rest_generate(filename): | ||
""" Generates the SPICE subcircuit for a level-restorer. Appends it to file 'filename'. """ | ||
|
||
# Open the file for appending | ||
spice_file = open(filename, 'a') | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write("* Level-restorer PMOS\n") | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write(".SUBCKT rest n_pull n_gate n_vdd n_gnd Wp=45n\n") | ||
spice_file.write("MPREST n_pull n_gate n_vdd n_vdd pmos L=gate_length W=Wp\n") | ||
spice_file.write(".ENDS\n\n\n") | ||
spice_file.close() | ||
|
||
|
||
def wire_generate(filename): | ||
""" Generates the SPICE subcircuit for a wire. Appends it to file 'filename'. """ | ||
|
||
# Open the file for appending | ||
spice_file = open(filename, 'a') | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write("* Interconnect wire\n") | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write(".SUBCKT wire n_in n_out Rw=1 Cw=1\n") | ||
spice_file.write("CWIRE_1 n_in gnd Cw\n") | ||
spice_file.write("RWIRE_1 n_in n_out Rw\n") | ||
spice_file.write("CWIRE_2 n_out gnd Cw\n") | ||
spice_file.write(".ENDS\n\n\n") | ||
spice_file.close() | ||
|
||
|
||
def ptran_generate(filename): | ||
""" Generates the SPICE subcircuit for a pass-transistor. Appends it to file 'filename'. """ | ||
|
||
# Open the file for appending | ||
spice_file = open(filename, 'a') | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write("* Pass-transistor\n") | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write(".SUBCKT ptran n_in n_out n_gate n_gnd Wn=45n\n") | ||
spice_file.write("MNPASS n_in n_gate n_out n_gnd nmos L=gate_length W=Wn\n") | ||
spice_file.write(".ENDS\n\n\n") | ||
spice_file.close() | ||
|
||
|
||
def tgate_generate(filename): | ||
""" Generates the SPICE subcircuit for a transmission gate. Appends it to file 'filename'. """ | ||
|
||
# Open the file for appending | ||
spice_file = open(filename, 'a') | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write("* Transmission gate\n") | ||
spice_file.write("******************************************************************************************\n") | ||
spice_file.write(".SUBCKT tgate n_in n_out n_gate_nmos n_gate_pmos n_vdd n_gnd Wn=45n Wp=45n\n") | ||
spice_file.write("MNTGATE n_in n_gate_nmos n_out n_gnd nmos L=gate_length W=Wn\n") | ||
spice_file.write("MPTGATE n_in n_gate_pmos n_out n_vdd pmos L=gate_length W=Wp\n") | ||
spice_file.write(".ENDS\n\n\n") | ||
spice_file.close() |
Oops, something went wrong.