Replace Pspice U* and .model cards with their Xspice equivalent statements. There are still memory leaks which will be plugged next. The .subckts have only digital ports, which will need to addressed for mixed A/D designs.

This commit is contained in:
Brian Taylor 2022-05-05 20:50:36 -07:00 committed by Holger Vogt
parent 2c3c632349
commit 96a1b528fd
3 changed files with 165 additions and 39 deletions

View File

@ -52,7 +52,7 @@ Author: 1985 Wayne A. Christopher
/* gtri - end - 12/12/90 */
#endif
/* #define INTEGRATE_UDEVICES */
#define INTEGRATE_UDEVICES
#ifdef INTEGRATE_UDEVICES
#include "ngspice/udevices.h"
#endif
@ -8287,21 +8287,43 @@ static void rem_double_braces(struct card* newcard)
}
#ifdef INTEGRATE_UDEVICES
static void list_the_cards(struct card *startcard, char *prefix)
{
struct card *card;
if (!startcard) { return; }
for (card = startcard; card; card = card->nextcard) {
char* cut_line = card->line;
printf("%s %s\n", prefix, cut_line);
}
}
static struct card *the_last_card(struct card *startcard)
{
struct card *card, *lastcard = NULL;
if (!startcard) { return NULL; }
for (card = startcard; card; card = card->nextcard) {
lastcard = card;
}
return lastcard;
}
static struct card *u_instances(struct card *startcard)
{
struct card *card, *returncard = NULL, *subcktcard = NULL;
struct card *newcard = NULL, *last_newcard = NULL;
int level = 0;
int models_ok = 0, models_not_ok = 0;
int udev_ok = 0, udev_not_ok = 0;
BOOL create_called = FALSE, repeat_pass = FALSE;
BOOL skip_next = FALSE;
BOOL skip_next = FALSE, verbose = FALSE;
char *tmp = NULL, *pos;
card = startcard;
while (card) {
char *cut_line = card->line;
skip_next = FALSE;
printf("line: %s\n", cut_line);
if (verbose) printf("line: %s\n", cut_line);
if (ciprefix(".subckt", cut_line)) {
models_ok = models_not_ok = 0;
udev_ok = udev_not_ok = 0;
@ -8311,48 +8333,68 @@ static struct card *u_instances(struct card *startcard)
printf("Too many nesting levels\n");
break;
}
tmp = TMALLOC(char, strlen(cut_line) + 1);
(void) memcpy(tmp, cut_line, strlen(cut_line) + 1);
subcktcard = card;
printf("** subckt: %s\n", cut_line);
if (verbose) printf("** subckt: %s\n", cut_line);
if (!repeat_pass) {
if (create_called) {
cleanup_model_xlator();
cleanup_udevice();
}
create_model_xlator();
initialize_udevice();
create_called = TRUE;
printf("Doing first pass\n");
if (verbose) printf("Doing first pass\n");
} else {
printf("Doing second pass\n");
pos = strstr(tmp, "optional");
if (pos) {
*pos = '\0';
}
//printf(" %s\n", tmp);
if (verbose) printf("Doing second pass\n");
}
//tfree(tmp);
} else if (ciprefix(".ends", cut_line)) {
level--;
printf("** ends: %s\n", cut_line);
if (verbose) printf("** ends: %s\n", cut_line);
if (repeat_pass) {
printf("Second pass ");
newcard = replacement_udevice_cards();
if (newcard) {
subcktcard->nextcard = newcard;
tfree(subcktcard->line);
subcktcard->line = tmp;
//list_the_cards(newcard, "Replacement:");
last_newcard = the_last_card(newcard);
if (last_newcard) {
last_newcard->nextcard = card; // the .ends card
}
}
if (verbose) printf("Second pass ");
//printf(" %s\n", cut_line);
} else {
printf("First pass ");
if (verbose) printf("First pass ");
}
printf("udev_ok=%d udev_not_ok=%d models_ok=%d models_not_ok=%d\n",
if (verbose) printf("udev_ok=%d udev_not_ok=%d models_ok=%d models_not_ok=%d\n",
udev_ok, udev_not_ok, models_ok, models_not_ok);
if (models_not_ok > 0 || udev_not_ok > 0) {
repeat_pass = FALSE;
cleanup_model_xlator();
cleanup_udevice();
create_called = FALSE;
} else if (udev_ok > 0) {
printf("Repeat subckt\n");
if (verbose) printf("Repeat subckt\n");
repeat_pass = TRUE;
card = subcktcard;
skip_next = TRUE;
} else {
repeat_pass = FALSE;
cleanup_model_xlator();
cleanup_udevice();
create_called = FALSE;
}
subcktcard = NULL;
} else if (ciprefix(".model", cut_line)) {
if (subcktcard && !repeat_pass) {
printf("** model: %s\n", cut_line);
if (verbose) printf("** model: %s\n", cut_line);
if (!u_process_model_line(cut_line)) {
printf("Unable to convert model\n");
if (verbose) printf("Unable to convert model\n");
models_not_ok++;
} else {
models_ok++;
@ -8360,30 +8402,32 @@ static struct card *u_instances(struct card *startcard)
}
} else if (ciprefix("u", cut_line)) {
if (subcktcard) {
printf("** instance: %s\n", cut_line);
if (verbose) printf("** instance: %s\n", cut_line);
if (repeat_pass) {
if (!u_process_instance(cut_line)) {
/* Bail out */
printf("Unable to convert instance\n");
if (verbose) printf("Unable to convert instance\n");
break;
}
} else {
if (u_check_instance(cut_line)) {
printf("Instance can be converted\n");
if (verbose) printf("Instance can be converted\n");
udev_ok++;
} else {
printf("Instance can NOT be converted\n");
if (verbose) printf("Instance can NOT be converted\n");
udev_not_ok++;
}
}
}
} else {
udev_not_ok++;
}
if (!skip_next) {
card = card->nextcard;
}
}
if (create_called) {
cleanup_model_xlator();
cleanup_udevice();
}
return returncard;
}
@ -8435,10 +8479,13 @@ static struct card *pspice_compat(struct card *oldcard)
}
#ifdef INTEGRATE_UDEVICES
//list_the_cards(oldcard, "After AKO");
/* Here
{
struct card *ucard;
ucard = u_instances(oldcard);
}
*/
#endif
/* Process .distribution cards. */
@ -8474,6 +8521,18 @@ static struct card *pspice_compat(struct card *oldcard)
nextcard = insert_new_line(nextcard, new_str, 9, 0);
nextcard->nextcard = oldcard;
#ifdef INTEGRATE_UDEVICES
/* or here? */
{
struct card *ucard;
//ucard = u_instances(oldcard);
//ucard = u_instances(nextcard);
ucard = u_instances(newcard);
list_the_cards(oldcard, "After udevices");
}
#endif
/* add predefined parameters TEMP, VT after each subckt call */
/* FIXME: This should not be necessary if we had a better sense of
hierarchy during the evaluation of TEMPER */

