SCInstUtilImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Bryan Preas, January 19, 1987 12:18:55 pm PST
compoments utility routines
-- InstWidth - find width of component at current orientation
-- InstHeight - find height of component at current orientation
-- BpHeight - find height of bp when considering side it is on
-- BpWidth - find width of bp when considering side it is on
-- MinMaxBPOffset - find min and max offsets of bonding pads on side
-- BpOffsets - find offsets of bonding pads on side
-- BpPos - find position of inst on side
-- PosOf- find the position (side, x, and y) of a component on a pin
-- RotateRect- Rotate a rectangle of a cell
-- LgOffsets- determine offsets of components in row
-- AllOffsets - determine all component offsets
-- AsgnChanPos - assign current positions to horizontal and vertical channels
-- CheckInsts - check row and position of comps
-- CheckInst - check row and position of a inst
-- EnumeratePinsOnInst - enumerate the net pins on an instance
DIRECTORY
CD, CDBasics, CoreClasses, Rope, SC, SCInstUtil, SCPrivate, SCRowUtil, SCUtil, RTBasic, RTSets;
SCInstUtilImpl: CEDAR PROGRAM
IMPORTS CDBasics, SC, SCInstUtil, SCRowUtil, SCUtil, Rope, RTBasic, RTSets
EXPORTS SCInstUtil
SHARES SC =
BEGIN
defltLgOrien: PUBLIC SCPrivate.Orientation ← 1;
defltBpOrien: PUBLIC ARRAY SC.Side OF SCPrivate.Orientation ← [3, 1, 4, 2];
find width of component at current orientation
InstWidth: PUBLIC PROCEDURE[inst: SCPrivate.Instance] RETURNS[width: SC.Number] =
BEGIN
find current orientation
orien: SCPrivate.OrientationOrNone ← inst.curOrien;
now get width based on orientation
SELECT orien FROM
0, 1, 3, 5, 6 => width ← inst.object.size.p;
2, 4, 7, 8 => width ← inst.object.size.q;
ENDCASE;
END;
find height of component at current orientation
InstHeight: PUBLIC PROCEDURE[inst: SCPrivate.Instance] RETURNS[height: SC.Number] =
BEGIN
find current orientation
orien: SCPrivate.OrientationOrNone ← inst.curOrien;
now get height based on orientation
SELECT orien FROM
0, 1, 3, 5, 6 => height ← inst.object.size.q;
2, 4, 7, 8 => height ← inst.object.size.p;
ENDCASE;
END;
find height of bp when considering its side
(this is, the dimension perpendicular to side)
BpHeight: PUBLIC PROCEDURE[inst: SCPrivate.Instance] RETURNS[height: SC.Number] = {
IF inst.whichClass # io THEN
SC.Error[programmingError, Rope.Cat["Instance: ", inst.name, " should be an IO"]];
SELECT inst.curSide FROM
top, bottom => height ← InstHeight[inst];
left, right => height ← InstWidth[inst];
ENDCASE => SC.Error[programmingError, NIL]};
find height of bp when considering side it is on
this is along to side
BpWidth: PUBLIC PROCEDURE[inst: SCPrivate.Instance] RETURNS[width: SC.Number] = {
IF inst.whichClass # io THEN
SC.Error[programmingError, Rope.Cat["Instance: ", inst.name, " should be an IO"]];
SELECT inst.curSide FROM
top, bottom => width ← InstWidth[inst];
left, right => width ← InstHeight[inst];
ENDCASE => SC.Error[programmingError, NIL]};
find offsets of bonding pads on side
MinMaxBPOffset: PUBLIC PROCEDURE[handle: SC.Handle, side: SC.Side] RETURNS [minOffset, maxOffset: SC.Number] = {
InstProc: SCRowUtil.EachInstProc = {
minOffset ← MIN[minOffset, instance.offset];
maxOffset ← MAX[maxOffset, instance.offset]};
minOffset ← LAST[INT];
maxOffset ← FIRST[INT];
[] ← SCRowUtil.EnumerateAllInstsOnSide[handle, side, InstProc]};
find offsets of bonding pads on side
BpOffsets: PUBLIC PROCEDURE[handle: SC.Handle, side: SC.Side, pos1, pos2: SCPrivate.ZMaxPosSr] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
bpRow: SCPrivate.BpRow ← layoutData.bpRows[side];
offset: SC.Number;
posA: SCPrivate.ZMaxPosSr ← MIN[pos1, pos2];
posB: SCPrivate.ZMaxPosSr ← MAX[pos1, pos2];
IF posA <= 1 THEN {posA ← 1; offset ← 0}
ELSE
{inst: SCPrivate.Instance ← bpRow.bpsOnSide[posA-1];
IF side = bottom OR side = right THEN offset ← inst.offset + InstWidth[inst] + bpRow.bpSpacing
ELSE offset ← inst.offset + bpRow.bpSpacing};
IF posB = 0 OR posB > bpRow.nBpsOnSide THEN posB ← bpRow.nBpsOnSide;
FOR posIndex: SCPrivate.ZMaxPosSr IN [posA .. posB] DO
inst: SCPrivate.Instance ← bpRow.bpsOnSide[posIndex];
width: SC.Number ← BpWidth[inst];
IF side = bottom OR side = right THEN inst.offset ← offset
ELSE inst.offset ← offset + width;
offset ← offset + width + bpRow.bpSpacing;
ENDLOOP};
check offsets of bonding pads on side
CheckBpOffsets: PUBLIC PROCEDURE[handle: SC.Handle, side: SC.Side] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
bpRow: SCPrivate.BpRow ← layoutData.bpRows[side];
offset: SC.Number ← 0;
FOR posIndex: SCPrivate.ZMaxPosSr IN [1 .. bpRow.nBpsOnSide] DO
inst: SCPrivate.Instance ← bpRow.bpsOnSide[posIndex];
width: SC.Number ← BpWidth[inst];
IF side = bottom OR side = right THEN {
IF inst.offset # offset THEN SC.Error[programmingError, "Not suppose to happen"]}
ELSE {
IF inst.offset # offset + width THEN SC.Error[programmingError, "Not suppose to happen"]};
offset ← offset + width + bpRow.bpSpacing;
ENDLOOP};
find position of inst on side
assumes that channel and bp positions have been assigned.
BpPos: PUBLIC PROCEDURE[handle: SC.Handle, inst: SCPrivate.Instance] RETURNS[result: SC.Number] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
bpRow: SCPrivate.BpRow ← layoutData.bpRows[inst.curSide];
IF inst.whichClass # io THEN
SC.Error[programmingError, "objet must be of type io"];
SELECT inst.curSide FROM
left, right => result ← bpRow.sideOrg.q + inst.offset;
bottom, top => result ← bpRow.sideOrg.p + inst.offset;
ENDCASE};
find position of pin on an inst
assumes that channel and instance positions have been assigned.
InstPosOf: PUBLIC PROCEDURE[handle: SC.Handle, inst: SCPrivate.Instance, pin: SCPrivate.ObjectPin] RETURNS[pos: RTBasic.PQPos] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
this code is copied from PosOf for efficiency
first find the position at normal orientation
xy: CD.Position ← SELECT pin.pinPos.side FROM
bottom => [pin.pinPos.location, pin.pinPos.depth],
right => [InstWidth[inst] - pin.pinPos.depth, pin.pinPos.location],
top => [pin.pinPos.location, InstHeight[inst] - pin.pinPos.depth],
left => [pin.pinPos.depth, pin.pinPos.location],
ENDCASE => SC.Error[programmingError, "No suppose to happen"];
now rotate the pin position to current orien
xyPos: CD.Position ← SELECT inst.curOrien FROM
1 => [xy.x, xy.y], -- original
2 => [xy.y, InstWidth[inst] - xy.x], -- rotate270
3 => [InstWidth[inst] - xy.x, InstHeight[inst] - xy.y], -- rotate180
4 => [InstHeight[inst] - xy.y, xy.x], -- rotate90
5 => [InstWidth[inst] - xy.x, xy.y], -- mirrorX
6 => [xy.x, InstHeight[inst] - xy.y], -- rotate180X
7 => [xy.y, xy.x], -- rotate270X
8 => [InstHeight[inst] - xy.y, InstWidth[inst] - xy.x], -- rotate90X
ENDCASE => SC.Error[programmingError, "No suppose to happen"];
SELECT inst.whichClass FROM
logic, ft => {
lgRow: SCPrivate.LgRow ← layoutData.lgRows.rows[inst.curRow];
pos ← [lgRow.rowOrg.p + inst.offset + xyPos.x, lgRow.rowOrg.q + xyPos.y]};
io => {
bpRow: SCPrivate.BpRow ← layoutData.bpRows[inst.curSide];
pos ← SELECT inst.curSide FROM
left, right => [bpRow.sideOrg.p + xyPos.x, bpRow.sideOrg.q + inst.offset + xyPos.y],
bottom, top => [bpRow.sideOrg.p + inst.offset + xyPos.x, bpRow.sideOrg.q + xyPos.y],
ENDCASE => SC.Error[programmingError, "No suppose to happen"]};
ENDCASE};
find the position (side, x, and y) of a component on a pin
PosOf: PUBLIC PROCEDURE[inst: SCPrivate.Instance, pin: SCPrivate.ObjectPin]
RETURNS [pinDes: SCInstUtil.PinDescription] = {
first find the position at normal orientation
xy: CD.Position ← SELECT pin.pinPos.side FROM
bottom => [pin.pinPos.location, pin.pinPos.depth],
right => [InstWidth[inst] - pin.pinPos.depth, pin.pinPos.location],
top => [pin.pinPos.location, InstHeight[inst] - pin.pinPos.depth],
left => [pin.pinPos.depth, pin.pinPos.location],
ENDCASE => SC.Error[programmingError, "No suppose to happen"];
now rotate the pin position to current orien
xyOrien: CD.Position ← SELECT inst.curOrien FROM
1 => [xy.x, xy.y], -- original
2 => [xy.y, InstWidth[inst] - xy.x], -- rotate270
3 => [InstWidth[inst] - xy.x, InstHeight[inst] - xy.y], -- rotate180
4 => [InstHeight[inst] - xy.y, xy.x], -- rotate90
5 => [InstWidth[inst] - xy.x, xy.y], -- mirrorX
6 => [xy.x, InstHeight[inst] - xy.y], -- rotate180X
7 => [xy.y, xy.x], -- rotate270X
8 => [InstHeight[inst] - xy.y, InstWidth[inst] - xy.x], -- rotate90X
ENDCASE => SC.Error[programmingError, "No suppose to happen"];
pinDes ← [xyOrien.x, xyOrien.y, SCUtil.SideTranslate[pin.pinPos.side, inst.curOrien]]};
find the position of a rotated rectangle wintin a component
RotateRect: PUBLIC PROCEDURE[inst: SCPrivate.Instance, defRect: SC.Rect]
RETURNS [SC.Rect] = {
now rotate the pin position to current orien
newRect: SC.Rect;
SELECT inst.curOrien FROM
1 => -- original
{newRect.x1 ← defRect.x1; newRect.y1 ← defRect.y1;
newRect.x2 ← defRect.x2; newRect.y2 ← defRect.y2};
2 => -- rotate270
{newRect.x1 ← defRect.y1; newRect.y1 ← InstWidth[inst] - defRect.x1;
newRect.x2 ← defRect.y2; newRect.y2 ← InstWidth[inst] - defRect.x2};
3 => -- rotate180
{newRect.x1 ← InstWidth[inst] - defRect.x1; newRect.y1 ← InstHeight[inst] - defRect.y1;
newRect.x2 ← InstWidth[inst] - defRect.x2; newRect.y2 ← InstHeight[inst] - defRect.y2};
4 => -- rotate90
{newRect.x1 ← InstHeight[inst] - defRect.y1; newRect.y1 ← defRect.x1;
newRect.x2 ← InstHeight[inst] - defRect.y2; newRect.y2 ← defRect.x2};
5 => -- mirrorX
{newRect.x1 ← InstWidth[inst] - defRect.x1; newRect.y1 ← defRect.y1;
newRect.x2 ← InstWidth[inst] - defRect.x2; newRect.y2 ← defRect.y2};
6 => -- rotate180X
{newRect.x1 ← defRect.x1; newRect.y1 ← InstHeight[inst] - defRect.y1;
newRect.x2 ← defRect.x2; newRect.y2 ← InstHeight[inst] - defRect.y2};
7 => -- rotate270X
{newRect.x1 ← defRect.y1; newRect.y1 ← defRect.x1;
newRect.x2 ← defRect.y2; newRect.y2 ← defRect.x2};
8 => -- rotate90X
{newRect.x1 ← InstHeight[inst] - defRect.y1; newRect.y1 ← InstWidth[inst] - defRect.x1;
newRect.x2 ← InstHeight[inst] - defRect.y2; newRect.y2 ← InstWidth[inst] - defRect.x2};
ENDCASE => SC.Error[programmingError, "No suppose to happen"];
RETURN[CDBasics.ReInterpreteRect[newRect]]};
determine offsets of components in row
LgOffsets: PUBLIC PROCEDURE[handle: SC.Handle, row: SCPrivate.ZMaxRowSr, pos1, pos2: SCPrivate.ZMaxPosSr] = {
compute offsets of all comps on row
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
lgRow: SCPrivate.LgRow ← lgRows.rows[row];
offset: SC.Number;
posA: SCPrivate.ZMaxPosSr ← MIN[pos1, pos2];
posB: SCPrivate.ZMaxPosSr ← MAX[pos1, pos2];
IF posA <= 1 THEN {posA ← 1; offset ← 0}
ELSE
{inst: SCPrivate.Instance ← lgRow.lgsOnRow[posA-1];
offset ← inst.offset + InstWidth[inst]};
IF posB = 0 OR posB > lgRow.nLgsOnRow THEN posB ← lgRow.nLgsOnRow;
FOR posIndex: SCPrivate.MaxPosSr IN [posA .. posB] DO
inst: SCPrivate.Instance ← lgRow.lgsOnRow[posIndex];
SELECT inst.whichClass FROM
ft, logic => {inst.offset ← offset; offset ← offset + InstWidth[inst]};
ENDCASE;
ENDLOOP;
update max row widths
IF posB = lgRow.nLgsOnRow THEN
{lgRow.size.p ← offset;
IF lgRow.size.p >= lgRows.maxRowWidth THEN
{lgRows.maxRowWidth ← lgRow.size.p; lgRows.numMaxRows ← 1}
ELSE [lgRows.maxRowWidth, lgRows.numMaxRows] ← SCRowUtil.FindMaxRow[handle]}};
determine all component offsets
AllOffsets: PUBLIC PROCEDURE [handle: SC.Handle] = {
RowRroc: SCRowUtil.EachRowProc = {
LgOffsets[handle, row, 0, SCPrivate.maxPos]};
SideProc: SCRowUtil.EachSideProc = {
BpOffsets[handle, side, 0, SCPrivate.maxPos]};
[] ← SCRowUtil.EnumerateRows[handle, RowRroc];
[] ← SCRowUtil.EnumerateSides[handle, SideProc]};
assign current positions to horizontal and vertical channels
AsgnChanPos: PUBLIC PROCEDURE[handle: SC.Handle] =
BEGIN
compute the minimum channel dimensions
EachSide: SCRowUtil.EachSideProc = {
IF bpRow.dimInvalid THEN SCRowUtil.ComputeSideHeight[handle, side];
sideDim[side] ← MAX[0, bpRow.size.p + (bpRow.nBpsOnSide -1) * bpRow.bpSpacing]};
EachRow: SCRowUtil.EachRowProc = {
IF lgRow.dimInvalid THEN SCRowUtil.ComputeRowHeight[handle, lgRow.rowNum]};
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
parms: SCPrivate.Parms ← NARROW[handle.parms];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
bpRows: SCPrivate.BpRows ← layoutData.bpRows;
sideChans: SCPrivate.SideChans ← layoutData.sideChans;
rowChans: SCPrivate.RowChans ← layoutData.rowChans;
nChans: SCPrivate.MaxChanSr ← rowChans.count;
pitch: SC.Number ← RTBasic.IRSize[parms.ftObject.cdOb].x;
sideDim: ARRAY SC.Side OF SC.Number;
[] ← SCRowUtil.EnumerateSides[handle, EachSide];
[] ← SCRowUtil.EnumerateRows[handle, EachRow];
row 1 and channel 1 data
rowChans.chans[1].chanPos ← 0;
sideChans[left].sideChanPos ← 0;
lgRows.horzRowOrg ← 0;
lgRows.rows[1].rowOrg.p ← lgRows.horzRowOrg + ((lgRows.maxRowWidth - lgRows.rows[1].size.p)/2)/pitch*pitch;
lgRows.rows[1].rowOrg.q ← rowChans.chans[1].chanPos;
now the interior channels
FOR chan: SCPrivate.MaxChanSr IN [2 .. nChans] DO
rowChans.chans[chan].chanPos ← lgRows.rows[chan-1].rowOrg.q + lgRows.rows[chan-1].size.q;
IF chan <= lgRows.count THEN {
lgRows.rows[chan].rowOrg.q ← rowChans.chans[chan].chanPos + rowChans.chans[chan].chanWidth;
lgRows.rows[chan].rowOrg.p ← lgRows.horzRowOrg + ((lgRows.maxRowWidth - lgRows.rows[chan].size.p)/2)/pitch*pitch};
ENDLOOP;
now the right side
sideChans[right].sideChanPos ← lgRows.horzRowOrg + lgRows.maxRowWidth;
get total height and width
layoutData.totHeight ← rowChans.chans[nChans].chanPos; -- + rowChans.chans[nChans].chanWidth;
layoutData.totWidth ← sideChans[right].sideChanPos;
now update the side orgs
bpRows[bottom].sideOrg.q ← 0;
bpRows[bottom].sideOrg.p ← lgRows.horzRowOrg + (lgRows.maxRowWidth - sideDim[bottom]) / 2;
update right side data
bpRows[right].sideOrg.p ← layoutData.totWidth;
bpRows[right].sideOrg.q ← (layoutData.totHeight - sideDim[right])/ 2;
update top side data
bpRows[top].sideOrg.p ← lgRows.horzRowOrg + (lgRows.maxRowWidth - sideDim[top])/ 2;
bpRows[top].sideOrg.q ← layoutData.totHeight;
update left side data
bpRows[left].sideOrg.p ← 0;
bpRows[left].sideOrg.q ← (layoutData.totHeight - sideDim[left])/ 2;
END;
find chans that these comps touch
ChansForInsts: PUBLIC PROCEDURE[handle: SC.Handle, insts: SCPrivate.InstanceList]
RETURNS [touchesChan: SCPrivate.ChanSet ← RTSets.RTMdSetEmpty] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
FOR instList: SCPrivate.InstanceList ← insts, instList.rest WHILE instList # NIL DO
inst: SCPrivate.Instance ← instList.first;
SELECT inst.whichClass FROM
ft, logic => {IF inst.curRow > 0 THEN
{touchesChan ← RTSets.RTMdSetUnion[touchesChan, RTSets.RTMdSetGenerateElement[(inst.curRow+1)-1]];
touchesChan ← RTSets.RTMdSetUnion[touchesChan , RTSets.RTMdSetGenerateElement[(inst.curRow)-1]]}};
io => {IF inst.curSide = bottom THEN
touchesChan ← RTSets.RTMdSetUnion[touchesChan, RTSets.RTMdSetGenerateElement[(1)-1]];
IF inst.curSide = top THEN
touchesChan ← RTSets.RTMdSetUnion[touchesChan, RTSets.RTMdSetGenerateElement[(layoutData.rowChans.count)-1]]};
ENDCASE;
ENDLOOP};
check row and position of a inst
CheckInst: PUBLIC PROCEDURE[handle: SC.Handle, inst: SCPrivate.Instance] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
SELECT inst.whichClass FROM
logic, ft =>
{row: SC.Number ← inst.curRow;
pos: SC.Number ← inst.curPos;
lgRow: SCPrivate.LgRow ← layoutData.lgRows.rows[row];
IF row <= 0 OR row > layoutData.rowChans.count THEN
{IF ~(row = 0 AND pos = 0 AND inst.whichClass = ft) THEN
SC.Error[programmingError, " "]}
ELSE IF pos <= 0 OR pos > lgRow.nLgsOnRow THEN
SC.Error[programmingError, " "]
ELSE
{trialInst: SCPrivate.Instance ← lgRow.lgsOnRow[pos];
IF inst # trialInst THEN
SC.Error[programmingError, " "]}};
io =>
{side: SC.Side ← inst.curSide;
pos: SC.Number ← inst.curPos;
bpRow: SCPrivate.BpRow ← layoutData.bpRows[side];
IF side = none THEN
SC.Error[programmingError, " "]
ELSE IF pos <= 0 OR pos > bpRow.nBpsOnSide THEN
SC.Error[programmingError, " "]
ELSE
{trialInst: SCPrivate.Instance ← bpRow.bpsOnSide[pos];
IF inst # trialInst THEN
SC.Error[programmingError, " "]}};
ENDCASE};
check row and position of a inst
CheckInsts: PUBLIC PROCEDURE[handle: SC.Handle] = {
EachInst: SCInstUtil.EachInstanceProc = {
CheckInst[handle, instance]};
[] ← SCInstUtil.EnumerateAllInstances[handle, EachInst]};
EnumerateAllInstances: PUBLIC PROC [handle: SC.Handle, eachInstance: SCInstUtil.EachInstanceProc] RETURNS [quit: BOOL] = {
structureData: SCPrivate.StructureData ← NARROW[handle.structureData];
quit ← EnumerateInstances[handle, 1, structureData.instances.count, eachInstance]};
EnumerateInstances: PUBLIC PROC [handle: SC.Handle, startInst, stopInst: SCPrivate.MaxInstanceSr, eachInstance: SCInstUtil.EachInstanceProc] RETURNS [quit: BOOLFALSE] = {
structureData: SCPrivate.StructureData ← NARROW[handle.structureData];
FOR inst: SCPrivate.MaxInstanceSr IN [startInst .. stopInst] WHILE ~quit DO
quit ← eachInstance[structureData.instances.inst[inst]];
ENDLOOP};
EnumeratePinsOnInst: PUBLIC PROC [instance: SCPrivate.Instance, eachPin: SCInstUtil.EachPinProc] RETURNS [quit: BOOLFALSE] = {
FOR pin: NAT IN [0 .. instance.pinNets.size) WHILE ~quit DO
quit ← eachPin[instance, pin, instance.pinNets.n[pin]];
ENDLOOP};
DefineInstance: PUBLIC PROCEDURE [handle: SC.Handle, instanceName: Rope.ROPE, object: SCPrivate.Object, coreInstance: CoreClasses.CellInstance, equivName: Rope.ROPENIL]
RETURNS [instance: SCPrivate.Instance ← NIL] = {
define a component (an instance of object)
structureData: SCPrivate.StructureData ← NARROW[handle.structureData];
instances: SCPrivate.Instances ← structureData.instances;
object.numTimesUsed ← object.numTimesUsed + 1;
construct he instance record
SELECT object.typeClass FROM
logic =>
{instance ← NEW[logic SCPrivate.InstanceRec];
instance.whichClass ← logic;
instances.numLogics ← instances.numLogics + 1};
ft =>
{instance ← NEW[ft SCPrivate.InstanceRec];
instance.whichClass ← ft;
instances.numFts ← instances.numFts + 1};
io =>
{instance ← NEW[io SCPrivate.InstanceRec];
instance.equivPortClass ← equivName;
instance.whichClass ← io;
instances.numIOs ← instances.numIOs + 1};
ENDCASE => SC.Error[callingError, Rope.Cat["Feedthrus not allowed in input: ", instance.name, ", object: ", object.name, "\n"]];
instance.name ← instanceName;
instance.object ← object;
initialize the nets connected to these pins
instance.pinNets ← NEW[SCPrivate.PinNetsRec[object.numPins]];
instances.count ← instances.count + 1;
instance.num ← instances.count;
instances.inst[instances.count] ← instance};
NumInstsOnList: PUBLIC PROCEDURE [instances: SCPrivate.InstanceList] RETURNS [count: SCPrivate.ZMaxInstanceSr ← 0] = {
FOR instList: SCPrivate.InstanceList ← instances, instList.rest WHILE instList # NIL DO
count ← count + 1;
ENDLOOP};
CDOrien: PUBLIC PROCEDURE[instance: SCPrivate.Instance] RETURNS [orien: CD.Orientation] = {
get the CD orientation
SELECT instance.curOrien FROM
0 => orien ← SC.Error[programmingError, "Not suppose to happen"];
1 => orien ← original;
2 => orien ← rotate270;
3 => orien ← rotate180;
4 => orien ← rotate90;
5 => orien ← mirrorX;
6 => orien ← rotate180X;
7 => orien ← rotate270X;
8 => orien ← rotate90X;
ENDCASE};
END.