-- ChecksumsImpl.mesa
-- last edit by: HGM March 5, 1981 3:47 PM
-- last edit by: BLyon January 16, 1981 9:54 AM

DIRECTORY
BufferDefs USING [OisBuffer],
Checksums USING [ComputeChecksum],
CommunicationInternal USING [],
CommUtilDefs USING [thisIsAnAlto],
PrincOpsUtils USING [BITAND, BITNOT, BITOR, BITSHIFT],
PrincOps USING [zADD, zDADD, zEXCH, zJ2, zJNE3, zLIN1, zLI0, zPUSH],
OISCPTypes USING [BufferBody];

ChecksumsImpl: PROGRAM
IMPORTS Checksums, PrincOpsUtils
EXPORTS CommunicationInternal, Checksums
SHARES BufferDefs =

BEGIN OPEN Checksums;

-- These procedures sets the checksum field of the Ois Packet.
SetChecksum: PUBLIC PROCEDURE [b: BufferDefs.OisBuffer] =
BEGIN
b.ois.checksum ←
IF CommUtilDefs.thisIsAnAlto THEN SlowlyComputeChecksum[
0, (b.ois.pktLength + 1)/2 - 1, @b.ois.pktLength]
ELSE ComputeChecksum[0, (b.ois.pktLength + 1)/2 - 1, @b.ois.pktLength];
END;

-- These procedures checks the checksum field of the Ois Packet,
-- and returns TRUE or FALSE. The buffer is always a system buffer

TestChecksum: PUBLIC PROCEDURE [b: BufferDefs.OisBuffer] RETURNS [BOOLEAN] =
BEGIN
cs: CARDINAL ← 0;
IF b.ois.checksum = 177777B THEN RETURN[TRUE];
cs ←
IF CommUtilDefs.thisIsAnAlto THEN SlowlyComputeChecksum[
cs, (b.ois.pktLength + 1)/2 - 1, @b.ois.pktLength]
ELSE ComputeChecksum[cs, (b.ois.pktLength + 1)/2 - 1, @b.ois.pktLength];
RETURN[b.ois.checksum = cs];
END;

SlowlyComputeChecksum: PUBLIC PROCEDURE [
cs: CARDINAL, nWords: CARDINAL, p: LONG POINTER] RETURNS [CARDINAL] =
BEGIN
t: CARDINAL;
THROUGH [0..nWords) DO
IF cs > (t ← cs + p^) THEN cs ← t + 1 ELSE cs ← t;
IF cs >= 100000B THEN cs ← cs*2 + 1 ELSE cs ← cs*2;
p ← p + 1;
ENDLOOP;
IF cs = 177777B THEN cs ← 0;
RETURN[cs];
END;

-- This procedure updates the checksum field of the Ois Packet
-- after it increments the oisTransportControl.

zz: PRIVATE POINTER TO OISCPTypes.BufferBody = NIL;
transportControlOffset: CARDINAL =
LOOPHOLE[@zz.transCntlAndPktTp, CARDINAL] - LOOPHOLE[zz, CARDINAL];
IncrOisTransportControlAndUpdateChecksum: PUBLIC PROCEDURE [
b: BufferDefs.OisBuffer] =
BEGIN
oldVal: WORD ← LOOPHOLE[b.ois.transCntlAndPktTp, CARDINAL];
resisdual: INTEGER;
b.ois.transCntlAndPktTp.transportControl.hopCount ←
b.ois.transCntlAndPktTp.transportControl.hopCount + 1;
IF b.ois.checksum = 177777B THEN RETURN;
resisdual ← PrincOpsUtils.BITAND[
(b.ois.pktLength + 1)/2 - transportControlOffset, 17B];
b.ois.checksum ← OnesAdd[
b.ois.checksum, LeftCycle[
OnesSub[LOOPHOLE[b.ois.transCntlAndPktTp, CARDINAL], oldVal], resisdual]];
END; -- UpdateChecksum

LeftCycle: PROCEDURE [val: CARDINAL, dist: INTEGER] RETURNS [CARDINAL] = INLINE
BEGIN OPEN PrincOpsUtils;
RETURN[BITOR[BITSHIFT[val, dist], BITSHIFT[val, dist - 16]]];
END;

OnesSub: PROCEDURE [a, b: CARDINAL] RETURNS [CARDINAL] = INLINE
BEGIN RETURN[OnesAdd[a, PrincOpsUtils.BITNOT[b]]]; END;

-- Beware: Making this work on a real Alto is quite tricky. If you get it wrong, it will do things like store 0 in the word the new checksum points at.
OnesAdd: PROCEDURE [a, b: CARDINAL] RETURNS [c: CARDINAL] = MACHINE CODE
BEGIN
-- c ← a + b; IF c<a THEN c ← c + 1; IF c=177777B THEN c ← 0;
PrincOps.zLI0;
PrincOps.zEXCH;
PrincOps.zLI0;
PrincOps.zDADD;
PrincOps.zADD;
PrincOps.zLIN1;
PrincOps.zJNE3;
PrincOps.zLI0;
PrincOps.zJ2;
PrincOps.zPUSH;
END;

END. -- ChecksumsImpl