static char *SccsId = "@(#)getTech.c 4.9 (TU-Delft) 04/20/93";
/**********************************************************

Name/Version      : space/4.9

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

Author(s)         : A.J. van Genderen
		  : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


        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 <dmincl.h>
#include "include/config.h"
#include "include/type.h"
#include "aux/aux.h"
#include "extract/define.h"
#include "extract/extern.h"

#define MajorProtNr  1

#define DEFAULT_TECH_FILE "space.def.t"

/* Next defines must be < 0.
 */
#define ELEM_END   -1
#define ELEM_IDEM  -2
#define ELEM_ERROR -3

#define optCap3D 0

int nrOfMasks;
int nrOfConductors;
int nrOfExtConductors;
int nrOfSpiderLevels;

/* These variables are, for example, used for displaying
 * purposes, to adjust the transformation dependend
 * on the z-dimension. (XSPACE)
 * They are also used to determine the z-extend for rounding purposes. (CAP3D)
 */
double Z_top, Z_bot;

maskinfo_t * masktable;

layerCond_t * layCTab;
elemDef_t *** keyTab;		/* array containing pointers into elemTab */
static
elemDef_t  ** elemTab;		/* array containing pointers to elemDef_t's */
static
int keyTabSize = 0;
elemDef_t   * elemDefTab;	/* array of elemDef_t's */
int elemDefTabSize;

char **resSortTab;
int resSortTabSize;
char **capSortTab;
int capSortTabSize;

mask_t sBitmask;
mask_t eBitmask;
mask_t oeBitmask;

mask_t filterBitmask;
mask_t torBitmask;

mask_t coreBitmask;

double * conVal;
double * maxResVal;
mask_t * conductorColor;	/* maps conductor number to color */
int * conductorMask;		/* maps conductor number to mask index */
bool_t DiffusionConductor [MAXCONDUCTORS+1];

static int minorPrNr;

/* local operations */
private void    readTechFile ();
private FILE * openTechFile ();
private void setCoreBitMask ();

void getTechnology (dmproject, techDef, techFile)
DM_PROJECT * dmproject;
char * techDef;
char * techFile;
{
    FILE * fp_tech = NULL;

    if ((fp_tech = openTechFile (dmproject, techDef, techFile)) == NULL) {
	say ("can't open technology file");
	die ();
    }

    readTechFile (fp_tech);

    setCoreBitMask ();

    CLOSE (fp_tech);
}

