-- File: AMCUCold.mesa,  Last Edit: HGM  January 6, 1981  9:51 PM

DIRECTORY
  AltoDefs USING [PageSize],
  BcplOps USING [BcplJSR],
  ControlDefs USING [GlobalFrameHandle],
  FrameDefs USING [MakeCodeResident, UnlockCode, GlobalFrame],
  InlineDefs USING [BITOR],
  Mopcodes USING [zPOP],
  ProcessDefs USING [InterruptLevel, CV, DisableInterrupts, EnableInterrupts],
  Runtime USING [CallDebugger],
  SDDefs USING [SD, sIOResetBits],
  SegmentDefs USING [
    DataSegmentHandle, VMtoDataSegment, DeleteDataSegment, PupBufferDS],
  SystemDefs USING [AllocateResidentPages],

  StatsDefs USING [StatsGetCounters, StatsGetText],
  CommUtilDefs USING [magicMemoryLocation],
  CommFlags USING [doDebug, doStats],
  DriverDefs USING [GetGiantVector],
  PupDefs USING [];

AMCUCold: PROGRAM
  IMPORTS
    BcplOps, FrameDefs, InlineDefs, ProcessDefs, Runtime, SegmentDefs, SystemDefs,
    StatsDefs, DriverDefs
  EXPORTS CommUtilDefs, DriverDefs, PupDefs =
  BEGIN

  errorHandler: PROCEDURE [ERROR] ← DefaultErrorHandler;

  CaptureErrors: PUBLIC PROCEDURE [proc: PROCEDURE [ERROR]] =
    BEGIN errorHandler ← proc END;

  DefaultErrorHandler: PROCEDURE [why: ERROR] =
    BEGIN Runtime.CallDebugger["PupGlitch"L]; Glitch[why]; END;

  Glitch: PUBLIC PROCEDURE [why: ERROR] = BEGIN errorHandler[why]; END;

  InterruptLevelAlreadyInUse: PUBLIC ERROR = CODE;
  InterruptLevelNotInUse: PUBLIC ERROR = CODE;

  AddInterruptHandler: PUBLIC PROCEDURE [
    i: ProcessDefs.InterruptLevel, c: POINTER TO CONDITION, w: WORD] =
    BEGIN
    IF ProcessDefs.CV[i] # NIL THEN Glitch[InterruptLevelAlreadyInUse];
    ProcessDefs.CV[i] ← c;
    ProcessDefs.DisableInterrupts[];
    SDDefs.SD[SDDefs.sIOResetBits] ← InlineDefs.BITOR[
      SDDefs.SD[SDDefs.sIOResetBits], w];
    ProcessDefs.EnableInterrupts[];
    END;

  RemoveInterruptHandler: PUBLIC PROCEDURE [i: ProcessDefs.InterruptLevel] =
    BEGIN
    IF ProcessDefs.CV[i] = NIL THEN Glitch[InterruptLevelNotInUse];
    ProcessDefs.CV[i] ← NIL;
    END;


  myHostNumber: CARDINAL ← 0;
  GetEthernetHostNumber: PUBLIC PROCEDURE RETURNS [CARDINAL] =
    BEGIN
    HostCode: ARRAY [0..3) OF WORD ←
      [102400B, -- sub 0,0
	061004B, -- startio - returns host number in ac0
	001400B]; -- jmp 0,3
    IF myHostNumber # 0 THEN RETURN[myHostNumber];
    RETURN[BcplOps.BcplJSR[JSR, @HostCode[0], NIL] MOD 400B];
    END;

  SmashMyHostNumber: PUBLIC PROCEDURE [new: CARDINAL] =
    BEGIN myHostNumber ← new; END;

  Shorten: PROCEDURE [LONG POINTER] RETURNS [POINTER] = MACHINE CODE
    BEGIN Mopcodes.zPOP; END;


  LockCode: PUBLIC PROCEDURE [what: UNSPECIFIED] =
    BEGIN
    who: ControlDefs.GlobalFrameHandle = FrameDefs.GlobalFrame[what];
    FrameDefs.MakeCodeResident[who];
    END;

  UnlockCode: PUBLIC PROCEDURE [what: UNSPECIFIED] =
    BEGIN
    who: ControlDefs.GlobalFrameHandle = FrameDefs.GlobalFrame[what];
    FrameDefs.UnlockCode[who];
    END;



  -- Used only to allocate a/the buffer pool

  AllocateBuffers: PUBLIC PROCEDURE [nwords: CARDINAL] RETURNS [LONG POINTER] =
    BEGIN
    pages: CARDINAL ← (nwords + AltoDefs.PageSize - 1)/AltoDefs.PageSize;
    base: POINTER ← SystemDefs.AllocateResidentPages[pages];
    seg: SegmentDefs.DataSegmentHandle;
    seg ← SegmentDefs.VMtoDataSegment[base];
    seg.type ← SegmentDefs.PupBufferDS;
    RETURN[base];
    END;

  FreeBuffers: PUBLIC PROCEDURE [base: LONG POINTER] =
    BEGIN
    seg: SegmentDefs.DataSegmentHandle;
    seg ← SegmentDefs.VMtoDataSegment[Shorten[base]];
    SegmentDefs.DeleteDataSegment[seg];
    END;

  AllocateIocbs: PUBLIC PROCEDURE [nwords: CARDINAL] RETURNS [LONG POINTER] =
    BEGIN
    pages: CARDINAL ← (nwords + AltoDefs.PageSize - 1)/AltoDefs.PageSize;
    RETURN[SystemDefs.AllocateResidentPages[pages]];
    END;

  FreeIocbs: PUBLIC PROCEDURE [base: LONG POINTER] =
    BEGIN
    seg: SegmentDefs.DataSegmentHandle;
    seg ← SegmentDefs.VMtoDataSegment[Shorten[base]];
    SegmentDefs.DeleteDataSegment[seg];
    END;

  SetDebuggingPointer: PUBLIC PROCEDURE [where: LONG POINTER] =
    BEGIN CommUtilDefs.magicMemoryLocation↑ ← Shorten[where]; END;


  -- initialization

  IF CommFlags.doDebug AND CommFlags.doStats THEN
    BEGIN
    DriverDefs.GetGiantVector[].statCounters ← StatsDefs.StatsGetCounters[];
    DriverDefs.GetGiantVector[].statStrings ← StatsDefs.StatsGetText[];
    END;
  END.