; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > $.Source.Vdu5 ; ***************************************************************************** ; ; Print a character in VDU 5 mode ; ; *****This file has been extensively modified by DJS ; Alter these at your peril ! cxl RN 0 scr RN 0 ecfptr RN 1 cword0 RN 1 cyb RN 2 cyt2 RN 2 scrend RN 2 cword1 RN 2 cxr RN 3 cyb2 RN 3 ormask RN 3 cxl2 RN 4 eormask RN 4 cyb3 RN 5 charmsk RN 5 cword2 RN 5 cyt RN 6 llength RN 6 chartmp RN 6 sizex RN 7 charptr RN 7 sizey RN 8 invcharshf RN 8 charbyte RN 9 cxr2 RN 10 charshf RN 10 lgBPC RN 11 Vdu5Wrch Push R14 BL Vdu5DoChar Pull R14 B PostCharMove ; Vdu23_18 ; LDR R0, [WsPtr, #QQ+1] Vdu5DoChar ADD ecfptr, WsPtr, #FgEcfOraEor ;Base address of OR/EOR pairs Vdu5DoChar10 Push "R14" MOV charbyte, R0 ;Put character out of harm's ; way ASSERT cxl < cyt ASSERT GCsIY = GCsIX +4 ADD cxl, WsPtr, #GCsIX LDMIA cxl, {cxl, cyt} ; cxl=where left pixel would be ; cyt=where top pixel would be ASSERT sizex < sizey ADD sizex, WsPtr, #GCharSizes LDMIA sizex, {sizex, sizey} CMP sizey, #16 ; if SizeY=8 or SizeY=16 TEQNE sizey, #8 ; (leaving CS <=> SizeY=16) TEQEQ sizex, #8 ; and SizeX=8, then do it fast BNE SlowVdu5 ; else do by scaled char TEQ charbyte, #127 ; Which font do we use? ADDNE charptr, WsPtr, #(Font-32*8) ; Soft if character not DELETE ADREQL charptr, HardFont-32*8 ; Hard if character is DELETE ADD charptr, charptr, charbyte, LSL #3 ;Point at char def MOVCS charptr, charptr, ASL #1 ; Double address if SizeY = 16 SUBCS charptr, charptr, #1 ; (tricky code, originally ; designed by TMD) SUB cyb, cyt, sizey ADD cyb, cyb, #1 ; where bottom pixel would be ADD cxr, cxl, #7 ; where right pixel would be ASSERT GWBRow = GWLCol+4 ASSERT GWRCol = GWLCol+8 ASSERT GWTRow = GWLCol+12 ASSERT cyb3 > cxl2 ASSERT cxr2 > cyb3 ASSERT R14 > cxr2 ADD cxl2, WsPtr, #GWLCol LDMIA cxl2, {cxl2, cyb3, cxr2, R14} Greatest cxl2, cxl2, cxl ; cxl2 := windowed left ; (2 instructions) Least cxr2, cxr2, cxr ; cxr2 := windowed right ; (2 instructions) Greatest cyb2, cyb3, cyb ; cyb2 := windowed bottom ; (3 instructions) Least cyt2, R14, cyt ; cyt2 := windowed top ; (3 instructions) SUBS cyb2, cyt2, cyb2 ; top >= bottom ? CMPGE cxr2, cxl2 ; and right >= left ? Pull "PC", LT ; Exit if not. Otherwise cyb2 ; has become clipped height LDR R14, [WsPtr, #CursorFlags] ; update changed box, if wanted TST R14, #ClipBoxEnableBit BLNE ClipVdu5 ADD charptr, charptr, cyt ; adjust charptr to point at SUB charptr, charptr, cyt2 ; first used row of character MOV charmsk, #&FF ; Produce mask to do left/right SUB R14, cxl2, cxl ; clipping MOV charmsk, charmsk, LSR R14 SUB R14, cxr2, cxl2 ADD R14, R14, #1 BIC charmsk, charmsk, charmsk, LSR R14 TEQ sizey, #16 ; If double height, signal this ORREQ charmsk, charmsk, #1:SHL:31 ; by making charmsk negative ASSERT llength > scr ASSERT LineLength = YWindLimit+4 LDR lgBPC, [WsPtr, #Log2BPC] ; Address point at (cxl, cyt2), MOV charshf, cxl, LSL lgBPC ; putting address in scr, bit ADD scr, WsPtr, #YWindLimit ; offset in charshf and LDMIA scr, {scr, llength} ; adjusting ecfptr SUB scr, scr, cyt2 AND R14, scr, #7 ADD ecfptr, ecfptr, R14, LSL #3 LDR R14, [WsPtr, #ScreenStart] MLA scr, llength, scr, R14 MOV R14, charshf, ASR #5 ADD scr, scr, R14, LSL #2 AND charshf, charshf, #31 MLA scrend, llength, cyb2, scr ;Calculate terminating address RSB invcharshf, charshf, #32 ;And inverse shift Vdu5NextLine ASSERT eormask > ormask LDMIA ecfptr!, {ormask, eormask} ;Pick up ecf info and advance TST ecfptr, #63 ; ecf pointer, wrapping if SUBEQ ecfptr, ecfptr, #64 ; necessary ASSERT HardFont < &40000000 :LOR: HardFont >= &C0000000 ASSERT WsPtr < &40000000 :LOR: WsPtr >= &C0000000 TEQ charmsk, #0 ; Double height? (MI=yes) LDRMIB charbyte, [charptr, -charptr, ASR #1] ; Use ASR, as font will be at LDRPLB charbyte, [charptr] ; top or bottom of memory (zero page, ADD charptr, charptr, #1 ; system heap or ROM) ANDS charbyte, charbyte, charmsk ;Clip left & right; skip loop BEQ Vdu5TryNextLine ; body if nothing to plot Push "ecfptr,scrend,charmsk,llength,charptr" LDR R14, [WsPtr, #TextExpandArea] ;Address correct expansion ADD charptr, charbyte, #&100 ; table entry, assuming that ADD charptr, R14, charptr, LSL lgBPC ; this is not mode 10 or greater CMP lgBPC, #1 ;Pick up this entry: LDRLSB cword0, [charptr, #0] ; 1 byte if lgBPC = 0 LDREQB R14, [charptr, #1] ; 2 bytes if lgBPC = 1 ORREQ cword0, cword0, R14, LSL #8 MOV cword1, #0 BLS Vdu5DoOneWord CMP lgBPC, #3 LDRLO cword0, [charptr, #0] ; 1 word if lgBPC = 2 BLO Vdu5DoOneWord BHI Vdu5Mode10 ; 4 words if lgBPC = 4 LDMIA charptr, {cword0, cword1} ; 2 words if lgBPC = 3 MOVS cword2, cword1, LSR invcharshf MACRO $l DoVdu5Word $c, $reg, $off $l LDR$c chartmp, [scr, #$off] AND$c R14, ormask, $reg ORR$c chartmp, chartmp, R14 AND$c R14, eormask, $reg EOR$c chartmp, chartmp, R14 STR$c chartmp, [scr, #$off] MEND Vdu5DoTwoWords DoVdu5Word NE, cword2, 8 MOV cword1, cword1, LSL charshf Vdu5DoOneWord ORRS cword1, cword1, cword0, LSR invcharshf DoVdu5Word NE, cword1, 4 MOVS cword0, cword0, LSL charshf DoVdu5Word NE, cword0, 0 Vdu5LinePainted Pull "ecfptr,scrend,charmsk,llength,charptr" Vdu5TryNextLine TEQ scr, scrend ADDNE scr, scr, llength BNE Vdu5NextLine Pull "PC" ; This is mode 10 (or similar) - we must do bit expansion on the fly Vdu5Mode10 CMP lgBPC, #5 ; is this a 32 bit per pixel mode, if so then ignore the BEQ Vdu5Mode32 ; existing code and use a newer function ADRL charptr, C16BTab AND R14, charbyte, #&0F ADD R14, charptr, R14, LSL #3 LDMIA R14, {cword0, cword1} MOVS cword2, cword1, LSR invcharshf DoVdu5Word NE, cword2, 16 MOV cword1, cword1, LSL charshf ORRS cword1, cword1, cword0, LSR invcharshf DoVdu5Word NE, cword1, 12 MOVS cword2, cword0, LSL charshf AND R14, charbyte, #&F0 ADD R14, charptr, R14, LSR #1 LDMIA R14, {cword0, cword1} ORRS cword2, cword2, cword1, LSR invcharshf B Vdu5DoTwoWords ; Expand the character data out to 32 bit per pixel (mode 48 or similar) MACRO $l PixMunge32 $reg, $mask, $offset $l TST $reg, #$mask LDRNE chartmp, [scr, #$offset] ORRNE chartmp, chartmp, ormask EORNE chartmp, chartmp, eormask STRNE chartmp, [scr, #$offset] MEND MACRO $l PixSolid32 $reg, $mask, $offset $l TST $reg, #$mask STRNE chartmp, [scr, #$offset] MEND ; Perform bit expansion on the fly, this is a word based operation, no need to ; extract sub-pixels from the ORR / EOR masks, simply perform the bit test and ; then write the character data to the screen! Vdu5Mode32 [ AvoidScreenReads CMP ormask, #&FFFFFFFF BNE Vdu5Mode32_NotSolid MVN chartmp, eormask PixSolid32 charbyte, 1<<7, 0 PixSolid32 charbyte, 1<<6, 4 PixSolid32 charbyte, 1<<5, 8 PixSolid32 charbyte, 1<<4, 12 PixSolid32 charbyte, 1<<3, 16 PixSolid32 charbyte, 1<<2, 20 PixSolid32 charbyte, 1<<1, 24 PixSolid32 charbyte, 1<<0, 28 B Vdu5LinePainted Vdu5Mode32_NotSolid ] PixMunge32 charbyte, 1<<7, 0 PixMunge32 charbyte, 1<<6, 4 PixMunge32 charbyte, 1<<5, 8 PixMunge32 charbyte, 1<<4, 12 PixMunge32 charbyte, 1<<3, 16 PixMunge32 charbyte, 1<<2, 20 PixMunge32 charbyte, 1<<1, 24 PixMunge32 charbyte, 1<<0, 28 B Vdu5LinePainted ; flow down and try the next line ; ***************************************************************************** ; ; Slow VDU 5 - Print char by scaled method (in SprExtend) ; ; in: R1 (ecfptr) = pointer to ecf pattern ; R7 (sizex) = SizeX ; R8 (sizey) = SizeY ; R9 (charbyte) = character to plot ; ; Stack: Return address ; ASSERT ecfptr = R1 ASSERT sizex = R7 ASSERT sizey = R8 ASSERT charbyte = R9 SlowVdu5 ROUT MOV R10, R1 ; R10 := ecfptr ; now save current GCOL on stack if necessary ADD R11, WsPtr, #FgEcfOraEor TEQ R10, R11 ; if going to use this one BEQ %FT20 ; then skip MOV R0, #64 ; 64 bytes 10 LDMIA R11, {R3-R6} ; copy old GCOL into stack Push "R3-R6" ; frame, reversing order of ; 16 byte chunks LDMIA R10!, {R3-R6} ; copy new colour STMIA R11!, {R3-R6} ; into GCOL SUBS R0, R0, #16 BNE %BT10 20 MOV R4, #8 MOV R5, #8 Push "R4,R5" Push "R7,R8" MOV R6, R13 ; R6 -> scaling block SUB R1, R8, #1 ; SizeY-1 LDR R5, [WsPtr, #YEigFactor] ADD R3, WsPtr, #GCsX LDMIA R3, {R3, R4} ; R3 = ext X; R4 = ext Y (top) SUB R4, R4, R1, LSL R5 ; R4 = ext Y (bottom) MOV R1, R9 ; R1 = char MOV R0, #SpriteReason_PaintCharScaled SWI XOS_SpriteOp ADD R13, R13, #4*4 ; junk scaling block TEQ R10, R11 ; if we didn't copy GCOLs Pull "PC", EQ ; then return, else copy back MOV R0, #64 30 Pull "R3-R6" ; Reverse order of 16 byte STMDB R11!, {R3-R6} ; chunks during copy again SUBS R0, R0, #16 BNE %BT30 Pull PC ; ***************************************************************************** ; ; VDU 5 - Start printing text at graphics cursor ENQ GraphicsMode R0 MOVNE PC, R14 MOV R1, #0 BSR CursorOnOff ; turn cursor off without ; saving to copy LDR R6, [WsPtr, #CursorFlags] ORR R6, R6, #Vdu5Bit B R6toCursorFlags ; ***************************************************************************** ; ; VDU 4 - Return to printing text at text cursor EOT GraphicsMode R0 MOVNE PC,LR MOV R1, #1 BSR CursorOnOff ; restore cursor from copy LDR R6, [WsPtr, #CursorFlags] BIC R6, R6, #Vdu5Bit B R6toCursorFlags ; ***************************************************************************** ; ; Vdu5HT - Move cursor "right" when in VDU 5 mode ; ; in: R6 = CursorFlags Vdu5HT Push R14 BL GCursorMove ; try to move in +ve X direction BCC EndVdu5HT ; if successful, finish BL GCursorB0 ; else move cursor to -ve X boundary Vdu5HT10 EOR R6, R6, #8 ; change to +ve Y direction BL GCursorMove ; try to move in that direction BLCS GCursorB0 ; if unsuccessful, move to -ve Y bdy EndVdu5HT Pull R14 B IEG ; ***************************************************************************** ; ; Vdu5BS - Move cursor "left" when in VDU 5 mode ; ; in: R6 = CursorFlags Vdu5BS EOR R6, R6, #6 ; go to -ve X direction B Vdu5HT ; dead easy, huh ? ; ***************************************************************************** ; ; Vdu5LF - Move cursor "down" when in VDU 5 mode ; ; in: R6 = CursorFlags Vdu5LF Push R14 B Vdu5HT10 ; ***************************************************************************** ; ; Vdu5VT - Move cursor "up" when in VDU 5 mode ; ; in: R6 = CursorFlags Vdu5VT EOR R6, R6, #6 ; go to -ve Y direction (eventually) B Vdu5LF ; ***************************************************************************** ; ; Vdu5CR - Carriage return in VDU 5 mode ; ; in: R6 = CursorFlags Vdu5CR BSR GCursorB0 B IEG ; ***************************************************************************** ; ; Vdu5FF - Clear screen in VDU 5 mode ; ; in: R6 = CursorFlags Vdu5FF BSR Home B CLG ; ***************************************************************************** ; ; Vdu5TAB - TAB(X,Y) in VDU 5 mode ; ; in: R0 = X, R1 = Y, R6 = CursorFlags Vdu5TAB BSR GCursorBdy EOR R6, R6, #8 MOV R0, R1 BSR GCursorBdy B IEG ; ***************************************************************************** ; ; Vdu5Delete - Delete in VDU 5 mode (already done backspace) ; ; in: R6 = CursorFlags Vdu5Delete ADD ecfptr, WsPtr, #BgEcfStore ; STORE background colour/ecf MOV R0, #127 ; uses hard font for this char B Vdu5DoChar10 ; ***************************************************************************** ; ; GCursorMove - Move graphics cursor in direction specified by R6 ; (0,4 = right; 2,6 = left; 8,10 = down; 12,14 = up) ; R6 is preserved GCursorMove ADD R0, WsPtr, #GCsIX LDMIA R0, {R0, R1} ; R0 = GCsIX; R1 = GCsIY ADD R2, WsPtr, #GCharSpacing+8 ; +8 needed to address it LDMDB R2, {R2, R3} ; R2=GCharSpaceX;R3=GCharSpaceY WINDow R0, R1, R8,R9,R10,R11 ; return LT if outside window ADR R7, GCMVTab B DoJumpTable GCMVTab & GMoveRight-GCMVTab & GMoveLeft-GCMVTab & GMoveRight-GCMVTab & GMoveLeft-GCMVTab & GMoveDown-GCMVTab & GMoveDown-GCMVTab & GMoveUp-GCMVTab & GMoveUp-GCMVTab ; Move graphics cursor right if possible - on exit C=0 iff OK to move GMoveRight ADD R0, R0, R2 ; add on GCharSpaceX GMove10 STR R0, [WsPtr, #GCsIX] GMove15 BLT GMoveOK ; if we were outside already TST R6, #&40 ; or we are in nowrap mode BNE GMoveOK ; then we were OK to move WINDow R0, R1, R8,R9,R10,R11 BGE GMoveOK ; if inside now, then OK SEC MOV PC, R14 GMoveOK CLC MOV PC, R14 ; Move graphics cursor left if possible - on exit C=0 iff OK to move GMoveLeft SUB R0, R0, R2 ; subtract off GCharSpaceX B GMove10 ; Move graphics cursor down if possible - on exit C=0 iff OK to move GMoveDown SUB R1, R1, R3 ; subtract off GCharSpaceY GMove20 STR R1, [WsPtr, #GCsIY] B GMove15 ; Move graphics cursor up if possible - on exit C=0 iff OK to move GMoveUp ADD R1, R1, R3 ; add on GCharSpaceY B GMove20 ; ***************************************************************************** ; ; Move graphics cursor to boundary indicated by value of R6 in bits 1-3 ; (0 or 4 = left, 2 or 6 = right, 8 or 10 = up, 12 or 14 = down) ; + R0 character positions in ; GCursorB0 MOV R0, #0 GCursorBdy ADR R7, GCBDYTab B DoJumpTable GCBDYTab & GCursorLBdy-GCBDYTab & GCursorRBdy-GCBDYTab & GCursorLBdy-GCBDYTab & GCursorRBdy-GCBDYTab & GCursorUBdy-GCBDYTab & GCursorUBdy-GCBDYTab & GCursorDBdy-GCBDYTab & GCursorDBdy-GCBDYTab ; Move graphics cursor to left boundary + R0 characters in GCursorLBdy LDR R7, [WsPtr, #GWLCol] LDR R2, [WsPtr, #GCharSpaceX] MLA R0, R2, R0, R7 ; GCsIX := GWLCol + (X*SpaceX) STR R0, [WsPtr, #GCsIX] MOV PC, R14 ; Move graphics cursor to right boundary + R0 characters in ; (adjust for character size) GCursorRBdy LDR R7, [WsPtr, #GWRCol] LDR R2, [WsPtr, #GCharSizeX] SUB R7, R2, R7 ; R7 = SizeX-GWRCol LDR R2, [WsPtr, #GCharSpaceX] MLA R0, R2, R0, R7 ; R0 = SizeX-GWRCol+X*SpaceX RSB R0, R0, #1 ; GWRCol-X*SpaceX-(SizeX-1) STR R0, [WsPtr, #GCsIX] MOV PC, R14 ; Move graphics cursor to up boundary + R0 characters in GCursorUBdy LDR R7, [WsPtr, #GWTRow] LDR R2, [WsPtr, #GCharSpaceY] RSB R2, R2, #0 ; -SizeY MLA R0, R2, R0, R7 ; GWTRow-Y*SizeY STR R0, [WsPtr, #GCsIY] MOV PC, R14 ; Move graphics cursor to down boundary + R0 characters in ; (adjust for character size) GCursorDBdy LDR R7, [WsPtr, #GWBRow] LDR R2, [WsPtr, #GCharSpaceY] MLA R0, R2, R0, R7 ; GWBRow+Y*SpaceY LDR R2, [WsPtr, #GCharSizeY] ADD R0, R0, R2 SUB R0, R0, #1 ; GWBRow+Y*SpaceY+(SizeY-1) STR R0, [WsPtr, #GCsIY] MOV PC, R14 ; ***************************************************************************** ; ; ClipVdu5 - Add a VDU 5 char to clip box ; ; in: cxl2 = left ; cyb2 = top-bottom ; cxr2 = right ; cyt2 = top ; ; out: All registers preserved ; ASSERT (cxl2=R4) :LAND: (cyb2=R3) :LAND: (cxr2=R10) :LAND: (cyt2=R2) ClipVdu5 ROUT Push "R0-R3, R4, R10, R14" MOV R0, cxl2 SUB R1, cyt2, cyb2 ; top-(top-bottom) = bottom MOV R3, cyt2 MOV R2, cxr2 BL MergeClipBox Pull "R0-R3, R4, R10, PC" END