static char *SccsId = "@(#)lcircuit.c 3.10 (TU-Delft) 09/28/92";
/**********************************************************

Name/Version      : dblist/3.10

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

Author(s)         : A.J. Schooneveld
Creation date     : 24-Mar-1988
Modified by       : G.W. Sloof
Modification date : 13-Apr-1988
Modified by       : S. de Graaf
Modification date : 28-Apr-1988


        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) 1988, All rights reserved
**********************************************************/
#include "stdio.h"
#include "malloc.h"
#include "string.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "dmincl.h"

int view_nr;

typedef struct _mc { /* describes info for a cell call */
    char cellname[DM_MAXNAME + 1];
    int func;
    long num;
    struct _cell *cell;
    struct _mc *next;
} MC;

typedef struct _cell { /* describes info for cell definition */
    char cellname[DM_MAXNAME + 1];
    long numcellcall;
    int shown, func;
    int imported;
    struct _mc *subcell;
    struct _cell *next, *prev, *findnext;
} CELL;

extern DM_PROJECT *project; /* project key */
extern int dflag;
extern int hflag;
extern int iflag;
extern int rflag;
extern int sflag;
extern int tflag;
static int svalue;
extern int oneview;

static char *dev_list[] = {
    "nenh", "penh", "ndep", "cap", "res",
    "and", "nand", "or", "nor", "exor", "invert",
    NULL
};

static char **lay_cl;
static CELL *celllist = NULL;
static CELL *findlist = NULL;
static CELL unlinked;  /* used as a mark */

in_lay_cl (name)
char *name;
{
    register char **cl;

    if (!lay_cl)
	lay_cl = (char **)
	    dmGetMetaDesignData (CELLLIST, project, LAYOUT);
    for (cl = lay_cl; *cl != NULL; ++cl) {
	if (strcmp (*cl, name) == 0) return (1); /* yes */
    }
    return (0); /* no */
}

in_dev_list (name)
char *name;
{
    register char **cl;
    for (cl = dev_list; *cl != NULL; ++cl) {
	if (strcmp (*cl, name) == 0) return (1); /* yes */
    }
    return (0); /* no */
}

MC *
samelevel (name, subcelllist, func)
char *name;
MC *subcelllist;
int func;
{
    register MC *tmp;

    /* cell must have proper type (func or not) and name */
    for (tmp = subcelllist; tmp != NULL; tmp = tmp -> next) {
	if (strcmp (name, tmp -> cellname) == 0
		   && func == tmp -> func) return tmp;
    }
    return (tmp);
}

insertcell (cell)
CELL *cell;
{
    static CELL *prevcell;

    if (celllist == NULL) {
	celllist = findlist = cell;
    }
    else {
	prevcell -> next = cell;
	prevcell -> findnext = cell;
	cell -> prev = prevcell;
    }
    prevcell = cell;
}

int
find_f_attr (src)
register char *src;
{
    while (*src != '\0') {
	if (*src++ == 'f') {
	    if (*src == '\0' || *src == ';')
		return (1);
	}
	while (*src != '\0' && *src != ';') ++src;
	while (*src == ';') ++src;
    }
    return (0);
}

