-- File: PupChecksums.mesa,  Last Edit: HGM  October 15, 1980  7:37 PM

DIRECTORY
  MiscAlpha USING [aCHKSUM],
  Mopcodes USING [zMISC, zPOP, zADD, zDADD, zEXCH, zDUP, zLI0],
  AltoRam USING [PupChecksum],
  PupRouterDefs USING [Checksum],
  CommUtilDefs USING [thisIsAnAlto],
  BufferDefs USING [PupBuffer];

PupChecksums: PROGRAM IMPORTS AltoRam EXPORTS PupRouterDefs =
  BEGIN

  checksum: PUBLIC PupRouterDefs.Checksum ←
    IF CommUtilDefs.thisIsAnAlto THEN software ELSE princOps;

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

  ComputeD0Checksum: PROCEDURE [cs: CARDINAL, nWords: CARDINAL, p: LONG POINTER]
    RETURNS [CARDINAL] = MACHINE CODE
    BEGIN Mopcodes.zMISC, MiscAlpha.aCHKSUM; END;

  OnesComplementAddAndCycle: PROCEDURE [a, b: LONG UNSPECIFIED]
    RETURNS [UNSPECIFIED] = MACHINE CODE
    BEGIN
    Mopcodes.zDADD;
    Mopcodes.zADD; -- Ones add if a+b are in CARDINAL range
    Mopcodes.zDUP;
    Mopcodes.zLI0;
    Mopcodes.zEXCH;
    Mopcodes.zLI0; -- Make LONG again
    Mopcodes.zDADD;
    Mopcodes.zADD;
    END;


  SetPupChecksum: PUBLIC PROCEDURE [b: BufferDefs.PupBuffer] =
    BEGIN
    size: CARDINAL ← (b.pupLength - 1)/2;
    checksumLoc: LONG POINTER ← @b.pupLength + size;
    cs: CARDINAL;
    SELECT checksum FROM
      princOps =>
	BEGIN checksumLoc↑ ← ComputeD0Checksum[0, size, @b.pupLength]; END;
      alto =>
	BEGIN
	where: POINTER ← ShortenData[@b.pupLength];
	checksumLoc↑ ← AltoRam.PupChecksum[0, where, size];
	END;
      none => BEGIN checksumLoc↑ ← 177777B; END;
      software =>
	BEGIN
	p: LONG POINTER TO ARRAY [0..0) OF WORD = LOOPHOLE[@b.pupLength];
	cs ← 0;
	FOR i: CARDINAL IN [0..size) DO
	  cs ← OnesComplementAddAndCycle[p[i], cs]; ENDLOOP;
	IF cs = 177777B THEN cs ← 0;
	checksumLoc↑ ← cs;
	END;
      ENDCASE => NULL;
    END;

  TestPupChecksum: PUBLIC PROCEDURE [b: BufferDefs.PupBuffer] RETURNS [BOOLEAN] =
    BEGIN
    size: CARDINAL ← ((LOOPHOLE[b.pupLength - 1, CARDINAL])/2);
    checksumLoc: LONG POINTER ← @b.pupLength + size;
    cs: CARDINAL;
    IF checksumLoc↑ = 177777B THEN RETURN[TRUE];
    SELECT checksum FROM
      princOps =>
	BEGIN
	-- BEWARE: The stack must be empty.  Dont try RETURN[xx↑=PupChecksum[xxx]];
	cs ← ComputeD0Checksum[0, size, @b.pupLength];
	END;
      alto =>
	BEGIN
	where: POINTER ← ShortenData[@b.pupLength];
	-- BEWARE: The stack must be empty.  Dont try RETURN[xx↑=PupChecksum[xxx]];
	cs ← AltoRam.PupChecksum[0, where, size];
	END;
      none => BEGIN RETURN[TRUE]; END;
      software =>
	BEGIN
	p: LONG POINTER TO ARRAY [0..0) OF WORD = LOOPHOLE[@b.pupLength];
	cs ← 0;
	FOR i: CARDINAL IN [0..size) DO
	  cs ← OnesComplementAddAndCycle[p[i], cs]; ENDLOOP;
	IF cs = 177777B THEN cs ← 0;
	END;
      ENDCASE => NULL;
    RETURN[checksumLoc↑ = cs];
    END;

  END.