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

Name/Version      : makebox/4.7

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

Author(s)         : S. de Graaf
Creation date     : 22-Apr-1986
Modified by       : S. de Graaf
Modification date : 01-Sep-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 "extern.h"

struct stat st_buf;
int  no_masks;
int  close_xx;
DM_CELL *ckey;
int  two_levels;

struct tmtx * tm_p_last;
struct tmtx * tm_s_last;
char * current_cell;

/*
** expand cell
*/
exp_cell (cell)
char *cell;
{
    FILE      *fp_exp;
    DM_STREAM *fp;
    char      *mask_name;
    register int i;
    int j, inf3_samples;
    int no_files;

#ifdef DEBUG
P_E "=> exp_cell(%s)\n", cell);
#endif

    ckey = dmCheckOut (project, cell, WORKING, DONTCARE, LAYOUT, ATTACH);

    current_cell = cell;

    fp = dmOpenStream (ckey, "info", "r");
    dmGetDesignData (fp, GEO_INFO);
    dmCloseStream (fp, COMPLETE);

    if (part_exp) {
	part_exp = 4;
	if (exp_reg[0] <= ginfo.bxl) {
	    exp_reg[0] = ginfo.bxl; --part_exp;
	}
	if (exp_reg[1] >= ginfo.bxr) {
	    exp_reg[1] = ginfo.bxr; --part_exp;
	}
	if (exp_reg[2] <= ginfo.byb) {
	    exp_reg[2] = ginfo.byb; --part_exp;
	}
	if (exp_reg[3] >= ginfo.byt) {
	    exp_reg[3] = ginfo.byt; --part_exp;
	}
#ifdef DEBUG
if (!part_exp)
    P_E "partial expansion false, cell bbox inside exp_reg\n");
