{
	File name:  CountBits.mc
	Description: CountBits Opcodes ------- CountBitsOn/CountBitsOff  -------
	Author:  Prabir Mohanty
	Created: June 2, 1986
}

{	Copyright (C) 1986 by Xerox Corporation.  All rights reserved.}






{************   Code for    CountBitsOff.mc    *******************************}




@COUNTBITSOFF:

at[ 06, 10, ESCAn ] 


{    Set L2 to 0 to execute only code of CountBitsOff. 	
			 L2 is set to 1 for code of CountBitsOn.         }


{    Retrieve Count from TOS to "R" register COUNT    } 
        
	L2 ← 0, Limit ← STK, pop, 				  c1;
	SrcBit ← STK, pop, GOTO[StartCount],	  		  c2;









{************   Code for    CountBitsOn.mc    *******************************}

@COUNTBITSON:

at[ 05, 10, ESCAn ] 



{***************           pop arguments    			 ***********}	

{    Set L2 to 1 to execute only code of CountBitsOn. 				 
     L2 is set to 0 for code of CountBitsOff.         }
{    The TOS has been redefined to "R" register COUNT.    } 
       
	 				 
 {   Retrieve Limit into R register.          }       
	L2 ← 1, Limit ← STK, pop, 	   			  c1;
	
	
	SrcBit ← STK, pop, 				  	  c2;


	


{********  Common  Code for CountBitsOn.mc  &  CountBitsOff.mc   *************}



	
StartCount:
 
{The common code of CountBitsOn and CountBitsOff starts from StartCount. The differences between
 the two algorithms is accounted for by making a two-way dispatch on link register L2 into different 
 pieces of code wherever necessary and joining back in the common region. }
				 
 {   Retrieve Destination virtual addr into R registers.          }	
	
	rhVirtualH ← STK,pop,	        	 	  c3;
	rVirtualL ← STK, fXpop, fZpop, 		 	  c1;
	GOTO[NOPageCarry],				  c2;
	




{*********************************************************************************
  CODE TO READ NEXT WORD AND CALL ADDREESS CONVERSION IN CASE OF PAGE CROSS
*********************************************************************************} 	
ReadNextWord:
	rSrcReal ← MAR ← [rhSrcReal, rSrcReal + 1], c1;{Addr of source word}  
	BRANCH[ $, PageCarryC, 1],		         		  c2;
	Data ←MD, GOTO[ CheckBitNumAndLimit],		  		  c3;

	
PageCarryC:
{ If page carry, update vitual page and remap to get the new real address 	}

	rVirtualL ← rVirtualL and ~0FF, CANCELBR[$,1],	{mask out low order 8 bits}	  c3;
	rVirtualL ← rVirtualL + r0100, CarryBr, { Add hex 100}		  c1;
{	Add 1 to rhVirtualH  just in case of carry and update if carry 		}       
	Q ← rhVirtualH + 1, LOOPHOLE[byteTiming],BRANCH[NOPageCarry,$],	  c2;

{	Update if page carry							}
	rhVirtualH ← Q LRot0, GOTO[MapAddr0],				  c3;

NOPageCarry:
	GOTO[MapAddr0],		 					  c3;


MapAddr0:
	temp ← Limit, ZeroBr,					  	  c1;
MapAddr:
        L0 ← L0.CountBits,BRANCH[ $, PreResults11],			  c2;
	CALL[MapSrc],							  c3;
	
	
	Data ← MD,GOTO[ CheckBitNumAndLimit ],  c3,MapSrcRet[L0.CountBits];

	


{*********************************************************************************
 	 CODE TO DECIDE WHETHER IT IS A BOUNDARY CASE OR FULL WORD CASE
*********************************************************************************}

	

CheckBitNumAndLimit:

{     Check if Bitno = 0. 		               }	
	SrcBit ← SrcBit and 0F, ZeroBr,			        	c1;
			
	
 {     Check if Limit >= 16, Branch to ZBitNo if Bitno = 0 or to NZBitNo if it is nonzero     }
	[]← Limit - 0F - 1, CarryBr, BRANCH[NonZeroSrcBit, ZeroSrcBit], c2; 
	
	
