-- Copyright (C) 1983, 1985  by Xerox Corporation. All rights reserved. 
-- PupMicrocodeBooter.mesa, HGM, 18-Jun-85  6:45:25

DIRECTORY
  Inline USING [LongCOPY, LowHalf],
  Process USING [Pause, Yield],
  Space USING [nullInterval],
  System USING [Pulses, GetClockPulses, PulsesToMicroseconds],

  Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool],
  BootServerDefs USING [microcodeReply, WhatHappened],
  BootServerFriends USING [BootFile, LockFileRead, SetupSpace, UnlockFile],
  PupDefs USING [PupBuffer, FastPath, GetLocalPupAddress, SendPup],
  PupTypes USING [PupAddress, miscSrvSoc];

PupMicrocodeBooter: PROGRAM
  IMPORTS Inline, Process, System, Buffer, PupDefs, BootServerFriends EXPORTS BootServerDefs
  =
  BEGIN

  microcodeVersionNumber: CARDINAL ← 1;

  MicrocodeBooter: PUBLIC PROCEDURE [
    bf: BootServerFriends.BootFile, him: PupTypes.PupAddress]
    RETURNS [what: BootServerDefs.WhatHappened] = {
    RETURN[RealMicrocodeBooter[bf, him, FALSE]]; };

  SlowMicrocodeBooter: PUBLIC PROCEDURE [
    bf: BootServerFriends.BootFile, him: PupTypes.PupAddress]
    RETURNS [what: BootServerDefs.WhatHappened] = {
    RETURN[RealMicrocodeBooter[bf, him, TRUE]]; };

  RealMicrocodeBooter: PROCEDURE [
    bf: BootServerFriends.BootFile, him: PupTypes.PupAddress, slow: BOOL]
    RETURNS [what: BootServerDefs.WhatHappened] =
    BEGIN
    pulses: System.Pulses ← System.GetClockPulses[];
    me: PupTypes.PupAddress ← PupDefs.GetLocalPupAddress[
      PupTypes.miscSrvSoc, @him];
    packetNumber: CARDINAL ← 0;
    pool: Buffer.AccessHandle;
    from: LONG POINTER;
    wordsLeft: CARDINAL ← Inline.LowHalf[bf.bytes/2];  -- won't work if more than 256 pages
    page: CARDINAL;
    IF ~PupDefs.FastPath[him] THEN slow ← TRUE;
    IF ~BootServerFriends.LockFileRead[bf] THEN RETURN[diskBusy];
    pool ← Buffer.MakePool[send: 10, receive: 0];
    IF bf.space = Space.nullInterval THEN BootServerFriends.SetupSpace[bf];
    from ← bf.space.pointer;
    BEGIN
    b: PupDefs.PupBuffer;
    IF from↑ # microcodeVersionNumber THEN GOTO MisMatch;
    from ← from + 256;  -- skip over header page in boot file
    wordsLeft ← wordsLeft - 256;
    FOR page ← 0, page + 3 DO
      length: CARDINAL;
      length ← IF wordsLeft > 255 THEN 255 ELSE wordsLeft;
      b ← Buffer.GetBuffer[pup, pool, send];
      b.pup.dest ← him;
      b.pup.source ← me;
      b.pup.pupID ← [microcodeVersionNumber, packetNumber];
      Inline.LongCOPY[from: from, nwords: length, to: @b.pup.pupWords[0]];
      PupDefs.SendPup[b, BootServerDefs.microcodeReply, length*2];
      IF slow THEN Pause[];
      packetNumber ← packetNumber + 1;
      from ← from + length;
      wordsLeft ← wordsLeft - length;
      IF wordsLeft = 0 THEN EXIT;
      -- second of three
      length ← IF wordsLeft > 255 THEN 255 ELSE wordsLeft;
      b ← Buffer.GetBuffer[pup, pool, send];
      b.pup.dest ← him;
      b.pup.source ← me;
      b.pup.pupID ← [microcodeVersionNumber, packetNumber];
      Inline.LongCOPY[from: from, nwords: length, to: @b.pup.pupWords[0]];
      PupDefs.SendPup[b, BootServerDefs.microcodeReply, length*2];
      IF slow THEN Pause[];
      packetNumber ← packetNumber + 1;
      from ← from + length;
      wordsLeft ← wordsLeft - length;
      IF wordsLeft = 0 THEN EXIT;
      -- third of three
      length ← IF wordsLeft > 258 THEN 258 ELSE wordsLeft;
      b ← Buffer.GetBuffer[pup, pool, send];
      b.pup.dest ← him;
      b.pup.source ← me;
      b.pup.pupID ← [microcodeVersionNumber, packetNumber];
      Inline.LongCOPY[from: from, nwords: length, to: @b.pup.pupWords[0]];
      PupDefs.SendPup[b, BootServerDefs.microcodeReply, length*2];
      IF slow THEN Pause[];
      packetNumber ← packetNumber + 1;
      from ← from + length;
      wordsLeft ← wordsLeft - length;
      IF wordsLeft = 0 THEN EXIT;
      ENDLOOP;
    b ← Buffer.GetBuffer[pup, pool, send];
    b.pup.dest ← him;
    b.pup.source ← me;
    b.pup.pupID ← [microcodeVersionNumber, packetNumber];
    PupDefs.SendPup[b, BootServerDefs.microcodeReply, 0];  -- End Marker for Initial
    pulses ← System.Pulses[System.GetClockPulses[] - pulses];
    bf.count ← bf.count + 1;
    bf.ms ← bf.ms + System.PulsesToMicroseconds[pulses]/1000;
    what ← micro;
    EXITS MisMatch => what ← troubles;
    END;
    BootServerFriends.UnlockFile[bf];
    Buffer.DestroyPool[pool];
    END;

  microsecondsToPause: LONG CARDINAL ← 10000;
  saveTheCpu: BOOL ← FALSE;
  Pause: PROCEDURE =
    BEGIN
    start: System.Pulses ← System.GetClockPulses[];
    DO
      pulses: System.Pulses ← System.Pulses[System.GetClockPulses[] - start];
      IF saveTheCpu THEN Process.Pause[1] ELSE Process.Yield[];
      IF System.PulsesToMicroseconds[pulses] > microsecondsToPause THEN EXIT;
      ENDLOOP;
    END;
    
  END.