static char *SccsId = "@(#)findDev.c 4.14 (TU-Delft) 06/26/92";
/**********************************************************

Name/Version      : xsls/4.14

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author(s)         : A.J. van Genderen
Creation date     : 16-Feb-1987
Modified by       : A.J. van Genderen
Modification date : 16-Feb-1987


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1987 , All rights reserved
**********************************************************/
#include "incl.h"

extern int language;
extern int dialect;
extern int incl_model;
extern int choosebulk;
extern int tog_nnod;
extern int tog_pnod;
extern int tog_nodnbr;
extern int xtree;
extern int alsoImport;

extern DM_PROJECT *dmproject;

extern FILE *fp_out;

static struct model_info *Devs;

static FILE *fp_spicemod;
static char *fn_spicemod;

static struct cir *NoDevs;

float vpbulk;
float vnbulk;
int vpbulkdefined;
int vnbulkdefined;
int nvolt_in_lib;
int pvolt_in_lib;

int lineno;
int spicemod;

initDevs ()
{
    Devs = NULL;
    fp_spicemod = NULL;
    vpbulkdefined = 0;
    vnbulkdefined = 0;

    nvolt_in_lib = 0;
    pvolt_in_lib = 0;

    NoDevs = NULL;
}

struct model_info * findDev (name, imported, proj, isroot)    
char *name;              
int imported;
DM_PROJECT *proj;
int isroot;
{              
    /* look if the cell is a device (Devs list might be extended) */

    int device;
    struct model_info *m;
    struct model_info *mlast;
    char primnm[32];
    FILE *fp;
    DM_CELL *dkey;
    DM_STREAM *dsp;
    char *real_name;
    struct cir *cl;
    struct cir *newcl;
    struct model_info *check_predef_dev ();
    struct model_info *check_spec_dev ();


    /* first, check it from the existing Devs list */

    m = Devs;
    mlast = m;
    while (m != NULL && strcmp (m -> name, name) != 0) {
        mlast = m;
        m = m -> next;
    }
    if (m != NULL)
        return (m);    /* device in Devs list */

    /* also, check if it has not been examined before */

    cl = NoDevs;
    while (cl && strcmp (cl -> name, name) != 0) {
        cl = cl -> next;
    }
    if (cl)
        return (NULL); /* device has previously been recognized as non-device */

#ifndef ESE
    /* second, if SPICE check it from the spice_prim file */

    if (language == SPICE && (fp = fopen ("spice_prim", "r")) != NULL) {

        device = 0;

        while (fscanf (fp, "%s", primnm) > 0 && !device) {

	    if (strcmp (primnm, name) == 0) {

                PALLOC (m, 1, struct model_info);
                strcpy (m -> name, name);
                strcpy (m -> out_name, m -> name);
                m -> dw = 0;
                m -> dl = 0;
                m -> vbulkdefined = 0;
                m -> prefix[0] = '\0';
                m -> spec_dev = 0;
	        m -> param = "w l";
   
                if (mlast)
                    mlast -> next = m;
                else
                    Devs = m;
                m -> next = NULL;

	        fscanf (fp, "%s", m -> prefix);

		m -> proj = dmFindProjKey (imported, name, proj,
					 &real_name, CIRCUIT);

		if (xtree && alsoImport 
		    && strcmp (name, real_name) != 0) {
		    fatalErr (
		 "cannot handle aliases when also retrieving imported cells:", 
			  real_name);
		}

                if ((dkey = dmCheckOut (m -> proj, real_name, 
                                       isroot ? WORKING : ACTUAL, 
			               DONTCARE, CIRCUIT, READONLY)) != NULL) {

                    /* read the term file */

                    dsp = dmOpenStream (dkey, "term", "r");
                    termRun (m, dsp, 0, -1);
                    dmCloseStream (dsp, COMPLETE);

                    dmCheckIn (dkey, QUIT);
                }

                device = 1;
	    }

	    while (getc (fp) != '\n');
        }

        fclose (fp);

        if (device)
            return (m);
    }
#endif /* ESE */


    /* third, if not SPICE then look at predefined devices */

    if (language != SPICE && (m = check_predef_dev (name, mlast))) {

        return (m);    /* device is predefined */
    }


    /* fourth, look if the device is specified in the database */

    if (m = check_spec_dev (name, imported, proj, mlast, isroot)) {

        return (m);    /* device is specified in the database */
    }

    
    /* fifth, if SPICE then look at predefined devices */

    if (language == SPICE && (m = check_predef_dev (name, mlast))) {

        return (m);    /* device is predefined */
    }

    
    /* it is not a device */

    PALLOC (newcl, 1, struct cir);
    strcpy (newcl -> name, name);
    newcl -> next = NoDevs;
    NoDevs = newcl;

    return (NULL);
}