NonZeroSrcBit:
	temp ← SrcBit + 1,  CANCELBR[ShiftContinue,1],			c3; 

	
ZeroSrcBit:
{ 	Check to see if the word is all ones/zeros. Also if Limit >=16 branch to next instruction, 
 else to CheckBits ( in this case the Srcbit is zero and hence no preshifting necessary) for bit wise value checking. }
        BRANCH[ CheckBits, $ ],L2Disp, 		c3;

{	Branch to WordCount if the word is all ones/zeros else to next instruction which
starts the piece of code doing bit wise value checking.				}	

{	Branch to Countones if L2 = 1 else  to Countzeros		 }
    	BRANCH[ CountZeros, CountOnes],				c1;

	
{ 	For case of CountBitsOff, check that the word is all zeros       }	
CountZeros:[] ← Data, ZeroBr,GOTO[CommonPoint0],		c2;
{ 	For case of CountBitsOn, check that the word is all ones      	 }	
CountOnes:[] ← Data + 1, CarryBr, 				c2;


{The code for CountBitsOn and CountBitsOff  becomes common here again	 }
CommonPoint0:temp ← Limit - 0F -1, BRANCH[ BitWiseCheck, WordCount], c3;


{*********************************************************************************
 		 CODE TO PROCESS FULL WORDS OF ALL ONES/ZEROS 
*********************************************************************************}

WordCount:
{	The word is all ones/zeros and we update all the counters appropriately  and go
 onto check the next word. The Limit counter has already been calculated and put in "temp" 
 before we branched to this label. }
	Limit ← temp, ZeroBr, CANCELBR[$,1], 			 c1;
{ 	If Limit has reached zero, then processing  is done, go to push results   
	  Else fetch the next word from real memory and process.		}
       	Count ← Count + 0F + 1, BRANCH[ $, PushResults],	 c2;
	GOTO[ ReadNextWord ],	         			 c3;



			                          
{*********************CODE TO PROCESS BOUNDARY CASES AND SPECIAL CASE  ***************}
       
{	This portion of code does bitwise counting of ones/zeros in the word
 for the boundary cases and the special case }

BitWiseCheck:    					 
	temp ← SrcBit, ZeroBr, GOTO[ ShiftLoop ],		 c1;
ShiftContinue:
	temp ← temp -1,	ZeroBr,					 c1;
ShiftLoop:		
	BRANCH[ $, CheckBits1]			 		c2;
	Data ← Data LShift1, GOTO[ShiftContinue],  	c3;



CheckBits:
{  Bit-wise checking of destination bits					}

{  Branch to CountOness if L2 = 1 else to Countzeross 				}
	BRANCH[ CountZeross, CountOness], Data ← Data LShift1, NegBr,     c1;

	
CheckBits1:
{  Bit-wise checking of destination bits					}

{  Branch to CountOness if L2 = 1 else to Countzeross 				}
	L2Disp,								    c3;
	BRANCH[ CountZeross, CountOness], Data ← Data LShift1, NegBr,     c1;

CheckBits2:
{  Bit-wise checking of destination bits					}

{  Branch to CountOness if L2 = 1 else to Countzeross 				}
	BRANCH[ CountZeross, CountOness], Data ← Data LShift1, NegBr,     c1;

	
{  If met with a bit of opposite value, go to PushResults and terminate.	}
CountOness:Count ← Count  + 1,  BRANCH[PreResults0, CommonPoint1],    	    c2;
CountZeross:Count ← Count  + 1, BRANCH[CommonPoint11, PreResults00],	    c2;




{The code for CountBitsOn and CountBitsOff  becomes common here again	 }


CommonPoint11:
	SrcBit ← SrcBit + 1,  GOTO[CountContinue]        c3;

CommonPoint1:
	SrcBit ← SrcBit + 1,          	 		 c3;


