-- FILE: <Juniper>RamLoad.mesa Last Edited by Swinehart, March 25, 1980 7:35 AM
DIRECTORY
AltoDefs: FROM "AltoDefs" USING[PageNumber, BytesPerPage, BytesPerWord],
InlineDefs: FROM "InlineDefs" USING[BITAND],
BcplOps: FROM "BcplOps" USING[BcplJSR],
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, BcplOps, sg: SegmentDefs EXPORTS RamDefs =
BEGIN OPEN RamDefs, PrivateRamDefs; -- module body
RamWord: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL];
LoadRamAndBoot: PUBLIC PROCEDURE[m: MuImage, boot: BOOLEAN,
bank: [0..2]←0 ] 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. On 3K RAM machines, loads image into whichever microcode RAM bank is specified. Caution: if bank#0 AND boot, destroys locations 0 and 1 in bank 0.
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];
ramConfig: RamConfiguration← ReadRamConfiguration[];
IF ramConfig=rom1ram0 OR
(bank # 0 AND ramConfig # rom1ram3) 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], bank];-- load the ram
IF boot THEN SilentBoot[m.blv];-- start it running wherever the MuImage specifies
END; --LoadRamAndBoot
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
TestVal: CARDINAL=52525B;
NTestVal: CARDINAL=125252B;
ReadRamConfiguration: PUBLIC PROCEDURE RETURNS [RamConfiguration] =
-- WARNING: Bank 2 must not have task or emulator code running in
-- it at locations 777-1000 during this test!
BEGIN --ReadRamConfiguration
config: RamConfiguration;
saveRam0, saveRam2, y: ARRAY[0..2) OF MicroCode;
test: ARRAY [0..1) OF MicroCode ←
LOOPHOLE[RamWord[high: TestVal, low: TestVal]];
nTest: ARRAY[0..1) OF MicroCode←
LOOPHOLE[RamWord[high: NTestVal, low: NTestVal]];
test2: ARRAY[0..2) OF MicroCode←
[[r: 3, aluF: BusPlus1, bs: ReadR, f1: SwMode, f2: Noop, loadT: no, loadLM: yes, next: 1000B],
[r: 3, aluF: Bus, bs: RGets, f1: Noop, f2: Noop, loadT: no, loadLM: no, next: EmSTART]];
saveRam0Desc: RamImage ← DESCRIPTOR[saveRam0];
saveRam2Desc: RamImage ← DESCRIPTOR[saveRam2];
yDesc: RamImage ← DESCRIPTOR[y];
testDesc: RamImage ← DESCRIPTOR[test];
nTestDesc: RamImage ← DESCRIPTOR[nTest];
test2Desc: RamImage ← DESCRIPTOR[test2];
ReadRam[777B, saveRam0Desc];
ReadRam[777B, saveRam2Desc, 2];
-- Write different test values into RAM0 and RAM2
WriteRam[777B, testDesc];
WriteRam[777B, nTestDesc, 2];
-- Read back the RAM0 copy. If it has the value written into RAM0 then 3k RAM exists. If it has the value written into RAM2 then 1k RAM exists. If it has neither value then no RAM exists.
ReadRam[777B, yDesc];
config← IF y[0]=test[0] THEN rom1ram3 ELSE
IF y[0]=nTest[0] THEN rom1ram1 ELSE rom1ram0;
-- If 1k RAM exists then test for 2k ROM option.
IF config=rom1ram1 THEN BEGIN
WriteRam[777B, test2Desc];
IF JumpToRam[777B, 0] = 0 THEN config←rom2ram1;
END;
-- Restore RAM work area
WriteRam[777B, saveRam0Desc];
WriteRam[777B, saveRam2Desc, 2];
RETURN [config];
END; --ReadRamConfiguration
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
ExtendedMicroAddress: TYPE = MACHINE DEPENDENT RECORD
[
unused: [0..4)←0, -- 2 bit
bank: [0..2]←0, -- 2 bits
unused1: [0..2)←0, -- 1 bit
selectHighWord: BOOLEAN←FALSE, -- 1 bit
address: [0..2000B) -- 10 bits
];
ReadRam: PROCEDURE[a: MicroAddress, v: RamImage, bank: [0..2]←0] =
-- 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
];
lowAddr: CARDINAL←
LOOPHOLE[ExtendedMicroAddress[address: LOOPHOLE[a], bank: bank]];
highAddr: CARDINAL←
LOOPHOLE[ExtendedMicroAddress[address: LOOPHOLE[a],
selectHighWord: TRUE, bank: bank]];
high, low: CARDINAL;
i: CARDINAL;
FOR i IN [0..LENGTH[v])
DO
high ← BcplOps.BcplJSR[JSR, BASE[code], highAddr+i];
low ← BcplOps.BcplJSR[JSR, BASE[code], lowAddr+i];
v[i] ← LOOPHOLE[RamWord[high: high, low: low], MicroCode];
ENDLOOP;
END; --ReadRam
WriteRam: PROCEDURE[a: MicroAddress, v: RamImage, bank: [0..2]←0] =
-- 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
];
addr: ExtendedMicroAddress←[bank: bank, address: LOOPHOLE[a]];
acs: MACHINE DEPENDENT RECORD[n, ramAddr, vecAddr, svAc3: UNSPECIFIED];
acs ← [n: LENGTH[v], ramAddr: addr, vecAddr:BASE[v], svAc3: NIL]; -- prepare parameters for Alto code
[] ← BcplOps.BcplJSR[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 ← BcplOps.BcplJSR[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
];
fromAc0BcplOps.BcplJSR[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: Swinehart, March 15, 1980 5:26 PM Support 3k ram options as described in RamDefs
Changed by: Swinehart, March 25, 1980 7:34 AM, repair configuration query
Changed by: Maleson, July 1, 1980 4:38 PM Mesa6: NovaOps ← BcplOps
Changed by: Mitchell, DateTime Reason