-- RamLoad.mesa Last Edited by Johnsson, May 21, 1980 11:43 AM DIRECTORY AltoDefs USING [PageNumber, BytesPerPage, BytesPerWord], InlineDefs USING [BITAND, BITSHIFT], BcplOps USING [BcplJSR], PrivateRamDefs USING [ BootLocusVector, ConstantImage, EmSTART, maxConstAddr, MicroAddress, MicroCode, RamImage, ReadR, RGets], RamDefs USING [MuImage], SegmentDefs USING [ FileHandle, FileSegmentHandle, NewFile, NewFileSegment, DefaultBase, DefaultPages, GetEndOfFile, Read, OldFileOnly, SwapIn, FileSegmentAddress, ReleaseFile, Unlock, SwapOut, DeleteFileSegment]; RamLoad: PROGRAM IMPORTS InlineDefs, BcplOps, SegmentDefs EXPORTS RamDefs = BEGIN OPEN RamDefs, PrivateRamDefs; LoadRamAndBoot: PUBLIC PROCEDURE [ m: MuImage, boot: BOOLEAN ← FALSE, 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. BEGIN 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 ~RamExists[] THEN RETURN[177777B]; IF boot THEN BEGIN WriteRam[0, resetToProm, bank]; 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; 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 IF InlineDefs.BITAND[StartIO[0], 77777B] = 77777B THEN ERROR NoEtherNetBoard; SetBootLocusVector[blv]; [] ← StartIO[100000B]; -- boot it. END; 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 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; CheckConstants: PROCEDURE [c: ConstantImage] RETURNS [constDiffs: CARDINAL] = BEGIN 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; RamExists: PROCEDURE RETURNS [BOOLEAN] = -- Returns TRUE if Ram attached, FALSE if not. BEGIN 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; RamWord: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL]; ReadRam: PROCEDURE [a: MicroAddress, v: RamImage, b: [0..2] ← 0] = -- Read Ram words beginning at location a in bank b; LENGTH[v] RamWords are read into v. BEGIN 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 bankSel: CARDINAL = InlineDefs.BITSHIFT[b, 12]; high, low: CARDINAL; i: CARDINAL; FOR i IN [0..LENGTH[v]) DO high ← BcplOps.BcplJSR[JSR, BASE[code], a + bankSel + i + selectHighWord]; low ← BcplOps.BcplJSR[JSR, BASE[code], a + bankSel + i]; v[i] ← LOOPHOLE[RamWord[high: high, low: low], MicroCode]; ENDLOOP; END; WriteRam: PROCEDURE [a: MicroAddress, v: RamImage, b: [0..2] ← 0] = -- Beginning at Ram location a in bank b, write LENGTH[v] RamWords into the Ram. The loop to do this is written entirely in Bcpl 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 code: ARRAY [0..14) OF CARDINAL ← [111000B, -- MOV 0,2 ;move ptr to parameter record to indexable register 55003B, -- STA 3,3,2 ; save return address in parameter record 25001B, -- LDA 1,1,2 ;load ram address 35002B, -- LOOP: LDA 3,2,2 ;get @v[i] 21400B, -- LDA 0,0,3 ;load v[i].high into ac0 for wrtram 35401B, -- LDA 3,1,3 ;load v[i].low into ac3 for wrtram 061012B, -- WRTRAM 125420B, -- INCZ 1,1 ; increment the ram address 11002B, -- ISZ 2,2 ; increment the vector address twice 11002B, -- ISZ 2,2 15000B, -- DSZ 0,2 ; decrement count and check if done 770B, -- JMP LOOP ; nope, go around again 35003B, -- LDA 3,3,2 ; finished, load the return address 1400B -- JMP 0,3 ; return ]; acs: MACHINE DEPENDENT RECORD [n, ramAddr, vecAddr, svAc3: UNSPECIFIED]; acs ← [n: LENGTH[v], ramAddr: a + InlineDefs.BITSHIFT[b, 12], vecAddr: BASE[v], svAc3: NIL]; [] ← BcplOps.BcplJSR[JSR, BASE[code], @acs]; END; JumpToRam: PROCEDURE [ac1: MicroAddress, ac0: UNSPECIFIED] RETURNS [fromAc0: CARDINAL] = -- Jump to the Ram location given by ac1, passing ac0 in Alto AC0. BEGIN 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; StartIO: PUBLIC PROCEDURE [ac0: UNSPECIFIED] RETURNS [fromAc0: CARDINAL] = -- Do an SIO with ac0 passed in the Alto AC0. BEGIN code: ARRAY [0..2) OF CARDINAL ← [061004B, -- SIO 001400B -- JMP 0,3 ]; fromAc0 ← BcplOps.BcplJSR[JSR, BASE[code], ac0]; END; muFH: SegmentDefs.FileHandle ← NIL; muSeg: SegmentDefs.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 SegmentDefs; 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; 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 SegmentDefs; 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; END...