View File

@ -17,10 +17,13 @@
hazard detection.
Only the common logic gates, flip-flops, and latches are suported.
First pass through a subcircuit. Call create_model_xlator() and read the
First pass through a subcircuit. Call initialize_udevice() and read the
.model cards by calling u_process_model_line() (or similar) for each card,
The delays for the different types (ugate, utgate, ueff, ugff) are stored
by get_delays_...() and add_delays_to_model_xlator().
by get_delays_...() and add_delays_to_model_xlator(). Also, during the
first pass, check that each U* instance can be translated to Xspice.
If there are any .model or U* instance cards that cannot be processed
in the .subckt, then there is no second pass and the .subckt is skipped.
Second pass through a subcircuit. To translate each U* instance call
u_process_instance_line() (or similar). This calls translate_...()
@ -29,7 +32,7 @@
gen_..._instance(). Creating new cards to replace the U* and .model
cards needs modifying where the output goes from processing an instance.
This will be added either to this file or to frontend/inpcom.c.
Finally, call cleanup_model_xlator() before repeating the sequence for
Finally, call cleanup_udevice() before repeating the sequence for
another subcircuit.
*/
@ -44,13 +47,13 @@
#include "ngspice/bool.h"
#include "ngspice/stringskip.h"
#include "ngspice/stringutil.h"
#include "ngspice/inpdefs.h"
#include "ngspice/udevices.h"
/*
TODO check for name collisions when creating new names
TODO add support for oa and oai gates, srff, pullup/down
*/
#define TRACE
extern struct card* insert_new_line(
struct card* card, char* line, int linenum, int linenum_orig);
/* #define TRACE */
/* device types */
#define D_AND 0
@ -160,6 +163,10 @@ typedef struct s_xlator {
Xlatep iter;
} Xlator;
#ifdef TRACE
static void interpret_xlator(Xlatorp xp, BOOL brief);
#endif
/* For timing model extraction */
#define EST_UNK -1
#define EST_MIN 0
@ -324,25 +331,21 @@ static void delete_xlate(Xlatep p)
static Xlatep 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;
xlp = TMALLOC(Xlate, 1);
xlp->next = NULL;
xlp->translated = TMALLOC(char, strlen(translated) + 1);
strcpy(xlp->translated, translated);
xlp->delays = TMALLOC(char, strlen(delays) + 1);
strcpy(xlp->delays, delays);
xlp->utype = TMALLOC(char, strlen(utype) + 1);
strcpy(xlp->utype, utype);
xlp->xspice = TMALLOC(char, strlen(xspice) + 1);
strcpy(xlp->xspice, xspice);
xlp->tmodel = TMALLOC(char, strlen(tmodel) + 1);
strcpy(xlp->tmodel, tmodel);
xlp->mname = TMALLOC(char, strlen(mname) + 1);
strcpy(xlp->mname, mname);
return xlp;
@ -448,6 +451,19 @@ static Xlatep next_xlator(Xlatorp xp)
return ret;
}
static Xlatorp append_xlator(Xlatorp dest, Xlatorp src)
{
Xlatep x1, copy;
if (!dest || !src) { return NULL; }
for (x1 = first_xlator(src); x1; x1 = next_xlator(src)) {
copy = create_xlate(x1->translated, x1->delays, x1->utype,
x1->xspice, x1->tmodel, x1->mname);
dest = add_xlator(dest, copy);
}
return dest;
}
#ifdef TRACE
static void interpret_xlator(Xlatorp xp, BOOL brief)
{
@ -479,11 +495,59 @@ static void interpret_xlator(Xlatorp xp, BOOL brief)
/* static Xlatorp for collecting timing model delays */
static Xlatorp model_xlatorp = NULL;
static Xlatorp default_models = NULL;
static Xlatorp translated_p = NULL;
void create_model_xlator(void)
static void create_translated_xlator(void)
{
translated_p = create_xlator();
}
static void cleanup_translated_xlator(void)
{
#ifdef TRACE
printf("\nStart cleanup\n");
interpret_xlator(translated_p, TRUE);
printf("End cleanup\n");
#endif
delete_xlator(translated_p);
translated_p = NULL;
}
struct card *replacement_udevice_cards(void)
{
struct card *newcard = NULL, *nextcard = NULL;
char *new_str = NULL;
Xlatep x;
int count = 0;
if (!translated_p) { return NULL; }
for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) {
new_str = copy(x->translated);
if (count == 0) {
count++;
newcard = insert_new_line(NULL, new_str, 0, 0);
} else if (count == 1) {
count++;
nextcard = insert_new_line(newcard, new_str, 0, 0);
} else {
count++;
nextcard = insert_new_line(nextcard, new_str, 0, 0);
}
}
/*
for (card = newcard; card; card = card->nextcard) {
char* cut_line = card->line;
printf("NEW CARD: %s\n", cut_line);
}
*/
return newcard;
}
void initialize_udevice(void)
{
Xlatep xdata;
create_translated_xlator();
model_xlatorp = create_xlator();
default_models = create_xlator();
/* .model d0_gate ugate () */
@ -500,8 +564,9 @@ void create_model_xlator(void)
(void) add_xlator(default_models, xdata);
}
void cleanup_model_xlator(void)
void cleanup_udevice(void)
{
cleanup_translated_xlator();
delete_xlator(model_xlatorp);
model_xlatorp = NULL;
delete_xlator(default_models);
@ -2684,6 +2749,7 @@ BOOL u_process_instance(char *nline)
retval = FALSE;
}
if (xp) {
append_xlator(translated_p, xp);
#ifdef TRACE
interpret_xlator(xp, TRUE);
#endif

View File

@ -4,7 +4,8 @@
BOOL u_process_instance(char *line);
BOOL u_process_model_line(char *line);
BOOL u_check_instance(char *line);
void create_model_xlator(void);
void cleanup_model_xlator(void);
void initialize_udevice(void);
struct card *replacement_udevice_cards(void);
void cleanup_udevice(void);
#endif