private void readTechFile (fp_tech)
FILE * fp_tech;
{
    int t;
    char c;
    int i;
    int cx;
    int cnt;
    char fmt[12];
    char namebuf[80];
    int elemTabSize = 0;
    int elemTabIndex = 0;
    int keyTabIndex = 0;

    char * strsave ();

    Z_top = -INF;
    Z_bot =  INF;

    if ((c = getc (fp_tech)) == '#') {
	fscanf (fp_tech, "%d %d", &t, &minorPrNr);
	if (t != MajorProtNr) {
	    say ("incompatible version of technology file");
	    die ();
	}
    }
    else {
	ungetc (c, fp_tech);
	minorPrNr = 0;
    }

    fscanf (fp_tech, "%d", &nrOfMasks);

    /* The +1 below is necessary for addition of the
     * mesh_gln pseudo mask, which is used for the mesh refinement
     * for resistance extraction using the two-pass mechanism
     * or for hierarchical 3D capacitance extraction.
     */
    masktable = NEW (maskinfo_t, nrOfMasks + 1);
    for (i = 0; i < nrOfMasks; i++) {
	fscanf (fp_tech, "%s %d %d %d",
		namebuf,
		&masktable[i].terminal,
		&masktable[i].color,
		&masktable[i].conductor);
	masktable[i].name = strsave (namebuf);
    }

    fscanf (fp_tech, "%d", &nrOfConductors);

    nrOfExtConductors = nrOfConductors;


    /* NvdM
     * The array conductorColor maps conductor numbers to colors.
     * This is used to find the color of a spider when
     * animating 3d cap extraction.
     * An alternative solution would be to make
     * conductor numbers the same as mask numbers,
     * this would simplify some other things to,
     * e.g. separate mask and conductor field of
     * elemdefs would not be neccessary then.
     * The DiffusionConductor array will contain TRUE
     * for drain/source conductors.
     */

    /* AvG
     * The array conductorMask maps conductor numbers to mask indices.
     * This is used to find the mask of a conductor when generating
     * a coordinate pair + mask info for a net.
     */

    filterBitmask = 0;

    conductorColor = NEW (mask_t, nrOfConductors);
    conductorMask = NEW (int, nrOfConductors);

    for (i = 0; i < nrOfMasks; i++) {
	if (masktable[i].conductor >= 0) {
	    DiffusionConductor[masktable[i].conductor] = FALSE;

	    conductorColor[masktable[i].conductor] = masktable[i].color;
	    conductorMask[masktable[i].conductor] = i;

	    filterBitmask |= masktable[i].color;
	}
    }

    fscanf (fp_tech, "%d", &sBitmask);
    fscanf (fp_tech, "%d", &eBitmask);
    fscanf (fp_tech, "%d", &oeBitmask);

    if (minorPrNr >= 1) {
	fscanf (fp_tech, "%d", &resSortTabSize);
	resSortTab = NEW (char *, resSortTabSize);
	for (i = 0; i < resSortTabSize; i++) {
	    fscanf (fp_tech, "%s", namebuf);
	    resSortTab[i] = NEW (char, strlen (namebuf) + 1);
	    strcpy (resSortTab[i], namebuf);
	}
	fscanf (fp_tech, "%d", &capSortTabSize);
	capSortTab = NEW (char *, capSortTabSize);
	for (i = 0; i < capSortTabSize; i++) {
	    fscanf (fp_tech, "%s", namebuf);
	    capSortTab[i] = NEW (char, strlen (namebuf) + 1);
	    strcpy (capSortTab[i], namebuf);
	}
    }
    else {
	resSortTab = NEW (char *, 1);
	strcpy (namebuf, "res");
	resSortTab[0] = NEW (char, strlen (namebuf) + 1);
	strcpy (resSortTab[0], namebuf);
	capSortTab = NEW (char *, 1);
	strcpy (namebuf, "cap");
	capSortTab[0] = NEW (char, strlen (namebuf) + 1);
	strcpy (capSortTab[0], namebuf);
    }

    fscanf (fp_tech, "%d", &elemDefTabSize);
    elemDefTab = NEW (elemDef_t, elemDefTabSize);

    /* Initialize torBitmask with all one's
     * such that potentially every tile can
     * have a transistor.
     * When reading in the element definition for a
     * transistor, turn bits in torBitmask off in such a
     * way that only bits corresponding to masks that are
     * present in each transistor remain set.
     * Then, a tile can only have a transistor if 
     * tile -> color & torBitmask == torBitmask.
     * See also CanHaveTor in define.h.
     */
    torBitmask = ~0;

    for (i = 0; i < elemDefTabSize; i++) {
	fscanf (fp_tech, "%s", namebuf);
	sprintf (fmt, "%%%ds", MAX_ELEM_NAME);
	sscanf (namebuf, fmt, elemDefTab[i].name);
	fscanf (fp_tech, "%d %d %d %d",
		&elemDefTab[i].id,
		&elemDefTab[i].cond,
		&elemDefTab[i].cond_cnt,
		&elemDefTab[i].type);

	switch (elemDefTab[i].type) {
	    case CONTELEM:
		if (minorPrNr < 1)
		    elemDefTab[i].s.cont.sortNr = 0;
		else
		    fscanf (fp_tech, "%d", &elemDefTab[i].s.cont.sortNr);
		fscanf (fp_tech, "%d %d %le",
			&elemDefTab[i].s.cont.mask1,
			&elemDefTab[i].s.cont.mask2,
			&elemDefTab[i].s.cont.val);
		elemDefTab[i].s.cont.con1 = 
		    masktable [elemDefTab[i].s.cont.mask1].conductor;
		elemDefTab[i].s.cont.con2 = 
		    masktable [elemDefTab[i].s.cont.mask2].conductor;
		break;
	    case TORELEM:
		fscanf (fp_tech, "%d %d",
			&elemDefTab[i].s.tor.gMask,
			&elemDefTab[i].s.tor.dsMask);
		elemDefTab[i].s.tor.gCon = 
		    masktable [elemDefTab[i].s.tor.gMask].conductor;
		elemDefTab[i].s.tor.dsCon = 
		    masktable [elemDefTab[i].s.tor.dsMask].conductor;

		DiffusionConductor [elemDefTab[i].s.tor.dsCon] = TRUE;/*!!!3D*/

                if (optAccWL)
		    elemDefTab[i].s.tor.cx = nrOfExtConductors++;

		torBitmask &= (1 << elemDefTab[i].s.tor.gMask) 
			    | (1 << elemDefTab[i].s.tor.dsMask);
		break;
	    case SURFCAPELEM:
	    case EDGECAPELEM:
	    case LATCAPELEM:
		if (minorPrNr < 1)
		    elemDefTab[i].s.cap.sortNr = 0;
		else
		    fscanf (fp_tech, "%d", &elemDefTab[i].s.cap.sortNr);
		fscanf (fp_tech, "%d %d %d %d %d %d %d %d %le",
			&elemDefTab[i].s.cap.pMask,
			&elemDefTab[i].s.cap.pOccurrence,
			&elemDefTab[i].s.cap.nMask,
			&elemDefTab[i].s.cap.nOccurrence,
			&elemDefTab[i].s.cap.sBitPresent,
			&elemDefTab[i].s.cap.sBitAbsent,
			&elemDefTab[i].s.cap.oeBitPresent,
			&elemDefTab[i].s.cap.oeBitAbsent,
			&elemDefTab[i].s.cap.val);
		elemDefTab[i].s.cap.pCon = 
		    masktable [elemDefTab[i].s.cap.pMask].conductor;
		if (elemDefTab[i].s.cap.nMask >= 0)
		    elemDefTab[i].s.cap.nCon = 
			masktable [elemDefTab[i].s.cap.nMask].conductor;
		else
		    elemDefTab[i].s.cap.nCon = -1; 
		break;
	    case RESELEM:
		if (minorPrNr < 1)
		    elemDefTab[i].s.res.sortNr = 0;
		else
		    fscanf (fp_tech, "%d", &elemDefTab[i].s.res.sortNr);
		fscanf (fp_tech, "%d %le",
			&elemDefTab[i].s.res.mask,
			&elemDefTab[i].s.res.val);
		elemDefTab[i].s.res.con = 
		    masktable [elemDefTab[i].s.res.mask].conductor;
		break;
	    case VDIMELEM:
		fscanf (fp_tech, "%d %le %le",
			&elemDefTab[i].s.vdim.mask,
			&elemDefTab[i].s.vdim.height,
			&elemDefTab[i].s.vdim.thickness);
		elemDefTab[i].s.vdim.con = 
		    masktable [elemDefTab[i].s.vdim.mask].conductor;
		Z_top = Max (Z_top,   elemDefTab[i].s.vdim.height
                                    + elemDefTab[i].s.vdim.thickness);
		Z_bot = Min (Z_bot, elemDefTab[i].s.vdim.height);
		break;
	    case ESHAPEELEM:
	    case CSHAPEELEM:
		fscanf (fp_tech, "%d %le %le %le %le",
			&elemDefTab[i].s.shape.mask,
			&elemDefTab[i].s.shape.xb1,
			&elemDefTab[i].s.shape.xt1,
			&elemDefTab[i].s.shape.xb2,
			&elemDefTab[i].s.shape.xt2);
		elemDefTab[i].s.shape.con = 
		    masktable [elemDefTab[i].s.shape.mask].conductor;
		break;
	    default:
		ASSERT (0);
		break;
	}
    }

    conVal = NEW (double, nrOfExtConductors);

    cnt = getnum (fp_tech);
    if (cnt) layCTab = NEW (layerCond_t, cnt);
    else layCTab = NULL;
    for (i = 0; i < cnt; i++) {
	layCTab[i].mask = getnum (fp_tech);
	layCTab[i].occurrence = getnum (fp_tech);
	layCTab[i].present = getnum (fp_tech);
    }
   
    keyTabSize  = getnum (fp_tech);
    keyTab = NEW (elemDef_t **, keyTabSize);

    elemTabSize = getnum (fp_tech);
    elemTab = NEW (elemDef_t *, elemTabSize);

    elemTabIndex = 0;
    for (keyTabIndex = 0; keyTabIndex < keyTabSize; keyTabIndex++) {
	keyTab[keyTabIndex] = elemTab + elemTabIndex;
	while ((i = getElemNumber (fp_tech)) >= 0) {
	    switch (elemDefTab[i].type) {
		case LATCAPELEM:
		    if (optCap3D || !optLatCap) continue;
		    break;

		case SURFCAPELEM:
		case EDGECAPELEM:
		    if (!optCap && !optCap3D) continue;
		    if (optCap3D && (!diffusionGndCap (elemDefTab+i)))
			continue;
		    break;
	    }

	    elemTab[elemTabIndex++] = elemDefTab + i;
	}
	if (i == ELEM_IDEM) {  /* the elements for this key
				  were already seen for another key.
				  Copy the value in keyTab */

	    i = getElemNumber (fp_tech);
	    ASSERT (i >= 0 && i < keyTabIndex);
	    keyTab[keyTabIndex] = keyTab[i];

	    i = getElemNumber (fp_tech);  /* to read new line */
	    ASSERT (i == ELEM_END);
	}
	else {
	    elemTab[elemTabIndex++] = NULL;
	}
    }

    /* If the elemTab array is empty for more than 10k,
     * realloc to reclaim the empty space.
     * It can be empty because of elemDefs left out because
     * of option settings (see the loop above),
     * or because of a bug in tecc (date: 930329).
     */
    if ((elemTabSize - elemTabIndex) * sizeof (elemDef_t *) > 10 * 1024) {
	int offset;
	elemDef_t ** n;
	Debug (fprintf (stderr, "elemTab empty: %d\n",
	    (elemTabSize - elemTabIndex) * sizeof (elemDef_t *)));
	elemTabSize = elemTabIndex;
	n = RESIZE (elemTab, elemDef_t *, elemTabSize);
	/* if the address changed, correct the pointers towards it. */
	if (n != elemTab) {
	    offset = n - elemTab;
	    Debug (fprintf (stderr, "offset: %d\n", offset));
	    elemTab = n;
	    for (keyTabIndex = 0; keyTabIndex < keyTabSize; keyTabIndex++)
		keyTab[keyTabIndex] += offset;
	}
    }

    /* Find maximum values for resistances of interconnection
     * masks. The result is used for the estimation of the
     * resistances of interconnect polygons.
     */

    maxResVal = NEW (double, nrOfConductors);
    for (i = 0; i < nrOfConductors; i++) {
	maxResVal[i] = 0.0;
    }
    for (i = 0; i < elemDefTabSize; i++) {
	if (elemDefTab[i].type == RESELEM) {
	    cx = elemDefTab[i].s.res.con; 
	    if (elemDefTab[i].s.res.val > maxResVal[cx])
	        maxResVal[cx] = elemDefTab[i].s.res.val;
	}
    }
}