struct model_info *check_spec_dev (name, imported, proj, mlast, isroot)
char *name;
int imported;
DM_PROJECT *proj;
struct model_info *mlast;
int isroot;
{
    DM_CELL *dkey;
    DM_STREAM *dsp;
    char keyword[80];
    char buf[80];
    struct stat statbuf;
    struct model_info *m;
    char *real_name;
    DM_PROJECT *new_proj;
    IMPCELL **impcelllist;
    int isImportedCell;

    m = NULL;
    isImportedCell = 0;

    if (imported) {
	impcelllist = (IMPCELL **)dmGetMetaDesignData (IMPORTEDCELLLIST, 
					               proj, CIRCUIT);
	while (*impcelllist) {
	    if (strcmp ((*impcelllist) -> alias, name) == 0) {
		isImportedCell = 1;
		break;
	    }
	    impcelllist++;
	}
    }

    if (isImportedCell
     || (int) dmGetMetaDesignData (EXISTCELL, proj, name, CIRCUIT) == 1) {

        new_proj = dmFindProjKey (imported, name, 
			      proj, &real_name, CIRCUIT);

	if (xtree && alsoImport 
	    && strcmp (name, real_name) != 0) {
	    fatalErr (
	 "cannot handle aliases when also retrieving imported cells:", 
		  real_name);
	}

        if ((dkey = dmCheckOut (new_proj, real_name, 
				isroot ? WORKING : ACTUAL, 
			        DONTCARE, CIRCUIT, READONLY)) == NULL) {
            return (NULL);
        }

        if (dmStat (dkey, "devmod", &statbuf) == 0) {

            /* it is a database-specified device */

            PALLOC (m, 1, struct model_info);
            strcpy (m -> name, name);
            strcpy (m -> out_name, m -> name);
            strcpy (m -> orig_name, real_name);
	    m -> imported = imported;
	    m -> proj = new_proj;
            m -> dw = 0;
            m -> dl = 0;
	    m -> vbulkdefined = 0;
            m -> prefix[0] = '\0';
            m -> spec_dev = 1;
	    m -> param = "w l";
   
            if (mlast)
                mlast -> next = m;
            else
                Devs = m;
            m -> next = NULL;

            /* read the devmod file */

            dsp = dmOpenStream (dkey, "devmod", "r");

            spicemod = 0;
	    lineno = 1;

	    while (getword (dsp -> dmfp, keyword, 0, 1) > 0) {

		if (strcmp (keyword, "begin") == 0) {

		    if (getword (dsp -> dmfp, keyword, 1, 0) > 0) {
			if (strcmp (keyword, "spicemod") == 0)
			    spicemod = 1;
		    }
		    else {
			sprintf (buf, "%d", lineno);
			fatalErr ("stream devmod: syntax error at line", buf);
		    }
		}
		else if (strcmp (keyword, "prefix") == 0 && spicemod) {
		    getword (dsp -> dmfp, m -> prefix, 1, 0);
                }
		else if (strcmp (keyword, "dw") == 0 && spicemod) {
		    if (getword (dsp -> dmfp, buf, 1, 0) > 0)
			sscanf (buf, "%e", &m -> dw);
                }
		else if (strcmp (keyword, "dl") == 0 && spicemod) {
		    if (getword (dsp -> dmfp, buf, 1, 0) > 0)
			sscanf (buf, "%e", &m -> dl);
                }
		else if (strcmp (keyword, "bulk") == 0 && spicemod) {
		    if (getword (dsp -> dmfp, buf, 1, 0) > 0)
			sscanf (buf, "%e", &m -> vbulk);
		    else
			m -> vbulk = 0.0;
		    m -> vbulkdefined = 1;
                }
		else if (strcmp (keyword, "end") == 0 && spicemod) {
		    spicemod = 0;
		}
	    }

            dmCloseStream (dsp, COMPLETE);


            /* read the term file */

            dsp = dmOpenStream (dkey, "term", "r");
            termRun (m, dsp, 0, -1);
            dmCloseStream (dsp, COMPLETE);
        }

        dmCheckIn (dkey, QUIT);
    }

    return (m);
}