readcell (name, remoteName, view, dmpr)
char *name, *remoteName, *view;
DM_PROJECT *dmpr;
{
    DM_CELL *dmcell;
    DM_STREAM *dmstream;
    register MC *tmp, *tmpmc;
    register CELL *tmpcell;
    int i, isfunc = 0;
    long num;
    struct stat buf;

    if (!(tmpcell = (CELL *) calloc (1, sizeof (CELL)))) {
	die (3, name);
    }

    strcpy (tmpcell -> cellname, name);
    tmpcell -> func = 0;

    if (!remoteName) {
	dmcell = dmCheckOut (dmpr, name,
			ACTUAL, DONTCARE, view, READONLY);

	if (view_nr == 2) {
	    if (dmStat (dmcell, "fterm", &buf) == 0) {
		tmpcell -> func += 2;
	    }
	    if (dmStat (dmcell, "devmod", &buf) == 0) {
		tmpcell -> func += 4;
	    }
	    if (dmStat (dmcell, "mc", &buf)) goto chkin;
	}
	++(tmpcell -> func);
	dmstream = dmOpenStream (dmcell, "mc", "r");
	tmpmc = NULL; /* no cell calls yet */

	if (view_nr == 1) { /* layout */

	    while (dmGetDesignData (dmstream, GEO_MC) > 0) {

		/* increment cell call count */
		(tmpcell -> numcellcall)++;

		/* check if cell already called here */
		if ((tmp = (MC *) samelevel (gmc.cell_name,
			 tmpcell -> subcell, 0)) == NULL) {

		    /* is not found in the subcelllist,
		       insert it in the list */
		    if (!(tmp = (MC *) calloc (1, sizeof (MC)))) {
			die (3, gmc.cell_name);
		    }
		    if (tmpmc == NULL)
			tmpcell -> subcell = tmp;
		    else
			tmpmc -> next = tmp;
		    tmpmc = tmp;

		    strcpy (tmp -> cellname, gmc.cell_name);
		}

		/* record number of called cells */
		tmp -> num += (gmc.nx + 1) * (gmc.ny + 1);
	    }
	    if (dmStat (dmcell, "is_macro", &buf) == 0) {
		DM_STREAM *dsp;
		int flag;

		dsp = dmOpenStream (dmcell, "is_macro", "r");
		if (fscanf (dsp -> dmfp, "%d", &flag) > 0 && flag == 1)
		    tmpcell -> func += 8;
		dmCloseStream (dsp, COMPLETE);
	    }
	}
	else if (view_nr == 2) { /* circuit */

	    while (dmGetDesignData (dmstream, CIR_MC) > 0) {

		/* increment cell call count */
		(tmpcell -> numcellcall)++;

		/* inst_attribute used to check functional
						type of subcell */
		isfunc = find_f_attr (cmc.inst_attribute);

		/* check if cell already called here */
		if ((tmp = (MC *) samelevel (cmc.cell_name,
			     tmpcell -> subcell, isfunc)) == NULL) {

		    /* is not found in the subcelllist,
		       insert it in the list */
		    if (!(tmp = (MC *) calloc (1, sizeof (MC)))) {
			die (3, cmc.cell_name);
		    }
		    if (tmpmc == NULL)
			tmpcell -> subcell = tmp;
		    else
			tmpmc -> next = tmp;
		    tmpmc = tmp;

		    strcpy (tmp -> cellname, cmc.cell_name);

		    /* inst_attribute used to flag functional
		    ** in type of subcell
		    */
		    tmp -> func = isfunc;
		}

		/* record number of called cells */
		if (cmc.inst_dim != 0) {
		    num = 0; /* counter for number of instances */
		    for (i = 0; i < cmc.inst_dim; ++i)
			num += (cmc.inst_upper[i] - cmc.inst_lower[i] + 1);
		    tmp -> num += num;
		}
		else
		    tmp -> num += 1; /* one instance */
	    }
	}
	else if (view_nr == 3) { /* floorplan */

	    while (dmGetDesignData (dmstream, FLP_MC) > 0) {

		/* increment cell call count */
		(tmpcell -> numcellcall)++;

		/* check if cell already called here */
		if ((tmp = (MC *) samelevel (fmc.cell_name,
			 tmpcell -> subcell, 0)) == NULL) {

		    /* is not found in the subcelllist,
		       insert it in the list */
		    if (!(tmp = (MC *) calloc (1, sizeof (MC)))) {
			die (3, fmc.cell_name);
		    }
		    if (tmpmc == NULL)
			tmpcell -> subcell = tmp;
		    else
			tmpmc -> next = tmp;
		    tmpmc = tmp;

		    strcpy (tmp -> cellname, fmc.cell_name);
		}

		/* record number of called cells */
		tmp -> num += (fmc.nx + 1) * (fmc.ny + 1);
	    }
	}
	dmCloseStream (dmstream, QUIT);
chkin:
	dmCheckIn (dmcell, COMPLETE);
    }
    else
	tmpcell -> imported = 1;

    /* insert cell in list of cell descriptions */
    insertcell (tmpcell);
}

CELL *
findcell (name)
char *name;
{
    register CELL *tmp;

    for (tmp = findlist; tmp != NULL; tmp = tmp -> findnext) {
	if (strcmp (name, tmp -> cellname) == 0) return tmp;
    }
    return tmp;
}

updatecall (cell)
CELL *cell;
{
    register CELL *tmpc;
    register MC *tmpm;

    for (tmpm = cell -> subcell; tmpm != NULL; tmpm = tmpm -> next) {
	if ((tmpc = findcell (tmpm -> cellname)) == NULL) {
	    /* cannot find cell */
	    continue;
	}
	if (tmpc -> next != &unlinked) {
	    /* cell is still in celllist, do an unlink */
	    if (tmpc != celllist) {
		if (tmpc -> prev != NULL)
		    tmpc -> prev -> next = tmpc -> next;
		if (tmpc -> next != NULL)
		    tmpc -> next -> prev = tmpc -> prev;
	    }
	    else {
		celllist = tmpc -> next;
		celllist -> prev = NULL;
	    }
	    tmpc -> next = &unlinked; /* mark as unlinked */
	    tmpc -> prev = NULL;
	}
	tmpm -> cell = tmpc;
    }
}

