-- File CIFDrcControl.mesa
-- Written by Dan Fitzpatrick and Martin Newell, August 1980
-- Last updated: August 3, 1981 1:52 PM

DIRECTORY

CIFControlDefs: FROM "CIFControlDefs" USING [DrawCIF],
CIFDevicesDefs: FROM "CIFDevicesDefs" USING [DeviceDescriptor, DeviceDescriptorRecord,
RegisterDevice, GetCIFOutDevice],
CIFDrcDefs: FROM "CIFDrcDefs",
CIFDrcScanDefs: FROM "CIFDrcScanDefs" USING [DrcScanStart, DrcScanEnd, DrcTrigger, EnterEdge],
CIFDrcUtilsDefs: FROM "CIFDrcUtilsDefs" USING [Edge, MakeEdge],
CIFOutputDefs: FROM "CIFOutputDefs" USING [SetSorting],
CIFUtilitiesDefs: FROM "CIFUtilitiesDefs" USING [Rectangle,
SetClipRectangle, GetClipRectangle, DrawClipRectangle,
SetDisplayContext, GetDisplayContext, MapRectangle],
Graphics: FROM "Graphics" USING [DisplayContext, NewContext, PushContext,
PopContext, CopyContext, Scale],
IODefs: FROM "IODefs" USING [WriteLine
, WriteDecimal],
IntDefs: FROM "IntDefs" USING[ILastBB],
JaMDrcDefs: FROM "JaMDrcDefs" USING[JaMDrcStartUp],
JaMFnsDefs: FROM "JaMFnsDefs" USING [PopString],
Real: FROM "Real" USING [Fix],
StringDefs: FROM "StringDefs" USING [AppendChar, AppendString],
SystemDefs: FROM "SystemDefs" USING [AllocateHeapNode];

CIFDrcControl: PROGRAM
IMPORTS CIFControlDefs, CIFDevicesDefs, CIFDrcScanDefs, CIFDrcUtilsDefs, CIFOutputDefs, CIFUtilitiesDefs, Graphics, IODefs, IntDefs, JaMDrcDefs, JaMFnsDefs, Real, StringDefs, SystemDefs =

BEGIN OPEN CIFControlDefs, CIFDevicesDefs, CIFDrcScanDefs, CIFDrcUtilsDefs, CIFOutputDefs, CIFUtilitiesDefs, Graphics, IODefs, IntDefs, JaMDrcDefs, JaMFnsDefs, Real, StringDefs, SystemDefs;


-- CIF DRC procedures

DrcDeviceRecord: DeviceDescriptorRecord ← [
next:NIL,
name:"drc",
deviceSelect: DrcSelect,
deviceDrawFrame: DrcDrawFrame,
deviceSetScale: DrcSetScale,
deviceSetClipRegion: DrcSetClipRegion,
deviceOutput: DrcOutput,
deviceLayer: DrcLayer,
deviceLoadLayer: DrcLoadLayer,
deviceRectangle: DrcRectangle,
deviceStartPoly: DrcStartPoly,
devicePolyVertex: DrcPolyVertex,
deviceEndPoly: DrcEndPoly,
deviceText: DrcText
];

DrcSelect: PROCEDURE RETURNS[BOOLEAN] =
BEGIN
--
DrcSetClipRegion[GetClipRectangle[]];
RETURN[TRUE];
END;

DrcDrawFrame: PROCEDURE =
BEGIN
DrawClipRectangle[];
END;

DrcSetScale: PROCEDURE [factor: REAL] =
BEGIN
dc: DisplayContext ← GetDisplayContext[];
PopContext[dc];
PushContext[dc];
Scale[dc, [factor,factor]];
END;

DrcSetClipRegion: PROCEDURE [rt: Rectangle] =
BEGIN
SetClipRectangle[rt];
END;

DrcOutput: PROCEDURE =
--expects <baseName> (STRING)
BEGIN
baseName: STRING ← [100];
saveContext: DisplayContext ← GetDisplayContext[];
r: Rectangle ← GetClipRectangle[]; --clipping region in CIF units
etop: REAL;
PopString[baseName];
SetDisplayContext[drcContext];
SetClipRectangle[r];
drcClipRectangle ← MapRectangle[r,drcContext,identityContext];
etop ← drcClipRectangle.ury;
DrcStart[baseName];
DrawCIF[Fix[r.llx],Fix[r.urx],Fix[r.lly],Fix[r.ury]];
DrcEnd[etop];
SetDisplayContext[saveContext];
SetClipRectangle[r];
END;

DrcStart: PROCEDURE[fileName: STRING] =
BEGIN
--Initialize EdgeList and ActiveList
WriteLine["Start Drc"];
SetSorting[incy];
DrcCurrentLayer ← 32000; --i.e. not set
DrcScanStart[fileName];
ObliqueCount ← 0;
END;

DrcEnd: PROCEDURE [ymax: REAL] =
BEGIN
DrcScanEnd[ymax];
IF ObliqueCount#0 THEN
{WriteDecimal[ObliqueCount]; WriteLine[" oblique polygons ignored"]; };
END;

DrcLayer: PROCEDURE [layer: CARDINAL] =
--used to trigger scan conversion up to bottom of object about to be received
BEGIN
l,r,b,t: LONG INTEGER;
bottom: REAL;
rec: Rectangle;
[l,r,b,t] ← ILastBB[]; --in chip coordinates
--kludge - need bottom of current object in Extractor coords
rec ← MapRectangle[[l,b,r,t], drcContext, identityContext]; --**may need to be in cifdrccontrol to get at drcContext (see CIFExtControl)
bottom ← MIN[rec.lly,rec.ury]-1; -- -1 to be on safe side
DrcTrigger[bottom];
DrcCurrentLayer ← layer;
END;

DrcLoadLayer: PROCEDURE[layer:CARDINAL, v0,v1,v2,v3: CARDINAL] =
BEGIN
END;


--DrcTrapezoid: PUBLIC PROCEDURE [t:POINTER TO TrapezoidBlock] =
--make two edges of appropriate types
--
BEGIN OPEN t;
--
edge: Edge;
--
IF DrcCurrentLayer > 4 THEN RETURN;
--
edge ← MakeEdge[xsleft,ystart,xeleft,yend,TRUE];
--
IF edge#NIL THEN EnterEdge[DrcCurrentLayer, edge];
--
edge ← MakeEdge[xsright,ystart,xeright,yend,FALSE];
--
IF edge#NIL THEN EnterEdge[DrcCurrentLayer, edge];
--
END;

DrcRectangle: PROCEDURE [r: Rectangle] =
--make two edges of appropriate types
BEGIN
edge: Edge;
IF DrcCurrentLayer>4 THEN RETURN;
edge ← MakeEdge[r.llx,r.lly, r.llx,r.ury, TRUE];
IF edge#NIL THEN EnterEdge[DrcCurrentLayer, edge];
edge ← MakeEdge[r.urx,r.lly, r.urx,r.ury, FALSE];
IF edge#NIL THEN EnterEdge[DrcCurrentLayer, edge];
END;

Vertex: TYPE = POINTER TO VertexRecord;
VertexRecord: TYPE = RECORD[
next: Vertex,
x,y: REAL
];

--Poly procs buffer input and reject it if non-orthogonal
--Must be removed when non-orthogonal features are handled

x0,y0: REAL;
Polygon,LastVertex: Vertex;
ObliquePolygon: BOOLEAN;
ObliqueCount: CARDINAL;

DrcStartPoly: PROCEDURE [x,y: REAL] =
BEGIN
IF DrcCurrentLayer>4 THEN RETURN;
x0 ← x;
y0 ← y;
ObliquePolygon ← FALSE;
Polygon ← LastVertex ← AllocateVertex[NIL,x,y];
END;