struct model_info *check_predef_dev (name, mlast)
char *name;
struct model_info *mlast;
{
    struct model_info *m = NULL;

    if (strcmp (name, "nenh") == 0) {

        PALLOC (m, 1, struct model_info);
        strcpy (m -> name, "nenh");
        strcpy (m -> out_name, m -> name);
	m -> proj = NULL;
        m -> dw = 0;
        m -> dl = 0;
        m -> vbulk = -5.0;
	m -> vbulkdefined = 1;
        m -> prefix[0] = '\0';
	m -> spec_dev = 0;
	m -> param = "w l";
        switch (language) {
            case SLS:
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
	    case SPICE:
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
	    default:
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
        }

    }
    else if (strcmp (name, "penh") == 0) {

        PALLOC (m, 1, struct model_info);
        strcpy (m -> name, "penh");
        strcpy (m -> out_name, m -> name);
	m -> proj = NULL;
        m -> dw = 0;
        m -> dl = 0;
        m -> vbulk = 5.0;
	m -> vbulkdefined = 1;
        m -> prefix[0] = '\0';
	m -> spec_dev = 0;
	m -> param = "w l";
        switch (language) {
	    case SLS:
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
	    case SPICE:
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
	    default:
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
        }

    }
    else if (strcmp (name, "ndep") == 0) {

        PALLOC (m, 1, struct model_info);
        strcpy (m -> name, "ndep");
        strcpy (m -> out_name, m -> name);
	m -> proj = NULL;
        m -> dw = 0;
        m -> dl = 0;
        m -> vbulk = -5.0;
	m -> vbulkdefined = 1;
        m -> prefix[0] = '\0';
	m -> spec_dev = 0;
	m -> param = "w l";
        switch (language) {
	    case SLS:
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
	    case SPICE:
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
	    default:
	        termstore (m, "g", 0, NULL, NULL, INPUT);
	        termstore (m, "d", 0, NULL, NULL, INOUT);
	        termstore (m, "s", 0, NULL, NULL, INOUT);
	        break;
        }

    }
    else if (strcmp (name, "res") == 0) {

        PALLOC (m, 1, struct model_info);
        strcpy (m -> name, "res");
        strcpy (m -> out_name, m -> name);
	m -> proj = NULL;
	m -> spec_dev = 0;
	m -> param = "v";
        termstore (m, "p", 0, NULL, NULL, INOUT);
        termstore (m, "n", 0, NULL, NULL, INOUT);

    }
    else if (strcmp (name, "cap") == 0) {

        PALLOC (m, 1, struct model_info);
        strcpy (m -> name, "cap");
        strcpy (m -> out_name, m -> name);
	m -> proj = NULL;
	m -> spec_dev = 0;
	m -> param = "v";
        termstore (m, "p", 0, NULL, NULL, INPUT);
        termstore (m, "n", 0, NULL, NULL, INPUT);

    }

    if (m != NULL) {
        if (Devs == NULL)
            Devs = m;
        else {
            mlast -> next = m;
        }
        m -> next = NULL;
    }

    return (m);
}

termstore (m, name, dim, lower, upper, type)
struct model_info *m;
char *name;
long dim;
long *lower;
long *upper;
int type;
{
    struct term_ref *end;
    struct term_ref *tref;

    PALLOC (tref, 1, struct term_ref);
    PALLOC ((tref -> t), 1, struct cir_term);

    tref -> type = type;

    tref -> next = NULL;
    sprintf (tref -> t -> term_name, "%s", name);
    tref -> t -> term_dim = dim;
    tref -> t -> term_upper = upper;
    tref -> t -> term_lower = lower;

    if ((end = m -> terms) == NULL) {
	m -> terms = tref;
    }
    else {
	while (end -> next != NULL) 
	    end = end -> next;
	end -> next = tref;
    }
}

