-- FILE: <Juniper>RamLoad.mesa Last Edited by Mitchell, October 31, 1979 10:35 AM
DIRECTORY
AltoDefs: FROM "AltoDefs" USING[PageNumber, BytesPerPage, BytesPerWord],
InlineDefs: FROM "InlineDefs" USING[BITAND],
NovaOps: FROM "NovaOps" USING[NovaJSR],
PrivateRamDefs: FROM "PrivateRamDefs",
RamDefs: FROM "RamDefs",
SegmentDefs: FROM "SegmentDefs" USING[FileHandle, FileSegmentHandle, NewFile, NewFileSegment, DefaultBase, DefaultPages, GetEndOfFile, Read, OldFileOnly, SwapIn, FileSegmentAddress, ReleaseFile, Unlock, SwapOut, DeleteFileSegment];
RamLoad: PROGRAM IMPORTS InlineDefs, NovaOps, sg: SegmentDefs EXPORTS RamDefs =
BEGIN OPEN RamDefs, PrivateRamDefs; -- module body
LoadRamAndBoot: PUBLIC PROCEDURE[m: MuImage, boot: BOOLEAN] RETURNS [constDiffs: CARDINAL] =
-- loads the ram from the MuImage, checks the constants and returns number of constant mismatches. If boot=TRUE, also does a silent boot: first, a silent boot is done to guarantee that the machine is in ground state (everything running in ROM0 - ok for Mesa?) and then, after loading the ram image, another silent boot is done as specified in the blv field of the MuImage.
BEGIN --LoadRamAndBoot
muCode: ARRAY [0..2) OF MicroCode ←-- to be loaded at loc 0
[
[r: 0, aluF: Bus, bs: ReadR, f1: SwMode, f2: Noop, loadT: no, loadLM: no, next: 1],
[r: 0, aluF: Bus, bs: ReadR, f1: Noop, f2: Noop, loadT: no, loadLM: no, next: EmSTART]
];
resetToProm: RamImage = DESCRIPTOR[muCode];
IF NOT RamExists[] THEN RETURN[177777B];
IF boot THEN
BEGIN
WriteRam[0, resetToProm];
SilentBoot[BootLocusVector[177776B]];-- blv value to reset to ROM0
END;
constDiffs ← CheckConstants[DESCRIPTOR[m.constVector]];
WriteRam[0, DESCRIPTOR[m.ramVector]];-- load the ram
IF boot THEN SilentBoot[m.blv];-- start it running wherever the MuImage specifies
END; --LoadRamAndBoot
ReadBlv: PUBLIC PROCEDURE[m: MuImage] RETURNS [BootLocusVector] =
BEGIN RETURN [m.blv] END;
NoEtherNetBoard: PUBLIC ERROR = CODE;
SilentBoot: PUBLIC PROCEDURE[blv: BootLocusVector] =
-- check to see that a silent boot is possible (I.e., that Alto has an EtherNet board), sets boot locus vector and does the StartIO to cause a silent boot.
BEGIN --SilentBoot
IF InlineDefs.BITAND[StartIO[0], 77777B]=77777B THEN ERROR NoEtherNetBoard;
SetBootLocusVector[blv];
[]←StartIO[100000B];-- boot it.
END; --SilentBoot
SetBootLocusVector: PROCEDURE[blv: BootLocusVector] =
-- Removes part of the code in the Ram (so be sure no task is running in the ram before doing this or the Alto will be zapped), writes some microcode into the same place and jumps to it to set the boot locus vector and then puts the previous ram contents back. A subsequent StartIO can be used to do a silent boot (see, e.g., LoadRamAndBoot above).
BEGIN --SetBootLocusVector
muCode: ARRAY [0..4) OF MicroCode ←-- microcode to go at loc 1000B
[
[r: 0, aluF: Bus, bs: ReadR, f1: Task, f2: Noop, loadT: no, loadLM: no, next: 1001B],
[r: 3--AC0--, aluF: Bus, bs: ReadR, f1: RmrGets, f2: Noop, loadT: no, loadLM: no, next: 1002B],
[r: 0, aluF: Bus, bs: ReadR, f1: SwMode, f2: Noop, loadT: no, loadLM: no, next: 1003B],
[r: 0, aluF: Bus, bs: ReadR, f1: Noop, f2: Noop, loadT: no, loadLM: no, next: EmSTART]
];
ldBLV: RamImage = DESCRIPTOR[muCode];
sv: ARRAY [0..4) OF MicroCode;
svDesc: RamImage = DESCRIPTOR[sv];
ReadRam[1000B, svDesc];-- save part of the ram
WriteRam[1000B, ldBLV];
[]←JumpToRam[1000B, blv];-- execute the code and give it the blv parameter
WriteRam[1000B, svDesc];-- put saved ram contents back
END; --SetBootLocusVector
CheckConstants: PROCEDURE[c: ConstantImage] RETURNS [constDiffs: CARDINAL] =
BEGIN --CheckConstants
muCode: ARRAY [0..2) OF MicroCode ←
[
[r: 0, aluF: Bus, bs: 0, f1: SwMode, f2: ReadConst, loadT: no, loadLM: yes, next: 1001B],
[r: 3--ACO--, aluF: Bus, bs: RGets, f1: Noop, f2: Noop, loadT: no, loadLM: no, next: EmSTART]
];
readConsti: RamImage ← DESCRIPTOR[muCode];
old: ARRAY [0..2) OF MicroCode;
descOld: RamImage = DESCRIPTOR[old];
i, const: CARDINAL;
ibits: MACHINE DEPENDENT RECORD[blank: [0..377B], high5: [0..37B], low3: [0..7B]];
constDiffs ← 0;
ReadRam[1000B, descOld];-- salt what is in RAM away
FOR i IN [1..maxConstAddr]
DO
ibits ← LOOPHOLE[i];-- to look at bits of i
readConsti[0].r ← ibits.high5;-- compile high-order microcode word
readConsti[0].bs ← ibits.low3;-- r,bs fields used to address constant memory
WriteRam[1000B, readConsti];
const ← JumpToRam[1000B, 0];
IF c[i]#const AND c[i]#0 THEN constDiffs ← constDiffs+1;
ENDLOOP;
WriteRam[1000B, descOld];-- restore RAM contents
END; --CheckConstants
RamExists: PROCEDURE RETURNS [BOOLEAN] =
-- Returns TRUE if Ram attached, FALSE if not.
BEGIN --RamExists
sv, y: ARRAY [0..1) OF MicroCode;
test: ARRAY [0..1) OF MicroCode ←
[[r: 31, aluF: undefAlu1, bs: ReadR, f1: Noop, f2: taskSpec5, loadT: no, loadLM: no, next: 525B]];
svDesc: RamImage ← DESCRIPTOR[sv];
yDesc: RamImage ← DESCRIPTOR[y];
testDesc: RamImage ← DESCRIPTOR[test];
ReadRam[774B, svDesc];-- save Ram word
WriteRam[774B, testDesc]; ReadRam[774B, yDesc];
WriteRam[774B, svDesc];-- restore Ram word
RETURN[ y[0]=test[0] ];
END; --RamExists
RamWord: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL];
ReadRam: PROCEDURE[a: MicroAddress, v: RamImage] =
-- Read Ram words beginning at location a; LENGTH[v] RamWords are read into v.
BEGIN --ReadRam
code: ARRAY [0..3) OF CARDINAL ←-- reads RAM half-word (16 bits) addressed by AC0 into AC0
[
105000B,-- MOV 0,1
061011B,-- RDRAM
001400B-- JMP 0,3
];
selectHighWord: CARDINAL = 2000B;-- to select high-order 16 bits of a RAM word
high, low: CARDINAL;
i: CARDINAL;
FOR i IN [0..LENGTH[v])
DO
high ← NovaOps.NovaJSR[JSR, BASE[code], a+i+selectHighWord];
low ← NovaOps.NovaJSR[JSR, BASE[code], a+i];
v[i] ← LOOPHOLE[RamWord[high: high, low: low], MicroCode];
ENDLOOP;
END; --ReadRam
WriteRam: PROCEDURE[a: MicroAddress, v: RamImage] =
-- Beginning at Ram location a, write LENGTH[v] RamWords into the Ram. The loop to do this is written entirely in Nova code so that it can operate even if the microcode being loaded temporarily clobbers Mesa microcode (as is the case when using XMesa on wide-bodied Altos).
BEGIN --WriteRam
code: ARRAY [0..14) OF CARDINAL ←
[
111000B,--MOV0,2;move ptr to parameter record to indexable register
55003B,-- STA3,3,2; save return address in parameter record
25001B,-- LDA1,1,2;load ram address
35002B,-- LOOP:LDA3,2,2;get @v[i]
21400B,-- LDA0,0,3;load v[i].high into ac0 for wrtram
35401B,-- LDA3,1,3;load v[i].low into ac3 for wrtram
061012B,-- WRTRAM
125420B,-- INCZ1,1; increment the ram address
11002B,-- ISZ2,2; increment the vector address twice
11002B,-- ISZ2,2
15000B,-- DSZ0,2; decrement count and check if done
770B,-- JMPLOOP; nope, go around again
35003B,-- LDA3,3,2; finished, load the return address
1400B-- JMP0,3; return
];
acs: MACHINE DEPENDENT RECORD[n, ramAddr, vecAddr, svAc3: UNSPECIFIED];
acs ← [n: LENGTH[v], ramAddr: a, vecAddr:BASE[v], svAc3: NIL]; -- prepare parameters for Alto code
[] ← NovaOps.NovaJSR[JSR, BASE[code], @acs];
END; --WriteRam
JumpToRam: PROCEDURE[ac1: MicroAddress, ac0: UNSPECIFIED] RETURNS[fromAc0: CARDINAL] =
-- Jump to the Ram location given by ac1, passing ac0 in Alto AC0.
BEGIN --JumpToRam
code: ARRAY [0..5) OF CARDINAL ←
[
111000B,-- MOV 0,2
021000B,-- LDA 0,0,2
025001B,-- LDA 1,1,2
061010B,-- JMPRAM
001400B-- JMP 0,3
];
acs: MACHINE DEPENDENT RECORD[ac0: UNSPECIFIED, ac1: CARDINAL --MicroAddress--]
← [ac0, ac1];
fromAc0 ← NovaOps.NovaJSR[JSR, BASE[code], @acs];
END; --JumpToRam
StartIO: PUBLIC PROCEDURE[ac0: UNSPECIFIED] RETURNS [fromAc0: CARDINAL] =
-- Do an SIO with ac0 passed in the Alto AC0.
BEGIN --StartIO
code: ARRAY [0..2) OF CARDINAL ←
[
061004B,-- SIO
001400B-- JMP 0,3
];
fromAc0NovaOps.NovaJSR[JSR,BASE[code], ac0];
END; --StartIO
muFH: sg.FileHandle ← NIL;
muSeg: sg.FileSegmentHandle ← NIL;
checkConstVec: ARRAY [1..13] OF CARDINAL = -- what first constants in a Packed Mu file should be
[1, 2, 177776B, 177777B, 177777B, 17B, 177777B, 3, 4, 5, 6, 7, 10B];
MuFileAlreadyOpen: PUBLIC ERROR = CODE;
SuspiciousPackedMuFile: PUBLIC ERROR = CODE;
ReadPackedMuFile: PUBLIC PROCEDURE[name: STRING] RETURNS[theImage: MuImage] =
-- Read and swap in a Packed Mu file and check it to increase our confidence that it is a valid MuImage as prepared by the program PackMu.Run.
BEGIN OPEN sg; --ReadPackedMuFile
lastPage: AltoDefs.PageNumber;
lastByteCount: [0..AltoDefs.BytesPerPage];
i: CARDINAL;
IF muFH # NIL THEN ERROR MuFileAlreadyOpen;
theImage←NIL;
muFH ← NewFile[name: name, access: Read, version: OldFileOnly];
BEGIN
[page: lastPage, byte: lastByteCount] ← GetEndOfFile[muFH];
IF lastPage#12B THEN GOTO FileLooksBad;
IF lastByteCount MOD AltoDefs.BytesPerWord # 0 THEN GOTO FileLooksBad;
muSeg ← NewFileSegment[file: muFH, base: DefaultBase, pages: DefaultPages, access: Read];
SwapIn[muSeg];
theImage ← FileSegmentAddress[muSeg];
FOR i IN [1..13] DO IF checkConstVec[i]#theImage.constVector[i] THEN GOTO FileLooksBad; ENDLOOP;
EXITS
FileLooksBad =>
BEGIN
ReleaseMuImage[theImage];
ERROR SuspiciousPackedMuFile;
END;
END;
END; --ReadPackedMuFile
ReleaseMuImage: PUBLIC PROCEDURE[theImage: MuImage] =
-- Release the FileHandle for the current packed MuImage. IF muSeg#NIL, then swap it out first and get rid of the segment. Then release the file.
BEGIN OPEN sg; --ReleaseMuImage
IF muSeg=NIL THEN
BEGIN
IF theImage#NIL THEN ERROR;
ReleaseFile[muFH];
END
ELSE
BEGIN
Unlock[muSeg]; SwapOut[muSeg];
DeleteFileSegment[muSeg];
muSeg ← NIL;
END;
muFH←NIL;
END; --ReleaseMuImage
-- I N I T I A L I Z A T I O N
END. -- RamLoad
Edit Log
Remark: Sturgis: 5-Jun-79 18:33:41: any comments earlier than October 1, 1978 placed in the Juniper History Log.
Changed by: Mitchell, March 6, 1979 11:51 PM Conversion to Mesa 5.0; now must IMPORT InlineDefs and NovaOps
Changed by: Mitchell, October 31, 1979 10:36 AM
Added ReadBlv procedure to get BootLocusVector from a MuImage.
Changed by: Mitchell, DTAcrType