-- File: PupMicrocodeBooterAlto.mesa,  Last Edit: HGM  November 2, 1980  12:10 PM

DIRECTORY
  Environment USING [bytesPerPage],
  System USING [Pulses, GetClockPulses, PulsesToMicroseconds],
  Lock USING [LockDisk, UnlockDisk],
  BootServerDefs USING [
    BootFile, WhatHappened, microcodeReply, microcodeVersionNumber],
  ReadDefs USING [
    CBZptr, CBptr, GetNextPage, ReleasePage, StartReading, StopReading],
  CommUtilDefs USING [CopyLong],
  PupDefs USING [PupBuffer, GetLocalPupAddress, GetFreePupBuffer, SendPup],
  PupTypes USING [PupAddress, miscSrvSoc];

PupMicrocodeBooterAlto: PROGRAM
  IMPORTS System, Lock, CommUtilDefs, ReadDefs, PupDefs EXPORTS BootServerDefs =
  BEGIN OPEN BootServerDefs;

  blankDisplay: BOOLEAN ← TRUE;

  bufferSize: CARDINAL ← 5; -- patch by hand to adjust

  MicrocodeBooter: PUBLIC PROCEDURE [bf: BootFile, him: PupTypes.PupAddress]
    RETURNS [what: WhatHappened] =
    BEGIN
    zone: ReadDefs.CBZptr;
    cb: ReadDefs.CBptr;
    pulses: System.Pulses ← System.GetClockPulses[];
    packetNumber: CARDINAL ← 0;
    n: CARDINAL;
    chunk: POINTER TO ARRAY [0..0) OF WORD;
    me: PupTypes.PupAddress ← PupDefs.GetLocalPupAddress[
      PupTypes.miscSrvSoc, @him];
    IF ~Lock.LockDisk[bf.fileName, read, blankDisplay] THEN RETURN[diskBusy];
    BEGIN
    one, two: WORD;
    b: PupDefs.PupBuffer;
    zone ← ReadDefs.StartReading[@bf.file.fID, bufferSize];
    cb ← ReadDefs.GetNextPage[zone]; -- skip file system leader page
    ReadDefs.ReleasePage[cb];
    cb ← ReadDefs.GetNextPage[zone]; -- skip boot file header page
    chunk ← cb.dataAddress;
    IF chunk[0] # microcodeVersionNumber THEN GOTO MisMatch;
    ReadDefs.ReleasePage[cb];
    -- It takes 3 Alto words to specify a complete D0 ControlStore word.  In order to simplify the EProm logic, the Boot Server sends packets that have an integral number of ControlStore words.  Unfortunately that doesn't mesh with the Alto wordsPerPage.  That is the story behind the following verbose clump of code.
    DO
      length: CARDINAL;
      -- first of three
      cb ← ReadDefs.GetNextPage[zone];
      chunk ← cb.dataAddress;
      n ← cb.labelAddress.bytes;
      IF n = 0 THEN EXIT;
      length ← IF n = Environment.bytesPerPage THEN n - 2 ELSE n;
      b ← PupDefs.GetFreePupBuffer[];
      b.dest ← him;
      b.source ← me;
      b.pupID ← [microcodeVersionNumber, packetNumber];
      CommUtilDefs.CopyLong[from: @chunk[0], nwords: 255, to: @b.pupWords[0]];
      one ← chunk[255];
      PupDefs.SendPup[b, BootServerDefs.microcodeReply, length];
      packetNumber ← packetNumber + 1;
      ReadDefs.ReleasePage[cb];
      IF n # Environment.bytesPerPage THEN EXIT;
      -- second of three
      cb ← ReadDefs.GetNextPage[zone];
      chunk ← cb.dataAddress;
      n ← cb.labelAddress.bytes;
      length ← IF n = Environment.bytesPerPage THEN n - 2 ELSE n + 2;
      b ← PupDefs.GetFreePupBuffer[];
      b.dest ← him;
      b.source ← me;
      b.pupID ← [microcodeVersionNumber, packetNumber];
      b.pupWords[0] ← one;
      -- copy extra word in case this is the last page
      CommUtilDefs.CopyLong[from: @chunk[0], nwords: 255, to: @b.pupWords[1]];
      one ← chunk[254];
      two ← chunk[255];
      PupDefs.SendPup[b, BootServerDefs.microcodeReply, length];
      packetNumber ← packetNumber + 1;
      ReadDefs.ReleasePage[cb];
      IF n # Environment.bytesPerPage THEN EXIT;
      -- third of three
      cb ← ReadDefs.GetNextPage[zone];
      chunk ← cb.dataAddress;
      n ← cb.labelAddress.bytes;
      b ← PupDefs.GetFreePupBuffer[];
      b.dest ← him;
      b.source ← me;
      b.pupID ← [microcodeVersionNumber, packetNumber];
      b.pupWords[0] ← one;
      b.pupWords[1] ← two;
      CommUtilDefs.CopyLong[from: @chunk[0], nwords: 256, to: @b.pupWords[2]];
      PupDefs.SendPup[b, BootServerDefs.microcodeReply, n + 4];
      packetNumber ← packetNumber + 1;
      ReadDefs.ReleasePage[cb];
      IF n # Environment.bytesPerPage THEN EXIT;
      ENDLOOP;
    b ← PupDefs.GetFreePupBuffer[];
    b.dest ← him;
    b.source ← me;
    b.pupID ← [microcodeVersionNumber, packetNumber];
    PupDefs.SendPup[b, BootServerDefs.microcodeReply, 0];
    -- End Marker for Initial
    ReadDefs.StopReading[zone];
    pulses ← System.Pulses[System.GetClockPulses[] - pulses];
    bf.count ← bf.count + 1;
    bf.ms ← bf.ms + System.PulsesToMicroseconds[pulses]/1000;
    what ← micro;
    EXITS MisMatch => BEGIN ReadDefs.StopReading[zone]; what ← troubles; END;
    END;
    Lock.UnlockDisk[bf.fileName, blankDisplay];
    END;

  END.