#endif
	if (exp_reg[1] <= ginfo.bxl
	    || exp_reg[0] >= ginfo.bxr
	    || exp_reg[3] <= ginfo.byb
	    || exp_reg[2] >= ginfo.byt) {
P_E
"warning: cell '%s' not expanded, outside exp. region\n", cell);
	    return;
	}
    }
    else {
	exp_reg[0] = ginfo.bxl;
	exp_reg[1] = ginfo.bxr;
	exp_reg[2] = ginfo.byb;
	exp_reg[3] = ginfo.byt;
    }

    inf3_samples = samples;
    if (samples > 1) {
	exp_reg[0] *= samples;
	exp_reg[1] *= samples;
	exp_reg[2] *= samples;
	exp_reg[3] *= samples;
    }
    else
	samples = 1;

    no_files = no_masks = process -> nomasks;

    /* determine real number of open files (add term masks) */
    for (i = 0; i < no_masks; ++i) {
	if (process -> mask_type[i] == DM_INTCON_MASK)
	    process -> mask_no[i] = no_files++;
    }

    /* allocate file pointers */
    ALLOCARR (fp_bxx, no_files, DM_STREAM *);
    ALLOCARR (no_bxx, no_files, long);
    if (!dflag) {
	ALLOCARR (fp_nxx, no_masks, DM_STREAM *);
#ifdef _NFILE
	if (no_files + no_masks + 5 > _NFILE) ++close_xx;
#endif _NFILE
    }

    if (!nordatahack) {
	/* clear info3 */
	fp = dmOpenStream (ckey, "info3", "w");
	dmPutDesignData (fp, GEO_INFO3);
	dmCloseStream (fp, COMPLETE);

	/* open all expansion files */
	if (hier_mode && netterm)
	    fp_tid = dmOpenStream (ckey, "nettid", "w");
	else
	    fp_tid = dmOpenStream (ckey, "tid", "w");
	if (!noTidpos)
	    fp_tidpos = dmOpenStream (ckey, "tidpos", "w");
	if (!hier_mode)
	    fp_spec = dmOpenStream (ckey, "spec", "w");
	else
	    dmUnlink (ckey, "spec");
    }

    /* open cell "bxx" files, and open or remove "nxx" files */
    for (i = 0; i < no_masks; ++i) {
	mask_name = process -> mask_name[i];
	sprintf (buf, "%s_nxx", mask_name);
	if (!dflag) {
	    fp_nxx[i] = dmOpenStream (ckey, buf, "w");
#ifdef _NFILE
	    if (close_xx) dmCloseStream (fp_nxx[i], COMPLETE);
#endif _NFILE
	}
	else
	    dmUnlink (ckey, buf);
	sprintf (buf, "%s_bxx", mask_name);
	if (nordatahack)
	    fp_bxx[i] = dmOpenStream (ckey, buf, "a");
	else
	    fp_bxx[i] = dmOpenStream (ckey, buf, "w");
	no_bxx[i] = 0;
	if (process -> mask_type[i] == DM_INTCON_MASK) {
	    if (hier_mode && netterm)
		sprintf (buf, "n_%s_bxx", mask_name);
	    else
		sprintf (buf, "t_%s_bxx", mask_name);
	    j = process -> mask_no[i];
	    if (nordatahack)
	        fp_bxx[j] = dmOpenStream (ckey, buf, "a");
	    else
	        fp_bxx[j] = dmOpenStream (ckey, buf, "w");
	    no_bxx[j] = 0;
	}
    }

    /*
    ** initialize the mc-tree and cell-list
    */
    ALLOCPTR (celllist, clist);
    celllist -> ckey = ckey;
    celllist -> hier = 0;
    celllist -> mc_p = 0;
    celllist -> cl_next = NULL;

    if (exp_depth > 0) {
	trav_mctree (celllist, 0);
	gtid.term_offset = -1;
	strcpy (gtid.cell_name, cell);
	strcpy (gtid.inst_name, "$");
	gtid.m_nx = 0;
	gtid.m_ny = 0;
	if (!nordatahack)
	    dmPutDesignData (fp_tid, GEO_TID);
    }

    ALLOCARR (px, pt_size, double);
    ALLOCARR (py, pt_size, double);

    expand ();

    if (!nordatahack) {
	/*
	** close the cell "tid" and "bxx" files
	*/
	dmCloseStream (fp_tid, COMPLETE);
	if (!noTidpos)
	    dmCloseStream (fp_tidpos, COMPLETE);
	if (!hier_mode)
	    dmCloseStream (fp_spec, COMPLETE);
    }
    for (i = 0; i < no_files; ++i) {
	dmCloseStream (fp_bxx[i], COMPLETE);
    }
    if (!dflag && !close_xx)
    for (i = 0; i < no_masks; ++i) {
	dmCloseStream (fp_nxx[i], COMPLETE);
    }

    signal (SIGINT, SIG_IGN);
    if (!nordatahack) {
	/*
	** write no_of_boxes for each mask
	** to the cell "info2" file
	*/
	fp = dmOpenStream (ckey, "info2", "w");
	ginfo2.nr_groups = 0;
	for (i = 0; i < no_files; ++i) {
	    ginfo2.nr_boxes = no_bxx[i];
	    dmPutDesignData (fp, GEO_INFO2);
	}
	dmCloseStream (fp, COMPLETE);

	fp = dmOpenStream (ckey, "info3", "w");
	ginfo3.bxl = exp_reg[0];
	ginfo3.bxr = exp_reg[1];
	ginfo3.byb = exp_reg[2];
	ginfo3.byt = exp_reg[3];
	ginfo3.nr_samples = inf3_samples;
	dmPutDesignData (fp, GEO_INFO3);
	dmCloseStream (fp, COMPLETE);
    }

    if (!(fp_exp = fopen (fn_exp, "w"))) errexit (4, fn_exp);
    fprintf (fp_exp, "%s\n", cell);
    fclose (fp_exp);

    dmCkinAll (COMPLETE);

    current_cell = NULL;

#ifdef DEBUG
P_E "<= exp_cell()\n");
#endif
}

expand ()
{
    register struct clist *clp;
    register int i;
    struct tmtx *tm;
    DM_STREAM *fp;
    struct clist *prev;

    /* place the top-level cell in the front of celllist */

    prev = NULL;
    for (clp = celllist; clp; clp = clp -> cl_next) {
	if (!clp -> mc_p) {
	    break;
	}
	prev = clp;
    }
    if (prev) 
	prev -> cl_next = clp -> cl_next;
    if (clp != celllist) {
	clp -> cl_next = celllist;
	celllist = clp;
    }

    for (clp = celllist; clp; clp = clp -> cl_next) {
#ifdef DEBUG
pr_clist (clp);
#endif
	free_tm ();
	cellkey = clp -> ckey;
	cellname = cellkey -> cell;

	s_mode = 0;
	if (Lflag && cellkey -> dmproject != project) ++s_mode;

	if (part_exp) {
	    fp = dmOpenStream (cellkey, "info", "r");
	    dmGetDesignData (fp, GEO_INFO);
	    ginfo.bxl *= samples;
	    ginfo.bxr *= samples;
	    ginfo.byb *= samples;
	    ginfo.byt *= samples;
	    dmCloseStream (fp, COMPLETE);
	}

	level = 0;
	ALLOCPTR (tm, tmtx);
	tm -> mtx[0] = 1; tm -> mtx[1] = 0; tm -> mtx[2] = 0;
	tm -> mtx[3] = 0; tm -> mtx[4] = 1; tm -> mtx[5] = 0;
	tm -> tm_next = 0;

        two_levels = 0;
        tm_p_last = 0;
        tm_s_last = 0;
	calc_tm (clp -> mc_p, tm);

	if (clp -> hier != 1) {
	    if (tm_p || tm_s) read_term (clp);
	}

	if (clp -> hier != 0) {
	    read_hier_term (clp);
	}

	if (tm_p && clp -> hier != 1) {
	    if (!nordatahack)
	        read_box ();

	    if (dmStat (cellkey, "nor", &st_buf)) dmError (cellkey -> cell);

	    if (st_buf.st_size > 0)
	    if (!dflag) {
#ifdef _NFILE
		/* close "bxx" and reopen "nxx" files */
		if (close_xx)
		for (i = 0; i < no_masks; ++i) {
		    dmCloseStream (fp_bxx[i], COMPLETE);
		    sprintf (buf, "%s_nxx", process -> mask_name[i]);
		    fp_nxx[i] = dmOpenStream (ckey, buf, "a");
		}
#endif _NFILE

		read_nor2 ();

#ifdef _NFILE
		/* close "nxx" and reopen "bxx" files */
		if (close_xx)
		for (i = 0; i < no_masks; ++i) {
		    dmCloseStream (fp_nxx[i], COMPLETE);
		    sprintf (buf, "%s_bxx", process -> mask_name[i]);
		    fp_bxx[i] = dmOpenStream (ckey, buf, "a");
		}
#endif _NFILE
	    }
	    else
		read_nor ();
	}
    }
}

