Compare commits
10 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d9e6c78adb | |
|
|
d8580be739 | |
|
|
1a16502a69 | |
|
|
5ecf10c022 | |
|
|
e366cf6a4c | |
|
|
7ecebb5dd6 | |
|
|
099d513011 | |
|
|
e45399d347 | |
|
|
7a3717b02a | |
|
|
a062fdcfe0 |
|
|
@ -2324,7 +2324,7 @@ CmdDoProperty(
|
|||
TxCommand *cmd,
|
||||
int argstart)
|
||||
{
|
||||
PropertyRecord *proprec;
|
||||
PropertyRecord *proprec = NULL;
|
||||
char *value;
|
||||
bool propfound, dolist;
|
||||
int proptype, proplen, propvalue, i;
|
||||
|
|
@ -2662,31 +2662,31 @@ CmdDoProperty(
|
|||
* the valid number of arguments, then again to parse the
|
||||
* values, once the property record has been allocated
|
||||
*/
|
||||
if (proptype == PROPERTY_TYPE_PLANE)
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
for (proplen = 0; *value != '\0'; )
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
proprec->prop_value.prop_plane = plane;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
for (proplen = 0; *value != '\0'; )
|
||||
if (isspace(*value) && (*value != '\0')) value++;
|
||||
if (!isspace(*value))
|
||||
{
|
||||
if (isspace(*value) && (*value != '\0')) value++;
|
||||
if (!isspace(*value))
|
||||
{
|
||||
proplen++;
|
||||
while (!isspace(*value) && (*value != '\0')) value++;
|
||||
}
|
||||
proplen++;
|
||||
while (!isspace(*value) && (*value != '\0')) value++;
|
||||
}
|
||||
if (proplen > 0)
|
||||
}
|
||||
if (proplen > 0)
|
||||
{
|
||||
if (proptype == PROPERTY_TYPE_PLANE)
|
||||
{
|
||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||
proprec->prop_value.prop_plane = plane;
|
||||
} else {
|
||||
proprec = (PropertyRecord *)mallocMagic(
|
||||
sizeof(PropertyRecord) +
|
||||
(proplen - 2) * sizeof(int));
|
||||
}
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
}
|
||||
proprec->prop_type = proptype;
|
||||
proprec->prop_len = proplen;
|
||||
|
||||
/* Second pass */
|
||||
value = cmd->tx_argv[argstart + 1];
|
||||
|
|
|
|||
|
|
@ -647,6 +647,9 @@ cmdSelectArea(
|
|||
if (!(crec->dbw_flags & DBW_SEELABELS)) TTMaskClearType(&mask, L_LABEL);
|
||||
if (!(crec->dbw_flags & DBW_SEECELLS)) TTMaskClearType(&mask, L_CELL);
|
||||
}
|
||||
else if (option == SEL_AREA)
|
||||
TTMaskSetType(&mask, L_LABEL);
|
||||
|
||||
SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
int xj, yj, direction;
|
||||
resNode **PendingList;
|
||||
{
|
||||
resNode *resptr;
|
||||
resNode *resptr = NULL;
|
||||
resDevice *resDev;
|
||||
tElement *tcell;
|
||||
int newnode;
|
||||
|
|
@ -64,7 +64,8 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
|
||||
ri = (resInfo *) TiGetClientPTR(tp);
|
||||
resDev = ri->deviceList;
|
||||
if ((ri->sourceEdge & direction) != 0)
|
||||
if ((((ri->sourceEdge & direction) != 0) && (resDev->rd_nterms == 4))
|
||||
|| (resDev->rd_nterms > 2))
|
||||
{
|
||||
if (resDev->rd_fet_source == (resNode *) NULL)
|
||||
{
|
||||
|
|
@ -73,11 +74,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
resDev->rd_fet_source = resptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
resptr = resDev->rd_fet_source;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (resDev->rd_nterms > 3)
|
||||
{
|
||||
if (resDev->rd_fet_drain == (resNode *) NULL)
|
||||
{
|
||||
|
|
@ -86,9 +85,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
resDev->rd_fet_drain = resptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
resptr = resDev->rd_fet_drain;
|
||||
}
|
||||
}
|
||||
if (newnode)
|
||||
{
|
||||
|
|
@ -99,7 +96,10 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
resptr->rn_te = tcell;
|
||||
ResAddToQueue(resptr, PendingList);
|
||||
}
|
||||
NEWBREAK(resptr, tile, xj, yj, NULL);
|
||||
if (resptr != NULL)
|
||||
{
|
||||
NEWBREAK(resptr, tile, xj, yj, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -131,20 +131,14 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
ri = (resInfo *) TiGetClientPTR(tp);
|
||||
resDev = ri->deviceList;
|
||||
|
||||
/* Arrived at a device that has a terminal connected to substrate */
|
||||
/* that is not a FET bulk terminal (e.g., varactor, diode). */
|
||||
if (resDev->rd_nterms < 4) return;
|
||||
|
||||
if (resDev->rd_fet_subs == (resNode *) NULL)
|
||||
if (resDev->rd_fet_subs == (resNode *)NULL)
|
||||
{
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
newnode = TRUE;
|
||||
resDev->rd_fet_subs = resptr;
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
newnode = TRUE;
|
||||
resDev->rd_fet_subs = resptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
resptr = resDev->rd_fet_subs;
|
||||
}
|
||||
resptr = resDev->rd_fet_subs;
|
||||
|
||||
if (newnode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -148,30 +148,49 @@ void
|
|||
ResDissolveContacts(contacts)
|
||||
ResContactPoint *contacts;
|
||||
{
|
||||
TileType t, oldtype;
|
||||
TileType t, conttype;
|
||||
Tile *tp;
|
||||
TileTypeBitMask residues;
|
||||
TileType residue[NP][NT];
|
||||
int pNum;
|
||||
|
||||
bzero((char *)residue, NP * NT * sizeof(TileType));
|
||||
|
||||
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
|
||||
{
|
||||
oldtype=contacts->cp_type;
|
||||
conttype = contacts->cp_type;
|
||||
|
||||
#ifdef PARANOID
|
||||
if (oldtype == TT_SPACE)
|
||||
if (conttype == 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))
|
||||
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
|
||||
/* Fill in details of the residue types for each contact type.
|
||||
* This is done only once per contact type. This could be refined
|
||||
* further by temporarily changing the paint table directly or
|
||||
* creating a separate paint table which erases contact cuts and
|
||||
* replaces them with the residues.
|
||||
*/
|
||||
|
||||
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]);
|
||||
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
|
||||
if (residue[DBPlane(conttype)][conttype] == TT_SPACE)
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
residue[pNum][conttype] = DBPlaneToResidue(conttype, pNum);
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
if (DBTypeOnPlane(conttype, pNum))
|
||||
{
|
||||
DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect),
|
||||
DBStdEraseTbl(conttype, pNum), (PaintUndoInfo *)NULL);
|
||||
DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect),
|
||||
DBStdPaintTbl(residue[pNum][conttype], pNum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PARANOID
|
||||
if (TiGetTypeExact(tp) == contacts->cp_type)
|
||||
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(conttype)]);
|
||||
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
|
||||
if (TiGetTypeExact(tp) == conttype)
|
||||
TxError("Error in Contact Preprocess Routines\n");
|
||||
#endif
|
||||
}
|
||||
|
|
@ -378,13 +397,14 @@ ResAddBreakpointFunc(tile, dinfo, node)
|
|||
*
|
||||
* ResFindNewContactTiles --
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* Side Effects: modifies information in the contact records.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -396,29 +416,40 @@ ResFindNewContactTiles(contacts)
|
|||
int pNum;
|
||||
Tile *tile;
|
||||
TileTypeBitMask mask;
|
||||
TileType lastType = TT_SPACE;
|
||||
|
||||
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
|
||||
{
|
||||
DBFullResidueMask(contacts->cp_type, &mask);
|
||||
|
||||
/* Watch for types that connect to the substrate plane or well; */
|
||||
/* e.g., psubstratepdiff connects to nwell but not through a */
|
||||
/* contact. */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
||||
/* Avoid re-running the following code for the same contact type */
|
||||
if (contacts->cp_type != lastType)
|
||||
{
|
||||
TileTypeBitMask cMask;
|
||||
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
||||
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
||||
lastType = contacts->cp_type;
|
||||
DBFullResidueMask(contacts->cp_type, &mask);
|
||||
|
||||
if (!TTMaskIsZero(&cMask))
|
||||
TTMaskSetMask(&mask, &cMask);
|
||||
/* Watch for types that connect to the substrate plane or well; */
|
||||
/* e.g., psubstratepdiff connects to nwell but not through a */
|
||||
/* contact. */
|
||||
|
||||
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
||||
{
|
||||
TileTypeBitMask cMask;
|
||||
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
||||
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
||||
|
||||
if (!TTMaskIsZero(&cMask))
|
||||
TTMaskSetMask(&mask, &cMask);
|
||||
}
|
||||
}
|
||||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
if (!DBTypeOnPlane(contacts->cp_type, pNum) &&
|
||||
(pNum != ExtCurStyle->exts_globSubstratePlane))
|
||||
continue;
|
||||
|
||||
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
|
||||
GOTOPOINT(tile, &(contacts->cp_center));
|
||||
PlaneSetHint(ResDef->cd_planes[pNum], tile);
|
||||
#ifdef PARANOID
|
||||
if (tile == (Tile *) NULL)
|
||||
{
|
||||
|
|
@ -476,10 +507,11 @@ ResFindNewContactTiles(contacts)
|
|||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
|
|
@ -1381,6 +1413,7 @@ FindStartTile(resisdata, SourcePoint)
|
|||
{
|
||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||
GOTOPOINT(tile, &workingPoint);
|
||||
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
|
||||
SourcePoint->p_x = workingPoint.p_x;
|
||||
SourcePoint->p_y = workingPoint.p_y;
|
||||
|
||||
|
|
@ -1414,6 +1447,7 @@ FindStartTile(resisdata, SourcePoint)
|
|||
|
||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||
GOTOPOINT(tile, &workingPoint);
|
||||
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
|
||||
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
|
|
@ -1765,6 +1799,7 @@ ResGetDevice(pt, type)
|
|||
|
||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||
GOTOPOINT(tile, &workingPoint);
|
||||
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
|
||||
|
||||
const ClientData ticlient = TiGetClient(tile);
|
||||
if (IsSplit(tile))
|
||||
|
|
|
|||
|
|
@ -76,10 +76,9 @@ ResCalcTileResistance(tile, info, pendingList, doneList)
|
|||
if (x < MinX) MinX = x;
|
||||
if (y > MaxY) MaxY = y;
|
||||
if (y < MinY) MinY = y;
|
||||
|
||||
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||
{
|
||||
device = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, produce resistors for partition. Keep track of */
|
||||
|
|
@ -125,7 +124,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
resNode **pendingList, **doneList;
|
||||
resResistor **resList;
|
||||
{
|
||||
int height;
|
||||
int count, height;
|
||||
bool merged;
|
||||
TileType ttype;
|
||||
Breakpoint *p1, *p2, *p3;
|
||||
|
|
@ -134,6 +133,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
resNode *currNode;
|
||||
float rArea;
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
HashTable BreakTable;
|
||||
HashEntry *he;
|
||||
|
||||
merged = FALSE;
|
||||
height = TOP(tile) - BOTTOM(tile);
|
||||
|
|
@ -163,21 +164,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
ttype = TiGetTypeExact(tile);
|
||||
|
||||
/* Re-sort nodes left to right. */
|
||||
count = ResSortBreaks(&info->breakList, TRUE);
|
||||
|
||||
ResSortBreaks(&info->breakList, TRUE);
|
||||
/* For long lists (defined as >= 16 entries), make a hash table of
|
||||
* the node pointer conversions so that each node can be updated
|
||||
* as we walk the list, instead of walking the rest of the list in
|
||||
* a nested loop for each entry.
|
||||
*/
|
||||
if (count >= 16)
|
||||
HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
|
||||
|
||||
/*
|
||||
* Eliminate breakpoints with the same X coordinate and merge
|
||||
* their nodes.
|
||||
*/
|
||||
|
||||
p2= info->breakList;
|
||||
p2 = info->breakList;
|
||||
|
||||
/* Add extra left area to leftmost node */
|
||||
|
||||
p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile));
|
||||
while (p2->br_next != NULL)
|
||||
{
|
||||
/* Has the node been recorded as needing to be replaced? */
|
||||
if (count >= 16)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
he = HashLookOnly(&BreakTable, (char *)p2->br_this);
|
||||
if (!he) break;
|
||||
p2->br_this = (resNode *)HashGetValue(he);
|
||||
}
|
||||
}
|
||||
p1 = p2;
|
||||
p2 = p2->br_next;
|
||||
if (p2->br_loc.p_x == p1->br_loc.p_x)
|
||||
|
|
@ -215,25 +233,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
/*
|
||||
* Was the node used in another info or breakpoint?
|
||||
* If so, replace the old node with the new one.
|
||||
*
|
||||
* Short lists: Walk the list to the end and change
|
||||
* nodes on the fly.
|
||||
* Long lists: Record the change to be made in the
|
||||
* hash table so that it can be executed as each list
|
||||
* entry is encountered.
|
||||
*/
|
||||
|
||||
p3 = p2->br_next;
|
||||
while (p3 != NULL)
|
||||
if (count >= 16)
|
||||
{
|
||||
if (p3->br_this == currNode)
|
||||
p3->br_this = p2->br_this;
|
||||
|
||||
p3 = p3->br_next;
|
||||
he = HashFind(&BreakTable, (char *)currNode);
|
||||
HashSetValue(he, (char *)p2->br_this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p3 = p2->br_next;
|
||||
while (p3 != NULL)
|
||||
{
|
||||
if (p3->br_this == currNode)
|
||||
p3->br_this = p2->br_this;
|
||||
|
||||
/*
|
||||
* If the X coordinates don't match, make a resistor between
|
||||
* the breakpoints.
|
||||
*/
|
||||
p3 = p3->br_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If the X coordinates don't match, make a resistor between
|
||||
* the breakpoints.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
resistor = (resResistor *)mallocMagic((unsigned)sizeof(resResistor));
|
||||
resistor->rr_nextResistor = (*resList);
|
||||
resistor->rr_lastResistor = NULL;
|
||||
|
|
@ -276,6 +307,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
|||
}
|
||||
}
|
||||
|
||||
if (count >= 16) HashKill(&BreakTable);
|
||||
|
||||
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
|
||||
freeMagic((char *)p2);
|
||||
info->breakList = NULL;
|
||||
|
|
@ -301,7 +334,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
resNode **pendingList, **doneList;
|
||||
resResistor **resList;
|
||||
{
|
||||
int width;
|
||||
int count, width;
|
||||
bool merged;
|
||||
TileType ttype;
|
||||
Breakpoint *p1, *p2, *p3;
|
||||
|
|
@ -310,6 +343,8 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
resNode *currNode;
|
||||
float rArea;
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
HashTable BreakTable;
|
||||
HashEntry *he;
|
||||
|
||||
merged = FALSE;
|
||||
width = RIGHT(tile) - LEFT(tile);
|
||||
|
|
@ -329,7 +364,15 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
}
|
||||
|
||||
/* Re-sort nodes south to north. */
|
||||
ResSortBreaks(&info->breakList, FALSE);
|
||||
count = ResSortBreaks(&info->breakList, FALSE);
|
||||
|
||||
/* For long lists (defined as >= 16 entries), make a hash table of
|
||||
* the node pointer conversions so that each node can be updated
|
||||
* as we walk the list, instead of walking the rest of the list in
|
||||
* a nested loop for each entry.
|
||||
*/
|
||||
if (count >= 16)
|
||||
HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
|
||||
|
||||
/* Simplified split tile handling */
|
||||
if (IsSplit(tile))
|
||||
|
|
@ -353,51 +396,75 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
|||
p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile));
|
||||
while (p2->br_next != NULL)
|
||||
{
|
||||
/* Has the node been recorded as needing to be replaced? */
|
||||
if (count >= 16)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
he = HashLookOnly(&BreakTable, (char *)p2->br_this);
|
||||
if (!he) break;
|
||||
p2->br_this = (resNode *)HashGetValue(he);
|
||||
}
|
||||
}
|
||||
p1 = p2;
|
||||
p2 = p2->br_next;
|
||||
if (p1->br_loc.p_y == p2->br_loc.p_y)
|
||||
{
|
||||
if (p2->br_this == p1->br_this)
|
||||
{
|
||||
currNode = NULL;
|
||||
p1->br_next = p2->br_next;
|
||||
freeMagic((char *)p2);
|
||||
p2 = p1;
|
||||
currNode = NULL;
|
||||
p1->br_next = p2->br_next;
|
||||
freeMagic((char *)p2);
|
||||
p2 = p1;
|
||||
}
|
||||
else if (p2->br_this == resCurrentNode)
|
||||
{
|
||||
currNode = p1->br_this;
|
||||
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
||||
freeMagic((char *)p1);
|
||||
merged = TRUE;
|
||||
currNode = p1->br_this;
|
||||
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
||||
freeMagic((char *)p1);
|
||||
merged = TRUE;
|
||||
}
|
||||
else if (p1->br_this == resCurrentNode)
|
||||
{
|
||||
currNode = p2->br_this;
|
||||
p1->br_next = p2->br_next;
|
||||
ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList);
|
||||
merged = TRUE;
|
||||
freeMagic((char *)p2);
|
||||
p2 = p1;
|
||||
currNode = p2->br_this;
|
||||
p1->br_next = p2->br_next;
|
||||
ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList);
|
||||
merged = TRUE;
|
||||
freeMagic((char *)p2);
|
||||
p2 = p1;
|
||||
}
|
||||
else
|
||||
{
|
||||
currNode = p1->br_this;
|
||||
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
||||
freeMagic((char *)p1);
|
||||
currNode = p1->br_this;
|
||||
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
||||
freeMagic((char *)p1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Was the node used in another info or breakpoint?
|
||||
* If so, replace the old node with the new one.
|
||||
*
|
||||
* Short lists: Walk the list to the end and change
|
||||
* nodes on the fly.
|
||||
* Long lists: Record the change to be made in the
|
||||
* hash table so that it can be executed as each list
|
||||
* entry is encountered.
|
||||
*/
|
||||
p3 = p2->br_next;
|
||||
while (p3 != NULL)
|
||||
if (count >= 16)
|
||||
{
|
||||
if (p3->br_this == currNode)
|
||||
p3->br_this = p2->br_this;
|
||||
he = HashFind(&BreakTable, (char *)currNode);
|
||||
HashSetValue(he, (char *)p2->br_this);
|
||||
}
|
||||
else
|
||||
{
|
||||
p3 = p2->br_next;
|
||||
while (p3 != NULL)
|
||||
{
|
||||
if (p3->br_this == currNode)
|
||||
p3->br_this = p2->br_this;
|
||||
|
||||
p3 = p3->br_next;
|
||||
p3 = p3->br_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -491,7 +558,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
* breakpoint, then return.
|
||||
*/
|
||||
|
||||
if (info->breakList->br_next == NULL)
|
||||
if (info->breakList->br_next == NULL)
|
||||
{
|
||||
freeMagic((char *)info->breakList);
|
||||
info->breakList = NULL;
|
||||
|
|
@ -525,7 +592,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
(devedge & TOPEDGE) == devedge ||
|
||||
(devedge & BOTTOMEDGE) == devedge)
|
||||
{
|
||||
ResSortBreaks(&info->breakList,TRUE);
|
||||
ResSortBreaks(&info->breakList, TRUE);
|
||||
p2 = NULL;
|
||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||
{
|
||||
|
|
@ -919,21 +986,207 @@ ResDoContacts(contact, nodes, resList)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResSortBreaks --
|
||||
* BreakCompare --
|
||||
*
|
||||
* Helper routine for MergeSortBreaks() (below). Simple
|
||||
* comparison of the breakpoint position. Comparison is
|
||||
* done for the X position if "xsort" is TRUE, and the Y
|
||||
* position if "xsort" is FALSE.
|
||||
*
|
||||
* Return value:
|
||||
* Return -1 if the (x or y) position of a is less than the
|
||||
* (x or y) position of b; return +1 if the position of a is
|
||||
* greater than the position of b; and return 0 if they have
|
||||
* equal positions.
|
||||
*
|
||||
* Side effect:
|
||||
* None.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
BreakCompare(
|
||||
Breakpoint *a,
|
||||
Breakpoint *b,
|
||||
int xsort)
|
||||
{
|
||||
if (xsort == TRUE)
|
||||
{
|
||||
if (a->br_loc.p_x < b->br_loc.p_x) return -1;
|
||||
if (a->br_loc.p_x > b->br_loc.p_x) return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a->br_loc.p_y < b->br_loc.p_y) return -1;
|
||||
if (a->br_loc.p_y > b->br_loc.p_y) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* MergeSorted --
|
||||
*
|
||||
* Helper routine for MergeSortBreaks() (below). Merge sort
|
||||
* merging routine.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Breakpoint *
|
||||
MergeSorted(
|
||||
Breakpoint *a,
|
||||
Breakpoint *b,
|
||||
int xsort)
|
||||
{
|
||||
Breakpoint head;
|
||||
Breakpoint *tail = &head;
|
||||
|
||||
head.br_next = NULL;
|
||||
|
||||
while (a != NULL && b != NULL)
|
||||
{
|
||||
if (BreakCompare(a, b, xsort) <= 0)
|
||||
{
|
||||
tail->br_next = a;
|
||||
a = a->br_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->br_next = b;
|
||||
b = b->br_next;
|
||||
}
|
||||
tail = tail->br_next;
|
||||
}
|
||||
tail->br_next = (a != NULL) ? a : b;
|
||||
|
||||
return head.br_next;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* SplitList --
|
||||
*
|
||||
* Helper routine for MergeSortBreaks() (below). Merge sort
|
||||
* splitting routine.
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
* None.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
SplitList(
|
||||
Breakpoint *source,
|
||||
Breakpoint **front,
|
||||
Breakpoint **back)
|
||||
{
|
||||
Breakpoint *slow;
|
||||
Breakpoint *fast;
|
||||
|
||||
if (source == NULL || source->br_next == NULL)
|
||||
{
|
||||
*front = source;
|
||||
*back = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
slow = source;
|
||||
fast = source->br_next;
|
||||
|
||||
while (fast != NULL)
|
||||
{
|
||||
fast = fast->br_next;
|
||||
|
||||
if (fast != NULL)
|
||||
{
|
||||
slow = slow->br_next;
|
||||
fast = fast->br_next;
|
||||
}
|
||||
}
|
||||
|
||||
*front = source;
|
||||
*back = slow->br_next;
|
||||
slow->br_next = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* MergeSortBreaks --
|
||||
*
|
||||
* See "ResSortBreaks" below. Alternative to bubble sort for long
|
||||
* linked lists.
|
||||
*
|
||||
* Results:
|
||||
* Pointer to a sorted breakpoint list.
|
||||
*
|
||||
* Side effects:
|
||||
* The breakpoints are sorted.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Breakpoint *
|
||||
MergeSortBreaks(Breakpoint *list, int xsort)
|
||||
{
|
||||
Breakpoint *a, *b;
|
||||
|
||||
if (list == NULL || list->br_next == NULL)
|
||||
return list;
|
||||
|
||||
SplitList(list, &a, &b);
|
||||
|
||||
a = MergeSortBreaks(a, xsort);
|
||||
b = MergeSortBreaks(b, xsort);
|
||||
|
||||
return MergeSorted(a, b, xsort);
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResSortBreaks --
|
||||
*
|
||||
* Sort breakpoints, either in the X direction (if "xsort" is TRUE)
|
||||
* or in the Y direction (if "xsort" is FALSE). For short lists
|
||||
* (< 16 elements), a simple bubble sort is used. For larger lists,
|
||||
* a merge sort is used. Most resistor networks are short, but
|
||||
* power/ground networks can be huge and cause a performance
|
||||
* bottleneck.
|
||||
*
|
||||
* Results:
|
||||
* Return the length of the list (maximum truncated at 16) so that
|
||||
* the calling routine can determine if this is a long or a short
|
||||
* linked list and treat it accordingly.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResSortBreaks(masterlist, xsort)
|
||||
Breakpoint **masterlist;
|
||||
int xsort;
|
||||
{
|
||||
Breakpoint *p1, *p2, *p3, *p4;
|
||||
bool changed;
|
||||
int count = 0;
|
||||
|
||||
for (p1 = *masterlist; p1; p1 = p1->br_next)
|
||||
{
|
||||
count++;
|
||||
if (count > 16)
|
||||
{
|
||||
*masterlist = MergeSortBreaks(*masterlist, xsort);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simple bubble sort */
|
||||
|
||||
changed = TRUE;
|
||||
while (changed == TRUE)
|
||||
|
|
@ -970,5 +1223,6 @@ ResSortBreaks(masterlist, xsort)
|
|||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -839,9 +839,9 @@ ResTriangleCheck(resptr)
|
|||
*
|
||||
* ResMergeNodes--
|
||||
*
|
||||
* results: none
|
||||
* Results: none
|
||||
*
|
||||
* side effects: appends all the cElement, jElement, tElement and
|
||||
* Side Effects: appends all the cElement, jElement, tElement and
|
||||
* resElement structures from node 2 onto node 1. Node 2 is
|
||||
* then eliminated.
|
||||
*
|
||||
|
|
@ -1010,7 +1010,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
* ResDeleteResPointer-- Deletes the pointer from a node to a resistor.
|
||||
* Used when a resistor is deleted.
|
||||
*
|
||||
* Results:none
|
||||
* Results: none
|
||||
*
|
||||
* Side Effects: Modifies a node's resistor list.
|
||||
*
|
||||
|
|
@ -1018,7 +1018,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
|||
*/
|
||||
|
||||
void
|
||||
ResDeleteResPointer(node,resistor)
|
||||
ResDeleteResPointer(node, resistor)
|
||||
resNode *node;
|
||||
resResistor *resistor;
|
||||
|
||||
|
|
@ -1059,7 +1059,7 @@ ResDeleteResPointer(node,resistor)
|
|||
*
|
||||
* ResEliminateResistor--
|
||||
*
|
||||
* Results:none
|
||||
* Results: none
|
||||
*
|
||||
* Side Effects: Deletes a resistor. Does not delete pointers from nodes to
|
||||
* resistor.
|
||||
|
|
@ -1097,8 +1097,7 @@ ResEliminateResistor(resistor, homelist)
|
|||
* they are no longer needed. If the 'info' option is used,
|
||||
* the node is eradicated.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
* Results: none.
|
||||
*
|
||||
* Side Effects: frees memory
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1356,7 +1356,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
|||
}
|
||||
if (extDev->subs == extNode)
|
||||
{
|
||||
if ((layoutDev->rd_nterms >= 4) && ((subs = layoutDev->rd_fet_subs) != NULL))
|
||||
if ((subs = layoutDev->rd_fet_subs) != NULL)
|
||||
{
|
||||
if (subs->rn_name != NULL && notdecremented)
|
||||
{
|
||||
|
|
@ -1422,7 +1422,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
|||
extNode->status |= DONTKILL;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (layoutDev->rd_nterms > 3)
|
||||
{
|
||||
if ((source = layoutDev->rd_fet_source) != NULL)
|
||||
{
|
||||
|
|
@ -1469,7 +1469,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (extDev->drain == extNode)
|
||||
else if ((extDev->drain == extNode) && (layoutDev->rd_nterms > 3))
|
||||
{
|
||||
/* Check for devices with only one terminal. If it was cast as source, */
|
||||
/* then swap it with the drain so that the code below handles it */
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
||||
#endif /* not lint */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for qsort() */
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
|
@ -386,7 +387,7 @@ ResMoveDevices(node1, node2)
|
|||
devptr = devptr->te_nextt;
|
||||
if (device->rd_fet_gate == node1)
|
||||
device->rd_fet_gate = node2;
|
||||
else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1))
|
||||
else if (device->rd_fet_subs == node1)
|
||||
device->rd_fet_subs = node2;
|
||||
else if (device->rd_fet_source == node1)
|
||||
device->rd_fet_source = node2;
|
||||
|
|
@ -401,6 +402,29 @@ ResMoveDevices(node1, node2)
|
|||
node1->rn_te = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* qrescompare ---
|
||||
*
|
||||
* Sort routine for qsort() to be used by ResScrunchNet(). Sorts in
|
||||
* order of the resistor value, smallest to largest.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
qrescompare(const void *one, const void *two)
|
||||
{
|
||||
int cval;
|
||||
|
||||
resResistor *r1 = *((resResistor **)one);
|
||||
resResistor *r2 = *((resResistor **)two);
|
||||
|
||||
if (r1->rr_value < r2->rr_value) return -1;
|
||||
else if (r1->rr_value == r2->rr_value) return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -424,29 +448,82 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
|||
float tolerance;
|
||||
|
||||
{
|
||||
resResistor *locallist = NULL, *current, *working;
|
||||
resResistor *current, *working;
|
||||
resNode *node1, *node2;
|
||||
resElement *rcell1;
|
||||
int c1, c2;
|
||||
int c1, c2, count = 0;
|
||||
|
||||
/* Sort resistors by size */
|
||||
current = *reslist;
|
||||
while (current != NULL)
|
||||
/* Method used to sort resistors by size depends on list length */
|
||||
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||
{
|
||||
working = current;
|
||||
current = current->rr_nextResistor;
|
||||
if (working == *reslist)
|
||||
*reslist = current;
|
||||
else
|
||||
working->rr_lastResistor->rr_nextResistor = current;
|
||||
count++;
|
||||
if (count >= 10) break;
|
||||
}
|
||||
|
||||
/* Sort resistors by size */
|
||||
|
||||
if (current != NULL)
|
||||
current->rr_lastResistor = working->rr_lastResistor;
|
||||
if (count >= 10)
|
||||
{
|
||||
int i;
|
||||
resResistor **resSortList;
|
||||
|
||||
ResAddResistorToList(working, &locallist);
|
||||
/* For long lists, sort using qsort() */
|
||||
/* NOTE: It might be better to use the same merge sort used for
|
||||
* MergeSortBreaks() in ResMakeRes.c, as it does not incur the
|
||||
* overhead of allocating memory and populating the array.
|
||||
*/
|
||||
count = 0;
|
||||
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||
count++;
|
||||
|
||||
resSortList = (resResistor **)mallocMagic(count * sizeof(resResistor *));
|
||||
|
||||
count = 0;
|
||||
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||
{
|
||||
resSortList[count] = current;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
|
||||
qsort(resSortList, count, sizeof(resResistor *), qrescompare);
|
||||
|
||||
/* Regenerate links on sorted list */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
current = resSortList[i];
|
||||
current->rr_nextResistor = (i == count - 1) ? NULL : resSortList[i + 1];
|
||||
current->rr_lastResistor = (i == 0) ? NULL : resSortList[i - 1];
|
||||
}
|
||||
*reslist = resSortList[0];
|
||||
|
||||
freeMagic(resSortList);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Original method: Walk the linked list and re-sort by size. */
|
||||
|
||||
resResistor *locallist = NULL;
|
||||
|
||||
current = *reslist;
|
||||
while (current != NULL)
|
||||
{
|
||||
working = current;
|
||||
current = current->rr_nextResistor;
|
||||
if (working == *reslist)
|
||||
*reslist = current;
|
||||
else
|
||||
working->rr_lastResistor->rr_nextResistor = current;
|
||||
|
||||
if (current != NULL)
|
||||
current->rr_lastResistor = working->rr_lastResistor;
|
||||
|
||||
ResAddResistorToList(working, &locallist);
|
||||
}
|
||||
*reslist = locallist;
|
||||
}
|
||||
|
||||
*reslist = locallist;
|
||||
while (*reslist != NULL && (*reslist)->rr_value < tolerance)
|
||||
{
|
||||
current = *reslist;
|
||||
|
|
@ -501,8 +578,8 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
|||
}
|
||||
}
|
||||
/*
|
||||
* If the current resistor isn't a deadend, add its value and
|
||||
* area to that of the next smallest one. If it is a deadend,
|
||||
* If the current resistor isn't a dead end, add its value and
|
||||
* area to that of the next smallest one. If it is a dead end,
|
||||
* simply add its area to its node.
|
||||
*/
|
||||
if (c1 != 0 && c2 != 0)
|
||||
|
|
@ -567,7 +644,7 @@ ResAddResistorToList(resistor, locallist)
|
|||
resResistor *resistor, **locallist;
|
||||
|
||||
{
|
||||
resResistor *local,*last=NULL;
|
||||
resResistor *local, *last = NULL;
|
||||
|
||||
for (local = *locallist; local != NULL; local = local->rr_nextResistor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -231,7 +231,8 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
|
||||
resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice)));
|
||||
resDev->rd_nterms = nterms;
|
||||
resDev->rd_terminals = (resNode **) mallocMagic(nterms * sizeof(resNode *));
|
||||
|
||||
resDev->rd_terminals = (resNode **)mallocMagic(nterms * sizeof(resNode *));
|
||||
for (i = 0; i != nterms; i++)
|
||||
resDev->rd_terminals[i] = (resNode *) NULL;
|
||||
|
||||
|
|
@ -733,6 +734,7 @@ ResPreProcessDevices(TileList, DeviceList, Def)
|
|||
|
||||
tile = PlaneGetHint(Def->cd_planes[pNum]);
|
||||
GOTOPOINT(tile, &(TileList->area.r_ll));
|
||||
PlaneSetHint(Def->cd_planes[pNum], tile);
|
||||
|
||||
tt = TiGetType(tile);
|
||||
tstruct = (resInfo *) TiGetClientPTR(tile);
|
||||
|
|
|
|||
|
|
@ -51,16 +51,24 @@ typedef struct resistor
|
|||
#define rr_connection1 rr_node[0]
|
||||
#define rr_connection2 rr_node[1]
|
||||
|
||||
/* Definitions for old FET-style MOSFET devices */
|
||||
/* Definitions for old FET-style MOSFET devices. Actual devices may have
|
||||
* any number of terminals. "GATE" is the identifying type; "SUBS" is
|
||||
* the substrate/well connection (if it exists), and the other terminals
|
||||
* make up the remaining entries. Memory will be allocated for the
|
||||
* substrate whether or not one is defined for the device. If the device
|
||||
* does not define a substrate connection, then this entry will remain
|
||||
* NULL.
|
||||
*/
|
||||
|
||||
#define RT_GATE 0
|
||||
#define RT_SOURCE 1
|
||||
#define RT_DRAIN 2
|
||||
#define RT_SUBS 3
|
||||
#define RT_SUBS 1
|
||||
#define RT_SOURCE 2
|
||||
#define RT_DRAIN 3
|
||||
|
||||
#define rd_fet_gate rd_terminals[RT_GATE]
|
||||
#define rd_fet_subs rd_terminals[RT_SUBS]
|
||||
#define rd_fet_source rd_terminals[RT_SOURCE]
|
||||
#define rd_fet_drain rd_terminals[RT_DRAIN]
|
||||
#define rd_fet_subs rd_terminals[RT_SUBS]
|
||||
|
||||
typedef struct device
|
||||
{
|
||||
|
|
@ -543,7 +551,7 @@ extern void ResCheckExtNodes();
|
|||
extern void ResSortByGate();
|
||||
extern void ResFixDevName();
|
||||
extern void ResWriteLumpFile();
|
||||
extern void ResSortBreaks();
|
||||
extern int ResSortBreaks();
|
||||
extern Plane *extResPrepSubstrate();
|
||||
|
||||
/* C99 compat */
|
||||
|
|
|
|||
|
|
@ -834,6 +834,8 @@ chunkdone:
|
|||
if (DBIsContact(type))
|
||||
TTMaskSetOnlyType(&typeMask, type);
|
||||
|
||||
/* Allow labels to be selected as part of the chunk */
|
||||
TTMaskSetType(&typeMask, L_LABEL);
|
||||
SelectArea(&newscx, &typeMask, xMask, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ SimConnectFunc(
|
|||
TileType loctype, ctype;
|
||||
TileType newdinfo = 0;
|
||||
int i, pNum;
|
||||
static char nodeName[256];
|
||||
static char nodeName[MAXPATHNAME];
|
||||
CellDef *def;
|
||||
TerminalPath *tpath = cx->tc_filter->tf_tpath;
|
||||
|
||||
|
|
@ -133,7 +133,8 @@ SimConnectFunc(
|
|||
char c = *n;
|
||||
|
||||
SigDisableInterrupts();
|
||||
strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first));
|
||||
strncpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first),
|
||||
MAXPATHNAME);
|
||||
SigEnableInterrupts();
|
||||
|
||||
*n = c;
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ proc magic::libcallback {command} {
|
|||
|
||||
switch $command {
|
||||
load {$winname load $celldef}
|
||||
place {$winname getcell $celldef}
|
||||
place {$winname getcell $celldef child 0 0}
|
||||
pick {
|
||||
magic::tool pick
|
||||
$winname getcell $celldef
|
||||
$winname getcell $celldef child 0 0
|
||||
magic::startselect $winname pick
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -651,9 +651,9 @@ proc magic::startselect {window {option {}}} {
|
|||
select nocycle
|
||||
}
|
||||
}
|
||||
set Opts(origin) [cursor]
|
||||
set Opts(origin) [cursor internal]
|
||||
set Opts(motion) [bind ${window} <Motion>]
|
||||
bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor\]; \
|
||||
bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor internal\]; \
|
||||
set x \[expr {\[lindex \$p 0\] - [lindex $Opts(origin) 0]}\]i; \
|
||||
set y \[expr {\[lindex \$p 1\] - [lindex $Opts(origin) 1]}\]i; \
|
||||
*bypass select move \${x} \${y}}]
|
||||
|
|
|
|||
Loading…
Reference in New Issue