对于前面提到的后台自动运行的持续的DRC检查器,也是在DRCcontin.c
中实现的,核心方法为DRCContinuous
,由WindDispatch()
调用,这个函数会一直运行,检查当前窗口中是否有待DRC的区域,如果有则就会使用恰当的方式进行检查。当用户键入了一个新的命令后,这个函数会以最快的方式进入中断。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104void 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。 第三,它为检查提供了规范形式,特别是涉及子单元格的检查,因此无论原始检查区域是什么,都可以产生相同的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135int 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的检查。
原话是这样的:
1
2
3
4
5
6
7
8
9
10
11The 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检查内容请搜索靠谱客的其他文章。
发表评论 取消回复