{ File Name: FlipX.mc 
  Description: Get mirror image for 1 bit or 8 bits data.
  Author: MYT
  Created: Nov 24, 1986
  Last edited: Dec 18, 1986 *after code review* 
  Last edited by JPM: Jan 15, 1987 *bug fix at fmcont (bad L0 value)* 
  		      Jan 28, 1987 *bug fix near fvrcom (width = 1 case didn't work)* 
}

{ Copyright (C) 1986 by XEROX corporation. All rights reserved.}

{ FlipX.mc includes 2 opcodes - FlipXBits and FlipXGray,

  L0 is caller for MapSrc and MapDst, L0=L0.FlipXRight for 1st right word, L0=L0.FlipXLast for other right words(MapSrc) and left words(MapDst)
  
  L2 is used to indicate bits or gray, L2=0 for FlipXBits, L2=1 for FlipXGray.
  L4 is used to indicate if 1st word to process, L4=0 for 1st word(either left or right),otherwise, L4=1.
  L7 is used to specify left ,right or middle word when page cross happened, L7=0 for left, L7=1 for right, L7=2 for middle.
  
  Globol subroutines called - ComMapWord (in ComMapSub) to bring in pages needed,
  			      MapSrc (in GrayBltSubs) to map real address for 1st right word and remap right word for page cross cases, L0 = L0.FlipXRight for 1st right word, L0 = L0.FlipXLast for remapping. 		
			      MapDst (in GrayBltSubs) to map real address for the left and middle word remap for page cross cases, L0 = L0.FlipXLast for left or middle word remapping.
}
@FlipXBits:

at [0B,10,ESCAn]

{****************************************************************************************
 	POP Parameters from stack for FlipXBits			
 ****************************************************************************************}
  {	Set L2 = 0 for FlipXBits			 }
	L2←0,bitWidth ← TOS,ZeroBr,			c1;{L2=0, TOS=width, bitWidth=r2 for commapsub }
	rhVirtualH ← Urhleft,BRANCH[flipxcommon,fnodataB], 	c2;{rhleft}
	
@FlipXGray:

at [0C,10,ESCAn]

{****************************************************************************************
 	POP Parameters from stack for FlipXGray			
 ****************************************************************************************}
  {	Set L2 = 1 for FlipXGray			 }
	L2←1,bitWidth ← TOS,ZeroBr,			c1;{L2=1, TOS=width, bitWidth=r2 for commapsub }
	rhVirtualH ← Urhleft,BRANCH[$,fnodataB],	c2;
	
flipxcommon:	
	rVirtualL ← Urleft,				c3;{rleft}

{****************************************************************************************			       		 	Save arguments and call ComMapWord to get left real address 	 			
****************************************************************************************}
	Uworkrleft ← rVirtualL,				c1;{ save rleft virtual address to some working U-reeg}
	Q ← rhVirtualH,					c2;{ save rhleft virtual address to some working U-reeg}
	Uworkrhleft ← Q,				c3;
	VD ← rVirtualL,					c1;{ set up parameters for left to call commapword}
	Q ← rhVirtualH,L1←1,				c2;
	rhVD ← Q LRot0,					c3;
	DBit←0,						c1;
	L3 ← L3.FlipX,					c2;{ L3 is caller for commapsub }
	CALL[ComMapWord],				c3;{ rcount=r2 } 
{ rC and rhC contains left real address after ComMapWord }
	BRANCH[$,FlipXPageFault],			c2,at [L3.FlipX,10,ComMapRet];
	rleftreal←BARealALo,				c3;{set up left real address from rC to r6(rleftreal)}
	Q ← BARealAHi,					c1;
	rhleftreal ← Q LRot0,				c2;
{ restore registers }
	width ← Uwidth,					c3;
	rVirtualL ← Urleft,				c1;
	rhVirtualH ← Urhleft,				c2;
{****************************************************************************************
 	virtual and real address process for the 1st left and right word			
 ****************************************************************************************}	
	bitWidth ← bitWidth - 1,L4 ← 0,			c3;
{ caculate right virtual address and save in U-register } 
	rVirtualL ← rVirtualL + bitWidth,CarryBr,	c1;{right = left + width - 1}
	Q ← rhVirtualH,BRANCH[$,fvrcarry],		c2;
	GOTO[fvrcom],					c3;
fvrcarry:
	Q ← Q + 1,					c3;{ if carry }
fvrcom:	Urright ← rVirtualL,L0 ← L0.FlipXRight,		c1;{ save right virtual address }
	rhVirtualH ← Q LRot0,	     			c2;{ rVirtualL=r0B the virtual address to call MapSrc  }
	Urhright ← Q,CALL[MapSrc],			c3;{ save rhright into U-reg, caller-rB, retrurned-r2 }
	width ← width DRShift1,				c3,MapSrcRet[L0.FlipXRight];{ width/2 = word count, bit inversed after DRShift1 }
	[] ← width,ZeroBr,				c1;
	USavecheck ← Q,BRANCH[$,fonlyone],		c2;{ bit15 of Q is flag for middle case, 0 is middle case, 1 is not. }
	Noop,						c3;
{****************************************************************************************			       			Read left or right data and branch to reverse 			
****************************************************************************************}	
fleft:	MAR ← [rhleftreal,rleftreal+0],L7←0,GOTO[fleftc2],	c1;{ 1st left word entry }
fleftloop:
	MAR ← rleftreal ← [rhleftreal,rleftreal+1],L7←0,	c1;
fleftc2:
	rcount ← 11,L2Disp,BRANCH[$,flpagecross,1],	c2;{ L2Disp checks if bits or gray }
	rwork ← MD,BRANCH[LReverseBits,$,2],		c3;{ read left data, branch to reverse left data }
	
frhtchk:
ftoright:
	rwork ← rwork LRot8,L7 ← 1,			c1;{ rotate left data for gray}
	rcount ← 11,L4Disp,				c2;{ L4Disp checks if 1st entry for right word }
	BRANCH [fright,frightloop,2],			c3;
		
fright:	MAR ← [rhrightreal,rrightreal+0],L4 ← 1,GOTO[frightc2],		c1;{ 1st right word entry, reset L4=1 for not first read} 
frightloop:
	MAR ← rrightreal ← [rhrightreal,rrightreal-1],	c1;	
frightc2:
	rtemp ← rwork,L2Disp,BRANCH[$,frpagecross,1], 	c2;{ store left reversed data }
	rwork ← MD,BRANCH[RReverseBits,$,2],		c3;{ read right data, branch to reverse right data }
	
fwrite:
	MAR ← [rhrightreal,rrightreal+0],		c1;
	MDR ← rtemp,					c2;{ write left reversed data to right }
fbrk0:	rwork ← rwork LRot8,				c3;{ rotate right data }

flpwrt:	MAR ← [rhleftreal,rleftreal+0],			c1;
	MDR ← rwork, width ← width - 1,ZeroBr,		c2;{ write right reversed data to left }
{updata word counter for next pair of words to flip}
	BRANCH [fleftloop,chkodd,2],			c3;
	
{****************************************************************************************			       			Reverse bits or byte 			
****************************************************************************************}
RReverseBits:{ right word }
	rwork ← rwork LRot8,GOTO[ReverseBits],		c1;{rotate rwork back, process reverse bits}
	
LReverseBits:{ left word }
	rwork ← rwork LRot8,GOTO[ReverseBits],		c1;{rotate rwork back, process reverse bits}
	
MReverseBits:{ middle word }
	rwork ← rwork LRot8,				c1;{rotate rwork back, process reverse bits}
	
ReverseBits:
	rcount ← rcount-1,ZeroBr,			c2;
	rwork ← rwork DRShift1,BRANCH[$,RevRet],	c3;
	rworkR ← rworkR DLShift1,GOTO [ReverseBits],		c1;
RevRet:	rwork ← ~rworkR,L7Disp,				c1;{invert result from Q}
	DISP2[fLRM],					c2;
fmto:	GOTO[fmrotate],					c3,at[2,4,fLRM];
flto:	GOTO[ftoright],					c3,at[0,4,fLRM];
frto:	GOTO[fwrite],					c3,at[1,4,fLRM];	
	
{****************************************************************************************			       			FlipX Page Cross Handler 			
****************************************************************************************}
flpagecross:{ page cross from left word }
	rVirtualL ← Uworkrleft,CANCELBR[fpcross,1],	c3;{ left word, same as fmpagecross }
	
frpagecross:{ page cross from right word }
	rVirtualL ← Urright,CANCELBR[$,1],		c3;{ restore previous right virtual address }
frnxt:	rhVirtualH ← Urhright,				c1;{rhright}
	rVirtualL ← rVirtualL or 0FF,L0 ← L0.FlipXLast, c2;{ mask out low order 8 bits }
	rVirtualL ← rVirtualL - r0100, CarryBr,		c3;{ new page number }
	Q ← rhVirtualH - 1,LOOPHOLE[byteTiming],BRANCH[$,frpno],	c1;
	rhVirtualH ← Q LRot0,GOTO[frpcom],		c2;	
frpno:	Noop,						c2;
frpcom:	Urright ← rVirtualL,				c3;{resave new right virtual address into working U-register}
	Q ← rhVirtualH,					c1;
	Urhright ← Q,					c2;{remap real address for right}
	CALL[MapSrc],					c3;{remap new page and get new real address}
	rwork ← MD,L7Disp,GOTO[fDisp],			c3,MapSrcRet[L0.FlipXLast];
		
fmpagecross:{ page cross from middle word }
	rVirtualL ← Uworkrleft,CANCELBR[$,1],		c3;{ use left process for middle word, restore the 1st left virtual address,L7=0 for left, L7=1 for right }
fpcross:
	rhVirtualH ← Uworkrhleft,			c1;{rhleft}
	rVirtualL ← rVirtualL and ~0FF,L0 ← L0.FlipXLast,	c2;{ mask out low order 8 bits }
	rVirtualL ← rVirtualL + r0100, CarryBr,		c3;{ new page number for left }
	Q ← rhVirtualH + 1, LOOPHOLE[byteTiming],BRANCH[fmcont,$],	c1;
	rhVirtualH ← Q LRot0,GOTO[fmpcom],			c2;
fmcont:	Noop,						c2;
fmpcom:	Uworkrleft ← rVirtualL,				c3;{update new virtual address into left working U-register*17*}
	Q ← rhVirtualH,					c1;
	Uworkrhleft ← Q,				c2; 
	CALL[MapDst],					c3;{remap new page and get new real address}
	rwork ← MD,L7Disp,				c3,MapDstRet[L0.FlipXLast];
fDisp:	DISP2[fLRMpc],					c1;
pcleft:	L2Disp,						c2,at[0,4,fLRMpc];
	BRANCH[LReverseBits,ftoright,2],		c3;{*17*}
pcmiddle:
	L2Disp,						c2,at[2,4,fLRMpc];		
	BRANCH[MReverseBits,fmrotate,2],		c3;{*17*}
pcright:
	L2Disp,						c2,at[1,4,fLRMpc];		
	BRANCH[RReverseBits,fwrite,2],			c3;{*17*}
		
{****************************************************************************************			       			FlipX Page Fault Handler 			
****************************************************************************************}
{{page fault from 1st right word mapping}
	GOTO[fpfRest],					c3,MapSrcF[L0.FlipXRight];
		
{page fault from right word pagecross remap}
	GOTO[fpfRest],					c3,MapSrcF[L0.FlipXLast];

{page fault from left or middle word remap}
	GOTO[fpfRest],					c3,MapDstF[L0.FlipXLast];}
FlipXPageFault:{page fault from commapsub for 1st left word}
	uFaultParm0 ← VD,				c3;
	T ← Q,						c1;
	Q ← rhVD,					c2;
	uFaultParm1 ← Q,				c3;
fpfRest:
	Noop,						c1;
	GOTO[Bank1Fault], 				c2;

{****************************************************************************************			       			odd case 			
****************************************************************************************}
fonlyone:{ only one word to process }
	rcount ← 11,					c3;
	MAR ← [rhleftreal,rleftreal+0],GOTO[fmiddlec2],	c1;{ 1st left word entry }	

chkodd:	rcount ← USavecheck,			c1;
	[] ← rcount+0,NegBr,		c2;
	rcount ← 11,BRANCH[foddnot1st,ftoexit],	c3;
	
foddnot1st:
	MAR ← rleftreal ← [rhleftreal,rleftreal+1],L7 ← 2{Flip.Middle},	c1;{ update L7 caller}
fmiddlec2:
	L2Disp,BRANCH[$,fmpagecross,1],			c2;
	rwork ← MD,BRANCH[MReverseBits,$,2],		c3;{ read middle data }
fmrotate:
	rwork ← rwork LRot8,				c1;
	Noop,						c2;
	Noop,						c3;	
	
fmtowrite:
	MAR ← [rhleftreal,rleftreal+0],			c1;{rotate data, set up write address, branch bits or gray}
fmwrite:
	MDR ← rwork ,					c2;{ write right data to left }

fnodataB:
	stackP ← 0,GOTO[Bank1NxtInstc1],		c3;
ftoexit:Noop,						c1;
	GOTO[fnodataB],					c2;