2017-04-25 14:41:48 +02:00
|
|
|
/* NMwiring.c -
|
|
|
|
|
*
|
|
|
|
|
* This file contains procedures that manipulate wiring
|
|
|
|
|
* and netlists. For example, there are procedures to
|
|
|
|
|
* generate a net from a wire, to rip up a wire, and to
|
|
|
|
|
* verify that all the connections in a netlist actually
|
|
|
|
|
* exist in the circuit.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/netmenu/NMwiring.c,v 1.3 2008/12/11 04:20:11 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.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 "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "netmenu/netmenu.h"
|
|
|
|
|
#include "netmenu/nmInt.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "drc/drc.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "router/router.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "select/select.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* The following structure is used to hold information about
|
|
|
|
|
* areas to be erased during net ripup.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct nmwarea
|
|
|
|
|
{
|
|
|
|
|
Rect nmwa_area; /* Area to be deleted. */
|
|
|
|
|
TileType nmwa_type; /* Type of material to be erased. */
|
|
|
|
|
struct nmwarea *nmwa_next; /* Next item in list, or NULL for end. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* The following static is used by nmwNetTermFunc to signal to nmwNetTileFunc
|
|
|
|
|
* that it found a terminal.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static bool nmwGotTerm;
|
|
|
|
|
|
|
|
|
|
/* The following arrays (which grow dynamically as the need arises)
|
|
|
|
|
* are used during net-list verification, culling, and routing measurement.
|
|
|
|
|
* They record all of the terminals found in the current net. Terminals are
|
|
|
|
|
* recorded by the addresses of their names and by their areas.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static char ** nmwVerifyNames; /* Actual storage (malloc'ed). */
|
|
|
|
|
static char ** nmwNonTerminalNames; /* Actual storage (malloc'ed). */
|
|
|
|
|
static Rect *nmwVerifyAreas; /* Areas of terminals (malloc'ed). */
|
|
|
|
|
static int nmwCullDone; /* Counts number of cull errors */
|
|
|
|
|
static int nmwVerifySize = 0; /* Size of arrays. */
|
|
|
|
|
static int nmwNonTerminalSize = 0; /* Size of arrays. */
|
|
|
|
|
static int nmwVerifyCount; /* Number of valid entries in array.*/
|
|
|
|
|
static int nmwNonTerminalCount; /* Number of valid entries in array.*/
|
|
|
|
|
static int nmwVerifyErrors; /* Counts number of errors found. */
|
|
|
|
|
static bool nmwVerifyNetHasErrors; /* TRUE means an error has already
|
|
|
|
|
* been found in the current net.
|
|
|
|
|
*/
|
|
|
|
|
static bool nmwNetFound = FALSE; /* TRUE means a net has been found and
|
|
|
|
|
* we should skip the rest of the
|
2020-05-23 23:13:14 +02:00
|
|
|
* terminals in that net
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
/* The nmMeasureTiles array (which grows dynamically as needed) records
|
|
|
|
|
* all tiles found on the current net.
|
|
|
|
|
*/
|
|
|
|
|
static int nmMeasureSize = 0; /* Size of tile array */
|
|
|
|
|
static int nmMeasureCount; /* Number of valid tile array entries */
|
|
|
|
|
static Tile ** nmMeasureTiles = NULL; /* Actual storage for tile array */
|
|
|
|
|
|
|
|
|
|
/* Counters used to measure net statistics */
|
|
|
|
|
static int nmMArea = 0;
|
|
|
|
|
static int nmPArea = 0;
|
|
|
|
|
static int nmVCount= 0;
|
|
|
|
|
|
|
|
|
|
/* Maximimum length for terminals allocated here: */
|
|
|
|
|
|
|
|
|
|
#define TERMLENGTH 200
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwRipTileFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked by DBSrConnect when ripping up
|
|
|
|
|
* paint. It records each tile found on a list, so they can
|
|
|
|
|
* be deleted later (it isn't safe for us to just delete the
|
|
|
|
|
* tile here, since there is a search in progress over the
|
|
|
|
|
* database).
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search from aborting.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Adds rectangular areas to the list.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
nmwRipTileFunc(tile, plane, listHead)
|
|
|
|
|
Tile *tile; /* Tile that is to be deleted. */
|
|
|
|
|
int plane; /* Plane index of the tile */
|
|
|
|
|
struct nmwarea **listHead; /* Pointer to list head pointer. */
|
|
|
|
|
{
|
|
|
|
|
struct nmwarea *new;
|
|
|
|
|
|
|
|
|
|
new = (struct nmwarea *) mallocMagic(sizeof(struct nmwarea));
|
|
|
|
|
TiToRect(tile, &new->nmwa_area);
|
|
|
|
|
new->nmwa_type = TiGetType(tile);
|
|
|
|
|
new->nmwa_next = *listHead;
|
|
|
|
|
*listHead = new;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMRipup --
|
|
|
|
|
*
|
|
|
|
|
* Starting from some piece of paint in the edit cell underneath
|
|
|
|
|
* the box, this procedure rips up all connected paint.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The edit cell is modified.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
NMRipup()
|
|
|
|
|
{
|
|
|
|
|
struct nmwarea *list;
|
|
|
|
|
Rect area;
|
|
|
|
|
TileTypeBitMask maskBits;
|
|
|
|
|
|
|
|
|
|
/* Collect all the connected areas together into a list. */
|
|
|
|
|
|
|
|
|
|
list = NULL;
|
|
|
|
|
if (!ToolGetEditBox(&area)) return 0;
|
|
|
|
|
|
|
|
|
|
/* Expand the box to get everything touching it. */
|
|
|
|
|
|
|
|
|
|
GEO_EXPAND(&area, 1, &area);
|
|
|
|
|
|
|
|
|
|
(void) DBSrConnect(EditCellUse->cu_def, &area,
|
|
|
|
|
&DBAllButSpaceAndDRCBits, DBConnectTbl,
|
|
|
|
|
&TiPlaneRect, nmwRipTileFunc, (ClientData) &list);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Now go through the list one item at a time and delete
|
|
|
|
|
* the attached paint.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
TTMaskZero(&maskBits);
|
|
|
|
|
while (list != NULL)
|
|
|
|
|
{
|
|
|
|
|
DBErase(EditCellUse->cu_def, &list->nmwa_area, list->nmwa_type);
|
|
|
|
|
TTMaskSetType(&maskBits, list->nmwa_type);
|
|
|
|
|
(void) DBEraseLabel(EditCellUse->cu_def, &list->nmwa_area, &maskBits, NULL);
|
|
|
|
|
TTMaskClearType(&maskBits, list->nmwa_type);
|
|
|
|
|
DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &list->nmwa_area);
|
|
|
|
|
DBWAreaChanged(EditCellUse->cu_def, &list->nmwa_area, DBW_ALLWINDOWS,
|
|
|
|
|
&DBAllButSpaceBits);
|
|
|
|
|
freeMagic((char *) list);
|
|
|
|
|
list = list->nmwa_next;
|
|
|
|
|
}
|
|
|
|
|
DBReComputeBbox(EditCellUse->cu_def);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmRipLocFunc --
|
|
|
|
|
*
|
|
|
|
|
* This function is called once for each terminal location in
|
|
|
|
|
* a netlist being ripped up in its entirety. It rips up any
|
|
|
|
|
* paint underneath this terminal, and adds its area into the
|
|
|
|
|
* total area affected so far.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search from aborting.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* A net gets ripped up.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmRipLocFunc(rect, name, label, area)
|
|
|
|
|
Rect *rect; /* Area of the terminal, edit cell coords. */
|
|
|
|
|
char *name; /* Name of the terminal (ignored). */
|
|
|
|
|
Label *label; /* Pointer to the label, used to find out
|
|
|
|
|
* what layer the label's attached to.
|
|
|
|
|
*/
|
|
|
|
|
Rect *area; /* We GeoInclude into this all the areas of
|
|
|
|
|
* all the tiles we delete.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
struct nmwarea *list;
|
|
|
|
|
Rect initialArea;
|
|
|
|
|
TileTypeBitMask maskBits;
|
|
|
|
|
|
|
|
|
|
/* This code is basically the same as in NMRipup. */
|
|
|
|
|
|
|
|
|
|
GEO_EXPAND(rect, 1, &initialArea);
|
|
|
|
|
list = NULL;
|
|
|
|
|
(void) DBSrConnect(EditCellUse->cu_def, &initialArea,
|
|
|
|
|
&DBConnectTbl[label->lab_type], DBConnectTbl,
|
|
|
|
|
&TiPlaneRect, nmwRipTileFunc, (ClientData) &list);
|
|
|
|
|
TTMaskZero(&maskBits);
|
|
|
|
|
TTMaskClearType(&maskBits, label->lab_type);
|
|
|
|
|
while (list != NULL)
|
|
|
|
|
{
|
|
|
|
|
DBErase(EditCellUse->cu_def, &list->nmwa_area, list->nmwa_type);
|
|
|
|
|
TTMaskSetType(&maskBits, list->nmwa_type);
|
|
|
|
|
(void) DBEraseLabel(EditCellUse->cu_def, &list->nmwa_area, &maskBits, NULL);
|
|
|
|
|
TTMaskClearType(&maskBits, list->nmwa_type);
|
|
|
|
|
(void) GeoInclude(&list->nmwa_area, area);
|
|
|
|
|
freeMagic((char *) list);
|
|
|
|
|
list = list->nmwa_next;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmRipNameFunc --
|
|
|
|
|
*
|
|
|
|
|
* This function gets called during netlist ripup. It's invoked
|
|
|
|
|
* once for each terminal name in the list. It just calls
|
|
|
|
|
* DBSrLabelLoc to invoke nmRipLocFunc for each terminal
|
|
|
|
|
* location associated with the name.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search from aborting.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Nothing here, but it calls procedures that rip up nets.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmRipNameFunc(name, firstInNet, area)
|
|
|
|
|
char *name; /* Name of terminal. */
|
|
|
|
|
bool firstInNet; /* Ignored by this procedure. */
|
|
|
|
|
Rect *area; /* Passed through as ClientData to
|
|
|
|
|
* nmRipLocFunc.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
(void) DBSrLabelLoc(EditCellUse, name, nmRipLocFunc, (ClientData) area);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMRipupList --
|
|
|
|
|
*
|
|
|
|
|
* This function rips up all wiring associated with each net in
|
|
|
|
|
* the current netlist.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Massive amounts of wiring is destroyed. The edit cell may never
|
|
|
|
|
* be the same again.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
NMRipupList()
|
|
|
|
|
{
|
|
|
|
|
Rect area;
|
|
|
|
|
|
|
|
|
|
/* This is easy. Just enumerate every terminal in the netlist.
|
|
|
|
|
* For each terminal, ripup all wiring starting at the point of
|
|
|
|
|
* the terminal. The client data is used to pass around a
|
|
|
|
|
* rectangle that accumlates the total area of the edit cell that
|
|
|
|
|
* was modified.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
area = GeoNullRect;
|
|
|
|
|
(void) NMEnumNets(nmRipNameFunc, (ClientData) &area);
|
|
|
|
|
DBReComputeBbox(EditCellUse->cu_def);
|
|
|
|
|
DBWAreaChanged(EditCellUse->cu_def, &area, DBW_ALLWINDOWS,
|
|
|
|
|
&DBAllButSpaceBits);
|
|
|
|
|
DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &area);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwNetCellFunc --
|
|
|
|
|
*
|
|
|
|
|
* This function is called by DBCellSrArea as part of nmwNetTileFunc.
|
|
|
|
|
* Its function is to print an error message for each cell found.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 2 always, to skip past the current array.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* An error message is printed.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
nmwNetCellFunc(scx)
|
|
|
|
|
SearchContext *scx; /* Describes search. */
|
|
|
|
|
{
|
|
|
|
|
TxError("Cell id %s touches net but has no terminals.\n",
|
|
|
|
|
scx->scx_use->cu_id);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwCheckFunc --
|
|
|
|
|
*
|
|
|
|
|
* This function is called by NMEnumTerms when we're checking to
|
|
|
|
|
* see if a given terminal is in a given net.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 1 if its two arguments match (terminal is in net).
|
|
|
|
|
* Returns 0 otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
nmwCheckFunc(name, otherName)
|
|
|
|
|
char *name; /* Terminal in net. */
|
|
|
|
|
char *otherName; /* Terminal we want to know if it's in net. */
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(name, otherName) == 0) return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwNetTermFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called by DBTreeSrLabels for each label found
|
|
|
|
|
* under the current tile being processed during netlist extraction.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Zero is always returned to keep the search alive, unless
|
|
|
|
|
* there's no current netlist, in which case 1 is returned
|
|
|
|
|
* to abort the search.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If the terminal is not in the edit cell (i.e. it contains a "/")
|
|
|
|
|
* it is added to the current net. The current net pointer is
|
|
|
|
|
* changed to refer to this terminal to provide for our caller a
|
|
|
|
|
* handle on the net.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmwNetTermFunc(scx, label, tpath, netPtr)
|
|
|
|
|
SearchContext *scx; /* Describes state of search (ignored). */
|
|
|
|
|
Label *label; /* Label (ignored). */
|
|
|
|
|
TerminalPath *tpath; /* Gives hierarchical label name. */
|
|
|
|
|
char **netPtr; /* Pointer to a terminal in current net. */
|
|
|
|
|
{
|
|
|
|
|
char *p, *p2;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (strchr(tpath->tp_first, '/') == 0) return 0;
|
|
|
|
|
|
|
|
|
|
/* Add the label name onto the end of the terminal path name. */
|
|
|
|
|
|
|
|
|
|
p2 = tpath->tp_next;
|
|
|
|
|
for (p = label->lab_text; *p != 0; p += 1)
|
|
|
|
|
{
|
|
|
|
|
if (p2 == tpath->tp_last) break;
|
|
|
|
|
*p2++ = *p;
|
|
|
|
|
}
|
|
|
|
|
*p2 = 0;
|
|
|
|
|
|
|
|
|
|
/* If this terminal is already in a net, don't remove it. But issue a
|
|
|
|
|
* warning if it's not in the net we think it should be.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nmwGotTerm = TRUE;
|
|
|
|
|
if (NMTermInList(tpath->tp_first))
|
|
|
|
|
{
|
|
|
|
|
if ((*netPtr == NULL)
|
|
|
|
|
|| (NMEnumTerms(*netPtr, nmwCheckFunc,
|
|
|
|
|
(ClientData) tpath->tp_first) == 0))
|
|
|
|
|
{
|
|
|
|
|
TxError("Warning: %s was already in a net (I left it there).\n",
|
|
|
|
|
tpath->tp_first);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (*netPtr == NULL)
|
|
|
|
|
*netPtr = NMAddTerm(tpath->tp_first, tpath->tp_first);
|
|
|
|
|
else *netPtr = NMAddTerm(tpath->tp_first, *netPtr);
|
|
|
|
|
if (*netPtr == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("No current netlist! Please select one and retry.\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwNetTileFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked by DBSrConnect from NMWExtract.
|
|
|
|
|
* It is called once for each connected tile. Its purpose
|
|
|
|
|
* is to do two things. First, it sees if there are any
|
|
|
|
|
* labels underneath the tile, other than those in the edit
|
|
|
|
|
* cell. If so, it adds them to the net that's being formed
|
|
|
|
|
* Secondly, if there are no terminals under the tile, then
|
|
|
|
|
* there better not be any subcells under it either. If
|
|
|
|
|
* there are, warning messages are printed by nmNetCellFunc.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search alive, unless there's
|
|
|
|
|
* no current netlist, in which case 1 is returned to abort.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* A terminal is added to a net. *netPtr is set to point to
|
|
|
|
|
* a terminal in the netlist.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
nmwNetTileFunc(tile, plane, netPtr)
|
|
|
|
|
Tile *tile; /* Tile that is connected to net. */
|
|
|
|
|
int plane; /* Plane index of the tile */
|
|
|
|
|
char **netPtr; /* Pointer to pointer to net name. */
|
|
|
|
|
{
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
char label[TERMLENGTH];
|
|
|
|
|
TerminalPath tpath;
|
|
|
|
|
|
|
|
|
|
/* Add any terminals under this tile to the netlist. We
|
|
|
|
|
* have to blow up the tile's area by one for searching,
|
|
|
|
|
* so that we get anything that even touches it.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
TiToRect(tile, &scx.scx_area);
|
|
|
|
|
scx.scx_area.r_xbot -= 1;
|
|
|
|
|
scx.scx_area.r_xtop += 1;
|
|
|
|
|
scx.scx_area.r_ybot -= 1;
|
|
|
|
|
scx.scx_area.r_ytop += 1;
|
|
|
|
|
scx.scx_use = EditCellUse;
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
tpath.tp_first = label;
|
|
|
|
|
tpath.tp_next = label;
|
|
|
|
|
tpath.tp_last = &label[TERMLENGTH-1];
|
|
|
|
|
nmwGotTerm = FALSE;
|
|
|
|
|
if (DBTreeSrLabels(&scx, &DBConnectTbl[TiGetType(tile)], 0, &tpath,
|
|
|
|
|
TF_LABEL_ATTACH, nmwNetTermFunc, (ClientData) netPtr) != 0)
|
|
|
|
|
{
|
|
|
|
|
/* Non-zero return value means no current netlist. Quit now. */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If no new terminal was added, then make sure there aren't any
|
|
|
|
|
* subcells underneath the current tile.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!nmwGotTerm)
|
|
|
|
|
{
|
|
|
|
|
(void) DBCellSrArea(&scx, nmwNetCellFunc, (ClientData) NULL);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMExtract --
|
|
|
|
|
*
|
|
|
|
|
* Starting from all paint in the edit cell that is underneath
|
|
|
|
|
* the box, this procedure finds all terminals in subcells that
|
|
|
|
|
* are attached to the net and puts them into the netlist as a
|
|
|
|
|
* new net. The new net is highlighted.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* A new net is created and highlighted.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
NMExtract()
|
|
|
|
|
{
|
|
|
|
|
Rect area;
|
|
|
|
|
char *net = NULL;
|
|
|
|
|
|
|
|
|
|
if (!ToolGetEditBox(&area)) return 0;
|
|
|
|
|
|
|
|
|
|
/* Expand the box area so we'll pick up everything touching it. */
|
|
|
|
|
|
|
|
|
|
GEO_EXPAND(&area, 1, &area);
|
|
|
|
|
net = NULL;
|
|
|
|
|
(void) DBSrConnect(EditCellUse->cu_def, &area,
|
|
|
|
|
&DBAllButSpaceAndDRCBits, DBConnectTbl,
|
|
|
|
|
&TiPlaneRect, nmwNetTileFunc, (ClientData) &net);
|
|
|
|
|
if (net == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("There aren't any terminals connected");
|
|
|
|
|
TxError(" to paint under the box\n");
|
|
|
|
|
TxError("(except those, if any, already in other nets).\n");
|
|
|
|
|
}
|
|
|
|
|
NMSelectNet(net);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwVerifyLabelFunc2 --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked once for each label that is actually
|
|
|
|
|
* wired to the current net being verified.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search alive.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If the label is a terminal in the list, it is added to
|
|
|
|
|
* the array nmwVerifyNames. In addition, any other terminals
|
|
|
|
|
* with the same name are searched out and wiring is traced
|
|
|
|
|
* from them to look for yet other terminals (this is done to
|
|
|
|
|
* handle feedthroughs).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
int
|
|
|
|
|
nmwVerifyLabelFunc2(scx, label, tpath, cd)
|
|
|
|
|
SearchContext *scx; /* Describes state of search. */
|
|
|
|
|
Label *label; /* Label. */
|
|
|
|
|
TerminalPath *tpath; /* Gives hierarchical label name. */
|
|
|
|
|
ClientData cd; /* Used in nmwVerifyTileFunc */
|
|
|
|
|
{
|
|
|
|
|
char *p, *p2;
|
|
|
|
|
char *name;
|
|
|
|
|
extern int nmwVerifyLabelFunc(); /* Forward reference. */
|
|
|
|
|
|
|
|
|
|
/* Add the label name onto the end of the terminal path name. */
|
|
|
|
|
|
|
|
|
|
p2 = tpath->tp_next;
|
|
|
|
|
for (p = label->lab_text; *p != 0; p += 1)
|
|
|
|
|
{
|
|
|
|
|
if (p2 == tpath->tp_last) break;
|
|
|
|
|
*p2++ = *p;
|
|
|
|
|
}
|
|
|
|
|
*p2 = 0;
|
|
|
|
|
|
|
|
|
|
/* See if the label is supposed to be in a net. If not, forget it. */
|
|
|
|
|
|
|
|
|
|
name = NMTermInList(tpath->tp_first);
|
|
|
|
|
/*if (name == NULL) return 0;*/
|
2020-05-23 23:13:14 +02:00
|
|
|
if (name == NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
** make sure there is enough space in the array to hold this
|
|
|
|
|
** NonTerminal. If not, allocate a new array and copy the old to
|
|
|
|
|
** the new.
|
|
|
|
|
*/
|
|
|
|
|
if (nmwNonTerminalCount == nmwNonTerminalSize)
|
|
|
|
|
{
|
|
|
|
|
char ** newNames;
|
|
|
|
|
int i, newSize;
|
|
|
|
|
|
|
|
|
|
newSize = 2*nmwNonTerminalSize;
|
|
|
|
|
if (newSize < 16) newSize = 16;
|
|
|
|
|
newNames = (char **) mallocMagic((unsigned) newSize*sizeof(char **));
|
|
|
|
|
for (i = 0; i < nmwNonTerminalSize; i++)
|
|
|
|
|
{
|
|
|
|
|
newNames[i] = nmwNonTerminalNames[i];
|
|
|
|
|
}
|
|
|
|
|
for (i = nmwNonTerminalSize; i < newSize; i++)
|
|
|
|
|
{
|
|
|
|
|
newNames[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (nmwNonTerminalSize != 0)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) nmwNonTerminalNames);
|
|
|
|
|
}
|
|
|
|
|
nmwNonTerminalNames = newNames;
|
|
|
|
|
nmwNonTerminalSize = newSize;
|
|
|
|
|
}
|
|
|
|
|
(void) StrDup(&(nmwNonTerminalNames[nmwNonTerminalCount]),
|
|
|
|
|
tpath->tp_first);
|
|
|
|
|
nmwNonTerminalCount += 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure that there's enough space in the array to hold this
|
|
|
|
|
* terminal. If not, then allocate a new array and copy the old
|
|
|
|
|
* to the new.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (nmwVerifyCount == nmwVerifySize)
|
|
|
|
|
{
|
|
|
|
|
char ** newNames;
|
|
|
|
|
Rect *newAreas;
|
|
|
|
|
int i, newSize;
|
|
|
|
|
|
|
|
|
|
newSize = 2*nmwVerifySize;
|
|
|
|
|
if (newSize < 16) newSize = 16;
|
|
|
|
|
newNames = (char **) mallocMagic((unsigned) newSize*sizeof(char **));
|
|
|
|
|
newAreas = (Rect *) mallocMagic((unsigned) newSize*sizeof(Rect));
|
|
|
|
|
for (i = 0; i < nmwVerifySize; i++)
|
|
|
|
|
{
|
|
|
|
|
newNames[i] = nmwVerifyNames[i];
|
|
|
|
|
newAreas[i] = nmwVerifyAreas[i];
|
|
|
|
|
}
|
|
|
|
|
if (nmwVerifySize != 0)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) nmwVerifyNames);
|
|
|
|
|
freeMagic((char *) nmwVerifyAreas);
|
|
|
|
|
}
|
|
|
|
|
nmwVerifyNames = newNames;
|
|
|
|
|
nmwVerifyAreas = newAreas;
|
|
|
|
|
nmwVerifySize = newSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add the name and areas to the arrays. Use the name from the
|
|
|
|
|
* netlist table, since its address is permanent and can be
|
|
|
|
|
* compared later to see if we got all the terminals in the net.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
nmwVerifyNames[nmwVerifyCount] = name;
|
|
|
|
|
GeoTransRect(&scx->scx_trans, &label->lab_rect,
|
|
|
|
|
&nmwVerifyAreas[nmwVerifyCount]);
|
|
|
|
|
nmwVerifyCount += 1;
|
|
|
|
|
|
|
|
|
|
/* See if there are any other labels with the same name as this
|
|
|
|
|
* one. If so, trace out the wiring that connects to them.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
(void) DBSrLabelLoc(EditCellUse, name, nmwVerifyLabelFunc, cd);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwVerifyTileFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked when tracing out wiring to see what's
|
|
|
|
|
* actually attached to a net. It is invoked once for each tile
|
|
|
|
|
* in the wiring.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search alive.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Any terminals found under the tile are added to nmwVerifyNames.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
2025-01-06 17:25:15 +01:00
|
|
|
nmwVerifyTileFunc(
|
|
|
|
|
Tile *tile, /* Tile that is connected to this net. */
|
|
|
|
|
int plane, /* Plane index of the tile. */
|
|
|
|
|
ClientData cdata) /* Processing function for each tile. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-01-06 17:25:15 +01:00
|
|
|
int (*func)(Tile *) = (int (*)(Tile *))CD2FUN(cdata);
|
2017-04-25 14:41:48 +02:00
|
|
|
SearchContext scx;
|
|
|
|
|
char label[TERMLENGTH];
|
|
|
|
|
TerminalPath tpath;
|
|
|
|
|
|
|
|
|
|
/* Search out all the labels underneath the tile, regardless of cell. */
|
|
|
|
|
|
|
|
|
|
if(func!=NULL)
|
|
|
|
|
(*func)(tile);
|
|
|
|
|
TiToRect(tile, &scx.scx_area);
|
|
|
|
|
GEO_EXPAND(&scx.scx_area, 1, &scx.scx_area);
|
|
|
|
|
scx.scx_use = EditCellUse;
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
tpath.tp_first = label;
|
|
|
|
|
tpath.tp_next = label;
|
|
|
|
|
tpath.tp_last = &label[TERMLENGTH-1];
|
|
|
|
|
(void) DBTreeSrLabels(&scx, &DBConnectTbl[TiGetType(tile)],
|
2025-01-06 17:25:15 +01:00
|
|
|
0, &tpath, TF_LABEL_ATTACH, nmwVerifyLabelFunc2, cdata);
|
2017-04-25 14:41:48 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwVerifyLabelFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked for each label of a terminal in
|
|
|
|
|
* a net. Its purpose is to trace out all wiring emanating
|
|
|
|
|
* from each label and add the terminals attached to that
|
|
|
|
|
* wiring into the arrays of stuff in the current net. This
|
|
|
|
|
* procedure is invoked for the first terminal in each net,
|
|
|
|
|
* and also for each additional terminal in case there are
|
|
|
|
|
* feedthroughs.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the search alive.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Causes the table nmwVerifyNames to be built.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
nmwVerifyLabelFunc(rect, name, label, cd)
|
|
|
|
|
Rect *rect; /* Area of the label, in EditUse coords. */
|
|
|
|
|
char *name; /* Hierarchical name of label. */
|
|
|
|
|
Label *label; /* Actual label structure. */
|
2025-01-06 17:25:15 +01:00
|
|
|
ClientData cd; /* Client data for nmwVerifyTileFunc (function pointer) */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
TileTypeBitMask *mask;
|
|
|
|
|
int i;
|
|
|
|
|
Rect biggerArea;
|
|
|
|
|
|
|
|
|
|
/* If this label has already been seen and processed, don't
|
|
|
|
|
* process it again. That could lead to infinite loops.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nmwVerifyCount; i++)
|
|
|
|
|
{
|
|
|
|
|
Rect *r;
|
|
|
|
|
|
|
|
|
|
r = &nmwVerifyAreas[i];
|
|
|
|
|
if ((r->r_xbot == rect->r_xbot) && (r->r_ybot == rect->r_ybot)
|
|
|
|
|
&& (r->r_xtop == rect->r_xtop) && (r->r_ytop == rect->r_ytop)
|
|
|
|
|
&& (strcmp(name, nmwVerifyNames[i]) == 0))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Trace out all wiring in the edit cell that's attached to this
|
|
|
|
|
* label (to accumulate information about what's actually wired).
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (label->lab_type == TT_SPACE) mask = &DBAllButSpaceAndDRCBits;
|
|
|
|
|
else mask = &DBConnectTbl[label->lab_type];
|
|
|
|
|
|
|
|
|
|
/* We want to consider anything that even touches the label. */
|
|
|
|
|
|
|
|
|
|
GEO_EXPAND(rect, 1, &biggerArea);
|
|
|
|
|
(void) DBSrConnect(EditCellUse->cu_def, &biggerArea, mask,
|
|
|
|
|
DBConnectTbl, &TiPlaneRect, nmwVerifyTileFunc, cd);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwVErrorLabelFunc --
|
|
|
|
|
*
|
|
|
|
|
* Called when a terminal isn't present in its net. Generates
|
|
|
|
|
* a feedback area once, then aborts the search.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 1 to abort the search: one feedback area is
|
|
|
|
|
* all that we want.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Generates a feedback area.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmwVErrorLabelFunc(rect, name, label)
|
|
|
|
|
Rect *rect; /* Area of label in edit cell coords. */
|
|
|
|
|
char *name; /* Hierarchical name of label. */
|
|
|
|
|
Label *label; /* Pointer to the label itself (not used). */
|
|
|
|
|
{
|
|
|
|
|
char msg[200];
|
|
|
|
|
Rect biggerArea;
|
|
|
|
|
|
|
|
|
|
(void) sprintf(msg, "Net of \"%.100s\" isn't fully connected.", name);
|
|
|
|
|
|
|
|
|
|
/* Make the feedback area larger than the label; otherwise point labels
|
|
|
|
|
* won't be visible at all.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
GEO_EXPAND(rect, 1, &biggerArea);
|
|
|
|
|
DBWFeedbackAdd(&biggerArea, msg, EditCellUse->cu_def, 1,
|
|
|
|
|
STYLE_PALEHIGHLIGHTS);
|
|
|
|
|
nmwVerifyErrors += 1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwVerifyTermFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called for each terminal in a net to make sure
|
|
|
|
|
* that the terminal's name appears in the list of terminals found
|
|
|
|
|
* in the net.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0 to keep the search alive.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* All entries in nmwVerifyNames that match name are NULL'ed out
|
|
|
|
|
* to show that they were found.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmwVerifyTermFunc(name, report)
|
|
|
|
|
char *name; /* Name of terminal. */
|
|
|
|
|
bool report; /* TRUE => print error messages */
|
|
|
|
|
{
|
|
|
|
|
int i, found;
|
|
|
|
|
|
|
|
|
|
found = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Find and clear all matching entries in nmwVerifyNames. */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nmwVerifyCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if (nmwVerifyNames[i] == NULL) continue;
|
|
|
|
|
if (strcmp(nmwVerifyNames[i], name) != 0) continue;
|
|
|
|
|
found = TRUE;
|
|
|
|
|
nmwVerifyNames[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the terminal wasn't found, and this is the first error
|
|
|
|
|
* for the net, print an error. Only print one error per net.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* if (found || nmwVerifyNetHasErrors) return 0; */
|
|
|
|
|
if (found) return 0;
|
|
|
|
|
nmwVerifyNetHasErrors = TRUE;
|
|
|
|
|
if(report)
|
|
|
|
|
{
|
|
|
|
|
/*TxError("Net of \"%s\" isn't fully connected.\n", name);*/
|
|
|
|
|
TxError("Terminal \"%s\" not connected.\n", name);
|
|
|
|
|
(void) DBSrLabelLoc(EditCellUse, name, nmwVErrorLabelFunc,
|
|
|
|
|
(ClientData) name);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwVerifyNetFunc --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called during net-list verification. It
|
|
|
|
|
* is invoked once for each terminal in each net in the list.
|
|
|
|
|
* It ignores all but the first terminals in nets. For each
|
|
|
|
|
* net, it checks to be sure the net is wired correctly.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns 0 to keep the enumeration alive.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Outputs messages for short circuits or open circuits.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
nmwVerifyNetFunc(name, first)
|
|
|
|
|
char *name; /* Name of terminal. */
|
|
|
|
|
bool first; /* TRUE means this is first terminal
|
|
|
|
|
* of a new net.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/*if (!first) return 0;*/
|
|
|
|
|
if (first)
|
|
|
|
|
nmwNetFound = FALSE;
|
|
|
|
|
if (nmwNetFound) return 0;
|
|
|
|
|
|
|
|
|
|
/* First, collect all the terminals that can be reached from
|
|
|
|
|
* the current terminal, using wiring in the edit cell and
|
|
|
|
|
* feedthroughs in children (if there are multiple terminals
|
|
|
|
|
* by the same name, they're assumed to be connected). Start
|
|
|
|
|
* off by enumerating all instances of the first terminal. Lower-
|
|
|
|
|
* level procedures do the rest.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
nmwVerifyCount=0;
|
|
|
|
|
nmwNonTerminalCount=0;
|
|
|
|
|
(void) DBSrLabelLoc(EditCellUse, name, nmwVerifyLabelFunc,
|
|
|
|
|
(ClientData) NULL);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Check whether the label was found, if not report an error.
|
|
|
|
|
*/
|
|
|
|
|
if (nmwVerifyCount == 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Terminal \"%s\" not found\n", name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
nmwNetFound = TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Next, enumerate all of the terminals in the net, and make sure
|
|
|
|
|
* that they got found by the search. NmwVerifyTermFunc takes
|
|
|
|
|
* care of errors and NULLs out entries that it found terminals
|
|
|
|
|
* for.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
nmwVerifyNetHasErrors = FALSE;
|
|
|
|
|
(void) NMEnumTerms(name, nmwVerifyTermFunc, (ClientData) 1);
|
|
|
|
|
|
|
|
|
|
/* If there are any non-NULL names left in the array nmwVerifyNames,
|
|
|
|
|
* they represent shorts between this net and other nets. Print
|
|
|
|
|
* errors for them.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (i = 0; i < nmwVerifyCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if (nmwVerifyNames[i] != NULL)
|
|
|
|
|
{
|
|
|
|
|
Rect biggerArea;
|
|
|
|
|
char msg[200];
|
|
|
|
|
|
|
|
|
|
TxError("Net \"%s\" shorted to net \"%s\".\n",
|
|
|
|
|
name, nmwVerifyNames[i]);
|
|
|
|
|
GEO_EXPAND(&nmwVerifyAreas[i], 1, &biggerArea);
|
|
|
|
|
(void) sprintf(msg, "Net \"%.80s\" shorted to net \"%.80s\".\n",
|
|
|
|
|
name, nmwVerifyNames[i]);
|
|
|
|
|
DBWFeedbackAdd(&biggerArea, msg, EditCellUse->cu_def,
|
|
|
|
|
1, STYLE_PALEHIGHLIGHTS);
|
|
|
|
|
nmwVerifyErrors += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** If there are any errors in this net, than print all the NonTerminals
|
|
|
|
|
** that are attached to electrically connected paint.
|
|
|
|
|
*/
|
|
|
|
|
if (nmwVerifyNetHasErrors && nmwNonTerminalCount != 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("Error found on net of %s:\n", name);
|
|
|
|
|
TxError("Additional electrically connected labels:\n");
|
|
|
|
|
for (i = 0; i < nmwNonTerminalCount; i++)
|
|
|
|
|
{
|
|
|
|
|
TxError("\t%s\n", nmwNonTerminalNames[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMWVerify --
|
|
|
|
|
*
|
|
|
|
|
* This procedure examines wiring in the edit cell to make sure
|
|
|
|
|
* that the connects are implemented exactly as specified in the
|
|
|
|
|
* current net-list. This means that nets are fully connected,
|
|
|
|
|
* and do not connect to any other nets in the list.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Error messages are output for open or shorted nets.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
NMVerify()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Enumerate all the nets and let the search function do the
|
|
|
|
|
* real work.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
nmwVerifyErrors = 0;
|
|
|
|
|
(void) NMEnumNets(nmwVerifyNetFunc, (ClientData) NULL);
|
|
|
|
|
|
|
|
|
|
/* Free the space allocated for error reporting
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < nmwNonTerminalSize; i++)
|
|
|
|
|
{
|
|
|
|
|
if (nmwNonTerminalNames[i] != NULL)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) nmwNonTerminalNames[i]);
|
|
|
|
|
nmwNonTerminalNames[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nmwVerifyErrors == 0)
|
|
|
|
|
TxPrintf("No wiring errors found.\n");
|
|
|
|
|
else
|
|
|
|
|
if (nmwVerifyErrors == 1)
|
|
|
|
|
TxPrintf("One feedback area generated (you're getting close!).\n");
|
|
|
|
|
else
|
|
|
|
|
TxPrintf("%d feedback areas generated.\n", nmwVerifyErrors);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMCull --
|
|
|
|
|
*
|
|
|
|
|
* Update the current netlist to remove nets that are already wired.
|
|
|
|
|
* This allows the user to hand-route some nets and then fix the netlist
|
|
|
|
|
* to skip those nets.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifys the current netlist information.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
NMCull()
|
|
|
|
|
{
|
|
|
|
|
int nmwCullNetFunc();
|
|
|
|
|
|
|
|
|
|
/* This implementation is the complement of the verify command. Instead
|
|
|
|
|
* of finding bad nets and reporting them, find good nets and remove them.
|
|
|
|
|
*/
|
|
|
|
|
nmwCullDone = 0; /* Number of correctly wired nets */
|
|
|
|
|
(void) NMEnumNets(nmwCullNetFunc, (ClientData) NULL);
|
|
|
|
|
|
|
|
|
|
if (nmwCullDone == 0)
|
|
|
|
|
TxPrintf("No fully-wired nets found.\n");
|
|
|
|
|
else
|
|
|
|
|
if (nmwCullDone == 1)
|
|
|
|
|
TxPrintf("One fully-wired net deleted from the netlist.\n");
|
|
|
|
|
else
|
|
|
|
|
TxPrintf("%d fully-wired nets deleted from the netlist.\n",
|
|
|
|
|
nmwCullDone);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwCullNetFunc --
|
|
|
|
|
*
|
|
|
|
|
* Net enumeration function called during netlist updating. Ignores all
|
|
|
|
|
* but the first terminals in nets. Check to see if a net is wired
|
|
|
|
|
* correctly. If so, remove the net from the netlist.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
nmwCullNetFunc(name, first)
|
|
|
|
|
char *name; /* Name of a terminal in a net */
|
|
|
|
|
bool first; /* TRUE => first terminal of a net */
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!first) return 0;
|
|
|
|
|
|
|
|
|
|
/* The implementation parallels nmwVerifyNetFunc. Begin by collecting all
|
|
|
|
|
* terminals reachable from the current terminal, using wiring in the edit
|
|
|
|
|
* cell and feedthroughs in children (if there are multiple terminals by
|
|
|
|
|
* the same name, they are assumed to be connected).
|
|
|
|
|
*/
|
|
|
|
|
nmwVerifyCount=0; /* Number of valid entries in temp array */
|
|
|
|
|
(void) DBSrLabelLoc(EditCellUse, name, nmwVerifyLabelFunc,
|
|
|
|
|
(ClientData) NULL);
|
|
|
|
|
|
|
|
|
|
/* Enumerate all terminals in the net and make sure that they got found
|
|
|
|
|
* by the search. NmwVerifyTermFunc takes care of errors and NULLs out
|
|
|
|
|
* entries for terminals it finds.
|
|
|
|
|
*/
|
|
|
|
|
nmwVerifyNetHasErrors = FALSE; /* Set only in nmwVerifyTermFunc */
|
|
|
|
|
(void) NMEnumTerms(name, nmwVerifyTermFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/* If all terminals in the net were found on the list of terminals connected
|
|
|
|
|
* to the first terminal, then check further to see if there are any short
|
|
|
|
|
* circuits. Any non-NULL names in nmwVerifyNames indicate short circuits.
|
|
|
|
|
* Print errors for them, if any.
|
|
|
|
|
*/
|
|
|
|
|
if (!nmwVerifyNetHasErrors)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < nmwVerifyCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if (nmwVerifyNames[i] != NULL)
|
|
|
|
|
{
|
|
|
|
|
Rect biggerArea;
|
|
|
|
|
char msg[200];
|
|
|
|
|
|
|
|
|
|
TxError("Net \"%s\" shorted to net \"%s\".\n",
|
|
|
|
|
name, nmwVerifyNames[i]);
|
|
|
|
|
GEO_EXPAND(&nmwVerifyAreas[i], 1, &biggerArea);
|
|
|
|
|
(void) sprintf(msg, "Net \"%.80s\" shorted to net \"%.80s\".\n",
|
|
|
|
|
name, nmwVerifyNames[i]);
|
|
|
|
|
DBWFeedbackAdd(&biggerArea, msg, EditCellUse->cu_def,
|
|
|
|
|
1, STYLE_PALEHIGHLIGHTS);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* If we made it all the way through the loop then all terminals in
|
|
|
|
|
* the net were found and there were no errors. In this case it is
|
|
|
|
|
* okay to delete the net from the netlist.
|
|
|
|
|
*/
|
|
|
|
|
if( i == nmwVerifyCount )
|
|
|
|
|
{
|
|
|
|
|
nmwCullDone += 1; /* Count the number of nets deleted */
|
|
|
|
|
NMDeleteNet(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
#ifdef ROUTE_MODULE
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMMeasureNet --
|
|
|
|
|
*
|
|
|
|
|
* Collect statistics on the current selection, presumably a routed wire:
|
|
|
|
|
* find the total metal and poly areas in the selection and divide by the
|
|
|
|
|
* widths of these layers. Add via widths to the total wire length.
|
|
|
|
|
* The user must watch out for nets split by feed-throughs: the selection
|
|
|
|
|
* may not be the entire net!
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Increments wire length counters.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
NMMeasureNet()
|
|
|
|
|
{
|
|
|
|
|
int nmMeasureFunc();
|
|
|
|
|
TileTypeBitMask nmMeasureMask;
|
|
|
|
|
|
|
|
|
|
nmMArea = nmPArea = nmVCount = 0;
|
|
|
|
|
TTMaskZero(&nmMeasureMask);
|
|
|
|
|
TTMaskSetType(&nmMeasureMask, RtrMetalType);
|
|
|
|
|
TTMaskSetType(&nmMeasureMask, RtrPolyType);
|
|
|
|
|
TTMaskSetType(&nmMeasureMask, RtrContactType);
|
|
|
|
|
(void) SelEnumPaint(&nmMeasureMask, TRUE, (bool *) NULL,
|
|
|
|
|
nmMeasureFunc, (ClientData) NULL);
|
|
|
|
|
TxPrintf("Total: %d; Metal: %d; Poly: %d; Vias: %d\n",
|
|
|
|
|
nmMArea/RtrMetalWidth +nmPArea/RtrPolyWidth +nmVCount*RtrContactWidth,
|
|
|
|
|
nmMArea/RtrMetalWidth, nmPArea/RtrPolyWidth, nmVCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmMeasureFunc(r, type, clientData)
|
|
|
|
|
Rect *r;
|
|
|
|
|
TileType type;
|
|
|
|
|
ClientData clientData;
|
|
|
|
|
{
|
|
|
|
|
if(type == RtrMetalType)
|
|
|
|
|
nmMArea=nmMArea+(r->r_xtop-r->r_xbot)*(r->r_ytop-r->r_ybot);
|
|
|
|
|
else
|
|
|
|
|
if(type == RtrPolyType)
|
|
|
|
|
nmPArea=nmPArea+(r->r_xtop-r->r_xbot)*(r->r_ytop-r->r_ybot);
|
|
|
|
|
else
|
|
|
|
|
if(type == RtrContactType)
|
|
|
|
|
nmVCount++;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* NMMeasureAll --
|
|
|
|
|
*
|
|
|
|
|
* Measure the length of all wiring attached to all terminals. This
|
|
|
|
|
* implementation uses the verify code to enumerate all of the tiles
|
|
|
|
|
* connected to any terminal of each net. This routine calls the ones
|
|
|
|
|
* that do the real work.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Prints the value.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
NMMeasureAll(fp)
|
|
|
|
|
FILE * fp;
|
|
|
|
|
{
|
|
|
|
|
int nmAllFunc();
|
|
|
|
|
|
|
|
|
|
nmMArea = nmPArea = nmVCount= 0;
|
|
|
|
|
(void) NMEnumNets(nmAllFunc, (ClientData) fp);
|
|
|
|
|
TxPrintf("Total: %d; Metal: %d; Poly: %d; Vias: %d\n",
|
|
|
|
|
nmMArea/RtrMetalWidth +nmPArea/RtrPolyWidth +nmVCount*RtrContactWidth,
|
|
|
|
|
nmMArea/RtrMetalWidth, nmPArea/RtrPolyWidth, nmVCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
|
int
|
|
|
|
|
nmAllFunc(name, firstInNet, fp)
|
|
|
|
|
char *name;
|
|
|
|
|
bool firstInNet;
|
|
|
|
|
FILE * fp;
|
|
|
|
|
{
|
|
|
|
|
void nmwMeasureTileFunc();
|
|
|
|
|
int saveM, saveP, saveV;
|
|
|
|
|
|
|
|
|
|
/* Trace out all wiring connected to the net. Only process the first
|
|
|
|
|
* terminal in each net.
|
|
|
|
|
*/
|
|
|
|
|
if (!firstInNet) return 0;
|
|
|
|
|
|
|
|
|
|
/* Save old values for counters in case they need to be written to
|
|
|
|
|
* a log file.
|
|
|
|
|
*/
|
|
|
|
|
saveM=nmMArea; saveP=nmPArea; saveV=nmVCount;
|
|
|
|
|
|
|
|
|
|
nmwVerifyCount = 0;
|
|
|
|
|
nmMeasureCount = 0;
|
|
|
|
|
(void) DBSrLabelLoc(EditCellUse, name, nmwVerifyLabelFunc,
|
2025-01-06 17:25:15 +01:00
|
|
|
FUN2CD(nmwMeasureTileFunc));
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (fp!=NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Write the wire length statistics for this net to a file.
|
|
|
|
|
*/
|
|
|
|
|
saveM=nmMArea-saveM;
|
|
|
|
|
saveP=nmPArea-saveP;
|
|
|
|
|
saveV=nmVCount-saveV;
|
|
|
|
|
fprintf(fp,"Net %s total: %d; Metal: %d; Poly: %d; Vias: %d\n",
|
|
|
|
|
name,
|
|
|
|
|
saveM/RtrMetalWidth +saveP/RtrPolyWidth +saveV*RtrContactWidth,
|
|
|
|
|
saveM/RtrMetalWidth, saveP/RtrPolyWidth, saveV);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* nmwMeasureTileFunc --
|
|
|
|
|
*
|
|
|
|
|
* This routine is passed to nmwVerifyTileFunc and is called for each
|
|
|
|
|
* tile connected to some terminal in a net. If the tile is on a
|
|
|
|
|
* routing layer and not seen before, then add the tile to the current
|
|
|
|
|
* routing measurements.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Increments the routing statistics variables.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nmwMeasureTileFunc(tile)
|
|
|
|
|
Tile * tile;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
Rect r;
|
|
|
|
|
TileType tt;
|
|
|
|
|
|
|
|
|
|
/* Process a tile if it is on a routing layer */
|
|
|
|
|
|
|
|
|
|
tt=TiGetType(tile);
|
|
|
|
|
if ((tt==RtrMetalType) || (tt==RtrPolyType) || (tt==RtrContactType))
|
|
|
|
|
{
|
|
|
|
|
/* Check to see if the tile is already in the table. If not, then
|
|
|
|
|
* process it to add it into the statistics being collected.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < nmMeasureCount; i++)
|
|
|
|
|
if (nmMeasureTiles[i] == tile)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &r);
|
|
|
|
|
|
|
|
|
|
/* Add the tile's area to the globals for routing statistics.
|
|
|
|
|
*/
|
|
|
|
|
if( tt == RtrMetalType )
|
|
|
|
|
nmMArea = nmMArea +(r.r_xtop -r.r_xbot) *(r.r_ytop -r.r_ybot);
|
|
|
|
|
else
|
|
|
|
|
if( tt == RtrPolyType )
|
|
|
|
|
nmPArea = nmPArea +(r.r_xtop- r.r_xbot) *(r.r_ytop -r.r_ybot);
|
|
|
|
|
else
|
|
|
|
|
nmVCount++;
|
|
|
|
|
|
|
|
|
|
/* Add the tile to the array of tiles already seen.
|
|
|
|
|
*/
|
|
|
|
|
if (nmMeasureCount == nmMeasureSize)
|
|
|
|
|
{
|
|
|
|
|
/* Not enough space to hold this tile. Allocate a new array
|
|
|
|
|
* and copy the old one to the new.
|
|
|
|
|
*/
|
|
|
|
|
Tile ** newTiles;
|
|
|
|
|
int newSize;
|
|
|
|
|
|
|
|
|
|
newSize = 2 * nmMeasureSize;
|
|
|
|
|
if (newSize < 16) newSize = 16;
|
|
|
|
|
newTiles =
|
|
|
|
|
(Tile **) mallocMagic((unsigned) newSize * sizeof(Tile *));
|
|
|
|
|
for (i = 0; i < nmMeasureSize; i++)
|
|
|
|
|
newTiles[i] = nmMeasureTiles[i];
|
|
|
|
|
|
|
|
|
|
if (nmMeasureSize != 0)
|
|
|
|
|
freeMagic((char *) nmMeasureTiles);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
nmMeasureTiles = newTiles;
|
|
|
|
|
nmMeasureSize = newSize;
|
|
|
|
|
}
|
|
|
|
|
nmMeasureTiles[nmMeasureCount++]=tile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* ROUTE_MODULE */
|