SisyphCmdsImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Created by Pradeep Sindhu, December 9, 1985 10:01:52 pm PST
Pradeep Sindhu, September 26, 1986 2:06:15 pm PDT
Barth, January 13, 1986 3:30:05 pm PST
Bertrand Serlet December 8, 1986 6:41:13 pm PST
Jean-Marc Frailong June 20, 1986 8:25:11 pm PDT
Last Edited by: Jacobi July 15, 1986 2:40:48 pm PDT
DIRECTORY
Basics, CD, CDBasics, CDCells, CDDirectory, CDImports, CDInstances, CDLayers, CDMenus, CDOps, CDOrient, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, CDViewer, Core, CoreClasses, CoreOps, CoreGeometry, GList, IO, PW, Rope, RopeList, Sinix, SinixOps, Sisyph, TerminalIO, ViewerClasses, ViewerOps;
SisyphCmdsImpl: CEDAR PROGRAM
IMPORTS Basics, CD, CDBasics, CDCells, CDDirectory, CDImports, CDInstances, CDLayers, CDMenus, CDOps, CDOrient, CDPanelFonts, CDProperties, CDRects, CDSatellites, CDTexts, CDViewer, CoreOps, CoreGeometry, GList, IO, PW, Rope, RopeList, Sinix, SinixOps, Sisyph, TerminalIO, ViewerOps
SHARES Sinix = BEGIN
ROPE: TYPE = Rope.ROPE;
ROPES: TYPE = LIST OF ROPE;
Wire: TYPE = Core.Wire;
CellType: TYPE = Core.CellType;
Icon: TYPE ~ REF IconRep;
IconRep: TYPE ~ RECORD [
name: ROPENIL, -- The short name of the icon, i.e. excluding the ".icon" part
boxWidth: CD.Number, -- Width of lines for icon box
pinRect: CD.Position, -- Size of pins (horizontal pin)
guard: CD.Number, -- Spacing between pin and pin name
grid: CD.Number, -- The grid on which pins should be aligned
font: CDTexts.CDFont, -- ChipNDale font to be used for all texts
pins: ARRAY CoreGeometry.Side OF ROPES -- The sorted pin names on all four sides
];
Command Procs
cdIconForKey: ATOM = $IconFor;
MakeIcon: PROC [comm: CDSequencer.Command] = {
CDMenus.CallMenuAndExecute[$SisyphIconMenu, comm];
};
UnMakeIcon: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
exprs, news: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN;
FlushCache[selected.ob];
exprs ← NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]];
WHILE exprs#NIL DO
IF NOT Sisyph.IsResultExpression[exprs.first] THEN news ← CONS [exprs.first, news];
exprs ← exprs.rest;
ENDLOOP;
CDProperties.PutProp[selected.ob, cdIconForKey, NIL];
CDProperties.PutProp[selected.ob, Sisyph.expressionsProp, news];
};
ChangeVisibility: PROC [comm: CDSequencer.Command] = {
CDMenus.CallMenuAndExecute[$SisyphVisibilityMenu, comm];
};
MakeInvisibleToExtractor: PROC [comm: CDSequencer.Command] = {
nInstances: INT ← 0;
FOR w: LIST OF CD.Instance ← CDOps.InstList[comm.design], w.rest WHILE w#NIL DO
inst: CD.Instance ← w.first;
IF inst.selected THEN {
CDProperties.PutProp[inst, Sisyph.mode.extractProcProp, $ExtractNull];
nInstances ← nInstances+1;
FlushCache[inst.ob]
}
ENDLOOP;
TerminalIO.WriteF["Made %g instances invisible to Sisyph\n", IO.int[nInstances]]
};
MakeVisibleToExtractor: PROC [comm: CDSequencer.Command] = {
nInstances: INT ← 0;
FOR w: LIST OF CD.Instance ← CDOps.InstList[comm.design], w.rest WHILE w#NIL DO
inst: CD.Instance ← w.first;
IF inst.selected THEN {
CDProperties.PutProp[inst, Sisyph.mode.extractProcProp, NIL];
nInstances ← nInstances+1;
FlushCache[inst.ob]
}
ENDLOOP;
TerminalIO.WriteF["Made %g instances visible to Sisyph\n", IO.int[nInstances]]
};
FlushCache: PROC [obj: CD.Object] = {
CDProperties.PutProp[obj, Sinix.cacheProp, NIL];
IF CDCells.IsCell[obj] THEN {
cellPtr: CD.CellPtr ← NARROW [obj.specificRef];
FOR l: LIST OF CD.Instance ← cellPtr.contents, l.rest WHILE l#NIL DO
FlushCache[l.first.ob];
ENDLOOP;
};
};
FlushSisyphCaches: PROC [comm: CDSequencer.Command] = {
FOR w: LIST OF CD.Instance ← CDOps.InstList[comm.design], w.rest WHILE w#NIL DO
IF w.first.selected THEN FlushCache[w.first.ob];
ENDLOOP;
};
MakeCellIconWithCodeDef: PROC [comm: CDSequencer.Command] = {
iconName: ROPE;
selected: CD.Instance;
multiple: BOOL;
cellIconExprPrefix: ROPE ← Rope.Cat[Sisyph.cellIconRope, " ← "];
cellIconExpr: ROPE;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN;
FlushCache[selected.ob];
iconName ← CDDirectory.Name[selected.ob];
IF NOT Rope.Match["*.icon", iconName] THEN TerminalIO.WriteF["*** Convention for icons is to suffix them with '.icon'.\n"];
cellIconExpr ← PW.RequestRope[Rope.Cat["Type code: ", cellIconExprPrefix]];
cellIconExpr ← Rope.Cat[cellIconExprPrefix, cellIconExpr];
exprs ← NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]];
exprs ← CONS [cellIconExpr, StripResultExprs[exprs]];
CDProperties.PutProp[selected.ob, Sisyph.expressionsProp, exprs];
CDProperties.PutProp[selected.ob, cdIconForKey, NIL];
};
MakeCellIconWithGeometryDef: PROC [comm: CDSequencer.Command] = {
iconName: ROPE;
selected: CD.Instance;
multiple: BOOL;
schematicName: ROPE;
cellIconExprPrefix: ROPE ← Rope.Cat[Sisyph.cellIconRope, " ← "];
cellIconExpr: ROPE;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN;
FlushCache[selected.ob];
iconName ← CDDirectory.Name[selected.ob];
IF NOT Rope.Match["*.icon", iconName] THEN TerminalIO.WriteF["*** Convention for icons is to suffix them with '.icon'.\n"];
schematicName ← PW.RequestRope["Type schematic name: "];
IF CDDirectory.Fetch[comm.design, schematicName].object = NIL THEN {
TerminalIO.WriteF["*** No such object in design.\n"];
RETURN;
};
IF NOT Rope.Match["*.sch", schematicName] THEN TerminalIO.WriteF["*** Convention for schematics is to suffix them with '.sch'.\n"];
cellIconExpr ← Rope.Cat[cellIconExprPrefix, "ES[\"", schematicName, "\", cx]"];
exprs ← NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]];
exprs ← CONS [cellIconExpr, StripResultExprs[exprs]];
CDProperties.PutProp[selected.ob, Sisyph.expressionsProp, exprs];
CDProperties.PutProp[selected.ob, cdIconForKey, schematicName];
};
MakeWireIconWithCodeDef: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
wireIconExprPrefix: ROPE ← Rope.Cat[Sisyph.wireIconRope, " ← "];
wireIconExpr: ROPE;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN;
FlushCache[selected.ob];
wireIconExpr ← PW.RequestRope[Rope.Cat["Type code: ", wireIconExprPrefix]];
wireIconExpr ← Rope.Cat[wireIconExprPrefix, wireIconExpr];
exprs ← NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]];
exprs ← CONS [wireIconExpr, StripResultExprs[exprs]];
CDProperties.PutProp[selected.ob, Sisyph.expressionsProp, exprs];
CDProperties.PutProp[selected.ob, cdIconForKey, NIL];
};
CreateIconCommand: PROC [comm: CDSequencer.Command] ~ {
User interface to create icon from schematic
schematicName, iconShortName: ROPE;
icon: CD.Object;
cell: Core.CellType;
selected: CD.Instance; multiple: BOOL;
grid: CD.Number ← -1;
cellRef: REF;
viewer: ViewerClasses.Viewer ← CDViewer.GetViewer[comm];
IF viewer#NIL THEN WITH ViewerOps.GetViewer[viewer, $Grid] SELECT FROM
rgrid: REF CD.Number => grid ← rgrid^;
ENDCASE => NULL;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN;
schematicName ← CDDirectory.Name[selected.ob];
IF schematicName=NIL THEN {
TerminalIO.WriteF["*** Selected schematic has no name.\n"];
RETURN;
};
IF NOT Rope.Match["*.sch", schematicName] THEN TerminalIO.WriteF["*** Convention for schematics is to suffix them with '.sch'.\n"];
cellRef ← SinixOps.ExtractCDInstance[selected, comm.design, Sisyph.mode].result;
IF ISTYPE [cellRef, Core.CellType] THEN cell ← NARROW [cellRef]
ELSE {
TerminalIO.WriteF["*** Selected cell does not extract to Core CellType\n"];
RETURN;
};
iconShortName ← PW.RequestRope["Type icon short name: "];
IF Rope.IsEmpty[iconShortName]
THEN iconShortName ← IF Rope.Match["*.sch", schematicName]
THEN Rope.Substr[schematicName, 0, Rope.Length[schematicName]-4]
ELSE schematicName;
IF Rope.IsEmpty[schematicName] THEN {
TerminalIO.WriteF["No name provided, no default from schematic.\n"];
RETURN;
};
IF CDDirectory.Fetch[comm.design, Rope.Cat[iconShortName, ".icon"]].found THEN {
TerminalIO.WriteF["*** The icon %g.icon already exists!\n", IO.rope[iconShortName]];
RETURN;
};
icon ← IconFromSchematic[cell, schematicName, iconShortName, comm.design, grid];
IF icon=NIL THEN RETURN;
CDCells.SetSimplificationTreshhold[cell: icon, val: 30, inPixels: TRUE];
CDOps.IncludeObjectI[comm.design, icon, comm.pos];
};
ShowInstExpressions: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Instance Expressions:\n"];
PutRopes[NARROW [CDProperties.GetInstanceProp[selected, Sisyph.expressionsProp]]];
};
AddInstExpression: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Add Instance Expression\n"];
exprs ← NARROW [CDProperties.GetInstanceProp[selected, Sisyph.expressionsProp]];
exprs ← CONS [PW.RequestRope[Rope.Cat[" New Expression: "]], exprs];
CDProperties.PutInstanceProp[selected, Sisyph.expressionsProp, exprs]
};
EditInstExpressions: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Edit Instance Expressions\n"];
exprs ← NARROW[CDProperties.GetInstanceProp[selected, Sisyph.expressionsProp]];
exprs ← EditExpressions[exprs, "Expression"];
CDProperties.PutInstanceProp[selected, Sisyph.expressionsProp, exprs]
};
ShowObjExpressions: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Object Expressions:\n"];
PutRopes[NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]]];
IF NOT CDImports.IsImport[selected.ob] THEN RETURN;
IF NARROW [selected.ob.specificRef, CDImports.ImportPtr].boundInstance=NIL
THEN {TerminalIO.WriteF["Object is an unbound import.\n"]; RETURN};
TerminalIO.WriteF["Object Expressions of the bound import:\n"];
PutRopes[NARROW [CDProperties.GetObjectProp[NARROW [selected.ob.specificRef, CDImports.ImportPtr].boundInstance.ob, Sisyph.expressionsProp]]];
};
AddObjExpression: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Add Object Expression\n"];
exprs ← NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]];
exprs ← CONS [PW.RequestRope[Rope.Cat[" New Expression: "]], exprs];
CDProperties.PutObjectProp[selected.ob, Sisyph.expressionsProp, exprs]
};
EditObjExpressions: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
exprs: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Edit Object Expressions\n"];
exprs ← NARROW[CDProperties.GetObjectProp[selected.ob, Sisyph.expressionsProp]];
exprs ← EditExpressions[exprs, "Expression"];
CDProperties.PutObjectProp[selected.ob, Sisyph.expressionsProp, exprs]
};
ShowParmNames: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
parms: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Parm Names:"];
parms ← NARROW[CDProperties.GetObjectProp[selected.ob, Sisyph.parmNamesProp]];
WHILE parms#NIL DO
TerminalIO.WriteF[Rope.Cat["\n ", parms.first]];
parms ← parms.rest;
ENDLOOP;
TerminalIO.WriteF["\n"];
};
AddParmName: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
parms: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Add Parameter Name\n"];
parms ← NARROW [CDProperties.GetObjectProp[selected.ob, Sisyph.parmNamesProp]];
parms ← CONS [PW.RequestRope[Rope.Cat[" New Parameter: "]], parms];
CDProperties.PutObjectProp[selected.ob, Sisyph.parmNamesProp, parms]
};
EditParmNames: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
parms: ROPES;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~IsSingleSelected[selected, multiple] THEN RETURN;
TerminalIO.WriteF["Edit Object Expressions\n"];
parms ← NARROW[CDProperties.GetObjectProp[selected.ob, Sisyph.parmNamesProp]];
parms ← EditExpressions[parms, "Parameter"];
CDProperties.PutObjectProp[selected.ob, Sisyph.parmNamesProp, parms]
};
Create icon from schematic
AlignUpToGrid: PROC [x, grid: CD.Number] RETURNS [CD.Number] ~ {
RETURN [IF x>=0 THEN ((x+grid-1)/grid)*grid ELSE (x/grid)*grid]
};
AlignDownToGrid: PROC [x, grid: CD.Number] RETURNS [CD.Number] ~ {
RETURN [IF x>=0 THEN (x/grid)*grid ELSE ((x-grid+1)/grid)*grid]
};
AlignPositionUpToGrid: PROC [p: CD.Position, grid: CD.Number] RETURNS [CD.Position] ~ {
RETURN [[AlignUpToGrid[p.x, grid], AlignUpToGrid[p.y, grid]]]
};
AlignRectUpToGrid: PROC [r: CD.Rect, grid: CD.Number] RETURNS [CD.Rect] ~ {
RETURN [[x1: AlignDownToGrid[r.x1, grid], x2: AlignUpToGrid[r.x2, grid], y1: AlignDownToGrid[r.y1, grid], y2: AlignUpToGrid[r.y2, grid]]]
};
MoveInstances: PROC [list: CD.InstanceList, by: CD.Position] ~ {
Move all instances in the list by the required amount
WHILE list#NIL DO
list.first.location ← CDBasics.AddPoints[list.first.location, by];
list ← list.rest;
ENDLOOP;
};
BuildIconSides: PROC [icon: Icon] RETURNS [sideSize: ARRAY CoreGeometry.Side OF CD.Position, sideList: ARRAY CoreGeometry.Side OF CD.InstanceList] ~ {
Build all the pins and pin names for the icon.
BuildSideGeometry: PROC [on: CoreGeometry.Side, rotate: CD.Orientation, useTextEnd: BOOL, textOffset: CD.Position, pinStartPos: CD.Position] ~ {
Create geometry (pins and names) along an edge of the icon. All pins are aligned on grid coordinates. Text is centered on associated pin, at left or right according to request. Text is separated by guard CD units from the pin. The returned iLists alternates pins and names.
iList: CD.InstanceList ← NIL;
pinPos, satPos: CD.Position; -- real ones
pinPos ← pinStartPos;
FOR names: ROPES ← icon.pins[on], names.rest WHILE names#NIL DO
satObject: CD.Object = CDTexts.CreateText[text: names.first, font: icon.font];
pinObject: CD.Object = CDRects.CreateRect[size: icon.pinRect, l: CD.commentLayer];
satInst, pinInst: CD.Instance;
pinInst ← CDInstances.NewInst[ob: pinObject, location: pinPos, orientation: rotate];
satPos ← CDBasics.AddPoints[pinPos, textOffset];
satPos ← CDBasics.SubPoints[
satPos,
CDOrient.OrientedSize[
[IF useTextEnd THEN satObject.size.x ELSE 0,satObject.size.y/2],
rotate]];
satInst ← CDInstances.NewInst[ob: satObject, location: satPos, orientation: rotate];
Progress pin position
pinPos ← AlignPositionUpToGrid[CDBasics.AddPoints[pinPos, CDOrient.OrientedSize[[0, satObject.size.y], rotate]], icon.grid];
Set satellite property and add to result list
CDSatellites.Associate[master: pinInst, text: satInst];
iList ← CONS[pinInst, iList];
iList ← CONS[satInst, iList];
ENDLOOP;
IF iList#NIL THEN { -- Compute size (not default) and set logical base at [0,0]
r: CD.Rect = AlignRectUpToGrid[CDInstances.BoundingRectO[iList], icon.grid];
pos: CD.Position = CDBasics.BaseOfRect[r];
sideSize[on] ← CDBasics.SizeOfRect[r];
MoveInstances[iList, CDBasics.NegOffset[pos]];
}
ELSE sideSize[on] ← [0, 0];
sideList[on] ← iList;
};
BuildSideGeometry[on: top,
rotate: CDOrient.rotate270,
useTextEnd: TRUE,
textOffset: [0, -icon.guard],
pinStartPos: [0, -icon.pinRect.x]];
BuildSideGeometry[on: bottom,
rotate: CDOrient.rotate270,
useTextEnd: FALSE,
textOffset: [0, icon.pinRect.x+icon.guard],
pinStartPos: [0, 0]];
BuildSideGeometry[on: right,
rotate: CDOrient.original,
useTextEnd: TRUE,
textOffset: [-icon.guard, 0],
pinStartPos: [-icon.pinRect.x, 0]];
BuildSideGeometry[on: left,
rotate: CDOrient.original,
useTextEnd: FALSE,
textOffset: [icon.pinRect.x+icon.guard, 0],
pinStartPos: [0, 0]];
};
BuildIconFrame: PROC [icon: Icon, box: CD.Rect] RETURNS [list: CD.InstanceList ← NIL] ~ {
Build the geometry for the icon box
BuildBoxSide: PROC [size, at: CD.Position] ~ {
orient: CD.Orientation;
IF size.x>size.y THEN { -- This trick is necessary for stretchy moves...
orient ← CDOrient.rotate90;
size ← [size.y, size.x];
}
ELSE orient ← CDOrient.original;
list ← CONS [CDInstances.NewInst[ob: CDRects.CreateRect[size: size, l: CD.commentLayer], location: at, orientation: orient], list];
CDProperties.PutProp[list.first, Sisyph.mode.extractProcProp, $ExtractNull];
};
w: CD.Number = icon.boxWidth;
BuildBoxSide[size: [w, w+box.y2-box.y1], at: [box.x1, box.y1]]; -- left
BuildBoxSide[size: [w, w+box.y2-box.y1], at: [box.x2, box.y1]]; -- right
BuildBoxSide[size: [w+box.x2-box.x1, w], at: [box.x1, box.y1]]; -- bottom
BuildBoxSide[size: [w+box.x2-box.x1, w], at: [box.x1, box.y2]]; -- top
};
CommentText: PROC [text: ROPE, font: CDTexts.CDFont] RETURNS [ob: CD.Object] ~ {
IsItalic: PROC [fontName: ROPE] RETURNS [BOOL] = {
RETURN [Rope.Find[fontName, "i", Rope.Length[fontName]-1, FALSE]#-1]
};
italicFont: CDTexts.CDFont ←
IF ~IsItalic[font.supposedName] THEN CDTexts.MakeFont[
name: Rope.Cat[font.supposedName, "I"],
scale: font.scaleI]
ELSE font;
ob ← CDTexts.CreateText[text: text, font: italicFont];
};
BuildIconObject: PROC [icon: Icon, design: CD.Design] RETURNS [obj: CD.Object] ~ {
Build the CD object for the icon in the design. The object is included in the design. Raises an ERROR if the object already existed (should be checked by caller).
sideSize: ARRAY CoreGeometry.Side OF CD.Position;
sideList: ARRAY CoreGeometry.Side OF CD.InstanceList;
internalInstances: CD.InstanceList ← NIL;
iconFullName: ROPE = Rope.Cat[icon.name, ".icon"];
iconTextObject: CD.Object = CommentText[text: icon.name, font: icon.font];
iconText: CD.Instance;
inside, outside: CD.Rect;
width, height: CD.Number;
cellPtr: CD.CellPtr;
IF icon.grid<=0 THEN icon.grid ← design.technology.lambda;
[sideSize, sideList] ← BuildIconSides[icon];
Compute a reasonable size for the inside and outside of the icon.
width ← sideSize[left].x+sideSize[right].x+MAX[
sideSize[bottom].x,
sideSize[top].x,
AlignUpToGrid[2*iconTextObject.size.x, icon.grid]];
height ← MAX[
sideSize[left].y,
sideSize[right].y,
sideSize[bottom].y+sideSize[top].y+AlignUpToGrid[4*iconTextObject.size.y, icon.grid]];
inside.x1 ← sideSize[left].x;
inside.y1 ← sideSize[bottom].y;
inside.x2 ← width+icon.pinRect.y-sideSize[right].x;
inside.y2 ← height+icon.pinRect.y-sideSize[top].y;
outside.x1 ← IF sideList[left]=NIL THEN 0 ELSE icon.pinRect.x;
outside.y1 ← IF sideList[bottom]=NIL THEN 0 ELSE icon.pinRect.x;
outside.x2 ← IF sideList[right]=NIL THEN width ELSE width-icon.pinRect.x;
outside.y2 ← IF sideList[top]=NIL THEN height ELSE height-icon.pinRect.x;
Move the sides at their final locations and setup the icon name
MoveInstances[
sideList[bottom],
[AlignDownToGrid[(width+sideSize[left].x-sideSize[right].x-sideSize[bottom].x)/2, icon.grid], 0]];
MoveInstances[
sideList[top],
[AlignDownToGrid[(width+sideSize[left].x-sideSize[right].x-sideSize[top].x)/2, icon.grid], inside.y2]];
MoveInstances[
sideList[left],
[0, AlignDownToGrid[(height-sideSize[left].y)/2, icon.grid]]];
MoveInstances[
sideList[right],
[inside.x2, AlignDownToGrid[(height-sideSize[right].y)/2, icon.grid]]];
iconText ← CDInstances.NewInst[
ob: iconTextObject,
location: CDBasics.SubPoints[CDBasics.Center[inside], CDBasics.Center[CDBasics.RectAt[[0, 0], iconTextObject.size]]]];
Build the icon object
internalInstances ← BuildIconFrame[icon, outside];
internalInstances ← CONS [iconText, internalInstances];
FOR on: CoreGeometry.Side IN CoreGeometry.Side DO
FOR list: CD.InstanceList ← sideList[on], list.rest WHILE list#NIL DO
internalInstances ← CONS [list.first, internalInstances];
ENDLOOP;
ENDLOOP;
obj ← CDCells.CreateEmptyCell[];
cellPtr ← NARROW [obj.specificRef];
cellPtr.contents ← internalInstances;
[] ← CDCells.RepositionCell[obj, NIL]; -- This is only to set all cell values OK
IF CDDirectory.Fetch[design, iconFullName].found THEN {
TerminalIO.WriteF["*** The icon %g already exists!\n", IO.rope[iconFullName]];
ERROR;
};
IF NOT CDDirectory.Include[design, obj, iconFullName] THEN {
TerminalIO.WriteF["*** Direction insertion of icon %g failed.\n", IO.rope[iconFullName]];
ERROR;
};
};
IconFromSchematic: PROC [cell: Core.CellType, schematicName, iconName: ROPE, design: CD.Design, grid: CD.Number ← -1] RETURNS [obj: CD.Object] ~ {
Build an icon straight from the schematic. Return NIL object if error. The schematicName had better be the right one.
InternalPin: TYPE ~ REF InternalPinRep;
InternalPinRep: TYPE ~ RECORD [
name: ROPE,
rect: CD.Rect -- The InstRectO of the pin, used to sort along the side
];
Side: TYPE ~ RECORD [
border: CD.Rect, -- Representation of schematic side
pins: LIST OF InternalPin ← NIL
];
SearchPins: CoreOps.EachWireProc ~ {
pinGeom: CD.InstanceList ← CoreGeometry.GetPins[Sisyph.mode.decoration, wire];
pinName: ROPE = CoreOps.GetShortWireName[wire];
IF pinGeom=NIL THEN RETURN;
IF pinName=NIL THEN {
TerminalIO.WriteF["*** The wire %g has pins, but no short name\n", IO.rope[CoreOps.GetFullWireName[root: cell.public, wire: wire]]];
RETURN[quit: TRUE];
};
WHILE pinGeom#NIL DO -- Paranoid! the first pin should touch a side of the schematic
pinRect: CD.Rect = CDInstances.InstRectO[pinGeom.first];
FOR on: CoreGeometry.Side IN CoreGeometry.Side DO
IF CDBasics.Intersect[pinRect, sides[on].border] THEN {
sides[on].pins ← CONS [NEW [InternalPinRep ← [name: pinName, rect: pinRect]], sides[on].pins];
RETURN [subWires: FALSE];
};
ENDLOOP;
pinGeom ← pinGeom.rest;
ENDLOOP;
TerminalIO.WriteF["*** The wire %g has pins, but none of them touches the icon of the schematic.\n", IO.rope[CoreOps.GetFullWireName[root: cell.public, wire: wire]]];
RETURN [quit: TRUE];
};
XSort: GList.CompareProc ~ { -- Reverse order comparison
RETURN [Basics.CompareINT[NARROW[ref2, InternalPin].rect.x1, NARROW[ref1, InternalPin].rect.x1]];
};
YSort: GList.CompareProc ~ { -- Reverse order comparison
RETURN [Basics.CompareINT[NARROW[ref2, InternalPin].rect.y1, NARROW[ref1, InternalPin].rect.y1]];
};
lineWidth: CD.Number = CDLayers.LayerWidth[design, CD.commentLayer];
icon: Icon ← NEW [IconRep ← [name: iconName, boxWidth: lineWidth, pinRect: [x: 4*lineWidth, y: lineWidth], guard: 2*lineWidth, grid: grid, font: CDPanelFonts.CurrentFont[design]]];
sides: ARRAY CoreGeometry.Side OF Side;
cellIR: CD.Rect = CoreGeometry.GetIR[Sisyph.mode.decoration, cell];
exprs: ROPESNIL;
First, build rectangles representing the sides of the schematic
sides[top].border ← [x1: cellIR.x1, x2: cellIR.x2, y1: cellIR.y2, y2: cellIR.y2];
sides[bottom].border ← [x1: cellIR.x1, x2: cellIR.x2, y1: cellIR.y1, y2: cellIR.y1];
sides[right].border ← [x1: cellIR.x2, x2: cellIR.x2, y1: cellIR.y1, y2: cellIR.y2];
sides[left].border ← [x1: cellIR.x1, x2: cellIR.x1, y1: cellIR.y1, y2: cellIR.y2];
Scan the public to build the sides structure
IF CoreOps.VisitWireSeq[cell.public, SearchPins] THEN
RETURN [NIL];
Sort the pins on each side and setup the names in the icon structure
FOR on: CoreGeometry.Side IN CoreGeometry.Side DO
icon.pins[on] ← NIL;
FOR list: LIST OF InternalPin ← NARROW [GList.UniqueSort[list: sides[on].pins, compareProc: IF on=top OR on=bottom THEN XSort ELSE YSort]], list.rest WHILE list#NIL DO
icon.pins[on] ← CONS [list.first.name, icon.pins[on]];
ENDLOOP;
ENDLOOP;
Finally create the object from the icon structure
obj ← BuildIconObject[icon, design];
exprs ← CONS [Rope.Cat[Sisyph.cellIconRope, " ← ES[\"", schematicName, "\", cx]"], exprs];
CDProperties.PutProp[obj, Sisyph.expressionsProp, exprs];
CDProperties.PutProp[obj, $IconFor, schematicName];
};
Internal Utilities
PutRopes: PROC [ropes: ROPES] = {
WHILE ropes#NIL DO
TerminalIO.WriteF["\t%g\n", IO.rope[ropes.first]]; ropes ← ropes.rest;
ENDLOOP;
};
IsSingleSelectedAndCell: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = {
IF ~IsSingleSelected[selected, multiple] THEN RETURN [FALSE];
IF ~CDCells.IsCell[selected.ob] THEN {
TerminalIO.WriteF["*** Selected instance is not a cell—can't do it.\n"];
RETURN[FALSE];
};
RETURN[TRUE];
};
IsSingleSelected: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = {
IF selected=NIL THEN {
TerminalIO.WriteF["*** No current selection--can't do it.\n"];
RETURN[FALSE];
};
IF multiple THEN {
TerminalIO.WriteF["*** Multiple instances selected--can't do it.\n"];
RETURN[FALSE];
};
RETURN[TRUE];
};
StripResultExprs: PROC [in: ROPES] RETURNS [out: ROPES] = {
out ← NIL;
FOR l: ROPES ← in, l.rest WHILE l#NIL DO
IF ~Sisyph.IsResultExpression[l.first] THEN out ← CONS [l.first, out]
ENDLOOP;
};
EditExpressions: PROC [oldExprs: ROPES, prompt: ROPE] RETURNS [allExprs: ROPESNIL] = {
input: ROPE;
noOldExprs: BOOL ← oldExprs=NIL;
TerminalIO.WriteF["\n"];
WHILE oldExprs#NIL DO
input ← PW.RequestRope[Rope.Cat[" ", prompt, ": ", oldExprs.first, " Replacement: "]];
SELECT TRUE FROM
Rope.Equal[input, "-"] => TerminalIO.WriteF[" ** Deleted\n"];
Rope.IsEmpty[input] => allExprs ← CONS [oldExprs.first, allExprs];
ENDCASE => allExprs ← CONS [input, allExprs];
oldExprs ← oldExprs.rest;
ENDLOOP;
IF noOldExprs THEN {
input ← PW.RequestRope[Rope.Cat[" New ", prompt, ": "]];
WHILE ~Rope.IsEmpty[input] AND ~Rope.Equal[input, "-"] DO
allExprs ← CONS [input, allExprs];
input ← PW.RequestRope[Rope.Cat[" New ", prompt, ": "]];
ENDLOOP;
};
allExprs ← RopeList.Reverse[allExprs];
};
Initialization
FilterSch: SinixOps.FilterProc = {RETURN [Rope.Match["*.sch", name] OR Rope.Match["*.icon", name]]};
Main Menu
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Make Icon", p: MakeIcon, key: $SisyphMakeIcon, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Flush Sisyph Caches", p: FlushSisyphCaches, key: $FlushSisyphCaches, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Change Visibility For Sisyph", p: ChangeVisibility, key: $SisyphChangeVisibility, queue: doQueueAndMark];
SinixOps.RegisterExtractCommand[mode: Sisyph.mode, prompt: "Sisyph Extract", key: $SisyphExtractSelectedObj];
SinixOps.RegisterHighlightCommand[mode: Sisyph.mode, prompt: "Highlight net in schematic", key: $HighlightNetInSchematic];
SinixOps.RegisterBackgroundExtractionCommand[CD.FetchTechnology[$cmosB], Sisyph.mode, "Sch background extraction", $SchBackgroundExtract, FilterSch]; -- only works for CMosB. Not very clean
Make Icon Menu
[] ← CDMenus.CreateMenu["Sisyph: Make Icon", $SisyphIconMenu];
CDMenus.ImplementCommandToCallMenu[$SisyphIconMenu, $SisyphIconMenu];
CDMenus.ImplementEntryCommand[menu: $SisyphIconMenu, entry: "Create cell icon from schematic", p: CreateIconCommand, key: $CreateIconCommand, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SisyphIconMenu, entry: "Associate cell icon with schematic", p: MakeCellIconWithGeometryDef, key: $MakeCellIconWithGeometryDef, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SisyphIconMenu, entry: "Associate cell icon with code", p: MakeCellIconWithCodeDef, key: $MakeCellIconWithCodeDef, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SisyphIconMenu, entry: "Associate wire icon with code", p: MakeWireIconWithCodeDef, key: $MakeWireIconWithCodeDef, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SisyphIconMenu, entry: "Dissociate icon from source", p: UnMakeIcon, key: $UnMakeIcon, queue: doQueueAndMark];
Change Visibility Menu
[] ← CDMenus.CreateMenu["Sisyph: Change Visibility", $SisyphVisibilityMenu];
CDMenus.ImplementCommandToCallMenu[$SisyphVisibilityMenu, $SisyphVisibilityMenu];
CDMenus.ImplementEntryCommand[menu: $SisyphVisibilityMenu, entry: "Make Invisible to Sisyph", p: MakeInvisibleToExtractor, key: $MakeInvisibleToExtractor, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SisyphVisibilityMenu, entry: "Make Visible to Sisyph", p: MakeVisibleToExtractor, key: $MakeVisibleToExtractor, queue: doQueueAndMark];
Make Parameter Menu
[] ← CDMenus.CreateMenu["Sisyph: Parameter Specification", $SisyphParameterMenu];
CDMenus.ImplementCommandToCallMenu[$SisyphParameterMenu, $SisyphParameterMenu];
CDMenus.ImplementEntryCommand[menu: $SisyphParameterMenu, entry: "Show Parameter Names", p: ShowParmNames, key: $SisyphShowParmNames];
CDMenus.ImplementEntryCommand[menu: $SisyphParameterMenu, entry: "Add Parameter Name", p: AddParmName, key: $SisyphAddParmName, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SisyphParameterMenu, entry: "Edit Parameter Names", p: EditParmNames, key: $SisyphEditParmNames, queue: doQueueAndMark];
Expressions Menu
CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Show Instance Expressions (LI-Left)", p: ShowInstExpressions, key: $SisyphShowInstExpressions];
CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Add Instance Expression (LI-Middle)", p: AddInstExpression, key: $SisyphAddInstExpression, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Edit Instance Expressions (LI-Right)", p: EditInstExpressions, key: $SisyphEditInstExpressions, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Show Object Expressions (LO-Left)", p: ShowObjExpressions, key: $SisyphShowObjExpressions];
CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Add Object Expression (LO-Middle)", p: AddObjExpression, key: $SisyphAddObjExpression, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Edit Object Expressions (LO-Right)", p: EditObjExpressions, key: $SisyphEditObjExpressions, queue: doQueueAndMark];
END.