{
File : LispBitMapBit.mc
Author : Gunawan Santosa
Created : 26-Feb-85 14:05:34
================================================================================================
(BITMAPBIT BitMap X Y NewValue)
================================================================================================

	if 0 =< NewValue =< max value for a pixel
		then:	 Pixel(X, Y) ← NewValue
			 return old Pixel(X, Y)
			 
	if NewValue = NIL
		then:	 return Pixel(X, Y)
		
	else ERROR {UFN}

	in case (X, Y) outside BitMap
		then return 0 (and no mods)
		
	NOTE:   BitMap can also be a window
		UFN in this case!
		
	"BitMap" is a six word record of the following format:

	0:	BitMapBaseHi -- High word of Virtual Addr of [0, 0] of BitMap {upper left screen corner}
	1:	BitMapBaseLo -- Low word of Virtual Addr of [0, 0] of BitMap {upper left screen corner}
	2:	BitMapRasterWidth (words)
	3:	BitMapHeight (lines)
	4:	BitMapWidth (Pixels)
	5:	BitMapBitsPerPixel ({1 or 4 or 8})

	fetch stack parameters:
	S - 4:	BitMap	
	S - 2:	X
	S - 0:	Y
	TOS:	NewValue

	Test that the TYPE of BitMap = BitMapType
	fetch BitMap parameters:
	BitMapBaseHi -- High word of Virtual Addr of [0, 0] of BitMap {upper left screen corner}
	BitMapBaseLo -- Low word of Virtual Addr of [0, 0] of BitMap {upper left screen corner}
	BitMapRasterWidth (words)
	BitMapHeight (lines)
	BitMapWidth (Pixels)
	BitMapBitsPerPixel ({1 or 4 or 8})

	calculate word-address of pixel, and pixel-mask
	read old pixel value
	store new pixel value if appropriate
}

Set[BitMapType, 35'd]; {For BitMapBit}
Set[L0.BMMULT0, 5]; {For BitMapBit}
Set[L0.BMMULT1, 6]; {For BitMapBit}
Set[L0.BMB.NR.0B, 0B]; {For BitMapBit}
Set[L0.GBMP, 9]; {For BitMapBit}
 
RegDef[uBITMAPLO, U, 3A]; {For BitMapBit, low VA of Bitmap, tmp}
RegDef[uBITMAPHI, U,3B]; {For BitMapBit, high VA of Bitmap, tmp}
RegDef[uYLo, U, 57]; {For BitMapBit, low word of Y, tmp}

RegDef[uBITMAPBASELO, U, 42]; {For BitMapBit, low VA of Bitmapbase, tmp}
RegDef[uBITMAPBASEHI, U, 44]; {For BitMapBit, high VA of Bitmapbase, tmp}
RegDef[uBITMAPRASTERWIDTH, U, 2]; {For BitMapBit, Bitmaprasterwidth, tmp}
RegDef[uBITMAPHEIGHT, U, 3]; {For BitMapBit, Bitmapheight, tmp}
RegDef[uBITMAPWIDTH, U, 34]; {For BitMapBit, Bitmapwidth, tmp}
RegDef[uBITMAPBITSPERPIXEL, U, 7]; {For BitMapBit, Bitmapbitsperpixel, tmp}

RegDef[uDBMBaseLo, U, 30]; {For BitMapBit, low VA of Bitmapbase, tmp}
RegDef[uDBMBaseHi, U, 51]; {For BitMapBit, high VA of Bitmapbase, tmp}
RegDef[uDBRasterWidth, U, 53]; {For BitMapBit, Bitmaprasterwidth, tmp}
RegDef[uDBitMapHeight, U, 56]; {For BitMapBit, Bitmapheight, tmp}
RegDef[uDBitMapWidth, U, 55]; {For BitMapBit, Bitmapwidth, tmp}
RegDef[uDBitsPerPixel, U, 59]; {For BitMapBit, Bitmapbitsperpixel, tmp}

RegDef[uTT1, U, 47]; {For BitMapBit, tmp}
RegDef[uMASKL, U, 45]; {For BitMapBit, tmp}
RegDef[uZ, U, 35]; {For BitMapBit, tmp}

{
=======================================================================
Fetch BitMap, X, Y, and NewValue
=======================================================================

@FLOATARRAY2:	opcode[373'b],
	Bank ← FAOPBank, L1 ← 3{L1.LFA2prep},	c1;
	uTOS ← TOS,				c2;
	uTOSH ← TOSH, CROSS[FOP2],		c3;

	at[FOP2],
	Xbus ← ibNA, XDisp,			c1;
	DISP4[FOP2Disp], L2 ← 0,		c2;
}

	TT ← S, rhTT ← nRhS,			c3, at[06, 10, FOP2Disp];
						    {Link value for Bitmap parameters fetch}
						    
BR000:	MAR ← [rhS, S-1], L1 ← L1.NoFixesB2,	c1; {Point to high word of Y}
	TT ← TT - 2, CANCELBR[$, 2],		c2; {Prepare TT to fetch X}
	Q ← MD,					c3; 
		
	MAR ← [rhS, S+0], L3 ← 0,		c1; {Point to low word of Y}
	Ybus ← Q xor smallpl, ZeroBr,		c2;
	Q ← MD,	BRANCH[YNOK, $],		c3;

	MAR ← [rhTT, TT-1],			c1; {Point to high word of X}
	uYLo ← Q, CANCELBR[$, 2],		c2; {uYLo is low word of Y}
	Rx ← MD,				c3;
	
	MAR ← [rhTT, TT+0],			c1; {Point to low word of X}
	TT ← TT-2, L2 ← 6, 			c2; {Prepare TT to fetch BitMap}
	Q ← MD,	 				c3;

	MAR ← [rhTT, TT-1],				c1;
	Ybus ← Rx xor smallpl, CANCELBR[$, 2], ZeroBr,	c2; {uXLo is low word of X}
	Rx ← MD, BRANCH[XNOK, $],			c3; {Rx is high VA of BitMap}

	MAR ← [rhTT, TT+0],			c1;
	uXLo ← Q,  				c2; {uXHi is high word of X}
	TT ← MD, CALL[GetandTestBitMapParams],	c3; {TT is low VA of BitMap}
						    {Check Type of Bitmap and fetch Record}
	
	Ybus ← Q - 1, ZeroBr,			c3, at[6, 10, GetBitMapParamsRet];
					   	    {Q contains value of Bitsperpixel}	
{
======================================================
Determine bits per pixel value 
======================================================
}

	Ybus ← Q xor 4, ZeroBr, BRANCH[$, OneBitperPixel],			c1;
	Ybus ← Q xor 8, ZeroBr, BRANCH[$, FourBitsperPixel],			c2;
	TT ← RRot1 uXLo, BRANCH[IllegalBitsperPixel, EightBitsperPixel],	c3; {Divide X by 2}

OneBitperPixel:
	uMASKL ← Q, CANCELBR[$],	c2; {Load initial mask value (=1)}
	TT ← uXLo, GOTO[bmbvalchk],	c3; {Load X into TT}

FourBitsperPixel:
	Q ← 0F, CANCELBR[$],		c3; {Load initial mask value (=0000000000001111)}

	uMASKL ← Q,					c1;
	TT ← LShift1 uXLo, SE ← 0,			c2; {Divide X by 4}
	TT ← LShift1 TT, SE ← 0, GOTO[bmbvalchk],	c3; {Load the result into TT}

EightBitsperPixel:
	Q ← 0FF,			c1; {Load initial mask value (=0000000011111111)}
	uMASKL ← Q,			c2;
	TT ← TT LRot4, GOTO[bmbvalchk],	c3; {Multiply TT by 16}

bmbvalchk:

	Rx ← uBITMAPWIDTH,		c1; {Check if X inside Bitmap}
	Ybus ← Rx - TT - 1, CarryBr,	c2;
	uZ ← TT, BRANCH[XValTooBig, $],	c3; {uZ = X * Bits per pixel}
	
	TT ← TT and ~0F,		c1; {Divide TT by 16}
	TT ← TT LRot12,			c2;
	uXLo ← TT,			c3; {uXLo = X * Bits per pixel / 16}
	
	Ybus ← Q - TOS, CarryBr,			c1; {Check if NewValue doesn't exceed max value} 
	Rx ← uYLo, BRANCH[PixelValueTooBig, $],	c2;
	
	TT ← uBITMAPHEIGHT, L0 ← L0.BMMULT0,	c3;
	
	Q ← TT - Rx - 1, CarryBr,				c1;{Calculate the Y offset}
	TOS ← uBITMAPRASTERWIDTH, BRANCH[YValTooBig, $],	c2;
	CALL[MTPL],						c3; {Y*Bitmaprasterwidth}
			
{
================================================================================
Calculate address of pixel(X,Y)
================================================================================

Address = (Y*BITMAPRASTERWIDTH + (X*BITMAPBITSPERPIXEL)/16)+BITMAPBASE}

	Rx ← uXLo, L1 ← L1.RestoreTosB2,  		c2, at[L0.BMMULT0, 10, MULCALLER];
	Rx ← Rx + Q, CarryBr,				c3; {Start adding}
	
	Q ← uBITMAPBASELO, BRANCH[RXNC1, RXCR1],	c1; {Load low word of base address}

RXNC1:	GOTO[ADCL],					c2; {No carry to high order word}

RXCR1:	TT ← TT + 1, 					c2; {Propagate carry to high order word}
ADCL:	Rx ← Rx + Q, CarryBr, 				c3; {Set up low word of address}
AD11:	Q ← uBITMAPBASEHI, BRANCH[RXNC2, RXC2],		c1; {Load high word of base address}

RXNC2:	TT ← TT + Q, GOTO[HINC1],			c2;

RXC2:	TT ← TT + Q + 1, 				c2; {Propagate carry to high word}
HINC1:	rhTT ← TT LRot0, GOTO[HINC2],			c3;  {Set up high word of address}
			
{
================================================================================
Read pixel(X,Y)
================================================================================
}

HINC2:	Map ← TT ← [rhTT, Rx],			c1;
	L0 ← L0.BMB.NR.0B,			c2;
	rhRx ← Rx ← MD, XwdDisp,		c3;

	MAR ← Q ← [rhRx, TT + 0], DISP2[BMCHCK],	c1, at[L0.BMB.NR.0B, 10, NRWMapFixCallerB2];
	uRx ← Q,					c2, at[1, 4, BMCHCK];
	TT ← MD, 					c3; {Store it in TT}

	Rx ← uBITMAPBITSPERPIXEL ,	c1; 
	Q ← uZ, L0 ← 0A,		c2; {Retrieve X*Bits per pixel}
	Rx ← Q + Rx, YDisp, 		c3;						

{
==========================================================================	
Allign old pixels values
==========================================================================
	
Rotate left by : (((X*Bitsperpixel) mod 16) + Bitsperpixel) mod 16)
}

	Q ← uMASKL, DISP4[Allign],	c1; {Allign old pixel value to right hand side}
	uTTtmp ← TT,			c2, at[0A, 10, AllignRet]; {Save the entire word}
	TT ← TT and Q, 			c3; {Mask off unwanted bits}
	
	uTT1 ← TT, 				c1; {Save the old value}
	Ybus ← TOSH xor smallpl, ZeroBr,	c2; {Check if TOSH = 0E}
	TOS ← uTOS, BRANCH[TSQN, TSOK],		c3; {Retrieve new value}

{
=========================================================================	
Allign new pixels values
=========================================================================

Rotate left by: (16 - Bitsperpixel) - ((X*Bitsperpixel) mod 16)
}	
	
TSOK:	Q ← uTTtmp,			c1; {Retrieve the old word}
	TT ← Q - TT,			c2; {Mask off old value}
	TT ← TT or TOS,	L0 ← 0B,	c3; {Put the new value in}

	Ybus ← 0 - Rx, YDisp,		c1;
	Rx ← uRx, DISP4[Allign],	c2; {Allign the new word, restore Rx}
	S ← S - 6, GOTO[WrNV],		c3, at[0B, 10, AllignRet]; {Write new word}
	
TSQN:	Ybus ← TOSH or TOS, ZeroBr,	c1; {Check if new value is NIL}
	BRANCH[TSNK, TSN],		c2;

TSN:	TOSH ← smallpl,			c3; {Set up TOSH}
		
	Xbus ← ib,			c1;
	TOS ← uTT1,			c2; {Return old value of pixel (X,Y)}
	S ← S - 6, GOTO[c1.pc2B2],	c3; {Exit point when NewValue is NIL}
	
TSNK:	GOTO[ufnZ1],			c3;
	 
{
=======================================================================
Write NewValue into pixel(X, Y)
=======================================================================
}
	
WrNV:	MAR ← [rhRx, Rx + 0],		c1;
	MDR ← TT , Xbus ← ib,		c2; {Write it}
	TOS ← uTT1, GOTO[c1.pc2B2],	c3; {Exit point is here}
	
{
==============================================
(X,Y) is outside BITMAP or invalid number
==============================================

If X or Y is outside BITMAP, return 0.
}

XNOK:	GOTO[ufnX2],			c1;

YNOK:	GOTO[ufnX2],			c1;

XYER12:	TOS ← 0, Xbus ← ib,		c1; {If (X,Y) outside bitmap, return 0}
	TOSH ← smallpl,			c2;
	S ← S - 6, GOTO[c1.pc2B2],	c3;

XYER13:	TOS ← 0, Xbus ← ib,		c1; {If (X,Y) outside bitmap, return 0}
bmbsettosh:
	TOSH ← smallpl,			c2;
	S ← S - 6, GOTO[c1.pc2B2],	c3;

{
======================================================================
Bitmapbitsperpixel other than 1, 4 or 8, or NewValue exceeds max value
======================================================================
}

IllegalBitsperPixel:
	GOTO[ufnX2],	c1;

PixelValueTooBig:
	GOTO[ufnX1],	c3;

XValTooBig:
	TOS ← 0, Xbus ← ib, GOTO[bmbsettosh],	c1;

YValTooBig:
	TOS ← 0, Xbus ← ib, 	c3;
	
	GOTO[bmbsettosh],	c1;

{
=======================================================================
Map check
=======================================================================
}
	
	GOTO[NRWLMapFixB2],	c2, at[0, 4, BMCHCK];
	GOTO[NRWLMapFixB2],	c2, at[2, 4, BMCHCK];
	GOTO[NRWLMapFixB2],	c2, at[3, 4, BMCHCK];
	
{
=======================================================================
Multiplier subroutine
=======================================================================

Q = multiplicand
TOS = multiplier
Rx = counter
(TT Q) contains the result, Q is least significant word.
}

MTPL:	Rx ← 10,					c*{c1};
	TT ← 0,						c*{c2};
MLLP:	Ybus ← Q and 1, NZeroBr, 			c*{c3};

	Rx ← Rx - 1, ZeroBr, BRANCH[MPL0, MPL1],	c*{c1};
	
MPL0:	TT ← DARShift1 (TT + 0), BRANCH[MLLP, MLPE],	c*{c2};

MPL1:	TT ← DARShift1 (TT + TOS), BRANCH[MLLP, MLPE],	c*{c2};

MLPE:	Q ← ~Q, L0Disp,					c*{c3};

	RET[MULCALLER],					c*{c1};

{
=======================================================================
Test type of Bitmap and fetch record of Bitmap
=======================================================================

	subroutine to check BitMap type and get BitMap parameters

	Rx, TT have VA of BitMapTable
	L3 ← 0{Src}/1{Dst}  has six or'd in at exit
	L2 used for return
	uses NoFixes if PageFault
	trashes L0, L1, TT, Rx, Q, rhTT, rhRx
	values from table are placed into:
	if Src then : 	uBITMAPBASEHI		if Dst then :	uDBMBaseHi
			uBITMAPBASELO				uDBMBaseLo
			uBITMAPRASTERWIDTH			uDRasterWidth
			uBITMAPHEIGHT				uDBitMapHeight
			uBITMAPWIDTH				uDBitMapWidth
			uBITMAPBITSPERPIXEL			uDBitsPerPixel
			
Set[L0.GBMP, 09];{must be odd!  uses even also}}

GetandTestBitMapParams:
	MAR ← Q ← [TT, Rx + 0],			c1;{not mem ref, byte merge}
	rhTT ← Rx LRot0, 			c2;
	Rx ← Q, rhRx ← crhTypeTable,		c3;

	Rx ← Rx LRot8,				c1;
	Rx ← Rx RShift1, getTypemsBit, 		c2;
	Q ← 0FF,				c3;

	MAR ← [rhRx, Rx + 0],			c1;
	Rx ← BitMapType,			c2;
	Rx ← MD xor Rx,				c3;

GetBitMapParams:
	Map ← [rhTT, TT], L1 ← L1.NoFixesB2,			c1;
	Ybus ← Q and Rx, ZeroBr, L0 ← L0.GBMP,			c2;
	Rx ← rhRx ← MD, XRefBr, BRANCH[notBitMapufn, $],	c3;

	MAR ← Q ← [rhRx, TT + 0], BRANCH[GBMremapit, $],	c1, at[L0.GBMP, 10, RMapFixCallerB2];
	Rx ← Q, L3Disp,						c2;
	Q ← MD, L3Disp, DISP3[GBMfixitret, 1]			c3;

	MAR ← Rx ← [rhRx, Rx + 1], BRANCH[$, GBMdest1],		c1, at[1, 8, GBMfixitret];
	uBITMAPBASEHI ← Q, CANCELBR[$, 2],			c2;
GBMdest1ret:
	Q ← MD, L3Disp,						c3;

	MAR ← Rx ← [rhRx, Rx + 1], BRANCH[$, GBMdest2],		c1;
	uBITMAPBASELO ← Q, BRANCH[$, GBMfixitA, 1],		c2;
GBMdest2ret:
	Q ← MD, L3Disp,						c3;

	MAR ← Rx ← [rhRx, Rx + 1], BRANCH[$, GBMdest3, 2],	c1, at[3, 8, GBMfixitret];
	uBITMAPRASTERWIDTH ← Q, CANCELBR[$, 2],			c2;
GBMdest3ret:
	Q ← MD, L3Disp,						c3;

	MAR ← Rx ← [rhRx, Rx + 1], BRANCH[$, GBMdest4, 6], L3 ← 6,	c1;
	uBITMAPHEIGHT ← Q, BRANCH[$, GBMfixitB, 1],			c2;
GBMdest4ret:
	Q ← MD, L3Disp,							c3;

	MAR ← [rhRx, Rx + 1], BRANCH[$, GBMdest5, 6],			c1, at[7, 8, GBMfixitret];
	uBITMAPWIDTH ← Q, CANCELBR[$, 2],				c2;
GBMdest5ret:
	Q ← MD, L3Disp,							c3;

	BRANCH[$, GBMdest6, 6], L2Disp,					c1;
	uBITMAPBITSPERPIXEL ← Q, DISP4[GetBitMapParamsRet],		c2;

GBMdest1:
	uDBMBaseHi ← Q, CANCELBR[GBMdest1ret, 2],			c2;

GBMdest2:
	uDBMBaseLo ← Q, BRANCH[GBMdest2ret, GBMfixitA, 1],		c2;

GBMdest3:
	uDBRasterWidth ← Q, CANCELBR[GBMdest3ret, 2],			c2;

GBMdest4:
	uDBitMapHeight ← Q, BRANCH[GBMdest4ret, GBMfixitB, 1],		c2;

GBMdest5:
	uDBitMapWidth ← Q, CANCELBR[GBMdest5ret, 2],			c2;

GBMdest6:
	uDBitsPerPixel ← Q, DISP4[GetBitMapParamsRet],			c2;

GBMremapit:
	CALL[RLMapFixB2],						c2;

GBMfixitA:
	TT ← TT and ~0FF, GOTO[GBMallfixit],				c3;

GBMfixitB:
	TT ← TT and ~0FF, GOTO[GBMallfixit],				c3;

GBMallfixit:
	Q ← 0FF + 1,							c1;
	TT ← TT + Q, CarryBr,						c2;
	Rx ← 0, BRANCH[GetBitMapParams, GBMfixrh],			c3;

GBMfixrh:
	Q ← rhTT,							c1;
	Q ← Q + 1,							c2;
	rhTT ← Q LRot0,	GOTO[GetBitMapParams],				c3;
					
notBitMapufn:
	CANCELBR[ufnX2, 3],						c1;

	{END}