For unspecified gate delays (logic and tristate gates), which PSpice would consider as zero, set the rise and fall delays to 1.e-12s (the minimum for Xspice). For dff, jkff, dlatch, and srlatch use the Xspice default 1.0ns for rise and fall delays. If the ngspice variable (ps_port_directions & 2) is true, write the translated subckt to stdout, with TRANS_OUT prefix, for debugging purposes. The user could edit and replace the translated subckt if desired.
This commit is contained in:
parent
c72781584a
commit
2db2b3416f
|
|
@ -58,10 +58,13 @@
|
||||||
#include "ngspice/macros.h"
|
#include "ngspice/macros.h"
|
||||||
#include "ngspice/udevices.h"
|
#include "ngspice/udevices.h"
|
||||||
#include "ngspice/logicexp.h"
|
#include "ngspice/logicexp.h"
|
||||||
|
#include "ngspice/dstring.h"
|
||||||
|
|
||||||
extern struct card* insert_new_line(
|
extern struct card* insert_new_line(
|
||||||
struct card* card, char* line, int linenum, int linenum_orig);
|
struct card* card, char* line, int linenum, int linenum_orig);
|
||||||
|
|
||||||
|
#define USE_SHORTEST_DELAYS
|
||||||
|
#define FF_LATCH_DEFAULT_DELAYS
|
||||||
//#define TRACE
|
//#define TRACE
|
||||||
|
|
||||||
/* device types */
|
/* device types */
|
||||||
|
|
@ -207,6 +210,8 @@ struct name_entry {
|
||||||
NAME_ENTRY next;
|
NAME_ENTRY next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static char *get_zero_rise_fall(void);
|
||||||
|
|
||||||
#ifdef TRACE
|
#ifdef TRACE
|
||||||
static void print_name_list(NAME_ENTRY nelist);
|
static void print_name_list(NAME_ENTRY nelist);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -393,7 +398,7 @@ static void add_all_port_names(char *subckt_line)
|
||||||
if (!subckt_line) {
|
if (!subckt_line) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ps_port_directions >= 2) {
|
if (ps_port_directions & 4) {
|
||||||
printf("TRANS_IN %s\n", subckt_line);
|
printf("TRANS_IN %s\n", subckt_line);
|
||||||
} else if (ps_port_directions) {
|
} else if (ps_port_directions) {
|
||||||
printf("%s\n", subckt_line);
|
printf("%s\n", subckt_line);
|
||||||
|
|
@ -757,8 +762,25 @@ struct card *replacement_udevice_cards(void)
|
||||||
translated_p = add_xlator(translated_p, x);
|
translated_p = add_xlator(translated_p, x);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (ps_port_directions & 2) {
|
||||||
|
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:");
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\nTRANS_OUT %s\n", tmp);
|
||||||
|
tfree(tmp);
|
||||||
|
}
|
||||||
for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) {
|
for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) {
|
||||||
if (ps_port_directions >= 2) {
|
if (ps_port_directions & 2) {
|
||||||
printf("TRANS_OUT %s\n", x->translated);
|
printf("TRANS_OUT %s\n", x->translated);
|
||||||
}
|
}
|
||||||
new_str = copy(x->translated);
|
new_str = copy(x->translated);
|
||||||
|
|
@ -773,6 +795,18 @@ struct card *replacement_udevice_cards(void)
|
||||||
nextcard = insert_new_line(nextcard, new_str, 0, 0);
|
nextcard = insert_new_line(nextcard, new_str, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ps_port_directions & 2) {
|
||||||
|
char *p1 = NULL, *p2 = NULL;
|
||||||
|
DS_CREATE(tmpds, 64);
|
||||||
|
p1 = strstr(current_subckt, ".subckt");
|
||||||
|
p1 += strlen(".subckt");
|
||||||
|
p1 = skip_ws(p1);
|
||||||
|
p2 = p1;
|
||||||
|
p2 = skip_non_ws(p2);
|
||||||
|
ds_cat_mem(&tmpds, p1, (p2 - p1));
|
||||||
|
printf("TRANS_OUT .ends %s\n\n", ds_get_buf(&tmpds));
|
||||||
|
ds_free(&tmpds);
|
||||||
|
}
|
||||||
return newcard;
|
return newcard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -811,8 +845,9 @@ void initialize_udevice(char *subckt_line)
|
||||||
num_name_collisions = 0;
|
num_name_collisions = 0;
|
||||||
/*
|
/*
|
||||||
Variable ps_port_directions != 0 to turn on pins and ports.
|
Variable ps_port_directions != 0 to turn on pins and ports.
|
||||||
If ps_port_directions >= 2 also print the Pspice input lines with
|
If (ps_port_directions & 4) also print the Pspice input lines with
|
||||||
prefix TRANS_IN, and the translated Xspice equivalent lines
|
prefix TRANS_IN.
|
||||||
|
If (ps_port_directions & 2) print translated Xspice equivalent lines
|
||||||
with prefix TRANS_OUT.
|
with prefix TRANS_OUT.
|
||||||
*/
|
*/
|
||||||
if (!cp_getvar("ps_port_directions", CP_NUM, &ps_port_directions, 0)) {
|
if (!cp_getvar("ps_port_directions", CP_NUM, &ps_port_directions, 0)) {
|
||||||
|
|
@ -842,7 +877,12 @@ void initialize_udevice(char *subckt_line)
|
||||||
model_xlatorp = create_xlator();
|
model_xlatorp = create_xlator();
|
||||||
default_models = create_xlator();
|
default_models = create_xlator();
|
||||||
/* .model d0_gate ugate () */
|
/* .model d0_gate ugate () */
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
xdata = create_xlate("", "(rise_delay=1.0e-12 fall_delay=1.0e-12)",
|
||||||
|
"ugate", "", "d0_gate", "");
|
||||||
|
#else
|
||||||
xdata = create_xlate("", "", "ugate", "", "d0_gate", "");
|
xdata = create_xlate("", "", "ugate", "", "d0_gate", "");
|
||||||
|
#endif
|
||||||
(void) add_xlator(default_models, xdata);
|
(void) add_xlator(default_models, xdata);
|
||||||
/* .model d0_gff ugff () */
|
/* .model d0_gff ugff () */
|
||||||
xdata = create_xlate("", "", "ugff", "d_dlatch", "d0_gff", "");
|
xdata = create_xlate("", "", "ugff", "d_dlatch", "d0_gff", "");
|
||||||
|
|
@ -853,7 +893,12 @@ void initialize_udevice(char *subckt_line)
|
||||||
xdata = create_xlate("", "", "ueff", "", "d0_eff", "");
|
xdata = create_xlate("", "", "ueff", "", "d0_eff", "");
|
||||||
(void) add_xlator(default_models, xdata);
|
(void) add_xlator(default_models, xdata);
|
||||||
/* .model d0_tgate utgate () */
|
/* .model d0_tgate utgate () */
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
xdata = create_xlate("", "(delay=1.0e-12)",
|
||||||
|
"utgate", "", "d0_tgate", "");
|
||||||
|
#else
|
||||||
xdata = create_xlate("", "", "utgate", "", "d0_tgate", "");
|
xdata = create_xlate("", "", "utgate", "", "d0_tgate", "");
|
||||||
|
#endif
|
||||||
(void) add_xlator(default_models, xdata);
|
(void) add_xlator(default_models, xdata);
|
||||||
/* reset for the new subckt */
|
/* reset for the new subckt */
|
||||||
add_zero_delay_inverter_model = FALSE;
|
add_zero_delay_inverter_model = FALSE;
|
||||||
|
|
@ -1939,6 +1984,9 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi)
|
||||||
char *new_inst = NULL, *model_stmt = NULL, *final_model_name = NULL;
|
char *new_inst = NULL, *model_stmt = NULL, *final_model_name = NULL;
|
||||||
char *new_stmt = NULL, *instance_name = NULL;
|
char *new_stmt = NULL, *instance_name = NULL;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
char *zero_delay_str = NULL;
|
||||||
|
#endif
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
Xlatorp xxp = NULL;
|
Xlatorp xxp = NULL;
|
||||||
Xlatep xdata = NULL;
|
Xlatep xdata = NULL;
|
||||||
|
|
@ -2016,10 +2064,19 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* .model statement for the input gates */
|
/* .model statement for the input gates */
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
zero_delay_str = get_zero_rise_fall();
|
||||||
|
model_stmt = tprintf(".model %s %s%s",
|
||||||
|
model_name, ingates, zero_delay_str);
|
||||||
|
#else
|
||||||
model_stmt = tprintf(".model %s %s", model_name, ingates);
|
model_stmt = tprintf(".model %s %s", model_name, ingates);
|
||||||
|
#endif
|
||||||
xdata = create_xlate_translated(model_stmt);
|
xdata = create_xlate_translated(model_stmt);
|
||||||
xxp = add_xlator(xxp, xdata);
|
xxp = add_xlator(xxp, xdata);
|
||||||
tfree(model_stmt);
|
tfree(model_stmt);
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
tfree(zero_delay_str);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Final OR/NOR, AND/NAND gate */
|
/* Final OR/NOR, AND/NAND gate */
|
||||||
final_model_name = tprintf("%s_out", model_name);
|
final_model_name = tprintf("%s_out", model_name);
|
||||||
|
|
@ -2185,6 +2242,9 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
|
||||||
} else {
|
} else {
|
||||||
char *new_model_nm = NULL;
|
char *new_model_nm = NULL;
|
||||||
char *new_stmt = NULL;
|
char *new_stmt = NULL;
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
char *zero_rise_fall = NULL;
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
Use connector as original gate output and tristate input;
|
Use connector as original gate output and tristate input;
|
||||||
tristate has original gate output and utgate delay;
|
tristate has original gate output and utgate delay;
|
||||||
|
|
@ -2198,10 +2258,19 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
|
||||||
xxp = add_xlator(xxp, xdata);
|
xxp = add_xlator(xxp, xdata);
|
||||||
tfree(new_stmt);
|
tfree(new_stmt);
|
||||||
/* new model statement e.g. .model d_au2nand3 d_nand */
|
/* new model statement e.g. .model d_au2nand3 d_nand */
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
zero_rise_fall = get_zero_rise_fall();
|
||||||
|
new_stmt = tprintf(".model %s %s%s", modelnm, xspice,
|
||||||
|
zero_rise_fall);
|
||||||
|
#else
|
||||||
new_stmt = tprintf(".model %s %s", modelnm, xspice);
|
new_stmt = tprintf(".model %s %s", modelnm, xspice);
|
||||||
|
#endif
|
||||||
xdata = create_xlate_translated(new_stmt);
|
xdata = create_xlate_translated(new_stmt);
|
||||||
xxp = add_xlator(xxp, xdata);
|
xxp = add_xlator(xxp, xdata);
|
||||||
tfree(new_stmt);
|
tfree(new_stmt);
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
tfree(zero_rise_fall);
|
||||||
|
#endif
|
||||||
/* now the added tristate */
|
/* now the added tristate */
|
||||||
/* model name of added tristate */
|
/* model name of added tristate */
|
||||||
new_model_nm = tprintf("d_a%s_tribuf", iname);
|
new_model_nm = tprintf("d_a%s_tribuf", iname);
|
||||||
|
|
@ -2342,10 +2411,19 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
|
||||||
char *str1 = NULL, *modname = NULL;
|
char *str1 = NULL, *modname = NULL;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
/* Zero delay model for all original array instances */
|
/* Zero delay model for all original array instances */
|
||||||
str1 = tprintf(".model %s %s", primary_model, xspice);
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
char *zero_delay_str = get_zero_rise_fall();
|
||||||
|
str1 = tprintf(".model %s %s%s",
|
||||||
|
primary_model, xspice, zero_delay_str);
|
||||||
|
#else
|
||||||
|
str1 = tprintf(".model %s %s", primary_model, xspice);
|
||||||
|
#endif
|
||||||
xdata = create_xlate_translated(str1);
|
xdata = create_xlate_translated(str1);
|
||||||
xxp = add_xlator(xxp, xdata);
|
xxp = add_xlator(xxp, xdata);
|
||||||
tfree(str1);
|
tfree(str1);
|
||||||
|
#ifdef USE_SHORTEST_DELAYS
|
||||||
|
tfree(zero_delay_str);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/* model name of added tristate */
|
/* model name of added tristate */
|
||||||
modname = tprintf("d_a%s_tribuf", iname);
|
modname = tprintf("d_a%s_tribuf", iname);
|
||||||
|
|
@ -2714,19 +2792,35 @@ static char *get_delays_ueff(char *rem)
|
||||||
}
|
}
|
||||||
if (clkd && setd) {
|
if (clkd && setd) {
|
||||||
delays = tprintf("(clk_delay = %s "
|
delays = tprintf("(clk_delay = %s "
|
||||||
"set_delay = %s reset_delay = %s "
|
"set_delay = %s reset_delay = %s"
|
||||||
"rise_delay = 1.0ns fall_delay = 2.0ns)",
|
#ifdef FF_LATCH_DEFAULT_DELAYS
|
||||||
|
" rise_delay = 1.0ns fall_delay = 1.0ns)",
|
||||||
|
#else
|
||||||
|
" rise_delay = 1.0ns fall_delay = 2.0ns)",
|
||||||
|
#endif
|
||||||
clkd, setd, resetd);
|
clkd, setd, resetd);
|
||||||
} else if (clkd) {
|
} else if (clkd) {
|
||||||
delays = tprintf("(clk_delay = %s "
|
delays = tprintf("(clk_delay = %s"
|
||||||
"rise_delay = 1.0ns fall_delay = 2.0ns)",
|
#ifdef FF_LATCH_DEFAULT_DELAYS
|
||||||
|
" rise_delay = 1.0ns fall_delay = 1.0ns)",
|
||||||
|
#else
|
||||||
|
" rise_delay = 1.0ns fall_delay = 2.0ns)",
|
||||||
|
#endif
|
||||||
clkd);
|
clkd);
|
||||||
} else if (setd) {
|
} else if (setd) {
|
||||||
delays = tprintf("(set_delay = %s reset_delay = %s "
|
delays = tprintf("(set_delay = %s reset_delay = %s"
|
||||||
"rise_delay = 1.0ns fall_delay = 2.0ns)",
|
#ifdef FF_LATCH_DEFAULT_DELAYS
|
||||||
|
" rise_delay = 1.0ns fall_delay = 1.0ns)",
|
||||||
|
#else
|
||||||
|
" rise_delay = 1.0ns fall_delay = 2.0ns)",
|
||||||
|
#endif
|
||||||
setd, resetd);
|
setd, resetd);
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef FF_LATCH_DEFAULT_DELAYS
|
||||||
|
delays = tprintf("(rise_delay = 1.0ns fall_delay = 1.0ns)");
|
||||||
|
#else
|
||||||
delays = tprintf("(rise_delay = 1.0ns fall_delay = 2.0ns)");
|
delays = tprintf("(rise_delay = 1.0ns fall_delay = 2.0ns)");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
delete_timing_data(tdp1);
|
delete_timing_data(tdp1);
|
||||||
delete_timing_data(tdp2);
|
delete_timing_data(tdp2);
|
||||||
|
|
@ -2793,14 +2887,14 @@ static char *get_delays_ugff(char *rem, char *d_name)
|
||||||
s1 = NULL;
|
s1 = NULL;
|
||||||
if (enab) {
|
if (enab) {
|
||||||
if (d_delay) {
|
if (d_delay) {
|
||||||
s1 = tprintf("%s = %s enable_delay = %s ",
|
s1 = tprintf("%s = %s enable_delay = %s",
|
||||||
dname, d_delay, enab);
|
dname, d_delay, enab);
|
||||||
} else {
|
} else {
|
||||||
s1 = tprintf("enable_delay = %s ", enab);
|
s1 = tprintf("enable_delay = %s", enab);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (d_delay) {
|
if (d_delay) {
|
||||||
s1 = tprintf("%s = %s ", dname, d_delay);
|
s1 = tprintf("%s = %s", dname, d_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setd = NULL;
|
setd = NULL;
|
||||||
|
|
@ -2816,18 +2910,35 @@ static char *get_delays_ugff(char *rem, char *d_name)
|
||||||
} else if (tppcqhl && strlen(tppcqhl) > 0) {
|
} else if (tppcqhl && strlen(tppcqhl) > 0) {
|
||||||
setd = resetd = tppcqhl;
|
setd = resetd = tppcqhl;
|
||||||
}
|
}
|
||||||
|
s2 = NULL;
|
||||||
if (setd) {
|
if (setd) {
|
||||||
s2 = tprintf("set_delay = %s reset_delay = %s "
|
s2 = tprintf("set_delay = %s reset_delay = %s"
|
||||||
"rise_delay = 1.0ns fall_delay = 2.0ns)",
|
#ifdef FF_LATCH_DEFAULT_DELAYS
|
||||||
|
" rise_delay = 1.0ns fall_delay = 1.0ns",
|
||||||
|
#else
|
||||||
|
" rise_delay = 1.0ns fall_delay = 2.0ns",
|
||||||
|
#endif
|
||||||
setd, resetd);
|
setd, resetd);
|
||||||
} else {
|
} else {
|
||||||
s2 = tprintf("rise_delay = 1.0ns fall_delay = 2.0ns)");
|
#ifdef FF_LATCH_DEFAULT_DELAYS
|
||||||
|
s2 = tprintf("rise_delay = 1.0ns fall_delay = 1.0ns");
|
||||||
|
#else
|
||||||
|
s2 = tprintf("rise_delay = 1.0ns fall_delay = 2.0ns");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (s1) {
|
if (s1) {
|
||||||
delays = tprintf("(%s%s", s1, s2);
|
if (s2) {
|
||||||
|
delays = tprintf("(%s %s)", s1, s2);
|
||||||
|
} else {
|
||||||
|
delays = tprintf("(%s)", s1);
|
||||||
|
}
|
||||||
tfree(s1);
|
tfree(s1);
|
||||||
} else {
|
} else {
|
||||||
delays = tprintf("(%s", s2);
|
if (s2) {
|
||||||
|
delays = tprintf("(%s)", s2);
|
||||||
|
} else {
|
||||||
|
delays = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tfree(s2);
|
tfree(s2);
|
||||||
delete_timing_data(tdp1);
|
delete_timing_data(tdp1);
|
||||||
|
|
@ -3632,6 +3743,9 @@ BOOL u_process_instance(char *nline)
|
||||||
if (!xspice) {
|
if (!xspice) {
|
||||||
if (eq(itype, "logicexp")) {
|
if (eq(itype, "logicexp")) {
|
||||||
delete_instance_hdr(hdr);
|
delete_instance_hdr(hdr);
|
||||||
|
if (ps_port_directions & 4) {
|
||||||
|
printf("TRANS_IN %s\n", nline);
|
||||||
|
}
|
||||||
behav_ret = f_logicexp(nline);
|
behav_ret = f_logicexp(nline);
|
||||||
if (!behav_ret && current_subckt) {
|
if (!behav_ret && current_subckt) {
|
||||||
fprintf(stderr, "ERROR in %s\n", current_subckt);
|
fprintf(stderr, "ERROR in %s\n", current_subckt);
|
||||||
|
|
@ -3644,6 +3758,9 @@ BOOL u_process_instance(char *nline)
|
||||||
return behav_ret;
|
return behav_ret;
|
||||||
} else if (eq(itype, "pindly")) {
|
} else if (eq(itype, "pindly")) {
|
||||||
delete_instance_hdr(hdr);
|
delete_instance_hdr(hdr);
|
||||||
|
if (ps_port_directions & 4) {
|
||||||
|
printf("TRANS_IN %s\n", nline);
|
||||||
|
}
|
||||||
behav_ret = f_pindly(nline);
|
behav_ret = f_pindly(nline);
|
||||||
if (!behav_ret && current_subckt) {
|
if (!behav_ret && current_subckt) {
|
||||||
fprintf(stderr, "ERROR in %s\n", current_subckt);
|
fprintf(stderr, "ERROR in %s\n", current_subckt);
|
||||||
|
|
@ -3662,7 +3779,7 @@ BOOL u_process_instance(char *nline)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ps_port_directions >= 2) {
|
if (ps_port_directions & 4) {
|
||||||
printf("TRANS_IN %s\n", nline);
|
printf("TRANS_IN %s\n", nline);
|
||||||
}
|
}
|
||||||
/* Skip past instance name, type, pwr, gnd */
|
/* Skip past instance name, type, pwr, gnd */
|
||||||
|
|
@ -3722,7 +3839,7 @@ BOOL u_process_model_line(char *line)
|
||||||
|
|
||||||
if (n > 0 && line[n] == '\n') line[n] = '\0';
|
if (n > 0 && line[n] == '\n') line[n] = '\0';
|
||||||
if (strncmp(line, ".model ", strlen(".model ")) == 0) {
|
if (strncmp(line, ".model ", strlen(".model ")) == 0) {
|
||||||
if (ps_port_directions >= 2) {
|
if (ps_port_directions & 4) {
|
||||||
printf("TRANS_IN %s\n", line);
|
printf("TRANS_IN %s\n", line);
|
||||||
}
|
}
|
||||||
newline = TMALLOC(char, strlen(line) + 1);
|
newline = TMALLOC(char, strlen(line) + 1);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue