我是靠谱客的博主 温暖鲜花,最近开发中收集的这篇文章主要介绍Magic源码阅读(六)——DRC检查的实现(下),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

对于前面提到的后台自动运行的持续的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中最终同样调用了DRCInteractionCheckDRCArrayCheck函数。这正好对应了上面的三条规则的第二条和第三条。

最后依旧是整体的架构图

架构图

在这里插入图片描述

最后

以上就是温暖鲜花为你收集整理的Magic源码阅读(六)——DRC检查的实现(下)的全部内容,希望文章能够帮你解决Magic源码阅读(六)——DRC检查的实现(下)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部