int diffusionGndCap (elem)
elemDef_t * elem;
{
    int n;

    if (elem -> s.cap.nCon >= 0 && elem -> s.cap.pCon >= 0)
	return (0); 		/* not a ground cap */

    if ((n = elem -> s.cap.nCon) >= 0 && DiffusionConductor[n]) return (1);
    if ((n = elem -> s.cap.pCon) >= 0 && DiffusionConductor[n]) return (1);

    return (0);			/* not a diffusion ground cap */
}

char * conNr2Name (n)
int n;
{
    int i;
    for (i = 0; i < nrOfMasks; i++)
	if (masktable [i].conductor == n)
	    return (masktable[i].name);
    return (NULL);
}

int conName2Nr (name)
char *name;
{
    int i;
    for (i = 0; i < nrOfMasks; i++) {
        if (strcmp (masktable[i].name, name) == 0)
            return (masktable[i].conductor);
    }

    return (-1);
}


private FILE * openTechFile (dmproject, techDef, techFile)
DM_PROJECT * dmproject;
char * techDef;
char * techFile;
{
    FILE * cfopen ();

    if (techFile == NULL) {
	if (techDef == NULL) {
	    techFile = dmGetMetaDesignData (PROCPATH, dmproject,
					DEFAULT_TECH_FILE);
	}
	else {
	    techFile = dmGetMetaDesignData (PROCPATH, dmproject,
			    mprintf ("space.%s.t", techDef));
	    if (access (techFile, 0) != 0) {
		say ("space.%s.t: no such element definition in %s",
		    techDef, dmGetMetaDesignData (PROCPATH, dmproject, ""));
		die ();
	    }
	}
    }

    if (techFile) {
	verbose ("technology file: %s\n", techFile);
	return (cfopen (techFile, "r"));
    }

    return (NULL);
}