free_tm ()
{
    register struct tmtx *t1, *t2;

    t2 = tm_p;
    while (t1 = t2) {
	t2 = t1 -> tm_next;
	FREE (t1);
    }
    tm_p = 0;

    t2 = tm_s;
    while (t1 = t2) {
	t2 = t1 -> tm_next;
	FREE (t1);
    }
    tm_s = 0;
}

calc_tm (pmc, ptm)
struct mc_elmt *pmc;
struct tmtx *ptm;
{
    register int i, j;
    register long *a, *b;
    register struct tmtx *tm;
    long tdx, tdy;

    if (!pmc) {
	if (part_exp && outwdw (ptm -> mtx)) {
	    FREE (ptm);
	    return;
	}
	if (s_mode || level == exp_depth) {
	    ptm -> name = cellname;
	    ptm -> tm_next = 0;
	    if (tm_s_last) 
		tm_s_last -> tm_next = ptm;
	    else
		tm_s = ptm;
	    tm_s_last = ptm;
	}
	else {
	    ptm -> tm_next = 0;
	    if (tm_p_last) 
		tm_p_last -> tm_next = ptm;
	    else
		tm_p = ptm;
	    tm_p_last = ptm;
	}
	return;
    }

    if (++level > exp_depth) goto ret;

    if (level > 1) two_levels = 1;

    a = ptm -> mtx;
    for (; pmc; pmc = pmc -> mc_next) {
	if (level == 1) {
	    cellname = pmc -> name;
	}
	b = pmc -> mtx;
	tdx = b[2];
	for (i = 0;;) {
	    tdy = b[5];
	    for (j = 0;;) {
		ALLOCPTR (tm, tmtx);
		tm -> mtx[0] = b[0] * a[0] + b[1] * a[3];
		tm -> mtx[1] = b[0] * a[1] + b[1] * a[4];
		tm -> mtx[2] = b[0] * a[2] + b[1] * a[5] + tdx;
		tm -> mtx[3] = b[3] * a[0] + b[4] * a[3];
		tm -> mtx[4] = b[3] * a[1] + b[4] * a[4];
		tm -> mtx[5] = b[3] * a[2] + b[4] * a[5] + tdy;

		calc_tm (pmc -> parent -> mc_p, tm);

		if (++j > pmc -> ny) break;
		tdy += pmc -> dy;
	    }
	    if (++i > pmc -> nx) break;
	    tdx += pmc -> dx;
	}
    }

ret:
    --level;
    FREE (ptm);
}

outwdw (m)
register long *m;
{
    long xl, xr, yb, yt, tmp;

    xl = m[0] * ginfo.bxl + m[1] * ginfo.byb + m[2];
    yb = m[3] * ginfo.bxl + m[4] * ginfo.byb + m[5];
    xr = m[0] * ginfo.bxr + m[1] * ginfo.byt + m[2];
    yt = m[3] * ginfo.bxr + m[4] * ginfo.byt + m[5];

    if (xl > xr) { tmp = xl; xl = xr; xr = tmp; }
    if (yb > yt) { tmp = yb; yb = yt; yt = tmp; }

    if (xr <= exp_reg[0] || xl >= exp_reg[1]
    ||  yt <= exp_reg[2] || yb >= exp_reg[3]) {
    /*
    ** the box-coordinates have no overlap
    ** with the expansion region
    */
	return (1);
    }
    return (0);
}
