#ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResMain.c,v 1.4 2010/06/24 12:37:56 tim Exp $"; #endif /* not lint */ #include #include #include #include #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" CellUse *ResUse=NULL; /* Our use and def */ CellDef *ResDef=NULL; TileTypeBitMask ResConnectWithSD[NT]; /* A mask that goes from */ /* SD's to devices. */ TileTypeBitMask ResCopyMask[NT]; /* Indicates which tiles */ /* are to be copied. */ resResistor *ResResList=NULL; /* Resistor list */ resNode *ResNodeList=NULL; /* Processed Nodes */ resDevice *ResDevList=NULL; /* Devices */ ResContactPoint *ResContactList=NULL; /* Contacts */ resNode *ResNodeQueue=NULL; /* Pending nodes */ resNode *ResOriginNode=NULL; /* node where R=0 */ resNode *resCurrentNode; int ResTileCount=0; /* Number of tiles rn_status */ extern Region *ResFirst(); extern Tile *FindStartTile(); extern int ResEachTile(); extern int ResLaplaceTile(); extern ResSimNode *ResInitializeNode(); extern HashTable ResNodeTable; /* *-------------------------------------------------------------------------- * * ResInitializeConn-- * * Sets up mask by Source/Drain type of devices. This is * exts_deviceSDtypes turned inside out. * * Results: none * * Side Effects: Sets up ResConnectWithSD. * *------------------------------------------------------------------------- */ void ResInitializeConn() { TileType dev, diff; char *dev_name; ExtDevice *devptr; for (dev = TT_TECHDEPBASE; dev < TT_MAXTYPES; dev++) { devptr = ExtCurStyle->exts_device[dev]; if ((devptr != NULL) && ((dev_name = devptr->exts_deviceName) != NULL) && (strcmp(dev_name, "None"))) { for (diff = TT_TECHDEPBASE; diff < TT_MAXTYPES; diff++) { if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]), diff) TTMaskSetType(&ResConnectWithSD[diff],dev); if TTMaskHasType(&(devptr->exts_deviceSubstrateTypes),diff) TTMaskSetType(&ResConnectWithSD[diff],dev); } } TTMaskSetMask(&ResConnectWithSD[dev],&DBConnectTbl[dev]); } } /* * ---------------------------------------------------------------------------- * * ResGetReCell -- * * This procedure makes sure that ResUse,ResDef * have been properly initialized to refer to a cell definition * named "__RESIS__". * * Results: * None. * * Side effects: * A new cell use and/or def are created if necessary. * * -------------------------------------------------------------------------- */ void ResGetReCell() { if (ResUse != NULL) return; ResDef = DBCellLookDef("__RESIS__"); if (ResDef == NULL) { ResDef = DBCellNewDef("__RESIS__"); ASSERT (ResDef != (CellDef *) NULL, "ResGetReCell"); DBCellSetAvail(ResDef); ResDef->cd_flags |= CDINTERNAL; } ResUse = DBCellNewUse(ResDef, (char *) NULL); DBSetTrans(ResUse, &GeoIdentityTransform); ResUse->cu_expandMask = CU_DESCEND_SPECIAL; } /* *-------------------------------------------------------------------------- * * ResDissolveContacts-- * * results: none * * Side Effects: All contacts in the design are broken into their * constituent * layers. There should be no contacts in ResDef after this procedure * runs. * * *------------------------------------------------------------------------ */ void ResDissolveContacts(contacts) ResContactPoint *contacts; { TileType t, oldtype; Tile *tp; TileTypeBitMask residues; for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact) { oldtype=contacts->cp_type; #ifdef PARANOID if (oldtype == TT_SPACE) { TxError("Error in Contact Dissolving for %s \n",ResCurrentNode); } #endif DBFullResidueMask(oldtype, &residues); DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype); for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) { if (TTMaskHasType(&residues, t)) { if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, t)) continue; DBPaint(ResUse->cu_def, &(contacts->cp_rect), t); } } tp = ResDef->cd_planes[DBPlane(contacts->cp_type)]->pl_hint; GOTOPOINT(tp,&(contacts->cp_rect.r_ll)); #ifdef PARANOID if (TiGetTypeExact(tp) == contacts->cp_type) { TxError("Error in Contact Preprocess Routines\n"); } #endif } } /* *--------------------------------------------------------------------------- * * ResMakePortBreakpoints -- * * Search for nodes which are ports, and force them to be breakpoints * in the "tileJunk" field of their respective tiles in ResUse. This * ensures that connected nodes that stretch between two ports will * not be assumed to be "hanging" nodes. * * Do the same thing for labels. * *---------------------------------------------------------------------------- */ void ResMakePortBreakpoints(def) CellDef *def; { Plane *plane; Rect *rect; TileTypeBitMask mask; HashSearch hs; HashEntry *entry; ResSimNode *node; int ResAddBreakpointFunc(); /* Forward Declaration */ HashStartSearch(&hs); while((entry = HashNext(&ResNodeTable,&hs)) != NULL) { node=(ResSimNode *) HashGetValue(entry); if (node->status & PORTNODE) { plane = def->cd_planes[DBPlane(node->rs_ttype)]; rect = &(node->rs_bbox); TTMaskSetOnlyType(&mask, node->rs_ttype); (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, ResAddBreakpointFunc, (ClientData)node); } } } /* *--------------------------------------------------------------------------- * * ResMakeLabelBreakpoints -- * * Search for labels that are part of a node, and force them to be * breakpoints in the "tileJunk" field of their respective tiles in * ResUse. This ensures (among other things) that pins of a top level * cell will be retained and become the endpoint of a net. * *---------------------------------------------------------------------------- */ void ResMakeLabelBreakpoints(def) CellDef *def; { Plane *plane; Rect *rect; TileTypeBitMask mask; HashEntry *entry; ResSimNode *node; Label *slab; int ResAddBreakpointFunc(); /* Forward Declaration */ for (slab = def->cd_labels; slab != NULL; slab = slab->lab_next) { entry = HashFind(&ResNodeTable, slab->lab_text); node = ResInitializeNode(entry); node->drivepoint = slab->lab_rect.r_ll; node->rs_bbox = slab->lab_rect; node->location = slab->lab_rect.r_ll; node->rs_ttype = slab->lab_type; node->type = slab->lab_type; plane = def->cd_planes[DBPlane(slab->lab_type)]; rect = &(node->rs_bbox); TTMaskSetOnlyType(&mask, slab->lab_type); (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, ResAddBreakpointFunc, (ClientData)node); } } /* *---------------------------------------------------------------------------- * * ResAddBreakpointFunc -- * * Add a breakpoint to the "tileJunk" structure of the tile * *---------------------------------------------------------------------------- */ int ResAddBreakpointFunc(tile, node) Tile *tile; ResSimNode *node; { tileJunk *junk; if (tile->ti_client == (ClientData) CLIENTDEFAULT) return 0; NEWPORT(node, tile); return 0; } /* *--------------------------------------------------------------------------- * * ResFindNewContactTiles -- * * * Results: none * * Side Effects: dissolving contacts eliminated the tiles that * contacts->nextcontact pointed to. This procedure finds the tile now under * center and sets that tile's ti_client field to point to the contact. The * old value of clientdata is set to nextTilecontact. * *---------------------------------------------------------------------------- */ void ResFindNewContactTiles(contacts) ResContactPoint *contacts; { int pNum; Tile *tile; TileTypeBitMask mask; for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact) { DBFullResidueMask(contacts->cp_type, &mask); for (pNum=PL_TECHDEPBASE; pNumcd_planes[pNum]->pl_hint; GOTOPOINT(tile, &(contacts->cp_center)); #ifdef PARANOID if (tile == (Tile *) NULL) { TxError("Error: setting contact tile to null\n"); } #endif if ((IsSplit(tile) && TTMaskHasType(&mask, TiGetRightType(tile))) || TTMaskHasType(&mask, TiGetType(tile))) { tileJunk *j = (tileJunk *)tile->ti_client; cElement *ce; ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement))); contacts->cp_tile[contacts->cp_currentcontact] = tile; ce->ce_thisc = contacts; ce->ce_nextc = j->contactList; (contacts->cp_currentcontact) += 1; j->contactList = ce; } } #ifdef PARANOID if (contacts->cp_currentcontact > LAYERS_PER_CONTACT) { TxError("Error: Not enough space allocated for contact nodes\n"); } #endif } } /* *-------------------------------------------------------------------------- * * ResProcessTiles--Calls ResEachTile with processed tiles belonging to * nodes in ResNodeQueue. When all the tiles corresponding * to a node have been processed, the node is moved to * ResNodeList. * * Results: Return 1 if any error occurred, 0 otherwise. * * Side Effects: Cleans extraneous linked lists from nodes. * *-------------------------------------------------------------------------- */ int ResProcessTiles(goodies, origin) Point *origin; ResGlobalParams *goodies; { Tile *startTile; int tilenum,merged; resNode *resptr2; jElement *workingj; cElement *workingc; ResFixPoint *fix; resNode *resptr; int (*tilefunc)(); #ifdef LAPLACE tilefunc = (ResOptionsFlags & ResOpt_DoLaplace)?ResLaplaceTile:ResEachTile; #else tilefunc = ResEachTile; #endif if (ResOptionsFlags & ResOpt_Signal) { startTile = FindStartTile(goodies, origin); if (startTile == NULL) return(1); resCurrentNode = NULL; (void) (*tilefunc)(startTile, origin); } #ifdef ARIEL else if (ResOptionsFlags & ResOpt_Power) { for (fix = ResFixList; fix != NULL;fix=fix->fp_next) { Tile *tile = fix->fp_tile; if (tile == NULL) { tile = ResDef->cd_planes[DBPlane(fix->fp_ttype)]->pl_hint; GOTOPOINT(tile, &(fix->fp_loc)); if (TiGetTypeExact(tile) != TT_SPACE) { fix->fp_tile = tile; } else { tile = NULL; } } if (tile != NULL) { int x = fix->fp_loc.p_x; int y = fix->fp_loc.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); fix->fp_node = resptr; NEWBREAK(resptr, tile, x, y, NULL); } } for (fix = ResFixList; fix != NULL; fix = fix->fp_next) { Tile *tile = fix->fp_tile; if (tile != NULL && (((tileJunk *)tile->ti_client)->tj_status & RES_TILE_DONE) == 0) { resCurrentNode = fix->fp_node; (void) (*tilefunc)(tile, (Point *)NULL); } } } #endif #ifdef PARANOID else { TxError("Unknown analysis type in ResProcessTiles\n"); } #endif /* Process Everything else */ while (ResNodeQueue != NULL) { /* * merged keeps track of whether another node gets merged into * the current one. If it does, then the node must be processed * because additional junctions or contacts were added */ resptr2 = ResNodeQueue; merged = FALSE; /* Process all junctions associated with node */ for (workingj = resptr2->rn_je; workingj != NULL; workingj = workingj->je_nextj) { ResJunction *rj = workingj->je_thisj; if (rj->rj_status == FALSE) { for (tilenum = 0; tilenum < TILES_PER_JUNCTION; tilenum++) { Tile *tile = rj->rj_Tile[tilenum]; tileJunk *j = (tileJunk *) tile->ti_client; if ((j->tj_status & RES_TILE_DONE) == 0) { resCurrentNode = resptr2; merged |= (*tilefunc)(tile,(Point *)NULL); } if (merged & ORIGIN) break; } if (merged & ORIGIN) break; rj->rj_status = TRUE; } } /* Next, Process all contacts. */ for (workingc = resptr2->rn_ce;workingc != NULL;workingc = workingc->ce_nextc) { ResContactPoint *cp = workingc->ce_thisc; if (merged & ORIGIN) break; if (cp->cp_status == FALSE) { int newstatus = TRUE; for (tilenum = 0; tilenum < cp->cp_currentcontact; tilenum++) { Tile *tile = cp->cp_tile[tilenum]; tileJunk *j = (tileJunk *) tile->ti_client; if ((j->tj_status & RES_TILE_DONE) == 0) { if (cp->cp_cnode[tilenum] == resptr2) { resCurrentNode = resptr2; merged |= (*tilefunc)(tile,(Point *)NULL); } else { newstatus = FALSE; } } if (merged & ORIGIN) break; } if (merged & ORIGIN) break; cp->cp_status = newstatus; } } /* * If nothing new has been added via a merge, then the node is * finished. It is removed from the pending queue, added to the * done list, cleaned up, and passed to ResDoneWithNode */ if (merged == FALSE) { ResRemoveFromQueue(resptr2,&ResNodeQueue); resptr2->rn_more = ResNodeList; resptr2->rn_less = NULL; resptr2->rn_status &= ~PENDING; resptr2->rn_status |= FINISHED | MARKED; if (ResNodeList != NULL) { ResNodeList->rn_less = resptr2; } if (resptr2->rn_noderes == 0) { ResOriginNode=resptr2; } ResNodeList = resptr2; ResCleanNode(resptr2, FALSE, &ResNodeList, &ResNodeQueue); ResDoneWithNode(resptr2); } } return(0); } /*------------------------------------------------------------------------- * * ResExtractNet-- extracts the resistance net at the specified * rn_loc. If the resulting net is greater than the tolerance, * simplify and return the resulting network. * * Results: 0 iff it worked. * * Side effects: Produces a resistance network for the node. * * *------------------------------------------------------------------------- */ bool ResExtractNet(startlist,goodies,cellname) ResFixPoint *startlist; ResGlobalParams *goodies; char *cellname; { SearchContext scx; int pNum; ResDevTile *DevTiles,*lasttile; TileTypeBitMask FirstTileMask; Point startpoint; ResFixPoint *fix; static int first = 1; /* Make sure all global network variables are reset */ ResResList=NULL; ResNodeList=NULL; ResDevList=NULL; ResNodeQueue=NULL; ResContactList = NULL; ResOriginNode = NULL; /* Pass back network pointers */ goodies->rg_maxres = 0; goodies->rg_tilecount = 0; /*set up internal stuff if this is the first time through */ if (first) { ResInitializeConn(); first = 0; ResGetReCell(); } /* Initialize Cell */ if (cellname) { CellDef *def = DBCellLookDef(cellname); if (def == (CellDef *) NULL) { TxError("Error: No such cell \"%s\"\n", cellname); return TRUE; } scx.scx_use = DBCellNewUse(def, (char *)NULL); DBSetTrans (scx.scx_use, &GeoIdentityTransform); scx.scx_trans = GeoIdentityTransform; } else { MagWindow *w = ToolGetBoxWindow(&scx.scx_area, (int *) NULL); if (w == (MagWindow *) NULL) { TxError("Sorry, the box must appear in one of the windows.\n"); return TRUE; } scx.scx_use = (CellUse *) w->w_surfaceID; scx.scx_trans = GeoIdentityTransform; } DBCellClearDef(ResUse->cu_def); /* Copy Paint */ DevTiles = NULL; lasttile = NULL; for (fix = startlist; fix != NULL;fix=fix->fp_next) { ResDevTile *newdevtiles,*tmp; #ifdef ARIEL if ((ResOptionsFlags & ResOpt_Power) && strcmp(fix->fp_name,goodies->rg_name) != 0) continue; #endif scx.scx_area.r_ll.p_x = fix->fp_loc.p_x-2; scx.scx_area.r_ll.p_y = fix->fp_loc.p_y-2; scx.scx_area.r_ur.p_x = fix->fp_loc.p_x+2; scx.scx_area.r_ur.p_y = fix->fp_loc.p_y+2; startpoint = fix->fp_loc; // Because fix->fp_ttype might come from a label with a sticky type // that does not correspond exactly to the layer underneath, include // all connecting types. /* TTMaskSetOnlyType(&FirstTileMask,fix->fp_ttype); */ TTMaskSetMask(&FirstTileMask, &DBConnectTbl[fix->fp_ttype]); newdevtiles = DBTreeCopyConnectDCS(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect, ResUse); for (tmp = newdevtiles; tmp && tmp->nextDev; tmp = tmp->nextDev); if (newdevtiles) { if (DevTiles) { lasttile->nextDev = newdevtiles; } else { DevTiles = newdevtiles; } lasttile = tmp; } } ExtResetTiles(scx.scx_use->cu_def, extUnInit); /* find all contacts in design and note their position */ ResContactList = (ResContactPoint *) ExtFindRegions(ResUse->cu_def, &(ResUse->cu_def->cd_bbox), &DBAllButSpaceAndDRCBits, ResConnectWithSD, extUnInit, ResFirst, ResEach); ExtResetTiles(ResUse->cu_def,extUnInit); /* * dissolve the contacts and find which tiles now cover the point * where the tile used to be. */ ResDissolveContacts(ResContactList); /* Add "junk" fields to tiles */ for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { Plane *plane = ResUse->cu_def->cd_planes[pNum]; Rect *rect = &ResUse->cu_def->cd_bbox; ResFracture(plane,rect); (void) DBSrPaintClient((Tile *) NULL,plane,rect, &DBAllButSpaceAndDRCBits, (ClientData) CLIENTDEFAULT, ResAddPlumbing, (ClientData) &ResDevList); } /* Finish preprocessing. */ ResMakePortBreakpoints(ResUse->cu_def); ResMakeLabelBreakpoints(ResUse->cu_def); ResFindNewContactTiles(ResContactList); ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def); #ifdef LAPLACE if (ResOptionsFlags & ResOpt_DoLaplace) { for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { Plane *plane = ResUse->cu_def->cd_planes[pNum]; Rect *rect = &ResUse->cu_def->cd_bbox; Res1d(plane,rect); } } #endif #ifdef ARIEL if (ResOptionsFlags & ResOpt_Power) { for (fix = startlist; fix != NULL;fix=fix->fp_next) { fix->fp_tile = ResUse->cu_def->cd_planes[DBPlane(fix->fp_ttype)]->pl_hint; GOTOPOINT(fix->fp_tile,&fix->fp_loc); if (TiGetTypeExact(fix->fp_tile) == TT_SPACE) fix->fp_tile = NULL; } } #endif /* do extraction */ if (ResProcessTiles(goodies, &startpoint) != 0) return TRUE; return FALSE; } /* *------------------------------------------------------------------------- * * ResCleanUpEverything--After each net is extracted by ResExtractNet, * the resulting memory must be freed up, and varius trash swept under * the carpet in preparation for the next extraction. * * Results: none * * Side Effects: Frees up memory formerly occupied by network elements. * *------------------------------------------------------------------------- */ void ResCleanUpEverything() { int pNum; resResistor *oldRes; resDevice *oldDev; ResContactPoint *oldCon; /* check integrity of internal database. Free up lists. */ for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { (void) DBSrPaintClient((Tile *) NULL,ResUse->cu_def->cd_planes[pNum], &(ResUse->cu_def->cd_bbox),&DBAllButSpaceAndDRCBits, (ClientData) CLIENTDEFAULT,ResRemovePlumbing, (ClientData) NULL); } while (ResNodeList != NULL) { ResCleanNode(ResNodeList,TRUE,&ResNodeList,&ResNodeQueue); } while (ResContactList != NULL) { oldCon = ResContactList; ResContactList = oldCon->cp_nextcontact; freeMagic((char *)oldCon); } while (ResResList != NULL) { oldRes = ResResList; ResResList = ResResList->rr_nextResistor; freeMagic((char *)oldRes); } while (ResDevList != NULL) { oldDev = ResDevList; ResDevList = ResDevList->rd_nextDev; if ((oldDev->rd_status & RES_DEV_SAVE) == 0) { freeMagic((char *)oldDev->rd_terminals); freeMagic((char *)oldDev); } } DBCellClearDef(ResUse->cu_def); } /* *------------------------------------------------------------------------- * * FindStartTile-- To start the extraction, we need to find the first driver. * The sim file gives us the location of a point in or near (within 1 * unit) of the device. FindStartTile looks for the device, then * for adjoining diffusion. The diffusion tile is returned. * * Results: returns source diffusion tile, if it exists. Otherwise, return * NULL. * * Side Effects: none * *------------------------------------------------------------------------- */ Tile * FindStartTile(goodies, SourcePoint) Point *SourcePoint; ResGlobalParams *goodies; { Point workingPoint; Tile *tile, *tp; int pnum, t1, t2; ExtDevice *devptr; /* If the drive point is on a contact, check for the contact residues */ /* first, then the contact type itself. */ if (DBIsContact(goodies->rg_ttype)) { TileTypeBitMask *rmask = DBResidueMask(goodies->rg_ttype); TileType savtype = goodies->rg_ttype; TileType rtype; savtype = goodies->rg_ttype; for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++) if (TTMaskHasType(rmask, rtype)) { if ((tile = FindStartTile(goodies, SourcePoint)) != NULL) { goodies->rg_ttype = savtype; return tile; } } goodies->rg_ttype = savtype; } workingPoint.p_x = goodies->rg_devloc->p_x; workingPoint.p_y = goodies->rg_devloc->p_y; pnum = DBPlane(goodies->rg_ttype); /* for drivepoints, we don't have to find a device */ if (goodies->rg_status & DRIVEONLY) { tile = ResUse->cu_def->cd_planes[pnum]->pl_hint; GOTOPOINT(tile, &workingPoint); SourcePoint->p_x = workingPoint.p_x; SourcePoint->p_y = workingPoint.p_y; if (TiGetTypeExact(tile) == goodies->rg_ttype) return tile; else { /* On the other hand, drivepoints derived from subcircuit */ /* boundaries lie on tile boundaries, and GOTOPOINT() will */ /* pick the tile on the wrong side for TOP and RIGHT */ /* segment coincidences. */ if (workingPoint.p_x == LEFT(tile)) { for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp)) if (TiGetRightType(tp) == goodies->rg_ttype) return(tp); } else if (workingPoint.p_y == BOTTOM(tile)) { for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp)) if (TiGetTopType(tp) == goodies->rg_ttype) return(tp); } } TxError("Couldn't find wire at %d %d\n", goodies->rg_devloc->p_x, goodies->rg_devloc->p_y); return NULL; } tile = ResUse->cu_def->cd_planes[pnum]->pl_hint; GOTOPOINT(tile, &workingPoint); if (IsSplit(tile)) { if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile)) != 0) { t1 = TiGetLeftType(tile); TiSetBody(tile, t1 & ~TT_SIDE); } else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile)) != 0) { t1 = TiGetRightType(tile); TiSetBody(tile, t1 & TT_SIDE); } else { TxError("Couldn't find device at %d %d\n", goodies->rg_devloc->p_x, goodies->rg_devloc->p_y); return(NULL); } } else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)) == 0) { TxError("Couldn't find device at %d %d\n", goodies->rg_devloc->p_x, goodies->rg_devloc->p_y); return(NULL); } else t1 = TiGetType(tile); devptr = ExtCurStyle->exts_device[t1]; /* left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp)) { t2 = TiGetRightType(tp); if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2)) { SourcePoint->p_x = LEFT(tile); SourcePoint->p_y = (MIN(TOP(tile),TOP(tp))+ MAX(BOTTOM(tile),BOTTOM(tp)))>>1; return(tp); } } /* right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp)) { t2 = TiGetLeftType(tp); if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2)) { SourcePoint->p_x = RIGHT(tile); SourcePoint->p_y = (MIN(TOP(tile),TOP(tp))+ MAX(BOTTOM(tile),BOTTOM(tp)))>>1; return(tp); } } /* top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp=BL(tp)) { t2 = TiGetBottomType(tp); if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2)) { SourcePoint->p_y = TOP(tile); SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp))+ MAX(LEFT(tile),LEFT(tp)))>>1; return(tp); } } /* bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp)) { t2 = TiGetTopType(tp); if (TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),t2)) { SourcePoint->p_y = BOTTOM(tile); SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp))+ MAX(LEFT(tile),LEFT(tp)))>>1; return(tp); } } return((Tile *) NULL); } /* *------------------------------------------------------------------------- * * ResGetDevice -- Once the net is extracted, we still have to equate * the sim file devices with the layout devices. ResGetDevice * looks for a device at the given location. * * Results: returns device structure at location DevicePoint, if it * exists. * * Side Effects: none * *------------------------------------------------------------------------- */ resDevice * ResGetDevice(pt) Point *pt; { Point workingPoint; Tile *tile; int pnum; workingPoint.p_x = (*pt).p_x; workingPoint.p_y = (*pt).p_y; for (pnum= PL_TECHDEPBASE; pnum < DBNumPlanes; pnum++) { if (TTMaskIntersect(&ExtCurStyle->exts_deviceMask,&DBPlaneTypes[pnum]) == 0) { continue; } /*start at hint tile for device plane */ tile = ResUse->cu_def->cd_planes[pnum]->pl_hint; GOTOPOINT(tile,&workingPoint); if (IsSplit(tile)) { if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile)) || TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile))) return(((tileJunk *)tile->ti_client)->deviceList); } else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile))) { return(((tileJunk *)tile->ti_client)->deviceList); } } return (NULL); }