概述
对于前面提到的后台自动运行的持续的DRC检查器,也是在DRCcontin.c
中实现的,核心方法为DRCContinuous
,由WindDispatch()
调用,这个函数会一直运行,检查当前窗口中是否有待DRC的区域,如果有则就会使用恰当的方式进行检查。当用户键入了一个新的命令后,这个函数会以最快的方式进入中断。
void
DRCContinuous()
{
#ifndef MAGIC_WRAPPER
Rect drc_orig_bbox; /* Area of DRC def that changed. */
#endif
if (DRCHasWork == FALSE)
{
#ifdef MAGIC_WRAPPER
DRCStatus = DRC_NOT_RUNNING;
#endif
return;
}
#ifdef MAGIC_WRAPPER
if (DRCStatus != DRC_NOT_RUNNING) return; /* Avoid infinitely recursive loop */
GrFlush();
DRCStatus = DRC_IN_PROGRESS;
Tcl_EvalEx(magicinterp, "after idle magic::drcstate busy", -1, 0);
if (TxInputRedirect != TX_INPUT_REDIRECTED) TxSetPrompt(']');
/* fprintf(stderr, "Starting DRCn"); fflush(stderr); */
#endif
UndoDisable(); /* Don't want to undo error info. */
drc_orig_bbox = DRCdef->cd_bbox;
while (DRCPendingRoot != (DRCPendingCookie *) NULL)
{
/* DBSrPaintArea() returns 1 if drcCheckTile()
* returns 1, meaning that a CHECK tile
* was found and processed.
*/
while ((DRCPendingRoot != (DRCPendingCookie *)NULL) &&
DBSrPaintArea ((Tile *) NULL,
DRCPendingRoot->dpc_def->cd_planes[PL_DRC_CHECK],
&TiPlaneRect, &DBAllButSpaceBits, drcCheckTile, (ClientData) NULL))
{
/* check for new user command (without blocking) */
#ifdef MAGIC_WRAPPER
/* Execute pending Tcl events, so the DRC process doesn't block. */
/* NOTE: Exclude file events, or else "drc catchup" will not work */
/* in batch mode. */
UndoEnable();
while (Tcl_DoOneEvent(TCL_DONT_WAIT))
{
if (DRCStatus == DRC_BREAK_PENDING)
{
/* fprintf(stderr, "DRC exiting loop. . .n"); fflush(stderr); */
DRCStatus = DRC_NOT_RUNNING;
return;
}
}
UndoDisable();
/* fprintf(stderr, "DRC continuing internally. . .n"); fflush(stderr); */
#else
#ifndef USE_IO_PROBE
if (SigInterruptPending) goto checkDone;
#else
if (TxGetInputEvent (FALSE, FALSE) == TRUE) goto checkDone;
#endif
#endif
}
/* No check tiles were found, so knock this cell off the list. */
if (DRCPendingRoot != (DRCPendingCookie *)NULL) {
DBReComputeBbox(DRCPendingRoot->dpc_def);
freeMagic((char *) DRCPendingRoot);
DRCPendingRoot = DRCPendingRoot->dpc_next;
}
/* Give the timestamp manager a chance to update any mismatches. */
DBFixMismatch();
}
#ifdef MAGIC_WRAPPER
DRCStatus = DRC_NOT_RUNNING;
Tcl_EvalEx(magicinterp, "after idle magic::drcstate idle", -1, 0);
/* fprintf(stderr, "DRC is finishedn"); fflush(stderr); */
if (TxInputRedirect != TX_INPUT_REDIRECTED) TxSetPrompt('%');
#endif
checkDone:
UndoEnable();
/* As a convenience for debugging DRC stuff, we pretend the DRC
* cell is a real one and recompute its bounding box, and redisplay
* both its old area (currently in box) and its current area.
*/
DBReComputeBbox(DRCdef);
(void) GeoInclude(&DRCdef->cd_bbox, &drc_orig_bbox);
DBWAreaChanged(DRCdef, &drc_orig_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits);
#ifdef MAGIC_WRAPPER
WindUpdate();
GrFlush();
#endif
}
接下来是DRCCheckTile
,这个函数是Magic持续规则检查器的核心函数,当在当前plane中发现一个待检查的tile时,就会调用该方法,因此是被调用次数最多的方法。
出于DRC的目的,每个cell都以棋盘样式根据DRCStepSize划分为宫格。 所有检查均根据这些格子进行。 找到待检查tile时,我们会在包含原始tile左下角的格子中找到该tile的所有外部区域。 棋盘格方法用于三个目的。 首先,它允许将附近的小tile合并起来以进行检查。 其次,它限制了一次完成的最大工作量,因此,如果我们被新命令打断,仍有希望最终赶上DRC。 第三,它为检查提供了规范形式,特别是涉及子单元格的检查,因此无论原始检查区域是什么,都可以产生相同的结果。
int
drcCheckTile(tile, arg)
Tile * tile; /* tile in DRC_CHECK plane */
ClientData arg; /* Not used. */
{
Rect square; /* Square area of the checkerboard
* being processed right now.
*/
Rect erasebox; /* erase old ERROR tiles in this
* region and clip new ERRORs to it
*/
Rect checkbox;
CellDef * celldef; /* First CellDef on DRCPending list. */
Rect redisplayArea; /* Area to be redisplayed. */
extern int drcXorFunc(); /* Forward declarations. */
extern int drcPutBackFunc();
celldef = DRCPendingRoot->dpc_def;
DRCErrorDef = celldef;
/* Find the checkerboard square containing the lower-left corner
* of the check tile, then find all check tiles within that square.
*/
DRCstatSquares += 1;
square.r_xbot = (LEFT(tile)/DRCStepSize) * DRCStepSize;
if (square.r_xbot > LEFT(tile)) square.r_xbot -= DRCStepSize;
square.r_ybot = (BOTTOM(tile)/DRCStepSize) * DRCStepSize;
if (square.r_ybot > BOTTOM(tile)) square.r_ybot -= DRCStepSize;
square.r_xtop = square.r_xbot + DRCStepSize;
square.r_ytop = square.r_ybot + DRCStepSize;
erasebox = GeoNullRect;
(void) DBSrPaintArea((Tile *) NULL, celldef->cd_planes[PL_DRC_CHECK],
&square, &DBAllButSpaceBits, drcIncludeArea, (ClientData) &erasebox);
GeoClip(&erasebox, &square);
/* TxPrintf("Check area = (%d, %d) (%d, %d)n",
erasebox.r_xbot, erasebox.r_ybot,
erasebox.r_xtop, erasebox.r_ytop);
*/
/* checkbox is erasebox expanded by DRCTechHalo. Note that this is */
/* computed independently inside DRCInteractionCheck(). */
GEO_EXPAND(&erasebox, DRCTechHalo, &checkbox);
GeoClip(&checkbox, &square);
/* Use drcDisplayPlane to save all the current errors in the
* area we're about to recheck.
*/
DBClearPaintPlane(drcDisplayPlane);
(void) DBSrPaintArea((Tile *) NULL, celldef->cd_planes[PL_DRC_ERROR],
&square, &DBAllButSpaceBits, drcXorFunc, (ClientData) NULL);
/* Check #1: recheck the paint of the cell, ignoring subcells. */
DRCErrorType = TT_ERROR_P;
DBClearPaintPlane(drcTempPlane);
/* May 4, 2008: Moved DRCBasicCheck into DRCInteractionCheck
* to avoid requiring DRC rules to be satisfied independently
* of subcells (checkbox was [erasebox + DRCTechHalo], now
* computed within DRCInteractionCheck()).
*/
/* DRCBasicCheck (celldef, &checkbox, &erasebox, drcPaintError,
(ClientData) drcTempPlane); */
/* Check #2: check interactions between paint and subcells, and
* also between subcells and other subcells. If any part of a
* square is rechecked for interactions, the whole thing has to
* be rechecked. We use TT_ERROR_S tiles for this so that we
* don't have to recheck paint and array errors over the whole
* square.
*/
DRCErrorType = TT_ERROR_S;
(void) DRCInteractionCheck(celldef, &square, &erasebox,
drcPaintError, (ClientData) drcTempPlane);
/* Check #3: check for array formation errors in the area. */
DRCErrorType = TT_ERROR_P;
(void) DRCArrayCheck(celldef, &erasebox, drcPaintError,
(ClientData) drcTempPlane);
/* If there was an interrupt, return without modifying the cell
* at all.
*/
if (SigInterruptPending) return 1;
/* Erase the check tile from the check plane, erase the pre-existing
* error tiles, and paint back in the new error tiles. Do this all
* with interrupts disabled to be sure that it won't be aborted.
*/
SigDisableInterrupts();
DBPaintPlane(celldef->cd_planes[PL_DRC_CHECK], &erasebox,
DBStdEraseTbl(TiGetType(tile), PL_DRC_CHECK),
(PaintUndoInfo *) NULL);
DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &erasebox,
DBStdEraseTbl(TT_ERROR_P, PL_DRC_ERROR),
(PaintUndoInfo *) NULL);
DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &checkbox,
DBStdEraseTbl(TT_ERROR_S, PL_DRC_ERROR),
(PaintUndoInfo *) NULL);
(void) DBSrPaintArea((Tile *) NULL, drcTempPlane, &TiPlaneRect,
&DBAllButSpaceBits, drcPutBackFunc, (ClientData) celldef);
/* XOR the new errors in the tile with the old errors we
* saved in drcDisplayPlane. Where information has changed,
* clip to square and redisplay. If check tiles are being
* displayed, then always redisplay the entire area.
*/
(void) DBSrPaintArea((Tile *) NULL, celldef->cd_planes[PL_DRC_ERROR],
&square, &DBAllButSpaceBits, drcXorFunc, (ClientData) NULL);
if (DBBoundPlane(drcDisplayPlane, &redisplayArea))
{
GeoClip(&redisplayArea, &square);
if (!GEO_RECTNULL(&redisplayArea))
DBWAreaChanged (celldef, &redisplayArea, DBW_ALLWINDOWS,
&DRCLayers);
}
if (DRCDisplayCheckTiles)
DBWAreaChanged(celldef, &square, DBW_ALLWINDOWS, &DRCLayers);
DBCellSetModified (celldef, TRUE);
SigEnableInterrupts();
return (1); /* stop the area search: we modified the database! */
}
上面的代码中主要进行了三种meta-rules的检查。
原话是这样的:
The three DRC meta-rules are:
(1) paint in one CellDef must be consistent by itself,
that is, without regard to subcells
(2) subtrees must be consistent -- this includes both
paint interacting with subcells, and subcells
interacting with each other.
(3) an arrayed use of a CellDef must be consistent by itself,
that is, without regard to paint or other subcells
in the parent. This check happens automatically as
part of the subtree check.
个人理解第一条就是在不考虑subcell的情况下,其本身是没有问题的;第二条是说该cell与其subcell、该cell的subcell之间的interaction没有问题;第三条则是指array中的各个元素之间的interaction没有问题。
我们发现在DRCCheckTile
中最终同样调用了DRCInteractionCheck
和DRCArrayCheck
函数。这正好对应了上面的三条规则的第二条和第三条。
最后依旧是整体的架构图
架构图
最后
以上就是温暖鲜花为你收集整理的Magic源码阅读(六)——DRC检查的实现(下)的全部内容,希望文章能够帮你解决Magic源码阅读(六)——DRC检查的实现(下)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复