magic/extract/ExtHard.c

491 lines
14 KiB
C

/*
* ExtHard.c --
*
* Circuit extraction.
* Procedures for finding the name of a node during hierarchical
* extraction, when no label for that node could be found in the
* interaction area.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/extract/ExtHard.c,v 1.2 2010/06/24 12:37:17 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "utils/styles.h"
#include "debug/debug.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "utils/geofast.h"
/* Forward declarations */
void extHardFreeAll();
bool extHardGenerateLabel();
bool extHardSetLabel();
/*
* ----------------------------------------------------------------------------
*
* extLabFirst --
* extLabEach --
*
* Filter functions passed to ExtFindRegions when tracing out extended
* label regions as part of hierarchical circuit extraction. We use the
* TransRegion record because it allows us to save a pointer to a tile
* along with the usual LabRegion data. Since treg_area is not needed,
* we use it to store the plane of the tile.
*
* Results:
* extLabFirst returns a pointer to a new TransRegion.
* extLabEach returns NULL.
*
* Side effects:
* Memory is allocated by extLabFirst.
* We cons the newly allocated region onto the front of the existing
* region list.
*
* ----------------------------------------------------------------------------
*/
Region *
extLabFirst(tile, arg)
Tile *tile;
FindRegion *arg;
{
TransRegion *reg;
reg = (TransRegion *) mallocMagic((unsigned) (sizeof (TransRegion)));
reg->treg_next = (TransRegion *) NULL;
reg->treg_labels = (LabelList *) NULL;
reg->treg_pnum = DBNumPlanes;
reg->treg_area = DBNumPlanes;
reg->treg_tile = tile;
/* Prepend it to the region list */
reg->treg_next = (TransRegion *) arg->fra_region;
arg->fra_region = (Region *) reg;
return ((Region *) reg);
}
/*ARGSUSED*/
int
extLabEach(tile, pNum, arg)
Tile *tile;
int pNum;
FindRegion *arg;
{
TransRegion *reg = (TransRegion *) arg->fra_region;
/* Avoid setting the region's tile pointer to a split tile if we can */
if (IsSplit(reg->treg_tile) && !IsSplit(tile))
{
reg->treg_tile = tile;
reg->treg_area = pNum;
}
if (reg->treg_area == DBNumPlanes) reg->treg_area = pNum;
extSetNodeNum((LabRegion *)reg, pNum, tile);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* extHardProc --
*
* Called for each cell use in a tree. We determine if there is any
* geometry in this cell whose type is in the mask arg->hw_mask and
* whose node name we can determine.
*
* If so, we set arg->hw_label to point to a newly allocated Label whose
* name is the full hierarchical path of the node name we just found, and
* whose location (lab_rect) lies within the geometry of the node, but has
* been transformed to root coordinates by scx->scx_trans.
*
* Several fields in the HardWay struct pointed to by 'arg' control
* the details of how we assign a label:
*
* arg->hw_prefix If this is FALSE, we are responsible for constructing
* the full hierarchical pathname for the generated label
* starting from the immediate children of the root cell
* ha->ha_parentUse->cu_def. We do this by appending
* the use-id of scx->scx_use to arg->hw_tpath before
* appending the final component of the label name to
* arg->hw_tpath.
*
* If TRUE, we are responsible only for appending segments
* to arg->hw_tpath for grandchildren of the root cell and
* their descendants; the caller is responsible for the
* initial part of the pathname.
*
* arg->hw_autogen If FALSE, attempt to find an existing label for the
* geometry in the node.
*
* If TRUE, generate a label from the canonical nodename
* for the first piece of geometry we find.
*
* Results:
* Returns 0 if the caller (DBCellSrArea) should keep going,
* or 1 if we've succeeded and the caller may return.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
int
extHardProc(scx, arg)
SearchContext *scx; /* Context of the search to this cell */
HardWay *arg; /* See above; this structure provides both
* options to govern how we generate labels
* and a place to store the label we return.
*/
{
HierExtractArg *ha = arg->hw_ha;
bool isTopLevel = (scx->scx_use->cu_parent == ha->ha_parentUse->cu_def);
CellDef *def = scx->scx_use->cu_def;
TransRegion *reg;
TransRegion *labRegList;
char *savenext;
int ret = 0;
/*
* Build up next component of label path.
* If the caller has already taken care of generating a prefix
* for immediate children of the root cell, arg->hw_prefix will
* have been set to FALSE.
*/
savenext = arg->hw_tpath.tp_next; /* Will be restored before we return */
if (arg->hw_prefix || !isTopLevel)
{
arg->hw_tpath.tp_next =
DBPrintUseId(scx, savenext, arg->hw_tpath.tp_last - savenext,
FALSE);
*arg->hw_tpath.tp_next++ = '/';
*arg->hw_tpath.tp_next = '\0';
}
/*
* We use a TransRegion because it holds both a LabelList
* and a tile pointer, and call extLabEach to make sure
* that treg_pnum and treg_ll are kept up-to-date (so we
* can generate a node label if none is found).
*
* The call below may return several TransRegions, as when
* geometry in a parent overlaps two different nodes in a
* single child.
*/
labRegList = (TransRegion *) ExtFindRegions(def, &scx->scx_area,
&arg->hw_mask, ExtCurStyle->exts_nodeConn, extUnInit,
extLabFirst, extLabEach, FALSE);
if (labRegList)
{
/*
* If labels are being generated automatically on this pass,
* we don't bother to assign labels to geometry. Instead, we
* construct a new label based on the lower-leftmost tile in
* the Region labRegList.
*/
if (arg->hw_autogen)
{
(void) extHardGenerateLabel(scx, labRegList, arg);
goto success;
}
/*
* Assign labels to LabRegions.
* Tiles in 'def' that belong to nodes other than those in labRegList
* will have uninitialized region pointers, and so will not have labels
* assigned to them.
*/
// ExtLabelRegions(def, ExtCurStyle->exts_nodeConn, &labRegList,
// &scx->scx_area);
ExtLabelRegions(def, ExtCurStyle->exts_nodeConn, NULL, NULL);
/* Now try to find a region with a node label */
for (reg = labRegList; reg; reg = reg->treg_next)
if (reg->treg_labels && extHardSetLabel(scx, reg, arg))
goto success;
/* No luck; it's as though there was no geometry at all */
extHardFreeAll(def, labRegList);
}
/* No luck; check our subcells recursively */
ret = DBCellSrArea(scx, extHardProc, (ClientData) arg);
arg->hw_tpath.tp_next = savenext;
goto done;
success:
extHardFreeAll(def, labRegList);
ret = 1;
done:
return (ret);
}
/*
* ----------------------------------------------------------------------------
*
* extHardSetLabel --
*
* We found a LabRegion, 'reg', that has a label list.
* Walk down its label list looking for a node label.
* If we find one, append it to the TerminalPath we've
* been constructing from the root, make a new label
* whose text is this full pathname, and assign it to
* arg->hw_label.
*
* The coordinates of the result label are those of
* the node label we find, transformed by scx->scx_trans
* to lie in the root.
*
* Results:
* Returns TRUE if we found a node label, FALSE if not.
*
* Side effects:
* If successful, allocates a new Label struct as described
* above, and assigns it to arg->hw_label.
*
* ----------------------------------------------------------------------------
*/
bool
extHardSetLabel(scx, reg, arg)
SearchContext *scx; /* We use scx->scx_trans to transform label
* coordinates in the def scx->scx_use->cu_def
* up to root coordinates.
*/
TransRegion *reg; /* Region with a label list */
HardWay *arg; /* We will set arg->hw_label if a node
* label is found on the label list of 'reg'.
*/
{
TerminalPath *tpath = &arg->hw_tpath;
Label *oldlab, *newlab;
char *srcp, *dstp;
LabelList *ll;
int prefixlen;
char *text;
int len;
Rect r;
int pNum;
Tile *tp;
for (ll = reg->treg_labels; ll; ll = ll->ll_next)
if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME)) break;
if (ll == (LabelList *) NULL)
return (FALSE);
oldlab = ll->ll_label;
/* Compute length of new label */
prefixlen = tpath->tp_next - tpath->tp_first;
len = strlen(oldlab->lab_text) + prefixlen;
/* Allocate a Label big enough to hold the complete path */
newlab = (Label *) mallocMagic((unsigned) (sizeof (Label) + len - 3));
r=oldlab->lab_rect;
if (!GEO_SURROUND(&scx->scx_area,&r))
{
GEOCLIP(&r,&scx->scx_area);
pNum = DBPlane(oldlab->lab_type);
tp = scx->scx_use->cu_def->cd_planes[pNum]->pl_hint;
GOTOPOINT(tp, &r.r_ll);
scx->scx_use->cu_def->cd_planes[pNum]->pl_hint = tp;
if ((TransRegion *)extGetRegion(tp) == reg)
{
/* found an OK point */
r.r_ur.p_x =r.r_ll.p_x+1;
r.r_ur.p_y =r.r_ll.p_y+1;
}
else
{
GOTOPOINT(tp, &r.r_ur);
if ((TransRegion *)extGetRegion(tp) == reg)
{
r.r_ll = r.r_ur;
}
else
{
/* forget it; we're never going to find the damn thing */
r=oldlab->lab_rect;
}
}
}
GeoTransRect(&scx->scx_trans, &r, &newlab->lab_rect);
newlab->lab_type = oldlab->lab_type;
newlab->lab_flags = oldlab->lab_flags;
text = oldlab->lab_text;
/* Don't care, really, which orientation the label has */
newlab->lab_just = GEO_NORTH;
/* Construct the text of the new label */
dstp = newlab->lab_text;
if (prefixlen)
{
srcp = tpath->tp_first;
do { *dstp++ = *srcp++; } while (--prefixlen > 0);
}
srcp = text;
while (*dstp++ = *srcp++) /* Nothing */;
arg->hw_label = newlab;
if (DebugIsSet(extDebugID, extDebHardWay))
TxPrintf("Hard way: found label = \"%s\"\n", newlab->lab_text);
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* extHardGenerateLabel --
*
* Generate a label automatically from reg->treg_pnum and
* reg->treg_ll according to the conventions used for node
* labels in ExtBasic.c. The label is prefixed with the
* TerminalPath we've been constructing from the root in
* arg->hw_tpath.
*
* The coordinates of the result label are those of reg->treg_tile->ti_ll,
* transformed by scx->scx_trans to lie in the root.
*
* Results:
* Always TRUE.
*
* Side effects:
* Allocates a new Label struct as described above,
* and assigns it to arg->hw_label.
*
* ----------------------------------------------------------------------------
*/
bool
extHardGenerateLabel(scx, reg, arg)
SearchContext *scx; /* We use scx->scx_trans to transform the
* generated label's coordinates up to
* root coordinates.
*/
TransRegion *reg; /* Region whose treg_ll and treg_pnum we use
* to generate a new label name.
*/
HardWay *arg; /* We set arg->hw_label to the new label */
{
TerminalPath *tpath = &arg->hw_tpath;
char *srcp, *dstp;
Label *newlab;
int prefixlen;
char gen[100];
int len;
Rect r;
Point p;
extMakeNodeNumPrint(gen, (LabRegion *)reg);
prefixlen = tpath->tp_next - tpath->tp_first;
len = strlen(gen) + prefixlen;
newlab = (Label *) mallocMagic((unsigned) (sizeof (Label) + len - 3));
r.r_ll = reg->treg_tile->ti_ll;
r.r_ur.p_x = r.r_ll.p_x+1;
r.r_ur.p_y = r.r_ll.p_y+1;
GEOCLIP(&r,&scx->scx_area);
GeoTransRect(&scx->scx_trans, &r, &newlab->lab_rect);
newlab->lab_type = TiGetType(reg->treg_tile);
/* Don't care, really, which orientation the label has */
newlab->lab_just = GEO_NORTH;
/* Mark this as a generated label; may or may not be useful */
newlab->lab_flags = LABEL_GENERATE;
/* Construct the text of the new label */
dstp = newlab->lab_text;
if (prefixlen)
{
srcp = tpath->tp_first;
do { *dstp++ = *srcp++; } while (--prefixlen > 0);
}
srcp = gen;
while (*dstp++ = *srcp++) /* Nothing */;
arg->hw_label = newlab;
if (DebugIsSet(extDebugID, extDebHardWay))
TxPrintf("Hard way: generated label = \"%s\"\n", newlab->lab_text);
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* extHardFreeAll --
*
* Reset all the ti_client fields that we set in 'def' that
* were set to point to regions in the list 'tReg' of TransRegions.
* Then free all the regions in 'tReg'.
*
* Results:
* None.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
void
extHardFreeAll(def, tReg)
CellDef *def;
TransRegion *tReg;
{
TransRegion *reg;
LabelList *ll;
FindRegion arg;
/* Don't need to initialize arg.fra_first below */
arg.fra_connectsTo = ExtCurStyle->exts_nodeConn;
arg.fra_def = def;
arg.fra_each = (int (*)()) NULL;
arg.fra_region = (Region *) extUnInit;
for (reg = tReg; reg; reg = reg->treg_next)
{
/* Reset all ti_client fields to extUnInit */
arg.fra_uninit = (ClientData) reg;
if (reg->treg_tile)
{
arg.fra_pNum = reg->treg_area;
ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg);
}
/* Free all LabelLists and then the region */
for (ll = reg->treg_labels; ll; ll = ll->ll_next)
freeMagic((char *) ll);
freeMagic((char *) reg);
}
}