QuickDraw/BitBlt.a

797 lines
36 KiB
Plaintext
Executable File

.INCLUDE GRAFTYPES.TEXT
;---------------------------------------------------------------
;
; --> BITBLT.TEXT
;
; Low-level bit boundary block transfer.
;
.PROC BITBLT,7
.REF LEFTMASK,RIGHTMASK,PATEXPAND
;--------------------------------------------------------------
;
; PROCEDURE BitBlt(srcBits,dstBits: BitMap;
; srcRect,dstRect: Rect;
; mode: INTEGER; pat: Pattern);
;
; TRANSFERS A RECTANGULAR BLOCK OF BITS WITH NO CLIPPING AT ALL.
; MODE SPECIFIES THE COMBINATION MODE AND WHETHER THE SOURCE SHOULD COME
; FROM THE SOURCE BITMAP OR FROM A REPEATING PATTERN.
;
; COPYRIGHT APPLE COMPUTER INC.
; WRITTEN BY BILL ATKINSON
;
; POSITION INDEPENDENT AND RE-ENTRANT, CLOBBERS ONLY A0.
;
; MODES: 0 SRC --> DST
; 1 SRC OR DST --> DST
; 2 SRC XOR DST --> DST
; 3 SRC BIC DST --> DST
;
; 4 (NOT SRC) --> DST
; 5 (NOT SRC) OR DST --> DST
; 6 (NOT SRC) XOR DST --> DST
; 7 (NOT SRC) BIC DST --> DST
;
; 8 PATTERN --> DST
; 9 PATTERN OR DST --> DST
; 10 PATTERN XOR DST --> DST
; 11 PATTERN BIC DST --> DST
;
; 12 (NOT PATTERN) --> DST
; 13 (NOT PATTERN) OR DST --> DST
; 14 (NOT PATTERN) XOR DST --> DST
; 15 (NOT PATTERN) BIC DST --> DST
;
;
;----------------------------------------------------
;
; A6 OFFSETS OF PARAMETERS AFTER LINK:
;
PARAMSIZE .EQU 22 ;SIZE OF PARAMETERS
SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP
DSTBITS .EQU SRCBITS-4 ;LONG, ADDR OF BITMAP
SRCRECT .EQU DSTBITS-4 ;LONG, ADDR OF RECT
DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT
MODE .EQU DSTRECT-2 ;WORD
PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN
;----------------------------------------------------
;
; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
EXPAT .EQU -64 ;16 LONGS
SRCV .EQU EXPAT-2 ;WORD
DSTV .EQU SRCV-2 ;WORD
SRCROW .EQU DSTV-2 ;WORD
DSTROW .EQU SRCROW-2 ;WORD
srcBump .EQU DSTROW-2 ;WORD
HEIGHT .EQU srcBump-2 ;WORD
WORDCNT .EQU HEIGHT-2 ;WORD
SAVEA5 .EQU WORDCNT-4 ;LONG
VARSIZE .EQU SAVEA5 ;SIZE OF LOCAL VARIABLES
;-------------------------------------------------------------------
;
; ENTER HERE. CALLER TAKES CARE OF CURSOR.
;
LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES
MOVEM.L D3-D7/A2-A5,-(SP) ;SAVE REGS
MOVE.L A5,SAVEA5(A6) ;SAVE GLOBAL POINTER
;----------------------------------------------------------------------
;
; GET PARAMETER POINTERS IN REGISTERS
;
MOVE.L SRCRECT(A6),A2 ;A2 POINTS TO SRCRECT
MOVE.L DSTRECT(A6),A3 ;A3 POINTS TO DSTRECT
MOVE.L SRCBITS(A6),A4 ;A4 POINTS TO SRCBITS
MOVE.L DSTBITS(A6),A5 ;A5 POINTS TO DSTBITS
;-------------------------------------------------------------
;
; CALC HEIGHT OF DSTRECT. QUIT IF HEIGHT <= 0
;
MOVE BOTTOM(A3),D0 ;GET BOTTOM
SUB TOP(A3),D0 ;CALC HEIGHT
BLE GOHOME ;QUIT IF HEIGHT <= 0
MOVE D0,HEIGHT(A6) ;SAVE FOR LATER
;--------------------------------------------------------------
;
; SET UP FOR TOP TO BOTTOM, LEFT TO RIGHT
; GET SRC AND DST TOP AND ROWBYTES
;
MOVEQ #2,D3 ;BUMP:=2 (TRANSFER LEFT TO RIGHT)
MOVE TOP(A2),D0 ;GET SRC TOP
SUB BOUNDS+TOP(A4),D0 ;CONVERT SRC TOP TO GLOBAL
MOVE D0,SRCV(A6) ;SAVE FOR LATER
MOVE TOP(A3),D0 ;GET DST TOP
SUB BOUNDS+TOP(A5),D0 ;CONVERT DST TOP TO GLOBAL
MOVE D0,DSTV(A6) ;SAVE FOR LATER
MOVE ROWBYTES(A4),SRCROW(A6) ;SRCROW:=SRCBITS.ROWBYTES
MOVE ROWBYTES(A5),DSTROW(A6) ;DSTROW:=DSTBITS.ROWBYTES
;--------------------------------------------------------------------
;
; SET UP INVERT FLAG, IN CASE SRC OR PATTERN WILL BE INVERTED
;
CLR D7 ;SAY NOT INVERTED
MOVE MODE(A6),D0 ;GET TRANSFER MODE
BTST #2,D0 ;IS MODE AN INV. ONE ?
BEQ.S MODEOK ;NOT INVERTED, CONTINUE
NOT D7 ;INVERTED, PUT -1 IN INVERT REG
MODEOK BTST #3,D0 ;WILL WE USE PATTERN ?
BEQ.S DIREC ;NO, DON'T BOTHER TO SET UP
;------------------------------------------------------------
;
; PATTERN WILL BE USED. EXPAND 8 BYTE PATTERN TO 16 LONGS.
;
MOVE BOUNDS+LEFT(A5),D2 ;GET GLOBAL-LOCAL OFFSET
MOVE.L PAT(A6),A0 ;POINT TO BYTE WIDE PATTERN
LEA EXPAT(A6),A1 ;POINT TO EXPANDED PATTERN
MOVE.L SAVEA5(A6),A5 ;GET GLOBAL POINTER
JSR PATEXPAND ;EXPAND 8 BYTES TO 16 LONGS
MOVE.L DSTBITS(A6),A5 ;RESTORE A5 TO DSTBITS
;------------------------------------------------------------
;
; SET UP (VERT * 4) MOD 64 AS PATTERN SELECTOR
;
MOVEQ #$F,D7 ;TREAT COORD MOD 16
AND TOP(A3),D7 ;GET DST TOP LOCAL COORD
LSL #2,D7 ;QUAD FOR LONG PATTERNS
MOVE.L EXPAT(A6,D7),D6 ;GET FIRST PATTERN DATA
BRA.S NOTSRC ;NOT USING SRC, SKIP OVER
;-----------------------------------------------------------
;
; SOURCE WILL BE USED, SO SET UP VERT AND HORIZ DIRECTIONS
; SUCH THAT SRC WON'T GET CLOBBERED TILL AFTER IT HAS BEEN USED
;
DIREC MOVE.L BASEADDR(A4),D0 ;GET SRC BASEADDR
CMP.L BASEADDR(A5),D0 ;ARE SRC AND DST ARRAYS THE SAME ?
BNE.S GETSRC ;NO, DONT WORRY ABOUT OVERLAP
MOVE SRCV(A6),D0 ;GET SRCV
CMP DSTV(A6),D0 ;IS SRCV > DSTV ?
BGT.S GETSRC ;YES, CONTINUE WITH TOP TO BOTTOM
BLT.S UPSIDE ;NO, DO UPSIDE DOWN
MOVE LEFT(A2),D0 ;SAME VERT, CHOOSE HORIZ DIRECTION
SUB BOUNDS+LEFT(A4),D0 ;CONVERT SRC LEFT TO GLOBAL
MOVE LEFT(A3),D1 ;GET DST LEFT
SUB BOUNDS+LEFT(A5),D1 ;CONVERT TO GLOBAL
CMP D1,D0 ;IS SRCLEFT < DSTLEFT ?
BGE.S GETSRC ;NO, DO LEFT TO RIGHT
NEG D3 ;YES, BUMP:=-2 (RIGHT TO LEFT)
BRA.S GETSRC ;CONTINUE
;----------------------------------------------------------
;
; DO UPSIDE DOWN TO AVOID CLOBBERING SRC
;
UPSIDE MOVE HEIGHT(A6),D0 ;GET HEIGHT
SUB #1,D0 ;CALC HEIGHT-1
ADD D0,SRCV(A6) ;SRCVERT:=SRCV+HEIGHT-1
ADD D0,DSTV(A6) ;DSTVERT:=DSTV+HEIGHT-1
NEG SRCROW(A6) ;SRCROW:=-SRCROW
NEG DSTROW(A6) ;DSTROW:=-DSTROW
;-----------------------------------------------------
;
; SET UP SHIFTCNT IN D6 (RELATIVE SHIFT BETWEEN SRC & DST)
;
GETSRC MOVE LEFT(A3),D6 ;GET DST LEFT
SUB BOUNDS+LEFT(A5),D6 ;CONVERT TO GLOBAL
MOVE LEFT(A2),D1 ;GET SRC LEFT
SUB BOUNDS+LEFT(A4),D1 ;CONVERT TO GLOBAL
SUB D1,D6 ;CALC DELTA HORIZ
AND #$F,D6 ;SHIFTCNT:=DELTA HORIZ MOD 16
;------------------------------------------------------------
;
; SET UP SRCLEFT IN A4, ADDR OF LEFTMOST SRC WORD
; (GOODBYE SRCBITS PTR)
;
MOVE SRCV(A6),D0 ;GET FIRST SRC VERT
MULU ROWBYTES(A4),D0 ;CALC SRC ROWBYTES * FIRST SRC VERT
MOVE.L BASEADDR(A4),A4 ;GET START OF SRC BITMAP
ADD.L D0,A4 ;ADD TO BITMAP START
ADD D6,D1 ;CALC SRCH+SHIFTCNT
ASR #3,D1 ;CONVERT BITS TO BYTE OFFSET
AND #$FFFE,D1 ;TRUNC TO WORD BOUNDARY
ADD D1,A4 ;LEAVE SRCLEFT IN A4
;------------------------------------------------------------
;
; SET UP DSTLEFT IN A5, ADDR OF LEFTMOST DST WORD
; (GOODBYE DSTBITS PTR)
;
NOTSRC MOVE LEFT(A3),D1 ;GET DST LEFT
SUB BOUNDS+LEFT(A5),D1 ;CONVERT TO GLOBAL
MOVE DSTV(A6),D0 ;GET FIRST DST VERT
MULU ROWBYTES(A5),D0 ;CALC DSTROW * FIRST DST VERT
MOVE.L BASEADDR(A5),A5 ;GET START OF DST BITMAP
ADD.L D0,A5 ;ADD DSTV*DSTROW
MOVE D1,D0 ;COPY DSTLEFT GLOBAL
ASR #4,D1 ;CONVERT FROM DOTS TO WORDS
ADD D1,D1 ;DOUBLE FOR BYTES
ADD D1,A5 ;LEAVE DSTLEFT IN A5
;-------------------------------------
;
; SET UP LEFTMASK IN D4
; (GOODBYE SRCRECT PTR)
;
MOVE D0,D1 ;SAVE DSTH
JSR LEFTMASK ;GET LEFTMASK
MOVE D0,D4 ;PUT IN D4
;-------------------------------------
;
; SET UP RIGHTMASK IN D5
; (GOODBYE DSTRECT PTR)
;
AND #$F,D1 ;TREAT DSTH MOD 16
MOVE RIGHT(A3),D0 ;GET DST RIGHT
SUB LEFT(A3),D0 ;CALC WIDTH
BLE GOHOME ;QUIT IF WIDTH <= 0
ADD D1,D0 ;CALC (DSTH MOD 16) + WIDTH
MOVE D0,D1 ;MAKE AN EXTRA COPY
JSR RIGHTMASK ;GET RIGHT MASK
MOVE D0,D5 ;SAVE RIGHTMASK IN D5
;------------------------------------------------
;
; CALC TOTAL NUMBER OF DST WORDS-1
;
ASR #4,D1 ;CALC ((DSTH MOD 16)+WIDTH) DIV 16
MOVE D1,WORDCNT(A6) ;SAVE AS WORDCNT
MOVE D1,D2 ;set up for below
;
; Set up srcBump and dstBump, assuming bumping to the right
;
ADD D1,D1 ;calc 2*wordCount
MOVE D1,D0 ;make a copy
ADD #2,D0 ;adjust for total bytesNeeded
;--------------------------------------------------------------------------
;
; IF DRAWING BACKWARDS FROM RIGHT, then adjust dstBump,
; ADJUST SRCADDR,DSTADDR TO FIRST WORD,
; AND SWAP LEFT AND RIGHT MASKS FOR FIRSTMASK AND LASTMASK.
;
MOVE D3,A0 ;put hBump (+-2) into A0
TST D3 ;ARE WE STARTING ON THE LEFT ?
BPL.S DIROK ;YES, CONTINUE
NEG D0 ;calc -1 * bytesNeeded
ADD D1,A5 ;ADJUST DSTADDR TO RIGHTMOST
ADD D1,A4 ;ADJUST SRCADDR TO RIGHTMOST
EXG D4,D5 ;FIRSTMASK=RIGHT,LASTMASK=LEFT
DIROK MOVE srcRow(A6),srcBump(A6)
SUB D0,srcBump(A6) ;srcBump := srcRow +- bytesBumped
MOVE dstRow(A6),A3
SUB D0,A3 ;dstBump := dstRow +- bytesBumped
;----------------------------------------------
;
; SET UP MODE CASE JUMP IN A1
;
GETMODE MOVE MODE(A6),D0 ;GET TRANSFER MODE
BNE.S NOTFAST ;BR IF NOT MODE 0
TST D6 ;IS SHIFTCNT 0 ?
BNE.S NOTFAST ;NO, CONTINUE
TST WORDCNT(A6) ;IS WORDCNT > 0 ?
BLE.S NOTFAST ;NO, CONTINUE
LEA SETUP0,A1 ;USE FAST COPY.
TST D3 ;ARE WE BUMPING LEFT TO RIGHT ?
BPL.S NEXTROW ;YES, ALL SET
LEA LEFT0,A1 ;NO, USE BACKWARDS LOOP
BRA.S NEXTROW
NOTFAST AND #$B,D0 ;TREAT MODE MOD 16 AND KILL INVERT BIT
MOVE D0,D1 ;MAKE A COPY
AND #3,D0 ;MASK FOR LOW BITS ONLY
ADD D0,D1 ;MAKE MODIFIED MODE * 2 FOR INDEX
TST D2 ;IS DST ALL IN ONE WORD ?
BNE.S DOMAIN ;NO, USE FIRST JUMP TABLE
ADD #16,D1 ;YES, USE SECOND JUMP TABLE
DOMAIN LEA MODETAB,A1 ;GET ADDRESS OF MODE TABLE
ADD 0(A1,D1),A1 ;POINT TO THIS MODE'S ROW LOOP
;---------------------------------------------------------
;
; OUTER LOOP: DO EACH SCAN LINE AND COME BACK TO NXTSRC OR NXTPAT.
; SOME MODES OPTIMIZE AND DO WHOLE OUTER LOOP AND COME BACK TO GOHOME.
;
NEXTROW MOVE HEIGHT(A6),D3 ;get height
SUB #1,D3 ;init DBRA rowcount
ROWLOOP MOVE D4,D1 ;MASK:=FIRSTMASK
MOVE WORDCNT(A6),D2 ;GET WORDCOUNT
JMP (A1) ;DO THIS ROW AND COME BACK
NXTSRC ADD srcBump(A6),A4 ;bump srcPtr to next row
ADD A3,A5 ;BUMP DSTADDR TO NEXT ROW
DBRA D3,ROWLOOP ;loop for all srcRows
BRA.S GOHOME ;then quit
NXTPAT ADD #4,D7 ;BUMP PATTERN SELECTOR
AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT
MOVE.L EXPAT(A6,D7),D6 ;GET PATTERN DATA FOR NEXT ROW
ADD A3,A5 ;BUMP DSTADDR TO NEXT ROW
DBRA D3,ROWLOOP ;loop for all srcRows
;then quit
GOHOME MOVEM.L (SP)+,D3-D7/A2-A5 ;RESTORE REGS
UNLINK PARAMSIZE,'BITBLT '
;---------------------------------------------------------------;
; ;
; INTERFACE TO EACH BITBLT SCANLINE LOOP: ;
; ;
; REGISTERS: A0: hBump (+-2) D0: scratch ;
; A1: MODE CASE JUMP D1: FIRSTMASK ;
; A2: used for loop jmp D2: WORDCNT ;
; A3: dstBump D3: height-1 ;
; A4: SRCPTR D4: FIRSTMASK ;
; A5: DSTPTR D5: LASTMASK ;
; A6: LOCALS D6: SHIFTCNT OR PATTERN ;
; A7: STACK PTR D7: INVERT OR PAT-SEL ;
; ;
;---------------------------------------------------------------;
MODETAB .WORD MAIN0-MODETAB ;JUMP TABLE USED IF DST WIDER THAN ONE WORD
.WORD MAIN1-MODETAB
.WORD MAIN2-MODETAB
.WORD MAIN3-MODETAB
.WORD SETUP8-MODETAB
.WORD MAIN9-MODETAB
.WORD SETUP10-MODETAB
.WORD MAIN11-MODETAB
.WORD END0-MODETAB ;JUMP TABLE USED IF DST FITS IN ONE WORD WIDE
.WORD END1-MODETAB
.WORD END2-MODETAB
.WORD END3-MODETAB
.WORD WORD8-MODETAB
.WORD END9-MODETAB
.WORD END10-MODETAB
.WORD END11-MODETAB
;------------------------------------------------------------
;
; OPTIMIZE RIGHT HORIZONTAL SCROLL IF NO SHIFT.
; ONLY IF MODE 0, BUMPING RIGHT TO LEFT, WORDCNT > 0, AND NO SHIFT.
;
LEFT0 MOVE (A4),D0 ;GET SRC FROM BITMAP
ADD A0,A4 ;BUMP LEFT
AND D1,D0 ;MASK FIRST WORD
NOT D1 ;MAKE NOTMASK
AND (A5),D1 ;GET DATA FROM DST
OR D1,D0 ;MERGE WITH SRC DATA
MOVE D0,(A5) ;PUT RESULT TO DST
ADD A0,A5 ;BUMP LEFT
MOVEQ #-1,D1 ;FLUSH MASK FOR END0
SUB #1,D2 ;DEC WORD COUNT
BEQ.S END0 ;BR IF NO UNMASKED WORDS
SUB A0,A4 ;GET READY FOR PRE-DECREMENT
SUB A0,A5 ;GET READY FOR PRE-DECREMENT
LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT
BCC.S LONE0 ;BR IF EVEN # WORDS LEFT
MOVE -(A4),-(A5) ;ELSE MAKE EVEN BY DOING A WORD
SUB #1,D2 ;ADJUST LONGCOUNT
BRA.S LMORE0 ;SEE IF ANY LONGS LEFT TO DO
LTWO0 MOVE.L -(A4),-(A5) ;MOVE A LONG WORD
LONE0 MOVE.L -(A4),-(A5) ;MOVE ANOTHER LONG
SUB #2,D2 ;ANY UNMASKED LONGS LEFT IN ROW ?
LMORE0 BGT LTWO0 ;YES, AT LEAST 2 LONGS LEFT
BEQ LONE0 ;YES, FINISH UP LAST LONG
ADD A0,A4 ;RETURN TO NORMAL AFTER PRE-DECREMENT
ADD A0,A5 ;RETURN TO NORMAL AFTER PRE-DECREMENT
BRA.S END0 ;DO LAST WORD WITH MASK
;------------------------------------------------------------
;
; OPTIMIZE VERTICAL AND LEFT HORIZONTAL SCROLL IF SHIFT = 0.
; ONLY IF MODE 0, BUMPING LEFT TO RIGHT, WORDCNT > 0, AND NO SHIFT.
;
SETUP0 LEA FAST0,A1 ;only do setup once
LEA COPYBIG,A2 ;point to big copy
BRA CALCLP ;share loop calc
FAST0 MOVE (A4)+,D0 ;GET SRC FROM BITMAP
AND D1,D0 ;MASK FIRST WORD
NOT D1 ;MAKE NOTMASK
AND (A5),D1 ;GET DST DATA
OR D1,D0 ;MERGE WITH SRC DATA
MOVE D0,(A5)+ ;PUT RESULT TO DST
MOVEQ #-1,D1 ;FLUSH MASK FOR END0
SUB #1,D2 ;DEC WORD COUNT
BEQ.S END0 ;BR IF NO UNMASKED WORDS
JSR (A2) ;call unwound copy loop
MOVEQ #-1,D2 ;force finish up below
;-------------------------------------------------------
;
; MODE 0 OR 4: SRC --> DST
;
END0 AND D5,D1 ;MASK:=MASK AND LASTMASK
MAIN0 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP
ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT
LSR.L D6,D0 ;ALIGN TO DST
EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND D1,D0 ;MASK SRC
NOT D1 ;FORM NOTMASK
AND (A5),D1 ;GET DST DATA
OR D1,D0 ;MERGE WITH SRC DATA
MOVE D0,(A5) ;PUT RESULT TO DST
ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT
MOVEQ #-1,D1 ;FLUSH MASK
SUB #1,D2 ;DEC WORD COUNT
BGT MAIN0 ;BR IF UNMASKED WORDS LEFT
BEQ END0 ;DO LAST WORD WITH LASTMASK
BRA NXTSRC ;LOOP BACK FOR MORE
;----------------------------------------------------------
;
; Call copybig with wordcount in D2 (clobbered)
;
COPYBIG BCLR #0,D2 ;is wordcount even ?
BEQ.S @1 ;yes, continue
MOVE.W (A4)+,(A5)+ ;no, make it even
@1 SUB #32,D2 ;calc wordcount-32
BLE.S @2 ;continue if wordcount <= 32
BSR.S COPY32 ;else copy 32 words
BRA.S @1 ;and loop for more
@2 NEG D2 ;calc 32-wordcount
JMP COPY32(D2) ;jump into loop
COPY32 MOVE.L (A4)+,(A5)+ ;TABLE TO COPY 0..32 WORDS
MOVE.L (A4)+,(A5)+ ;wordCount = 30
MOVE.L (A4)+,(A5)+ ;wordCount = 28
MOVE.L (A4)+,(A5)+ ;wordCount = 26
MOVE.L (A4)+,(A5)+ ;wordCount = 24
MOVE.L (A4)+,(A5)+ ;wordCount = 22
MOVE.L (A4)+,(A5)+ ;wordCount = 20
MOVE.L (A4)+,(A5)+ ;wordCount = 18
MOVE.L (A4)+,(A5)+ ;wordCount = 16
MOVE.L (A4)+,(A5)+ ;wordCount = 14
MOVE.L (A4)+,(A5)+ ;wordCount = 12
MOVE.L (A4)+,(A5)+ ;wordCount = 10
MOVE.L (A4)+,(A5)+ ;wordCount = 8
MOVE.L (A4)+,(A5)+ ;wordCount = 6
MOVE.L (A4)+,(A5)+ ;wordCount = 4
MOVE.L (A4)+,(A5)+ ;wordCount = 2
COPY0 RTS ;wordCount = 0
COPY31 MOVE.L (A4)+,(A5)+ ;TABLE TO COPY 1..31 WORDS
MOVE.L (A4)+,(A5)+ ;wordCount = 29
MOVE.L (A4)+,(A5)+ ;wordCount = 27
MOVE.L (A4)+,(A5)+ ;wordCount = 25
MOVE.L (A4)+,(A5)+ ;wordCount = 23
MOVE.L (A4)+,(A5)+ ;wordCount = 21
MOVE.L (A4)+,(A5)+ ;wordCount = 19
MOVE.L (A4)+,(A5)+ ;wordCount = 17
MOVE.L (A4)+,(A5)+ ;wordCount = 15
MOVE.L (A4)+,(A5)+ ;wordCount = 13
MOVE.L (A4)+,(A5)+ ;wordCount = 11
MOVE.L (A4)+,(A5)+ ;wordCount = 9
MOVE.L (A4)+,(A5)+ ;wordCount = 7
MOVE.L (A4)+,(A5)+ ;wordCount = 5
MOVE.L (A4)+,(A5)+ ;wordCount = 3
COPY1 MOVE.W (A4)+,(A5)+ ;wordCount = 1
RTS
;-------------------------------------------------------
;
; MODE 1 OR 5: SRC OR DST --> DST
;
END1 AND D5,D1 ;MASK:=MASK AND LASTMASK
MAIN1 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP
ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT
LSR.L D6,D0 ;ALIGN TO DST
EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND D1,D0 ;MASK SRC
OR D0,(A5) ;OR SRC INTO DST
ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT
MOVEQ #-1,D1 ;FLUSH MASK
SUB #1,D2 ;DEC WORD COUNT
BGT MAIN1 ;LOOP TILL LAST WORD
BEQ END1 ;DO LAST WORD WITH LASTMASK
BRA NXTSRC ;LOOP BACK FOR NEXT ROW
;-------------------------------------------------------
;
; MODE 2 OR 6: SRC XOR DST --> DST
;
END2 AND D5,D1 ;MASK:=MASK AND LASTMASK
MAIN2 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP
ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT
LSR.L D6,D0 ;ALIGN TO DST
EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND D1,D0 ;MASK SRC
EOR D0,(A5) ;XOR SRC INTO DST
ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT
MOVEQ #-1,D1 ;FLUSH MASK
SUB #1,D2 ;DEC WORD COUNT
BGT MAIN2 ;LOOP TILL LAST WORD
BEQ END2 ;DO LAST WORD WITH LASTMASK
BRA NXTSRC ;LOOP BACK FOR NEXT ROW
;-------------------------------------------------------
;
; MODE 3 OR 7: SRC BIC DST --> DST
;
END3 AND D5,D1 ;MASK:=MASK AND LASTMASK
MAIN3 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP
ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT
LSR.L D6,D0 ;ALIGN TO DST
EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND D1,D0 ;MASK SRC
NOT D0 ;INVERT SRC
AND D0,(A5) ;BIT CLEAR SRC INTO DST
ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT
MOVEQ #-1,D1 ;FLUSH MASK
SUB #1,D2 ;DEC WORD COUNT
BGT MAIN3 ;LOOP TILL LAST WORD
BEQ END3 ;DO LAST WORD WITH LASTMASK
BRA NXTSRC ;LOOP BACK FOR NEXT ROW
;-----------------------------------------------------------
;
; OPTIMIZE MODE 8 OR 12 IF DST FITS IN ONE WORD (VERT LINES ETC)
;
WORD8 AND D5,D1 ;COMBINE LEFT AND RIGHT MASKS
MOVE D1,D5 ;COPY COMBINED MASK
NOT D5 ;FORM NOTMASK
WORD8A AND D1,D6 ;MASK EXTRA PATTERN TO ZEROS
MOVE (A5),D0 ;GET DST DATA
AND D5,D0 ;AND WITH NOTMASK
OR D6,D0 ;MERGE WITH SRC DATA
MOVE D0,(A5)+ ;PUT RESULT TO DST
ADD A3,A5 ;BUMP DSTPTR TO NEXT ROW
ADD #4,D7 ;BUMP PATTERN SELECTOR
AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT
MOVE EXPAT(A6,D7),D6 ;GET PATTERN FOR NEXT ROW
DBRA D3,WORD8A ;LOOP ALL ROWS
BRA GOHOME
;-------------------------------------------------------
;
; MODE 8 OR 12: PATTERN --> DST (FILLING AREAS, DRAWING LINES)
;
SETUP8 LEA FAST8,A1 ;only do setup once
LEA FILLBIG,A2 ;point to big fill
CALCLP CMP #32,D2 ;is wordcnt > 32 ?
BGT.S @2 ;yes use fillbig
ADD #COPY0+1-COPYBIG,A2 ;no, point to even table
BTST #0,D2 ;will wordcount-1 be even ?
BNE.S @1 ;yes, use even table
ADD #COPY1+1-COPY0,A2 ;no, point to odd table
@1 SUB D2,A2 ;adjust loop jump
@2 JMP (A1) ;re-connect with shared code
FAST8 MOVE D6,D0 ;GET PATTERN DATA
AND D1,D0 ;MASK FIRST WORD
NOT D1 ;MAKE NOTMASK
AND (A5),D1 ;GET DST DATA
OR D1,D0 ;MERGE WITH PAT DATA
MOVE D0,(A5)+ ;PUT RESULT TO DST
SUB #1,D2 ;DEC WORD COUNT
BEQ.S END8 ;BR IF NO UNMASKED WORDS
JSR (A2) ;call unwound loop
END8 MOVE D5,D1 ;MASK:= RIGHTMASK
AND D1,D6 ;MASK PATTERN
NOT D1 ;MAKE NOTMASK
AND (A5),D1 ;GET DST DATA
OR D1,D6 ;MERGE WITH PAT DATA
MOVE D6,(A5)+ ;PUT RESULT TO DST
BRA NXTPAT ;LOOP BACK FOR NEXT ROW
;----------------------------------------------------------
;
; Call fillbig with wordcount in D2 (clobbered)
;
FILLBIG BCLR #0,D2 ;is wordcount even ?
BEQ.S @1 ;yes, continue
MOVE.W D6,(A5)+ ;no, make it even
@1 SUB #32,D2 ;calc wordcount-32
BLE.S @2 ;continue if wordcount <= 32
BSR.S FILL32 ;elsae fill 32 words
BRA.S @1 ;and loop for more
@2 NEG D2 ;calc 32-wordcount
JMP FILL32(D2) ;jump into loop
FILL32 MOVE.L D6,(A5)+ ;TABLE TO FILL 0..32 WORDS
MOVE.L D6,(A5)+ ;wordCount = 30
MOVE.L D6,(A5)+ ;wordCount = 28
MOVE.L D6,(A5)+ ;wordCount = 26
MOVE.L D6,(A5)+ ;wordCount = 24
MOVE.L D6,(A5)+ ;wordCount = 22
MOVE.L D6,(A5)+ ;wordCount = 20
MOVE.L D6,(A5)+ ;wordCount = 18
MOVE.L D6,(A5)+ ;wordCount = 16
MOVE.L D6,(A5)+ ;wordCount = 14
MOVE.L D6,(A5)+ ;wordCount = 12
MOVE.L D6,(A5)+ ;wordCount = 10
MOVE.L D6,(A5)+ ;wordCount = 8
MOVE.L D6,(A5)+ ;wordCount = 6
MOVE.L D6,(A5)+ ;wordCount = 4
MOVE.L D6,(A5)+ ;wordCount = 2
RTS ;wordCount = 0
FILL31 MOVE.L D6,(A5)+ ;TABLE TO FILL 1..31 WORDS
MOVE.L D6,(A5)+ ;wordCount = 29
MOVE.L D6,(A5)+ ;wordCount = 27
MOVE.L D6,(A5)+ ;wordCount = 25
MOVE.L D6,(A5)+ ;wordCount = 23
MOVE.L D6,(A5)+ ;wordCount = 21
MOVE.L D6,(A5)+ ;wordCount = 19
MOVE.L D6,(A5)+ ;wordCount = 17
MOVE.L D6,(A5)+ ;wordCount = 15
MOVE.L D6,(A5)+ ;wordCount = 13
MOVE.L D6,(A5)+ ;wordCount = 11
MOVE.L D6,(A5)+ ;wordCount = 9
MOVE.L D6,(A5)+ ;wordCount = 7
MOVE.L D6,(A5)+ ;wordCount = 5
MOVE.L D6,(A5)+ ;wordCount = 3
MOVE.W D6,(A5)+ ;wordCount = 1
RTS
;-------------------------------------------------------
;
; MODE 9 OR 13: PATTERN OR DST --> DST
;
END9 AND D5,D1 ;MASK:=MASK AND LASTMASK
MAIN9 MOVE D6,D0 ;GET PATTERN DATA
AND D1,D0 ;MASK PATTERN
OR D0,(A5)+ ;OR PATTERN INTO DST
MOVEQ #-1,D1 ;FLUSH MASK
SUB #1,D2 ;DEC WORD COUNT
BGT MAIN9 ;LOOP TILL LAST WORD
BEQ END9 ;DO LAST WORD WITH LASTMASK
BRA NXTPAT ;LOOP BACK FOR NEXT ROW
;-------------------------------------------------------
;
; MODE 10 OR 14: PATTERN XOR DST --> DST (INVERTING AREAS, XOR LINES)
;
SETUP10 LEA FAST10,A1 ;only do setup once
LEA XORBIG,A2 ;point to big fill
BRA CALCLP ;share loop calc
FAST10 MOVE D6,D0 ;GET PATTERN DATA
AND D1,D0 ;MASK FIRST WORD
EOR D0,(A5)+ ;XOR PATTERN INTO DST
MOVEQ #-1,D1 ;FLUSH MASK FOR END10
SUB #1,D2 ;DEC WORD COUNT
BEQ.S END10 ;BR IF NO UNMASKED WORDS
JSR (A2) ;call unwound loop
MOVEQ #-1,D2 ;force finish up below
END10 AND D5,D1 ;MASK:=MASK AND LASTMASK
AND D1,D6 ;MASK PATTERN
EOR D6,(A5)+ ;XOR PATTERN DATA INTO DST
BRA NXTPAT ;LOOP BACK FOR NEXT ROW
;----------------------------------------------------------
;
; Call XORbig with wordcount in D2 (clobbered)
;
XORBIG BCLR #0,D2 ;is wordcount even ?
BEQ.S @1 ;yes, continue
EOR.W D6,(A5)+ ;no, make it even
@1 SUB #32,D2 ;calc wordcount-32
BLE.S @2 ;continue if wordcount <= 32
BSR.S XOR32 ;else XOR 32 words
BRA @1 ;and loop for more
@2 NEG D2 ;calc 32-wordcount
JMP XOR32(D2) ;jump into loop
XOR32 EOR.L D6,(A5)+ ;TABLE TO XOR 0..32 WORDS
EOR.L D6,(A5)+ ;wordCount = 30
EOR.L D6,(A5)+ ;wordCount = 28
EOR.L D6,(A5)+ ;wordCount = 26
EOR.L D6,(A5)+ ;wordCount = 24
EOR.L D6,(A5)+ ;wordCount = 22
EOR.L D6,(A5)+ ;wordCount = 20
EOR.L D6,(A5)+ ;wordCount = 18
EOR.L D6,(A5)+ ;wordCount = 16
EOR.L D6,(A5)+ ;wordCount = 14
EOR.L D6,(A5)+ ;wordCount = 12
EOR.L D6,(A5)+ ;wordCount = 10
EOR.L D6,(A5)+ ;wordCount = 8
EOR.L D6,(A5)+ ;wordCount = 6
EOR.L D6,(A5)+ ;wordCount = 4
EOR.L D6,(A5)+ ;wordCount = 2
RTS ;wordCount = 0
XOR31 EOR.L D6,(A5)+ ;TABLE TO XOR 1..31 WORDS
EOR.L D6,(A5)+ ;wordCount = 29
EOR.L D6,(A5)+ ;wordCount = 27
EOR.L D6,(A5)+ ;wordCount = 25
EOR.L D6,(A5)+ ;wordCount = 23
EOR.L D6,(A5)+ ;wordCount = 21
EOR.L D6,(A5)+ ;wordCount = 19
EOR.L D6,(A5)+ ;wordCount = 17
EOR.L D6,(A5)+ ;wordCount = 15
EOR.L D6,(A5)+ ;wordCount = 13
EOR.L D6,(A5)+ ;wordCount = 11
EOR.L D6,(A5)+ ;wordCount = 9
EOR.L D6,(A5)+ ;wordCount = 7
EOR.L D6,(A5)+ ;wordCount = 5
EOR.L D6,(A5)+ ;wordCount = 3
EOR.W D6,(A5)+ ;wordCount = 1
RTS
;-------------------------------------------------------
;
; MODE 11 OR 15: PATTERN BIC DST --> DST
;
END11 AND D5,D1 ;MASK:=MASK AND LASTMASK
MAIN11 MOVE D6,D0 ;GET PATTERN DATA
AND D1,D0 ;MASK PATTERN
NOT D0 ;INVERT PATTERN
AND D0,(A5)+ ;BIC PATTERN INTO DST
MOVEQ #-1,D1 ;FLUSH MASK
SUB #1,D2 ;DEC WORD COUNT
BGT MAIN11 ;LOOP TILL LAST WORD
BEQ END11 ;DO LAST WITH LASTMASK
BRA NXTPAT ;LOOP BACK FOR NEXT ROW
.ASCII 'CopyRight 1983 Apple Computer Inc.'
.END