Several PSPICE 9.1 evaluation digital libraries contain timing .model statements at the global level for subckts with U* instances that reference those models. By specifying "set ps_global_tmodels=1" in .spiceinit an extra pass inside u_instances() will collect those global timing models for use in subckts. Report errors detected when ngspice parses a LOGICEXP but has not added support for operator precendence. Include a hint of how to fix those errors by inserting parentheses. This error only occurs in 10 of 585 cases in the libraries. Note that inpcompat.c has been saved as a unix filetype.

This commit is contained in:
Brian Taylor 2024-01-16 15:29:58 -08:00 committed by Holger Vogt
parent add31fd410
commit a70297e87a
4 changed files with 2288 additions and 2052 deletions

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@
/* Turn off/on debug tracing */
#define PRINT_ALL FALSE
//#define PRINT_ALL TRUE
static char *get_pindly_instance_name(void);
/* Start of btree symbol table */
#define SYM_INPUT 1
@ -1222,7 +1223,18 @@ static BOOL gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols)
if (tok_count != 2) goto gen_error;
} else if (lex_gate_op(val)) {
if (gate_op != 0) {
if (val != gate_op) goto gen_error;
if (val != gate_op) {
fprintf(stderr,
"\nERROR operator precedence parsing is not implemented\n"
" at expression %s\n"
" Please modify the LOGICEXP by inserting parentheses.\n"
" For example change a & b | c & d & e | f\n"
" to (a & b) | (c & d & e) | f\n"
" to get the desired PSPice precedence rules\n",
t->line
);
goto gen_error;
}
}
gate_op = val;
} else {
@ -1570,6 +1582,7 @@ BOOL f_logicexp(char *line)
int t, num_ins = 0, num_outs = 0, i;
char *endp;
BOOL ret_val = TRUE;
char *uname = NULL;
lex_init(line);
current_lexer = parse_lexer;
@ -1577,6 +1590,8 @@ BOOL f_logicexp(char *line)
&parse_lexer->lexer_sym_tab);
t = lex_scan(); // U*
if (!expect_token(t, LEX_ID, NULL, TRUE, 1)) goto error_return;
uname = (char *)TMALLOC(char, strlen(parse_lexer->lexer_buf) + 1);
strcpy(uname, parse_lexer->lexer_buf);
/* logicexp ( int , int ) */
t = lex_scan();
if (!expect_token(t, LEX_ID, "logicexp", TRUE, 2)) goto error_return;
@ -1653,14 +1668,16 @@ BOOL f_logicexp(char *line)
current_lexer = NULL;
if (!ret_val) {
fprintf(stderr, "ERROR parsing logicexp\n");
fprintf(stderr, "ERROR in \"%s\"\n", line);
fprintf(stderr, "ERROR in instance %s\n", uname);
cleanup_parser();
}
if (uname) tfree(uname);
return ret_val;
error_return:
delete_lexer(parse_lexer);
current_lexer = NULL;
if (uname) tfree(uname);
return FALSE;
}
@ -1877,7 +1894,8 @@ static char *get_typ_estimate(char *min, char *typ, char *max, DSTRING *pds)
{
char *tmpmax = NULL, *tmpmin = NULL;
float valmin, valmax, average;
char *units1, *units2;
char *unitsmin, *unitsmax;
char *instance = NULL;
ds_clear(pds);
if (typ && strlen(typ) > 0 && typ[0] != '-') {
@ -1892,12 +1910,33 @@ static char *get_typ_estimate(char *min, char *typ, char *max, DSTRING *pds)
}
if (tmpmin && tmpmax) {
if (strlen(tmpmin) > 0 && strlen(tmpmax) > 0) {
valmin = strtof(tmpmin, &units1);
valmax = strtof(tmpmax, &units2);
average = (valmin + valmax) / (float)2.0;
ds_cat_printf(pds, "%.2f%s", average, units2);
if (!eq(units1, units2)) {
printf("WARNING units do not match\n");
valmin = strtof(tmpmin, &unitsmin);
valmax = strtof(tmpmax, &unitsmax);
if (!eq(unitsmin, unitsmax)) {
printf("WARNING typ_estimate units do not match"
" min %s max %s", tmpmin, tmpmax);
if (unitsmin[0] == unitsmax[0]) {
average = (valmin + valmax) / (float)2.0;
ds_cat_printf(pds, "%.2f%cs", average, unitsmin[0]);
} else if (unitsmin[0] == 'p' && unitsmax[0] == 'n') {
valmax = (float)1000.0 * valmax;
average = (valmin + valmax) / (float)2.0;
ds_cat_printf(pds, "%.2fps", average);
} else if (unitsmin[0] == 'n' && unitsmax[0] == 'p') {
ds_cat_printf(pds, "%.2fns", valmin);
} else {
ds_cat_printf(pds, "%.2f%s", valmin, unitsmin);
}
instance = get_pindly_instance_name();
printf(" using delay %s", ds_get_buf(pds));
if (instance) {
printf(" pindly %s\n", instance);
} else {
printf("\n");
}
} else {
average = (valmin + valmax) / (float)2.0;
ds_cat_printf(pds, "%.2f%s", average, unitsmax);
}
return ds_get_buf(pds);
}
@ -2145,6 +2184,7 @@ static BOOL new_gen_output_models(LEXER lx)
} else if (eq(lx->lexer_buf, "setup_hold")
|| eq(lx->lexer_buf, "width")
|| eq(lx->lexer_buf, "freq")
|| eq(lx->lexer_buf, "boolean")
|| eq(lx->lexer_buf, "general")) {
in_pindly = FALSE;
in_tristate = FALSE;
@ -2160,6 +2200,9 @@ static BOOL new_gen_output_models(LEXER lx)
goto err_return;
}
val = lexer_scan(lx);
if (val == ',') {
val = lexer_scan(lx);
}
}
if (!extract_delay(lx, val, pline_arr, idx, FALSE)) goto err_return;
for (i = 0; i < arrlen; i++) {
@ -2178,11 +2221,15 @@ static BOOL new_gen_output_models(LEXER lx)
if (prit) { printf("tristate enable %s ", lx->lexer_buf); }
val = lexer_scan(lx);
if (val != '=') {
goto err_return;
}
val = lexer_scan(lx);
if (val != LEX_ID) {
goto err_return;
// if there is no '=' it must be an enable id
if (val != LEX_ID) {
goto err_return;
}
} else { // enable id follows '='
val = lexer_scan(lx);
if (val != LEX_ID) {
goto err_return;
}
}
if (prit) { printf("ena \"%s\"\n", lx->lexer_buf); }
ds_clear(&enable_name);
@ -2215,6 +2262,9 @@ static BOOL new_gen_output_models(LEXER lx)
goto err_return;
}
val = lexer_scan(lx);
if (val == ',') {
val = lexer_scan(lx);
}
}
if (!extract_delay(lx, val, pline_arr, idx, TRUE)) goto err_return;
for (i = 0; i < arrlen; i++) {
@ -2236,6 +2286,24 @@ err_return:
return FALSE;
}
static char *pindly_instance_name = NULL;
static void set_pindly_instance_name(char *name)
{
if (pindly_instance_name) {
tfree(pindly_instance_name);
pindly_instance_name = NULL;
}
if (name) {
pindly_instance_name = (char *)TMALLOC(char, strlen(name) + 1);
strcpy(pindly_instance_name, name);
}
}
static char *get_pindly_instance_name(void)
{
return pindly_instance_name;
}
BOOL f_pindly(char *line)
{
int t, num_ios = 0, num_ena = 0, num_refs = 0, i;
@ -2249,6 +2317,7 @@ BOOL f_pindly(char *line)
current_lexer = lxr;
t = lexer_scan(lxr); // U*
if (!expect_token(t, LEX_ID, NULL, TRUE, 50)) goto error_return;
set_pindly_instance_name(lxr->lexer_buf);
/* pindly ( int , int, int ) */
t = lexer_scan(lxr);
@ -2330,20 +2399,25 @@ BOOL f_pindly(char *line)
}
if (!new_gen_output_models(lxr)) {
char *i_name = get_pindly_instance_name();
fprintf(stderr, "ERROR generating models for pindly\n");
fprintf(stderr, "ERROR in \"%s\"\n", line);
if (i_name) {
fprintf(stderr, "ERROR in instance %s\n", i_name);
}
goto error_return;;
}
gen_pindly_buffers();
delete_lexer(lxr);
cleanup_pindly_tab();
current_lexer = NULL;
set_pindly_instance_name(NULL);
return TRUE;
error_return:
delete_lexer(lxr);
cleanup_pindly_tab();
current_lexer = NULL;
set_pindly_instance_name(NULL);
return FALSE;
}

