
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResBasic.c,v 1.3 2010/06/24 12:37:56 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"

int resSubDevFunc();

/*
 *--------------------------------------------------------------------------
 *
 * resNodeIsPort --
 *
 *	If the given position is inside any port declared on the tile,
 *	change the node name to the port name.  Remove the port
 *	declaration if it was used.
 *
 *--------------------------------------------------------------------------
 */

void
resNodeIsPort(node, x, y, tile)
    resNode *node;
    int	    x;
    int	    y;
    Tile    *tile;
{
    Rect 	*rect;
    Point 	p;
    resPort 	*pl, *lp;
    tileJunk	*junk = (tileJunk *)(tile->ti_client);

    p.p_x = x;
    p.p_y = y;

    for (pl = junk->portList; pl; pl = pl->rp_nextPort)
    {
	rect = &(pl->rp_bbox);
	if (GEO_ENCLOSE(&p, rect))
	{
	    node->rn_name = pl->rp_nodename;
	    if (junk->portList == pl)
		junk->portList = pl->rp_nextPort;
	    else
	    {
	        for (lp = junk->portList; lp && (lp->rp_nextPort != pl);
			lp = lp->rp_nextPort);
		lp->rp_nextPort = pl->rp_nextPort;
	    }
	    freeMagic(pl);
	    break;
	}
    }
}

/*
 *--------------------------------------------------------------------------
 *
 * resAllPortNodes --
 *
 *	Generate new nodes and breakpoints for every unused port declared
 *	on a tile.
 *
 *--------------------------------------------------------------------------
 */

void
resAllPortNodes(tile, list)
    Tile 	*tile;
    resNode	**list;
{
    int		x, y;
    resNode	*resptr;
    resPort 	*pl;
    tileJunk	*junk = (tileJunk *)(tile->ti_client);

    for (pl = junk->portList; pl; pl = pl->rp_nextPort)
    {
	x = pl->rp_loc.p_x;
	y = pl->rp_loc.p_y;
	resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
	InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
	resptr->rn_status = TRUE;
	resptr->rn_noderes = 0;
	resptr->rn_name = pl->rp_nodename;
	ResAddToQueue(resptr, list);
	NEWBREAK(resptr, tile, x, y, NULL);
	freeMagic(pl);
    }
}

/*
 *--------------------------------------------------------------------------
 *
 * ResEachTile--for each tile, make a list of all possible current sources/
 *   sinks including contacts, devices, and junctions.  Once this
 *   list is made, calculate the resistor nextwork for the tile.
 *
 *  Results: returns TRUE or FALSE depending on whether a node was 
 *           involved in a merge.
 *
 *  Side Effects: creates Nodes, devices, junctions, and breakpoints.
 *
 *
 *--------------------------------------------------------------------------
 */

bool
ResEachTile(tile, startpoint)
    Tile 	*tile;
    Point 		*startpoint;

{
    Tile 	*tp;
    resNode	*resptr;
    cElement	*ce;
    TileType	t1, t2;
    int		xj, yj, i;
    bool	merged;
    tElement	*tcell;
    tileJunk	*tstructs= (tileJunk *)(tile->ti_client);
    ExtDevice   *devptr;
      
    ResTileCount++;

    /* Process startpoint, if any. */

    if (IsSplit(tile))
    {
	t1 = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
    }
    else
	t1 = TiGetTypeExact(tile);

    if (startpoint != (Point *) NULL)
    {
	int x = startpoint->p_x;
	int y = startpoint->p_y;
	resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
	InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
	resptr->rn_status = TRUE;
	resptr->rn_noderes = 0;
	ResAddToQueue(resptr, &ResNodeQueue);
	NEWBREAK(resptr, tile, x, y, NULL);
	resCurrentNode = resptr;
	resNodeIsPort(resptr, x, y, tile);
    }

    if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)
    {
	/* 
	 * The device is put in the center of the tile. This is fine
	 * for single tile device, but not as good for multiple ones.
	 */

	if (tstructs->tj_status & RES_TILE_DEV)
 	{
	    if (tstructs->deviceList->rd_fet_gate == NULL)
	    {
		int x = (LEFT(tile) + RIGHT(tile)) >> 1;
		int y = (TOP(tile) + BOTTOM(tile)) >> 1;

		resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
		tstructs->deviceList->rd_fet_gate = resptr;
		tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
		tcell->te_thist = tstructs->deviceList;
		tcell->te_nextt = NULL;

		InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
		resptr->rn_te = tcell;
		ResAddToQueue(resptr, &ResNodeQueue);
		resNodeIsPort(resptr, x, y, tile);

		NEWBREAK(resptr, tile, resptr->rn_loc.p_x,
		     			resptr->rn_loc.p_y, NULL);
	    }
	}
    }
		
