-- File: AltoRamLoader.mesa,  Last Edit: GEW  December 11, 1981  5:45 PM

-- This whole section was stolen and simplified from Mitchell's RamLoad for Juniper.
-- There is no check to be sure that Mesa is running in the Rom.

DIRECTORY
  AltoDefs USING [PageNumber, BytesPerPage, BytesPerWord],
  AllocDefs USING [MakeSwappedIn, DefaultDataSegmentInfo],
  BcplOps USING [BcplJSR],
  ControlDefs USING [GlobalFrameHandle],
  FrameDefs USING [GlobalFrame, SwapOutCode],
  FrameOps USING [Start, CodeHandle],
  ProcessDefs USING [DisableInterrupts, EnableInterrupts],
  SegmentDefs USING [
    FileHandle, FileSegmentHandle, Read, OldFileOnly, DefaultBase, DefaultPages,
    NewFile, NewFileSegment, DeleteFileSegment, GetEndOfFile, FileSegmentAddress,
    SwapIn, Unlock, SwapOut, FileNameError],
  Trouble USING [SetRamUnBooter],
  AltoRam USING [DoSilentBoot, UnBoot];

AltoRamLoader: PROGRAM
  IMPORTS
    AllocDefs, BcplOps, FrameDefs, FrameOps, ProcessDefs, SegmentDefs,
    Trouble, AltoRam
  EXPORTS AltoRam =
  BEGIN

  maxConstAddr: CARDINAL = 377B;
  sizeRam: CARDINAL = 2000B;

  PackedMuFile: TYPE = MACHINE DEPENDENT RECORD [
    brJunk: ARRAY [0..21B) OF UNSPECIFIED, -- header stuff in .br file
    bootVector: WORD,
    constVector: ARRAY [1..maxConstAddr] OF CARDINAL, -- const 0 is always zero
    ramVector: ARRAY [0..sizeRam) OF RamWord];
  RamWord: TYPE = MACHINE DEPENDENT RECORD [high, low: WORD];

  CantFindFile: PUBLIC ERROR = CODE;
  FileLooksCrufty: PUBLIC ERROR = CODE;

  LoadRamAndBoot: PUBLIC PROCEDURE [filename: STRING, dontLock: BOOLEAN ← FALSE] =
    BEGIN OPEN SegmentDefs;
    mu: POINTER TO PackedMuFile;
    muFH: FileHandle;
    muSeg: FileSegmentHandle;
    lastPage: AltoDefs.PageNumber;
    lastByteCount: [0..AltoDefs.BytesPerPage];
    i: CARDINAL;
    bootLocusVector: WORD;
    checkConstVec: ARRAY [1..13] OF CARDINAL =
      [1, 2, 177776B, 177777B, 177777B, 17B, 177777B, 3, 4, 5, 6, 7, 10B];
    muFH ← NewFile[
      filename, Read, OldFileOnly !
      SegmentDefs.FileNameError => ERROR CantFindFile];
    [page: lastPage, byte: lastByteCount] ← GetEndOfFile[muFH];
    IF lastPage # 12B THEN ERROR FileLooksCrufty;
    IF (lastByteCount MOD AltoDefs.BytesPerWord) # 0 THEN ERROR FileLooksCrufty;
    muSeg ← NewFileSegment[muFH, DefaultBase, DefaultPages, Read];
    SwapIn[muSeg];
    mu ← FileSegmentAddress[muSeg];
    bootLocusVector ← mu.bootVector;
    FOR i IN [1..13] DO
      -- check first few constants to be sure file isn't garbage
      IF checkConstVec[i] # mu.constVector[i] THEN ERROR FileLooksCrufty;
      ENDLOOP;
    IF ~dontLock THEN LockThingsInLowMemory[];
    ProcessDefs.DisableInterrupts[];
    WriteRam[@mu.ramVector];
    ProcessDefs.EnableInterrupts[];
    Unlock[muSeg];
    SwapOut[muSeg];
    DeleteFileSegment[muSeg];
    Trouble.SetRamUnBooter[AltoRam.UnBoot];
    AltoRam.DoSilentBoot[bootLocusVector];
    END;

  -- AltoRam.DoSilentBoot needs to be locked in bank 0 or things go POOF when we do the silent boot to move various tasks into the RAM.  The problem is that SilentBoot boot clears the bank registers, and the Mesa microcode expects them to point to the code segment.  NB: We leave AltoRam.DoSilentBoot locked because we must do another silent boot when we are finished to move the tasks back into the ROM.

  LockThingsInLowMemory: PUBLIC PROCEDURE =
    BEGIN
    gf: ControlDefs.GlobalFrameHandle;
    code: SegmentDefs.FileSegmentHandle;
    gf ← FrameDefs.GlobalFrame[AltoRam.DoSilentBoot];
    FrameOps.Start[[frame[gf]]];
    FrameDefs.SwapOutCode[gf];
    code ← FrameOps.CodeHandle[gf];
    AllocDefs.MakeSwappedIn[
      code, SegmentDefs.DefaultBase, AllocDefs.DefaultDataSegmentInfo];
    END;

  WriteRam: PROCEDURE [v: POINTER TO ARRAY [0..sizeRam) OF RamWord] =
    BEGIN
    -- This whole mess is in Bcpl code to make loading the RAM atomic for XMesa.
    code: ARRAY [0..14) OF CARDINAL ←
      [111000B, -- 	MOV 0,2
	055003B, -- 	STA 3,3,2
	025001B, -- 	LDA 1,1,2
	035002B, -- LP:	LDA 3,2,2
	021400B, -- 	LDA 0,0,3
	035401B, -- 	LDA 3,1,3
	061012B, -- 	WRTRAM
	125420B, -- 	INCZ 1,1
	011002B, -- 	ISZ 2,2
	011002B, -- 	ISZ 2,2
	015000B, -- 	DSZ 0,2
	000770B, -- 	JMP LP
	035003B, -- 	LDA 3,3,2
	001400B]; -- 	JMP 0,3
    acs: MACHINE DEPENDENT RECORD [n, ramAddr, vecAddr, svAc3: UNSPECIFIED];
    acs ← [n: sizeRam, ramAddr: 0, vecAddr: v, svAc3: NIL];
    [] ← BcplOps.BcplJSR[JSR, BASE[code], @acs];
    END;

  END.