View File

@ -59,12 +59,11 @@
#include "ngspice/udevices.h"
#include "ngspice/logicexp.h"
#include "ngspice/dstring.h"
#include "ngspice/hash.h"
extern struct card* insert_new_line(
struct card* card, char* line, int linenum, int linenum_orig);
//#define TRACE
/* device types */
#define D_AND 0
#define D_AO 1
@ -169,22 +168,22 @@ struct dltch_instance {
};
/* structs for instances and timing models which have been translated */
typedef struct s_xlate *Xlatep;
typedef struct s_xlate *Xlate_datap;
typedef struct s_xlate {
Xlatep next;
Xlate_datap next;
char *translated; // the translated instance line
char *delays; // the delays from the pspice timing model
char *utype; // pspice model type ugate, utgate, ueff, ugff, udly
char *xspice; // xspice device type such as d_and, d_dff, etc.
char *tmodel; // timing model name of pspice instance or model
char *mname; // name of the xspice timing model of the instance
} Xlate;
} Xlate_data;
typedef struct s_xlator *Xlatorp;
typedef struct s_xlator {
Xlatep head;
Xlatep tail;
Xlatep iter;
Xlate_datap head;
Xlate_datap tail;
Xlate_datap iter;
} Xlator;
/* For timing model extraction */
@ -211,10 +210,7 @@ struct name_entry {
static char *get_zero_rise_fall(void);
static char *get_name_hilo(char *tok_str);
#ifdef TRACE
static void print_name_list(NAME_ENTRY nelist);
#endif
static char *get_current_tmodel(void);
static NAME_ENTRY new_name_entry(char *name)
{
@ -261,18 +257,10 @@ static NAME_ENTRY find_name_entry(char *name, NAME_ENTRY nelist)
return NULL;
}
static void clear_name_list(NAME_ENTRY nelist, char *msg)
static void clear_name_list(NAME_ENTRY nelist)
{
NG_IGNORE(msg);
NAME_ENTRY x = NULL, next = NULL;
if (!nelist) { return; }
#ifdef TRACE
printf("%s\n", msg);
print_name_list(nelist);
#else
(void)msg;
#endif
for (x = nelist; x; x = next) {
next = x->next;
if (x->name) { tfree(x->name); }
@ -280,25 +268,13 @@ static void clear_name_list(NAME_ENTRY nelist, char *msg)
}
}
#ifdef TRACE
static void print_name_list(NAME_ENTRY nelist)
{
NAME_ENTRY x = NULL;
int count = 0;
if (!nelist) { return; }
for (x = nelist; x; x = x->next) {
printf("%s\n", x->name);
count++;
}
printf("NAME_COUNT %d\n", count);
}
#endif
/*
static data cleared and reset by initialize_udevice(),
cleared by cleanup_udevice().
*/
static int ps_port_directions = 0; // If non-zero list subckt port directions
static int ps_global_tmodels = 0; // If non-zero collect global tmodels
static int ps_global_hash_table = 1; // Use hash table for global tmodel names
static int ps_ports_and_pins = 0; // If non-zero list subckt port directions
static int ps_udevice_msgs = 0; // Controls the verbosity of U* warnings
/*
If ps_udevice_exit is non-zero then exit when u_process_instance fails
@ -461,9 +437,9 @@ static void add_all_port_names(char *subckt_line)
if (!subckt_line) {
return;
}
if (ps_port_directions & 4) {
if (ps_ports_and_pins & 4) {
printf("TRANS_IN %s\n", subckt_line);
} else if (ps_port_directions & 1) {
} else if (ps_ports_and_pins & 1) {
printf("%s\n", subckt_line);
}
copy_line = tprintf("%s", subckt_line);
@ -618,15 +594,15 @@ static char *find_xspice_for_delay(char *itype)
}
/* NOTE
Xlator and Xlate
Xlate struct data is stored in an Xlator list struct.
Xlator and Xlate_data
Xlate_data struct is stored in an Xlator list struct.
Used to save translated instance and model statements.
After an Xlator has been created, Xlate data is generated via
After an Xlator has been created, Xlate_data is generated via
create_xlate() and entered into the Xlator by add_xlator().
A first_xlator() ... next_xlator() iteration loop will retrieve
the Xlate data entries in an Xlator.
the Xlate_data entries in an Xlator.
*/
static void delete_xlate(Xlatep p)
static void delete_xlate(Xlate_datap p)
{
if (p) {
if (p->translated) { tfree(p->translated); }
@ -640,13 +616,13 @@ static void delete_xlate(Xlatep p)
return;
}
static Xlatep create_xlate(char *translated, char *delays, char *utype,
static Xlate_datap create_xlate(char *translated, char *delays, char *utype,
char *xspice, char *tmodel, char *mname)
{
/* Any unused parameter is called with an empty string "" */
Xlatep xlp;
Xlate_datap xlp;
xlp = TMALLOC(Xlate, 1);
xlp = TMALLOC(Xlate_data, 1);
xlp->next = NULL;
xlp->translated = TMALLOC(char, strlen(translated) + 1);
strcpy(xlp->translated, translated);
@ -663,12 +639,12 @@ static Xlatep create_xlate(char *translated, char *delays, char *utype,
return xlp;
}
static Xlatep create_xlate_translated(char *translated)
static Xlate_datap create_xlate_translated(char *translated)
{
return create_xlate(translated, "", "", "", "", "");
}
static Xlatep create_xlate_instance(
static Xlate_datap create_xlate_instance(
char *translated, char *xspice, char *tmodel, char *mname)
{
return create_xlate(translated, "", "", xspice, tmodel, mname);
@ -687,7 +663,7 @@ static Xlatorp create_xlator(void)
static void delete_xlator(Xlatorp xp)
{
Xlatep x, next;
Xlate_datap x, next;
if (xp) {
if (xp->head) {
@ -705,9 +681,9 @@ static void delete_xlator(Xlatorp xp)
return;
}
static Xlatorp add_xlator(Xlatorp xp, Xlatep x)
static Xlatorp add_xlator(Xlatorp xp, Xlate_datap x)
{
Xlatep prev;
Xlate_datap prev;
if (!xp || !x) { return NULL; }
if (!xp->head) {
@ -724,9 +700,9 @@ static Xlatorp add_xlator(Xlatorp xp, Xlatep x)
return xp;
}
static Xlatep first_xlator(Xlatorp xp)
static Xlate_datap first_xlator(Xlatorp xp)
{
Xlatep xret;
Xlate_datap xret;
if (!xp) { return NULL; }
xp->iter = xp->head;
@ -739,9 +715,9 @@ static Xlatep first_xlator(Xlatorp xp)
}
}
static Xlatep next_xlator(Xlatorp xp)
static Xlate_datap next_xlator(Xlatorp xp)
{
Xlatep ret;
Xlate_datap ret;
if (!xp) { return NULL; }
ret = xp->iter;
@ -754,7 +730,7 @@ static Xlatep next_xlator(Xlatorp xp)
static Xlatorp append_xlator(Xlatorp dest, Xlatorp src)
{
Xlatep x1, copy;
Xlate_datap x1, copy;
if (!dest || !src) { return NULL; }
for (x1 = first_xlator(src); x1; x1 = next_xlator(src)) {
@ -765,9 +741,14 @@ static Xlatorp append_xlator(Xlatorp dest, Xlatorp src)
return dest;
}
/* static Xlatorp for collecting timing model delays */
/* static Xlatorp for collecting subckt timing model delays */
static Xlatorp model_xlatorp = NULL;
/* static Xlatorp for collecting global timing model delays */
static Xlatorp global_model_xlatorp = NULL;
/* global model hash table */
static NGHASHPTR global_model_hash_table = NULL;
/* static Xlatorp for default zero delay models */
static Xlatorp default_models = NULL;
@ -794,7 +775,7 @@ struct card *replacement_udevice_cards(void)
{
struct card *newcard = NULL, *nextcard = NULL;
char *new_str = NULL;
Xlatep x;
Xlate_datap x;
int count = 0;
if (!translated_p) { return NULL; }
@ -831,25 +812,33 @@ struct card *replacement_udevice_cards(void)
translated_p = add_xlator(translated_p, x);
}
if (current_subckt && (ps_port_directions & 2)) {
if (current_subckt && (ps_ports_and_pins & 2)) {
DS_CREATE(ds_tmp, 128);
char *tmp = NULL, *pos = NULL, *posp = NULL;
tmp = TMALLOC(char, strlen(current_subckt) + 1);
(void) memcpy(tmp, current_subckt, strlen(current_subckt) + 1);
pos = strstr(tmp, "optional:");
posp = strstr(tmp, "params:");
ds_clear(&ds_tmp);
/* If there is an optional: and a param: then posp > pos */
if (pos) {
/* Remove the optional: section if present */
*pos = '\0';
if (posp) {
strcat(tmp, posp);
ds_cat_str(&ds_tmp, tmp);
ds_cat_str(&ds_tmp, posp);
printf("\nTRANS_OUT %s\n", ds_get_buf(&ds_tmp));
} else {
printf("\nTRANS_OUT %s\n", tmp);
}
} else {
printf("\nTRANS_OUT %s\n", tmp);
}
printf("\nTRANS_OUT %s\n", tmp);
tfree(tmp);
ds_free(&ds_tmp);
}
for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) {
if (ps_port_directions & 2) {
if (ps_ports_and_pins & 2) {
printf("TRANS_OUT %s\n", x->translated);
}
new_str = copy(x->translated);
@ -864,7 +853,7 @@ struct card *replacement_udevice_cards(void)
nextcard = insert_new_line(nextcard, new_str, 0, 0);
}
}
if (current_subckt && (ps_port_directions & 2)) {
if (current_subckt && (ps_ports_and_pins & 2)) {
char *p1 = NULL, *p2 = NULL;
DS_CREATE(tmpds, 64);
p1 = strstr(current_subckt, ".subckt");
@ -881,7 +870,7 @@ struct card *replacement_udevice_cards(void)
void u_add_instance(char *str)
{
Xlatep x;
Xlate_datap x;
if (str && strlen(str) > 0) {
x = create_xlate_translated(str);
@ -904,8 +893,48 @@ void u_add_logicexp_model(char *tmodel, char *xspice_gate, char *model_name)
void initialize_udevice(char *subckt_line)
{
Xlatep xdata;
/* If this has been called before, make sure you have called
* the corresponding cleanup_udevice.
* After call with NULL subckt_line, cleanup_udevice(TRUE).
* After call with non-NULL subckt_line, cleanup_udevice(FALSE).
*/
Xlate_datap xdata;
if (!cp_getvar("ps_global_tmodels", CP_NUM, &ps_global_tmodels, 0)) {
ps_global_tmodels = 0;
}
if (!cp_getvar("ps_global_hash_table", CP_NUM, &ps_global_hash_table, 0)) {
ps_global_hash_table = 1;
}
/*
Use tpzh.., tpzl.., tphz.., tplz.. for tristates
if they are the only delays.
*/
if (!cp_getvar("ps_tpz_delays", CP_NUM, &ps_tpz_delays, 0)) {
ps_tpz_delays = 1; // default: use tpz... delays if necessary
}
if (!cp_getvar("ps_use_mntymx", CP_NUM, &ps_use_mntymx, 0)) {
ps_use_mntymx = 4; // default: typ + shorter delays
}
set_u_devices_info(ps_use_mntymx);
/* if subckt_line is NULL only create the global model xlator */
if (!subckt_line) {
global_model_xlatorp = NULL;
global_model_hash_table = NULL;
if (!ps_global_tmodels) return;
global_model_xlatorp = create_xlator();
if (ps_global_hash_table) {
global_model_hash_table = nghash_init(nghash_table_size(101));
}
if (ps_global_hash_table) {
printf("NOTE using global models hash table search\n");
} else {
printf("NOTE using global models linear list search\n");
}
return;
}
new_names_list = NULL;
input_names_list = NULL;
output_names_list = NULL;
@ -913,14 +942,14 @@ void initialize_udevice(char *subckt_line)
port_names_list = NULL;
num_name_collisions = 0;
/*
Variable ps_port_directions != 0 to turn on pins and ports.
If (ps_port_directions & 4) also print the Pspice input lines with
Variable ps_ports_and_pins != 0 to turn on pins and ports.
If (ps_ports_and_pins & 4) also print the Pspice input lines with
prefix TRANS_IN.
If (ps_port_directions & 2) print translated Xspice equivalent lines
If (ps_ports_and_pins & 2) print translated Xspice equivalent lines
with prefix TRANS_OUT.
*/
if (!cp_getvar("ps_port_directions", CP_NUM, &ps_port_directions, 0)) {
ps_port_directions = 0;
if (!cp_getvar("ps_ports_and_pins", CP_NUM, &ps_ports_and_pins, 0)) {
ps_ports_and_pins = 0;
}
/*
Set ps_udevice_msgs to print warnings about PSpice device types.
@ -936,13 +965,6 @@ void initialize_udevice(char *subckt_line)
if (!cp_getvar("ps_udevice_exit", CP_NUM, &ps_udevice_exit, 0)) {
ps_udevice_exit = 0;
}
/*
Use tpzh.., tpzl.., tphz.., tplz.. for tristates
if they are the only delays.
*/
if (!cp_getvar("ps_tpz_delays", CP_NUM, &ps_tpz_delays, 0)) {
ps_tpz_delays = 1; // default: use tpz... delays if necessary
}
/* If non-zero use inverters with ff/latch control inputs */
if (!cp_getvar("ps_with_inverters", CP_NUM, &ps_with_inverters, 0)) {
ps_with_inverters = 0;
@ -951,10 +973,6 @@ void initialize_udevice(char *subckt_line)
if (!cp_getvar("ps_with_tri_inverters", CP_NUM, &ps_with_tri_inverters, 0)) {
ps_with_tri_inverters = 0;
}
if (!cp_getvar("ps_use_mntymx", CP_NUM, &ps_use_mntymx, 0)) {
ps_use_mntymx = 4; // default: typ + shorter delays
}
set_u_devices_info(ps_use_mntymx);
if (subckt_line && strncmp(subckt_line, ".subckt", 7) == 0) {
add_all_port_names(subckt_line);
@ -992,41 +1010,19 @@ void initialize_udevice(char *subckt_line)
add_drive_hilo = FALSE;
}
static void determine_port_type(void)
void cleanup_udevice(BOOL global)
{
BOOL inp = FALSE, outp = FALSE, tri = FALSE;
char *port_type = NULL;
NAME_ENTRY x = NULL;
for (x = port_names_list; x; x = x->next) {
inp = (find_name_entry(x->name, input_names_list) ? TRUE : FALSE);
outp = (find_name_entry(x->name, output_names_list) ? TRUE : FALSE);
tri = (find_name_entry(x->name, tristate_names_list) ? TRUE : FALSE);
port_type = "UNKNOWN";
if (tri) {
if (outp && inp) {
port_type = "INOUT";
} else if (outp) {
port_type = "OUT";
}
} else {
if (outp && inp) {
port_type = "OUT";
} else if (outp) {
port_type = "OUT";
} else if (inp) {
port_type = "IN";
}
if (global) {
if (global_model_xlatorp) {
delete_xlator(global_model_xlatorp);
}
if (ps_port_directions & 1) {
printf("port: %s %s\n", x->name, port_type);
global_model_xlatorp = NULL;
if (global_model_hash_table) {
nghash_free(global_model_hash_table, NULL, NULL);
}
global_model_hash_table = NULL;
return;
}
}
void cleanup_udevice(void)
{
determine_port_type();
cleanup_translated_xlator();
delete_xlator(model_xlatorp);
model_xlatorp = NULL;
@ -1034,15 +1030,15 @@ void cleanup_udevice(void)
default_models = NULL;
add_zero_delay_inverter_model = FALSE;
add_drive_hilo = FALSE;
clear_name_list(input_names_list, "INPUT_PINS");
clear_name_list(input_names_list);
input_names_list = NULL;
clear_name_list(output_names_list, "OUTPUT_PINS");
clear_name_list(output_names_list);
output_names_list = NULL;
clear_name_list(tristate_names_list, "TRISTATE_PINS");
clear_name_list(tristate_names_list);
tristate_names_list = NULL;
clear_name_list(port_names_list, "PORT_NAMES");
clear_name_list(port_names_list);
port_names_list = NULL;
clear_name_list(new_names_list, "NEW_NAMES");
clear_name_list(new_names_list);
new_names_list = NULL;
if (current_subckt) {
tfree(current_subckt);
@ -1051,16 +1047,16 @@ void cleanup_udevice(void)
subckt_msg_count = 0;
}
static Xlatep create_xlate_model(char *delays,
static Xlate_datap create_xlate_model(char *delays,
char *utype, char *xspice, char *tmodel)
{
return create_xlate("", delays, utype, xspice, tmodel, "");
}
static Xlatep find_tmodel_in_xlator(Xlatep x, Xlatorp xlp)
static Xlate_datap find_tmodel_in_xlator(Xlate_datap x, Xlatorp xlp)
{
/* Only for timing model xlators */
Xlatep x1;
Xlate_datap x1;
if (!x) { return NULL; }
if (!xlp) { return NULL; }
@ -1074,37 +1070,109 @@ static Xlatep find_tmodel_in_xlator(Xlatep x, Xlatorp xlp)
return NULL;
}
static Xlatep find_in_model_xlator(Xlatep x)
static Xlate_datap find_global_model_from_table(Xlate_datap x)
{
Xlatep x1;
Xlate_datap xglobal = NULL;
x1 = find_tmodel_in_xlator(x, model_xlatorp);
if (x1) { return x1; }
if (global_model_hash_table) {
DS_CREATE(ds_key, 32);
ds_cat_printf(&ds_key, "%s", x->tmodel);
if (x->xspice && strlen(x->xspice) > 0) {
ds_cat_printf(&ds_key, "___%s", x->xspice);
}
xglobal = (Xlate_datap) nghash_find(global_model_hash_table,
ds_get_buf(&ds_key));
ds_free(&ds_key);
}
return xglobal;
}
static void *insert_global_model_in_table(Xlate_datap x)
{
void *inserted = NULL;
if (global_model_hash_table) {
Xlate_datap xglobal = NULL;
DS_CREATE(ds_key, 32);
ds_clear(&ds_key);
ds_cat_printf(&ds_key, "%s", x->tmodel);
if (x->xspice && strlen(x->xspice) > 0) {
ds_cat_printf(&ds_key, "___%s", x->xspice);
}
xglobal = (Xlate_datap) nghash_find(global_model_hash_table,
ds_get_buf(&ds_key));
if (!xglobal) {
inserted = nghash_insert(global_model_hash_table,
ds_get_buf(&ds_key), x);
} else {
inserted = NULL;
}
ds_free(&ds_key);
}
return inserted;
}
static Xlate_datap find_in_model_xlator(Xlate_datap x, BOOL global)
{
Xlate_datap x1 = NULL;
/* for global timing models do not search the default models */
if (global) {
if (!ps_global_tmodels) return NULL;
if (ps_global_hash_table) {
if (global_model_hash_table) {
x1 = find_global_model_from_table(x);
return x1;
}
} else {
if (global_model_xlatorp) {
x1 = find_tmodel_in_xlator(x, global_model_xlatorp);
return x1;
}
}
return NULL;
} else {
if (model_xlatorp) {
x1 = find_tmodel_in_xlator(x, model_xlatorp);
if (x1) { return x1; }
}
}
/* If the timing model is not found local to the subckt,
* search for a default model
*/
x1 = find_tmodel_in_xlator(x, default_models);
return x1;
}
static void add_delays_to_model_xlator(char *delays,
char *utype, char *xspice, char *tmodel)
char *utype, char *xspice, char *tmodel, BOOL global)
{
/*
Specify xspice as "d_dlatch" or "d_srlatch" for ugff
otherwise xspice == ""
*/
Xlatep x = NULL, x1 = NULL;
Xlate_datap x = NULL, x1 = NULL;
Xlatorp xlp = NULL;
if (!model_xlatorp) { return; }
if (global) {
xlp = global_model_xlatorp;
} else {
xlp = model_xlatorp;
}
if (!xlp) { return; }
x = create_xlate_model(delays, utype, xspice, tmodel);
x1 = find_in_model_xlator(x);
x1 = find_in_model_xlator(x, global);
if (x1) {
/*
printf("Already found timing model %s utype %s\n",
x1->tmodel, x1->utype);
*/
delete_xlate(x);
return;
}
(void) add_xlator(model_xlatorp, x);
(void) add_xlator(xlp, x);
if (global && ps_global_hash_table) {
(void) insert_global_model_in_table(x);
}
}
/* classify gate variants */
@ -1661,7 +1729,7 @@ static char *new_inverter(char *iname, char *node, Xlatorp xlp)
/* Return the name of the output of the new inverter */
/* tfree the returned string after it has been used by the caller */
char *tmp = NULL, *instance_name = NULL, *not_node = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
instance_name = tprintf("a%s_%s", iname, node);
not_node = tprintf("not_%s", instance_name);
@ -1691,7 +1759,7 @@ static BOOL gen_timing_model(
The new .model statement is added to the Xlatorp of the translated
xspice instance and model lines (not to be confused with model_xlatorp.
*/
Xlatep xin = NULL, xout = NULL, newdata;
Xlate_datap xin = NULL, xout = NULL, newdata;
char *s1;
BOOL retval;
@ -1700,7 +1768,10 @@ static BOOL gen_timing_model(
} else {
xin = create_xlate_model("", utype, "", tmodel);
}
xout = find_in_model_xlator(xin);
xout = find_in_model_xlator(xin, FALSE); // local timing model
if (!xout) {
xout = find_in_model_xlator(xin, TRUE); // global timing model
}
if (xout) {
/* Don't delete xout or the model_xlatorp will be corrupted */
if (xout->delays && strlen(xout->delays) > 0) {
@ -1727,7 +1798,7 @@ static Xlatorp gen_dff_instance(struct dff_instance *ip, int withinv)
int i, num_gates;
char *modelnm, *s1;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
DS_CREATE(tmpdstr, 128);
@ -1839,7 +1910,7 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip, int withinv)
int i, num_gates;
char *modelnm, *s1;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
DS_CREATE(tmpdstr, 128);
@ -1958,7 +2029,7 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip, int withinv)
int i, num_gates;
char *modelnm, *s1, *s2, *s3;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
if (!ip) { return NULL; }
@ -2073,7 +2144,7 @@ static Xlatorp gen_srff_instance(struct srff_instance *srffp, int withinv)
int i, num_gates;
char *modelnm, *s1, *s2, *s3;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
BOOL need_preb_inv = FALSE, need_clrb_inv = FALSE;
if (!srffp) { return NULL; }
@ -2196,7 +2267,7 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi)
char *high_name = NULL, *low_name = NULL;
char *zero_delay_str = NULL;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
DS_CREATE(tmp_dstr, 128);
if (!compi) {
@ -2347,7 +2418,7 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
char *instance_name = NULL;
int i, j, k, width, num_gates, num_ins, num_outs;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
int withinv = ps_with_tri_inverters;
BOOL inv3_to_buf3 = FALSE;
BOOL inv3a_to_buf3a = FALSE;
@ -2551,9 +2622,9 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
to the model of a trailing tristate buffer.
*/
if (inv3a_to_buf3a) {
primary_model = tprintf("d_a%s_%s", iname, "buf3a");
primary_model = tprintf("d_a%s_%s", iname, "buf3a");
} else {
primary_model = tprintf("d_a%s_%s", iname, itype);
primary_model = tprintf("d_a%s_%s", iname, itype);
}
for (i = 0; i < num_gates; i++) { // start of for each gate
/* inputs */
@ -2764,7 +2835,7 @@ static void estimate_typ(struct timing_data *tdp)
char *tmpmax = NULL, *tmpmin = NULL;
char *min, *typ, *max;
float valmin, valmax, average;
char *units1, *units2;
char *unitsmin, *unitsmax, *tmodel = NULL;
if (!tdp) { return; }
min = tdp->min;
@ -2783,12 +2854,32 @@ static void estimate_typ(struct timing_data *tdp)
}
if (tmpmin && tmpmax) {
if (strlen(tmpmin) > 0 && strlen(tmpmax) > 0) {
valmin = strtof(tmpmin, &units1);
valmax = strtof(tmpmax, &units2);
average = (float)((valmin + valmax) / 2.0);
tdp->ave = tprintf("%.2f%s", average, units2);
if (!eq(units1, units2)) {
printf("WARNING units do not match\n");
valmin = strtof(tmpmin, &unitsmin);
valmax = strtof(tmpmax, &unitsmax);
if (!eq(unitsmin, unitsmax)) {
printf("WARNING estimate_typ units do not match"
" min %s max %s", tmpmin, tmpmax);
if (unitsmin[0] == unitsmax[0]) {
average = (valmin + valmax) / (float)2.0;
tdp->ave = tprintf("%.2f%cs", average, unitsmin[0]);
} else if (unitsmin[0] == 'p' && unitsmax[0] == 'n') {
valmax = (float)1000.0 * valmax;
average = (valmin + valmax) / (float)2.0;
tdp->ave = tprintf("%.2fps", average);
} else if (unitsmin[0] == 'n' && unitsmax[0] == 'p') {
tdp->ave = tprintf("%.2fns", valmin);
} else {
tdp->ave = tprintf("%.2f%s", valmin, unitsmin);
}
tmodel = get_current_tmodel();
if (tmodel) {
printf(" using delay %s tmodel %s\n", tdp->ave, tmodel);
} else {
printf(" using delay %s\n", tdp->ave);
}
} else {
average = (float)((valmin + valmax) / 2.0);
tdp->ave = tprintf("%.2f%s", average, unitsmax);
}
tdp->estimate = EST_AVE;
return;
@ -2854,21 +2945,38 @@ static char *select_delay(char *delay1, char *delay2)
*/
float val1, val2;
char *units1, *units2;
char *tmodel = NULL;
BOOL warns = FALSE;
val1 = strtof(delay1, &units1);
val2 = strtof(delay2, &units2);
if (!eq(units1, units2)) {
printf("WARNING units do not match\n");
printf("WARNING select_delay units do not match"
" min %s max %s", delay1, delay2);
warns = TRUE;
tmodel = get_current_tmodel();
if (tmodel) {
printf(" tmodel %s", tmodel);
}
}
if (mntymx_shorter.shorter_delays) {
if (val1 <= val2) {
if (warns) {
printf(" using delay %s\n", delay1);
}
return delay1;
}
} else {
if (val1 >= val2) {
if (warns) {
printf(" using delay %s\n", delay1);
}
return delay1;
}
}
if (warns) {
printf(" using delay %s\n", delay2);
}
return delay2;
}
@ -3196,7 +3304,25 @@ static char *get_delays_ugff(char *rem, char *d_name)
return delays;
}
static BOOL u_process_model(char *nline, char *original)
static char *current_tmodel = NULL;
static void set_current_tmodel(char *tmodel)
{
if (current_tmodel) {
tfree(current_tmodel);
current_tmodel = NULL;
}
if (tmodel) {
current_tmodel = (char *)TMALLOC(char, strlen(tmodel) + 1);
strcpy(current_tmodel,tmodel);
}
}
static char *get_current_tmodel(void)
{
return current_tmodel;
}
static BOOL u_process_model(char *nline, char *original, BOOL global)
{
char *tok, *remainder, *delays = NULL, *utype, *tmodel;
BOOL retval = TRUE;
@ -3209,6 +3335,7 @@ static BOOL u_process_model(char *nline, char *original)
if (!tok) { return FALSE; }
tmodel = TMALLOC(char, strlen(tok) + 1);
memcpy(tmodel, tok, strlen(tok) + 1);
set_current_tmodel(tmodel);
/* model utype */
tok = strtok(NULL, " \t(");
if (!tok) { tfree(tmodel); return FALSE; }
@ -3221,26 +3348,26 @@ static BOOL u_process_model(char *nline, char *original)
if (eq(utype, "ugate")) {
delays = get_delays_ugate(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
utype, "", tmodel, global);
if (delays) { tfree(delays); }
} else if (eq(utype, "utgate")) {
delays = get_delays_utgate(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
utype, "", tmodel, global);
if (delays) { tfree(delays); }
} else if (eq(utype, "ueff")) {
delays = get_delays_ueff(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
utype, "", tmodel, global);
if (delays) { tfree(delays); }
} else if (eq(utype, "ugff")) {
delays = get_delays_ugff(remainder, "d_dlatch");
add_delays_to_model_xlator((delays ? delays : ""),
utype, "d_dlatch", tmodel);
utype, "d_dlatch", tmodel, global);
if (delays) { tfree(delays); }
delays = get_delays_ugff(remainder, "d_srlatch");
add_delays_to_model_xlator((delays ? delays : ""),
utype, "d_srlatch", tmodel);
utype, "d_srlatch", tmodel, global);
if (delays) { tfree(delays); }
} else if (eq(utype, "uio")) {
/* skip uio models */
@ -3249,7 +3376,7 @@ static BOOL u_process_model(char *nline, char *original)
} else if (eq(utype, "udly")) {
delays = get_delays_udly(remainder);
add_delays_to_model_xlator((delays ? delays : ""),
utype, "", tmodel);
utype, "", tmodel, global);
if (delays) { tfree(delays); }
} else {
retval = FALSE;
@ -3258,6 +3385,7 @@ static BOOL u_process_model(char *nline, char *original)
} else {
retval = FALSE;
}
set_current_tmodel(NULL);
tfree(tmodel);
tfree(utype);
return retval;
@ -3931,7 +4059,7 @@ static Xlatorp translate_pull(struct instance_hdr *hdr, char *start)
char *model_name = NULL, *inst_stmt = NULL, *model_stmt = NULL;
int i, numpulls;
Xlatorp xp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
itype = hdr->instance_type;
iname = hdr->instance_name;
@ -3974,7 +4102,7 @@ static Xlatorp translate_dlyline(struct instance_hdr *hdr, char *start)
char *itype, *iname, *newline = NULL, *tok;
char *model_name = NULL, *tmodel = NULL;
Xlatorp xp = NULL;
Xlatep xdata = NULL;
Xlate_datap xdata = NULL;
DS_CREATE(statement, 128);
itype = hdr->instance_type;
@ -4168,7 +4296,7 @@ BOOL u_process_instance(char *nline)
if (!xspice) {
if (eq(itype, "logicexp")) {
delete_instance_hdr(hdr);
if (ps_port_directions & 4) {
if (ps_ports_and_pins & 4) {
printf("TRANS_IN %s\n", nline);
}
behav_ret = f_logicexp(nline);
@ -4183,7 +4311,7 @@ BOOL u_process_instance(char *nline)
return behav_ret;
} else if (eq(itype, "pindly")) {
delete_instance_hdr(hdr);
if (ps_port_directions & 4) {
if (ps_ports_and_pins & 4) {
printf("TRANS_IN %s\n", nline);
}
behav_ret = f_pindly(nline);
@ -4204,7 +4332,7 @@ BOOL u_process_instance(char *nline)
return FALSE;
}
}
if (ps_port_directions & 4) {
if (ps_ports_and_pins & 4) {
printf("TRANS_IN %s\n", nline);
}
/* Skip past instance name, type, pwr, gnd */
@ -4261,7 +4389,7 @@ BOOL u_process_instance(char *nline)
a Pspice .model timing model statement with all the '+' continuations
added minus the '+'.
*/
BOOL u_process_model_line(char *line)
BOOL u_process_model_line(char *line, BOOL global)
{
/* Translate a .model line to find the delays */
/* Return TRUE if ok */
@ -4271,12 +4399,12 @@ BOOL u_process_model_line(char *line)
if (n > 0 && line[n] == '\n') line[n] = '\0';
if (strncmp(line, ".model ", strlen(".model ")) == 0) {
if (ps_port_directions & 4) {
if (ps_ports_and_pins & 4) {
printf("TRANS_IN %s\n", line);
}
newline = TMALLOC(char, strlen(line) + 1);
(void) memcpy(newline, line, strlen(line) + 1);
retval = u_process_model(newline, line);
retval = u_process_model(newline, line, global);
tfree(newline);
return retval;
} else {

View File

@ -7,11 +7,11 @@ struct udevices_info {
};
BOOL u_process_instance(char *line);
BOOL u_process_model_line(char *line);
BOOL u_process_model_line(char *line, BOOL global);
BOOL u_check_instance(char *line);
void initialize_udevice(char *subckt_line);
struct card *replacement_udevice_cards(void);
void cleanup_udevice(void);
void cleanup_udevice(BOOL global);
void u_add_instance(char *str);
void u_add_logicexp_model(char *tmodel, char *xspice_gate, char *model_name);
void u_remember_pin(char *name, int type);