; 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.Vdu23 ; ***************************************************************************** ; ; DefineChar - define soft character ; ; in: R0 = char to be defined ; DefineChar ADD R1, WsPtr, #(Font-32*8) ADD R1, R1, R0, LSL #3 ; point to char definition ADD R2, WsPtr, #QQ+1 LDMIA R2, {R2, R3} ; load 8 bytes STMIA R1, {R2, R3} ; store 8 bytes Nop MOV PC, R14 ; ***************************************************************************** ; ; VDU 23,7,m,d,z| - Scroll window directly ; ; m=0 Scroll text window ; m=1 Scroll entire screen ; ; d=0 Scroll right ; d=1 Scroll left ; d=2 Scroll down ; d=3 Scroll up ; d=4 Scroll "right" ; d=5 Scroll "left" ; d=6 Scroll "down" ; d=7 Scroll "up" ; ; z=0 Scroll by 1 character cell ; z=1 Scroll by 1 char vertically, 1 byte (whatever that is) horiz. ; Vdu23_7 ROUT LDRB R0, [WsPtr, #QQ+1] ; R0 := m LDRB R1, [WsPtr, #QQ+2] ; R1 := d LDRB R2, [WsPtr, #QQ+3] ; R2 := z Scroll012 LDR R6, [WsPtr, #CursorFlags] AND R1, R1, #7 ; ignore higher bits CMP R1, #4 BCC %FT10 LDR R4, ScrollDirWord CMP R1, #6 MOVCS R4, R4, ROR #16 AND R3, R6, #&0E MOV R3, R3, LSL #1 MOV R4, R4, LSR R3 MOVS R1, R1, LSR #1 AND R1, R4, #&0F EORCS R1, R1, #1 10 Push R14 TST R6, #ClipBoxEnableBit ; if calculating clip box BLNE ClipScroll ; then add text window or whole screen CMP R0, #1 ; C=1 => whole screen ADC R1, R1, R1 ; put m into bit 0 TEQ R2, #0 ORRNE R1, R1, #&08 ; put z into bit 3 ADR R0, ScrollTab LDR R2, [R0, R1, LSL #2] ADR R14, ScrollRetn ADD PC, R0, R2 ; carry on entry is m ScrollRetn Pull R14 ; insert code here to re-address input cursor as well B AddressCursors ; re-address cursor positions ScrollDirWord & &33221010 ScrollTab & ScrollRightChar-ScrollTab ; window right char & ScrollRightChar-ScrollTab ; screen right char & ScrollLeftChar-ScrollTab ; window left char & ScrollLeftChar-ScrollTab ; screen left char & ScrollDown-ScrollTab ; window down char & HardScrollDown-ScrollTab ; screen down char & ScrollUp-ScrollTab ; window up char & HardScrollUp-ScrollTab ; screen up char & ScrollRightByte-ScrollTab ; window right byte & ScrollRightByte-ScrollTab ; screen right byte & ScrollLeftByte-ScrollTab ; window left byte & ScrollLeftByte-ScrollTab ; screen left byte & ScrollDown-ScrollTab ; window down byte & HardScrollDown-ScrollTab ; screen down byte & ScrollUp-ScrollTab ; window up byte & HardScrollUp-ScrollTab ; screen up byte ; ***************************************************************************** ; ; VDU 23,17,c,t| - Set tint ; ; c=0 Set text foreground tint (default &FF) ; c=1 Set text background tint (default &00) ; c=2 Set graphics foreground tint (default &FF) ; c=3 Set graphics background tint (default 0) ; c=4 t=0 => BBC compatible ECFs, t=1 => native ECFs (default 0) ; c=5 Swap foreground and background text colours/tints ; c=6 VDU 23,17,6,x;y; - Set ECF origin to (x,y) ; c=7 VDU 23,17,7,flags,x;y;0,0 - Set character size(s) ; c=8-255 Reserved ; ; t=tint Only bits 6,7 relevant with this hardware Vdu23_17 LDRB R0, [WsPtr, #QQ+1] ; get c CMP R0, #7 MOVHI R0, #17 ; if unknown (>7), reload R0 BHI UnknownVdu23 ; and call UKVDU23 vector BEQ SetCharSizes CMP R0, #6 BEQ SetECFOrigin CMP R0, #4 BHI SwapColours ; 5 => swap colours LDRB R1, [WsPtr, #QQ+2] ; tint or BBC parm STREQ R1, [WsPtr, #BBCcompatibleECFs] ; VDU 23,17,4,t... MOVEQ PC, R14 ADD R2, WsPtr, #TFTint LDR R3, [R2, R0, LSL #2] ; get old tint STR R1, [R2, R0, LSL #2] CMP R0, #2 ; graphics tint ? BCS SetColour ; then update masks EOR R1, R1, R3 TST R1, #&C0 ; are top two bits different ? MOVEQ PC, R14 ; no need to redo table ; amg: use R1 here instead of 'bpp' which is R0. I need R0 in a moment. LDR R1, [WsPtr, #BitsPerPix] CMP R1, #8 ; are we in 8 bits-per-pixel or more? MOVCC PC, R14 ; no, then exit Push "lr" ; amg: only do foreground or background as appropriate CMP R0,#1 BEQ %FT05 BL CompileTextFg B %FT10 05 BL CompileTextBg ; update TextFgColour/TextBgColour 10 Pull "lr" SetColoursDirty LDR R6, [WsPtr, #CursorFlags] ORR R6, R6, #TEUpdate ; yes, then set colours dirty STR R6, [WsPtr, #CursorFlags] MOV PC, R14 ; ***************************************************************************** SwapColours ROUT LDR R1, [WsPtr, #TForeCol] LDR R2, [WsPtr, #TBackCol] STR R1, [WsPtr, #TBackCol] STR R2, [WsPtr, #TForeCol] LDR R1, [WsPtr, #TextFgColour] LDR R2, [WsPtr, #TextBgColour] STR R1, [WsPtr, #TextBgColour] STR R2, [WsPtr, #TextFgColour] LDR R3, [WsPtr, #BitsPerPix] CMP R3, #8 ; C=1 <=> 256 colour mode BCC %FT10 ; [not 256 colour mode] LDR R1, [WsPtr, #TFTint] LDR R2, [WsPtr, #TBTint] STR R1, [WsPtr, #TBTint] STR R2, [WsPtr, #TFTint] 10 B SetColoursDirty ; don't bother optimising the case ; when both colours are the same ; ***************************************************************************** ; ; SetECFOrigin - Set the origin of the ECF pattern ; ; Called by VDU 23,17,6,x;y;0,0,0 ; ; in: QQ+2, QQ+3 = xlo, xhi ; QQ+4, QQ+5 = ylo, yhi ; SetECFOrigin ROUT ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+3] ; xhi ; LDRB R1, [WsPtr, #QQ+2] ; xlo ; PackXtnd R0, R0, R1 ; pack 2 bytes and sign extend ; LDRB R1, [WsPtr, #QQ+5] ; yhi ; LDRB R2, [WsPtr, #QQ+4] ; ylo ; PackXtnd R1, R1, R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+2 ; *****End of change made by DJS SetECFOriginCommon Push R14 ADD R8, WsPtr, #GCsX ; save ECursor away, cos EIG changes it LDMIA R8, {R6, R7} ; and we don't want it to! MOV R2, #&FF ; convert external-to-internal BL EIG ; as absolute coordinates ; now R0 = internal X; R1 = internal Y LDR R3, [WsPtr, #NPix] LDR R4, [WsPtr, #Log2BPC] AND R0, R0, R3 ; X MOD (number of pixels per word) ; *****Change made by DJS ; Original code was: ; MOVS R0, R0, LSL R4 ; number of bits to rotate ECF left by ; MOVEQ R0, #32 ; if zero then make 32 ; RSB R0, R0, #32 ; so we make it zero again! ; I don't think anything cares whether this value is 0 or 32 in this case - it ; is only used as Rm in a couple of MOV Rn, Rn, ROR Rm instructions. So change ; to: MOV R0, R0, LSL R4 ; number of bits to rotate ECF left by RSB R0, R0, #32 ; *****End of change made by DJS STR R0, [WsPtr, #ECFShift] ; number of bits to rotate right by LDR R3, [WsPtr, #YWindLimit] ; *****Change made by DJS ; Need to increase R3 by one to produce correct alignment of the ECF patterns, ; as YWindLimit is an inclusive bound, not an exclusive one. ADD R3, R3, #1 ; *****End of change made by DJS SUB R1, R3, R1 ; invert Y AND R1, R1, #7 ; modulo 8 STR R1, [WsPtr, #ECFYOffset] STMIA R8, {R6, R7} BL SetColour ; update colours now Pull PC ; ***************************************************************************** ; ; SWISetECFOrigin - Entry point for SWI OS_SetECFOrigin ; ; in: R0 = x-coordinate (external coords) ; R1 = y-coordinate (-------""------) ; SWISetECFOrigin ROUT Push "R0-R9, R14" VDWS WsPtr BL SetECFOriginCommon Pull "R0-R9, R14" ExitSWIHandler ; ***************************************************************************** ; ; Scroll left and right ; ; in: C=0 => scroll window ; C=1 => scroll screen ScrollLeftChar MOV R9, #0 B ScrollLeft ScrollLeftByte LDR R9, [WsPtr, #Log2BPP] LDR R10, [WsPtr, #ModeFlags] TST R10, #Flag_BBCGapMode ; if in BBC gap mode SUBNE R9, R9, #1 ; then 1 BBC byte = 2 ARM bytes ScrollLeft LDR R10, [WsPtr, #Log2BPC] SUB R9, R10, R9 MOV R10, #1 MOV R9, R10, LSL R9 ; R9 = bytes to move by ADC R0, R0, R0 ; bit0(R0) set => whole screen TST R6, #TeletextMode ; if teletext, then do special BNE TTXScrollLeft Push "R0, R14" ; save link and carry MOVS R0, R0, LSR #1 ; C=0/1 => window/screen BL GetScrWindInfo BL ScrollLeft2 Pull R0 MOVS R0, R0, LSR #1 ; now clear right hand column ADDCC R0, WsPtr, #TWBRow ; C=0 => window LDMCCIA R0, {R1-R3} ; R1 = TWBRow; R2 = TWRCol MOVCC R0, R2 ; R3 = TWTRow; R0 = TWRCol ADDCS R0, WsPtr, #ScrRCol ; C=1 => screen LDMCSIA R0, {R0, R1} ; R0 = ScrRCol; R1 = ScrBRow MOVCS R2, R0 ; R2 = ScrRCol; R3 = 0 MOVCS R3, #0 ; R9 = width of column to clear (in bytes) BL GetBoxInfo ; get info for right hand char column ; R2 -> top left of right hand char col ; R5 := number of bytes for one char ADD R2, R2, R5 ; R2 -> off right of top line MOV R5, R9 ; R5 := real number of bytes to do SUB R2, R2, R5 ; R2 -> top left of column to clear Pull R14 B ClearThisBox ; ***************************************************************************** GetScrWindInfo BCC GetWindowInfo GetScreenInfo MOV R0, #0 LDR R1, [WsPtr, #ScrBRow] LDR R2, [WsPtr, #ScrRCol] MOV R3, #0 B GetBoxInfo ; ***************************************************************************** ; ; ScrollLeft2 - Scroll area of screen left (don't clear right column) ; ; in: R2 -> screen(left,top) ; R5 = width of box in bytes ; R6 = number of scan lines in box ; R7 = linelength ; R9 = number of bytes to scroll by ; ScrollLeft2 ROUT SUBS R5, R5, R9 ; number of bytes to scroll MOVEQ PC, R14 ; none to scroll MOV R10, R9, LSL #3 ; number of bits moving by CMP R10, #32 MOVCS R10, #32 ; only do 32 at a time RSB R11, R10, #32 ; 32-number of bits moving by ScrollLineLeft MOV R0, R2 ; to addr (left) ADD R1, R0, R9 ; from addr (right) ADD R3, R0, R5 ; end+1 to addr 10 TST R0, #3 ; if not on word boundary LDRNEB R4, [R1], #1 ; then copy a byte from R1 STRNEB R4, [R0], #1 ; to R0 CMPNE R0, R3 ; if not on bdy and not at end BNE %BT10 ; then loop 20 ADD R1, R1, #3 ; round R1 up to next word BIC R1, R1, #3 TEQ R11, #0 ; if no shifts, use fast code BEQ %FT60 SUB R3, R3, #3 ; fudge factors anonymous CMP R0, R3 ; if can't do any words BCS %FT40 ; then skip LDR R8, [R0] ; get word to be put into R4 30 MOV R4, R8, LSR R10 ; get 2nd bits of old word LDR R8, [R1], #4 ; load new word ORR R4, R4, R8, LSL R11 ; merge with 1st bits of new STR R4, [R0], #4 ; and store CMP R0, R3 ; if more words to do then loop BCC %BT30 40 ADD R3, R3, #3 ; put it back again ; finish off the odd bytes ; R0 -> next dest byte ADD R1, R0, R9 ; R1 -> next source byte CMP R0, R3 ; if not at end 50 LDRCCB R4, [R1], #1 ; then copy a byte from R1 STRCCB R4, [R0], #1 ; to R0 CMPCC R0, R3 ; check for end BCC %BT50 ; and loop if not ADD R2, R2, R7 ; goto next line down SUBS R6, R6, #1 ; one less line to do BNE ScrollLineLeft MOV PC, R14 ; fast code for when R10=32, R11=0 60 SUB R3, R3, #7 ; must be able to do 8 bytes CMP R0, R3 70 LDMCCIA R1!, {R4, R8} ; if OK then copy 2 words STMCCIA R0!, {R4, R8} CMPCC R0, R3 ; check for end BCC %BT70 ADD R3, R3, #4 ; must be able to do 4 bytes CMP R0, R3 80 LDRCC R4, [R1], #4 ; if OK then copy a word STRCC R4, [R0], #4 CMPCC R0, R3 ; check for end BCC %BT80 B %BT40 ; do odd bytes at end ; ***************************************************************************** ScrollRightChar MOV R9, #0 B ScrollRight ScrollRightByte LDR R9, [WsPtr, #Log2BPP] LDR R10, [WsPtr, #ModeFlags] TST R10, #Flag_BBCGapMode ; if in BBC gap mode SUBNE R9, R9, #1 ; then 1 BBC byte = 2 ARM bytes ScrollRight LDR R10, [WsPtr, #Log2BPC] SUB R9, R10, R9 MOV R10, #1 MOV R9, R10, LSL R9 ; R9 = bytes to move by ADC R0, R0, R0 ; bit0(R0) set => whole screen TST R6, #TeletextMode ; if teletext, then do special BNE TTXScrollRight Push "R0, R14" ; save link and carry MOVS R0, R0, LSR #1 ; C=0/1 => window/screen BL GetScrWindInfo BL ScrollRight2 Pull R0 MOVS R0, R0, LSR #1 ; now clear left column ADDCC R0, WsPtr, #TWLCol ; C=0 => window LDMCCIA R0, {R0-R3} ; R0 = TWLCol; R1 = TWBRow MOVCC R2, R0 ; R2 = TWLCol; R3 = TWTRow MOVCS R0, #0 LDRCS R1, [WsPtr, #ScrBRow] MOVCS R2, R0 MOVCS R3, #0 ; R9 = width of column to clear (in bytes) BL GetBoxInfo ; get info for right hand char column ; R2 -> top left of left hand char col ; R5 := number of bytes for one char MOV R5, R9 ; R5 := real number of bytes to do Pull R14 B ClearThisBox ; ***************************************************************************** ; ; ScrollRight2 - Scroll area of screen right (don't clear left column) ; ; in: R2 -> screen(left,top) ; R5 = width of box in bytes ; R6 = number of scan lines in box ; R7 = linelength ; R9 = number of bytes to scroll by ; ScrollRight2 ROUT ADD R2, R2, R5 ; R2 -> off top right SUB R2, R2, #1 ; R2 -> top right SUBS R5, R5, R9 ; number of bytes to scroll MOVEQ PC, R14 ; none to scroll MOV R10, R9, LSL #3 ; number of bits moving by CMP R10, #32 MOVCS R10, #32 ; only do 32 at a time RSB R11, R10, #32 ; 32-number of bits moving by ScrollLineRight MOV R0, R2 ; to addr (right) SUB R1, R0, R9 ; from addr (left) SUB R3, R0, R5 ; end-1 to addr MOV R8, #(3 :SHL: 30) 10 CMP R8, R0, LSL #30 ; EQ if (R0 AND 3)=3 LDRNEB R4, [R1], #-1 ; if not then copy a byte STRNEB R4, [R0], #-1 CMPNE R0, R3 ; if not aligned and not end BNE %BT10 ; then loop SUB R1, R1, #3 ; round R1 down to next word BIC R1, R1, #3 SUB R0, R0, #3 ; make R0 -> word boundary TEQ R11, #0 ; if no shifts, use fast code BEQ %FT60 CMP R0, R3 ; if no words BLS %FT40 ; then skip LDR R8, [R0] ; get word to be put into R4 30 MOV R4, R8, LSL R10 LDR R8, [R1], #-4 ORR R4, R4, R8, LSR R11 STR R4, [R0], #-4 CMP R0, R3 ; if R3 < R1 then no more words BHI %BT30 40 ADD R0, R0, #3 ; put it back again ; finish off the odd bytes ; R0 -> next dest byte SUB R1, R0, R9 ; R1 -> next source byte CMP R0, R3 ; check for end 50 LDRHIB R4, [R1], #-1 ; if not end then copy byte STRHIB R4, [R0], #-1 CMPHI R0, R3 ; check for end BHI %BT50 ADD R2, R2, R7 ; move to next row SUBS R6, R6, #1 ; one less row to do BNE ScrollLineRight MOV PC, R14 ; fast code for when R10=32, R11=0 60 ADD R3, R3, #4 ; need to do at least 8 bytes CMP R0, R3 70 LDMHIDA R1!, {R4, R8} ; if OK then copy 2 words STMHIDA R0!, {R4, R8} CMPHI R0, R3 ; check for end BHI %BT70 SUB R3, R3, #4 ; put it back CMP R0, R3 80 LDRHI R4, [R1], #-4 ; if OK then copy 1 word STRHI R4, [R0], #-4 CMPHI R0, R3 ; check for end BHI %BT80 B %BT40 ; ***************************************************************************** ; ; VDU 23,16,x,y| - Change cursor flags ; ; new := (old AND y) EOR x Vdu23_16 LDRB R0, [WsPtr, #CursorFlags] ; just affect bottom byte LDRB R1, [WsPtr, #QQ+1] ; x LDRB R2, [WsPtr, #QQ+2] ; y AND R0, R0, R2 EOR R0, R0, R1 STRB R0, [WsPtr, #CursorFlags] TST R0, #1 BEQ RCRLF ; leaving 81 column mode ; so release CRLF MOV PC, R14 ; ***************************************************************************** ; ; Move cursor to R0 chars from boundary ; and check for being legal ; ; out: C=1 => was within window ; C=0 => outside window ASSERT CursorY = CursorX +4 CursorBdyCheck Push R14 BL CursorBdy ADD R9, WsPtr, #CursorX LDMIA R9, {R9, R10} CMP R4, R9 CMPCS R3, R10 Pull PC ; ***************************************************************************** ; ; Move 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 ; ; out: R7, R8, R11 undefined ; R0, R1, R6, R9, R10, R12, R13 preserved ; R2-R5 are window coords (left,down,right,up) ; ASSERT TWBRow = TWLCol + 4 ASSERT TWRCol = TWLCol + 8 ASSERT TWTRow = TWLCol + 12 InputCursorB0 MOV R0, #0 InputCursorBdy ADD R11, WsPtr, #InputCursorX B CBDY05 CursorB0 MOV R0, #0 CursorBdy ADD R11, WsPtr, #CursorX CBDY05 ADD R7, WsPtr, #TWLCol ; point to window coords LDMIA R7, {R2-R5} ADR R7, CBDYTab DoJumpTable AND R8, R6, #&0E LDR R8, [R7, R8, LSL #1] ADD PC, R7, R8 CBDYTab & CursorLBdy-CBDYTab & CursorRBdy-CBDYTab & CursorLBdy-CBDYTab & CursorRBdy-CBDYTab & CursorUBdy-CBDYTab & CursorUBdy-CBDYTab & CursorDBdy-CBDYTab & CursorDBdy-CBDYTab ; Move cursor to left boundary + R0 characters in CursorLBdy ADD R7, R0, R2 CBDY10 STR R7, [R11, #CursorX-CursorX] MOV PC, R14 ; Move cursor to right boundary + R0 characters in CursorRBdy SUB R7, R4, R0 B CBDY10 ; Move cursor to up boundary + R0 characters in CursorUBdy ADD R7, R0, R5 CBDY20 STR R7, [R11, #CursorY-CursorX] MOV PC, R14 ; Move cursor to down boundary + R0 characters in CursorDBdy SUB R7, R3, R0 B CBDY20 ; ***************************************************************************** ; ; CursorMove - Move cursor in direction corresponding to R6 bits 1-3 ; (0,4 = right; 2,6 = left; 8,10 = down; 12,14 = up) ; R6 is preserved ASSERT InputCursorY-InputCursorX = CursorY-CursorX ASSERT InputCursorAddr-InputCursorX = CursorAddr-CursorX InputCursorMove ADD R11, WsPtr, #InputCursorX B CurM10 CursorMove ADD R11, WsPtr, #CursorX CurM10 ADR R7, CMVTab B DoJumpTable CMVTab & MoveRight-CMVTab & MoveLeft-CMVTab & MoveRight-CMVTab & MoveLeft-CMVTab & MoveDown-CMVTab & MoveDown-CMVTab & MoveUp-CMVTab & MoveUp-CMVTab ; Move cursor right if possible - on exit C=1 iff at RHS MoveRight LDR R0, [R11, #CursorX-CursorX] LDR R4, [WsPtr, #TWRCol] CMP R0, R4 MOVCS PC, R14 LDR R2, [R11, #CursorAddr-CursorX] [ HiResTTX LDR R3, [WsPtr, #CharWidth] | LDR R3, [WsPtr, #BytesPerChar] ] ADD R0, R0, #1 ADD R2, R2, R3 STR R0, [R11, #CursorX-CursorX] STR R2, [R11, #CursorAddr-CursorX] MOV PC, R14 ; Move cursor left if possible - on exit C=1 iff at LHS MoveLeft LDR R0, [R11, #CursorX-CursorX] LDR R4, [WsPtr, #TWLCol] CMP R4, R0 MOVCS PC, R14 LDR R2, [R11, #CursorAddr-CursorX] [ HiResTTX LDR R3, [WsPtr, #CharWidth] | LDR R3, [WsPtr, #BytesPerChar] ] SUB R0, R0, #1 SUB R2, R2, R3 STR R0, [R11, #CursorX-CursorX] STR R2, [R11, #CursorAddr-CursorX] MOV PC, R14 ; Move cursor down if possible - on exit C=1 iff at bottom MoveDown LDR R1, [R11, #CursorY-CursorX] LDR R4, [WsPtr, #TWBRow] CMP R1, R4 MOVCS PC, R14 LDR R2, [R11, #CursorAddr-CursorX] LDR R3, [WsPtr, #RowLength] ADD R1, R1, #1 ADD R2, R2, R3 STR R1, [R11, #CursorY-CursorX] STR R2, [R11, #CursorAddr-CursorX] MOV PC, R14 ; Move cursor up if possible - on exit C=1 iff at top MoveUp LDR R1, [R11, #CursorY-CursorX] LDR R4, [WsPtr, #TWTRow] CMP R4, R1 MOVCS PC, R14 LDR R2, [R11, #CursorAddr-CursorX] LDR R3, [WsPtr, #RowLength] SUB R1, R1, #1 SUB R2, R2, R3 STR R1, [R11, #CursorY-CursorX] STR R2, [R11, #CursorAddr-CursorX] MOV PC, R14 ; ***************************************************************************** ; ; Special HT - used when abnormal cursor direction selected ; or if C81Bit set ; ; in: R6 = CursorFlags ; SpecialHT TST R6, #Vdu5Bit BNE Vdu5HT Push "R6,R14" BL RCRLFR6 Pull R6 BL CursorMove ; try to move in appropriate direction Pull PC, CC ; if successful, finish BL CursorB0 ; else move cursor to -ve X boundary BL AddressCursor ; re-address cursor Pull R14 B VduLF ; and do a line-feed ; ***************************************************************************** ; ; CHT - version of HT used after printing character ; will set pending CRLF if necessary ; ; in: R6 = CursorFlags CHT TST R6, R6, ROR #10 ; test for Vdu5 or &1E or C81Bit, latter not ; possible as we just printed a char BNE SpecialCHT LDR R0, [WsPtr, #CursorX] LDR R2, [WsPtr, #CursorAddr] [ HiResTTX LDR R3, [WsPtr, #CharWidth] | LDR R3, [WsPtr, #BytesPerChar] ] LDR R4, [WsPtr, #TWRCol] ADD R0, R0, #1 ADD R2, R2, R3 CMP R0, R4 STRLS R0, [WsPtr, #CursorX] STRLS R2, [WsPtr, #CursorAddr] MOVLS PC, R14 TST R6, #1 ; are we in "81-column" mode BNE CHT10 ; yes, then just set C81Bit BSR PageTest LDR R0, [WsPtr, #TWLCol] LDR R1, [WsPtr, #CursorY] LDR R4, [WsPtr, #TWBRow] ADD R1, R1, #1 CMP R1, R4 BLS CursorR0R1 ; not on bottom line STR R0, [WsPtr, #CursorX] BSR ScrollUp B AddressCursor ; re-address cursor position CHT10 ORR R6, R6, #C81Bit STR R6, [WsPtr, #CursorFlags] MOV PC, R14 SpecialCHT TST R6, #Vdu5Bit BNE Vdu5HT BSR CursorMove ; try to move in appropriate direction MOVCC PC, R14 ; if successful, finish TST R6, #1 BNE CHT10 Push R14 BL CursorB0 ; else move cursor to -ve X boundary BL AddressCursor ; re-address cursor Pull R14 B VduLF ; and do a line-feed ; ***************************************************************************** ; ; Special BS - used when abnormal cursor direction selected ; or Vdu5 mode ; or if C81Bit was set ; ; in : R6 = CursorFlags ; SpecialBS TST R6, #Vdu5Bit ; VDU 5 mode ? BNE Vdu5BS ; then branch TST R6, #C81Bit ; did we come here cos of C81Bit BICNE R6, R6, #C81Bit ; if so then clear the bit STRNE R6, [WsPtr, #CursorFlags] ; store it back MOVNE PC, R14 ; and leave cursor where it is EOR R6, R6, #6 ; move "left" Push R14 BL CursorMove Pull PC, CC ; if successful BL CursorB0 ; move to +ve X boundary BL AddressCursor ; re-address cursor Pull R14 B VT ; and do reverse line-feed ; ***************************************************************************** ; ; Special LF - used when abnormal cursor direction selected ; ; in : R6 = CursorFlags ; SpecialLF EOR R6, R6, #8 ; move "down" Push R14 BL CursorMove Pull PC, CC ; if successful BL CanScroll ; see if we can scroll Pull PC, CS ; if failed, exit with all done Pull R14 MOV R0, #0 ; scroll window MOV R1, #7 ; "up" MOV R2, #0 ; by 1 char B Scroll012 ; ***************************************************************************** ; ; Special VT - used when abnormal cursor direction selected ; ; in : R6 = CursorFlags ; SpecialVT EOR R6, R6, #14 ; move "up" Push R14 BL CursorMove Pull PC, CC ; if successful BL CanScroll ; see if we can scroll Pull PC, CS ; if failed, exit with all done Pull R14 MOV R0, #0 ; scroll window MOV R1, #6 ; "down" MOV R2, #0 ; by 1 char B Scroll012 ; ***************************************************************************** ; ; CanScroll - check whether we can scroll in direction R6 ; ; in: R6 = CursorFlags CanScroll ROUT Push R14 TST R6, #&10 ; do we scroll or move to other edge BNE CantScroll TST R6, #CursorsSplit BEQ %FT10 ; cursors not split, so input cursor ; not relevant EOR R6, R6, #6 BL InputCursorMove ; if cursor fails to move, it's OK ; where it is BL AddressInputCursor ; readdress it anyway, just in case EOR R6, R6, #6 ; put R6 back 10 CLC Pull PC CantScroll BL CursorB0 ; move to opposite edge BL AddressCursor SEC Pull PC ; ***************************************************************************** ; ; Release any pending CRLF ; RCRLF LDR R6, [WsPtr, #CursorFlags] ; Extra entry point when R6 already loaded RCRLFR6 TST R6, #C81Bit MOVEQ PC, R14 ; no pending CRLF BSR CR10 ; (clears C81Bit) B VduLF ; ***************************************************************************** ; ; VDU 23,8,t1,t2,x1,y1,x2,y2| - Clear block of text ; ; t=0 Top left of window ; t=1 Top of cursor column ; t=2 Off top right of window ; ; t=4 Left end of cursor line ; t=5 Cursor position ; t=6 Off right of cursor line ; ; t=8 Bottom left of window ; t=9 Bottom of cursor column ; t=10 Off bottom right of window ; Vdu23_8 MOV R0, #0 ; top left of window STRB R0, [WsPtr, #CBWS+0] STRB R0, [WsPtr, #CBWS+1] BSR CP81 ; cursor position STRB R0, [WsPtr, #CBWS+2] STRB R1, [WsPtr, #CBWS+3] BSR WBotRig ; bottom right of window ADD R0, R0, #1 ; off bottom right of window STRB R0, [WsPtr, #CBWS+4] STRB R1, [WsPtr, #CBWS+5] ADD R3, WsPtr, #CBWS ADD R2, R3, #QQ+2-CBWS LDRB R0, [WsPtr, #QQ+1] ; t1 BSR CLBL50 LDRB R0, [WsPtr, #QQ+2] ; t2 BSR CLBL50 ; Check end is after start LDRB R2, [WsPtr, #CBStart] ; start X LDRB R3, [WsPtr, #CBStart+1] ; start Y LDRB R4, [WsPtr, #CBEnd] ; end X LDRB R5, [WsPtr, #CBEnd+1] ; end Y CMP R5, R3 CMPEQ R4, R2 MOVLS PC, R14 ; end <= start so do nothing LDR R0, [WsPtr, #CursorX] ; save cursor position LDR R1, [WsPtr, #CursorY] Push "R0,R1" MOV R0, R3 ; First row to clear MOV R1, R2 ; Start position for first row LDRB R7, [WsPtr, #CBWS+4] ; End position for all but last row ADD R6, WsPtr, #TWLCol LDMIA R6, {R8-R11} LDR R6, [WsPtr, #CursorFlags] CLBL20 TEQ R0, R5 BEQ CLBL40 BSR RowClear ADD R0, R0, #1 MOV R1, #0 ; start position for subsequent rows B CLBL20 CLBL40 MOV R7, R4 ; end position for last row BSR RowClear Pull "R0,R1" STR R0, [WsPtr, #CursorX] STR R1, [WsPtr, #CursorY] B AddressCursor CLBL50 AND R1, R0, #3 MOV R1, R1, LSL #1 LDRB R6, [WsPtr, #CBWS+4] BSR CLBL60 MOV R1, R0, LSR #1 ORR R1, R1, #1 LDRB R6, [WsPtr, #CBWS+5] CLBL60 LDRB R4, [R3, R1] ; get base coordinate to use LDRB R5, [R2, #1]! ; get x or y offset MOV R5, R5, LSL #24 ADDS R4, R4, R5, ASR #24 ; add sign extended offset to base MOVMI R4, #0 ; if <0 then make =0 CMP R4, R6 MOVHI R4, R6 ; is this stringent enough ? STRB R4, [R2, #CBStart-(QQ+3)] MOV PC, R14 ; ***************************************************************************** ; ; RowClear - Clear a "row" {R1 <= X < R7, Y = R0} RowClear Push "R0-R11,R14" SUB R7, R7, #1 CMP R1, R7 BHI RowCL10 ; left > right, so ignore TST R6, #8 MOVEQ R2, R1 ; left MOVEQ R3, R0 ; bottom MOVEQ R4, R7 ; right MOVEQ R5, R0 ; top MOVNE R2, R0 ; left MOVNE R3, R7 ; bottom MOVNE R4, R0 ; right MOVNE R5, R1 ; top TST R6, #2 ADDEQ R0, R8, R2 ADDEQ R2, R8, R4 SUBNE R0, R10, R4 SUBNE R2, R10, R2 TST R6, #4 ADDEQ R1, R11, R3 ADDEQ R3, R11, R5 SUBNE R1, R9, R5 SUBNE R3, R9, R3 BL ClearBox RowCL10 Pull "R0-R11,PC" [ :LNOT: AssemblingArthur ; ***************************************************************************** ; ; DoVduExternal - External entry point for ; a) reading input cursor position ; b) reading output cursor position ; c) reading character at cursor position and screen mode ; d) resetting all or part of font ; e) reading font definitions ; f) reading VDU status ; g) reading VDU variables ; h) reading palette (OSWORD &0B) ; i) setting palette (OSWORD &0C) ; j) various mouse/pointer stuff ; k) set top of screen address ; l) set VDU driver bank ; m) set display bank ; ; in: R0 = 0 => read input cursor position ; R0 = 1 => read output cursor position ; R0 = 2 => OSBYTE &87 - R1 := char at cursor, R2 := screen mode ; R0 = 3 => reset font (R1*32 = start char, R2 = number of pages) ; R0 = 4 => OSWORD 10 (R1 -> control block) ; R0 = 5 => read VDU status ; R0 = 6 => read VDU variables number R1, R1+1 ; R0 = 7 => read palette ; R0 = 8 => set palette ; R0 = 9 => mouse/pointer control ; R0 = 10 => set top of screen address ; R0 = 11 => set VDU driver bank ; R0 = 12 => set display bank ; ; out: a,b; R1 = X, R2 = Y ; c; R1=char, R2=screen mode ; f; R1=VDU status ; g; R1=variable(n), R2=variable(n+1) ; R0, R3 destroyed ; R4-R11 preserved ; DoVduExternal ROUT CMP R0, #ExtEntries MOVCS PC, R14 LDR R3, [PC, R0, LSL #2] ADD PC, PC, R3 ExtTable OutputExternals ] ; ***************************************************************************** DoReadPOSVPOSI ROUT MOV R0, #0 B %FT05 DoReadPOSVPOSO MOV R0, #1 05 Push "R4-R11, R14" LDR R6, [WsPtr, #CursorFlags] TST R6, #CursorsSplit ; if cursors are split TEQNE R0, #1 ; and reading input cursor BNE %FT10 ; then use input cursor BL CP81 ; else read output cursor B %FT20 10 BL CP79 20 MOV R2, R1 MOV R1, R0 Pull "R4-R11, PC" ; ***************************************************************************** ; ; DoSetScreenStart - Set top of screen address (display + drivers) ; ; in: R1 -> control block ; [R1, #0] = bit mask; bit 0 set => change drivers address ; bit 1 set => change display address ; ; [R1, #1..4] = byte offset from lowest screen address ; ; out: - ; DoSetScreenStart ROUT Push R14 LDRB R3, [R1, #0] ; R3 = bitmask [ NoARMv6 :LOR: NoUnaligned LDRB R0, [R1, #1] LDRB R2, [R1, #2] ORR R0, R0, R2, LSL #8 LDRB R2, [R1, #3] ORR R0, R0, R2, LSL #16 LDRB R2, [R1, #4] ORR R0, R0, R2, LSL #24 ; R0 is now the offset | ; Use unaligned load from ARMv6 LDR R0, [R1, #1] ] LDR R2, [WsPtr, #TotalScreenSize] CMP R0, R2 BCS %FT10 ; offset too large Push "R0,R2,R3,R5-R10" MOV R0, #1 STRB R0, [WsPtr, #ScreenMemoryClaimed] ; indicate memory not available BL PreWrchCursor Pull "R0,R2,R3,R5-R10" LDR R14, [WsPtr, #ScreenEndAddr] ADD R0, R0, R14 SUB R0, R0, R2 ; make into a LOGRAM address TST R3, #1 BEQ %FT05 Push R0 BL NewScreenStart Pull R0 05 TST R3, #2 BLNE SetVinit ; program vinit and set DisplayStart Push "R5-R10" ; save registers BL PostWrchCursor Pull "R5-R10" 10 Pull PC ; ***************************************************************************** ; ; NewScreenStart - Update ScreenStart and readdress cursors ; ; in: R0 = new screen start ; ; out: R0, R2 corrupted; all others preserved ; NewScreenStart ROUT Push R14 LDR R2, [WsPtr, #DisplayScreenStart] BL SetDisplayScreenStart LDR R14, [WsPtr, #VduSprite] ; test if outputting to sprite TEQ R14, #0 ; Z => outputting to screen MOVNE PC, R14 ; if outputting to sprite, don't update ; Screenstart or cursor addresses STR R0, [WsPtr, #ScreenStart] SUB R0, R0, R2 ; R0 := new-old AdjustCursorVars LDR R14, [WsPtr, #CursorAddr] ADD R14, R14, R0 STR R14, [WsPtr, #CursorAddr] LDR R14, [WsPtr, #InputCursorAddr] ADD R14, R14, R0 STR R14, [WsPtr, #InputCursorAddr] Pull PC ; ***************************************************************************** ; ; DoSetDriverBank - Set VDU driver's screen bank (OSBYTE &70) ; ; in: R1 = bank number (1..n) (NOTE: starts at 1) ; DoSetDriverBank ROUT Push R14 MOVS R2, R1 BNE %FT10 LDR R1, [WsPtr, #VduStatus] TST R1, #Shadowing MOVEQ R2, #1 MOVNE R2, #2 10 LDR R0, =ZeroPage LDRB R1, [R0, #OsbyteVars + :INDEX: MemDriver] ; old value Push "R1,R4-R10" ; save registers BL ConvertBankToAddress ; R3 := start address of NEXT bank LDR R14, [WsPtr, #ScreenEndAddr] CMP R3, R14 ; if after end, can't do it Pull "R1,R4-R10,PC", HI ; so exit STRB R2, [WsPtr, #ScreenMemoryClaimed] ; indicate memory not available (R2<>0) STRB R2, [R0, #OsbyteVars + :INDEX: MemDriver] ; store new value LDR R0, [WsPtr, #DriverBankAddr] ; R0:=old default bank start LDR R2, [WsPtr, #DisplayScreenStart] ; R2:=old current screen start SUB R0, R2, R0 ; R0 := (current-default) ; in range 1-TotalSize..TotalSize-1 LDR R2, [WsPtr, #ScreenSize] SUB R3, R3, R2 ; default start of THIS bank STR R3, [WsPtr, #DriverBankAddr] ; R3 := new default bank start ADD R0, R0, R3 ; new current start (not bound checked) LDR R2, [WsPtr, #TotalScreenSize] RSBS R0, R0, R14 ADDLS R0, R0, R2 CMP R0, R2 SUBHI R0, R0, R2 ; now in bounds (but inverted) RSB R0, R0, R14 Push R0 BL PreWrchCursor Pull R0 BL NewScreenStart BL PostWrchCursor Pull "R1,R4-R10,PC" ; ***************************************************************************** ; ; DoSetDisplayBank - Set displayed screen bank (OSBYTE &71) ; ; in: R1 = bank number (1..n) (NOTE: starts at 1) ; DoSetDisplayBank ROUT Push R14 MOVS R2, R1 BNE %FT10 LDR R1, [WsPtr, #VduStatus] TST R1, #Shadowing MOVEQ R2, #1 MOVNE R2, #2 10 LDR R0, =ZeroPage LDRB R1, [R0, #OsbyteVars + :INDEX: MemDisplay] ; old value Push "R1,R4-R5" ; save registers BL ConvertBankToAddress ; R3 := start address of NEXT bank LDR R14, [WsPtr, #ScreenEndAddr] CMP R3, R14 ; if after end, can't do it Pull "R1,R4-R5,PC", HI ; so exit STRB R2, [WsPtr, #ScreenMemoryClaimed] ; indicate memory not available (R2<>0) STRB R2, [R0, #OsbyteVars + :INDEX: MemDisplay] ; store new value LDR R0, [WsPtr, #DisplayBankAddr] ; R0 := old default bank start LDR R2, [WsPtr, #DisplayStart] ; R2 := old current display start SUB R0, R2, R0 ; R0 := (current-default) ; in range 1-TotalSize..TotalSize-1 LDR R2, [WsPtr, #ScreenSize] SUB R3, R3, R2 ; default start of THIS bank STR R3, [WsPtr, #DisplayBankAddr] ; R3 := new default bank start ADD R0, R0, R3 ; new current start (not bound checked) LDR R2, [WsPtr, #TotalScreenSize] RSBS R0, R0, R14 ADDLS R0, R0, R2 CMP R0, R2 SUBHI R0, R0, R2 ; now in bounds (but inverted) RSB R0, R0, R14 BL SetVinit ; program vinit and set DisplayStart Pull "R1,R4-R5,PC" ; ***************************************************************************** ; ; CP81 - Read output cursor position, ; taking C81Bit and CursorFlags into account ; ; out: R0=X, R1=Y CP81 Push R14 BL CP80 LDR R6, [WsPtr, #CursorFlags] TST R6, #C81Bit ADDNE R0, R0, #1 ; in hidden column, so inc X Pull PC ; ***************************************************************************** ; ; CP79 - Read input cursor position, ; taking CursorFlags into account ; ; out: R0=X, R1=Y CP79 MOV R1, #InputCursorX-TWLCol B CP80R1 ; ***************************************************************************** ; ; WBotRig - Read coordinates of "bottom right" in user coords ; ; out: R0=X, R1=Y WBotRig ADD R5, WsPtr, #TWLCol LDR R6, [WsPtr, #CursorFlags] LDR R0, [R5, #TWLCol-TWLCol] ; get TWLCol LDR R1, [R5, #TWRCol-TWLCol] ; get TWRCol SUB R4, R1, R0 MOV R2, #0 MOV R1, #0 B CP8010 ; ***************************************************************************** ; ; CP80 - Read cursor position, taking CursorFlags into account CP80 MOV R1, #CursorX-TWLCol CP80R1 ADD R5, WsPtr, #TWLCol LDR R6, [WsPtr, #CursorFlags] MOV R2, #2 MOV R0, #0 BSR CP8020 MOV R4, R2 MOV R2, #4 CP8010 ADD R1, R1, #4 MOV R0, #TWTRow-TWLCol BSR CP8020 MOV R0, R2 MOV R1, R2 TST R6, #8 MOVEQ R0, R4 MOVNE R1, R4 MOV PC, R14 CP8020 TST R2, R6 EORNE R0, R0, #8 LDR R2, [R5, R0] LDR R3, [R5, R1] SUBNE R2, R2, R3 SUBEQ R2, R3, R2 MOV PC, R14 ; ***************************************************************************** ; ; Vdu23_0 - Program "6845" ; Vdu23_0 LDRB R1, [WsPtr, #QQ+1] ; get register number AND R2, R1, #31 ; address register is 5 bits CMP R2, #8 MOVCC PC, R14 BEQ Vdu23_0_8 CMP R2, #10 BEQ Vdu23_0_10 CMP R2, #12 BCC Vdu23_0_11 [ DoVdu23_0_12 BEQ Vdu23_0_12 CMP R2, #13 BEQ Vdu23_0_13 ] B UnknownVdu23 ; ***************************************************************************** ; ; Vdu23_0_8 - Program interlace ; ; in: R1 = unmasked register number (bits 5-7 may be set) Vdu23_0_8 ROUT LDRB R0, [WsPtr, #QQ+2] ; value to program into interlace TST R0, #&80 ; if negative, don't EOR with *TV TSTEQ R1, #&E0 ; if not register 8, don't EOR BNE %FT10 ; don't EOR LDROSB R1, TVInterlace TST R1, #1 EORNE R0, R0, #1 ; toggle if *TV n,1 and number +ve 10 [ UseGraphicsV Push "R14" MOV R4, #GraphicsV_SetInterlace BL CallGraphicsV Pull "R14" | Push "R0-R3, R9, R12, LR" mjsAddressHAL mjsCallHAL HAL_Video_SetInterlace Pull "R0-R3, R9, R12, LR" ] MOV PC, R14 [ DoVdu23_0_12 ; ***************************************************************************** ; ; Vdu23_0_12 - Program "hi" byte of start of screen ; Vdu23_0_12 MOV R2, #11 ; starting bit number V23012_10 LDRB R0, [WsPtr, #QQ+2] ; get parameter LDR R1, [WsPtr, #VinitCopy] MOV R1, R1, ROR R2 ; move changing bits to bottom BIC R1, R1, #&FF ; clear old bits out ORR R1, R1, R0 ; put in new bits RSB R2, R2, #32 ; fudge cos we ain't got ROL MOV R0, R1, ROR R2 ; put back to correct position B SetVinitPhys ; ***************************************************************************** ; ; Vdu23_0_13 - Program "lo" byte of start of screen ; Vdu23_0_13 MOV R2, #3 ; starting bit number B V23012_10 ] ; ***************************************************************************** ; ; Vdu23_9 - Equivalent of FX 9 ; Vdu23_10 - Equivalent of FX 10 ; ; in: R0 = 9 or 10 ; Vdu23_9 Vdu23_10 Push R14 ; for the SWI LDRB R1, [WsPtr, #QQ+1] ; get X parameter SWI XOS_Byte Pull PC, VC ; no error, then return Pull R14 ; get stack back B VduBadExit ; and tell the world ; ***************************************************************************** ; ; DoReadVDUStatus - Read VDU status ; ; out: R1 = status ; bit 0 set => printer enabled by VDU 2 ; bit 1 set => N/A ; bit 2 set => in page mode ; bit 3 set => text window in force ; bit 4 set => in a shadow mode ; bit 5 set => in VDU 5 mode ; bit 6 set => cursor editing in progress ; bit 7 set => VDU disabled (by VDU 21) ; ; R2 corrupted ; DoReadVDUStatus LDR R1, [WsPtr, #VduStatus] ; Vdu2, Window, Shadow bits LDR R2, [WsPtr, #CursorFlags] TST R2, #PageMode ORRNE R1, R1, #&04 TST R2, #Vdu5Bit ORRNE R1, R1, #&20 TST R2, #CursorsSplit ORRNE R1, R1, #&40 TST R2, #VduDisabled ORRNE R1, R1, #&80 MOV PC, R14 ; ***************************************************************************** ; ; DoReadVDUVariable - Read BBC-style VDU variables ; ; in: R1 = variable to read (only &00..&0F are supported) ; ; out: R1 = value of that variable ; R2 = value of next variable ; DoReadVDUVariable CMP R1, #(BBCVduVarsEnd-BBCVduVars) MOVCS PC, R14 ; don't support this variable ADR R3, BBCVduVars ; point to lookup table LDRB R0, [R3, R1]! ; get index for first variable LDRB R1, [WsPtr, R0] ; get first variable LDRB R0, [R3, #1] ; get index for second variable LDRB R2, [WsPtr, R0] ; get second variable MOV PC, R14 BBCVduVars EQUB GWLCol EQUB GWLCol+1 EQUB GWBRow EQUB GWBRow+1 EQUB GWRCol EQUB GWRCol+1 EQUB GWTRow EQUB GWTRow+1 EQUB TWLCol EQUB TWBRow EQUB TWRCol EQUB TWTRow EQUB OrgX EQUB OrgX+1 EQUB OrgY EQUB OrgY+1 BBCVduVarsEnd ; ***************************************************************************** ; ; SetCharSizes - Set char sizes for VDU 4 or VDU 5 text ; ; in: QQ+2 = flags: bit 0 set => set VDU 4 size ; bit 1 set => set VDU 5 size ; bit 2 set => set VDU 5 spacing ; QQ+3,4 x size in pixels ; QQ+5,6 y size in pixels ; ASSERT YEigFactor = XEigFactor +4 SetCharSizes ROUT LDRB R0, [WsPtr, #QQ+3] LDRB R2, [WsPtr, #QQ+4] ORR R0, R0, R2, LSL #8 ; R0 = x size LDRB R1, [WsPtr, #QQ+5] LDRB R2, [WsPtr, #QQ+6] ORR R1, R1, R2, LSL #8 ; R1 = y size LDRB R2, [WsPtr, #QQ+2] ADD R3, WsPtr, #GCharSizes TST R2, #2 ; if modifying VDU 5 size STMNEIA R3, {R0, R1} ADD R3, R3, #8 TST R2, #4 ; if modifying VDU 5 spacing STMNEIA R3, {R0, R1} MOV PC, R14 END