-- wiresCreate3.mesa

DIRECTORY SystemDefs:FROM"SystemDefs",
AltoFileDefs:FROM"AltoFileDefs",
DirectoryDefs:FROM"DirectoryDefs",
DisplayDefs:FROM"DisplayDefs",
GraphicsDefs:FROM"GraphicsDefs",
SegmentDefs:FROM"SegmentDefs",
StreamDefs:FROM"StreamDefs",
StringDefs:FROM"StringDefs",
WiresDefs:FROM"WiresDefs",
PressDefs:FROM"PressDefs",
IODefs:FROM"IODefs";
WiresCreate:PROGRAM
IMPORTS GraphicsDefs, PressDefs, SystemDefs, IODefs, StreamDefs,
DirectoryDefs,StringDefs,WiresDefs
EXPORTS WiresDefs =BEGIN OPEN WiresDefs;

Error:SIGNAL=CODE;
nullLoc: Location=[NULL,127,127];
circuitName: STRING←[30];
outFileName: STRING←[40];

EnumerateCircuit:PROCEDURE[call:OnI]=
BEGIN i:INTEGER; FOR i IN [0..topCircuit) DO call[i]; ENDLOOP; END;


--//////////////WIRE LIST Stuff///////////////

wireListArray:TYPE=ARRAY [0..maxWireNo] OF Wire;
wireList:POINTER TO wireListArray←NIL;
maxWireNo:INTEGER=200;
topWire:INTEGER;

EnumerateWires:PUBLIC PROCEDURE[call:PROCEDURE[INTEGER,WirePtr]]=BEGIN
i:INTEGER; FOR i IN [0..topWire) DO call[i,@wireList[i]]; ENDLOOP; END;

WireLength:PUBLIC PROCEDURE[i,j:Location] RETURNS[INTEGER]=BEGIN
RETURN[ABS[i.i-j.i]+ABS[i.j-j.j]]; END;

MakeWireList:PUBLIC PROCEDURE[print:BOOLEAN]= BEGIN
MakeTrack[]; -- chain the transistors
topWire←0;
EnumerateCircuit[WireListOneCircuit];
SortWireList[];
IF print THEN PrintWireList;
END;

AddToWireList:PROCEDURE[w:Wire]=BEGIN
wireList[topWire]←w;
topWire←topWire+1;
IF topWire>maxWireNo THEN Error;
END;

PrintWireList:PUBLIC PROCEDURE=BEGIN EnumerateWires[PrintWireListEntry]; END;

PrintWireListEntry:PROCEDURE[i: INTEGER, w:WirePtr]=BEGIN OPEN IODefs;
WriteNumber[i,[10,FALSE,TRUE,4]];
WriteString[" Circuit"]; WriteNumber[w.circuit,[10,FALSE,TRUE,3]];
WriteString[" length"]; WriteNumber[w.l,[10,FALSE,TRUE,3]];
WriteString[" from "]; WriteLocation[w.a];
WriteString[" to "]; WriteLocation[w.b];
WriteChar[CR];
END;

colorStrings:ARRAY Color OF STRING=["none "," red ","green","blue ","yel. "];

WriteLocation:PROCEDURE[l:Location]=BEGIN OPEN IODefs;
WriteNumber[l.i,[10,FALSE,TRUE,2]];
WriteChar[’,];
WriteNumber[l.j,[10,FALSE,TRUE,2]];
WriteString[SELECT l.contact FROM
chanA=>" chanA",
gate=>" gate",
chanB=>" chanB",
ENDCASE=>ERROR];
END;

thisW:INTEGER;

WireListOneCircuit:PROCEDURE[i:INTEGER]=BEGIN
-- IF i=vdd OR i=gnd THEN RETURN;
thisW←i;
InitTemp[];
EnumerateTrack[i,AddToTemp];
EnumerateTemp[InitSep];
EnumerateTemp[FindAndUseNextSmallestTemp];
END;

SortWireList:PROCEDURE=BEGIN i,j:INTEGER;
FOR i IN [0..topWire) DO FOR j IN (i..topWire) DO
IF ShorterWire[j,i] THEN BEGIN
temp:Wire←wireList[i]; wireList[i]←wireList[j]; wireList[j]←temp;
END;
ENDLOOP; ENDLOOP;
END;

ShorterWire:PROCEDURE[i,j:INTEGER] RETURNS[BOOLEAN]=BEGIN
wi:WirePtr←@wireList[i];
wj:WirePtr←@wireList[j];
nonGreeni:BOOLEAN←wi.a.contact=gate OR wi.b.contact=gate;
nonGreenj:BOOLEAN←wj.a.contact=gate OR wj.b.contact=gate;
circuiti:INTEGER←SELECT wi.circuit FROM gnd=>3,vdd=>2,ENDCASE=>1;
circuitj:INTEGER←SELECT wj.circuit FROM gnd=>3,vdd=>2,ENDCASE=>1;
RETURN[IF circuiti#circuitj THEN circuiti<circuitj
ELSE IF nonGreeni#nonGreenj THEN nonGreenj
ELSE wi.l<wj.l];
END;

--///// END WIRELIST STUFF////
--///// START TEMP STUFF /////

wireTempArray:TYPE=ARRAY [0..maxTemp] OF Location;
wireSepArray:TYPE=ARRAY [0..maxTemp] OF INTEGER;

maxTemp:INTEGER=30;
topTemp:INTEGER;
wireTemp:POINTER TO wireTempArray←NIL;
wireSep:POINTER TO wireSepArray←NIL;

EnumerateTemp:PROCEDURE[call:OnI]=
BEGIN k:INTEGER; FOR k IN [0..topTemp) DO call[k]; ENDLOOP; END;

InitTemp:PROCEDURE=BEGIN topTemp←0; END;

InitSep:OnI=BEGIN wireSep[i]←i; END;

AddToTemp:PROCEDURE[l:Location]=BEGIN
wireTemp[topTemp]←l; topTemp←topTemp+1; IF topTemp>maxTemp THEN Error;
END;

FindAndUseNextSmallestTemp:PROCEDURE[i:INTEGER]=BEGIN
bestj:INTEGER; best:INTEGER←10000; k:INTEGER=i;

FindClosest:OnI=BEGIN
l:INTEGER←WireLength[wireTemp[i],wireTemp[k]];
IF wireSep[k]#wireSep[i] AND l<best THEN BEGIN best←l; bestj←i; END;
END;

WindSep:OnI=BEGIN IF wireSep[i]=wireSep[k] THEN wireSep[i]←wireSep[bestj];
END;

EnumerateTemp[FindClosest];
IF best=10000 THEN RETURN;
AddToWireList[[a:wireTemp[i],
b:wireTemp[bestj],c:none,l:best,circuit:thisW]];
EnumerateTemp[WindSep];
END;

--////// END TEMP STUFF////

--//////////////CONTROL///////////////

PrintStickDiagram:PROCEDURE;

AllocateStuffForCreate:PUBLIC PROCEDURE[call:PROCEDURE]=BEGIN OPEN SystemDefs;
PrintStickDiagram←call;
grid←AllocateSegment[SIZE[gridType]];
track←AllocateSegment[SIZE[trackType]];
circuits←AllocateSegment[SIZE[circuitsType]];
wireList←AllocateSegment[SIZE[wireListArray]];
wireTemp←AllocateSegment[SIZE[wireTempArray]];
wireSep←AllocateSegment[SIZE[wireSepArray]];
END;

--//////////////GRID///////////////

side:PUBLIC Loc;
printGrid:POINTER TO gridType;
grid:PUBLIC POINTER TO gridType←NIL;

EnumerateGrid:PUBLIC PROCEDURE[call:PROCEDURE[i,j:INTEGER]]=BEGIN i,j:INTEGER;
FOR i IN (0..side] DO FOR j IN (0..side] DO call[i,j]; ENDLOOP; ENDLOOP;
END;

EnumerateGridPlusOne:PUBLIC PROCEDURE[call:PROCEDURE[i,j:INTEGER]]=BEGIN i,j:INTEGER;
FOR i IN [0..side+1) DO FOR j IN [0..side+1) DO call[i,j]; ENDLOOP; ENDLOOP;
END;

EnumerateGridPlusTwo:PUBLIC PROCEDURE[call:PROCEDURE[i,j:INTEGER]]=BEGIN i,j:INTEGER;
FOR i IN [0..side+1] DO FOR j IN [0..side+1] DO call[i,j]; ENDLOOP; ENDLOOP;
END;

ClearGrid:PUBLIC PROCEDURE[i,j:INTEGER]=BEGIN grid[i][j]←nullTransistor; END;

EnumerateSide:PUBLIC PROCEDURE[call:PROCEDURE[INTEGER]]=BEGIN
i:INTEGER; FOR i IN (0..side] DO call[i]; ENDLOOP; END;

EnumerateSidePlusOne:PUBLIC PROCEDURE[call:PROCEDURE[INTEGER]]=BEGIN
i:INTEGER; FOR i IN [0..side] DO call[i]; ENDLOOP; END;

EnumerateSidePlusTwo:PUBLIC PROCEDURE[call:PROCEDURE[INTEGER]]=BEGIN
i:INTEGER; FOR i IN [0..side+1] DO call[i]; ENDLOOP; END;


--//////////////TRACK///////////////

--the purpose of track is to efficiently find all the transistors in a circuit
--the track operations are:
--Make Track, which builds the data structures
--EnumerateTrack, which calls you back with each transistor participating
-- in the specified circuit
--Valid Circuit, which returns true if there is some transistor this circuit

circuitsType:TYPE=ARRAY [0..topCircuit+5) OF Location;
circuits:POINTER TO circuitsType←NIL;

LTriple:TYPE=RECORD[a,b,c:Location];
trackType:TYPE=ARRAY [0..maxSide) OF ARRAY [0..maxSide) OF LTriple;
track:POINTER TO trackType←NIL;

MakeTrack:PROCEDURE=BEGIN
EnumerateCircuit[ClearCircuit];
EnumerateGrid[ClearTrack];
EnumerateGrid[BuildTrack];
END;

EnumerateTrack:PROCEDURE[i:INTEGER,Call:PROCEDURE[Location]]=BEGIN
l:Location;
FOR l←circuits[i],SELECT l.contact FROM
chanA=>track[l.i][l.j].a ,
gate=>track[l.i][l.j].b,
chanB=>track[l.i][l.j].c,
ENDCASE => ERROR
UNTIL l=nullLoc DO Call[l]; ENDLOOP;
END;

ValidCircuit:PROCEDURE[i:INTEGER] RETURNS[BOOLEAN]=
BEGIN RETURN[circuits[i]#nullLoc];END;

ClearCircuit:PROCEDURE[i:INTEGER]=BEGIN circuits[i]←nullLoc; END;

ClearTrack:PROCEDURE[i,j:INTEGER]=
BEGIN track[i][j]←[nullLoc,nullLoc,nullLoc]; END;

BuildTrack:PROCEDURE[i,j:INTEGER]=BEGIN
s,t,w:Circuit;
[s,t,w]←grid[i][j];
IF s ~IN [0..topCircuit]
OR t ~IN [0..topCircuit]
OR w ~IN [0..topCircuit] THEN Error;
track[i][j]←[circuits[s],circuits[t],circuits[w]];
IF t=s THEN track[i][j].b←[chanA,i,j] -- Handle pullups
ELSE IF t=w THEN track[i][j].b←[chanB,i,j];
circuits[s]←[chanA,i,j];
circuits[w]←[chanB,i,j];
circuits[t]←[gate,i,j]; -- If s=t or w=t this will override. It’s OK.
END;

--//////////////INPUT STUFF///////////////


GetInput:PUBLIC PROCEDURE[print:BOOLEAN]=BEGIN
OPEN AltoFileDefs,IODefs,DirectoryDefs,StreamDefs,
SegmentDefs,StringDefs;
kbdStream,otherStream,currentStream: StreamHandle;
pInFileFP: POINTER TO FP;
inFileFP: FP;
fileNameValid,readFromKbd: BOOLEAN;
inFileName: STRING ← [40];
inputLine: STRING ← [80];
tempString: STRING←[10];
inputTail: SubString;

ChompDecimal: PROCEDURE[src: SubString] RETURNS[INTEGER]=BEGIN
OPEN StringDefs;
i,j,sign,wall: INTEGER;
wall ←src.offset+src.length-1; -- mark the end of line
i ← src.offset;
j ← 0;
WHILE IF i<= wall THEN src.base.text[i]=’ ELSE FALSE
DO i ← i+1; ENDLOOP; -- skip blanks
IF src.base.text[i]=’- THEN BEGIN sign←-1; i←i+1 END ELSE sign←1;
IF src.base.text[i] NOT IN [’0..’9] THEN Error;
WHILE IF i<= wall THEN src.base.text[i] IN [’0..’9] ELSE FALSE
DO
j ← 10*j+(src.base.text[i]-’0);
i ← i + 1;
ENDLOOP;
src.length←src.length-(i-src.offset);
src.offset←i;
RETURN[sign*j];
END;

ChompID: PROCEDURE[src: SubString, dest:STRING]=BEGIN
OPEN StringDefs;
i,wall: INTEGER;
temp: SubString;
tempD: SubStringDescriptor;
temp ← @tempD;
tempD.base←src.base;
dest.length←0;
wall ←src.offset+src.length-1; -- mark the end of line
i ← src.offset;
WHILE IF i<= wall THEN src.base.text[i]=’ ELSE FALSE
DO i ← i+1; ENDLOOP; -- skip initial blanks
tempD.offset←i;
tempD.length←0;
WHILE IF i<= wall THEN src.base.text[i]#’ ELSE FALSE
DO
i ← i + 1;
tempD.length←tempD.length+1;
ENDLOOP;
AppendSubString[dest,temp];
src.length←src.length-(i-src.offset);
src.offset←i;
END;


ParseTransistor: PRIVATE PROCEDURE RETURNS[BOOLEAN]=BEGIN
OPEN IODefs, StreamDefs, StringDefs;
a,b,c: INTEGER;
i,j: INTEGER;

IF (IF currentStream#kbdStream THEN TRUE ELSE
~currentStream.endof[currentStream]) -- blame kbdStream lossage
THEN BEGIN -- parse a line --
ReadLine[inputLine];
inputTail↑ ←SubStringDescriptor[inputLine,0,inputLine.length];
i ← ChompDecimal[inputTail];
IF i < 0 THEN RETURN[FALSE];
j ← ChompDecimal[inputTail];
IF (i NOT IN [1..side]) OR (j NOT IN [1..side]) THEN Error;
ChompID[inputTail,tempString];
a ← CPTI[tempString];
ChompID[inputTail,tempString];
b ← CPTI[tempString];
ChompID[inputTail,tempString];
c ← CPTI[tempString];
grid[i][j]←[a,b,c];
END ELSE RETURN[FALSE];
RETURN[TRUE];
END; -- of ParseTransistor --

pInFileFP←@inFileFP;
fileNameValid ← readFromKbd ← FALSE;
UNTIL fileNameValid DO
WriteString["Enter the Name of the File for Input:"];
ReadID[inFileName];
WriteChar[CR];
IF inFileName.length=0 THEN
fileNameValid ← readFromKbd ← TRUE
ELSE fileNameValid←DirectoryLookup[pInFileFP,inFileName,FALSE];
ENDLOOP;
circuitName.length←0;
WHILE circuitName.length<20 AND
inFileName.text[circuitName.length]#’. DO
circuitName.text[circuitName.length]←inFileName.text[circuitName.length];
circuitName.length←circuitName.length+1;
ENDLOOP;
currentStream ← kbdStream ← GetInputStream[];
IF readFromKbd THEN
WriteLine["Input from Keyboard Requested. Proceed."]
ELSE BEGIN
currentStream ← otherStream ←NewByteStream[inFileName,Read];
SetInputStream[otherStream];
END;
-- Get first line to decide on the size --
ReadLine[inputLine];
inputTail↑ ←[inputLine,0,inputLine.length];
side ← ChompDecimal[inputTail];

InitAtoms[];
EnumerateGridPlusTwo[ClearGrid];

WHILE ParseTransistor[] DO NULL; ENDLOOP;

IF ~readFromKbd THEN
BEGIN
SetInputStream[kbdStream];
otherStream.destroy[otherStream];
END;
IF print THEN PrintG[];
END;


--///////////////PRINTING//////////////

PrintG:PUBLIC PROCEDURE=BEGIN OPEN IODefs,StreamDefs;
i,j: INTEGER;
output: StreamHandle;
output←GetOutputStream[];
printGrid←grid;
IODefs.WriteChar[CR];
-- Write a Header Line
IODefs.WriteString["j(y)\i(x)"];
FOR i IN (0..side] DO IODefs.OutNumber[output,i,
NumberFormat[10,FALSE,FALSE,11] ]; ENDLOOP;
IODefs.WriteChar[CR];
IODefs.WriteChar[CR];
-- Write out the Grid.
FOR j DECREASING IN (0..side] DO -- handle the y’s
IODefs.OutNumber[output,j,NumberFormat[10,FALSE,FALSE,11] ];
FOR i IN (0..side] DO -- x coordinate
PrintGrid[i,j];
ENDLOOP;
IODefs.WriteChar[CR];
ENDLOOP;
END;

PrintGSection:PUBLIC PROCEDURE=BEGIN
printGrid←grid;
IODefs.WriteChar[CR];
EnumerateGrid[PrintGridSection];
END;

PrintGrid:PROCEDURE[i,j:INTEGER]=BEGIN OPEN IODefs;
WriteChar[’ ];
WriteId[printGrid[i][j].a];
WriteId[printGrid[i][j].b];
WriteId[printGrid[i][j].c];
WriteChar[’ ];
END;

PrintGridSection:PROCEDURE[i,j:INTEGER]=BEGIN OPEN IODefs;
x:INTEGER;
IF j=0 THEN WriteChar[CR];
x←MAX[FindSectionId[printGrid[i][j].a],
FindSectionId[printGrid[i][j].b],
FindSectionId[printGrid[i][j].c]];
WriteChar[SELECT x FROM -1=>’x,0=>’0,1=>’1,2=>’2,3=>’3,4=>’4,
5=>’5,6=>’6,7=>’7,8=>’8,ENDCASE=>’9];
END;

WriteId:PROCEDURE[a:INTEGER]=BEGIN
IF a=nullCircuit THEN IODefs.WriteString[" "]
ELSE BEGIN
IODefs.WriteChar[’ ];
IODefs.WriteChar[atoms[a].a];
IODefs.WriteChar[atoms[a].b];
END;
END;

FindSectionId:PROCEDURE[a:INTEGER] RETURNS[INTEGER]=BEGIN
IF a=gnd THEN RETURN[-1];
RETURN[SELECT atoms[a].a FROM
’0,’ =>0, ’1=>1, ’2=>2, ’3=>3, ’4=>4, ’5=>5, ’6=>6, ’7=>7, ’8=>8,
ENDCASE=>-1];
END;

--/////////////ATOMS//////////////

Id:TYPE=RECORD[a,b:CHARACTER];
atoms:ARRAY[0..maxAtom+3] OF Id;
maxAtom:INTEGER=500;
topAtom,vdd,gnd:INTEGER;
tempString:STRING←[6];


InitAtoms:PROCEDURE=BEGIN
gd: STRING="gd";
vd: STRING="vd";
topAtom←0;
gnd←CPTI["gd"];
vdd←CPTI["vd"];
END;

CPTI:PROCEDURE[inStr:STRING] RETURNS[b:INTEGER]=BEGIN
id: Id;
i:INTEGER;
IF inStr.length=1 THEN id ←[’ ,inStr.text[0]]
ELSE id ←[inStr.text[0],inStr.text[1]];
FOR i IN [0..topAtom) DO IF id=atoms[i] THEN RETURN[i]; ENDLOOP;
atoms[topAtom]←id;
topAtom←topAtom+1;
IF topAtom>maxAtom THEN Error;
RETURN[topAtom-1];
END;

--/////////////GRAPHICS//////////////

maxX,maxY: INTEGER;
cornerX,cornerY: CARDINAL;
halfHeight:INTEGER=12000;
halfWidth:INTEGER=8000;
display:BOOLEAN←TRUE;
press:PressDefs.PressFileDescriptor;
Screen:POINTER TO GraphicsDefs.Bitmap;
OldDCB:CARDINAL;
DCBHead: POINTER TO CARDINAL= LOOPHOLE[420B];
MouseButtons: POINTER TO CARDINAL = LOOPHOLE[177030B];
KeyBoard1: POINTER TO CARDINAL = LOOPHOLE[177034B];
KeyBoard2: POINTER TO CARDINAL = LOOPHOLE[177035B];
MouseX: POINTER TO CARDINAL = LOOPHOLE[426B];
MouseY: POINTER TO CARDINAL = LOOPHOLE[427B];

PrintGeometry:PUBLIC PROCEDURE[name:STRING]= BEGIN
tScale: INTEGER←scale;
display←FALSE;
scale←scale*35; -- assumes 72+a tad screen dots per inch
cornerY←cornerX←35*xOrg;
PressDefs.InitPressFileDescriptor[@press,name];
PrintStickDiagram[];
PressDefs.ClosePressFile[@press];
display←TRUE;
scale←tScale;
END;--print geom

scale:INTEGER;
debugPrint:PUBLIC BOOLEAN←FALSE;
first:PUBLIC BOOLEAN;

PutBox:PUBLIC PROCEDURE[color:Color,x,y,m,n:CARDINAL]=BEGIN
pressWidth: CARDINAL=20000;
pressheight: CARDINAL=25000;
x1,y1,w1,w2:INTEGER;
IF debugPrint THEN BEGIN
IODefs.WriteChar[SELECT color FROM g=>’g,r=>’r,b=>’b,ENDCASE=>’y];
IODefs.WriteNumber[x,[10,FALSE,TRUE,4]];
IODefs.WriteNumber[y,[10,FALSE,TRUE,4]];
IODefs.WriteNumber[m,[10,FALSE,TRUE,3]];
IODefs.WriteNumber[n,[10,FALSE,TRUE,3]];
IODefs.WriteChar[CR];
RETURN;
END;
IF (m<=1 AND n<=1) OR
m NOT IN [1..1000) OR n NOT IN [1..1000) THEN RETURN;
IF display THEN BEGIN DisplayBox[color,x,y,m,n]; RETURN; END;
IF silFile THEN BEGIN
feat:SilFeature;
t:[0..16)←SELECT color FROM r=>1, g=>3, b=>4, y=>2, ENDCASE=>0;
IF x>77777B THEN x←1;
IF y>77777B THEN y←1;
IF x>500 THEN x←500;
IF y>silYMax THEN y←silYMax-1;
feat←[macro:177777B,
xUL:[0,xOrg+scale*x],
yUL:[0,yOrg-scale*(y+n)],
xLR:[t,xOrg+scale*(x+m)],
yLR:[14,yOrg-scale*y]];
WriteSilFeature[feat];
RETURN;
END;
-- // Default: produce a PRESS file //
SELECT color FROM
r=>PressDefs.SetColor[@press,220,128,255];
g=>PressDefs.SetColor[@press,080,128,255];
b=>PressDefs.SetColor[@press,140,064,255];
y=>PressDefs.SetColor[@press,40,128,255];
none=>PressDefs.SetColor[@press,140,000,000];
ENDCASE;
x1←cornerX+scale*x;
y1←cornerY+scale*y;
w1←scale*m;
w2←scale*n;
IF x1>pressWidth OR y1>pressheight THEN RETURN;
IF x1+w1>pressWidth THEN w1←pressWidth-x1;
IF y1+w2>pressheight THEN w2←pressheight-y1;
PressDefs.PutRectangle[@press,x1,y1,w1,w2];
END;--PutBox

MakeSilFile:PUBLIC PROCEDURE[s:STRING]= BEGIN OPEN StreamDefs;
outputStream←NewWordStream[s,Write+Append];
outputStream.reset[outputStream];
outputStream.put[outputStream,34562B];
display←FALSE; silFile←TRUE;
PrintStickDiagram[];
display←TRUE; silFile←FALSE;
outputStream.destroy[outputStream];
END;

silFile:PUBLIC BOOLEAN←FALSE;
silYMax:CARDINAL=750;
SilWord:TYPE=RECORD[a:[0..17B],b:[0..7777B]];
SilFeature:TYPE=RECORD[macro:CARDINAL,xUL,yUL,xLR,yLR:SilWord];
outputStream:StreamDefs.DiskHandle;

WriteSilFeature:PROCEDURE[feat:SilFeature]=BEGIN
outputStream.put[outputStream,feat.macro];
outputStream.put[outputStream,feat.xUL];
outputStream.put[outputStream,feat.yUL];
outputStream.put[outputStream,feat.xLR];
outputStream.put[outputStream,feat.yLR];
END;
--
--
Graphics Display Procedures
--
xOrg,yOrg: CARDINAL; --
origin of the image
dxMax:CARDINAL;
dyMax:CARDINAL; --
size of the display screen
smallDisplay:BOOLEAN←FALSE;

StartDisplay
:PUBLIC PROCEDURE= BEGIN --initialize the screen
dxMax←dyMax←IF smallDisplay THEN 256 ELSE 608;
GraphicsDefs.SetDefaultBitmap[dxMax,dyMax];
OldDCB← DCBHead↑;
Screen ← GraphicsDefs.TurnOnGraphics[];
END;

Display:PUBLIC PROCEDURE= BEGIN
GraphicsDefs.EraseArea[0,0,dxMax,dyMax];
xOrg← 8;
yOrg← dyMax-8;
scale← MIN[dxMax/(maxX+16),dyMax/(maxY+16)];
IODefs.WriteString["scale="];
IODefs.WriteNumber[scale,[10,FALSE,TRUE,6]];
IODefs.WriteLine[""];
IF scale<1 THEN Error;
PrintStickDiagram[];
END;

ManipulateDisplay:PUBLIC PROCEDURE RETURNS[print:BOOLEAN]= BEGIN
DO SELECT TRUE FROM
BlueButton[] => Display[];
YellowButton[] => -- Reset the scale
BEGIN
scale← (MouseX↑-xOrg)/maxX;
GraphicsDefs.EraseArea[0,0,dxMax,dyMax];
PrintStickDiagram[];
END;
RedButton[] =>
BEGIN
xOrg←MouseX↑;
yOrg←MouseY↑;
GraphicsDefs.EraseArea[0,0,dxMax,dyMax];
PrintStickDiagram[];
END;
KeyBoard1↑= 177757B =>BEGIN print←TRUE; EXIT; END; --p was hit
KeyBoard2↑= 167777B =>BEGIN print←FALSE; EXIT; END; --q was hit
ENDCASE;
ENDLOOP;
TurnOffGraphics[];
DCBHead↑← OldDCB;
[]← IODefs.ReadChar[];
END;

RedButton:PROCEDURE RETURNS[BOOLEAN]= BEGIN
IF (MouseButtons↑ MOD 8) < 4
THEN BEGIN
UNTIL (MouseButtons↑ MOD 8) > 3 DO ENDLOOP;
RETURN [TRUE];
END
ELSE RETURN [FALSE];
END;

BlueButton:PROCEDURE RETURNS[BOOLEAN]= BEGIN
IF (MouseButtons↑ MOD 4) < 2
THEN BEGIN
UNTIL (MouseButtons↑ MOD 4) > 1 DO ENDLOOP;
RETURN [TRUE];
END
ELSE RETURN [FALSE];
END;

YellowButton:PROCEDURE RETURNS[BOOLEAN]= BEGIN
IF (MouseButtons↑ MOD 2) = 0
THEN BEGIN
UNTIL (MouseButtons↑ MOD 2) # 0 DO ENDLOOP;
RETURN [TRUE];
END
ELSE RETURN [FALSE];
END;

TurnOffGraphics:PROCEDURE= BEGIN
DCBHead↑← 0;
SystemDefs.FreeSegment[Screen.bits- 4];
Screen.bits← NIL;
END;


DisplayBox:PROCEDURE[color:Color,x,y,m,n:CARDINAL]=BEGIN
x1,y1,x2,y2: CARDINAL;
x1←xOrg+scale*x;
y1←yOrg-scale*y;
x2←xOrg+scale*(x+m);
y2←yOrg-scale*(y+n);
IF INTEGER[x1]<0 OR INTEGER[x2]<0 OR INTEGER[y1]<0 OR INTEGER[y2]<0
THEN Error;
SELECT color FROM
b=>GraphicsDefs.SetGrayLevel[14]; --
light grey
g=>GraphicsDefs.SetGrayLevel[10]; --
dark grey
r=>GraphicsDefs.SetGrayLevel[3]; --
almost black
none=>GraphicsDefs.SetGrayLevel[0];--
black
ENDCASE;
GraphicsDefs.PutGray[x1,y1,x2,y2];
END;--DisplayBox

DoOutputs: PUBLIC PROCEDURE[name:STRING,limitX,limitY:INTEGER]=BEGIN
maxX←limitX;
maxY←limitY;
StartDisplay[];
Display[];
[] ← ManipulateDisplay[]; -- This guy sets up the graphic transformation.
-- Note that it will always print.
outFileName.length←0;
StringDefs.AppendString[outFileName,circuitName];
StringDefs.AppendString[outFileName,".press"];
PrintGeometry[outFileName];
outFileName.length←0;
StringDefs.AppendString[outFileName,circuitName];
StringDefs.AppendString[outFileName,".sil"];
MakeSilFile[outFileName];
END;

END..

altoYMax:CARDINAL=1000;
SilFile:TYPE=RECORD[password:CARDINAL,data:ARRAY MANY OF SilFeature];
SilFeature:TYPE=RECORD[
macro:CARDINAL,
null:[4-bits], x:[12-bits],
null:[4-bits], yMax:[16 bits],
color:[4-bits], xMax:[12-bits],
font:[4-bits], y:[12-bits]]

password must be 34562B or 34563B
macro must be 177777B
Color:{xx,red,yellow,green,blue,xx,xx,xx,xx,orange,xx,xx,xx,xx,xx,xx}
y is measured down from the upper left corner!
font must be 14 (font<14 is a bcpl format string following, to be ignored)

Press colors: Red=0, Yellow=40, Green=80, Cyan=120, Blue=160,
Magenta=200, Red=240