#ifdef ARIEL
    if (i = ExtCurStyle->exts_plugSignalNum[t1])
    {
	tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
	   
	tcell->te_thist= ResImageAddPlug(tile, i, resCurrentNode);
	tcell->te_nextt = resCurrentNode->rn_te;
	resCurrentNode->rn_te = tcell;
    }
    if (TTMaskHasType(&ResSubsTypeBitMask,t1) &&
          			(ResOptionsFlags & ResOpt_DoSubstrate))
    {
	int	pNum;
	Rect tileArea;
	TileTypeBitMask  *mask = &ExtCurStyle->exts_subsTransistorTypes[t1];

	TiToRect(tile,&tileArea);
	for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
        {
	    if (TTMaskIntersect(&DBPlaneTypes[pNum], mask))
	    {
	        (void)DBSrPaintArea((Tile *) NULL, 
		  	ResUse->cu_def->cd_planes[pNum], 
		        &tileArea, mask, resSubDevFunc, (ClientData) tile);
	    }
        }
    }
#endif

    /* Process all the contact points */
    ce = tstructs->contactList;
    while (ce != (cElement *) NULL)
    {
	ResContactPoint	*cp = ce->ce_thisc;
	cElement	*oldce;
	if (cp->cp_cnode[0] == (resNode *) NULL)
	{
	    ResDoContacts(cp, &ResNodeQueue, &ResResList);
	}
	oldce = ce;
	ce = ce->ce_nextc;
	freeMagic((char *)oldce);
    }
    tstructs->contactList = NULL;     

    /* 
     * Walk the four sides of the tile looking for adjoining connecting
     * materials.
     */
       
    /* left */
    for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
    {
	t2 = TiGetRightType(tp);
	devptr = ExtCurStyle->exts_device[t2];
	if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
        /* found device */
	{
	    xj = LEFT(tile);
	    yj = (TOP(tp) + BOTTOM(tp)) >> 1;
	    ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
	}
	if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
	/* tile is junction  */
	{
	    /*junction rn_loc */
	    xj = LEFT(tile);
	    yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
	    (void) ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
	}
    }

    /* right */
    for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
    {
      	t2 = TiGetLeftType(tp);
	devptr = ExtCurStyle->exts_device[t2];
	if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
        /* found device */
	{
	    xj = RIGHT(tile);
	    yj = (TOP(tp)+BOTTOM(tp))>>1;
	    ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
	}
	if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
	/* tile is junction  */
	{
	    /*junction rn_loc */
	    xj = RIGHT(tile);
	    yj = (MAX(BOTTOM(tile),BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
	    (void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
	}
    }

    /* top */
    for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp))
    {
      	t2 = TiGetBottomType(tp);
	devptr = ExtCurStyle->exts_device[t2];
	if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask),t2) &&
	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t1))
        /* found device */
	{
	    yj = TOP(tile);
	    xj = (LEFT(tp)+RIGHT(tp))>>1;
	    ResNewSDDevice(tile,tp,xj,yj,BOTTOMEDGE, &ResNodeQueue);
	}
	if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1],t2)
	/* tile is junction  */
	{
	    yj = TOP(tile);
	    xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
	    ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
	}
    }

    /* bottom */
    for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
    {
      	t2 = TiGetTopType(tp);
	devptr = ExtCurStyle->exts_device[t2];
	if(TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2) &&
	      TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), t1))
        /* found device */
	{
	    yj = BOTTOM(tile);
	    xj = (LEFT(tp) + RIGHT(tp)) >> 1;
	    ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
	}
	if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
	/* tile is junction  */
	{
	    yj = BOTTOM(tile);
	    xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
	    ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
	}
    }
    tstructs->tj_status |= RES_TILE_DONE;
      
    resAllPortNodes(tile, &ResNodeQueue);

    merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue,
			&ResNodeList);

    return(merged);
}

/*
 *-------------------------------------------------------------------------
 *
 * resSubDevFunc -- called when DBSrPaintArea finds a device within
 *	a substrate area.
 *
 * Results: always returns 0 to keep search going.
 *
 * Side Effects: allocates substrate node.
 *
 *-------------------------------------------------------------------------
 */

int
resSubDevFunc(tile,tp)
	Tile	*tile,*tp;
	

{
     tileJunk	*junk = (tileJunk *)(tile->ti_client);
     resNode	*resptr;
     tElement	*tcell;
     int	x,y;

     if (junk->deviceList->rd_fet_subs == NULL)
     {
          resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
	  junk->deviceList->rd_fet_subs = resptr;
	  junk->tj_status |= RES_TILE_DEV;
          tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
	  tcell->te_thist = junk->deviceList;
	  tcell->te_nextt = NULL;
	  x = (LEFT(tile)+RIGHT(tile))>>1;
	  y = (TOP(tile)+BOTTOM(tile))>>1;

	  InitializeNode(resptr,x,y,RES_NODE_JUNCTION);
	  resptr->rn_te = tcell;
	  ResAddToQueue(resptr,&ResNodeQueue);

	  NEWBREAK(resptr,tp,x,y,NULL);
    }
    return 0;
}