interDevs ()
{
    char dev_name[DM_MAXNAME + 1];
    char c;
    char buf[128];
    long fpos_remem;
    long ftell ();
    struct model_info *m;

    if (language == SPICE && incl_model) {

        if (dialect == ESPICE) {
            fn_spicemod = (char *)dmGetMetaDesignData (
				     PROCPATH, dmproject, "espicemod");
        }
        else {
            fn_spicemod = (char *)dmGetMetaDesignData (
				     PROCPATH, dmproject, "spicemod");
        }

        OPENR (fp_spicemod, fn_spicemod, 0);

        if (fp_spicemod != NULL) {

            /* first read comment at top of file */
            while ((c = getc (fp_spicemod)) == '#') {
	        while (getc (fp_spicemod) != '\n');
            }
	    ungetc (c, fp_spicemod);

            while (fscanf (fp_spicemod, "%s", dev_name) == 1 
		   && dev_name[0] != '%') {

	        m = Devs; 
	        while (m != NULL && strcmp (m -> name, dev_name) != 0) {
	            m = m -> next;
	        }

		if (m != NULL && !m -> spec_dev) {
	            if (fscanf (fp_spicemod, "%s %e %e", m -> out_name, 
				        &(m -> dw), &(m -> dl)) != 3) {
	                fatalErr ("Syntax error in spicemod file", NULL);
	            }
		}
		else
	            fscanf (fp_spicemod, "%*s %*e %*e");
            }

            if (dev_name[0] == '%') {
	        while (getc (fp_spicemod) != '\n');
            }

            if (choosebulk) {
	        fpos_remem = ftell (fp_spicemod);
                while (fscanf (fp_spicemod, "%s", buf) == 1) {
	            if (strcmp (buf, "vnbulk") == 0
                        || strcmp (buf, "VNBULK") == 0) {

                        fscanf (fp_spicemod, "%*s %*s %e", &vnbulk);

		        tog_nnod = 1;
			nvolt_in_lib = 1;
	            }
	            if (strcmp (buf, "vpbulk") == 0
                        || strcmp (buf, "VPBULK") == 0) {

                        fscanf (fp_spicemod, "%*s %*s %e", &vpbulk);

		        tog_pnod = 1;
			pvolt_in_lib = 1;
	            }
	            while (getc (fp_spicemod) != '\n');
	        }
	        fseek (fp_spicemod, fpos_remem, 0);
            }
        }
    }

    if (language == SPICE && choosebulk) {

	m = Devs; 
	while (m != NULL) {

            if (m -> vbulkdefined) {

                /* we require that 1. vpbulk > vnbulk 
			           2. vpbulk > 0 if ! vnbulkdefined
			           3. vnbulk <= 0 if ! vpbulkdefined
                */

                if (! vpbulkdefined  && ! vnbulkdefined) {
                    if (m -> vbulk > 0.0) {
                        tog_pnod = 1;
                        vpbulk = m -> vbulk;
                        vpbulkdefined = 1;
                    }
                    else {
                        tog_nnod = 1;
                        vnbulk = m -> vbulk;
                        vnbulkdefined = 1;
                    }
                }
                else if (! vpbulkdefined && vnbulkdefined) {
                    if (m -> vbulk > vnbulk) {
                        tog_pnod = 1;
                        vpbulk = m -> vbulk;
                        vpbulkdefined = 1;
                    }
                    else if (m -> vbulk < vnbulk) {
                        tog_pnod = 1;
                        vpbulk = vnbulk;
                        vnbulk = m -> vbulk;
                        vpbulkdefined = 1;
                    }
                }
                else if (vpbulkdefined && ! vnbulkdefined) {
                    if (m -> vbulk < vpbulk) {
                        tog_nnod = 1;
                        vnbulk = m -> vbulk;
                        vnbulkdefined = 1;
                    }
                    else if (m -> vbulk > vpbulk) {
                        tog_nnod = 1;
                        vnbulk = vpbulk;
                        vpbulk = m -> vbulk;
                        vnbulkdefined = 1;
                    }
                }
                else {
                    if (m -> vbulk != vpbulk && m -> vbulk != vnbulk) {
                        sprintf (buf, "%fv, %fv and %fv", 
                                 vnbulk, vpbulk, m -> vbulk);
                        fatalErr (
                    "cannot handle more than 2 different bulk voltages;", buf);
                    }
                }
            }

	    m = m -> next;
	}
    }
}

printDevs ()
{
    struct model_info *m;
    int first;

    first = 1;

    m = Devs;
    while (m) {

        {
	    if (first) {
                oprint (0, "(external Primitives");
                oprint (0, "(edifLevel 0)");
                oprint (0, "(technology (numberDefinition))");
		first = 0;
	    }

            prHead (m, 1);

            oprint (0, ")");
            oprint (0, ")");
	}

	m = m -> next;
    }

    if (!first) {
        oprint (0, ")");
    }
}