CountContinue:	
{  The bit was of right value, continue bit-wise interrogation.	 Decrement 
number of bits still to be checked, i.e., Limit by 1				}	
	Limit ← Limit - 1,  ZeroBr,				 c1;
{  If Limit = 0, processing is done, go to push results.			}
	[] ← SrcBit - 0F -1, CarryBr, BRANCH[$, PreResults1], 	 c2;	 
{  If SrcBit is 16, it should point at zeroth bit of next word, reset it to zero.}
{  If SrcBit < 16, go to CheckBits, and continue bit-wise checking for rest of the word.}
	BRANCH[ CheckBits2, $], L2Disp,				 c3;
	SrcBit ← 0, CANCELBR[$,1]				 c1;
	Noop,							 c2;
	GOTO[ ReadNextWord ],		       			 c3;




{*********************************************************************************
 		 SET Count TO CORRECT VALUE
*********************************************************************************}	
PreResults0:
	Count ← Count - 1, GOTO[ SrcBitOk ],			c3;

PreResults00:
	Count ← Count - 1, GOTO[ SrcBitOk ],			c3;
	
			
	
{*********************************************************************************
 		 SET SrcBit Count TO CORRECT VALUE
*********************************************************************************}	
PreResults1: 
{If  SrcBit is 16, it should point at zeroth bit of next word, reset it to zero.	
 If SrcBit < 16, it is okay.							}
	BRANCH[SrcBitOk, $],    				  c3;  	
	SrcBit ←0,						  c1;
Proceed:	
	GOTO[ PushResults ],		 			  c2;
	
SrcBitOk:
	GOTO[ Pushvals0 ],					  c1;
	



{*****	 P R O C E S S I N G   D O N E ---- P U S H   T H E   R E S U L T S   ******}	


{    	Push  Destination virtual addr, SrcBit, Limit into Stack   	}	       
      	
PreResults11:
	Q ← rhVirtualH, push,GOTO[PushVals1],			  c3;

	
PushResults:
	rSrcReal  ← rSrcReal + 1, PgCarryBr,			  c3;
	BRANCH[ Pushvals0, $],			  		  c1;
	rVirtualL ← rVirtualL and ~0FF,				  c2;
	rVirtualL ← rVirtualL + r0100, CarryBr,			  c3;
	Q ← rhVirtualH + 1, LOOPHOLE[ byteTiming], BRANCH[ $, UpdatePageH],    c1;
UpdateNo:
	GOTO[PageHStore],						       c2;	
	 
UpdatePageH:
	rhVirtualH ← Q LRot0,					  c2;					
PageHStore:	   
      	Q ← rhVirtualH, push,GOTO[PushVals1],	  	 	  c3;
	

	
{ xxxxNext 3 instructions were added on Aug 5, 86 				}	



Pushvals0:
	Q ← rhVirtualH, push,					  c2;
	Noop,							  c3;

PushVals:
	rVirtualL ← rVirtualL and ~0FF,				  c1;
	rSrcReal ← rSrcReal and 0FF,				  c2;
	rVirtualL ← rVirtualL or rSrcReal,			  c3; 

PushVals1:
	STK ← rVirtualL, push,  				  c1;
	STK ← Q, push,						  c2;


{************** E X I T  T O   M E S A***************** }

	STK ← SrcBit, GOTO[ Bank1NxtInstc1 ],	    		  c3;
		
	



	
{*********************************************************************************

	T h e   P a g e   F a u l t   C a s e: save parameters in stack

********************************************************************************}

PageFault:
	Q ← rhVirtualH,	push,		  c3,MapSrcF[L0.CountBits];
	STK ← rVirtualL, push,  				c1;
	STK ← Q, push, 						c2;
	STK ←  SrcBit, push,					c3;
	STK ←  temp,						c1;
	GOTO[Bank1Fault],					c2;
	
{ Jump to the page fault handler routine in control store bank zero and return to 
the entry point with reexecution of opcode}