OpenFPGA/vpr7_x2p/libarchfpga/read_xml_spice.c

1327 lines
51 KiB
C

#include <string.h>
#include <assert.h>
#include "util.h"
#include "arch_types.h"
#include "ReadLine.h"
#include "ezxml.h"
#include "read_xml_util.h"
/* SPICE Support headers*/
#include "read_xml_spice_util.h"
#include "read_xml_spice.h"
/*********** Subroutines Declaration (only called in this source file) **********/
static void ProcessSpiceMeasParams(ezxml_t Parent,
t_spice_meas_params* meas_params);
static void ProcessSpiceStimulateParamsRiseFall(ezxml_t Parent,
float* rise_param,
float* fall_param,
enum e_spice_accuracy_type* rise_type,
enum e_spice_accuracy_type* fall_type);
static void ProcessSpiceStimulateParams(ezxml_t Parent,
t_spice_stimulate_params* stimulate_params);
static void ProcessSpiceParams(ezxml_t Parent,
t_spice_params* spice_params);
static void ProcessSpiceModel(ezxml_t Parent,
t_spice_model* spice_model);
static void ProcessSpiceModelPort(ezxml_t Node,
t_spice_model_port* port);
static void ProcessSpiceModelPassGateLogic(ezxml_t Node,
t_spice_model_pass_gate_logic* pass_gate_logic);
static void ProcessSpiceModelBuffer(ezxml_t Node,
t_spice_model_buffer* buffer);
static void ProcessSpiceTransistorType(ezxml_t Parent,
t_spice_transistor_type* spice_trans,
enum e_spice_trans_type trans_type);
static void ProcessSpiceTechLibTransistors(ezxml_t Parent,
t_spice_tech_lib* spice_tech_lib);
static
void ProcessSpiceSRAMOrganization(INOUTP ezxml_t Node,
OUTP t_sram_inf_orgz* cur_sram_inf_orgz,
boolean required);
/************ Subroutines***********/
static void ProcessSpiceMeasParams(ezxml_t Parent,
t_spice_meas_params* meas_params) {
ezxml_t Node, Cur;
/* Check */
if (meas_params == NULL) {
vpr_printf(TIO_MESSAGE_ERROR,"(File: %s,[LINE%d])meas_params is NULL!\n", __FILE__, __LINE__);
exit(1);
}
/* Number of simulation clock cycles */
if (0 == strcmp("auto", FindProperty(Parent, "sim_num_clock_cycle", FALSE))) {
meas_params->sim_num_clock_cycle = -1;
meas_params->auto_select_sim_num_clk_cycle = TRUE;
} else {
meas_params->sim_num_clock_cycle = GetIntProperty(Parent, "sim_num_clock_cycle", FALSE, -1);
meas_params->auto_select_sim_num_clk_cycle = FALSE;
}
ezxml_set_attr(Parent, "sim_num_clock_cycle", NULL);
/* Accuracy type: either frac or abs, set frac by default*/
if (NULL == FindProperty(Parent, "accuracy_type", FALSE)) {
meas_params->accuracy_type = SPICE_ABS;
meas_params->accuracy = 1e-13;
} else {
if (0 == strcmp(FindProperty(Parent, "accuracy_type", TRUE), "abs")) {
meas_params->accuracy_type = SPICE_ABS;
} else if (0 == strcmp(FindProperty(Parent, "accuracy_type", TRUE), "frac")) {
meas_params->accuracy_type = SPICE_FRAC;
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid accuracy_type at ARCH_XML[LINE%d]! Expect [frac|abs].\n",
__FILE__, __LINE__, Parent->line);
}
meas_params->accuracy = GetFloatProperty(Parent, "accuracy", TRUE, 1e-13);
}
ezxml_set_attr(Parent, "accuracy", NULL);
ezxml_set_attr(Parent, "accuracy_type", NULL);
/* Process slew parameters*/
Node = FindElement(Parent, "slew", FALSE);
if (Node) {
/* Find rise*/
Cur = FindElement(Node, "rise", FALSE);
if (Cur) {
/* Search for properties*/
/* Rise */
meas_params->slew_upper_thres_pct_rise = GetFloatProperty(Cur, "upper_thres_pct", TRUE, 0.9);
ezxml_set_attr(Cur, "upper_thres_pct", NULL);
meas_params->slew_lower_thres_pct_rise = GetFloatProperty(Cur, "lower_thres_pct", TRUE, 0.1);
ezxml_set_attr(Cur, "lower_thres_pct", NULL);
/* Free */
FreeNode(Cur);
}
/* Find fall*/
Cur = FindElement(Node, "fall", FALSE);
if (Cur) {
meas_params->slew_upper_thres_pct_fall = GetFloatProperty(Cur, "upper_thres_pct", TRUE, 0.1);
ezxml_set_attr(Cur, "upper_thres_pct", NULL);
meas_params->slew_lower_thres_pct_fall = GetFloatProperty(Cur, "lower_thres_pct", TRUE, 0.9);
ezxml_set_attr(Cur, "lower_thres_pct", NULL);
/* Free */
FreeNode(Cur);
}
FreeNode(Node);
}
/* Process delay parameters*/
Node = FindElement(Parent, "delay", FALSE);
if (Node) {
/* Find rise*/
Cur = FindElement(Node, "rise", FALSE);
if (Cur) {
/* Search for properties*/
/* Rise */
meas_params->input_thres_pct_rise = GetFloatProperty(Cur, "input_thres_pct", TRUE, 0.5);
ezxml_set_attr(Cur, "input_thres_pct", NULL);
meas_params->output_thres_pct_rise = GetFloatProperty(Cur, "output_thres_pct", TRUE, 0.5);
ezxml_set_attr(Cur, "output_thres_pct", NULL);
/* Free */
FreeNode(Cur);
}
/* Find fall*/
Cur = FindElement(Node, "fall", FALSE);
if (Cur) {
meas_params->input_thres_pct_fall = GetFloatProperty(Cur, "input_thres_pct", TRUE, 0.5);
ezxml_set_attr(Cur, "input_thres_pct", NULL);
meas_params->output_thres_pct_fall = GetFloatProperty(Cur, "output_thres_pct", TRUE, 0.5);
ezxml_set_attr(Cur, "output_thres_pct", NULL);
/* Free */
FreeNode(Cur);
}
FreeNode(Node);
}
return;
}
static void ProcessSpiceStimulateParamsRiseFall(ezxml_t Parent,
float* rise_param,
float* fall_param,
enum e_spice_accuracy_type* rise_type,
enum e_spice_accuracy_type* fall_type) {
ezxml_t Node;
/* Check */
assert(NULL != rise_param);
assert(NULL != fall_param);
assert(NULL != rise_type);
assert(NULL != fall_type);
/* initial to 0 */
(*rise_param) = 0.;
(*fall_param) = 0.;
(*rise_type) = SPICE_FRAC;
(*fall_type) = SPICE_FRAC;
/* Rise parameters */
Node = FindElement(Parent, "rise", TRUE);
if (Node) {
if (0 == strcmp("frac", FindProperty(Node, "slew_type", TRUE))) {
(*rise_type) = SPICE_FRAC;
} else if (0 == strcmp("abs", FindProperty(Node, "slew_type", TRUE))) {
(*rise_type) = SPICE_ABS;
} else {
vpr_printf(TIO_MESSAGE_ERROR, "Property(%s) should be defined in [LINE%d]!\n",
"slew_type" ,Node->line);
exit(1);
}
(*rise_param) = GetFloatProperty(Node, "slew_time", TRUE, 0.05);
ezxml_set_attr(Node, "slew_time", NULL);
ezxml_set_attr(Node, "slew_type", NULL);
/* Free */
FreeNode(Node);
}
/* Fall parameters */
Node = FindElement(Parent, "fall", TRUE);
if (Node) {
if (0 == strcmp("frac", FindProperty(Node, "slew_type", TRUE))) {
(*fall_type) = SPICE_FRAC;
} else if (0 == strcmp("abs", FindProperty(Node, "slew_type", TRUE))) {
(*fall_type) = SPICE_ABS;
} else {
vpr_printf(TIO_MESSAGE_ERROR, "Property(%s) should be defined in [LINE%d]!\n",
"slew_type" ,Node->line);
exit(1);
}
(*fall_param) = GetFloatProperty(Node, "slew_time", TRUE, 0.05);
ezxml_set_attr(Node, "slew_time", NULL);
ezxml_set_attr(Node, "slew_type", NULL);
/* Free */
FreeNode(Node);
}
return;
}
static void ProcessSpiceStimulateParams(ezxml_t Parent,
t_spice_stimulate_params* stimulate_params) {
ezxml_t Node;
/* Check */
if (stimulate_params == NULL) {
vpr_printf(TIO_MESSAGE_ERROR,"(File: %s,[LINE%d])stimulate_params is NULL!\n", __FILE__, __LINE__);
exit(1);
}
/* Find Clock */
Node = FindElement(Parent, "clock", FALSE);
if (Node) {
/* op_freq, sim_slack, prog_freq */
stimulate_params->op_clock_freq = OPEN;
/* op_freq (operation clock frequency) must be defined, either as a number or as "auto" */
if (0 == strcmp("auto", FindProperty(Node, "op_freq", TRUE))) {
/* We need a sim_slack */
} else {
stimulate_params->op_clock_freq = GetFloatProperty(Node, "op_freq", TRUE, OPEN);
/* We do not need a sim_slack */
}
ezxml_set_attr(Node, "op_freq", NULL);
/* Read sim_slack */
stimulate_params->sim_clock_freq_slack = GetFloatProperty(Node, "sim_slack", FALSE, 0.2);
ezxml_set_attr(Node, "sim_slack", NULL);
/* Read prog_freq (programming clock frequency): mandatory! */
stimulate_params->prog_clock_freq = GetFloatProperty(Node, "prog_freq", TRUE, OPEN);
/* For rising/falling slew */
ProcessSpiceStimulateParamsRiseFall(Node, &(stimulate_params->clock_slew_rise_time), &(stimulate_params->clock_slew_fall_time), &(stimulate_params->clock_slew_rise_type), &(stimulate_params->clock_slew_fall_type));
/* Free */
FreeNode(Node);
}
/* Find input */
Node = FindElement(Parent, "input", FALSE);
if (Node) {
/* Free */
/* For rising/falling slew */
ProcessSpiceStimulateParamsRiseFall(Node, &(stimulate_params->input_slew_rise_time), &(stimulate_params->input_slew_fall_time), &(stimulate_params->input_slew_rise_type), &(stimulate_params->input_slew_fall_type));
FreeNode(Node);
}
return;
}
static void ProcessSpiceMCVariationParams(ezxml_t Parent,
t_spice_mc_variation_params* variation_params) {
/* Check */
if (variation_params == NULL) {
vpr_printf(TIO_MESSAGE_ERROR,"(File: %s,[LINE%d])variation_params is NULL!\n",
__FILE__, __LINE__);
exit(1);
}
variation_params->abs_variation = GetFloatProperty(Parent, "abs_variation", TRUE, 0);
ezxml_set_attr(Parent, "abs_variation", NULL);
variation_params->num_sigma = GetIntProperty(Parent, "num_sigma", TRUE, 1);
ezxml_set_attr(Parent, "num_sigma", NULL);
return;
}
static void ProcessSpiceMonteCarloParams(ezxml_t Parent,
t_spice_mc_params* mc_params) {
ezxml_t Node;
/* Check */
if (mc_params == NULL) {
vpr_printf(TIO_MESSAGE_ERROR,"(File: %s,[LINE%d])mc_params is NULL!\n",
__FILE__, __LINE__);
exit(1);
}
mc_params->mc_sim = FALSE;
if (0 == strcmp("on", FindProperty(Parent, "mc_sim", TRUE))) {
mc_params->mc_sim = TRUE;
}
ezxml_set_attr(Parent, "mc_sim", NULL);
mc_params->num_mc_points = GetIntProperty(Parent, "num_mc_points", mc_params->mc_sim, 1);
ezxml_set_attr(Parent, "num_mc_points", NULL);
/* Process CMOS variations */
mc_params->cmos_variation.variation_on = FALSE;
if (NULL == FindProperty(Parent, "cmos_variation", FALSE)) {
mc_params->cmos_variation.variation_on = FALSE;
} else if (0 == strcmp("on", FindProperty(Parent, "cmos_variation", FALSE))) {
mc_params->cmos_variation.variation_on = TRUE;
}
Node = FindElement(Parent, "cmos", mc_params->cmos_variation.variation_on);
if (Node) {
ProcessSpiceMCVariationParams(Node, &(mc_params->cmos_variation));
FreeNode(Node);
}
ezxml_set_attr(Parent, "cmos_variation", NULL);
mc_params->rram_variation.variation_on = FALSE;
if (NULL == FindProperty(Parent, "rram_variation", FALSE)) {
mc_params->rram_variation.variation_on = FALSE;
} else if (0 == strcmp("on", FindProperty(Parent, "rram_variation", FALSE))) {
mc_params->rram_variation.variation_on = TRUE;
}
Node = FindElement(Parent, "rram", mc_params->rram_variation.variation_on);
if (Node) {
ProcessSpiceMCVariationParams(Node, &(mc_params->rram_variation));
FreeNode(Node);
}
ezxml_set_attr(Parent, "rram_variation", NULL);
mc_params->wire_variation.variation_on = FALSE;
if (NULL == FindProperty(Parent, "wire_variation", FALSE)) {
mc_params->wire_variation.variation_on = FALSE;
} else if (0 == strcmp("on", FindProperty(Parent, "wire_variation", FALSE))) {
mc_params->wire_variation.variation_on = TRUE;
}
Node = FindElement(Parent, "wire", mc_params->wire_variation.variation_on);
if (Node) {
ProcessSpiceMCVariationParams(Node, &(mc_params->wire_variation));
FreeNode(Node);
}
ezxml_set_attr(Parent, "wire_variation", NULL);
return;
}
static void ProcessSpiceParams(ezxml_t Parent,
t_spice_params* spice_params) {
ezxml_t Node;
InitSpiceParams(spice_params);
/* Check */
if (spice_params == NULL) {
vpr_printf(TIO_MESSAGE_ERROR,"(File: %s,[LINE%d])spice_params is NULL!\n", __FILE__, __LINE__);
exit(1);
}
/* Options*/
Node = FindElement(Parent, "options", FALSE);
if (Node) {
spice_params->sim_temp = GetIntProperty(Node, "sim_temp", TRUE, 25);
ezxml_set_attr(Node, "sim_temp", NULL);
/* OPTION post */
if (0 == strcmp("on", FindProperty(Node, "post", TRUE))) {
spice_params->post = TRUE;
} else if (0 == strcmp("off", FindProperty(Node, "post", TRUE))) {
spice_params->post = FALSE;
} else {
vpr_printf(TIO_MESSAGE_INFO, "Invalid value for post(Arch_file, LINE[%d])!\n", Node->line);
exit(1);
}
ezxml_set_attr(Node, "post", NULL);
/* OPTION captab */
if (0 == strcmp("on", FindProperty(Node, "captab", TRUE))) {
spice_params->captab = TRUE;
} else if (0 == strcmp("off", FindProperty(Node, "captab", TRUE))) {
spice_params->captab = FALSE;
} else {
vpr_printf(TIO_MESSAGE_INFO, "Invalid value for captab(Arch_file, LINE[%d])!\n", Node->line);
exit(1);
}
ezxml_set_attr(Node, "captab", NULL);
/* OPTION fast */
if (0 == strcmp("on", FindProperty(Node, "fast", TRUE))) {
spice_params->fast = TRUE;
} else if (0 == strcmp("off", FindProperty(Node, "fast", TRUE))) {
spice_params->fast = FALSE;
} else {
vpr_printf(TIO_MESSAGE_INFO, "Invalid value for fast(Arch_file, LINE[%d])!\n", Node->line);
exit(1);
}
ezxml_set_attr(Node, "fast", NULL);
/* Free*/
FreeNode(Node);
}
/* Process Monte Carlo Settings */
Node = FindElement(Parent, "monte_carlo", FALSE);
if (Node) {
ProcessSpiceMonteCarloParams(Node, &(spice_params->mc_params));
FreeNode(Node);
}
/* Process measure parameters*/
Node = FindElement(Parent, "measure", FALSE);
if (Node) {
ProcessSpiceMeasParams(Node, &(spice_params->meas_params));
FreeNode(Node);
}
/* Process stimulate parameters*/
Node = FindElement(Parent, "stimulate", FALSE);
if (Node) {
ProcessSpiceStimulateParams(Node, &(spice_params->stimulate_params));
FreeNode(Node);
}
return;
}
static void ProcessSpiceTransistorType(ezxml_t Parent,
t_spice_transistor_type* spice_trans,
enum e_spice_trans_type trans_type) {
if (spice_trans == NULL) {
vpr_printf(TIO_MESSAGE_ERROR,"ProcessSpiceTransistorType: spice_trans is NULL!\n");
exit(1);
}
spice_trans->type = trans_type;
spice_trans->model_name = my_strdup(FindProperty(Parent, "model_name", TRUE));
ezxml_set_attr(Parent, "model_name", NULL);
spice_trans->chan_length = GetFloatProperty(Parent,"chan_length",TRUE,0);
ezxml_set_attr(Parent, "chan_length", NULL);
spice_trans->min_width = GetFloatProperty(Parent,"min_width",TRUE,0);
ezxml_set_attr(Parent, "min_width", NULL);
}
static void ProcessSpiceModelBuffer(ezxml_t Node,
t_spice_model_buffer* buffer) {
boolean read_buf_info = FALSE;
boolean read_spice_model = FALSE;
char* Prop = NULL;
/* Be smart to find all the details */
/* Find "exist"*/
Prop = my_strdup(FindProperty(Node, "exist", FALSE));
if (NULL == Prop) {
buffer->exist = 0;
} else if (0 == strcmp(Prop,"on")) {
buffer->exist = 1;
} else if (0 == strcmp(Prop,"off")) {
buffer->exist = 0;
}
ezxml_set_attr(Node, "exist", NULL);
/* If buffer existed, we need to further find the spice_model_name */
if (1 == buffer->exist) {
read_buf_info = FALSE;
read_spice_model = TRUE;
} else if (0 == strcmp("design_technology", Node->name)) {
/* Only under the design technology Node, this contains buffer information */
read_buf_info = TRUE;
read_spice_model = FALSE;
}
buffer->spice_model_name = my_strdup(FindProperty(Node, "circuit_model_name", read_spice_model));
ezxml_set_attr(Node, "circuit_model_name", NULL);
/*Find Type*/
Prop = my_strdup(FindProperty(Node, "topology", read_buf_info));
if (NULL != Prop) {
if (0 == strcmp(Prop,"inverter")) {
buffer->type = SPICE_MODEL_BUF_INV;
} else if (0 == strcmp(Prop,"buffer")) {
buffer->type = SPICE_MODEL_BUF_BUF;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid value for type in input_buffer. Should be [inverter|buffer].\n",
Node->line);
exit(1);
}
}
ezxml_set_attr(Node, "topology", NULL);
/*Find Tapered*/
Prop = my_strdup(FindProperty(Node, "tapered", read_buf_info));
if (NULL != Prop) {
if (0 == strcmp(Prop,"on")) {
buffer->tapered_buf = 1;
/* Try to dig more properites ...*/
buffer->tap_buf_level = GetIntProperty(Node, "tap_drive_level", TRUE, 1);
buffer->f_per_stage = GetIntProperty(Node, "f_per_stage", FALSE, 4);
ezxml_set_attr(Node, "tap_drive_level", NULL);
ezxml_set_attr(Node, "f_per_stage", NULL);
} else if (0 == strcmp(FindProperty(Node,"tapered",TRUE),"off")) {
buffer->tapered_buf = 0;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid value for tapered buffer. Should be [on|off].\n",
Node->line);
exit(1);
}
}
ezxml_set_attr(Node, "tapered", NULL);
/* Find size*/
buffer->size = GetFloatProperty(Node, "size", read_buf_info, 0.);
ezxml_set_attr(Node, "size", NULL);
return;
}
static void ProcessSpiceModelPassGateLogic(ezxml_t Node,
t_spice_model_pass_gate_logic* pass_gate_logic) {
if (0 == strcmp(FindProperty(Node,"topology",TRUE),"transmission_gate")) {
pass_gate_logic->type = SPICE_MODEL_PASS_GATE_TRANSMISSION;
} else if (0 == strcmp(FindProperty(Node,"topology",TRUE),"pass_transistor")) {
pass_gate_logic->type = SPICE_MODEL_PASS_GATE_TRANSISTOR;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid topology of pass_gate_logic. Should be [transmission_gate|pass_transistor].\n",
Node->line);
exit(1);
}
ezxml_set_attr(Node, "topology", NULL);
pass_gate_logic->nmos_size = GetFloatProperty(Node,"nmos_size",TRUE,0);
ezxml_set_attr(Node, "nmos_size", NULL);
/* If the type of pass_gate_logic is pass transistor,
* the pmos_size is the size of level-restorer at the output node
*/
pass_gate_logic->pmos_size = GetFloatProperty(Node,"pmos_size",TRUE,0);
ezxml_set_attr(Node, "pmos_size", NULL);
return;
}
static void ProcessSpiceModelPort(ezxml_t Node,
t_spice_model_port* port) {
if (0 == strcmp(FindProperty(Node,"type",TRUE),"input")) {
port->type = SPICE_MODEL_PORT_INPUT;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"output")) {
port->type = SPICE_MODEL_PORT_OUTPUT;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"clock")) {
port->type = SPICE_MODEL_PORT_CLOCK;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"sram")) {
port->type = SPICE_MODEL_PORT_SRAM;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"bl")) {
port->type = SPICE_MODEL_PORT_BL;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"wl")) {
port->type = SPICE_MODEL_PORT_WL;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"blb")) {
port->type = SPICE_MODEL_PORT_BLB;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"wlb")) {
port->type = SPICE_MODEL_PORT_WLB;
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"inout")) {
port->type = SPICE_MODEL_PORT_INOUT;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid type of port. Should be [input|output|clock|sram|bl|wl].\n",
Node->line);
exit(1);
}
ezxml_set_attr(Node, "type", NULL);
/* Assign prefix and size*/
port->prefix = my_strdup(FindProperty(Node,"prefix",TRUE));
ezxml_set_attr(Node, "prefix", NULL);
port->size = GetIntProperty(Node,"size",TRUE,1);
ezxml_set_attr(Node, "size", NULL);
/* See if this is a mode selector.
* Currently, we only allow a SRAM port to be a mode selector */
if (SPICE_MODEL_PORT_SRAM == port->type) {
port->mode_select = GetBooleanProperty(Node, "mode_select", FALSE, FALSE);
ezxml_set_attr(Node, "mode_select", NULL);
}
/* Assign a default value for a port, which is useful in customizing the SRAM bit of idle LUTs */
port->default_val = GetIntProperty(Node, "default_val", FALSE, 0);
ezxml_set_attr(Node, "default_val", NULL);
/* See if this is a global signal
* We assume that global signals are shared by all the SPICE Model/blocks.
* We need to check if other SPICE model has the same port name
*/
port->is_global = GetBooleanProperty(Node, "is_global", FALSE, FALSE);
ezxml_set_attr(Node, "is_global", NULL);
/* Check if this port is a set or reset port */
port->is_reset = GetBooleanProperty(Node, "is_reset", FALSE, FALSE);
ezxml_set_attr(Node, "is_reset", NULL);
port->is_set = GetBooleanProperty(Node, "is_set", FALSE, FALSE);
ezxml_set_attr(Node, "is_set", NULL);
port->is_prog = GetBooleanProperty(Node, "is_prog", FALSE, FALSE);
ezxml_set_attr(Node, "is_prog", NULL);
/* Check if this port is a config_done port */
port->is_config_enable = GetBooleanProperty(Node, "is_config_enable", FALSE, FALSE);
ezxml_set_attr(Node, "is_config_enable", NULL);
/* Check if this port is linked to another spice_model*/
port->spice_model_name = my_strdup(FindProperty(Node,"circuit_model_name",FALSE));
ezxml_set_attr(Node, "circuit_model_name", NULL);
/* For BL/WL, BLB/WLB ports, we need to get the spice_model for inverters */
if ((SPICE_MODEL_PORT_BL == port->type)
||(SPICE_MODEL_PORT_WL == port->type)
||(SPICE_MODEL_PORT_BLB == port->type)
||(SPICE_MODEL_PORT_WLB == port->type)) {
port->inv_spice_model_name = my_strdup(FindProperty(Node, "inv_circuit_model_name", FALSE));
ezxml_set_attr(Node, "inv_circuit_model_name", NULL);
}
return;
}
static
void ProcessSpiceModelDelayInfo(ezxml_t Node,
t_spice_model_delay_info* cur_delay_info) {
char* delay_str = NULL;
/* Find the type */
if (0 == strcmp(FindProperty(Node, "type", TRUE), "rise")) {
cur_delay_info->type = SPICE_MODEL_DELAY_RISE;
} else if (0 == strcmp(FindProperty(Node, "type", TRUE), "fall")) {
cur_delay_info->type = SPICE_MODEL_DELAY_FALL;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid type of delay_info. Should be [rise|fall].\n",
Node->line);
exit(1);
}
ezxml_set_attr(Node, "type", NULL);
/* Find the input and output ports */
cur_delay_info->in_port_name = my_strdup(FindProperty(Node, "in_port", TRUE));
ezxml_set_attr(Node, "in_port", NULL);
cur_delay_info->out_port_name = my_strdup(FindProperty(Node, "out_port", TRUE));
ezxml_set_attr(Node, "out_port", NULL);
/* Find delay matrix */
cur_delay_info->value = my_strdup(Node->txt);
ezxml_set_txt(Node, "");
return;
}
static void ProcessSpiceModelWireParam(ezxml_t Parent,
t_spice_model_wire_param* wire_param) {
if (0 == strcmp("pie",FindProperty(Parent,"model_type",TRUE))) {
wire_param->type = WIRE_MODEL_PIE;
} else if (0 == strcmp("t",FindProperty(Parent,"model_type",TRUE))) {
wire_param->type = WIRE_MODEL_T;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid type of wire model(%s). Should be [pie|t].\n",
Parent->line,FindProperty(Parent,"model_type",TRUE));
exit(1);
}
ezxml_set_attr(Parent,"model_type",NULL);
wire_param->res_val = GetFloatProperty(Parent,"res_val",TRUE,0);
wire_param->cap_val = GetFloatProperty(Parent,"cap_val",TRUE,0);
wire_param->level = GetIntProperty(Parent,"level",TRUE,0);
ezxml_set_attr(Parent,"res_val",NULL);
ezxml_set_attr(Parent,"cap_val",NULL);
ezxml_set_attr(Parent,"level",NULL);
return;
}
static void ProcessSpiceModel(ezxml_t Parent,
t_spice_model* spice_model) {
ezxml_t Node, Cur;
int iport, i;
/* Basic Information*/
if (0 == strcmp(FindProperty(Parent,"type",TRUE),"mux")) {
spice_model->type = SPICE_MODEL_MUX;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"chan_wire")) {
spice_model->type = SPICE_MODEL_CHAN_WIRE;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"wire")) {
spice_model->type = SPICE_MODEL_WIRE;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"hard_logic")) {
spice_model->type = SPICE_MODEL_HARDLOGIC;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"lut")) {
spice_model->type = SPICE_MODEL_LUT;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"ff")) {
spice_model->type = SPICE_MODEL_FF;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"sram")) {
spice_model->type = SPICE_MODEL_SRAM;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"hard_logic")) {
spice_model->type = SPICE_MODEL_HARDLOGIC;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"sff")) {
spice_model->type = SPICE_MODEL_SCFF;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"iopad")) {
spice_model->type = SPICE_MODEL_IOPAD;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"wire_vdd")) {
spice_model->type = SPICE_MODEL_VDD;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"wire_gnd")) {
spice_model->type = SPICE_MODEL_GND;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"inv_buf")) {
spice_model->type = SPICE_MODEL_INVBUF;
} else if (0 == strcmp(FindProperty(Parent,"type",TRUE),"pass_gate")) {
spice_model->type = SPICE_MODEL_PASSGATE;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid type of spice model(%s). Should be [mux|lut|ff|io|sram|hard_logic|sff].\n",
Parent->line, FindProperty(Parent, "type", TRUE));
exit(1);
}
ezxml_set_attr(Parent, "type", NULL);
spice_model->name = my_strdup(FindProperty(Parent,"name",TRUE));
ezxml_set_attr(Parent, "name", NULL);
spice_model->prefix = my_strdup(FindProperty(Parent,"prefix",TRUE));
ezxml_set_attr(Parent, "prefix", NULL);
/* Find a spice_netlist path if we can*/
spice_model->model_netlist = my_strdup(FindProperty(Parent,"spice_netlist",FALSE));
if (spice_model->model_netlist) {
ezxml_set_attr(Parent, "spice_netlist", NULL);
}
/* Find a verilog_netlist path if we can*/
spice_model->verilog_netlist = my_strdup(FindProperty(Parent,"verilog_netlist",FALSE));
if (spice_model->verilog_netlist) {
ezxml_set_attr(Parent, "verilog_netlist", NULL);
}
/* Find the is_default if we can*/
spice_model->is_default = GetIntProperty(Parent,"is_default",FALSE,0);
ezxml_set_attr(Parent, "default", NULL);
/* Find a verilog_netlist path if we can*/
spice_model->dump_structural_verilog = GetBooleanProperty(Parent,"dump_structural_verilog", FALSE, FALSE);
ezxml_set_attr(Parent, "dump_structural_verilog", NULL);
/* Check the design technology settings*/
Node = ezxml_child(Parent, "design_technology");
if (Node) {
/* Specify if this spice_model is power gated or not*/
spice_model->design_tech_info.power_gated = GetBooleanProperty(Node,"power_gated", FALSE, FALSE);
ezxml_set_attr(Node, "power_gated", NULL);
/* More options*/
if (0 == strcmp(FindProperty(Node,"type",TRUE),"cmos")) {
spice_model->design_tech = SPICE_MODEL_DESIGN_CMOS;
/* If this spice model is an inverter, buffer or pass_gate,
* we need to read more settings
*/
spice_model->design_tech_info.buffer_info = NULL;
spice_model->design_tech_info.pass_gate_info = NULL;
switch (spice_model->type) {
case SPICE_MODEL_INVBUF:
spice_model->design_tech_info.buffer_info = (t_spice_model_buffer*)my_malloc(sizeof(t_spice_model_buffer));
ProcessSpiceModelBuffer(Node,spice_model->design_tech_info.buffer_info);
break;
case SPICE_MODEL_PASSGATE:
spice_model->design_tech_info.pass_gate_info = (t_spice_model_pass_gate_logic*)my_malloc(sizeof(t_spice_model_pass_gate_logic));
ProcessSpiceModelPassGateLogic(Node,spice_model->design_tech_info.pass_gate_info);
break;
default:
break;
}
} else if (0 == strcmp(FindProperty(Node,"type",TRUE),"rram")) {
spice_model->design_tech = SPICE_MODEL_DESIGN_RRAM;
/* RRAM tech. We need more properties*/
spice_model->design_tech_info.ron = GetFloatProperty(Node,"ron",TRUE,0);
ezxml_set_attr(Node, "ron", NULL);
spice_model->design_tech_info.roff = GetFloatProperty(Node,"roff",TRUE,0);
ezxml_set_attr(Node, "roff", NULL);
spice_model->design_tech_info.wprog_set_nmos = GetFloatProperty(Node,"wprog_set_nmos",TRUE,0);
ezxml_set_attr(Node, "wprog_set_nmos", NULL);
spice_model->design_tech_info.wprog_set_pmos = GetFloatProperty(Node,"wprog_set_pmos",TRUE,0);
ezxml_set_attr(Node, "wprog_set_nmos", NULL);
spice_model->design_tech_info.wprog_reset_nmos = GetFloatProperty(Node,"wprog_reset_nmos",TRUE,0);
ezxml_set_attr(Node, "wprog_reset_nmos", NULL);
spice_model->design_tech_info.wprog_reset_pmos = GetFloatProperty(Node,"wprog_reset_pmos",TRUE,0);
ezxml_set_attr(Node, "wprog_reset_pmos", NULL);
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] Invalid value for design_technology in spice model(%s). Should be [cmos|rram].\n",
Node->line,spice_model->name);
exit(1);
}
ezxml_set_attr(Node, "type", NULL);
/* Read in the structure if defined */
if (SPICE_MODEL_MUX == spice_model->type) {
if (0 == strcmp(FindProperty(Node,"structure",TRUE),"tree")) {
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_TREE;
} else if (0 == strcmp(FindProperty(Node,"structure",TRUE),"one-level")) {
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_ONELEVEL;
} else if (0 == strcmp(FindProperty(Node,"structure",TRUE),"multi-level")) {
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_MULTILEVEL;
/* New Structure: crossbar
} else if (0 == strcmp(FindProperty(Node,"structure",TRUE),"crossbar")) {
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_CROSSBAR;
*/
} else {
/* Set default to RRAM MUX */
if (SPICE_MODEL_DESIGN_RRAM == spice_model->design_tech) {
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_ONELEVEL;
} else {
/* Set default to SRAM MUX */
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_TREE;
}
}
} else {
/* Default: tree */
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_TREE;
}
ezxml_set_attr(Node, "structure", NULL);
if (SPICE_MODEL_STRUCTURE_MULTILEVEL == spice_model->design_tech_info.structure) {
spice_model->design_tech_info.mux_num_level = GetIntProperty(Node,"num_level",TRUE,1);
/* For num_level == 1, auto convert to one-level structure */
if (1 == spice_model->design_tech_info.mux_num_level) {
spice_model->design_tech_info.structure = SPICE_MODEL_STRUCTURE_ONELEVEL;
vpr_printf(TIO_MESSAGE_INFO,"[LINE%d] Automatically convert structure of spice model(%s) to one-level.\n",
Node->line, spice_model->name);
}
} else if (SPICE_MODEL_STRUCTURE_ONELEVEL == spice_model->design_tech_info.structure) {
/* Set mux_num_level for other structure: one-level and tree */
spice_model->design_tech_info.mux_num_level = 1;
}
ezxml_set_attr(Node, "num_level", NULL);
/* Specify if should use the advanced 4T1R MUX design */
spice_model->design_tech_info.advanced_rram_design = GetBooleanProperty(Node,"advanced_rram_design", FALSE, FALSE);
ezxml_set_attr(Node, "advanced_rram_design", NULL);
FreeNode(Node);
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] design_technology is expected in spice_model(%s).\n",
Node->line,spice_model->name);
exit(1);
}
/* LUT input_buffers */
Node = ezxml_child(Parent, "lut_input_buffer");
spice_model->lut_input_buffer = NULL;
if (Node) {
/* Malloc the lut_input_buffer */
spice_model->lut_input_buffer = (t_spice_model_buffer*)my_malloc(sizeof(t_spice_model_buffer));
ProcessSpiceModelBuffer(Node,spice_model->lut_input_buffer);
FreeNode(Node);
} else if (SPICE_MODEL_LUT == spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] lut_input_buffer is expected in spice_model(%s).\n",
Parent->line, spice_model->name);
exit(1);
}
/* Input Buffers*/
Node = ezxml_child(Parent, "input_buffer");
spice_model->input_buffer = NULL;
if (Node) {
/*Alloc*/
spice_model->input_buffer = (t_spice_model_buffer*)my_malloc(sizeof(t_spice_model_buffer));
ProcessSpiceModelBuffer(Node,spice_model->input_buffer);
FreeNode(Node);
} else if (SPICE_MODEL_INVBUF != spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] input_buffer is expected in spice_model(%s).\n",
Parent->line,spice_model->name);
exit(1);
}
/* Output Buffers*/
Node = ezxml_child(Parent, "output_buffer");
spice_model->output_buffer = NULL;
if (Node) {
spice_model->output_buffer = (t_spice_model_buffer*)my_malloc(sizeof(t_spice_model_buffer));
ProcessSpiceModelBuffer(Node,spice_model->output_buffer);
FreeNode(Node);
} else if (SPICE_MODEL_INVBUF != spice_model->type) {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] output_buffer is expected in spice_model(%s).\n",
Parent->line,spice_model->name);
exit(1);
}
/* Pass_gate_logic*/
Node = ezxml_child(Parent, "pass_gate_logic");
spice_model->pass_gate_logic = NULL;
if (Node) {
spice_model->pass_gate_logic = (t_spice_model_pass_gate_logic*)my_malloc(sizeof(t_spice_model_pass_gate_logic));
/* Find spice_model_name */
spice_model->pass_gate_logic->spice_model_name = my_strdup(FindProperty(Node, "circuit_model_name", TRUE));
ezxml_set_attr(Node, "circuit_model_name", NULL);
FreeNode(Node);
} else if ((SPICE_MODEL_MUX == spice_model->type)
||(SPICE_MODEL_LUT == spice_model->type)) {
/* We have some exceptions: VDD, GND, dff, sram and hard_logic*/
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] pass_gate_logic is expected in spice_model(%s).\n",
Node->line,spice_model->name);
exit(1);
}
/* Find All the ports*/
spice_model->num_port = CountChildren(Parent, "port", 1);
/*Alloc*/
spice_model->ports = (t_spice_model_port*)my_malloc(spice_model->num_port*sizeof(t_spice_model_port));
/* Assign each found spice model*/
for (iport = 0; iport < spice_model->num_port; iport++) {
Cur = FindFirstElement(Parent, "port", TRUE);
ProcessSpiceModelPort(Cur,&(spice_model->ports[iport]));
FreeNode(Cur);
}
/* Read in wire parameters */
if ((SPICE_MODEL_CHAN_WIRE == spice_model->type)||(SPICE_MODEL_WIRE == spice_model->type)) {
spice_model->wire_param = (t_spice_model_wire_param*)my_malloc(sizeof(t_spice_model_wire_param));
Node = ezxml_child(Parent, "wire_param");
if (Node) {
ProcessSpiceModelWireParam(Node,spice_model->wire_param);
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] wire_param is expected in spice_model(%s).\n",
Node->line,spice_model->name);
exit(1);
}
FreeNode(Node);
}
/* Find delay info */
spice_model->num_delay_info = CountChildren(Parent, "delay_matrix", 0);
/*Alloc*/
spice_model->delay_info = (t_spice_model_delay_info*) my_malloc(spice_model->num_delay_info * sizeof(t_spice_model_delay_info));
/* Assign each found spice model*/
for (i = 0; i < spice_model->num_delay_info; i++) {
Cur = FindFirstElement(Parent, "delay_matrix", TRUE);
ProcessSpiceModelDelayInfo(Cur, &(spice_model->delay_info[i]));
FreeNode(Cur);
}
/* Initialize the counter*/
spice_model->cnt = 0;
return;
}
/* Read XML under the Node of Organization */
static
void ProcessSpiceSRAMOrganization(INOUTP ezxml_t Node,
OUTP t_sram_inf_orgz* cur_sram_inf_orgz,
boolean required) {
const char *Prop;
if (NULL == Node) {
return;
}
cur_sram_inf_orgz->spice_model_name = my_strdup(FindProperty(Node, "circuit_model_name", required));
cur_sram_inf_orgz->spice_model = NULL;
ezxml_set_attr(Node, "circuit_model_name", NULL);
/* read organization type*/
Prop = FindProperty(Node, "organization", required);
if (NULL == Prop) {
cur_sram_inf_orgz->type = SPICE_SRAM_STANDALONE; /* Default */
} else if (0 == strcmp("scan-chain", Prop)) {
cur_sram_inf_orgz->type = SPICE_SRAM_SCAN_CHAIN;
} else if (0 == strcmp("memory_bank", Prop)) {
cur_sram_inf_orgz->type = SPICE_SRAM_MEMORY_BANK;
} else if (0 == strcmp("standalone", Prop)) {
cur_sram_inf_orgz->type = SPICE_SRAM_STANDALONE;
} else {
vpr_printf(TIO_MESSAGE_ERROR,
"[LINE %d] Unknown property %s for SRAM organization\n",
Node->line, FindProperty(Node, "organization", required));
exit(1);
}
ezxml_set_attr(Node, "organization", NULL);
return;
}
/* Read XML under the Node of SRAM */
void ProcessSpiceSRAM(INOUTP ezxml_t Node, OUTP struct s_arch* arch) {
ezxml_t Cur;
/* Process area */
if (NULL == Node) {
return;
}
arch->sram_inf.area = GetFloatProperty(Node, "area", FALSE, 6);
/* Read the SPICE sram organization details */
Cur = FindElement(Node, "spice", arch->read_xml_spice);
if (NULL != Cur) {
/* Malloc */
arch->sram_inf.spice_sram_inf_orgz = (t_sram_inf_orgz*)my_malloc(sizeof(t_sram_inf_orgz));
ProcessSpiceSRAMOrganization(Cur, arch->sram_inf.spice_sram_inf_orgz, arch->read_xml_spice);
FreeNode(Cur);
} else {
arch->sram_inf.spice_sram_inf_orgz = NULL;
}
/* Read the SPICE sram organization details */
Cur = FindElement(Node, "verilog", arch->read_xml_spice);
if (NULL != Cur) {
/* Malloc */
arch->sram_inf.verilog_sram_inf_orgz = (t_sram_inf_orgz*)my_malloc(sizeof(t_sram_inf_orgz));
ProcessSpiceSRAMOrganization(Cur, arch->sram_inf.verilog_sram_inf_orgz, arch->read_xml_spice);
FreeNode(Cur);
} else {
arch->sram_inf.verilog_sram_inf_orgz = NULL;
}
return;
}
/* Check Codes: We should check if we need to define the I/O transistors */
static void check_tech_lib(t_spice_tech_lib tech_lib,
int num_spice_model,
t_spice_model* spice_models) {
int i;
int rram_mux_found = 0;
int io_nmos_found = 0;
int io_pmos_found = 0;
for (i = 0; i < num_spice_model; i++) {
if ((SPICE_MODEL_MUX == spice_models[i].type)
&&(SPICE_MODEL_DESIGN_RRAM == spice_models[i].design_tech)) {
rram_mux_found = 1;
break;
}
}
/* RRAM MUX is not defined, no need to check the tech library*/
if (0 == rram_mux_found) {
return;
}
/* RRAM MUX is defined, check the tech library by searching for io_nmos and io_pmos */
for (i = 0; i < tech_lib.num_transistor_type; i++) {
if (SPICE_TRANS_IO_NMOS == tech_lib.transistor_types[i].type) {
io_nmos_found = 1;
}
if (SPICE_TRANS_IO_PMOS == tech_lib.transistor_types[i].type) {
io_pmos_found = 1;
}
}
if ((0 == io_nmos_found)||(0 == io_pmos_found)) {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s,[LINE%d]) I/O transistors are not defined for RRAM MUX!\nCheck your tech_lib!\n",
__FILE__, __LINE__);
exit(1);
}
return;
}
/* Check Codes: We should check the spice models */
static void check_spice_models(int num_spice_model,
t_spice_model* spice_models) {
int i,j;
int has_sram = 0;
int has_io = 0;
int has_mux = 0;
int has_in_port = 0;
int has_out_port = 0;
int has_clock_port = 0;
int has_sram_port = 0;
for (i = 0; i < num_spice_model; i++) {
/* Check whether spice models share the same name or prefix*/
for (j = 0; j < num_spice_model; j++) {
if (i == j) {
continue;
}
if (0 == strcmp(spice_models[i].prefix,spice_models[j].prefix)) {
vpr_printf(TIO_MESSAGE_ERROR,"Spice model(%s) and (%s) share the same prefix(%s), which is invalid!\n",
spice_models[i].name,spice_models[j].name,spice_models[i].prefix);
exit(1);
}
if (0 == strcmp(spice_models[i].name,spice_models[j].name)) {
vpr_printf(TIO_MESSAGE_ERROR,"Spice model(%s) and (%s) share the same name(%s), which is invalid!\n",
spice_models[i].name,spice_models[j].name,spice_models[i].name);
exit(1);
}
}
/* Check io has been defined and has input and output ports*/
if (SPICE_MODEL_IOPAD == spice_models[i].type) {
has_io = 1;
has_in_port = 0;
has_out_port = 0;
for (j = 0; j < spice_models[i].num_port; j++) {
if (SPICE_MODEL_PORT_INPUT == spice_models[i].ports[j].type) {
has_in_port = 1;
} else if (SPICE_MODEL_PORT_OUTPUT == spice_models[i].ports[j].type) {
has_out_port = 1;
}
}
/* Check if we have two ports*/
if ((0 == has_in_port)||(0 == has_out_port)) {
vpr_printf(TIO_MESSAGE_ERROR,"IO Spice model(%s) does not have input|output port\n",spice_models[i].name);
exit(1);
}
}
/* Check mux has been defined and has input and output ports*/
if (SPICE_MODEL_MUX == spice_models[i].type) {
has_mux = 1;
has_in_port = 0;
has_out_port = 0;
has_sram_port = 0;
for (j = 0; j < spice_models[i].num_port; j++) {
if (SPICE_MODEL_PORT_INPUT == spice_models[i].ports[j].type) {
has_in_port = 1;
} else if (SPICE_MODEL_PORT_OUTPUT == spice_models[i].ports[j].type) {
has_out_port = 1;
} else if (SPICE_MODEL_PORT_SRAM == spice_models[i].ports[j].type) {
has_sram_port = 1;
}
}
/* Check if we have two ports*/
if ((0 == has_in_port)||(0 == has_out_port)||(0 == has_sram_port)) {
vpr_printf(TIO_MESSAGE_ERROR,"MUX Spice model(%s) does not have input|output|sram port\n",spice_models[i].name);
exit(1);
}
/* Check the I/O transistors are defined when RRAM MUX is selected */
if (SPICE_MODEL_DESIGN_RRAM == spice_models[i].design_tech) {
if (!(0. < spice_models[i].design_tech_info.wprog_set_nmos)) {
vpr_printf(TIO_MESSAGE_ERROR, "wprog_set_nmos(%g) should be >0 for a RRAM MUX SPICE model (%s)!\n",
spice_models[i].design_tech_info.wprog_set_nmos, spice_models[i].name);
exit(1);
}
if (!(0. < spice_models[i].design_tech_info.wprog_set_pmos)) {
vpr_printf(TIO_MESSAGE_ERROR, "wprog_set_pmos(%g) should be >0 for a RRAM MUX SPICE model (%s)!\n",
spice_models[i].design_tech_info.wprog_set_pmos, spice_models[i].name);
exit(1);
}
if (!(0. < spice_models[i].design_tech_info.wprog_reset_nmos)) {
vpr_printf(TIO_MESSAGE_ERROR, "wprog_reset_nmos(%g) should be >0 for a RRAM MUX SPICE model (%s)!\n",
spice_models[i].design_tech_info.wprog_reset_nmos, spice_models[i].name);
exit(1);
}
if (!(0. < spice_models[i].design_tech_info.wprog_reset_pmos)) {
vpr_printf(TIO_MESSAGE_ERROR, "wprog_reset_pmos(%g) should be >0 for a RRAM MUX SPICE model (%s)!\n",
spice_models[i].design_tech_info.wprog_reset_pmos, spice_models[i].name);
exit(1);
}
}
}
/* Check sram has been defined and has input and output ports*/
if (SPICE_MODEL_SRAM == spice_models[i].type) {
has_sram = 1;
has_in_port = 0;
has_out_port = 0;
for (j = 0; j < spice_models[i].num_port; j++) {
if (SPICE_MODEL_PORT_INPUT == spice_models[i].ports[j].type) {
has_in_port = 1;
} else if (SPICE_MODEL_PORT_OUTPUT == spice_models[i].ports[j].type) {
has_out_port = 1;
}
}
/* Check if we have two ports*/
if ((0 == has_in_port)||(0 == has_out_port)) {
vpr_printf(TIO_MESSAGE_ERROR,"SRAM Spice model(%s) does not have input|output port\n",spice_models[i].name);
exit(1);
}
}
/* Check dff has input and output, clock ports*/
if (SPICE_MODEL_FF == spice_models[i].type) {
has_clock_port = 0;
has_in_port = 0;
has_out_port = 0;
for (j = 0; j < spice_models[i].num_port; j++) {
if (SPICE_MODEL_PORT_INPUT == spice_models[i].ports[j].type) {
has_in_port = 1;
} else if (SPICE_MODEL_PORT_OUTPUT == spice_models[i].ports[j].type) {
has_out_port = 1;
} else if (SPICE_MODEL_PORT_CLOCK == spice_models[i].ports[j].type) {
has_clock_port = 1;
}
}
/* Check if we have two ports*/
if ((0 == has_in_port)||(0 == has_out_port)||(0 == has_clock_port)) {
vpr_printf(TIO_MESSAGE_ERROR,"FF Spice model(%s) does not have input|output|clock port\n",spice_models[i].name);
exit(1);
}
}
/* Check lut has input and output, clock ports*/
if (SPICE_MODEL_LUT == spice_models[i].type) {
has_sram_port = 0;
has_in_port = 0;
has_out_port = 0;
for (j = 0; j < spice_models[i].num_port; j++) {
if (SPICE_MODEL_PORT_INPUT == spice_models[i].ports[j].type) {
has_in_port = 1;
} else if (SPICE_MODEL_PORT_OUTPUT == spice_models[i].ports[j].type) {
has_out_port = 1;
} else if (SPICE_MODEL_PORT_SRAM == spice_models[i].ports[j].type) {
has_sram_port = 1;
}
}
/* Check if we have two ports*/
if ((0 == has_in_port)||(0 == has_out_port)||(0 == has_sram_port)) {
vpr_printf(TIO_MESSAGE_ERROR,"LUT Spice model(%s) does not have input|output|sram port\n",spice_models[i].name);
exit(1);
}
}
}
if ((0 == has_io)||(0 == has_sram)||(0 == has_mux)) {
vpr_printf(TIO_MESSAGE_ERROR,"At least 1 io,sram,mux spice model should be defined!\n");
exit(1);
}
return;
}
static void ProcessSpiceTechLibTransistors(ezxml_t Parent,
t_spice_tech_lib* spice_tech_lib) {
ezxml_t Node, Cur;
int itrans;
/* TODO: move to a function for this */
/* Check the tech_lib*/
Node = FindElement(Parent, "tech_lib", TRUE);
if (Node) {
/* Check the type first*/
if (0 == strcmp("academia",FindProperty(Node, "lib_type", TRUE))) {
spice_tech_lib->type = SPICE_LIB_ACADEMIA;
} else if (0 == strcmp("industry",FindProperty(Node, "lib_type", TRUE))) {
spice_tech_lib->type = SPICE_LIB_INDUSTRY;
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] tech_lib type should be [industry|academia].\n",
Node->line);
exit(1);
}
ezxml_set_attr(Node, "lib_type", NULL);
if (SPICE_LIB_INDUSTRY == spice_tech_lib->type) {
spice_tech_lib->transistor_type = my_strdup(FindProperty(Node, "transistor_type", TRUE));
}
ezxml_set_attr(Node, "transistor_type", NULL);
spice_tech_lib->path = my_strdup(FindProperty(Node, "lib_path", TRUE));
ezxml_set_attr(Node, "lib_path", NULL);
/* Norminal VDD for standard transistors*/
spice_tech_lib->nominal_vdd = GetFloatProperty(Node, "nominal_vdd", TRUE, 0.);
ezxml_set_attr(Node, "nominal_vdd", NULL);
/* Norminal VDD for IO transistors : by default, give the value of nominal vdd */
spice_tech_lib->io_vdd = GetFloatProperty(Node, "io_vdd", FALSE, spice_tech_lib->nominal_vdd);
ezxml_set_attr(Node, "io_vdd", NULL);
/* Current Node search ends*/
FreeNode(Node);
} else {
vpr_printf(TIO_MESSAGE_ERROR,"[LINE %d] tech_lib does not exist in spice_settings.\n",
Node->line);
exit(1);
}
/* Check the transistors*/
Node = FindElement(Parent, "transistors", TRUE);
if (Node) {
spice_tech_lib->pn_ratio = GetFloatProperty(Node,"pn_ratio", TRUE, 0);
spice_tech_lib->model_ref = my_strdup(FindProperty(Node,"model_ref", TRUE));
ezxml_set_attr(Node, "pn_ratio", NULL);
ezxml_set_attr(Node, "model_ref", NULL);
/* Fill transistor_type number*/
spice_tech_lib->num_transistor_type = 0;
spice_tech_lib->num_transistor_type += CountChildren(Node, "nmos", 1);
assert(1 == spice_tech_lib->num_transistor_type);
spice_tech_lib->num_transistor_type += CountChildren(Node, "pmos", 1);
assert(2 == spice_tech_lib->num_transistor_type);
spice_tech_lib->num_transistor_type += CountChildren(Node, "io_nmos", 0);
spice_tech_lib->num_transistor_type += CountChildren(Node, "io_pmos", 0);
assert((2 == spice_tech_lib->num_transistor_type)||(4 == spice_tech_lib->num_transistor_type));
/*Alloc*/
spice_tech_lib->transistor_types = (t_spice_transistor_type*)my_malloc(spice_tech_lib->num_transistor_type*sizeof(t_spice_transistor_type));
/* Fill Standard NMOS */
itrans = 0;
Cur = FindFirstElement(Node, "nmos", TRUE);
ProcessSpiceTransistorType(Cur,&(spice_tech_lib->transistor_types[itrans]),SPICE_TRANS_NMOS);
FreeNode(Cur);
itrans++;
/* Fill Standard PMOS */
Cur = FindFirstElement(Node, "pmos", TRUE);
ProcessSpiceTransistorType(Cur,&(spice_tech_lib->transistor_types[itrans]),SPICE_TRANS_PMOS);
FreeNode(Cur);
itrans++;
/* Standard NMOS and PMOS are mandatory */
assert(2 == itrans);
/* Fill IO NMOS */
Cur = FindFirstElement(Node, "io_nmos", FALSE);
if (NULL != Cur) {
ProcessSpiceTransistorType(Cur,&(spice_tech_lib->transistor_types[itrans]),SPICE_TRANS_IO_NMOS);
FreeNode(Cur);
itrans++;
vpr_printf(TIO_MESSAGE_INFO, "Read I/O NMOS into tech. lib. successfully.\n");
}
/* Fill IO PMOS */
Cur = FindFirstElement(Node, "io_pmos", FALSE);
if (NULL != Cur) {
ProcessSpiceTransistorType(Cur,&(spice_tech_lib->transistor_types[itrans]),SPICE_TRANS_IO_PMOS);
FreeNode(Cur);
itrans++;
vpr_printf(TIO_MESSAGE_INFO, "Read I/O PMOS into tech. lib. successfully.\n");
}
assert((2 == itrans)||(4 == itrans));
/* Finish parsing this node*/
FreeNode(Node);
}
return;
}
/* Process the SPICE Settings*/
void ProcessSpiceSettings(ezxml_t Parent,
t_spice* spice) {
ezxml_t Node, Cur;
int imodel;
InitSpice(spice);
/* Check the parameters*/
Node = FindElement(Parent, "parameters", FALSE);
if (Node) {
ProcessSpiceParams(Node, &(spice->spice_params));
FreeNode(Node);
}
/* Technology Library and Transistors */
ProcessSpiceTechLibTransistors(Parent, &(spice->tech_lib));
/* module spice models*/
Node = FindElement(Parent, "module_circuit_models", FALSE);
if (Node) {
spice->num_spice_model = CountChildren(Node, "circuit_model", 1);
/*Alloc*/
spice->spice_models = (t_spice_model*)my_malloc(spice->num_spice_model*sizeof(t_spice_model));
/* Assign each found spice model*/
for (imodel = 0; imodel < spice->num_spice_model; imodel++) {
Cur = FindFirstElement(Node, "circuit_model", TRUE);
ProcessSpiceModel(Cur, &(spice->spice_models[imodel]));
FreeNode(Cur);
}
assert(imodel == spice->num_spice_model);
FreeNode(Node);
}
/* Check codes*/
check_tech_lib(spice->tech_lib, spice->num_spice_model, spice->spice_models);
check_spice_models(spice->num_spice_model,spice->spice_models);
return;
}