DrcPolyVertex: PROCEDURE [x,y: REAL] =
BEGIN
IF DrcCurrentLayer>4 THEN RETURN;
IF x#LastVertex.x AND y#LastVertex.y THEN ObliquePolygon ← TRUE;
IF ~ObliquePolygon THEN
{LastVertex.next ← AllocateVertex[NIL,x,y];
LastVertex ← LastVertex.next;
};
END;

DrcEndPoly: PROCEDURE =
BEGIN
v: Vertex;
IF DrcCurrentLayer>4 THEN RETURN;
DrcPolyVertex[x0,y0];
IF ObliquePolygon THEN
{UNTIL Polygon=NIL DO
v ← Polygon;
Polygon ← Polygon.next;
FreeVertex[v];
ENDLOOP;
ObliqueCount ← ObliqueCount + 1;
}
ELSE
{edge: Edge;
v ← Polygon;
Polygon ← Polygon.next;
xs ← v.x;
ys ← v.y;
FreeVertex[v];
UNTIL Polygon=NIL DO
v ← Polygon;
Polygon ← Polygon.next;
edge ← NIL;
SELECT TRUE FROM
v.y>ys=> edge ← MakeEdge[xs,ys, v.x,v.y,FALSE];
v.y<ys=> edge ← MakeEdge[v.x,v.y, xs,ys,TRUE];
ENDCASE;
IF edge#NIL THEN EnterEdge[DrcCurrentLayer, edge];
xs ← v.x;
ys ← v.y;
FreeVertex[v];
ENDLOOP;
};
END;

VertexFreeList: Vertex ← NIL;

AllocateVertex: PROCEDURE [next: Vertex, x,y: REAL]
RETURNS[v: Vertex] =
BEGIN
IF VertexFreeList#NIL THEN
{v ← VertexFreeList;
VertexFreeList ← VertexFreeList.next;
}
ELSE v ← AllocateHeapNode[SIZE[VertexRecord]];
v↑ ← [
next: next,
x: x,
y: y
];
END;

FreeVertex: PROCEDURE [v: Vertex] =
BEGIN
v.next ← VertexFreeList;
VertexFreeList ← v;
END;


xs,ys: REAL;

oldDrcStartPoly: PROCEDURE [x,y: REAL] =
BEGIN
x0 ← xs ← x;
y0 ← ys ← y;
END;

oldDrcPolyVertex: PROCEDURE [x,y: REAL] =
BEGIN
edge: Edge ← NIL;
IF DrcCurrentLayer>4 THEN RETURN;
SELECT TRUE FROM
y>ys=> edge ← MakeEdge[xs,ys, x,y,FALSE];
y<ys=> edge ← MakeEdge[x,y, xs,ys,TRUE];
ENDCASE;
IF edge#NIL THEN EnterEdge[DrcCurrentLayer, edge];
xs ← x;
ys ← y;
END;

oldDrcEndPoly: PROCEDURE =
BEGIN
DrcPolyVertex[x0,y0];
END;

DrcText: PROCEDURE[text: STRING, x,y: REAL] =
BEGIN
END;

DefaultExtension: PROCEDURE[name,ext: STRING] RETURNS[STRING] =
--set extension if not already present
BEGIN
i: CARDINAL;
FOR i IN [0..name.length) DO
IF name[i]=’. THEN RETURN[name];
ENDLOOP;
AppendChar[name,’.];
AppendString[name,ext];
RETURN[name];
END;

--Drc Parameters
drcClipRectangle: Rectangle;
drcContext: DisplayContext ← NewContext[GetCIFOutDevice[]];
identityContext: DisplayContext ← CopyContext[drcContext];

DrcCurrentLayer: CARDINAL;


--set up context

RegisterDevice[@DrcDeviceRecord];

JaMDrcStartUp[];

END.