endDevs ()
{
    DM_STREAM *dsp;
    DM_CELL *dkey;
    struct model_info *m;
    char buf[32];
    char c1, c2, c3, c;
    char keyword[80];

    if (language == SPICE && incl_model) {

        /* first add model descriptions from library */

        if (fp_spicemod) {

	    while ((c = getc (fp_spicemod)) != EOF) {
	        putc (c, fp_out);
	    }

	    CLOSE (fp_spicemod);
        }
        else {
	    putc ('\n', fp_out);
	}

        /* then add model descriptions from specified devices in the database */

	m = Devs;
	while (m) {

	    if (m -> spec_dev) {

		dkey = dmCheckOut (m -> proj, m -> orig_name, ACTUAL,
				   DONTCARE, CIRCUIT, READONLY);

		dsp = dmOpenStream (dkey, "devmod", "r");

		lineno = 1;

		while (getword (dsp -> dmfp, keyword, 0, 1) > 0) {

		    if (strcmp (keyword, "begin") == 0) {

			if (getword (dsp -> dmfp, keyword, 1, 0) > 0) {

			    if (strcmp (keyword, "spicemod") == 0) {

				while ((c = getc (dsp -> dmfp)) != '\n'
				       && c != EOF);
				fprintf (fp_out, "* device %s\n", 
						 m -> name);

				c1 = c2 = c3 = '\0';
				while ((c = getc (dsp -> dmfp)) != EOF
				       && !(c1 == '\n' && c2 == 'e' 
					    && c3 == 'n' && c == 'd')) {

				    if (!(c1 == '\n' 
					  && (c2 == ' ' || c2 == '\t'))) {

					c1 = c2;

					if (c1 != '\0')
					    putc (c1, fp_out);
				    }
				    c2 = c3;
				    c3 = c;

				}
			    }
			}
		    }
		}

		dmCloseStream (dsp, COMPLETE);

		dmCheckIn (dkey, QUIT);
	    }

	    m = m -> next;
	}

	if (choosebulk && !pvolt_in_lib && tog_pnod && vpbulkdefined) {
	    oprint (0, "vpbulk ");
	    nmprint (0, "pbulk", 0, NULL, NULL, 0, tog_nodnbr, 0);
	    oprint (0, " 0 ");
	    sprintf (buf, "%fV", vpbulk);
	    oprint (0, buf);
	    oprint (0, "\n");

	    oprint (0, "rpbulk ");
	    nmprint (0, "pbulk", 0, NULL, NULL, 0, tog_nodnbr, 0);
	    oprint (0, " 0 ");
	    oprint (0, "100meg");
	    oprint (0, "\n");
	    oprint (0, "\n");
	}

	if (choosebulk && !nvolt_in_lib && tog_nnod && vnbulkdefined) {
	    oprint (0, "vnbulk ");
	    nmprint (0, "nbulk", 0, NULL, NULL, 0, tog_nodnbr, 0);
	    oprint (0, " 0 ");
	    sprintf (buf, "%fV", vnbulk);
	    oprint (0, buf);
	    oprint (0, "\n");

	    oprint (0, "rnbulk ");
	    nmprint (0, "nbulk", 0, NULL, NULL, 0, tog_nodnbr, 0);
	    oprint (0, " 0 ");
	    oprint (0, "100meg");
	    oprint (0, "\n");
	    oprint (0, "\n");
	}

	if (choosebulk && ((tog_pnod && vpbulkdefined && !pvolt_in_lib)
			   || (tog_nnod && vnbulkdefined && !nvolt_in_lib))) {
	    oprint (0, "\n");
	}
    }
}

int getword (fp, buf, onSameLine, onNewLine)
FILE *fp;
char *buf;
int onSameLine;
int onNewLine;
{
    char c = '\0';

    if (onNewLine) {
        while ((c = getc (fp)) != '\n' && c != EOF);
	if (c == '\n')
	    lineno++;
    }

    if (c != EOF)
	c = getc (fp);

    while (c != EOF) {
	while (c == ' ' || c == '\t')
	    c = getc (fp);
	if (c == '\n') {
	    if (onSameLine) {
	        ungetc (c, fp);
		return (0);
	    }
	    else {
	        c = getc (fp);
	        lineno++;
	    }
	}
	else if (spicemod && c == '*') {
	    c = getc (fp);                 /* skip comment */
	}
	else {
	    ungetc (c, fp);
	    fscanf (fp, "%s", buf);
	    return (1);
	}
    }

    return (-1);
}

prImpDev ()
{
    prImpMod (Devs, "devices");
}
