Significant overhaul of the extresist code. The purpose of this
overhaul was to introduce the concept of a "connection point" between two cells to the ".ext" file format so that it becomes possible to do proper hierarchical R-C extraction. Previously this information was not kept in the .ext file, making it impossible for "extresist" to know what sub-net of a net connects up or down the hierarchy. However, additional changes were made to the extresist code (in the resis/ directory) to add the handling of connections up and down the hierarchy, and to make the code a lot clearer and fix ambiguous variable and subroutine names.
This commit is contained in:
parent
d9e6c78adb
commit
1bcad6a25c
|
|
@ -578,6 +578,20 @@ typedef struct extRectList
|
|||
struct extRectList *r_next;
|
||||
} ExtRectList;
|
||||
|
||||
/* Structure similar to the above, but adding a pointer to a cell use ID
|
||||
* and a client data record which can be used to hold a region pointer.
|
||||
*/
|
||||
|
||||
typedef struct extConnList
|
||||
{
|
||||
char *r_useid; /* Cell Use being connected to */
|
||||
TileType r_type; /* Connecting tile type in the parent */
|
||||
Rect r_r; /* Area of connection */
|
||||
ClientData r_upnode; /* Parent node making the connection */
|
||||
ClientData r_downnode; /* Child node making the connection */
|
||||
struct extConnList *r_next; /* Next item in the linked list */
|
||||
} ExtConnList;
|
||||
|
||||
/* -------------------- Search context information -------------------- */
|
||||
|
||||
/* Search contexts are used in hierarchical searches */
|
||||
|
|
|
|||
|
|
@ -1618,12 +1618,128 @@ efConnectionFreeLinkedList(Connection *conn)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* efConnPointFreeLinkedList --
|
||||
*
|
||||
* Release memory for linked-list of ConnectionPoint* based on internal
|
||||
* list at ConnectionPoint->conn_next. 'connpt' argument must be non-NULL.
|
||||
*
|
||||
* Results:
|
||||
* Deallocates linked-list of ConnectionPoint* starting at 'connpt'
|
||||
*
|
||||
* Side effects:
|
||||
* Deallocates one or more connection point record(s).
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
efConnPointFreeLinkedList(ConnectionPoint *connpt)
|
||||
{
|
||||
while (connpt)
|
||||
{
|
||||
ConnectionPoint *next = connpt->conn_next;
|
||||
if (connpt->conn_name != NULL)
|
||||
freeMagic(connpt->conn_name);
|
||||
freeMagic(connpt);
|
||||
connpt = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* efBuildConnect --
|
||||
*
|
||||
* Process a "connect" line from a .ext file.
|
||||
* Creates a record of the area and type of the connection. Since the
|
||||
* extraction at the point of finding connections no longer knows what
|
||||
* net in the celldef (if any) is part of the connection, only the
|
||||
* location and type is preserved, and the cell being connected has to
|
||||
* be recovered by a search on the celldef's layout. These records are
|
||||
* used only by "extresist".
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Allocates a new connection port record for extresist, and prepends
|
||||
* it to the list for def.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
efBuildConnect(def, llx, lly, urx, ury, layerName, upnodeName, downnodeName)
|
||||
Def *def;
|
||||
int llx, lly, urx, ury;
|
||||
char *layerName;
|
||||
char *upnodeName;
|
||||
char *downnodeName;
|
||||
{
|
||||
int tnew;
|
||||
ConnectionPoint *connpt;
|
||||
HashEntry *he;
|
||||
Use *subuse;
|
||||
char *hierptr, *qptr, *useid;
|
||||
|
||||
/* Can't do anything without a node name to connect to */
|
||||
if (!strcmp(downnodeName, "\"None\"")) return;
|
||||
|
||||
/* "downnodeName" should be hierarchical; stop at the first hierarchical
|
||||
* divider and use the prefix to find the use being connected to.
|
||||
* NOTE: This will require dealing with connections that are more than
|
||||
* one hierarchical level deep (to be done).
|
||||
*/
|
||||
useid = downnodeName;
|
||||
if (*useid == '"') useid++;
|
||||
hierptr = strchr(useid, '/');
|
||||
if (hierptr != NULL) *hierptr = '\0';
|
||||
qptr = strrchr(useid, '"');
|
||||
if (qptr != NULL) *qptr = '\0';
|
||||
|
||||
if (layerName)
|
||||
tnew = efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName);
|
||||
else
|
||||
tnew = 0;
|
||||
|
||||
connpt = (ConnectionPoint *)mallocMagic(sizeof(ConnectionPoint));
|
||||
|
||||
he = HashFind(&def->def_uses, useid);
|
||||
subuse = (Use *)HashGetValue(he);
|
||||
connpt->conn_use = subuse;
|
||||
|
||||
connpt->conn_r.r_xbot = llx;
|
||||
connpt->conn_r.r_ybot = lly;
|
||||
connpt->conn_r.r_xtop = urx;
|
||||
connpt->conn_r.r_ytop = ury;
|
||||
connpt->conn_type = tnew;
|
||||
if (!strcmp(upnodeName, "\"None\""))
|
||||
connpt->conn_name = (char *)NULL;
|
||||
else
|
||||
{
|
||||
if (*upnodeName == '"') upnodeName++;
|
||||
connpt->conn_name = StrDup((char **)NULL, upnodeName);
|
||||
if ((qptr = strrchr(connpt->conn_name, '"')) != NULL) *qptr = '\0';
|
||||
}
|
||||
|
||||
/* To do: Add "downnodeName" to the ConnectionPoint structure. This
|
||||
* may not be necessary, as it is only being used by "extresist" which
|
||||
* is not using the extflat parser.
|
||||
*/
|
||||
|
||||
connpt->conn_next = def->def_connpts;
|
||||
def->def_connpts = connpt;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* efBuildMerge --
|
||||
*
|
||||
* Process a "merge" line from a .ext file.
|
||||
* Creates a connection record for the names 'nodeName1' and
|
||||
* 'nodeName2'.
|
||||
*
|
||||
|
|
@ -1638,7 +1754,7 @@ efConnectionFreeLinkedList(Connection *conn)
|
|||
*/
|
||||
|
||||
void
|
||||
efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
|
||||
efBuildMerge(def, nodeName1, nodeName2, deltaC, av, ac)
|
||||
Def *def; /* Def to which this connection is to be added */
|
||||
char *nodeName1; /* Name of first node in connection */
|
||||
char *nodeName2; /* Name of other node in connection */
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ EFDone(func)
|
|||
efConnectionFreeLinkedList(def->def_conns);
|
||||
efConnectionFreeLinkedList(def->def_caps);
|
||||
efConnectionFreeLinkedList(def->def_resistors);
|
||||
efConnPointFreeLinkedList(def->def_connpts);
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (kill = def->def_kills; kill; kill = kill->kill_next)
|
||||
|
|
@ -248,6 +249,7 @@ efDefNew(name)
|
|||
newdef->def_conns = (Connection *) NULL;
|
||||
newdef->def_caps = (Connection *) NULL;
|
||||
newdef->def_resistors = (Connection *) NULL;
|
||||
newdef->def_connpts = (ConnectionPoint *) NULL;
|
||||
newdef->def_kills = (Kill *) NULL;
|
||||
|
||||
/* Initialize circular list of nodes */
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ typedef struct conn
|
|||
#define conn_res conn_value.conn_val_res
|
||||
#define conn_cap conn_value.conn_val_cap
|
||||
|
||||
typedef struct connpoint ConnectionPoint;
|
||||
|
||||
/* -------------------------- Defs and uses --------------------------- */
|
||||
|
||||
/* A Def exists for each .ext file */
|
||||
|
|
@ -162,6 +164,7 @@ typedef struct def
|
|||
/* The following are all NULL-terminated lists */
|
||||
|
||||
Connection *def_conns; /* Hierarchical connections/adjustments */
|
||||
ConnectionPoint *def_connpts; /* Position of hierarchical connections */
|
||||
Connection *def_caps; /* Two-terminal capacitors */
|
||||
Connection *def_resistors; /* Two-terminal resistors */
|
||||
Kill *def_kills; /* Used to modify hierarchical structure
|
||||
|
|
@ -206,6 +209,17 @@ typedef struct use
|
|||
|
||||
#define IsArray(u) ((u)->use_xlo!=(u)->use_xhi || (u)->use_ylo!=(u)->use_yhi)
|
||||
|
||||
/* Connection point structure (used by "extresist") */
|
||||
|
||||
typedef struct connpoint
|
||||
{
|
||||
Use *conn_use; /* Use being connected to */
|
||||
Rect conn_r; /* Area, edge, or point of connection */
|
||||
int conn_type; /* A tile type at the connection */
|
||||
char *conn_name; /* Top level name of node, or NULL */
|
||||
struct connpoint *conn_next; /* Next connection point in list */
|
||||
} ConnectionPoint;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/* Structure passed down during hierarchical searching */
|
||||
|
|
@ -307,7 +321,9 @@ extern void CapHashSetValue();
|
|||
extern DevParam *efGetDeviceParams();
|
||||
extern void efBuildNode();
|
||||
extern void efConnectionFreeLinkedList(Connection *conn);
|
||||
extern void efConnPointFreeLinkedList(ConnectionPoint *conn);
|
||||
extern void efBuildConnect();
|
||||
extern void efBuildMerge();
|
||||
extern void efBuildResistor();
|
||||
extern void efBuildCap();
|
||||
extern HierContext *EFFlatBuildOneLevel();
|
||||
|
|
|
|||
|
|
@ -275,15 +275,11 @@ readfile:
|
|||
efBuildCap(def, argv[1], argv[2], (double) cap);
|
||||
break;
|
||||
|
||||
/* subcap node capacitance */
|
||||
case SUBCAP:
|
||||
cap = cscale*atoCap(argv[2]);
|
||||
efAdjustSubCap(def, argv[1], cap);
|
||||
break;
|
||||
|
||||
/* equiv node1 node2 */
|
||||
case EQUIV:
|
||||
efBuildEquiv(def, argv[1], argv[2], resist, isspice);
|
||||
/* connect useid llx lly urx ury type "node" ... */
|
||||
case CONNECT:
|
||||
efBuildConnect(def, atoi(argv[1]), atoi(argv[2]),
|
||||
atoi(argv[3]), atoi(argv[4]), argv[5],
|
||||
argv[6], argv[7]);
|
||||
break;
|
||||
|
||||
/* replaces "fet" (below) */
|
||||
|
|
@ -344,6 +340,11 @@ readfile:
|
|||
}
|
||||
break;
|
||||
|
||||
/* equiv node1 node2 */
|
||||
case EQUIV:
|
||||
efBuildEquiv(def, argv[1], argv[2], resist, isspice);
|
||||
break;
|
||||
|
||||
/* for backwards compatibility */
|
||||
/* fet type xlo ylo xhi yhi area perim substrate GATE T1 T2 ... */
|
||||
case FET:
|
||||
|
|
@ -373,7 +374,7 @@ readfile:
|
|||
*/
|
||||
|
||||
cap = (argc > 3) ? atoCap(argv[3]) * cscale : 0;
|
||||
efBuildConnect(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4);
|
||||
efBuildMerge(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4);
|
||||
break;
|
||||
|
||||
/* node name R C x y layer a1 p1 a2 p2 ... [ attrs ] */
|
||||
|
|
@ -449,6 +450,12 @@ resistChanged:
|
|||
}
|
||||
break;
|
||||
|
||||
/* subcap node capacitance */
|
||||
case SUBCAP:
|
||||
cap = cscale*atoCap(argv[2]);
|
||||
efAdjustSubCap(def, argv[1], cap);
|
||||
break;
|
||||
|
||||
/* use def use-id T0 .. T5 */
|
||||
case USE:
|
||||
efBuildUse(def, argv[1], argv[2],
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
*/
|
||||
typedef enum
|
||||
{
|
||||
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
|
||||
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
|
||||
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
||||
ABSTRACT, ADJUST, ATTR, CAP, CONNECT, DEVICE, DIST, EQUIV, FET, KILLNODE,
|
||||
MERGE, NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE,
|
||||
SCALE, SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
||||
} Key;
|
||||
|
||||
static const struct
|
||||
|
|
@ -42,6 +42,7 @@ keyTable[] =
|
|||
{"adjust", ADJUST, 4},
|
||||
{"attr", ATTR, 8},
|
||||
{"cap", CAP, 4},
|
||||
{"connect", CONNECT, 7},
|
||||
{"device", DEVICE, 11}, /* effectively replaces "fet" */
|
||||
{"distance", DIST, 4},
|
||||
{"equiv", EQUIV, 3},
|
||||
|
|
|
|||
|
|
@ -1110,7 +1110,7 @@ ExtSortTerminals(tran, ll)
|
|||
do
|
||||
{
|
||||
changed = 0;
|
||||
for( nsd = 0; nsd < tran->tr_nterm-1; nsd++ )
|
||||
for (nsd = 0; nsd < tran->tr_nterm-1; nsd++)
|
||||
{
|
||||
p1 = &(tran->tr_termpos[nsd]);
|
||||
p2 = &(tran->tr_termpos[nsd+1]);
|
||||
|
|
@ -1155,14 +1155,17 @@ ExtSortTerminals(tran, ll)
|
|||
* but S,D attributes are not that common so it should not matter
|
||||
* that much -- Stefanos 5/96 */
|
||||
|
||||
for ( lp = ll ; lp ; lp = lp->ll_next )
|
||||
if ( lp->ll_attr == nsd ) lp->ll_attr = LL_SORTATTR ;
|
||||
else if ( lp->ll_attr == nsd+1 ) lp->ll_attr = nsd ;
|
||||
for ( lp = ll ; lp ; lp = lp->ll_next )
|
||||
if ( lp->ll_attr == LL_SORTATTR ) lp->ll_attr = nsd+1;
|
||||
for (lp = ll; lp; lp = lp->ll_next)
|
||||
if (lp->ll_attr == nsd)
|
||||
lp->ll_attr = LL_SORTATTR;
|
||||
else if (lp->ll_attr == nsd + 1)
|
||||
lp->ll_attr = nsd;
|
||||
for (lp = ll; lp; lp = lp->ll_next)
|
||||
if (lp->ll_attr == LL_SORTATTR)
|
||||
lp->ll_attr = nsd + 1;
|
||||
}
|
||||
}
|
||||
while( changed );
|
||||
while (changed);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ ExtCell(def, outName, doLength)
|
|||
char *filename;
|
||||
FILE *f = NULL;
|
||||
Plane *savePlane;
|
||||
bool noextract;
|
||||
|
||||
/* If marked abstract, then don't extract the cell */
|
||||
DBPropGet(def, "noextract", &noextract);
|
||||
if (noextract) return extPrepSubstrate(def);
|
||||
|
||||
/* Incremental extraction: If the cell is marked for no extraction,
|
||||
* then just prepare the substrate plane and return it to the caller.
|
||||
|
|
|
|||
|
|
@ -281,6 +281,13 @@ extHierSubstrate(ha, use, x, y)
|
|||
nn->nn_next = node2->node_names->nn_next;
|
||||
node2->node_names->nn_next = node1->node_names;
|
||||
node2->node_len += node1->node_len;
|
||||
if (node2->node_ports)
|
||||
{
|
||||
ExtConnList *nport;
|
||||
for (nport = node2->node_ports; nport && nport->r_next;
|
||||
nport = nport->r_next);
|
||||
if (nport) nport->r_next = node1->node_ports;
|
||||
}
|
||||
freeMagic((char *)node1);
|
||||
}
|
||||
else
|
||||
|
|
@ -294,6 +301,13 @@ extHierSubstrate(ha, use, x, y)
|
|||
nn->nn_next = node1->node_names;
|
||||
node1->node_names = node2->node_names;
|
||||
node1->node_len += node2->node_len;
|
||||
if (node1->node_ports)
|
||||
{
|
||||
ExtConnList *nport;
|
||||
for (nport = node1->node_ports; nport && nport->r_next;
|
||||
nport = nport->r_next);
|
||||
if (nport) nport->r_next = node2->node_ports;
|
||||
}
|
||||
freeMagic((char *)node2);
|
||||
}
|
||||
}
|
||||
|
|
@ -499,6 +513,13 @@ extHierConnectFunc1(oneTile, dinfo, ha)
|
|||
nn->nn_next = node2->node_names->nn_next;
|
||||
node2->node_names->nn_next = node1->node_names;
|
||||
node2->node_len += node1->node_len;
|
||||
if (node2->node_ports)
|
||||
{
|
||||
ExtConnList *nport;
|
||||
for (nport = node2->node_ports; nport && nport->r_next;
|
||||
nport = nport->r_next);
|
||||
if (nport) nport->r_next = node1->node_ports;
|
||||
}
|
||||
freeMagic((char *) node1);
|
||||
}
|
||||
else
|
||||
|
|
@ -514,6 +535,13 @@ extHierConnectFunc1(oneTile, dinfo, ha)
|
|||
nn->nn_next = node1->node_names;
|
||||
node1->node_names = node2->node_names;
|
||||
node1->node_len += node2->node_len;
|
||||
if (node1->node_ports)
|
||||
{
|
||||
ExtConnList *nport;
|
||||
for (nport = node1->node_ports; nport && nport->r_next;
|
||||
nport = nport->r_next);
|
||||
if (nport) nport->r_next = node2->node_ports;
|
||||
}
|
||||
freeMagic((char *) node2);
|
||||
}
|
||||
}
|
||||
|
|
@ -523,6 +551,48 @@ extHierConnectFunc1(oneTile, dinfo, ha)
|
|||
}
|
||||
|
||||
/*
|
||||
*------------------------------------------------------------------------
|
||||
*
|
||||
* extHierFindTopNode --
|
||||
*
|
||||
* Simple callback function used in extHierConnectFunc2() to retrieve
|
||||
* the node name of a node in the CellDef being extracted at a specific
|
||||
* point. If there is no node at that point (indicating that there is
|
||||
* paint in a subcell at that location but no paint in the top level
|
||||
* cell) then return NULL.
|
||||
*
|
||||
* Returns:
|
||||
* 1 if a node is found, otherwise 0 to keep the search going.
|
||||
*
|
||||
* Side effects:
|
||||
* A pointer to the node is returned in the clientData field.
|
||||
*
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
extHierFindTopNode(Tile *tile,
|
||||
TileType dinfo,
|
||||
ExtRegion **nreg)
|
||||
{
|
||||
ExtRegion *tireg;
|
||||
|
||||
tireg = (ExtRegion *)ExtGetRegion(tile, dinfo);
|
||||
if ((ClientData)tireg == CLIENTDEFAULT)
|
||||
{
|
||||
*nreg = (ExtRegion *)0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*nreg = tireg;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*------------------------------------------------------------------------
|
||||
*
|
||||
* extHierConnectFunc2 --
|
||||
*
|
||||
* Called once for each tile 'cum' in extHierCumFlat->et_use->cu_def
|
||||
|
|
@ -538,6 +608,8 @@ extHierConnectFunc1(oneTile, dinfo, ha)
|
|||
* if the types of ha->hierOneTile and 'cum' connect.
|
||||
* Otherwise, if the tiles actually overlap (as opposed
|
||||
* to merely abut), mark it with feedback as an error.
|
||||
*
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
|
|
@ -608,6 +680,53 @@ extHierConnectFunc2(cum, dinfo, ha)
|
|||
|
||||
if (node1 != node2)
|
||||
{
|
||||
ExtConnList *newport;
|
||||
int pNum;
|
||||
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
NodeRegion *topnode = NULL;
|
||||
|
||||
/* Record the area of connection for both nodes in their
|
||||
* respective coordinate systems, and the name of the
|
||||
* cell use to which the connection is made.
|
||||
*/
|
||||
newport = (ExtConnList *)mallocMagic(sizeof(ExtConnList));
|
||||
newport->r_r = r;
|
||||
newport->r_type = ttype;
|
||||
newport->r_useid = ha->ha_subUse->cu_id;
|
||||
|
||||
/* Find a node at the given location in et_lookNames (the
|
||||
* original CellDef being extracted). If there is no node
|
||||
* in the def itself then the entry is NULL.
|
||||
*/
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
if (TTMaskHasType(&DBPlaneTypes[pNum], ttype))
|
||||
{
|
||||
/* Make sure that the rect is not zero area */
|
||||
if (r.r_xtop == r.r_xbot)
|
||||
{
|
||||
r.r_xtop++;
|
||||
r.r_xbot--;
|
||||
}
|
||||
if (r.r_ytop == r.r_ybot)
|
||||
{
|
||||
r.r_ytop++;
|
||||
r.r_ybot--;
|
||||
}
|
||||
|
||||
DBSrPaintArea((Tile *)NULL,
|
||||
ha->ha_cumFlat.et_lookNames->cd_planes[pNum],
|
||||
&r, &DBConnectTbl[ttype], extHierFindTopNode,
|
||||
(ClientData)PTR2CD(&topnode));
|
||||
newport->r_upnode = PTR2CD(topnode);
|
||||
|
||||
newport->r_downnode = PTR2CD(node2->node_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node1->node_len < node2->node_len)
|
||||
{
|
||||
/*
|
||||
|
|
@ -622,6 +741,12 @@ extHierConnectFunc2(cum, dinfo, ha)
|
|||
node2->node_names->nn_next = node1->node_names;
|
||||
node2->node_len += node1->node_len;
|
||||
freeMagic((char *) node1);
|
||||
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
newport->r_next = node2->node_ports;
|
||||
node2->node_ports = newport;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -637,6 +762,12 @@ extHierConnectFunc2(cum, dinfo, ha)
|
|||
node1->node_names = node2->node_names;
|
||||
node1->node_len += node2->node_len;
|
||||
freeMagic((char *) node2);
|
||||
|
||||
if (ExtOptions & EXT_DOEXTRESIST)
|
||||
{
|
||||
newport->r_next = node1->node_ports;
|
||||
node1->node_ports = newport;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -733,6 +864,13 @@ extHierConnectFunc3(cum, dinfo, ha)
|
|||
nn->nn_next = node2->node_names->nn_next;
|
||||
node2->node_names->nn_next = node1->node_names;
|
||||
node2->node_len += node1->node_len;
|
||||
if (node2->node_ports)
|
||||
{
|
||||
ExtConnList *nport;
|
||||
for (nport = node2->node_ports; nport && nport->r_next;
|
||||
nport = nport->r_next);
|
||||
if (nport) nport->r_next = node1->node_ports;
|
||||
}
|
||||
freeMagic((char *) node1);
|
||||
}
|
||||
else
|
||||
|
|
@ -748,6 +886,13 @@ extHierConnectFunc3(cum, dinfo, ha)
|
|||
nn->nn_next = node1->node_names;
|
||||
node1->node_names = node2->node_names;
|
||||
node1->node_len += node2->node_len;
|
||||
if (node1->node_ports)
|
||||
{
|
||||
ExtConnList *nport;
|
||||
for (nport = node1->node_ports; nport && nport->r_next;
|
||||
nport = nport->r_next);
|
||||
if (nport) nport->r_next = node2->node_ports;
|
||||
}
|
||||
freeMagic((char *) node2);
|
||||
}
|
||||
}
|
||||
|
|
@ -916,6 +1061,7 @@ extOutputConns(table, outf)
|
|||
NodeName *nfirst;
|
||||
HashSearch hs;
|
||||
HashEntry *he;
|
||||
ExtConnList *nport, *npnext;
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while ((he = HashNext(table, &hs)))
|
||||
|
|
@ -948,7 +1094,6 @@ extOutputConns(table, outf)
|
|||
node->node_pa[n].pa_area,
|
||||
node->node_pa[n].pa_perim);
|
||||
fprintf(outf, "\n");
|
||||
|
||||
nn->nn_node = (Node *) NULL; /* Processed */
|
||||
|
||||
/* Subsequent merges */
|
||||
|
|
@ -960,6 +1105,23 @@ extOutputConns(table, outf)
|
|||
}
|
||||
}
|
||||
nn->nn_node = (Node *) NULL;
|
||||
for (nport = node->node_ports; nport;)
|
||||
{
|
||||
LabRegion *lreg = (LabRegion *)CD2PTR(nport->r_upnode);
|
||||
NodeName *nn2 = (NodeName *)CD2PTR(nport->r_downnode);
|
||||
|
||||
npnext = nport->r_next;
|
||||
/* Output port positions */
|
||||
fprintf(outf, "connect %d %d %d %d %s \"%s\" \"%s\"\n",
|
||||
nport->r_r.r_xbot, nport->r_r.r_ybot,
|
||||
nport->r_r.r_xtop, nport->r_r.r_ytop,
|
||||
DBTypeShortName(nport->r_type),
|
||||
(lreg == (LabRegion *)NULL) ? "None" :
|
||||
extNodeName(lreg),
|
||||
(nn2) ? nn2->nn_name : "None");
|
||||
freeMagic((char *)nport);
|
||||
nport = npnext;
|
||||
}
|
||||
freeMagic((char *) node);
|
||||
}
|
||||
freeMagic((char *) nfirst);
|
||||
|
|
@ -1005,6 +1167,7 @@ extHierNewNode(he)
|
|||
node->node_names = nn;
|
||||
node->node_cap = (CapValue) 0;
|
||||
node->node_len = 1;
|
||||
node->node_ports = (ExtConnList *)NULL;
|
||||
for (n = 0; n < nclasses; n++)
|
||||
node->node_pa[n].pa_perim = node->node_pa[n].pa_area = 0;
|
||||
HashSetValue(he, (char *) nn);
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ extInterSubtreeElement(use, trans, x, y, r)
|
|||
int
|
||||
extInterSubtreeTile(tile, dinfo, cxp)
|
||||
Tile *tile;
|
||||
TileType dinfo;
|
||||
TileType dinfo; /* (unused) */
|
||||
TreeContext *cxp;
|
||||
{
|
||||
SearchContext newscx;
|
||||
|
|
@ -343,8 +343,9 @@ extInterOverlapSubtree(scx)
|
|||
*/
|
||||
|
||||
int
|
||||
extInterOverlapTile(tile, cxp)
|
||||
extInterOverlapTile(tile, dinfo, cxp)
|
||||
Tile *tile;
|
||||
TileType dinfo; /* (unused) */
|
||||
TreeContext *cxp;
|
||||
{
|
||||
SearchContext *scx = cxp->tc_scx;
|
||||
|
|
|
|||
|
|
@ -54,12 +54,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
/* C99 compat */
|
||||
#include "drc/drc.h"
|
||||
|
||||
#ifdef exactinteractions
|
||||
/*
|
||||
* If "exactinteractions" is defined, we use an experimental algorithm
|
||||
* for finding exact interaction areas. Currently it doesn't work too
|
||||
* well, so we leave it turned off.
|
||||
* If "exactinteractions" is defined, use an experimental algorithm
|
||||
* for finding exact interaction areas. Currently it doesn't work
|
||||
* too well, so it is disabled.
|
||||
*/
|
||||
/* #define exactinteractions */
|
||||
|
||||
#ifdef exactinteractions
|
||||
int ExtInterBloat = 10;
|
||||
#endif /* exactinteractions */
|
||||
|
||||
|
|
|
|||
|
|
@ -981,6 +981,7 @@ typedef struct node
|
|||
* in the list is the "official" node name.
|
||||
*/
|
||||
int node_len; /* Number of entries in node_names */
|
||||
ExtConnList *node_ports; /* List of areas that connect to other cells */
|
||||
CapValue node_cap; /* Capacitance to substrate */
|
||||
PerimArea node_pa[1]; /* Dummy; each node actually has
|
||||
* ExtCurStyle->exts_numResistClasses
|
||||
|
|
|
|||
222
resis/ResBasic.c
222
resis/ResBasic.c
|
|
@ -27,64 +27,24 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* 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;
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
|
||||
p.p_x = x;
|
||||
p.p_y = y;
|
||||
|
||||
for (pl = info->portList; pl; pl = pl->rp_nextPort)
|
||||
{
|
||||
rect = &(pl->rp_bbox);
|
||||
if (GEO_ENCLOSE(&p, rect))
|
||||
{
|
||||
node->rn_name = pl->rp_nodename;
|
||||
if (info->portList == pl)
|
||||
info->portList = pl->rp_nextPort;
|
||||
else
|
||||
{
|
||||
for (lp = info->portList; lp && (lp->rp_nextPort != pl);
|
||||
lp = lp->rp_nextPort);
|
||||
lp->rp_nextPort = pl->rp_nextPort;
|
||||
}
|
||||
freeMagic(pl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* resAllPortNodes --
|
||||
* resMakePortBreakpoints --
|
||||
*
|
||||
* Generate new nodes and breakpoints for every unused port declared
|
||||
* on a tile. However, if "startpoint" is inside the port position,
|
||||
* then it has already been processed, so ignore it.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds breakpoints where ports (drivers, sinks, or labels) have been
|
||||
* defined as connected to the tile.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
resAllPortNodes(tile, list)
|
||||
resMakePortBreakpoints(tile, list)
|
||||
Tile *tile;
|
||||
resNode **list;
|
||||
{
|
||||
|
|
@ -92,6 +52,7 @@ resAllPortNodes(tile, list)
|
|||
resNode *resptr;
|
||||
resPort *pl;
|
||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||
ResConnect *connect;
|
||||
|
||||
free_magic1_t mm1 = freeMagic1_init();
|
||||
for (pl = info->portList; pl; pl = pl->rp_nextPort)
|
||||
|
|
@ -103,13 +64,30 @@ resAllPortNodes(tile, list)
|
|||
resptr->rn_status = TRUE;
|
||||
resptr->rn_noderes = 0;
|
||||
resptr->rn_name = pl->rp_nodename;
|
||||
|
||||
/* Link back to the resnode from the ResConnect record */
|
||||
connect = pl->rp_connect;
|
||||
connect->rc_node = resptr;
|
||||
|
||||
ResAddToQueue(resptr, list);
|
||||
NEWBREAK(resptr, tile, x, y, NULL);
|
||||
ResNewBreak(resptr, tile, x, y, NULL);
|
||||
freeMagic1(&mm1, pl);
|
||||
}
|
||||
freeMagic1_end(&mm1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure used by ResEachTile for the callback to ResMultiPlaneFunc()
|
||||
* to pass a pointer to the tile being processed, and the terminal being
|
||||
* searched.
|
||||
*/
|
||||
|
||||
typedef struct tile_and_term
|
||||
{
|
||||
Tile *tat_tile;
|
||||
int tat_term;
|
||||
} TileAndTerm;
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -128,12 +106,13 @@ resAllPortNodes(tile, list)
|
|||
*/
|
||||
|
||||
int
|
||||
ResMultiPlaneFunc(tile, dinfo, tpptr)
|
||||
ResMultiPlaneFunc(tile, dinfo, tat)
|
||||
Tile *tile;
|
||||
TileType dinfo; /* Not used, but needs to be handled */
|
||||
Tile **tpptr;
|
||||
TileAndTerm *tat;
|
||||
{
|
||||
Tile *tp = *tpptr;
|
||||
Tile *tp = tat->tat_tile;
|
||||
int term = tat->tat_term;
|
||||
int xj, yj;
|
||||
|
||||
/* Simplified split tile handling---Ignore the right side of
|
||||
|
|
@ -146,7 +125,7 @@ ResMultiPlaneFunc(tile, dinfo, tpptr)
|
|||
|
||||
xj = (LEFT(tile) + RIGHT(tile)) / 2;
|
||||
yj = (TOP(tile) + BOTTOM(tile)) / 2;
|
||||
ResNewSDDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
|
||||
ResNewTermDevice(tp, tile, term, xj, yj, OTHERPLANE, &ResNodeQueue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -195,7 +174,44 @@ ResSubstrateFunc(tile, dinfo, tpptr)
|
|||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* ResEachTile--for each tile, make a list of all possible current sources/
|
||||
* ResStartTile --
|
||||
*
|
||||
* For the tile at the starting point of the net, create an initial
|
||||
* resNode entry.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side Effects:
|
||||
* creates a node.
|
||||
*
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResStartTile(tile, x, y)
|
||||
Tile *tile;
|
||||
int x, y;
|
||||
|
||||
{
|
||||
resNode *resptr;
|
||||
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
resptr->rn_status = TRUE;
|
||||
resptr->rn_noderes = 0;
|
||||
ResAddToQueue(resptr, &ResNodeQueue);
|
||||
ResNewBreak(resptr, tile, x, y, NULL);
|
||||
if (resCurrentNode == NULL) resCurrentNode = resptr;
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* 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 network for the tile.
|
||||
*
|
||||
|
|
@ -214,10 +230,8 @@ ResSubstrateFunc(tile, dinfo, tpptr)
|
|||
#define IGNORE_BOTTOM 8
|
||||
|
||||
bool
|
||||
ResEachTile(tile, startpoint)
|
||||
ResEachTile(tile)
|
||||
Tile *tile;
|
||||
Point *startpoint;
|
||||
|
||||
{
|
||||
Tile *tp;
|
||||
resNode *resptr;
|
||||
|
|
@ -226,14 +240,12 @@ ResEachTile(tile, startpoint)
|
|||
int xj, yj, i;
|
||||
bool merged;
|
||||
tElement *tcell;
|
||||
resInfo *tstructs= (resInfo *)TiGetClientPTR(tile);
|
||||
resInfo *tstructs = (resInfo *)TiGetClientPTR(tile);
|
||||
ExtDevice *devptr;
|
||||
int sides;
|
||||
|
||||
ResTileCount++;
|
||||
|
||||
/* Process startpoint, if any. */
|
||||
|
||||
/* Simplification: Split tiles handle either the non-space side,
|
||||
* or if neither side is space, then handle the left side.
|
||||
*/
|
||||
|
|
@ -258,21 +270,7 @@ ResEachTile(tile, startpoint)
|
|||
t1 = TiGetTypeExact(tile);
|
||||
}
|
||||
|
||||
if (startpoint != (Point *) NULL)
|
||||
{
|
||||
int x = startpoint->p_x;
|
||||
int y = startpoint->p_y;
|
||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
|
||||
resptr->rn_status = TRUE;
|
||||
resptr->rn_noderes = 0;
|
||||
ResAddToQueue(resptr, &ResNodeQueue);
|
||||
NEWBREAK(resptr, tile, x, y, NULL);
|
||||
if (resCurrentNode == NULL) resCurrentNode = resptr;
|
||||
resNodeIsPort(resptr, x, y, tile);
|
||||
}
|
||||
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1))
|
||||
{
|
||||
/*
|
||||
* The device is put in the center of the tile. This is fine
|
||||
|
|
@ -295,9 +293,7 @@ ResEachTile(tile, startpoint)
|
|||
InitializeResNode(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,
|
||||
ResNewBreak(resptr, tile, resptr->rn_loc.p_x,
|
||||
resptr->rn_loc.p_y, NULL);
|
||||
}
|
||||
}
|
||||
|
|
@ -326,7 +322,7 @@ ResEachTile(tile, startpoint)
|
|||
|
||||
/* left */
|
||||
if (!(sides & IGNORE_LEFT))
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
{
|
||||
t2 = TiGetRightType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
||||
|
|
@ -341,14 +337,14 @@ ResEachTile(tile, startpoint)
|
|||
/* found device */
|
||||
xj = LEFT(tile);
|
||||
yj = (TOP(tp) + BOTTOM(tp)) >> 1;
|
||||
ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
|
||||
ResNewTermDevice(tile, tp, i, xj, yj, RIGHTEDGE, &ResNodeQueue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < devptr->exts_deviceSDCount) break;
|
||||
}
|
||||
}
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2))
|
||||
{
|
||||
/* tile is junction */
|
||||
xj = LEFT(tile);
|
||||
|
|
@ -359,7 +355,7 @@ ResEachTile(tile, startpoint)
|
|||
|
||||
/* right */
|
||||
if (!(sides & IGNORE_RIGHT))
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
{
|
||||
t2 = TiGetLeftType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
||||
|
|
@ -374,18 +370,18 @@ ResEachTile(tile, startpoint)
|
|||
/* found device */
|
||||
xj = RIGHT(tile);
|
||||
yj = (TOP(tp) + BOTTOM(tp)) >> 1;
|
||||
ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
|
||||
ResNewTermDevice(tile, tp, i, xj, yj, LEFTEDGE, &ResNodeQueue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < devptr->exts_deviceSDCount) break;
|
||||
}
|
||||
}
|
||||
if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
|
||||
if (TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2))
|
||||
{
|
||||
/* tile is junction */
|
||||
xj = RIGHT(tile);
|
||||
yj = (MAX(BOTTOM(tile),BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
|
||||
yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
|
||||
(void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
|
||||
}
|
||||
}
|
||||
|
|
@ -407,25 +403,25 @@ ResEachTile(tile, startpoint)
|
|||
/* found device */
|
||||
yj = TOP(tile);
|
||||
xj = (LEFT(tp) + RIGHT(tp)) >> 1;
|
||||
ResNewSDDevice(tile, tp, xj, yj, BOTTOMEDGE, &ResNodeQueue);
|
||||
ResNewTermDevice(tile, tp, i, xj, yj, BOTTOMEDGE, &ResNodeQueue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < devptr->exts_deviceSDCount) break;
|
||||
}
|
||||
}
|
||||
if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
|
||||
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;
|
||||
xj = (MAX(LEFT(tile), LEFT(tp)) + MIN(RIGHT(tile), RIGHT(tp))) >> 1;
|
||||
ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
|
||||
}
|
||||
}
|
||||
|
||||
/* bottom */
|
||||
if (!(sides & IGNORE_BOTTOM))
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
{
|
||||
t2 = TiGetTopType(tp);
|
||||
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
|
||||
|
|
@ -440,29 +436,30 @@ ResEachTile(tile, startpoint)
|
|||
/* found device */
|
||||
yj = BOTTOM(tile);
|
||||
xj = (LEFT(tp) + RIGHT(tp)) >> 1;
|
||||
ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
|
||||
ResNewTermDevice(tile, tp, i, xj, yj, TOPEDGE, &ResNodeQueue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < devptr->exts_deviceSDCount) break;
|
||||
}
|
||||
}
|
||||
if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
|
||||
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;
|
||||
xj = (MAX(LEFT(tile), LEFT(tp)) + MIN(RIGHT(tile), RIGHT(tp))) >> 1;
|
||||
ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for source/drain on other planes (e.g., capacitors, bipolars, ...) */
|
||||
/* Check for terminals on other planes (e.g., capacitors, bipolars, ...) */
|
||||
|
||||
if (TTMaskHasType(&ResSDTypesBitMask, t1))
|
||||
if (TTMaskHasType(&ResTermTypesBitMask, t1))
|
||||
{
|
||||
Rect r;
|
||||
int pNum;
|
||||
TileTypeBitMask devMask;
|
||||
TileAndTerm tat;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
|
||||
|
|
@ -470,20 +467,29 @@ ResEachTile(tile, startpoint)
|
|||
{
|
||||
if (DBTypeOnPlane(t1, pNum)) continue;
|
||||
|
||||
/* NOTE: This is ridiculously inefficient and should be done
|
||||
* in a different way.
|
||||
*/
|
||||
|
||||
TTMaskZero(&devMask);
|
||||
for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
|
||||
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
||||
for (devptr = ExtCurStyle->exts_device[t2]; devptr;
|
||||
devptr = devptr->exts_next)
|
||||
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
|
||||
if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1))
|
||||
TTMaskSetType(&devMask, t2);
|
||||
{
|
||||
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
|
||||
{
|
||||
/* Check if any type in the terminal type list exists on this
|
||||
* plane before calling the search function.
|
||||
*/
|
||||
TileTypeBitMask termtypes;
|
||||
|
||||
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
|
||||
&r, &devMask, ResMultiPlaneFunc, (ClientData)&tile);
|
||||
TTMaskAndMask3(&termtypes, &devptr->exts_deviceSDTypes[i],
|
||||
&DBPlaneTypes[pNum]);
|
||||
|
||||
if (TTMaskIsZero(&termtypes))
|
||||
{
|
||||
tat.tat_tile = tile;
|
||||
tat.tat_term = i;
|
||||
DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
|
||||
&r, &devptr->exts_deviceSDTypes[i],
|
||||
ResMultiPlaneFunc, (ClientData)&tat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -519,7 +525,7 @@ ResEachTile(tile, startpoint)
|
|||
|
||||
tstructs->ri_status |= RES_TILE_DONE;
|
||||
|
||||
resAllPortNodes(tile, &ResNodeQueue);
|
||||
resMakePortBreakpoints(tile, &ResNodeQueue);
|
||||
|
||||
merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue,
|
||||
&ResNodeList);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
|
|||
{
|
||||
resSanityStack = StackNew(64);
|
||||
}
|
||||
for (node = nodeList; node != NULL; node=node->rn_more)
|
||||
for (node = nodeList; node != NULL; node = node->rn_more)
|
||||
{
|
||||
node->rn_status &= ~RES_REACHED_NODE;
|
||||
if (node->rn_why & RES_NODE_ORIGIN)
|
||||
|
|
@ -133,7 +133,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
|
|||
}
|
||||
}
|
||||
foundorigin = 0;
|
||||
for (node = nodeList; node != NULL; node=node->rn_more)
|
||||
for (node = nodeList; node != NULL; node = node->rn_more)
|
||||
{
|
||||
if ((node->rn_status & RES_REACHED_NODE) == 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -128,11 +128,11 @@ ResPrintDeviceList(fp, list)
|
|||
{
|
||||
if (list->rd_terminals[i] == NULL) continue;
|
||||
if (fp == stdout)
|
||||
TxPrintf("%c (%d,%d) ",termtype[i],
|
||||
TxPrintf("%c (%d,%d) ", termtype[i],
|
||||
list->rd_terminals[i]->rn_loc.p_x,
|
||||
list->rd_terminals[i]->rn_loc.p_y);
|
||||
else
|
||||
fprintf(fp, "%c (%d,%d) ",termtype[i],
|
||||
fprintf(fp, "%c (%d,%d) ", termtype[i],
|
||||
list->rd_terminals[i]->rn_loc.p_x,
|
||||
list->rd_terminals[i]->rn_loc.p_y);
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ enumerate:
|
|||
}
|
||||
else
|
||||
{
|
||||
resTopTile=BL(resTopTile);
|
||||
resTopTile = BL(resTopTile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -205,7 +205,7 @@ ResCheckConcavity(bot, top, tt)
|
|||
ylen = ypos - resWalkdown(bot, tt, xpos, ypos, NULL);
|
||||
if (xlen > ylen)
|
||||
{
|
||||
(void) resWalkdown(bot,tt,xpos,ypos,ResSplitX);
|
||||
(void) resWalkdown(bot, tt, xpos, ypos, ResSplitX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ int
|
|||
resWalkup(tile, tt, xpos, ypos, func)
|
||||
Tile *tile;
|
||||
TileType tt;
|
||||
int xpos,ypos;
|
||||
int xpos, ypos;
|
||||
Tile * (*func)();
|
||||
|
||||
{
|
||||
|
|
@ -443,7 +443,7 @@ ResSplitX(tile, x)
|
|||
Tile *tp = TiSplitX(tile, x);
|
||||
Tile *tp2;
|
||||
|
||||
TiSetBody(tp,tt);
|
||||
TiSetBody(tp, tt);
|
||||
/* check to see if we can combine with the tiles above or below us */
|
||||
tp2 = RT(tile);
|
||||
if (TiGetType(tp2) == tt && LEFT(tp2) == LEFT(tile) && RIGHT(tp2) == RIGHT(tile))
|
||||
|
|
|
|||
|
|
@ -29,23 +29,28 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResNewSDDevice -- called when a device is reached via a piece of
|
||||
* diffusion. (Devices reached via poly, i.e.
|
||||
* gates, are handled by ResEachTile.)
|
||||
* ResNewTermDevice --
|
||||
*
|
||||
* Results:none
|
||||
* Called when a device is reached via a type in the device's
|
||||
* terminal type list (e.g., diffusion, for MOSFETs). Note that
|
||||
* devices reached by the device type (e.g., poly, for MOSFETs)
|
||||
* are handled by ResEachTile.
|
||||
*
|
||||
* Side Effects: determines to which terminal (source or drain) node
|
||||
* is connected. Makes new node if node hasn't already been created .
|
||||
* Allocates breakpoint in current tile for device.
|
||||
* Results:
|
||||
* None
|
||||
*
|
||||
* Side Effects:
|
||||
* Determines to which terminal (source or drain) node is connected.
|
||||
* Makes new node if node hasn't already been created. Allocates
|
||||
* breakpoint in current tile for device.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||
ResNewTermDevice(tile, tp, n, xj, yj, direction, PendingList)
|
||||
Tile *tile, *tp;
|
||||
int xj, yj, direction;
|
||||
int n, xj, yj, direction;
|
||||
resNode **PendingList;
|
||||
{
|
||||
resNode *resptr = NULL;
|
||||
|
|
@ -97,9 +102,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
ResAddToQueue(resptr, PendingList);
|
||||
}
|
||||
if (resptr != NULL)
|
||||
{
|
||||
NEWBREAK(resptr, tile, xj, yj, NULL);
|
||||
}
|
||||
ResNewBreak(resptr, tile, xj, yj, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -149,7 +152,7 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
|
|||
resptr->rn_te = tcell;
|
||||
ResAddToQueue(resptr, PendingList);
|
||||
}
|
||||
NEWBREAK(resptr, tile, xj, yj, NULL);
|
||||
ResNewBreak(resptr, tile, xj, yj, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -207,10 +210,10 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
|
|||
junction->rj_nextjunction[1] = ri2->junctionList;
|
||||
ri2->junctionList = junction;
|
||||
|
||||
NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x,
|
||||
ResNewBreak(junction->rj_jnode, tile, junction->rj_loc.p_x,
|
||||
junction->rj_loc.p_y, NULL);
|
||||
|
||||
NEWBREAK(junction->rj_jnode,tp, junction->rj_loc.p_x,
|
||||
ResNewBreak(junction->rj_jnode, tp, junction->rj_loc.p_x,
|
||||
junction->rj_loc.p_y, NULL);
|
||||
|
||||
}
|
||||
|
|
|
|||
367
resis/ResMain.c
367
resis/ResMain.c
|
|
@ -40,8 +40,7 @@ resNode *resCurrentNode;
|
|||
int ResTileCount = 0; /* Number of tiles rn_status */
|
||||
extern ExtRegion *ResFirst();
|
||||
extern Tile *FindStartTile();
|
||||
extern int ResEachTile();
|
||||
TileTypeBitMask ResSDTypesBitMask;
|
||||
TileTypeBitMask ResTermTypesBitMask;
|
||||
TileTypeBitMask ResSubTypesBitMask;
|
||||
|
||||
extern HashTable ResNodeTable;
|
||||
|
|
@ -100,7 +99,7 @@ ResInitializeConn()
|
|||
*
|
||||
* ResGetReCell --
|
||||
*
|
||||
* This procedure makes sure that ResUse,ResDef
|
||||
* This procedure makes sure that ResUse, ResDef
|
||||
* have been properly initialized to refer to a cell definition
|
||||
* named "__RESIS__".
|
||||
*
|
||||
|
|
@ -161,7 +160,7 @@ ResDissolveContacts(contacts)
|
|||
|
||||
#ifdef PARANOID
|
||||
if (conttype == TT_SPACE)
|
||||
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
|
||||
TxError("Error in Contact Dissolving for %s \n", ResCurrentNode);
|
||||
#endif
|
||||
|
||||
/* Fill in details of the residue types for each contact type.
|
||||
|
|
@ -196,22 +195,38 @@ ResDissolveContacts(contacts)
|
|||
}
|
||||
}
|
||||
|
||||
/* Structure used by ResMakeDriverSinkPorts() to pass information to
|
||||
* ResAddPortFunc(). Contains a reference to a node, so that the
|
||||
* link between the tile and the node can be maintained, and the
|
||||
* driver or sink, which has the information about the position and
|
||||
* tile type of the connection.
|
||||
*/
|
||||
|
||||
typedef struct driversinkdata {
|
||||
ResExtNode *dsd_node;
|
||||
ResConnect *dsd_connect;
|
||||
} DriverSinkData;
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* ResMakePortBreakpoints --
|
||||
* ResMakeDriverSinkPorts --
|
||||
*
|
||||
* Search for nodes which are ports, and force them to be breakpoints
|
||||
* in the "resInfo" 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.
|
||||
* Search through the list of node drivers and sinks (connections up
|
||||
* and down in the hierarchy), and make sure this information is
|
||||
* copied to the resInfo record of the tile(s) found at the connection.
|
||||
*
|
||||
* Do the same thing for labels.
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds information to the resInfo clientData of tiles in def.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResMakePortBreakpoints(def)
|
||||
ResMakeDriverSinkPorts(def)
|
||||
CellDef *def;
|
||||
{
|
||||
Plane *plane;
|
||||
|
|
@ -220,21 +235,66 @@ ResMakePortBreakpoints(def)
|
|||
HashSearch hs;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||
ResConnect *rdriver, *rsink;
|
||||
DriverSinkData dsd;
|
||||
int ResAddPortFunc(); /* Forward Declaration */
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
|
||||
{
|
||||
node = (ResExtNode *)HashGetValue(entry);
|
||||
if (node->status & PORTNODE)
|
||||
|
||||
for (rdriver = node->drivepoints; rdriver; rdriver = rdriver->rc_next)
|
||||
{
|
||||
if (node->rs_ttype <= 0)
|
||||
if (rdriver->rc_type <= 0)
|
||||
{
|
||||
TxError("Warning: Label \"%s\" is unconnected.\n", node->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
rect = &(node->rs_bbox);
|
||||
rect = &(rdriver->rc_rect);
|
||||
|
||||
/* If label is on a contact, the contact has been dissolved. */
|
||||
/* Assume that the uppermost residue is the port. This may */
|
||||
/* not necessarily be the case. Could do a boundary scan on */
|
||||
/* each residue plane to see which side of the contact is */
|
||||
/* the internal connection in the def. . . */
|
||||
|
||||
if (DBIsContact(rdriver->rc_type))
|
||||
{
|
||||
TileType type;
|
||||
|
||||
DBFullResidueMask(rdriver->rc_type, &mask);
|
||||
for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--)
|
||||
if (TTMaskHasType(&mask, type))
|
||||
{
|
||||
plane = def->cd_planes[DBPlane(type)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TTMaskSetOnlyType(&mask, rdriver->rc_type);
|
||||
plane = def->cd_planes[DBPlane(rdriver->rc_type)];
|
||||
}
|
||||
|
||||
dsd.dsd_connect = rdriver;
|
||||
dsd.dsd_node = node;
|
||||
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
|
||||
ResAddPortFunc, (ClientData)&dsd);
|
||||
}
|
||||
|
||||
/* Process sink points in the same way */
|
||||
|
||||
for (rsink = node->sinkpoints; rsink; rsink = rsink->rc_next)
|
||||
{
|
||||
if (rsink->rc_type <= 0)
|
||||
{
|
||||
TxError("Warning: Label \"%s\" is unconnected.\n", node->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
rect = &(rsink->rc_rect);
|
||||
|
||||
/* Beware of zero-area ports */
|
||||
if (rect->r_xbot == rect->r_xtop)
|
||||
|
|
@ -254,11 +314,11 @@ ResMakePortBreakpoints(def)
|
|||
/* each residue plane to see which side of the contact is */
|
||||
/* the internal connection in the def. . . */
|
||||
|
||||
if (DBIsContact(node->rs_ttype))
|
||||
if (DBIsContact(rsink->rc_type))
|
||||
{
|
||||
TileType type;
|
||||
|
||||
DBFullResidueMask(node->rs_ttype, &mask);
|
||||
DBFullResidueMask(rsink->rc_type, &mask);
|
||||
for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--)
|
||||
if (TTMaskHasType(&mask, type))
|
||||
{
|
||||
|
|
@ -268,40 +328,122 @@ ResMakePortBreakpoints(def)
|
|||
}
|
||||
else
|
||||
{
|
||||
TTMaskSetOnlyType(&mask, node->rs_ttype);
|
||||
plane = def->cd_planes[DBPlane(node->rs_ttype)];
|
||||
TTMaskSetOnlyType(&mask, rsink->rc_type);
|
||||
plane = def->cd_planes[DBPlane(rsink->rc_type)];
|
||||
}
|
||||
|
||||
dsd.dsd_connect = rsink;
|
||||
dsd.dsd_node = node;
|
||||
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
|
||||
ResAddBreakpointFunc, (ClientData)node);
|
||||
ResAddPortFunc, (ClientData)&dsd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------
|
||||
*
|
||||
* ResMakeLabelBreakpoints --
|
||||
* ResAddPortFunc --
|
||||
*
|
||||
* Search for labels that are part of a node, and force them to be
|
||||
* breakpoints in the "resInfo" 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.
|
||||
* Add a portList entry to the "resInfo" structure of the tile. The
|
||||
* portList entry keeps a record of the area of overlap or abutment
|
||||
* of the port, as well as a pointer to the resNode.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0;
|
||||
*
|
||||
* Side effects:
|
||||
* Adds information to a tile's "resInfo" clientData.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResAddPortFunc(tile, dinfo, dsd)
|
||||
Tile *tile;
|
||||
TileType dinfo; /* (unused) */
|
||||
DriverSinkData *dsd; /* Data for driver or sink */
|
||||
{
|
||||
resPort *rp;
|
||||
resInfo *pX;
|
||||
Rect rect;
|
||||
ResConnect *connect;
|
||||
ResExtNode *node;
|
||||
|
||||
if (TiGetClient(tile) == CLIENTDEFAULT)
|
||||
return 0;
|
||||
|
||||
/* To simplify processing, if a split tile does not have TT_SPACE
|
||||
* on either side, then only the left side is processed.
|
||||
*/
|
||||
if (IsSplit(tile))
|
||||
if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE)
|
||||
if (dinfo & TT_SIDE)
|
||||
return 0;
|
||||
|
||||
node = dsd->dsd_node;
|
||||
connect = dsd->dsd_connect;
|
||||
|
||||
TiToRect(tile, &rect);
|
||||
|
||||
pX = (resInfo *)TiGetClient(tile);
|
||||
|
||||
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort)));
|
||||
rp->rp_nextPort = pX->portList;
|
||||
rp->rp_bbox = connect->rc_rect;
|
||||
rp->rp_loc = connect->rc_rect.r_ll;
|
||||
rp->rp_connect = connect;
|
||||
rp->rp_nodename = node->name;
|
||||
pX->portList = rp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Structure used by ResMakeLabelPorts() to pass information to
|
||||
* ResAddPortFunc(). Contains a reference to a node, so that the
|
||||
* link between the tile and the node can be maintained, and the
|
||||
* label, which has the information about the position and tile
|
||||
* type of the label.
|
||||
*/
|
||||
|
||||
typedef struct reslabeldata {
|
||||
ResExtNode *rld_node;
|
||||
Label *rld_label;
|
||||
ResConnect *rld_connect;
|
||||
} ResLabelData;
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* ResMakeLabelPorts --
|
||||
*
|
||||
* Search for labels that are part of a node, and add them to the
|
||||
* portList linked list in the "resInfo" 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.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Adds information to the resInfo clientData of tiles in def.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResMakeLabelBreakpoints(def, resisdata)
|
||||
ResMakeLabelPorts(def, resisdata)
|
||||
CellDef *def;
|
||||
ResisData *resisdata;
|
||||
{
|
||||
Plane *plane;
|
||||
Rect *rect;
|
||||
TileTypeBitMask mask;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResConnect *rdriver, *newsink;
|
||||
Label *slab;
|
||||
int ResAddBreakpointFunc(); /* Forward Declaration */
|
||||
ResLabelData rld;
|
||||
int ResAddLabelFunc(); /* Forward Declaration */
|
||||
|
||||
for (slab = def->cd_labels; slab != NULL; slab = slab->lab_next)
|
||||
{
|
||||
|
|
@ -312,20 +454,26 @@ ResMakeLabelBreakpoints(def, resisdata)
|
|||
entry = HashFind(&ResNodeTable, slab->lab_text);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
/* If the drivepoint position changes and the drivepoint is */
|
||||
/* in the "resisdata" record, then make sure the tile type */
|
||||
/* in "resisdata" gets changed to match. */
|
||||
/* If there is an existing drivepoint at this location, */
|
||||
/* then ignore it. */
|
||||
|
||||
if (resisdata->rg_devloc == &node->drivepoint)
|
||||
for (rdriver = node->drivepoints; rdriver; rdriver = rdriver->rc_next)
|
||||
{
|
||||
if (GEO_TOUCH(&slab->lab_rect, &rdriver->rc_rect))
|
||||
break;
|
||||
}
|
||||
if (rdriver != NULL) break;
|
||||
|
||||
/* Add a new sinkpoint to the node where the label is */
|
||||
newsink = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
newsink->rc_next = node->sinkpoints;
|
||||
node->sinkpoints = newsink;
|
||||
|
||||
if (GEO_ENCLOSE(resisdata->rg_devloc, &slab->lab_rect))
|
||||
resisdata->rg_ttype = slab->lab_type;
|
||||
|
||||
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;
|
||||
|
||||
rect = &(node->rs_bbox);
|
||||
newsink->rc_rect = slab->lab_rect;
|
||||
newsink->rc_type = slab->lab_type;
|
||||
|
||||
/* If label is on a contact, the contact has been dissolved. */
|
||||
/* Assume that the uppermost residue is the port. This may */
|
||||
|
|
@ -351,29 +499,44 @@ ResMakeLabelBreakpoints(def, resisdata)
|
|||
plane = def->cd_planes[DBPlane(slab->lab_type)];
|
||||
}
|
||||
|
||||
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
|
||||
ResAddBreakpointFunc, (ClientData)node);
|
||||
|
||||
rld.rld_node = node;
|
||||
rld.rld_label = slab;
|
||||
rld.rld_connect = newsink;
|
||||
(void) DBSrPaintArea((Tile *) NULL, plane, &newsink->rc_rect, &mask,
|
||||
ResAddLabelFunc, (ClientData)&rld);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------------
|
||||
*
|
||||
* ResAddBreakpointFunc --
|
||||
* ResAddLabelFunc --
|
||||
*
|
||||
* Add a breakpoint to the "resInfo" structure of the tile
|
||||
* Add a portList entry to the "resInfo" structure of the tile. The
|
||||
* portList entry keeps a record of the area of overlap or abutment
|
||||
* of the port, as well as a pointer to the resNode.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0;
|
||||
*
|
||||
* Side effects:
|
||||
* Adds information to a tile's "resInfo" clientData.
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResAddBreakpointFunc(tile, dinfo, node)
|
||||
Tile *tile;
|
||||
TileType dinfo; /* (unused) */
|
||||
ResExtNode *node;
|
||||
ResAddLabelFunc(tile, dinfo, rld)
|
||||
Tile *tile;
|
||||
TileType dinfo; /* (unused) */
|
||||
ResLabelData *rld; /* Label and node data */
|
||||
{
|
||||
resInfo *info;
|
||||
resPort *rp;
|
||||
resInfo *pX;
|
||||
Rect rect;
|
||||
Label *label;
|
||||
ResExtNode *node;
|
||||
ResConnect *connect;
|
||||
|
||||
if (TiGetClient(tile) == CLIENTDEFAULT)
|
||||
return 0;
|
||||
|
|
@ -386,12 +549,25 @@ ResAddBreakpointFunc(tile, dinfo, node)
|
|||
if (dinfo & TT_SIDE)
|
||||
return 0;
|
||||
|
||||
NEWPORT(node, tile);
|
||||
node = rld->rld_node;
|
||||
label = rld->rld_label;
|
||||
connect = rld->rld_connect;
|
||||
|
||||
TiToRect(tile, &rect);
|
||||
|
||||
pX = (resInfo *)TiGetClient(tile);
|
||||
|
||||
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort)));
|
||||
rp->rp_nextPort = pX->portList;
|
||||
rp->rp_bbox = label->lab_rect;
|
||||
rp->rp_loc = label->lab_rect.r_ll;
|
||||
rp->rp_connect = connect;
|
||||
rp->rp_nodename = node->name;
|
||||
pX->portList = rp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -522,8 +698,8 @@ ResFindNewContactTiles(contacts)
|
|||
|
||||
int
|
||||
ResProcessTiles(resisdata, origin)
|
||||
Point *origin;
|
||||
ResisData *resisdata;
|
||||
Point *origin;
|
||||
|
||||
{
|
||||
Tile *startTile;
|
||||
|
|
@ -541,7 +717,8 @@ ResProcessTiles(resisdata, origin)
|
|||
if (startTile == NULL)
|
||||
return 1;
|
||||
resCurrentNode = NULL;
|
||||
(void) ResEachTile(startTile, origin);
|
||||
ResStartTile(startTile, origin->p_x, origin->p_y);
|
||||
(void) ResEachTile(startTile);
|
||||
}
|
||||
#ifdef PARANOID
|
||||
else
|
||||
|
|
@ -578,7 +755,7 @@ ResProcessTiles(resisdata, origin)
|
|||
if ((ri->ri_status & RES_TILE_DONE) == 0)
|
||||
{
|
||||
resCurrentNode = resptr2;
|
||||
merged |= ResEachTile(tile, (Point *)NULL);
|
||||
merged |= ResEachTile(tile);
|
||||
}
|
||||
}
|
||||
rj->rj_status = TRUE;
|
||||
|
|
@ -604,7 +781,7 @@ ResProcessTiles(resisdata, origin)
|
|||
if (cp->cp_cnode[tilenum] == resptr2)
|
||||
{
|
||||
resCurrentNode = resptr2;
|
||||
merged |= ResEachTile(tile, (Point *)NULL);
|
||||
merged |= ResEachTile(tile);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -687,7 +864,7 @@ ResCalcPerimOverlap(tile, dev)
|
|||
}
|
||||
|
||||
/* right */
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
{
|
||||
if TTMaskHasType(omask, TiGetLeftType(tp))
|
||||
overlap += MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp));
|
||||
|
|
@ -701,7 +878,7 @@ ResCalcPerimOverlap(tile, dev)
|
|||
}
|
||||
|
||||
/* bottom */
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
{
|
||||
if TTMaskHasType(omask, TiGetTopType(tp))
|
||||
overlap += MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp));
|
||||
|
|
@ -1086,15 +1263,22 @@ ResExtractNet(node, resisdata, cellname)
|
|||
|
||||
/* Copy Paint */
|
||||
|
||||
/* If the node location is INFINITY, then use the rs_bbox */
|
||||
/* If the node location is INFINITY, then use the first drivepoint */
|
||||
|
||||
if ((node->location.p_x == INFINITY) || (node->location.p_y == INFINITY))
|
||||
{
|
||||
scx.scx_area.r_ll.p_x = node->rs_bbox.r_xbot;
|
||||
scx.scx_area.r_ll.p_y = node->rs_bbox.r_ybot;
|
||||
scx.scx_area.r_ur.p_x = node->rs_bbox.r_xtop;
|
||||
scx.scx_area.r_ur.p_y = node->rs_bbox.r_ytop;
|
||||
startpoint = node->drivepoint;
|
||||
ResConnect *rdriver = node->drivepoints;
|
||||
if (rdriver)
|
||||
{
|
||||
scx.scx_area.r_ll.p_x = rdriver->rc_rect.r_xbot - 2;
|
||||
scx.scx_area.r_ll.p_y = rdriver->rc_rect.r_ybot - 2;
|
||||
scx.scx_area.r_ur.p_x = rdriver->rc_rect.r_xtop + 2;
|
||||
scx.scx_area.r_ur.p_y = rdriver->rc_rect.r_ytop + 2;
|
||||
startpoint.p_x = (rdriver->rc_rect.r_xtop + rdriver->rc_rect.r_xbot) / 2;
|
||||
startpoint.p_y = (rdriver->rc_rect.r_ytop + rdriver->rc_rect.r_ybot) / 2;
|
||||
}
|
||||
else
|
||||
TxError("Internal error: Node location is set to infinity.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1117,13 +1301,40 @@ ResExtractNet(node, resisdata, cellname)
|
|||
DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect,
|
||||
SEL_DO_LABELS, ResUse);
|
||||
}
|
||||
else if (node->drivepoints)
|
||||
{
|
||||
/* Use the first valid drivepoint */
|
||||
ResConnect *drivepoint = node->drivepoints;
|
||||
while (drivepoint && (drivepoint->rc_type == TT_SPACE))
|
||||
drivepoint = drivepoint->rc_next;
|
||||
if (drivepoint)
|
||||
{
|
||||
TTMaskZero(&FirstTileMask);
|
||||
TTMaskSetMask(&FirstTileMask, &DBConnectTbl[drivepoint->rc_type]);
|
||||
|
||||
TTMaskZero(&ResSDTypesBitMask);
|
||||
DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect,
|
||||
SEL_DO_LABELS, ResUse);
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Node %s: Did not find the net layout at any drivepoint.\n",
|
||||
node->name);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TxError("Node %s: Did not find the net layout at node location (%d %d).\n",
|
||||
node->name, node->location.p_x, node->location.p_y);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TTMaskZero(&ResTermTypesBitMask);
|
||||
TTMaskZero(&ResSubTypesBitMask);
|
||||
|
||||
/* Add devices to ResUse from list in node */
|
||||
DevTiles = NULL;
|
||||
for (tptr = node->firstDev; tptr; tptr = tptr->nextDev)
|
||||
for (tptr = node->devices; tptr; tptr = tptr->nextDev)
|
||||
{
|
||||
int result;
|
||||
int i;
|
||||
|
|
@ -1155,13 +1366,13 @@ ResExtractNet(node, resisdata, cellname)
|
|||
TTMaskSetOnlyType(&tMask, thisDev->type);
|
||||
DBTreeSrTiles(&scx, &tMask, 0, resExpandDevFunc, (ClientData)thisDev);
|
||||
|
||||
/* If the device has source/drain types in a different plane than */
|
||||
/* the device identifier type, then add the source/drain types to */
|
||||
/* the mask ResSDTypesBitMask. */
|
||||
/* If the device has terminal types in a different plane than */
|
||||
/* the device identifier type, then add the terminal types to */
|
||||
/* the mask ResTermTypesBitMask. */
|
||||
|
||||
devptr = tptr->thisDev->rs_devptr;
|
||||
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
|
||||
TTMaskSetMask(&ResSDTypesBitMask, &devptr->exts_deviceSDTypes[i]);
|
||||
TTMaskSetMask(&ResTermTypesBitMask, &devptr->exts_deviceSDTypes[i]);
|
||||
|
||||
/* Add the substrate types to the mask ResSubTypesBitMask */
|
||||
TTMaskSetMask(&ResSubTypesBitMask, &devptr->exts_deviceSubstrateTypes);
|
||||
|
|
@ -1227,8 +1438,8 @@ ResExtractNet(node, resisdata, cellname)
|
|||
* cell.
|
||||
*/
|
||||
|
||||
ResMakePortBreakpoints(ResUse->cu_def);
|
||||
ResMakeLabelBreakpoints(ResUse->cu_def, resisdata);
|
||||
ResMakeDriverSinkPorts(ResUse->cu_def);
|
||||
ResMakeLabelPorts(ResUse->cu_def, resisdata);
|
||||
|
||||
/* Finish preprocessing. */
|
||||
|
||||
|
|
@ -1428,13 +1639,13 @@ FindStartTile(resisdata, SourcePoint)
|
|||
|
||||
if (workingPoint.p_x == LEFT(tile))
|
||||
{
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
if (TiGetRightType(tp) == resisdata->rg_ttype)
|
||||
return(tp);
|
||||
}
|
||||
else if (workingPoint.p_y == BOTTOM(tile))
|
||||
{
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
|
||||
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
||||
if (TiGetTopType(tp) == resisdata->rg_ttype)
|
||||
return(tp);
|
||||
}
|
||||
|
|
@ -1491,7 +1702,7 @@ FindStartTile(resisdata, SourcePoint)
|
|||
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
||||
{
|
||||
SourcePoint->p_x = LEFT(tile);
|
||||
SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) +
|
||||
SourcePoint->p_y = (MIN(TOP(tile), TOP(tp)) +
|
||||
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
|
||||
return(tp);
|
||||
}
|
||||
|
|
@ -1534,7 +1745,7 @@ FindStartTile(resisdata, SourcePoint)
|
|||
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
||||
{
|
||||
SourcePoint->p_y = TOP(tile);
|
||||
SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) +
|
||||
SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) +
|
||||
MAX(LEFT(tile), LEFT(tp))) >> 1;
|
||||
return(tp);
|
||||
}
|
||||
|
|
@ -1590,7 +1801,7 @@ FindStartTile(resisdata, SourcePoint)
|
|||
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
||||
{
|
||||
SourcePoint->p_x = LEFT(tile);
|
||||
SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) +
|
||||
SourcePoint->p_y = (MIN(TOP(tile), TOP(tp)) +
|
||||
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
|
||||
while (!StackEmpty(devStack))
|
||||
{
|
||||
|
|
@ -1658,7 +1869,7 @@ FindStartTile(resisdata, SourcePoint)
|
|||
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
|
||||
{
|
||||
SourcePoint->p_y = TOP(tile);
|
||||
SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) +
|
||||
SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) +
|
||||
MAX(LEFT(tile), LEFT(tp))) >> 1;
|
||||
while (!StackEmpty(devStack))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -687,7 +687,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
}
|
||||
else
|
||||
{
|
||||
deltay=0;
|
||||
deltay = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -701,15 +701,15 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
|||
{
|
||||
if (p2->br_crect->r_ll.p_y > p1->br_loc.p_y)
|
||||
{
|
||||
deltay = MIN(deltay,p2->br_crect->r_ll.p_y - p1->br_loc.p_y);
|
||||
deltay = MIN(deltay, p2->br_crect->r_ll.p_y - p1->br_loc.p_y);
|
||||
}
|
||||
else if (p2->br_crect->r_ur.p_y < p1->br_loc.p_y)
|
||||
{
|
||||
deltay = MIN(deltay,p1->br_loc.p_y - p2->br_crect->r_ur.p_y);
|
||||
deltay = MIN(deltay, p1->br_loc.p_y - p2->br_crect->r_ur.p_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
deltay=0;
|
||||
deltay = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -887,7 +887,7 @@ ResDoContacts(contact, nodes, resList)
|
|||
Tile *tile = contact->cp_tile[tilenum];
|
||||
|
||||
contact->cp_cnode[tilenum] = resptr;
|
||||
NEWBREAK(resptr, tile, contact->cp_center.p_x,
|
||||
ResNewBreak(resptr, tile, contact->cp_center.p_x,
|
||||
contact->cp_center.p_y, &contact->cp_rect);
|
||||
}
|
||||
}
|
||||
|
|
@ -936,7 +936,7 @@ ResDoContacts(contact, nodes, resList)
|
|||
ccell->ce_thisc = contact;
|
||||
|
||||
contact->cp_cnode[tilenum] = resptr;
|
||||
NEWBREAK(resptr, tile, contact->cp_center.p_x,
|
||||
ResNewBreak(resptr, tile, contact->cp_center.p_x,
|
||||
contact->cp_center.p_y, &contact->cp_rect);
|
||||
|
||||
/* Add resistors here */
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ ResFixParallel(elimResis, newResis)
|
|||
* ResSeriesCheck -- for nodes with no devices, sees if a series
|
||||
* or loop combination is possible.
|
||||
*
|
||||
* Results: returns SINGLE,LOOP,or SERIES if succesful.
|
||||
* Results: returns SINGLE, LOOP, or SERIES if succesful.
|
||||
*
|
||||
* Side Effects: may delete some nodes and resistors.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
|
|||
char *nodename;
|
||||
|
||||
{
|
||||
int nodenum=0;
|
||||
int nodenum = 0;
|
||||
char newname[MAXNAME];
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
|
|
@ -261,7 +261,7 @@ ResPrintExtNode(outextfile, nodelist, node)
|
|||
{
|
||||
if (snode->rn_name == NULL)
|
||||
{
|
||||
(void)sprintf(tmpname,"%s",nodename);
|
||||
(void)sprintf(tmpname, "%s", nodename);
|
||||
|
||||
cp = tmpname + strlen(tmpname) - 1;
|
||||
if (*cp == '!' || *cp == '#') *cp = '\0';
|
||||
|
|
@ -342,13 +342,13 @@ ResPrintStats(resisdata, name)
|
|||
nodes = 0;
|
||||
resistors = 0;
|
||||
totalnets++;
|
||||
for (node = ResNodeList; node != NULL; node=node->rn_more)
|
||||
for (node = ResNodeList; node != NULL; node = node->rn_more)
|
||||
|
||||
{
|
||||
nodes++;
|
||||
totalnodes++;
|
||||
}
|
||||
for (res = ResResList; res != NULL; res=res->rr_nextResistor)
|
||||
for (res = ResResList; res != NULL; res = res->rr_nextResistor)
|
||||
{
|
||||
resistors++;
|
||||
totalresistors++;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,24 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#define PORT_URY 6
|
||||
#define PORT_TYPE 7
|
||||
|
||||
#define USE_DEF_NAME 1
|
||||
#define USE_ID_NAME 2
|
||||
#define USE_TRANSFORM_A 3
|
||||
#define USE_TRANSFORM_B 4
|
||||
#define USE_TRANSFORM_C 5
|
||||
#define USE_TRANSFORM_D 6
|
||||
#define USE_TRANSFORM_E 7
|
||||
#define USE_TRANSFORM_F 8
|
||||
|
||||
/* Note that "connect" lines may repeat these six entries up to argc */
|
||||
#define CONNECT_LLX 1
|
||||
#define CONNECT_LLY 2
|
||||
#define CONNECT_URX 3
|
||||
#define CONNECT_URY 4
|
||||
#define CONNECT_TYPE 5
|
||||
#define CONNECT_UP_NAME 6
|
||||
#define CONNECT_DOWN_NAME 7
|
||||
|
||||
#define MAXDIGIT 20
|
||||
|
||||
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
|
||||
|
|
@ -91,11 +109,18 @@ ResFixPoint *ResFixList;
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadExt--
|
||||
* ResReadExt --
|
||||
*
|
||||
* Results: returns 0 if ext file is correct, 1 if not.
|
||||
* Read a .ext file for resistance extraction. Extresist does not use
|
||||
* the .ext file reader in extflat/EFread.c because it takes only a
|
||||
* small amount of information from the .ext file, mainly to keep a
|
||||
* list of nets and net names, devices and their terminals and
|
||||
* connections, and subcell connections. However, it does make use
|
||||
* of the line parser and tokenizer in extflat.
|
||||
*
|
||||
* Side Effects:Reads in ExtTable and makes a hash table of nodes.
|
||||
* Results: Returns 0 if ext file is correct, 1 if not.
|
||||
*
|
||||
* Side Effects: Creates lists of nodes and devices for extresist.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
@ -107,8 +132,11 @@ ResReadExt(CellDef *def)
|
|||
int result, locresult;
|
||||
int argc, n, size = 0;
|
||||
FILE *fp;
|
||||
CellDef *dbdef;
|
||||
CellDef *dbdef, *parent;
|
||||
CellUse *use;
|
||||
ResExtNode *curnode;
|
||||
HashTable parentHash;
|
||||
HashEntry *he;
|
||||
|
||||
/* Search for the .ext file in the same way that efReadDef() does. */
|
||||
|
||||
|
|
@ -142,7 +170,10 @@ ResReadExt(CellDef *def)
|
|||
}
|
||||
|
||||
/* We don't care about most tokens, only DEVICE, NODE, PORT,
|
||||
* and SUBSTRATE; and MERGE is used to locate drive points.
|
||||
* and SUBSTRATE; and CONNECT is used to locate sink points.
|
||||
* Note that MERGE is not useful here, as it may implicitly
|
||||
* merge nets in the cell, which is useful for netlisting but
|
||||
* not for annotating the extraction file.
|
||||
*/
|
||||
switch (keyTable[n].k_key)
|
||||
{
|
||||
|
|
@ -161,17 +192,16 @@ ResReadExt(CellDef *def)
|
|||
case FET:
|
||||
locresult = ResReadFET(argc, argv);
|
||||
break;
|
||||
case MERGE:
|
||||
/* To be completed */
|
||||
/* ResReadDrivePoint(argc, argv); */
|
||||
case CONNECT:
|
||||
locresult = ResReadConnectPoint(def, argc, argv);
|
||||
break;
|
||||
case PORT:
|
||||
locresult = ResReadPort(argc, argv);
|
||||
break;
|
||||
case NODE:
|
||||
case SUBSTRATE:
|
||||
curnode = ResReadNode(argc, argv);
|
||||
break;
|
||||
case PORT:
|
||||
locresult = ResReadPort(argc, argv);
|
||||
break;
|
||||
case ATTR:
|
||||
locresult = ResReadAttribute(curnode, argc, argv);
|
||||
break;
|
||||
|
|
@ -184,9 +214,290 @@ ResReadExt(CellDef *def)
|
|||
if (locresult == 1) result = 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/* Find all the parent CellDefs of "def" and read the .ext file of
|
||||
* each one to find where connections are made to this cell from
|
||||
* parent cells. Place drive points at each connection point.
|
||||
*/
|
||||
HashInit(&parentHash, 32, HT_STRINGKEYS);
|
||||
|
||||
for (use = def->cd_parents; use; use = use->cu_nextuse)
|
||||
{
|
||||
if ((parent = use->cu_parent) == NULL) continue;
|
||||
if (parent->cd_flags & CDINTERNAL) continue;
|
||||
he = HashFind(&parentHash, parent->cd_name);
|
||||
if ((CellDef *)HashGetValue(he) == NULL)
|
||||
{
|
||||
/* Mark parent def as being visited */
|
||||
HashSetValue(he, (char *)parent);
|
||||
/* Read connection information from the parent's .ext file */
|
||||
ResReadParentExt(parent, def);
|
||||
}
|
||||
}
|
||||
HashKill(&parentHash);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadUse --
|
||||
*
|
||||
* Read a "use" statement from the .ext file of a parent CellDef of
|
||||
* the current def being extracted. If the use is a use of the
|
||||
* current def, then save the use name and its transform in the
|
||||
* hash table so that later "connect" statements can be translated
|
||||
* into the coordinate system of the current cell def.
|
||||
*
|
||||
* Results:
|
||||
* 1 if something went wrong with the parsing, 0 otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* May add to the hash table.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadUse(CellDef *def,
|
||||
int argc,
|
||||
char *argv[],
|
||||
HashTable *useHash)
|
||||
{
|
||||
char *defname, *useid;
|
||||
Transform *tinv, t;
|
||||
HashEntry *he;
|
||||
|
||||
defname = argv[USE_DEF_NAME];
|
||||
|
||||
if (strcmp(defname, def->cd_name)) return 0; /* Not my use */
|
||||
|
||||
useid = argv[USE_ID_NAME];
|
||||
|
||||
he = HashFind(useHash, useid);
|
||||
|
||||
t.t_a = atoi(argv[USE_TRANSFORM_A]);
|
||||
t.t_b = atoi(argv[USE_TRANSFORM_B]);
|
||||
t.t_c = atoi(argv[USE_TRANSFORM_C]);
|
||||
t.t_d = atoi(argv[USE_TRANSFORM_D]);
|
||||
t.t_e = atoi(argv[USE_TRANSFORM_E]);
|
||||
t.t_f = atoi(argv[USE_TRANSFORM_F]);
|
||||
|
||||
tinv = (Transform *)mallocMagic(sizeof(Transform));
|
||||
GeoInvertTrans(&t, tinv);
|
||||
|
||||
HashSetValue(he, (char *)tinv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadDrivePoint --
|
||||
*
|
||||
* Read a "connect" statement from the .ext file of a parent CellDef
|
||||
* of the current def being extracted. If the connection is made to
|
||||
* a use of the current def, then translate the area of the connection
|
||||
* into the current def, and mark the connection as a drive point of
|
||||
* def.
|
||||
*
|
||||
* Results:
|
||||
* 1 if something went wrong with the parsing, 0 otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* May add information to the node list of def.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadDrivePoint(CellDef *def,
|
||||
int argc,
|
||||
char *argv[],
|
||||
HashTable *useHash)
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResConnect *newdriver;
|
||||
int pNum;
|
||||
TileType ttype;
|
||||
Transform *t;
|
||||
Rect r;
|
||||
char *hierptr, *useid, *qptr, *downname;
|
||||
|
||||
/* Only handle entries that are in the use ID hash table */
|
||||
|
||||
useid = argv[CONNECT_DOWN_NAME];
|
||||
if (*useid == '"') useid++;
|
||||
hierptr = strchr(useid, '/');
|
||||
if (hierptr != NULL) *hierptr = '\0';
|
||||
qptr = strrchr(useid, '"');
|
||||
if (qptr != NULL) *qptr = '\0';
|
||||
if (hierptr != NULL)
|
||||
downname = hierptr + 1;
|
||||
else
|
||||
downname = useid; /* This is probably invalid */
|
||||
|
||||
entry = HashFind(useHash, useid);
|
||||
if ((t = (Transform *)HashGetValue(entry)) == NULL) return 0;
|
||||
|
||||
/* Check for the given tile type */
|
||||
ttype = DBTechNoisyNameType(argv[CONNECT_TYPE]);
|
||||
|
||||
if (ttype == -1)
|
||||
{
|
||||
TxError("Bad tile type name \"%s\" in .ext file for node %s\n",
|
||||
argv[CONNECT_TYPE], argv[CONNECT_UP_NAME]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Look up the node name */
|
||||
if (strcmp(downname, "None"))
|
||||
{
|
||||
entry = HashLookOnly(&ResNodeTable, downname);
|
||||
if (entry != NULL)
|
||||
node = (ResExtNode *)HashGetValue(entry);
|
||||
else
|
||||
{
|
||||
TxError("Unknown node name \"%s\" in .ext file connect entry\n",
|
||||
downname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate new drivepoint entry */
|
||||
|
||||
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
|
||||
r.r_xbot = atoi(argv[CONNECT_LLX]);
|
||||
r.r_ybot = atoi(argv[CONNECT_LLY]);
|
||||
r.r_xtop = atoi(argv[CONNECT_URX]);
|
||||
r.r_ytop = atoi(argv[CONNECT_URY]);
|
||||
|
||||
/* Translate the connection position from the parent to the
|
||||
* current cell def.
|
||||
*/
|
||||
GeoTransRect(t, &r, &newdriver->rc_rect);
|
||||
|
||||
newdriver->rc_type = ttype;
|
||||
newdriver->rc_node = (resNode *)NULL;
|
||||
|
||||
newdriver->rc_next = node->drivepoints;
|
||||
node->drivepoints = newdriver;
|
||||
node->status |= FORCE | DRIVELOC;
|
||||
|
||||
/* XXX Diagnostic XXX */
|
||||
TxPrintf("Added driver at %d %d %d %d\n",
|
||||
newdriver->rc_rect.r_xbot, newdriver->rc_rect.r_ybot,
|
||||
newdriver->rc_rect.r_xtop, newdriver->rc_rect.r_ytop);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadParentExt --
|
||||
*
|
||||
* Read a .ext file for a parent cell of the cell being extracted.
|
||||
* Each .ext file contains a list of connection points into its
|
||||
* subcells. However, no .ext file has information about how a
|
||||
* parent cell connects to it; the exact connection may depend on
|
||||
* the layout, and may or may not coincide with marked ports.
|
||||
* Except for the top level cell, for which only marked ports can
|
||||
* be used to guess at intended points of connection, every subcell
|
||||
* can query its parents to find exact points of connection.
|
||||
*
|
||||
* Results: Returns 0 if ext file is correct, 1 if not.
|
||||
*
|
||||
* Side Effects: Creates lists of connection points for extresist.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadParentExt(CellDef *parent,
|
||||
CellDef *def)
|
||||
{
|
||||
char *line = NULL, *argv[128];
|
||||
int result, locresult;
|
||||
int argc, n, size = 0;
|
||||
FILE *fp;
|
||||
CellDef *dbdef;
|
||||
ResExtNode *curnode;
|
||||
HashTable useHash;
|
||||
HashEntry *he;
|
||||
HashSearch hs;
|
||||
|
||||
/* Search for the .ext file in the same way that efReadDef() does. */
|
||||
|
||||
fp = ExtFileOpen(parent, (char *)NULL, "r", (char **)NULL);
|
||||
if (fp == NULL)
|
||||
{
|
||||
TxError("Cannot open file %s%s\n", parent->cd_name, ".ext");
|
||||
return 1;
|
||||
}
|
||||
|
||||
HashInit(&useHash, 32, HT_STRINGKEYS);
|
||||
|
||||
/* Read in the file. Makes use of various functions
|
||||
* from extflat, mostly in EFread.c.
|
||||
*/
|
||||
|
||||
EFSaveLocs = FALSE;
|
||||
efReadLineNum = 0;
|
||||
result = 0;
|
||||
|
||||
while ((argc = efReadLine(&line, &size, fp, argv)) >= 0)
|
||||
{
|
||||
n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]);
|
||||
if (n < 0)
|
||||
{
|
||||
efReadError("Unrecognized token \"%s\" (ignored)\n", argv[0]);
|
||||
continue;
|
||||
}
|
||||
if (argc < keyTable[n].k_mintokens)
|
||||
{
|
||||
efReadError("Not enough tokens for %s line\n", argv[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* When reading a parent .ext file to find connections to
|
||||
* the cell being extracted by "extresist", we only care
|
||||
* about CONNECT lines, and USE lines so that we can
|
||||
* translate the connection points into the current cell def.
|
||||
*
|
||||
* Note: This method depends on the .ext file format having
|
||||
* all "use" lines before "connect" lines.
|
||||
*/
|
||||
switch (keyTable[n].k_key)
|
||||
{
|
||||
case USE:
|
||||
locresult = ResReadUse(def, argc, argv, &useHash);
|
||||
break;
|
||||
case CONNECT:
|
||||
locresult = ResReadDrivePoint(def, argc, argv, &useHash);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (locresult == 1) result = 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
HashStartSearch(&hs);
|
||||
while ((he = HashNext(&useHash, &hs)))
|
||||
{
|
||||
if (HashGetValue(he) != NULL)
|
||||
{
|
||||
freeMagic(HashGetValue(he)); /* Free the allocated tranform */
|
||||
HashSetValue(he, (ClientData)NULL);
|
||||
}
|
||||
}
|
||||
HashKill(&useHash);
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
|
|
@ -213,14 +524,7 @@ ResReadNode(int argc, char *argv[])
|
|||
|
||||
node->location.p_x = atoi(argv[NODES_NODEX]);
|
||||
node->location.p_y = atoi(argv[NODES_NODEY]);
|
||||
|
||||
/* If this node was previously read as a port, then don't change the
|
||||
* node type, which is tracking the type at the drivepoint.
|
||||
*/
|
||||
if (!(node->status & PORTNODE))
|
||||
{
|
||||
node->type = DBTechNameType(argv[NODES_NODETYPE]);
|
||||
}
|
||||
node->type = DBTechNameType(argv[NODES_NODETYPE]);
|
||||
|
||||
if (node->type == -1)
|
||||
{
|
||||
|
|
@ -230,6 +534,82 @@ ResReadNode(int argc, char *argv[])
|
|||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResReadConnectPoint-- Reads in a "connect" statement from the .ext file
|
||||
* and sets node records accordingly to mark the node as a connection
|
||||
* point. There is a use (instance) name associated with each connection,
|
||||
* which is unused for finding connection points to subcells; we
|
||||
* don't care what the subcell is, only that there is a connection at
|
||||
* a point on a net in this cell that should be recorded and never
|
||||
* optimized out.
|
||||
*
|
||||
* Results: 0 if successful and 1 otherwise.
|
||||
*
|
||||
* Side Effects: see above
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResReadConnectPoint(CellDef *def,
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResConnect *newsink;
|
||||
int pNum;
|
||||
TileType ttype;
|
||||
|
||||
/* Check for the given tile type */
|
||||
ttype = DBTechNoisyNameType(argv[CONNECT_TYPE]);
|
||||
|
||||
if (ttype == -1)
|
||||
{
|
||||
TxError("Bad tile type name \"%s\" in .ext file for node %s\n",
|
||||
argv[CONNECT_TYPE], argv[CONNECT_UP_NAME]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Look up the node name */
|
||||
if (strcmp(argv[CONNECT_UP_NAME], "None"))
|
||||
{
|
||||
entry = HashLookOnly(&ResNodeTable, argv[CONNECT_UP_NAME]);
|
||||
if (entry != NULL)
|
||||
node = (ResExtNode *)HashGetValue(entry);
|
||||
else
|
||||
{
|
||||
TxError("Unknown node name \"%s\" in .ext file connect entry\n",
|
||||
argv[CONNECT_UP_NAME]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate new sinkpoint entry */
|
||||
|
||||
newsink = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
|
||||
newsink->rc_rect.r_xbot = atoi(argv[CONNECT_LLX]);
|
||||
newsink->rc_rect.r_ybot = atoi(argv[CONNECT_LLY]);
|
||||
newsink->rc_rect.r_xtop = atoi(argv[CONNECT_URX]);
|
||||
newsink->rc_rect.r_ytop = atoi(argv[CONNECT_URY]);
|
||||
newsink->rc_type = ttype;
|
||||
newsink->rc_node = (resNode *)NULL;
|
||||
|
||||
newsink->rc_next = node->sinkpoints;
|
||||
node->sinkpoints = newsink;
|
||||
node->status |= FORCE | DRIVELOC;
|
||||
|
||||
/* XXX Diagnostic XXX */
|
||||
TxPrintf("Added sink at %d %d %d %d\n", newsink->rc_rect.r_xbot,
|
||||
newsink->rc_rect.r_ybot, newsink->rc_rect.r_xtop,
|
||||
newsink->rc_rect.r_ytop);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -240,6 +620,13 @@ ResReadNode(int argc, char *argv[])
|
|||
*
|
||||
* Side Effects: see above
|
||||
*
|
||||
* NOTE: The use of "port" to mark drive points is restricted to top
|
||||
* level cells, because no other information is available about how the
|
||||
* cell connects to a parent cell. For every cell other than the top
|
||||
* level, the "connect" statements are used to find the actual locations
|
||||
* where signals connect between cells through abutting or overlapping
|
||||
* material.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -249,22 +636,30 @@ ResReadPort(int argc,
|
|||
{
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResConnect *newdriver;
|
||||
|
||||
entry = HashFind(&ResNodeTable, argv[PORT_NAME]);
|
||||
node = ResExtInitNode(entry);
|
||||
|
||||
node->drivepoint.p_x = atoi(argv[PORT_LLX]);
|
||||
node->drivepoint.p_y = atoi(argv[PORT_LLY]);
|
||||
node->status |= FORCE;
|
||||
/* To do: Check for multiple ports on a net; each port needs its
|
||||
* own drivepoint.
|
||||
*/
|
||||
node->status |= DRIVELOC | PORTNODE;
|
||||
node->rs_bbox.r_ll = node->drivepoint;
|
||||
node->rs_bbox.r_ur.p_x = atoi(argv[PORT_URX]);
|
||||
node->rs_bbox.r_ur.p_y = atoi(argv[PORT_URY]);
|
||||
node->rs_ttype = DBTechNoisyNameType(argv[PORT_TYPE]);
|
||||
node->type = node->rs_ttype;
|
||||
/* Generate new drivepoint entry */
|
||||
|
||||
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
|
||||
newdriver->rc_rect.r_xbot = atoi(argv[PORT_LLX]);
|
||||
newdriver->rc_rect.r_ybot = atoi(argv[PORT_LLY]);
|
||||
newdriver->rc_rect.r_xtop = atoi(argv[PORT_URX]);
|
||||
newdriver->rc_rect.r_ytop = atoi(argv[PORT_URY]);
|
||||
newdriver->rc_type = DBTechNoisyNameType(argv[PORT_TYPE]);
|
||||
newdriver->rc_node = (resNode *)NULL;
|
||||
|
||||
newdriver->rc_next = node->drivepoints;
|
||||
node->drivepoints = newdriver;
|
||||
node->status |= FORCE | DRIVELOC | PORTNODE;
|
||||
|
||||
/* XXX Diagnostic XXX */
|
||||
TxPrintf("Added port at %d %d %d %d\n",
|
||||
newdriver->rc_rect.r_xbot, newdriver->rc_rect.r_ybot,
|
||||
newdriver->rc_rect.r_xtop, newdriver->rc_rect.r_ytop);
|
||||
|
||||
if (node->type == -1)
|
||||
{
|
||||
|
|
@ -273,6 +668,7 @@ ResReadPort(int argc,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -287,7 +683,7 @@ ResReadPort(int argc,
|
|||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Allocates memory for a devPtr, adds to the node's firstDev linked
|
||||
* Allocates memory for a devPtr, adds to the node's "devices" linked
|
||||
* list.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
|
|
@ -302,8 +698,8 @@ ResNodeAddDevice(ResExtNode *node,
|
|||
|
||||
tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
|
||||
tptr->thisDev = device;
|
||||
tptr->nextDev = node->firstDev;
|
||||
node->firstDev = tptr;
|
||||
tptr->nextDev = node->devices;
|
||||
node->devices = tptr;
|
||||
tptr->terminal = termtype;
|
||||
}
|
||||
|
||||
|
|
@ -628,10 +1024,22 @@ ResReadAttribute(ResExtNode *node,
|
|||
else if (strncmp(avalue, "res:drive", 9) == 0 &&
|
||||
(ResOptionsFlags & ResOpt_Signal))
|
||||
{
|
||||
node->drivepoint.p_x = atoi(argv[RES_EXT_ATTR_X]);
|
||||
node->drivepoint.p_y = atoi(argv[RES_EXT_ATTR_Y]);
|
||||
node->rs_ttype = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
|
||||
ResConnect *newdriver;
|
||||
|
||||
/* Generate new drivepoint entry */
|
||||
|
||||
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
|
||||
node->status |= DRIVELOC;
|
||||
newdriver->rc_rect.r_xbot = atoi(argv[RES_EXT_ATTR_X]);
|
||||
newdriver->rc_rect.r_ybot = atoi(argv[RES_EXT_ATTR_Y]);
|
||||
newdriver->rc_rect.r_xtop = atoi(argv[RES_EXT_ATTR_X]);
|
||||
newdriver->rc_rect.r_ytop = atoi(argv[RES_EXT_ATTR_Y]);
|
||||
newdriver->rc_type = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
|
||||
newdriver->rc_node = (resNode *)NULL;
|
||||
|
||||
newdriver->rc_next = node->drivepoints;
|
||||
node->drivepoints = newdriver;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -668,11 +1076,11 @@ ResExtInitNode(entry)
|
|||
node->cap_couple = 0;
|
||||
node->resistance = 0;
|
||||
node->type = 0;
|
||||
node->firstDev = NULL;
|
||||
node->devices = NULL;
|
||||
node->name = entry->h_key.h_name;
|
||||
node->oldname = NULL;
|
||||
node->drivepoint.p_x = INFINITY;
|
||||
node->drivepoint.p_y = INFINITY;
|
||||
node->drivepoints = NULL;
|
||||
node->sinkpoints = NULL;
|
||||
node->location.p_x = INFINITY;
|
||||
node->location.p_y = INFINITY;
|
||||
}
|
||||
|
|
|
|||
299
resis/ResRex.c
299
resis/ResRex.c
|
|
@ -90,6 +90,7 @@ ExtResisForDef(celldef, resisdata)
|
|||
HashSearch hs;
|
||||
HashEntry *entry;
|
||||
devPtr *tptr, *oldtptr;
|
||||
ResConnect *sptr, *snext;
|
||||
ResExtNode *node;
|
||||
int result, idx;
|
||||
char *devname;
|
||||
|
|
@ -137,8 +138,8 @@ ExtResisForDef(celldef, resisdata)
|
|||
HashStartSearch(&hs);
|
||||
while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
|
||||
{
|
||||
node=(ResExtNode *) HashGetValue(entry);
|
||||
tptr = node->firstDev;
|
||||
node = (ResExtNode *) HashGetValue(entry);
|
||||
tptr = node->devices;
|
||||
if (node == NULL)
|
||||
{
|
||||
TxError("Error: NULL Hash entry!\n");
|
||||
|
|
@ -150,6 +151,18 @@ ExtResisForDef(celldef, resisdata)
|
|||
tptr = tptr->nextDev;
|
||||
freeMagic((char *)oldtptr);
|
||||
}
|
||||
for (sptr = node->drivepoints; sptr; )
|
||||
{
|
||||
snext = sptr->rc_next;
|
||||
freeMagic((char *)sptr);
|
||||
sptr = snext;
|
||||
}
|
||||
for (sptr = node->sinkpoints; sptr; )
|
||||
{
|
||||
snext = sptr->rc_next;
|
||||
freeMagic((char *)sptr);
|
||||
sptr = snext;
|
||||
}
|
||||
freeMagic((char *) node);
|
||||
}
|
||||
HashKill(&ResNodeTable);
|
||||
|
|
@ -749,6 +762,7 @@ resPortFunc(scx, lab, tpath, result)
|
|||
Point portloc;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResConnect *newdriver;
|
||||
|
||||
// Ignore the top level cell
|
||||
if (scx->scx_use->cu_id == NULL) return 0;
|
||||
|
|
@ -803,12 +817,15 @@ resPortFunc(scx, lab, tpath, result)
|
|||
/* Digital outputs are drivers */
|
||||
if (pclass == PORT_CLASS_OUTPUT) node->status |= FORCE;
|
||||
|
||||
node->drivepoint = portloc;
|
||||
/* Create new node drivepoint */
|
||||
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
|
||||
newdriver->rc_type = lab->lab_type;
|
||||
newdriver->rc_rect = r;
|
||||
newdriver->rc_next = node->drivepoints;
|
||||
node->drivepoints = newdriver;
|
||||
|
||||
node->status |= DRIVELOC | PORTNODE;
|
||||
node->rs_bbox = r;
|
||||
node->location = portloc;
|
||||
node->rs_ttype = lab->lab_type;
|
||||
node->type = lab->lab_type;
|
||||
|
||||
*result = 0;
|
||||
freeMagic(nodename);
|
||||
|
|
@ -884,33 +901,16 @@ int
|
|||
ResCheckPorts(cellDef)
|
||||
CellDef *cellDef;
|
||||
{
|
||||
Point portloc;
|
||||
Label *lab;
|
||||
HashEntry *entry;
|
||||
ResExtNode *node;
|
||||
ResConnect *newdriver;
|
||||
int result = 1;
|
||||
|
||||
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
if (lab->lab_flags & PORT_DIR_MASK)
|
||||
{
|
||||
/* Get drivepoint from the port connection direction(s) */
|
||||
/* NOTE: This is not rigorous! */
|
||||
|
||||
if (lab->lab_flags & (PORT_DIR_NORTH | PORT_DIR_SOUTH))
|
||||
portloc.p_x = (lab->lab_rect.r_xbot + lab->lab_rect.r_xtop) >> 1;
|
||||
else if (lab->lab_flags & (PORT_DIR_EAST | PORT_DIR_WEST))
|
||||
portloc.p_y = (lab->lab_rect.r_ybot + lab->lab_rect.r_ytop) >> 1;
|
||||
|
||||
if (lab->lab_flags & PORT_DIR_NORTH)
|
||||
portloc.p_y = lab->lab_rect.r_ytop;
|
||||
if (lab->lab_flags & PORT_DIR_SOUTH)
|
||||
portloc.p_y = lab->lab_rect.r_ybot;
|
||||
if (lab->lab_flags & PORT_DIR_EAST)
|
||||
portloc.p_x = lab->lab_rect.r_xtop;
|
||||
if (lab->lab_flags & PORT_DIR_WEST)
|
||||
portloc.p_x = lab->lab_rect.r_xbot;
|
||||
|
||||
entry = HashFind(&ResNodeTable, lab->lab_text);
|
||||
result = 0;
|
||||
if ((node = (ResExtNode *) HashGetValue(entry)) != NULL)
|
||||
|
|
@ -919,9 +919,9 @@ ResCheckPorts(cellDef)
|
|||
lab->lab_text);
|
||||
TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
node->location.p_x, node->location.p_y,
|
||||
portloc.p_x, portloc.p_y);
|
||||
lab->lab_rect.r_xbot, lab->lab_rect.r_ybot);
|
||||
TxFlush();
|
||||
node->drivepoint = portloc;
|
||||
|
||||
node->status |= FORCE;
|
||||
}
|
||||
else
|
||||
|
|
@ -934,16 +934,20 @@ ResCheckPorts(cellDef)
|
|||
TxPrintf("Port: name = %s is new node %p\n",
|
||||
lab->lab_text, (void *)node);
|
||||
TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n",
|
||||
portloc.p_x, portloc.p_y,
|
||||
portloc.p_x, portloc.p_y);
|
||||
node->location = portloc;
|
||||
node->drivepoint = node->location;
|
||||
lab->lab_rect.r_xbot, lab->lab_rect.r_ybot,
|
||||
lab->lab_rect.r_xtop, lab->lab_rect.r_ytop);
|
||||
TxFlush();
|
||||
|
||||
node->status |= REDUNDANT;
|
||||
}
|
||||
|
||||
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
|
||||
newdriver->rc_rect = lab->lab_rect;
|
||||
newdriver->rc_type = lab->lab_type;
|
||||
newdriver->rc_next = node->drivepoints;
|
||||
node->drivepoints = newdriver;
|
||||
|
||||
node->status |= DRIVELOC | PORTNODE;
|
||||
node->rs_bbox = lab->lab_rect;
|
||||
node->rs_ttype = lab->lab_type;
|
||||
node->type = lab->lab_type;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
@ -1003,7 +1007,7 @@ ResProcessNode(
|
|||
return 0;
|
||||
|
||||
ResCurrentNode = node->name;
|
||||
ResSortByGate(&node->firstDev);
|
||||
ResSortByGate(&node->devices);
|
||||
|
||||
/* Find largest SD device connected to node. */
|
||||
|
||||
|
|
@ -1015,9 +1019,9 @@ ResProcessNode(
|
|||
/* The following is only used if there is a drivepoint */
|
||||
/* to identify which tile the drivepoint is on. */
|
||||
|
||||
resisdata->rg_ttype = node->rs_ttype;
|
||||
resisdata->rg_ttype = node->type;
|
||||
|
||||
for (ptr = node->firstDev; ptr != NULL; ptr = ptr->nextDev)
|
||||
for (ptr = node->devices; ptr != NULL; ptr = ptr->nextDev)
|
||||
{
|
||||
RDev *t1;
|
||||
RDev *t2;
|
||||
|
|
@ -1067,16 +1071,26 @@ ResProcessNode(
|
|||
else
|
||||
minRes = 0;
|
||||
|
||||
if (node->status & DRIVELOC)
|
||||
/* NOTE: This needs to be fixed, as it is assuming that
|
||||
* a node has exactly one drivepoint; this is (probably)
|
||||
* valid for top level cells, but not in general.
|
||||
*/
|
||||
if ((node->status & (DRIVELOC | PORTNODE)) && (node->drivepoints != NULL))
|
||||
{
|
||||
resisdata->rg_devloc = &node->drivepoint;
|
||||
resisdata->rg_devloc = &node->drivepoints->rc_rect.r_ll;
|
||||
resisdata->rg_ttype = node->drivepoints->rc_type;
|
||||
resisdata->rg_status |= DRIVEONLY;
|
||||
}
|
||||
if (node->status & PORTNODE)
|
||||
|
||||
/* If there is no drivepoint but there is a sinkpoint, use that.
|
||||
* The "drivers" and "sinks" are arbitrary, anyway, and any of
|
||||
* them can be considered a node start point.
|
||||
*/
|
||||
else if ((node->status & (DRIVELOC | PORTNODE)) && (node->sinkpoints != NULL))
|
||||
{
|
||||
/* The node is a port, not a device, so make */
|
||||
/* sure rg_ttype is set accordingly. */
|
||||
resisdata->rg_ttype = node->rs_ttype;
|
||||
resisdata->rg_devloc = &node->sinkpoints->rc_rect.r_ll;
|
||||
resisdata->rg_ttype = node->sinkpoints->rc_type;
|
||||
resisdata->rg_status |= DRIVEONLY;
|
||||
}
|
||||
}
|
||||
if ((resisdata->rg_devloc == NULL) && (node->status & FORCE))
|
||||
|
|
@ -1222,7 +1236,7 @@ ResCheckExtNodes(celldef, resisdata)
|
|||
if (ResOptionsFlags & ResOpt_FastHenry)
|
||||
ResPrintReference(ResFHFile, ResRDevList, celldef);
|
||||
|
||||
for (node = ResOriginalNodes; node != NULL; node=node->nextnode)
|
||||
for (node = ResOriginalNodes; node != NULL; node = node->nextnode)
|
||||
{
|
||||
if (SigInterruptPending) break;
|
||||
total += ResProcessNode(node, celldef, resisdata, outfile,
|
||||
|
|
@ -1285,7 +1299,51 @@ ResCheckExtNodes(celldef, resisdata)
|
|||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResFixUpConnections--
|
||||
* ResFixUpDrivepoints --
|
||||
*
|
||||
* Change the name of a connection to a drivepoint (upward
|
||||
* connection in the hierarchy). If there is an existing
|
||||
* drivepoint that has the name of the node, then keep it
|
||||
* as-is. If not, then assign the original name of the node
|
||||
* to the drivepoint. All other drivepoints get a ".uX"
|
||||
* suffix added to the node name ("u" for "upward").
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResFixUpDrivepoints(ResConnect *driver,
|
||||
ResExtNode *node,
|
||||
char *nodename)
|
||||
{
|
||||
/* To be completed */
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResFixUpSinkpoints --
|
||||
*
|
||||
* Change the name of a connection to a sinkpoint (downward
|
||||
* connection in the hierarchy). All sinkpoints get a ".dX"
|
||||
* suffix added to the node name ("d" for "downward").
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResFixUpSinkpoints(ResConnect *sink,
|
||||
ResExtNode *node,
|
||||
char *nodename)
|
||||
{
|
||||
/* To be completed */
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResFixUpConnections --
|
||||
*
|
||||
* Changes the connection to a terminal of a device.
|
||||
* The new name is formed by appending .t# to the old name.
|
||||
* The new name is added to the hash table of node names.
|
||||
|
|
@ -1376,13 +1434,13 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
|||
}
|
||||
}
|
||||
|
||||
if (extDev->source == extNode)
|
||||
if ((extDev->source == extNode) && (layoutDev->rd_nterms > 3))
|
||||
{
|
||||
/* Check for devices with only one terminal. If it was cast as drain, */
|
||||
/* then swap it with the source so that the code below handles it */
|
||||
/* correctly. */
|
||||
|
||||
if (layoutDev->rd_fet_source == NULL && layoutDev->rd_fet_drain != NULL)
|
||||
if ((layoutDev->rd_fet_source == NULL) && (layoutDev->rd_fet_drain != NULL))
|
||||
{
|
||||
layoutDev->rd_fet_source = layoutDev->rd_fet_drain;
|
||||
layoutDev->rd_fet_drain = (struct resnode *)NULL;
|
||||
|
|
@ -1401,7 +1459,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
|||
if (((source = layoutDev->rd_fet_source) != NULL) &&
|
||||
((drain = layoutDev->rd_fet_drain) != NULL))
|
||||
{
|
||||
if (source->rn_name != NULL && notdecremented)
|
||||
if ((source->rn_name != NULL) && notdecremented)
|
||||
{
|
||||
resNodeNum--;
|
||||
notdecremented = FALSE;
|
||||
|
|
@ -1571,8 +1629,8 @@ ResFixDevName(line, type, device, layoutnode)
|
|||
}
|
||||
tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr)));
|
||||
tptr->thisDev = device;
|
||||
tptr->nextDev = node->firstDev;
|
||||
node->firstDev = tptr;
|
||||
tptr->nextDev = node->devices;
|
||||
node->devices = tptr;
|
||||
tptr->terminal = type;
|
||||
switch(type)
|
||||
{
|
||||
|
|
@ -1816,6 +1874,7 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx)
|
|||
devPtr *ptr;
|
||||
resDevice *layoutDev, *ResGetDevice();
|
||||
float rctol;
|
||||
ResConnect *driver, *sink;
|
||||
|
||||
rctol = resisdata->tdiTolerance;
|
||||
RCdev = resisdata->rg_bigdevres * resisdata->rg_nodecap;
|
||||
|
|
@ -1826,8 +1885,9 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx)
|
|||
(rctol + 1) * RCdev < rctol * resisdata->rg_Tdi)
|
||||
{
|
||||
ASSERT(resisdata->rg_Tdi != -1, "ResWriteExtFile");
|
||||
(void)sprintf(newname,"%s", node->name);
|
||||
cp = newname + strlen(newname)-1;
|
||||
|
||||
sprintf(newname, "%s", node->name);
|
||||
cp = newname + strlen(newname) - 1;
|
||||
if (*cp == '!' || *cp == '#') *cp = '\0';
|
||||
if ((rctol + 1) * RCdev < rctol * resisdata->rg_Tdi ||
|
||||
(ResOptionsFlags & ResOpt_Tdi) == 0)
|
||||
|
|
@ -1841,13 +1901,26 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx)
|
|||
else
|
||||
TxPrintf("Adding %s\n", node->name);
|
||||
|
||||
for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev)
|
||||
{
|
||||
if ((layoutDev = ResGetDevice(&ptr->thisDev->location, ptr->thisDev->rs_ttype)))
|
||||
{
|
||||
for (ptr = node->devices; ptr != NULL; ptr = ptr->nextDev)
|
||||
if ((layoutDev = ResGetDevice(&ptr->thisDev->location,
|
||||
ptr->thisDev->rs_ttype)))
|
||||
ResFixUpConnections(ptr->thisDev, layoutDev, node, newname);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the node name into a driver connection if no driver connection
|
||||
* has the original node name (e.g., was a port). All other drivers
|
||||
* get ".uX" suffixes to distinguish them from internal network nodes
|
||||
* (".nX").
|
||||
*/
|
||||
for (driver = node->drivepoints; driver != NULL; driver = driver->rc_next)
|
||||
ResFixUpDrivepoints(driver, node, newname);
|
||||
|
||||
/* Replace downward connections (sinks) with new node names. Node
|
||||
* names of sinks are given the suffix ".dX" to distinguish them
|
||||
* from terminals, drivers, and nodes.
|
||||
*/
|
||||
for (sink = node->sinkpoints; sink != NULL; sink = sink->rc_next)
|
||||
ResFixUpSinkpoints(driver, node, newname);
|
||||
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
ResPrintExtNode(ResExtFile, ResNodeList, node);
|
||||
|
|
@ -1872,3 +1945,113 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx)
|
|||
else return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* InitializeResNode --
|
||||
*
|
||||
* Initialize a ResNode structure.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Values are filled in the ResNode structure pointed to by "node".
|
||||
*
|
||||
* Notes:
|
||||
* This routine was previously defined as a macro.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void InitializeResNode(resNode *node,
|
||||
int x,
|
||||
int y,
|
||||
int why)
|
||||
{
|
||||
node->rn_te = NULL;
|
||||
node->rn_id = 0;
|
||||
node->rn_float.rn_area = 0.0;
|
||||
node->rn_name = NULL;
|
||||
node->rn_client = (ClientData)NULL;
|
||||
node->rn_noderes = RES_INFINITY;
|
||||
node->rn_je = NULL;
|
||||
node->rn_status = FALSE;
|
||||
node->rn_loc.p_x = x;
|
||||
node->rn_loc.p_y = y;
|
||||
node->rn_why = why;
|
||||
node->rn_ce = (cElement *)NULL;
|
||||
node->rn_re = (resElement *)NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResInfoInit--
|
||||
*
|
||||
* Initialize a resInfo structure.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Values are filled in the resInfo structure pointed to by "Info".
|
||||
*
|
||||
* Notes:
|
||||
* This routine was previously defined as a macro.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void ResInfoInit(resInfo *Info)
|
||||
{
|
||||
Info->contactList = (cElement *)NULL;
|
||||
Info->deviceList = (resDevice *)NULL;
|
||||
Info->junctionList = (ResJunction *)NULL;
|
||||
Info->breakList = (Breakpoint *)NULL;
|
||||
Info->portList = (resPort *)NULL;
|
||||
Info->ri_status = FALSE;
|
||||
Info->sourceEdge = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResNewBreak --
|
||||
*
|
||||
* Create and initialize a new breakpoint structure.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Memory is allocated for the breakpoint, values are filled in,
|
||||
* and the breakpoint is added to the resNode structure pointed
|
||||
* to by "node".
|
||||
*
|
||||
* Notes:
|
||||
* This routine was previously defined as a macro.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ResNewBreak(resNode *node,
|
||||
Tile *tile,
|
||||
int px,
|
||||
int py,
|
||||
Rect *crect)
|
||||
{
|
||||
Breakpoint *bp;
|
||||
resInfo *rX;
|
||||
|
||||
rX = (resInfo *)((tile)->ti_client);
|
||||
bp = (Breakpoint *)mallocMagic((unsigned)(sizeof(Breakpoint)));
|
||||
bp->br_next= rX->breakList;
|
||||
bp->br_this = node;
|
||||
bp->br_loc.p_x = px;
|
||||
bp->br_loc.p_y = py;
|
||||
bp->br_crect = crect;
|
||||
rX->breakList = bp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -389,9 +389,9 @@ ResMoveDevices(node1, node2)
|
|||
device->rd_fet_gate = node2;
|
||||
else if (device->rd_fet_subs == node1)
|
||||
device->rd_fet_subs = node2;
|
||||
else if (device->rd_fet_source == node1)
|
||||
else if ((device->rd_nterms > 2) && (device->rd_fet_source == node1))
|
||||
device->rd_fet_source = node2;
|
||||
else if (device->rd_fet_drain == node1)
|
||||
else if ((device->rd_nterms > 3) && (device->rd_fet_drain == node1))
|
||||
device->rd_fet_drain = node2;
|
||||
else
|
||||
TxError("Missing Device connection in squish routines"
|
||||
|
|
@ -707,7 +707,7 @@ ResDistributeCapacitance(nodelist, totalcap)
|
|||
|
||||
for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more)
|
||||
{
|
||||
for (rptr = workingNode->rn_re; rptr != NULL; rptr=rptr->re_nextEl)
|
||||
for (rptr = workingNode->rn_re; rptr != NULL; rptr = rptr->re_nextEl)
|
||||
if (rptr->re_thisEl->rr_float.rr_area != 0.0)
|
||||
TxError("Nonnull resistor area\n");
|
||||
|
||||
|
|
@ -920,7 +920,7 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist)
|
|||
*/
|
||||
|
||||
int
|
||||
ResDoSimplify(tolerance,resisdata)
|
||||
ResDoSimplify(tolerance, resisdata)
|
||||
float tolerance;
|
||||
ResisData *resisdata;
|
||||
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ ResAddPlumbing(tile, dinfo, arg)
|
|||
}
|
||||
}
|
||||
/* bottom */
|
||||
for(tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
|
||||
for (tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
|
||||
{
|
||||
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
|
||||
if (TiGetTopType(tp2) == t1)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ resCurrentPrintFunc(node, resistor, filename)
|
|||
void
|
||||
ResDeviceCounts()
|
||||
{
|
||||
int i,j,k;
|
||||
int i, j, k;
|
||||
resNode *n;
|
||||
resDevice *t;
|
||||
resResistor *r;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,19 @@ typedef struct device
|
|||
Tile *rd_tile; /* pointer to a tile in device */
|
||||
} resDevice;
|
||||
|
||||
/*
|
||||
* A resConnect maintains a location and tile type of a connections up
|
||||
* (driver) or down (sink), a tile type that makes the connection, and
|
||||
* a link to the resNode that must exist at the point of connection.
|
||||
*/
|
||||
typedef struct resconnect
|
||||
{
|
||||
TileType rc_type;
|
||||
Rect rc_rect;
|
||||
struct resnode *rc_node;
|
||||
struct resconnect *rc_next;
|
||||
} ResConnect;
|
||||
|
||||
/*
|
||||
* A junction is formed when two tiles that connect are next to one another.
|
||||
*/
|
||||
|
|
@ -108,9 +121,10 @@ typedef struct junction
|
|||
typedef struct resport
|
||||
{
|
||||
struct resport *rp_nextPort;
|
||||
Rect rp_bbox;
|
||||
Point rp_loc;
|
||||
char *rp_nodename;
|
||||
ResConnect *rp_connect;
|
||||
Rect rp_bbox;
|
||||
Point rp_loc;
|
||||
} resPort;
|
||||
|
||||
/*
|
||||
|
|
@ -328,17 +342,13 @@ typedef struct resextnode
|
|||
float cap_couple; /* Coupling capacitance */
|
||||
float resistance; /* Lumped resistance */
|
||||
float minsizeres; /* Minimum size resistor allowed */
|
||||
Point drivepoint; /* optional, user specified drive */
|
||||
/* point for network. */
|
||||
TileType rs_ttype; /* Tiletype of drivepoint */
|
||||
ResConnect *drivepoints; /* Upward connections */
|
||||
ResConnect *sinkpoints; /* Downward connections */
|
||||
Point location; /* Location of bottom of leftmost */
|
||||
/* tile in the lowest numbered */
|
||||
/* plane contained in the node. */
|
||||
Rect rs_bbox; /* Location of bottom of leftmost */
|
||||
/* tile in the lowest numbered */
|
||||
/* plane contained in the node. */
|
||||
TileType type; /* Tile type of tile at location */
|
||||
struct devptr *firstDev; /* Linked list of devices */
|
||||
struct devptr *devices; /* Linked list of devices */
|
||||
/* connected to node. */
|
||||
char *name; /* Pointer to name of node stored */
|
||||
/* in hash table. */
|
||||
|
|
@ -518,7 +528,7 @@ extern ResFixPoint *ResFixList;
|
|||
extern int ResTileCount;
|
||||
extern ResExtNode **ResNodeArray;
|
||||
extern CellDef *mainDef;
|
||||
extern TileTypeBitMask ResSDTypesBitMask;
|
||||
extern TileTypeBitMask ResTermTypesBitMask;
|
||||
extern TileTypeBitMask ResSubTypesBitMask;
|
||||
extern HashTable ResDevTable;
|
||||
extern TileTypeBitMask ResNoMergeMask[NT];
|
||||
|
|
@ -533,6 +543,7 @@ extern int ResReadResistor();
|
|||
extern int ResReadAttribute();
|
||||
extern int ResReadMerge();
|
||||
extern int ResReadSubckt();
|
||||
extern int ResReadParentExt();
|
||||
|
||||
extern int ResProcessNode();
|
||||
extern int ResExtCombineParallel();
|
||||
|
|
@ -553,12 +564,16 @@ extern void ResFixDevName();
|
|||
extern void ResWriteLumpFile();
|
||||
extern int ResSortBreaks();
|
||||
extern Plane *extResPrepSubstrate();
|
||||
extern bool ResEachTile();
|
||||
extern void ResStartTile();
|
||||
|
||||
|
||||
/* C99 compat */
|
||||
|
||||
extern void ExtResisForDef(CellDef *celldef, ResisData *resisdata);
|
||||
extern char *ResExtGetAttribute(char *sptr);
|
||||
extern int ResReadFET(int argc, char *argv[]);
|
||||
extern int ResReadConnectPoint(CellDef *def, int argc, char *argv[]);
|
||||
extern int ResReadPort(int argc, char *argv[]);
|
||||
extern char *ResExtGetAttribute(char *sptr);
|
||||
|
||||
|
|
@ -575,7 +590,7 @@ extern void ResEliminateResistor();
|
|||
extern bool ResExtractNet();
|
||||
extern int ResFracture();
|
||||
extern void ResMergeNodes();
|
||||
extern void ResNewSDDevice();
|
||||
extern void ResNewTermDevice();
|
||||
extern void ResNewSubDevice();
|
||||
extern void ResPreProcessDevices();
|
||||
extern void ResPrintDeviceList();
|
||||
|
|
@ -604,59 +619,8 @@ extern int resWalkleft();
|
|||
extern int resWalkright();
|
||||
extern int resWalkup();
|
||||
|
||||
/* Macros */
|
||||
|
||||
#define InitializeResNode(node,x,y,why) \
|
||||
{\
|
||||
(node)->rn_te = NULL;\
|
||||
(node)->rn_id=0;\
|
||||
(node)->rn_float.rn_area = 0.0;\
|
||||
(node)->rn_name = NULL;\
|
||||
(node)->rn_client = (ClientData)NULL;\
|
||||
(node)->rn_noderes = RES_INFINITY;\
|
||||
(node)->rn_je = NULL;\
|
||||
(node)->rn_status = FALSE;\
|
||||
(node)->rn_loc.p_x = (x);\
|
||||
(node)->rn_loc.p_y = (y);\
|
||||
(node)->rn_why = (why);\
|
||||
(node)->rn_ce = (cElement *) NULL;\
|
||||
(node)->rn_re = (resElement *) NULL;\
|
||||
}
|
||||
|
||||
#define ResInfoInit(Info) \
|
||||
{ \
|
||||
Info->contactList = (cElement *) NULL; \
|
||||
Info->deviceList = (resDevice *) NULL; \
|
||||
Info->junctionList = (ResJunction *) NULL; \
|
||||
Info->breakList = (Breakpoint *) NULL; \
|
||||
Info->portList = (resPort *) NULL; \
|
||||
Info->ri_status = FALSE; \
|
||||
Info->sourceEdge = 0 ; \
|
||||
}
|
||||
|
||||
#define NEWBREAK(node,tile,px,py,crect)\
|
||||
{\
|
||||
Breakpoint *bp;\
|
||||
resInfo *jX_ = (resInfo *)((tile)->ti_client); \
|
||||
bp = (Breakpoint *) mallocMagic((unsigned)(sizeof(Breakpoint))); \
|
||||
bp->br_next= jX_->breakList; \
|
||||
bp->br_this = (node); \
|
||||
bp->br_loc.p_x = px; \
|
||||
bp->br_loc.p_y = py; \
|
||||
bp->br_crect = (Rect *) (crect); \
|
||||
jX_->breakList = bp; \
|
||||
}
|
||||
|
||||
#define NEWPORT(node,tile)\
|
||||
{\
|
||||
resPort *rp;\
|
||||
resInfo *pX_ = (resInfo *)((tile)->ti_client); \
|
||||
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); \
|
||||
rp->rp_nextPort = pX_->portList; \
|
||||
rp->rp_bbox = node->rs_bbox; \
|
||||
rp->rp_loc = node->drivepoint; \
|
||||
rp->rp_nodename = node->name; \
|
||||
pX_->portList = rp; \
|
||||
}
|
||||
extern void InitializeResNode();
|
||||
extern void ResInfoInit();
|
||||
extern void ResNewBreak();
|
||||
|
||||
#endif /* _MAGIC__RESIS__RESIS_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue