{
File name:		CompressAssist.mc
Description:		Special M'Code for data compression. (originally for DASH project)
Author:			KXI    
Created:		12-Nov-85  9:12:36
Last Edited:
        RCH   21-Jul-86 16:19:51: Cmmented PushByte, PushByteToWordBoundary
    	KXI	 31-Jan-86 15:42:01: fix double word increment bug in @PB and @PBWB.
	KXI	 30-Jan-86 19:03:36: use L2 instead of L3 in @PB and @PBWB. fix even odd confusion.
	KXI	 30-Jan-86 14:55:59: add comments {each MCode definition describing by Mesa}
	KXI	 29-Jan-86 15:25:26: fix page end operations in @NMAD.
	KXI	 22-Jan-86 14:55:24: change page end operations in @NMAD.
	KXI	 14-Jan-86 18:14:40: add comments, remove L0 ← L0.NextMatchAndDiff, RLMFRet[L0.NextMatchAndDiff] and L0 ← L0.CLR
	AEF	 28-Dec-85 15:19:10: Change - to xor, fix CLR 
	AEF	 27-Dec-85 20:08:33: Fix last word of page problems 
	AEF	 27-Dec-85 12:30:31: Remove stack pushes 
	AEF	 27-Dec-85 11:43:40: Remove ref bit check, change names to abbreviations 
	AEF	 26-Dec-85 17:20:38: Change dispatches to branches in non-dup loop
	AEF	 26-Dec-85 15:38:51: Change TOS to RH reg in CLR, change 99 to FF, use NxtInstc1 label
	KXI	 26-Dec-85 10:12:44: bugs in NextMatchAndDiff about page end processings..
	KXI	 23-Dec-85 13:01:27: The definition of @NextMatchAndDiff was changed..
				     If state = **FF at the begginig then RETURN[(startVA + 100) AND FFFF00, (startVA + 100) AND FFFF00] 
	KXI	 20-Dec-85 14:32:27: remove PC ← PC + 1. change L1 value for Map.
	KXI	 19-Dec-85 16:32:57: change assignment of ESC Alpha number for each byte codes.}

{******************************************************************************
 *	NMAD: NextMatchAndDiff					ESC + ['b][H] 
 ******************************************************************************}
{	TOS = STK[0]  = minMatchCount
	STK = STK[-1] = startVA.High
	      STK[-2] = startVA.Low
	Assumption: A page which startVA points to is resident, in other words is not swappable. and map flags are alredy set as (r,d,wp) = (1,*,*) {readOK}.So This byte code does not need to check map flags.}
	
@NMAD:								at[ 4, 10, ESC3n],
	rhCurRefWordVA ← STK, pop, 					c1;
	rCurRefWordVA ← STK,						c2;
	rTopOfCurrentPg.Low ← rCurRefWordVA and ~00FF{FF00},		c3;
	
	Map ← Q ← [rhCurRefWordVA, rCurRefWordVA], L1 ← L1.PushDec2,	c1;
	rTopOfNextPg.Low ← rTopOfCurrentPg.Low + 0FF + 1,		c2;
	rCurRefWordRA ← rhCurRefWordRA ← MD,				c3;

	MAR ← rCurRefWordRA ← [rhCurRefWordRA, Q+0], 			c1;
 	Noop,								c2;
	rWordA ← MD,							c3;

	MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1],	c1;
	Noop, DISP2[CheckCr]{We are sure that bit 15 = 0.},		c2;
	rWordB ← MD,							c3, at[0,4,CheckCr];
  
      
{   --	not in duplicate mode.}

NMAD.NotDupLoop:
	MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1],	c1;
NotDupLoop.1C2:
	[]← rWordA xor rWordB, ZeroBr, L1 ← 9, BRANCH[$, NotDup.NextIsPgEnd0, 1],c2;
	rWordA ← MD{nextRefWord}, BRANCH[$, NMAD.Dup0],			c3;
	
	MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1],	c1;
NotDupLoop.2C2:
	[]← rWordB xor rWordA, ZeroBr, L1 ← 0D, BRANCH[$, NotDup.NextIsPgEnd1, 0D],c2;
	rWordB ← MD{nextRefWord}, BRANCH[NMAD.NotDupLoop, NMAD.Dup1],	c3;

 
{   --	in duplicate mode.}

{ calculate and save dupStartVA value.}
NMAD.Dup0: {here L1 = 2}
	rDupStartVA.lowByte ← rCurRefWordRA and 00FF, GOTO[.Dup.a],	c1;
NMAD.Dup1: {here L1 = 6}
	rDupStartVA.lowByte ← rCurRefWordRA and 00FF, GOTO[.Dup.a],	c1;
.Dup.a:
	rDupStartVA.lowByte{00,,**} ← rDupStartVA.lowByte - 2{adjust}, L1Disp,c2;
	STK{dupStartVA.Low} ← rTopOfCurrentPg.Low or rDupStartVA.lowByte{00,,**},
					BRANCH[DupLoop.2C1, DupLoop.1C1, 0B],c3;


NMAD.DupLoop:
DupLoop.1C1:
	MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1],	c1;
	[]← rWordA xor rWordB, ZeroBr, BRANCH[$, Dup.NextIsPgEnd0, 1],	c2;
	rWordA ← MD{nextRefWord}, BRANCH[NMAD.EndOfDup0, $],		c3;
	
DupLoop.2C1:
	MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1],	c1;
	[]← rWordB xor rWordA, ZeroBr, BRANCH[$, Dup.NextIsPgEnd1, 1],	c2;
	rWordB ← MD{nextRefWord}, BRANCH[NMAD.EndOfDup1, NMAD.DupLoop],	c3;



{****	End of Dup Check   ****}
NMAD.EndOfDup0:{here it is sure that rCurRefWordRA # **00H}
	 Q ← rDupStartVA.lowByte{00,,**}+TOS{minMatchCount}+1{adjust},	c1;
	 []← rCurRefWordRA{curRefWord+1} - Q, PgCarryBr,		c2;
	 rTemp{00,,**} ← rCurRefWordRA and 00FF, BRANCH[NMAD.CancelDups0{<}, NMAD.OKDups0{>=}],c3;
NMAD.CancelDups0:
	    MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1], GOTO[NotDupLoop.2C2],c1;
	   
NMAD.OKDups0: {RETURN[dupStartVA, curRefWordVA], here dupStartVA is already in stack.}
Dup..OKDup.a:  rTemp ← rTemp{00,,**} - 1{adjust}, push,			c1;
.OKDups1.a:
	    TOS ← STK{dupStartVA.High=curRefWordVA.High}, push, IBDisp,	c2;
	    STK{curRefWordVA.low} ← rTopOfCurrentPg.Low or rTemp{00,,**}, DISPNI[OpTable],c3;



NMAD.EndOfDup1:{here it is sure that rCurRefWordRA # **00H}
	 Q ← rDupStartVA.lowByte{00,,**}+TOS{minMatchCount}+1{adjust},	c1;
	 []← rCurRefWordRA{curRefWord+1} - Q, PgCarryBr,		c2;
	 rTemp{00,,**} ← rCurRefWordRA and 00FF, BRANCH[NMAD.CancelDups1{<}, NMAD.OKDups1{>=}],c3;
NMAD.CancelDups1:
	    MAR ← rCurRefWordRA ← [rhCurRefWordRA, rCurRefWordRA+1], GOTO[NotDupLoop.1C2],c1;
NMAD.OKDups1:{RETURN[dupStartVA, curRefWordVA], here dupStartVA is already in stack.}
	    rTemp ← rTemp{00,,**} - 1{adjust}, push, GOTO[.OKDups1.a],	c1;


{****	Page End processing  ****}

{** from Initial Mode **}
{NMAD.PgEnd:  start = **FFH}{RETURN[(startVA + 100) AND FFFF00, (startVA + 100) AND FFFF00]}
	STK ← rTopOfNextPg.Low, ZeroBr, push,				c3, at[2,4,CheckCr];
	
NotDup..NotDupPgEnd:{RETURN[(startVA + 100) AND FFFF00, (startVA + 100) AND FFFF00]}
Dup..CancelDup.PgEnd:
.PgEnd.C1:
	  TOS ← STK{startVA.High}, BRANCH[$, .PgEnd.a.Cr],		c1;
	  IBDisp, push,							c2;
.PgEnd.C3:
	  STK ← rTopOfNextPg.Low, DISPNI[OpTable],			c3;


.PgEnd.a.Cr:
	     TOS ← TOS{startVA.High} + 1,				c2;
	     STK ← TOS{startVA.High+1}, GOTO[.PgEnd.C1],		c3;



{** from NotDup Mode **}
NotDup.NextIsPgEnd0: {here we have to complete the last 2-words comparing..}
	STK ← Q ← rTopOfNextPg.Low, ZeroBr, push, BRANCH[NotDup..NotDupPgEnd, NotDup..DupPgEnd],c3;
NotDup.NextIsPgEnd1: {here we have to complete the last 2-words comparing..}
	STK ← Q ← rTopOfNextPg.Low, ZeroBr, push, BRANCH[NotDup..NotDupPgEnd, NotDup..DupPgEnd],c3;

NotDup..DupPgEnd: {RETURN[(startVA AND FFFF00) + 0FEH, (startVA + 100) AND FFFF00], here StartVA.High is already in stack.}
Dup.NotDupPgEnd.DupOK:
	  Q ← Q{rTopOfNextPg.Low} - 2, pop, CANCELBR[$, 1],		c1;
	  STK{dupStartVA.low} ← Q,					c2;
	  [] ← rTopOfNextPg.Low, ZeroBr, push,				c3;
	  
	  TOS ← STK{startVA.High}, BRANCH[NotDup..DupPgEnd.NoCr, NotDup..DupPgEnd.Cr],c1;
NotDup..DupPgEnd.Cr:
Dup..DupPgEnd.Cr:
	    TOS ← TOS{startVA.High} + 1, IBDisp, push, GOTO[.PgEnd.C3],	c2;
NotDup..DupPgEnd.NoCr:
Dup..DupPgEnd.NoCr:
	    IBDisp, push, GOTO[.PgEnd.C3],				c2;



{** from Dup Mode **}
Dup.NextIsPgEnd0: {here we have to complete the last 2-words comparing..}
	  [] ← rTopOfNextPg.Low, ZeroBr, push, BRANCH[Dup..NotDupPgEnd, Dup..DupPgEnd],c3;
Dup.NextIsPgEnd1: {here we have to complete the last 2-words comparing..}
	  [] ← rTopOfNextPg.Low, ZeroBr, push, BRANCH[Dup..NotDupPgEnd, Dup..DupPgEnd],c3;

Dup..DupPgEnd: {RETURN[dupStartVA, (startVA + 100) AND FFFF00], here dupStartVA is already in stack.}
	     TOS ← STK{startVA.High}, BRANCH[Dup..DupPgEnd.NoCr, Dup..DupPgEnd.Cr],c1;


Dup..NotDupPgEnd:{here rCurRefWordRA = **00H.}
	     [] ← rDupStartVA.lowByte{00,,**}+TOS{minMatchCount}+1{adjust}, PgCarryBr, CANCELBR[$, 1],c1;
	     pop{adjust}, BRANCH[..OKDup{>=}, ..CancelDup{<}],		c2;
	     
..OKDup: {RETURN[dupStartVA, (startVA AND FFFF00) + 0FFH]}
	        rTemp{00,,**} ← 0FF+1{this value will be decrement 1 at Dup..OKDup.a:}, GOTO[Dup..OKDup.a],c3;
	      
..CancelDup: {RETURN[(startVA + 100) AND FFFF00, (startVA + 100) AND FFFF00]}      
	        STK ← rTopOfNextPg.Low, ZeroBr, push, GOTO[Dup..CancelDup.PgEnd],c3;
	  

{******************************************************************************
 *	PB: PushByte						ESC + ['b][H] 
 ******************************************************************************}
{	TOS = STK[0]  = [00,,byte]
	STK = STK[-1] = odd
	      STK[-2] = addr.high
	      STK[-3] = addr.low}
	      
{@PB:								at[5, 10, ESC3n],
	rEvenOdd ← STK{odd}, pop, ZeroBr,				c1;
	L2 ← 0, BRANCH[PB.Odd, PB.Even],				c2;
PB.Odd:
	rByteMask ← ~0FF{FF00}, GOTO[PB.a],{odd => L2=0},		c3;
PB.Even:
	rByteMask ← 0FF, GOTO[PB.a],{even => L2=1},			c3;} 
		
{PB.a:
PB.PBWB:{L2=0 from @PBWB}
	rByte{byte,,00} ← TOS{00,,byte} LRot8,				c1;
	rhTT ← STK{addr.high}, fZpop,					c2;
	TT{addr.low} ← STK{addr.low},					c3;  }

{PB.Map:
	Map ← Q ← [rhTT,TT], L0 ← L0.PushByte,				c1;
	L1 ← L1.Push2Dec2,						c2;
	Rx ← rhRx ← MD, XWtOKDisp,					c3;

	MAR ← [rhRx, Q+0], BRANCH[PB.WrNotOK, PB.WrOK,0D],c1, WLMFRet[L0.PushByte];}
{PB.WrNotOK:
	   CALL[WLMapFix],c2;	
	   {sub.WLMapFix return to "WLMFRet[L0.PushByte]"}}
	   
{PB.WrOK:
	Rx ← Q, L2Disp{odd => L2=0, even => L2=1},			c2;
	rData ← rByteMask and MD, DISP4[EvenOdd],			c3;}
		   
{PB.Even1:}
{PB.END:
	MAR ← [rhRx, Rx+0],						c1, at[1,10, EvenOdd];
	MDR ← rByte and rData, push, IBDisp,				c2;
	TOS ← rEvenOdd xor 1, DISPNI[OpTable],				c3;}


{{PB.Odd1:}
	   Q{addr.low+1} ← TT{addr.low} + 1, CarryBr,			c1, at[0,10, EvenOdd];
	   STK{addr.low+1} ← Q, push, BRANCH[PB.NotCr, PB.Cr],c2; }
{PB.NotCr:
	   rByte{00,,byte} ← TOS{00,,byte}, GOTO[PB.END],		c3;}
	   
{PB.Cr:
	      Q ← STK{addr.high},					c3;
	      
	      Q{addr.high+1} ← Q + 1,					c1;
	      STK{addr.high+1} ← Q, GOTO[PB.NotCr],			c2;}
	      
	

{******************************************************************************
 *	PBWB: PushByteToWordBoundary				ESC + ['b][H] 
 ******************************************************************************}
{	TOS = STK[0]  = [00,,byte]
	STK = STK[-1] = odd
	      STK[-2] = addr.high
	      STK[-3] = addr.low}
	      
{@PBWB:								at[6, 10, ESC3n],
	rEvenOdd ← STK, fZpop, L2 ← 0, ZeroBr,				c1;
	rhTT ← STK{addr.high}, fZpop, BRANCH[PBWB.Odd, PBWB.Even],	c2;}
{PBWB.Odd:
	rByteMask ← ~0FF{FF00}, push, GOTO[PB.PBWB],			c3;{here L2=0}}
	
{PBWB.Even:
	TT{addr.low} ← STK{addr.low},					c3;
	
	Map ← Q ← [rhTT,TT], L0 ← L0.PushByteToWB,			c1;
	rTemp{addr.low+1} ← TT{addr.low} + 1, L1 ← L1.Push2Dec2,	c2;
	Rx ← rhRx ← MD, XWtOKDisp,					c3;

	MAR ← [rhRx, Q+0], BRANCH[PBWB.WrNotOK, PBWB.WrOK,0D],c1, WLMFRet[L0.PushByteToWB];}
{PBWB.WrNotOK:
	   CALL[WLMapFix],c2;	
	   {sub.WLMapFix return to "WLMFRet[L0.PushByteToWB]"}}
	   
{PBWB.WrOK:
	MDR ← TOS{00,,byte},						c2;
	STK ← rTemp{addr.low+1}, push, ZeroBr,				c3;


	Q ← STK{addr.high}, BRANCH[PBWB.NotCr,PBWB.Cr],			c1;}
{PBWB.NotCr:
	  TOS{addr.high} ← Q, IBDisp, GOTO[PBWB.END],			c2;}   
{PBWB.Cr:
	  TOS{addr.high+1} ← Q + 1, IBDisp, GOTO[PBWB.END],		c2;}
{PBWB.END:
	STK ← TOS{addr.high+1}, TOS ← 0{FALSE}, DISPNI[OpTable],	c3;}
	

{******************************************************************************
 *	CLR: Clear						ESC + ['b][H] 
 ******************************************************************************}
 {	TOS = STK[0]  = destHi
 	STK = STK[-1] = destLow
	Assumption: A page which dest points to is resident, in other words is not swappable. and map flags are alredy set as (r,d,wp) = (1,1,0) {writeOK}. So This byte code does not need to check map flags.}
	
@CLR:								at[7, 10, ESC3n],
	rDestVA ← TOS {destHi},						c1;
	rhDestVA ← rDestVA LRot0,					c2;
	rDestVA ← STK{destLow}, pop,					c3;
	
	Map ← Q ← [rhDestVA, rDestVA],					c1;
	Noop,								c2;
	rDestRA ← rhDestRA ← MD,					c3;
	
	MAR ← rDestRA ← [rhDestRA, Q+0], GOTO[CLR.Loop.C2],		c1;
  
CLR.Loop:
	MAR ← rDestRA ← [rhDestRA, rDestRA+1],				c1;
CLR.Loop.C2:
	MDR ← 0, BRANCH[$, CLR.End, 1],					c2;
	Noop, GOTO[CLR.Loop],						c3;
	

CLR.End:
	TOS ← STK{STK[-2]}, pop, GOTO[NxtInstc1], {in Refill}		c3;
	
{NxtInstc1:	Noop,							c1;
IBDispOnly:	IBDisp,							c2;
DISPNIonly:	DISPNI[OpTable],					c3;}




{ ****** M'Code definitions {describibg by Mesa} ****** }

{-- MesaCompressAssistImpl.mesa

-- Revised by CharlieLevy:		      7-Nov-85 20:24:04
-- Owner: CharlieLevy
-- Copyright (C) Xerox Corporation 1985. All rights reserved.

DIRECTORY
  MesaCompressAssist, Environment, Inline;

MesaCompressAssistImpl: PROGRAM
  EXPORTS MesaCompressAssist =
  BEGIN OPEN MesaCompressAssist;

  -- Pack Data Structure:

  -- Signals and Errors:

  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----  ----
  -- Public Operations
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----  ----
  NextMatchAndDiff: PUBLIC PROC [start: LONG POINTER, matchCount:[2..7]]
      RETURNS [nextMatch, nextDiff: LONG POINTER] =
    BEGIN
    lptCur: LONG POINTER;
    bvInDup: BOOLEAN;
    wordCur: WORD;
    lptDupStart, lptNextPage: LONG POINTER;
    
    bvInDup ← FALSE;				-- start out presuming in difference mode
    lptNextPage ← start + 256 - (LOOPHOLE[start, LONG CARDINAL] MOD 256);
    						-- default to start of next page, client must check for reasonableness
    wordCur ← start↑;				-- the first word in the difference string
    lptCur ← start + 1;
    DO
       
       IF wordCur # lptCur↑ THEN		-- compare the current and new words
           BEGIN				-- two words are unequal
	   IF bvInDup THEN
	     BEGIN				-- bvInDup
	     IF (lptCur - lptDupStart >= matchCount) THEN
	       RETURN [lptDupStart, lptCur]	-- enough of a match to return results
	     ELSE
	       bvInDup ← FALSE;  		-- cancel dup mode because two words are unequal
	     END;				-- bvInDup
	   wordCur ← lptCur↑;			-- set new wordCur in case we haven't returned
	   END					-- of two words are unequal
         ELSE
           BEGIN				-- two words are equal
	   IF bvInDup = FALSE THEN		-- (if in dup mode and words are equal, do nothing)
	     BEGIN				-- we just made a transition to possible duping
	     bvInDup ← TRUE;			-- we are now in possible duping mode
	     lptDupStart ← lptCur - 1;		-- and here's where that word run starts
	     END;				-- transition to possible duping
	   END;					-- of two words are equal
	   
       lptCur ← lptCur + 1;			-- bump pointer for next time
       IF lptCur = lptNextPage THEN RETURN [IF bvInDup THEN lptDupStart ELSE lptNextPage, lptNextPage];
       						-- bouncing off end of page
       						-- client will inspect to see if large enough match at page fault, if he chooses
       ENDLOOP;
    END;					-- of NextMatchAndDiff
    
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
  PushByte: PUBLIC PROC [bPtrOld: BPtr, byte: Environment.Byte] RETURNS [bPtrNew: BPtr]=
    BEGIN
    IF bPtrOld.odd THEN
      BEGIN
      bPtrOld.adrs↑.low ← byte;
      RETURN [[bPtrOld.adrs + 1, FALSE]];
      END
    ELSE
      BEGIN
      bPtrOld.adrs↑.high ← byte;
      RETURN [[bPtrOld.adrs, TRUE]];
      END;
    END;					-- of PushByte
    
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
  PushByteToWordBoundary: PUBLIC PROC [bPtrOld: BPtr, byte: Environment.Byte] RETURNS [bPtrNew: BPtr]=
    BEGIN
    IF NOT bPtrOld.odd THEN bPtrOld.adrs↑.high ← 0;-- needs a NOP
    bPtrOld.adrs↑.low ← byte;			-- in either case
    RETURN [[bPtrOld.adrs + 1, FALSE]];		-- in either case
    END;					-- of PushByteToWordBoundary
    
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 
    Clear: PUBLIC PROC [start: LONG POINTER] =
    BEGIN 
    -- this should be faster than using Inline.LongCOPY[]
    lptCur, lptNextPage: LONG POINTER;
    
    lptNextPage ← start + 256 - (LOOPHOLE[start, LONG CARDINAL] MOD 256);
    						-- default to start of next page, client must check for reasonableness
    lptCur ← start;
    DO
       lptCur↑ ← 0;
       lptCur ← lptCur + 1;			-- bump pointer for next time
       IF lptCur = lptNextPage THEN RETURN;	-- bouncing off end of page
       ENDLOOP;
    END;					-- of Clear
    
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
  -- Private Procedures
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----    
  -- Mainline Code
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----  
  END.  -- of CompressAssistImpl 
  
  LOG
15-Oct-85 CharlieLevy   created module
22-Oct-85  CL started using page faults rather than endPlusOne
25-Oct-85 CL added PushByte and PushByteToWordBoundary
28-Oct-85  CL made faster running and desk checked
 5-Nov-85 Cl removed procs we decided not to use
 7-Nov-85 changedname from CompressAssistImpl
 7-Nov-85 changed return values at end of page from NIL to lptNextPage}