Compare commits

...

7 Commits

Author SHA1 Message Date
R. Timothy Edwards d9e6c78adb Corrected an issue that was caused by early work on extresist:
The original version of extresist only worked with 4-terminal FET
devices, and handling of devices with fewer terminals was ignored,
and never properly dealt with.  This commit fixes the issues with
devices such as diodes that have fewer terminals.
2026-05-27 10:52:44 -04:00
R. Timothy Edwards d8580be739 Corrected a problem caused by fixing the "select visible" command
with respect to visible/invisible labels and cells.  The change
inadvertently made the "select area" command option stop selecting
labels on the same type as the layers being selected.  This has
been fixed.
2026-05-26 17:01:45 -04:00
R. Timothy Edwards 1a16502a69 Fixed a potential string overrun crash condition when doing
"getnode", as there is no limit on the length of a hierarchical
node name, and no check on the string length when copying back into
a fixed-length character array.
2026-05-25 14:39:12 -04:00
R. Timothy Edwards 5ecf10c022 Updated the version to go along with the merge of pull request #521
from Sylvain Munaut, which fixes an issue with the "property" command
when using the recently-added plane properties.
2026-05-25 12:07:33 -04:00
Sylvain Munaut e366cf6a4c commands: Fix parsing of plane properties in case of single string
The previous code would iterate over `proplen` chunks of strings
but would not initialize `proplen` for plane properties.

Technically for plane properties you don't need to "pre-count"
the string chunks but given how the code is currently written
it's easier to do the counting in all cases.

Also makes sure proprec is init to NULL so that if argument is
empty, property is set to NULL and not random value on the stack.

Fixes #520

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2026-05-25 12:49:52 +02:00
R. Timothy Edwards 7ecebb5dd6 Corrected a stupid omission to set the plane hint during a search
in "extresist", which when missing causes the plane to be searched
repeatedly from the same point instead of from the last place searched.
Can knock down the "extresist" time by up to 50%.
2026-05-24 22:01:29 -04:00
R. Timothy Edwards 099d513011 Corrected the "Pick" button action in the "Library Manager" window;
this had two issues:  (1) "getcell" was not being called with
"child 0 0", leading to child cells that are not placed where
expected in relation to a grid snap setting;  and (2) "cursor"
was assuming internal units and needed that to be explicitly
stated using "cursor internal".
2026-05-24 16:23:18 -04:00
15 changed files with 95 additions and 83 deletions

View File

@ -1 +1 @@
8.3.648
8.3.652

View File

@ -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];

View File

@ -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);
}

View File

@ -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)
{

View File

@ -449,6 +449,7 @@ ResFindNewContactTiles(contacts)
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
GOTOPOINT(tile, &(contacts->cp_center));
PlaneSetHint(ResDef->cd_planes[pNum], tile);
#ifdef PARANOID
if (tile == (Tile *) NULL)
{
@ -1412,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;
@ -1445,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))
{
@ -1796,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))

View File

@ -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 */
@ -248,7 +247,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
}
else
{
p3 = p2->br_next;
p3 = p2->br_next;
while (p3 != NULL)
{
if (p3->br_this == currNode)
@ -413,32 +412,32 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
{
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);
}
/*
@ -559,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;

View File

@ -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
*

View File

@ -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 */

View File

@ -387,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;

View File

@ -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);

View File

@ -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
{

View File

@ -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);
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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}}]