; 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.VduPointer ; mjs Sep 2000 ; ; kernel/HAL split ; display pointer updating is no longer VIDC/IOMD specific ; ; ***************************************************************************** ; ; DoPointerStuff - Entry point for OSWORD nn ; ; in: R1 -> control block ; [R1, #0] : Reason code ; ; Reason code 0 - Define pointer size, shape and active point ; ; [R1, #1] : Shape number (1..4) ; [R1, #2] : Width (w) in bytes (0..8) ; [R1, #3] : Height (h) in pixels (0..32) ; [R1, #4] : ActiveX in pixels from left (0..w*4-1) ; [R1, #5] : ActiveY in pixels from top (0..h-1) ; [R1, #6..9] : Pointer (P) to data ; [P, #0..w*h-1] : Data bytes in rows from top to bottom, ; left to right in each row. ; ; Reason code 1 - Define mouse coordinate bounding box ; ; [R1, #1..2] : left ; all treated as ; [R1, #3..4] : bottom ; signed 16-bit values, ; [R1, #5..6] : right ; relative to screen origin at the time ; [R1, #7..8] : top ; the command is issued ; ; If (left > right) or (bottom > top) then the command is ignored ; An infinite box can be obtained by setting ; left=&8000, right=&7FFF, bottom=&8000, top=&7FFF ; ; If the current mouse position is outside the box, it is moved to ; the nearest point inside the box ; ; The mouse buffer is NOT flushed - any buffered coords will be moved ; inside the bounding box when they are read. ; ; Reason code 2 - Define mouse multipliers ; ; [R1, #1] : X multiplier ; both treated as ; [R1, #2] : Y multiplier ; signed 8-bit values ; ; Reason code 3 - Set mouse position ; ; [R1, #1..2] : X position ; both treated as ; [R1, #3..4] : Y position ; signed 16-bit values ; The mouse buffer is flushed ; ; Reason code 4 - Read mouse position (not buffered) ; ; out: [R1, #1..2] : X position ; both treated as ; [R1, #3..4] : Y position ; signed 16-bit values ; ; Reason code 5 - Set pointer position ; ; [R1, #1..2] : X position ; both treated as ; [R1, #3..4] : Y position ; signed 16-bit values ; ; Reason code 6 - Read pointer position ; ; out: [R1, #1..2] : X position ; both treated as ; [R1, #3..4] : Y position ; signed 16-bit values ; DoPointerStuff ROUT LDRB R0, [R1, #0] CMP R0, #7 LDRCC PC, [PC, R0, LSL #2] MOV PC, R14 ; ***** WHY NO ERROR???????? DCD DoDefinePointer DCD DoMouseBox DCD SetMouseMult DCD SetMousePosn DCD ReadMousePosn DCD SetPointerPosn DCD ReadPointerPosn ; ***************************************************************************** DoDefinePointer ; We allow interrupts during time we copy shape, but we copy into a ; holding descriptor, so shape will never be displayed (whether its the ; current one, or becomes the current one with an OSByte 6A) until the ; vsync after we have a complete definition. ; ; We have two holding buffers, so that we can always choose a holding ; buffer that is not currently being used for display by the HAL, ; despite multiple definitions between vsyncs. This all assumes we ; are never re-entered, but the documentation for OS_Word 21,0 says ; re-entrancy undefined anyway - should really say not re-entrant. Push "R1-R7, R14" ; interrupts still off for critical choosing of buffer ; ADD R6, WsPtr, #PointerShapesH MOV R7, #0 ; try holding shape 1 LDR R14, [R6, R7, LSL #2] ; R14 -> shape LDR R2, [R14, #PointerBuffLA] ; shape buffer we propose to use LDR R0, [WsPtr, #PointerShapeLA] ; shape buffer owned by HAL TEQ R0, R2 ; identical? MOVEQ R7, #1 ; alright then, holding shape 2 LDREQ R14, [R6, R7, LSL #2] ; R14 -> shape ; now R7 = holding shape index (0,1), R14 -> shape, not owned by HAL CLRPSR I_bit, R0 ; re-enable interrupts LDRB R6, [R1, #1] ; shape number we're defining SUB R6, R6, #1 CMP R6, #4 ; now in range 0..3 ? BCS %FT90 ; bad shape number LDRB R0, [R1, #2] ; R0 = width (bytes) LDRB R2, [R1, #3] ; R2 = height LDRB R3, [R1, #4] ; R3 = ActiveX LDRB R4, [R1, #5] ; R4 = ActiveY CMP R2, #0 ; C=1 if EQ STREQB R2, [R14, #PointerWidth] STREQB R2, [R14, #PointerHeight] BEQ %FT80 ; empty shape (off) CMP R0, #0 ; C=1 if EQ STREQB R0, [R14, #PointerWidth] STREQB R0, [R14, #PointerHeight] CMPNE R0, #8+1 BCS %FT90 ; bad width CMP R2, #32+1 ; C=1 => bad height CMPCC R3, R0, LSL #2 ; ActiveX >= (width * 4) ? CMPCC R4, R2 ; ActiveY >= height BCS %FT90 ; bad definition STRB R0, [R14, #PointerWidth ] ; actual width in bytes, before padding to constant 8 STRB R2, [R14, #PointerHeight] STRB R3, [R14, #PointerActiveX] STRB R4, [R14, #PointerActiveY] ADD R4, R1, #6 LDW R1, R4, R3, R5 ; load word from ; unknown alignment ; Now R1 -> user's data LDR R3, [R14, #PointerBuffLA] ; R3 -> buffer to receive shape 20 ADD R4, R3, R0 ; terminating R3 for this row 30 LDRB R5, [R1], #1 40 STRB R5, [R3], #1 ; store to buffer CMP R3, R4 ; still within user data BCC %BT30 ; for this row ? ; now fill up rest of row MOV R5, #0 TST R3, #7 ; are we on a multiple of 8 BNE %BT40 ; no, then store 0 SUBS R2, R2, #1 ; done all rows ? BNE %BT20 ; no, then loop 80 ; we now have a completely defined shape in a holding buffer ; PHPSEI R0 ; disable interrupts for critical shape logic ADD R3, WsPtr, #PointerShapes ADD R4, WsPtr, #PointerShapesH LDR R1, [R3, R6, LSL #2] ; swap the holding shape (R7=0,1) into LDR R2, [R4, R7, LSL #2] ; the shape we've just defined (R6 = 0..3) STR R2, [R3, R6, LSL #2] STR R1, [R4, R7, LSL #2] PLP R0 ; restore interrupts 90 Pull "R1-R7,PC" ; ***************************************************************************** ; ; SetMouseRectangle - Called on mode change to set appropriate mouse ; rectangle and mouse position ; ; in: WsPtr -> VDWS ; SetMouseRectangle ROUT Push R14 ASSERT DisplayYWindLimit = DisplayXWindLimit +4 ASSERT DisplayXEigFactor = DisplayXWindLimit +8 ASSERT DisplayYEigFactor = DisplayXWindLimit +12 ADD R2, WsPtr, #DisplayXWindLimit LDMIA R2, {R2-R5} ADD R2, R2, #1 ; XWindLimit+1 MOV R2, R2, LSL R4 ; (XWindLimit+1) << XEigFactor SUB R4, R2, #1 ; ((XWindLimit+1) << XEigFactor)-1 MOV R2, R2, LSR #1 ; centre x of window ADD R3, R3, #1 ; YWindLimit+1 MOV R3, R3, LSL R5 ; (YWindLimit+1) << YEigFactor SUB R5, R3, #1 ; ((YWindLimit+1) << YEigFactor)-1 MOV R3, R3, LSR #1 ; centre y of window BL SetMousePosnRegs MOV R2, #0 ; left = 0 MOV R3, #0 ; bottom = 0 Push "R1-R6" B DoMouseBoxRegs DoMouseBox ROUT Push "R1-R6, R14" [ NoARMv6 :LOR: NoUnaligned LDRB R2, [R1, #1] ; R2 = left LDRB R0, [R1, #2] ORR R2, R2, R0, LSL #8 LDRB R3, [R1, #3] ; R3 = bottom LDRB R0, [R1, #4] ORR R3, R3, R0, LSL #8 LDRB R4, [R1, #5] ; R4 = right LDRB R0, [R1, #6] ORR R4, R4, R0, LSL #8 LDRB R5, [R1, #7] ; R5 = top LDRB R0, [R1, #8] ORR R5, R5, R0, LSL #8 | ; Use unaligned loads from ARMv6 LDRH R2, [R1, #1] ; R2 = left LDRH R3, [R1, #3] ; R3 = bottom LDRH R4, [R1, #5] ; R4 = right LDRH R5, [R1, #7] ; R5 = top ] DoMouseBoxRegs ; now add on graphics origin LDR R0, [WsPtr, #OrgX] ADD R2, R2, R0 ADD R4, R4, R0 LDR R0, [WsPtr, #OrgY] ADD R3, R3, R0 ADD R5, R5, R0 ; now sign extend all coords [ NoARMv6 MOV R2, R2, LSL #16 MOV R2, R2, ASR #16 MOV R3, R3, LSL #16 MOV R3, R3, ASR #16 MOV R4, R4, LSL #16 MOV R4, R4, ASR #16 MOV R5, R5, LSL #16 MOV R5, R5, ASR #16 | ; ARMv6 lets you do this using SXTH, but no support in objasm yet DCI &E6BF2072 ; SXTH R2, R2 DCI &E6BF3073 ; SXTH R3, R3 DCI &E6BF4074 ; SXTH R4, R4 DCI &E6BF5075 ; SXTH R5, R5 ] ; now check right >= left and top >= bottom CMP R4, R2 CMPGE R5, R3 BLT %FT10 ; bad definition ; everything seems OK, so disable IRQs while we update vars MRS R14, CPSR ORR R0, R14, #I32_bit MSR CPSR_c, R0 Push R11 LDR R11, =ZeroPage+KeyWorkSpace ADR R0, MouseBounds STMIA R0, {R2-R5} ; check mouse position is within box LDR R0, MouseX CMP R0, R2 ; if X < left STRLT R2, MouseX ; then X := left CMP R4, R0 ; if right < X STRLT R4, MouseX ; then X := right LDR R0, MouseY CMP R0, R3 ; if Y < bottom STRLT R3, MouseY ; then Y := bottom CMP R5, R0 ; if top < Y STRLT R5, MouseY ; then Y := top Pull R11 MSR CPSR_c, R14 ; restore old IRQ state 10 Pull "R1-R6, PC" ; ***************************************************************************** ; ; UpdatePointer - Called on vsync to update pointer position ; ; in: WsPtr (R12) -> VduDriverWorkSpace ; UpdatePointer ROUT LDRB R5, [WsPtr, #PointerShapeNumber] TST R5, #&80 ; pointer unlinked if bit 7 set LDREQ R6, MouseX STREQ R6, [WsPtr, #PointerX] LDREQ R6, MouseY STREQ R6, [WsPtr, #PointerY] ANDS R5, R5, #&7F ; clear bit 7 and set Z if 0 ie off BNE %FT20 10 MOV R0, #0 ; flags = 0 (pointer off) MOV R1, #0 ; x = 0 MOV R2, #0 ; y = 0 MOV R3, #0 ; shape descriptor = NULL STR R3, [WsPtr, #PointerShapeLA] ; NULL passed as last buffer address B %FT40 20 ADD R3, WsPtr, #PointerShapes-4 LDR R3, [R3, R5, LSL #2] ; R3 -> current shape block (R5 = shape 1..4) LDRB R0, [R3, #PointerHeight] ; height of 0 switches pointer off TEQ R0, #0 BEQ %BT10 MOV R0, #1 ; R0 = flags, set pointer on (bit 0 = 1) LDR R1, [WsPtr, #PointerShapeLA] ; last shape buffer given to HAL LDR R4, [R3, #PointerBuffLA] ; shape buffer we're about to give TEQ R1, R4 ; same as last time? STRNE R4, [WsPtr, #PointerShapeLA] ; update ORRNE R0, R0, #2 ; flag new shape (bit 1 = 1) LDR R1, [WsPtr, #PointerX] LDR R4, [WsPtr, #PointerXEigFactor] MOV R1, R1, ASR R4 ; R1 = pointer x, pixels LDRB R4, [R3, #PointerActiveX] SUB R1, R1, R4 ; R1 = pointer x, adjusted for active point LDR R2, [WsPtr, #PointerY] LDR R4, [WsPtr, #DisplayYEigFactor] LDR R5, [WsPtr, #DisplayYWindLimit] ; R5 = display height -1 SUB R2, R5, R2, ASR R4 ; R2 = pointer y, pixels, inverted LDRB R4, [R3, #PointerActiveY] SUB R2, R2, R4 ; R2 = pointer y, adjusted for active point ; and its up to the HAL to handle clipping according to h/w capabilities 40 [ UseGraphicsV Push "LR" MOV R4, #GraphicsV_UpdatePointer BL CallGraphicsV Pull "PC" | Push "R9, R12, LR" mjsAddressHAL mjsCallHAL HAL_Video_UpdatePointer Pull "R9, R12, PC" ] LTORG ; ***************************************************************************** SetMouseMult ROUT Push "R11,R14" LDR R11, =ZeroPage+KeyWorkSpace [ NoARMv4 LDRB R0, [R1, #1] MOV R0, R0, ASL #24 ; sign extend to 32 bits MOV R0, R0, ASR #24 | LDRSB R0, [R1, #1] ] STR R0, MouseXMult [ NoARMv4 LDRB R0, [R1, #2] MOV R0, R0, ASL #24 ; sign extend to 32 bits MOV R0, R0, ASR #24 | LDRSB R0, [R1, #2] ] STR R0, MouseYMult Pull "R11,PC" ; ***************************************************************************** ; ; GetCoordPair - get pair of 2-byte coords from R1+1..R1+4 ; adds on graphics origin and sign extends to 32 bits ; and puts X into R2, Y into R3 ; GetCoordPair ROUT [ NoARMv6 :LOR: NoUnaligned LDRB R0, [R1, #1] ; get X coordinate LDRB R2, [R1, #2] ORR R0, R0, R2, LSL #8 | ; Use unaligned loads and SXTH from ARMv6 LDRH R0, [R1, #1] ; get X coordinate ] LDR R2, [WsPtr, #OrgX] ; add on origin ADD R0, R0, R2 [ NoARMv6 MOV R0, R0, ASL #16 ; sign extend 16 to 32 MOV R2, R0, ASR #16 | DCI &E6BF2070 ; SXTH R2, R0 ] [ NoARMv6 :LOR: NoUnaligned LDRB R0, [R1, #3] ; get Y coordinate LDRB R3, [R1, #4] ORR R0, R0, R3, LSL #8 | LDRH R0, [R1, #3] ; get Y coordinate ] LDR R3, [WsPtr, #OrgY] ; add on origin ADD R0, R0, R3 [ NoARMv6 MOV R0, R0, ASL #16 ; sign extend 16 to 32 MOV R3, R0, ASR #16 | DCI &E6BF3070 ; SXTH R3, R0 ] MOV PC, R14 ; ***************************************************************************** SetMousePosn ROUT Push "R2, R3, R11, R14" LDR R11, =ZeroPage+KeyWorkSpace BL GetCoordPair ; now check point is within bounding box LDR R0, MouseBoundLCol CMP R2, R0 LDRGE R0, MouseBoundRCol CMPGE R0, R2 LDRGE R0, MouseBoundBRow CMPGE R3, R0 LDRGE R0, MouseBoundTRow CMPGE R0, R3 BLGE SetMousePosnRegs Pull "R2, R3, R11, PC" SetMousePosnRegs LDR R11, =ZeroPage+KeyWorkSpace STR R2, MouseX STR R3, MouseY B FlushMouse ; ***************************************************************************** ; ; StoreCoordPair - Stores X,Y coords in R2,R3 in R1+1..R1+4 ; subtracts graphics origin StoreCoordPair ROUT LDR R0, [WsPtr, #OrgX] ; subtract off origin SUB R2, R2, R0 [ NoARMv6 :LOR: NoUnaligned STRB R2, [R1, #1] ; store lo-byte of X MOV R2, R2, LSR #8 STRB R2, [R1, #2] ; store hi-byte of X | ; Use unaligned store from ARMv6 STRH R2, [R1, #1] ; store X ] LDR R0, [WsPtr, #OrgY] ; subtract off origin SUB R3, R3, R0 [ NoARMv6 :LOR: NoUnaligned STRB R3, [R1, #3] ; store lo-byte of Y MOV R3, R3, LSR #8 STRB R3, [R1, #4] ; store hi-byte of Y | ; Use unaligned store from ARMv6 STRH R3, [R1, #3] ; store X ] MOV PC, R14 ; ***************************************************************************** ReadMousePosn ROUT [ AssemblePointerV :LAND: {TRUE} Push "r0-r3, r9-r11, lr" BL PollPointer ; update mouse position on a read LDR r1, [sp, #1*4] ; reload pointer to buffer LDR R11, =ZeroPage+KeyWorkSpace LDR R2, MouseX ; get mouse X LDR R3, MouseY ; get mouse Y BL StoreCoordPair Pull "r0-r3, r9-r11, pc" | Push "R2, R3, R11, R14" LDR R11, =ZeroPage+KeyWorkSpace LDR R2, MouseX ; get mouse X LDR R3, MouseY ; get mouse Y BL StoreCoordPair Pull "R2, R3, R11, PC" ] ; ***************************************************************************** SetPointerPosn ROUT Push "R2, R3, R14" BL GetCoordPair STR R2, [WsPtr, #PointerX] STR R3, [WsPtr, #PointerY] Pull "R2, R3, PC" ; ***************************************************************************** ReadPointerPosn ROUT Push "R2, R3, R14" LDR R2, [WsPtr, #PointerX] LDR R3, [WsPtr, #PointerY] BL StoreCoordPair Pull "R2, R3, PC" ; ***************************************************************************** ; ; FlushMouse - Flush mouse buffer ; ; out: All registers preserved FlushMouse ROUT Push "R0-R2, R14" MOV R0, #21 MOV R1, #Buff_Mouse SWI XOS_Byte Pull "R0-R2, PC" LTORG ; ***************************************************************************** ; ; RemovePointer - Remove soft mouse pointer from screen ; RemovePointer ROUT STMFD R13!,{R0-R6,R14} LDRB R3, [WsPtr, #PointerShapeNumber] TST R3, #&7F MOVNE R0, #0 MOVNE R4, #GraphicsV_UpdatePointer BLNE CallGraphicsV LDMFD R13!,{R0-R6,PC} ; ***************************************************************************** ; ; RestorePointer - Restore soft mouse pointer to previous state ; RestorePointer ROUT STMFD R13!,{R0-R6,R14} LDRB R6, [WsPtr, #PointerShapeNumber] ANDS R6, R6, #&7F BEQ %FT10 ADD R3, WsPtr, #PointerShapes-4 LDR R3, [R3, R6, LSL #2] ; R3 -> current shape block (R6 = shape 1..4) MOV R0, #1 ; R0 = flags, set pointer on (bit 0 = 1) LDR R1, [WsPtr, #PointerShapeLA] ; last shape buffer given to HAL LDR R4, [R3, #PointerBuffLA] ; shape buffer we're about to give TEQ R1, R4 ; same as last time? STRNE R4, [WsPtr, #PointerShapeLA] ; update ORRNE R0, R0, #2 ; flag new shape (bit 1 = 1) LDR R1, [WsPtr, #PointerX] LDR R4, [WsPtr, #PointerXEigFactor] MOV R1, R1, ASR R4 ; R1 = pointer x, pixels LDRB R4, [R3, #PointerActiveX] SUB R1, R1, R4 ; R1 = pointer x, adjusted for active point LDR R2, [WsPtr, #PointerY] LDR R4, [WsPtr, #DisplayYEigFactor] LDR R5, [WsPtr, #DisplayYWindLimit] ; R5 = display height -1 SUB R2, R5, R2, ASR R4 ; R2 = pointer y, pixels, inverted LDRB R4, [R3, #PointerActiveY] SUB R2, R2, R4 ; R2 = pointer y, adjusted for active point ; and it's up to the HAL to handle clipping according to h/w capabilities MOV R4, #GraphicsV_UpdatePointer BL CallGraphicsV 10 LDMFD R13!,{R0-R6,PC} END