OpenFPGA/vpr7_x2p/vpr/SRC/fpga_spice/spice/spice_heads.c

271 lines
10 KiB
C

/***********************************/
/* SPICE Modeling for VPR */
/* Xifan TANG, EPFL/LSI */
/***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
/* Include vpr structs*/
#include "util.h"
#include "physical_types.h"
#include "vpr_types.h"
#include "globals.h"
#include "rr_graph.h"
#include "vpr_utils.h"
/* Include spice support headers*/
#include "linkedlist.h"
#include "fpga_spice_globals.h"
#include "spice_globals.h"
#include "fpga_spice_utils.h"
#include "spice_utils.h"
#include "spice_mux.h"
#include "spice_pbtypes.h"
#include "spice_subckt.h"
/* For mrFPGA */
#ifdef MRFPGA_H
#include "mrfpga_globals.h"
#endif
/***** Subroutines Declarations *****/
static
void fprint_spice_meas_header(char* meas_file_name,
t_spice_meas_params spice_meas_params);
static
void fprint_spice_stimulate_header(char* stimulate_file_name,
t_spice_stimulate_params spice_stimulate_params,
float vpr_clock_period,
int num_clock);
/***** Subroutines *****/
/* Print SPICE Netlists header*/
/* Print parameters for measurements */
static
void fprint_spice_meas_header(char* meas_file_name,
t_spice_meas_params spice_meas_params) {
FILE* fp = NULL;
/* Check */
assert(NULL != meas_file_name);
/* Create File */
fp = fopen(meas_file_name, "w");
if (NULL == fp) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Failure in create measure header file %s!\n",
__FILE__, __LINE__, meas_file_name);
exit(1);
}
/* Print parameters */
fprint_spice_head(fp, "Parameters for measurement");
fprintf(fp, "***** Parameters For Slew Measurement *****\n");
fprintf(fp, "***** Rising Edge *****\n");
fprintf(fp, ".param slew_upper_thres_pct_rise=%g\n", spice_meas_params.slew_upper_thres_pct_rise);
fprintf(fp, ".param slew_lower_thres_pct_rise=%g\n", spice_meas_params.slew_lower_thres_pct_rise);
fprintf(fp, "***** Falling Edge *****\n");
fprintf(fp, ".param slew_upper_thres_pct_fall=%g\n", spice_meas_params.slew_upper_thres_pct_fall);
fprintf(fp, ".param slew_lower_thres_pct_fall=%g\n", spice_meas_params.slew_lower_thres_pct_fall);
fprintf(fp, "***** Parameters For Delay Measurement *****\n");
fprintf(fp, "***** Rising Edge *****\n");
fprintf(fp, ".param input_thres_pct_rise=%g\n", spice_meas_params.input_thres_pct_rise);
fprintf(fp, ".param output_thres_pct_rise=%g\n", spice_meas_params.output_thres_pct_rise);
fprintf(fp, "***** Falling Edge *****\n");
fprintf(fp, ".param input_thres_pct_fall=%g\n", spice_meas_params.input_thres_pct_fall);
fprintf(fp, ".param output_thres_pct_fall=%g\n", spice_meas_params.output_thres_pct_fall);
/* Close File */
fclose(fp);
return;
}
/* Print parameters for measurements */
static
void fprint_spice_stimulate_header(char* stimulate_file_name,
t_spice_stimulate_params spice_stimulate_params,
float vpr_clock_period,
int num_clock) {
FILE* fp = NULL;
float sim_clock_freq = 0.;
float sim_clock_period = 0.;
/* Check */
assert(NULL != stimulate_file_name);
/* Create File */
fp = fopen(stimulate_file_name, "w");
if (NULL == fp) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Failure in create stimulate header file %s!\n",
__FILE__, __LINE__, stimulate_file_name);
exit(1);
}
fprint_spice_head(fp, "Parameters for Stimulations");
/* if estimated clock frequency from VPR is 0.
* this is a combinational circuit, clock frequency will never be used
*/
/* if the clock frequency is not specified in architecture file,
* We define the clock frequency with estimated value and slack
*/
fprintf(fp, "***** Frequency *****\n");
sim_clock_freq = spice_stimulate_params.op_clock_freq;
/* Simulate clock frequency should be larger than 0 !*/
assert(0. < sim_clock_freq); /*TODO: check this earlier!!! */
/* vpr_printf(TIO_MESSAGE_INFO, "Use Clock freqency %.2f [MHz] in SPICE simulation.\n", sim_clock_freq/1e6); */
fprintf(fp, ".param clock_period=%g\n", 1. / sim_clock_freq);
sim_clock_period = 1./sim_clock_freq;
/* Print parameters */
fprintf(fp, "***** Parameters For Input Stimulations *****\n");
switch (spice_stimulate_params.input_slew_rise_type) {
case SPICE_ABS:
if (sim_clock_period < (spice_stimulate_params.input_slew_rise_time
+ spice_stimulate_params.input_slew_fall_time)) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid input_slew_rise_time(%.2g), should be smaller than clock period(%.2g)!\n",
__FILE__, __LINE__, spice_stimulate_params.input_slew_rise_time, sim_clock_period);
exit(1);
}
fprintf(fp, ".param input_slew_pct_rise='%g/clock_period'\n", spice_stimulate_params.input_slew_rise_time);
break;
case SPICE_FRAC:
fprintf(fp, ".param input_slew_pct_rise='%g'\n", spice_stimulate_params.input_slew_rise_time);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid input_slew_rise_type!\n",
__FILE__, __LINE__);
exit(1);
}
switch (spice_stimulate_params.input_slew_fall_type) {
case SPICE_ABS:
if (sim_clock_period < (spice_stimulate_params.input_slew_rise_time
+ spice_stimulate_params.input_slew_fall_time)) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid input_slew_fall_time(%.2g), should be smaller than clock period(%.2g)!\n",
__FILE__, __LINE__, spice_stimulate_params.input_slew_fall_time, sim_clock_period);
exit(1);
}
fprintf(fp, ".param input_slew_pct_fall='%g/clock_period'\n", spice_stimulate_params.input_slew_fall_time);
break;
case SPICE_FRAC:
fprintf(fp, ".param input_slew_pct_fall='%g'\n", spice_stimulate_params.input_slew_fall_time);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid input_slew_fall_type!\n",
__FILE__, __LINE__);
exit(1);
}
fprintf(fp, "***** Parameters For Clock Stimulations *****\n");
fprintf(fp, "***** Slew *****\n");
switch (spice_stimulate_params.clock_slew_rise_type) {
case SPICE_ABS:
if (sim_clock_period < (spice_stimulate_params.clock_slew_rise_time
+ spice_stimulate_params.clock_slew_fall_time)) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid clock_slew_rise_time(%.2g)+clock_slew_fall_time(%.2g), should be smaller than clock period(%.2g)!\n",
__FILE__, __LINE__, spice_stimulate_params.clock_slew_rise_time,spice_stimulate_params.clock_slew_fall_time, sim_clock_period);
exit(1);
}
fprintf(fp, ".param clock_slew_pct_rise='%g/clock_period'\n", spice_stimulate_params.clock_slew_rise_time);
break;
case SPICE_FRAC:
fprintf(fp, ".param clock_slew_pct_rise='%g'\n", spice_stimulate_params.clock_slew_rise_time);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid clock_slew_rise_type!\n",
__FILE__, __LINE__);
exit(1);
}
switch (spice_stimulate_params.clock_slew_fall_type) {
case SPICE_ABS:
if (sim_clock_period < (spice_stimulate_params.clock_slew_rise_time
+ spice_stimulate_params.clock_slew_fall_time)) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid clock_slew_rise_time(%.2g)+clock_slew_fall_time(%.2g), should be smaller than clock period(%.2g)!\n",
__FILE__, __LINE__, spice_stimulate_params.clock_slew_rise_time,spice_stimulate_params.clock_slew_fall_time, sim_clock_period);
exit(1);
}
fprintf(fp, ".param clock_slew_pct_fall='%g/clock_period'\n", spice_stimulate_params.clock_slew_fall_time);
break;
case SPICE_FRAC:
fprintf(fp, ".param clock_slew_pct_fall='%g'\n", spice_stimulate_params.clock_slew_fall_time);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Invalid input_slew_fall_type!\n",
__FILE__, __LINE__);
exit(1);
}
fclose(fp);
return;
}
/* Print parameters for circuit designs */
static
void fprint_spice_design_param_header(char* design_param_file_name,
t_spice spice) {
FILE* fp = NULL;
/* Check */
assert(NULL != design_param_file_name);
/* Create File */
fp = fopen(design_param_file_name, "w");
if (NULL == fp) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d])Failure in create design parameter header file %s!\n",
__FILE__, __LINE__, design_param_file_name);
exit(1);
}
fprint_spice_head(fp, "Parameters for Circuit Designs");
fprint_tech_lib(fp,
spice.spice_params.mc_params.cmos_variation,
spice.tech_lib);
/* For transistors */
fprint_spice_circuit_param(fp,
spice.spice_params.mc_params,
spice.num_spice_model,
spice.spice_models);
fclose(fp);
return;
}
void spice_print_headers(char* include_dir_path,
float vpr_clock_period,
int num_clock,
t_spice spice) {
char* formatted_include_dir_path = format_dir_path(include_dir_path);
char* meas_header_file_path = NULL;
char* stimu_header_file_path = NULL;
char* design_param_header_file_path = NULL;
/* measurement header file */
meas_header_file_path = my_strcat(formatted_include_dir_path, meas_header_file_name);
fprint_spice_meas_header(meas_header_file_path, spice.spice_params.meas_params);
/* stimulate header file */
stimu_header_file_path = my_strcat(formatted_include_dir_path, stimu_header_file_name);
fprint_spice_stimulate_header(stimu_header_file_path, spice.spice_params.stimulate_params, vpr_clock_period, num_clock);
/* design parameter header file */
design_param_header_file_path = my_strcat(formatted_include_dir_path, design_param_header_file_name);
fprint_spice_design_param_header(design_param_header_file_path, spice);
return;
}