printtree (cellName)
char *cellName;
{
    register CELL *tmpc;

    svalue = 1;

    if (cellName == NULL) { /* display all */
	for (tmpc = celllist; tmpc != NULL; tmpc = tmpc -> next) {
	    /* if (!tmpc -> imported || iflag) */ {
		display (tmpc, 0L, 1, 0);
		if (sflag) ++svalue;
	    }
	}
    }
    else {
	if (tmpc = findcell (cellName)) {
	    /* if (!tmpc -> imported || iflag) */ {
		display (tmpc, 0L, 1, 0);
	    }
	}
    }
}

display (cell, numused, level, func)
CELL *cell;
long  numused;
int   level;
int   func;
{
    register MC *tmpm;

    printf ("%*d - %-*s ",
	(level - 1) * 4 + 1, level,
	DM_MAXNAME, cell -> cellname);

    if (level == 1) {
	if (cell -> imported)
	    printf (" (imported)\n");
	else {
	    if (cell -> func & 01)
		printf (" (%ld)", cell -> numcellcall);
	    if (cell -> func & 04)
		printf (" (device model)");
	    if (cell -> func & 010)
		printf (" (macro)");
	    if (!cell -> func & 01) {
		if (cell -> func & 02)
		    printf (" (function)\n");
		else
		    printf (" (nomc)\n");
		return;
	    }
	    printf ("\n");
	}
	if (rflag) return;
    }
    else {
	printf ("%4ld ", numused);
	if (func) {
	    printf ("(function)\n");
	    return;
	}
	else {
	    if (cell -> imported)
		printf (" (imported)");
	    else
		printf ("(%ld)", cell -> numcellcall);
	}
	if (cell -> func & 04)
	    printf (" (device model)");
	if (cell -> func & 010)
	    printf (" (macro)");
	printf ("\n");
    }

    if (tflag || cell -> shown != svalue) {
    cell -> shown = svalue;
    for (tmpm = cell -> subcell; tmpm != NULL; tmpm = tmpm -> next) {
	if (tmpm -> cell) {
	    display (tmpm -> cell, tmpm -> num, level + 1,
			tmpm -> func);
	}
	else {
	    switch (view_nr) {
	    case 1: /* layout */
		printf ("%*d - %-*s%4ld (nocell)\n",
		    level * 4 + 1, level + 1,
		    DM_MAXNAME, tmpm -> cellname, tmpm -> num);
		break;
	    case 2: /* circuit */
		if (in_dev_list (tmpm -> cellname)) {
		    if (dflag) {
			printf ("%*d - %-*s%4ld (device)%s",
			    level * 4 + 1, level + 1,
			    DM_MAXNAME, tmpm -> cellname, tmpm -> num,
			    (tmpm -> func) ? " (function)\n" : "\n");
		    }
		}
		else {
		    printf ("%*d - %-*s%4ld (nocell)\n",
			level * 4 + 1, level + 1,
			DM_MAXNAME, tmpm -> cellname, tmpm -> num);
		}
		break;
	    case 3: /* floorplan */
		printf ("%*d - %-*s%4ld ",
		    level * 4 + 1, level + 1,
		    DM_MAXNAME, tmpm -> cellname, tmpm -> num);
		if (in_lay_cl (tmpm -> cellname))
		    printf ("(layout)\n");
		else
		    printf ("(nocell)\n");
		break;
	    }
	}
    }
    }
}

freelist ()
{
    register MC   *tmpm;
    register CELL *tmpc;

    while (findlist != NULL) {
	while (findlist -> subcell != NULL) {
	    tmpm = findlist -> subcell -> next;
	    free ((char *) findlist -> subcell);
	    findlist -> subcell = tmpm;
	}
	tmpc = findlist -> findnext;
	free ((char *) findlist);
	findlist = tmpc;
    }
    celllist = NULL;
}

lview (cellName, view, nr)
char *cellName, *view;
int   nr;
{
    register CELL *tmp;
    register char **celllst;
    register IMPCELL **impcelllst;

    freelist ();

    view_nr = nr;

    if (!oneview)
	printf ("\n%s:\n", view);

    celllst = (char **)
	dmGetMetaDesignData (CELLLIST, project, view);
    if (view_nr == 1) { /* layout */
	lay_cl = celllst;
    }

    impcelllst = (IMPCELL **)
	dmGetMetaDesignData (IMPORTEDCELLLIST, project, view);

    if (!hflag) {
	lscells (cellName, celllst, impcelllst);
	return;
    }

    for (; *celllst != NULL; ++celllst) {
	readcell (*celllst, NULL, view, project);
    }

    for (; *impcelllst != NULL; ++impcelllst) {
	readcell ((*impcelllst) -> alias,
		  (*impcelllst) -> cellname, view, NULL);
    }

    /* remove the non-roots from celllist */
    for (tmp = celllist; tmp != NULL; tmp = tmp -> findnext) {
	updatecall (tmp);
    }

    printtree (cellName);
}