#include <ctype.h>
#define BASE   10

int getnum (fp)
register FILE * fp;
{
    int     negative = 0;
    register int number;
    register int c = getc (fp);

    while (c != EOF && isspace (c))
	c = getc (fp);

    if (c == '-') negative++, c = getc (fp);

    if (isdigit (c)) {
	number = c - '0';
	for (c = getc (fp); isdigit (c); c = getc (fp))
	    number = BASE * number + c - '0';

	if (negative)  return (-number); /* no need to ungetc */
	else           return (number);

    }
    say ("error in reading technology file");
    die ();
    return (-100);
}

int getElemNumber (fp)
register FILE * fp;
{
    register int number;
    register int c = getc (fp);

    while (c == ' ' || c == '\t')
	c = getc (fp);
    
    if (c == '\n') return (ELEM_END);
    if (c == '=')  return (ELEM_IDEM);

    if (isdigit (c)) {
	number = c - '0';
	for (c = getc (fp); isdigit (c); c = getc (fp))
	    number = BASE * number + c - '0';
	if (c == '\n')
	    ungetc (c, fp);
	return (number);
    }

    say ("error in reading technology file");
    die ();
    return (ELEM_ERROR);
}

private void setCoreBitMask ()
{
    int i;
    char * coreMaskName = paramLookupS ("core_mask", "core");
    coreBitmask = 0;
    for (i = 0; i < nrOfMasks; i++) {
	if (strsame (masktable[i].name, coreMaskName)) {
	    coreBitmask |= masktable[i].color;
	}
    }
}


#ifdef DRIVER

bool_t optCap = TRUE;
bool_t optCap3D = FALSE;

verbose () {}

int main (argc, argv)
int argc;
char * argv[];
{
    int i;
    elemDef_t ** el;
    FILE * fp = cfopen (argv[1], "r");

    readTechFile (fp);

    for (i = 0; i < 10; i++) {
	for (el = keyTab[i]; *el; el++) {
	    fprintf (stderr, "%s ", (*el) -> name);
	}
	fprintf (stderr, "\n");
    }
    fprintf (stderr, "...\n");
    for (i = keyTabSize - 10; i < keyTabSize; i++) {
	for (el = keyTab[i]; *el; el++) {
	    fprintf (stderr, "%s ", (*el) -> name);
	}
	fprintf (stderr, "\n");
    }

    return (0);
}
#endif /* DRIVER */
