; 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.VduDriver ; ; ARTHUR OPERATING SYSTEM - Vdu Drivers ; ======================= ; ; Vdu driver code - Vdu queue, mode, default windows etc. ; ; Author R C Manby ; Date 5.9.86 ; GET s.vdu.VduGrafDec MACRO RMVT $var, $BW [ "$BW"="B" = (wk$var-wkstart)*2 | [ "$BW"="W" = (wk$var-wkstart)*2 +1 | .... Invalid option on RMVT .... ] ] MEND MACRO RVVT $var ASSERT ($var >= 0) :LAND: ($var < &400) :LAND: (($var :AND: 3)=0) = $var :SHR: 2 MEND MACRO IssueService BL Issue_Service MEND MACRO MALIGN $length, $phase LCLA temp LCLS string temp SETA .-ArthurVduDriver [ "$phase"="" string SETS "ALIGN $length" | string SETS "ALIGN $length, $phase" ] $string temp SETA .-ArthurVduDriver-temp [ temp=0 ! 0, string :CC: " fitted exactly" | ! 0, string :CC: " wasted " :CC: :STR: temp ] MEND ; Macro to load up video bandwidth and video memory size MACRO GetBandwidthAndSize $bw, $size LDR $size, =ZeroPage LDR $size, [$size, #VideoSizeFlags] MOV $bw, #100*1024*1024 MOV $size, $size, LSR #12 MOV $size, $size, LSL #12 ! 0, "Sort out GetBandwidthAndSize" MEND ; ***************************************************************************** ; Vdu status bits Vdu2ModeBitPosn * 0 Vdu2Mode * 1 :SHL: Vdu2ModeBitPosn Windowing * 1 :SHL: 3 Shadowing * 1 :SHL: 4 ; ***************************************************************************** ArthurVduDriver ; ***************************************************************************** ; ; VduInit - Once only initialisation of Vdu drivers eg after Break ; ======= ; VduInit ROUT Push R14 LDR R0, =ZeroPage LDR R14, [R0, #VideoPhysAddr] ASSERT (ZeroPage :AND: 255) = 0 STRB R0, [R0, #OsbyteVars + :INDEX: VDUqueueItems] ;purge queue STRB R0, [WsPtr, #ScreenBlankFlag] ; not blanked MOV R0, #255 STRB R0, [WsPtr, #ScreenBlankDPMSState] ; however, no mode programmed yet MOV R0, #0 STR R0, [WsPtr, #CursorCounter] STR R0, [WsPtr, #CursorDesiredState] STR R0, [WsPtr, #VduStatus] STRB R0, [WsPtr, #PointerShapeNumber] ; make sure pointer off STR R0, [WsPtr, #PointerShapeLA] ; no shape passed to HAL yet STR R0, [WsPtr, #CursorStack] ; 0 bits => on STR R0, [WsPtr, #VduSaveAreaPtr] ; indicate no save area yet STR R0, [WsPtr, #ClipBoxEnable] ; no clip box calculating STRB R0, [WsPtr, #ExternalFramestore] STR R0, [WsPtr, #GraphicsVFeatures] MOV R3, #MaxGraphicsVDrivers LDR R2, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers 01 STR R0, [R2], #4 SUBS R3, R3, #1 BNE %BT01 MOV R0, #GraphicsVInvalid STR R0, [WsPtr, #CurrentGraphicsVDriver] STR R14, [WsPtr, #TrueVideoPhysAddr] ; init TrueVideoPhysAddr for internal RAM/VRAM framestore case LDR R0, =RangeC+SpriteReason_SwitchOutputToSprite STR R0, [WsPtr, #SpriteMaskSelect] MOV R0, #InitialCursorFlags ; TMD 25/9/86 STR R0, [WsPtr, #CursorFlags] ADRL R0, NUL ; point to MOV PC,R14 STR R0, [WsPtr, #WrchNbit] ; just in case ... ADRL R0, ExportedHLine STR R0, [WsPtr, #HLineAddr] ADD R0, WsPtr, #FgEcfOraEor STR R0, [WsPtr, #GcolOraEorAddr] MOV R0, #maxmode STR R0, [WsPtr, #MaxMode] ; constant now LDROSB R0, LastBREAK ; is it a hard reset ? TEQ R0, #SoftReset BEQ %FT10 ; [no, don't reset font] ; allocate buffer for Tim's whizzy text expansion. This now lives ; in the system heap, unless the claim request fails. If the request ; fails then the pointer points at the original buffer in the Vdu ; driver workspace. ; This allows the user to access depths upto 16 bit per pixel before ; strings things things become afoot at the Circle K. LDR R3, =TextExpandArea_Size BL ClaimSysHeapNode ; allocate buffer for heap data ADDVS R2, WsPtr, #TextExpand STR R2, [WsPtr, #TextExpandArea] LDR R3, =ModeSelector_MaxSize+4 ; get block for two overlapping copies BL ClaimSysHeapNode ; of mode selector, 1 word apart STR R2, [WsPtr, #KernelModeSelector] ; now reset soft font from hard font MOV R1, #1 ; start at character 1*32 STRB R1, [WsPtr, #ScreenMemoryClaimed] ; can't claim memory till a mode change MOV R2, #7 ; copy 7 pages BL DoResetFont ;initialise the 6 pointer shape pointers and blocks ;(shape buffers are 6 * &100 starting at CursorData) ; ADD r0, WsPtr, #PointerShapes LDR r2, =CursorData MOV r3, #6 ADD r4, WsPtr, #PointerShapeBlocks 02 STR r4, [r0] ; attach pointer to block STR r2, [r4, #PointerBuffLA] Push "r0-r2" MOV r1, #0 STRB r1, [r4, #PointerWidth] ; zero width STRB r1, [r4, #PointerHeight] ; zero height (no shape) SUB sp, sp, #3*4 ; room for one entry of OS_Memory page block MOV r1, sp STR r2, [r1, #4] ; provide logical address MOV r2, #1 MOV r0, #&2200 ; convert logical to physical address SWI XOS_Memory LDR r2, [r1, #8] ; read physical address STR r2, [r4, #PointerBuffPA] ADD sp, sp, #3*4 Pull "r0-r2" ADD r4, r4, #PointerBlkSize ADD r2, r2, #&100 ADD r0, r0, #4 SUBS r3, r3, #1 BNE %BT02 ; palette space (256 normal + 1 border + 3 pointer = 260), and allowing for Gamma Correction ; this space is: blank palette, 260 words ; logical and physical copies of both flash states, 260*4 words ; 3 lookup tables for r,g,b mapping, 3*256 bytes ; LDR r3, =Pal_Blocksize BL ClaimSysHeapNode ; this had better succeed! ASSERT :INDEX:Pal_Blank = 0 STR r2, [WsPtr, #BlankPalAddr] ADD r3, r2, #Pal_LogFirst STR r3, [WsPtr, #FirPalAddr] ADD r3, r2, #Pal_LogSecond STR r3, [WsPtr, #SecPalAddr] ; initialise blank palette to all solid black ; zero-init the other palettes too, to make sure log & phys palettes are ; consistent MOV r3, #0 LDR r4, =PalEntries*5 04 STR r3, [r2], #4 SUBS r4, r4, #1 BNE %BT04 ASSERT Pal_RTable = Pal_Blank + PalEntries*5*4 ; initialise red, green and blue transfer function tables to 1-1 mapping MOV r0, #0 05 STRB r0, [r2, #Pal_STable-Pal_RTable] ; store in supremacy table STRB r0, [r2, #Pal_BTable-Pal_RTable] ; store in blue table STRB r0, [r2, #Pal_GTable-Pal_RTable] ; store in green table STRB r0, [r2], #1 ; store in red table, and advance ADD r0, r0, #1 CMP r0, #256 BCC %BT05 10 BL SpriteInit LDR R14, [WsPtr, #ScreenEndAddr] LDR R0, [WsPtr, #TotalScreenSize] RSB R0, R0, R14 STR R0, [WsPtr, #DisplayStart] BL SetDisplayScreenStart STR R0, [WsPtr, #ScreenStart] STR R0, [WsPtr, #CursorAddr] STR R0, [WsPtr, #InputCursorAddr] Pull PC LTORG ; ***************************************************************************** ; ; InitialiseMode - Select mode number given by ModeNo variable ; ; Called by MOS once before initialisation, and then afterwards ; before printing "RISC OS ..." ; ; in: - ; out: r0 = corrupt, or error pointer ; All other registers preserved ; InitialiseMode ROUT ; if we don't have a video driver yet, now is a good time to check if the HAL ; provides one LDR r0, =ZeroPage+VduDriverWorkSpace+CurrentGraphicsVDriver LDR r0, [r0] CMP r0, #GraphicsVInvalid BEQ VduGrafHAL_Init ; tail-call since InitialiseMode will get called again when the HAL registers itself Entry "r1-r12" ; Refresh cached features flags before we start calling this new driver MOV r4, r0, LSL #24 ORR R4, R4, #GraphicsV_DisplayFeatures BL CallGraphicsV VDWS WsPtr STR r0, [WsPtr, #GraphicsVFeatures] ; Update screen memory information ASSERT GVDisplayFeature_SeparateFramestore < 256 ANDS r1, r0, #GVDisplayFeature_SeparateFramestore STRB r1, [WsPtr, #ExternalFramestore] BNE %FT20 ; Screen DA is in use LDR r0, =ZeroPage LDR r0, [r0, #VideoPhysAddr] STR r0, [WsPtr, #TrueVideoPhysAddr] ; Point TrueVideoPhysAddr at the base of screen DA MOV r0, #2 SWI XOS_ReadDynamicArea MOVVS r1, #0 ; shouldn't happen, but set a safe size just in case STR r1, [WsPtr, #TotalScreenSize] ; Ensure TotalScreenSize consistent with DA size ; Reinitialise a few more variables which are used by the screen DA handler ADD r1, r0, r1 STR r1, [WsPtr, #ScreenEndAddr] STR r0, [WsPtr, #DisplayStart] BL SetDisplayScreenStart STR r0, [WsPtr, #ScreenStart] B %FT30 20 ; Driver manages memory itself TST r0, #GVDisplayFeature_VariableFramestore BNE %FT30 ; Framestore changes with mode, we can't read its info here ; Framestore is fixed, get its info and remember it (ModeChangeSub currently relies on this for VRAM limit checking) LDR r0, =ZeroPage+VduDriverWorkSpace+CurrentGraphicsVDriver LDR r0, [r0] MOV r4, r0, LSL #24 ORR r4, r4, #GraphicsV_FramestoreAddress BL CallGraphicsV CMP r4, #0 MOVNE r1, #0 ; If call wasn't claimed, claim 0 screen memory. Mode change will then fail with out of memory error, which is about the best we can do. STR r0, [WsPtr, #TrueVideoPhysAddr] STR r1, [WsPtr, #TotalScreenSize] 30 MOV r0, #1 ; no need to check for soft reset, SWI XOS_ReadSysInfo ; always use configured value MOV r1, r0 MOV r0, #ScreenModeReason_SelectMode SWI XOS_ScreenMode BVC %FT40 MOV r0, #114 ; failed, so get rid of any shadow MOV r1, #1 SWI XOS_Byte SWI XOS_WriteI+22 SWIVC XOS_WriteI+0 ; and if we can't get mode 0, we're really fooked!!! 40 BLVC UpdateAllPalette ; make sure GV driver is aware of the pointer colours (this will also redundantly set the main palette + border colour, but re-using this routine as-is avoids duplicating a bunch of code) EXIT ; ; ;------------------------------------------------------------------------------ ; ; Vdu - Main VDU driver entry point ; === Queue up bytes and dispatch via JVec ; ; in: R0 = character to be printed ; ; out: C=1 <=> send character to printer if enabled ; Vdu ROUT LDR R11, =ZeroPage ; NB used later in Vdu07 as well LDRB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] MOVS R9, R10, LSL #24 ; move up to top byte (for sign extend) BEQ Vdu07 ; not queueing, then start Vdu sequence ; *****Comment made by DJS: Changing this to fall through if not queueing ; and branch if queueing might be a good idea - it would speed up all ; printable characters and simple cursor movements. LDR R8, [WsPtr, #QOffset] STRB R0, [R8, R9, ASR #24] ; add byte to queue ADD R10, R10, #1 ; move on pointer STRB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] CMP R10, #&100 ; finished sequence ? MOVCC PC, R14 ; no, then return (no printing) Push "R0, R14" BL PreWrchCursor ; exits with R6 = CursorFlags Pull "R0" 05 ADR R14, VduPrintExit Push R14 BL Vdu05 BL PostWrchCursor CLC ; also clears V ADD SP,SP,#4 Pull PC VduPrintExit ; exit used if print required BL PostWrchCursor SEC ; also clears V Pull PC ; ***************************************************************************** Vdu05 ROUT TST R6, #VduDisabled ; VDU enabled ? LDREQ PC, [WsPtr, #JVec] ; yes, then do it (no printing) ; Queue sequence has just completed, but VDU is disabled ; Only interesting case is VDU 1 (SOH), which must still print ; the character if the printer is enabled LDR R10, [WsPtr, #JVec] ADR R11, SOH TEQ R10, R11 ; JVec -> SOH ? MOVNE PC, R14 ; no, then return (no printing) SOH LDR R1, [WsPtr, #VduStatus] ; in VDU 2 mode ? TST R1, #Vdu2Mode MOVEQ PC, R14 ; no, then return Push R14 BL MOSDoPrint Pull PC, VC ; good exit, so return Pull R14 ; bad exit, return with error B VduBadExit ; ***************************************************************************** Vdu07 ROUT AND R0, R0, #&FF ; Only look at bottom byte! CMP R0,#127 ;If DELETE, change R0 to 32 and MOVEQ R0,#32 ; drop through to control char code CMPNE R0,#31 ;Otherwise, branch to printable char BHI Vdu20 ; code if not a control char ; *****Further desirable change: Make printable characters fall through, ; control characters take the branch - speeding up printable characters is ; important! ADR R10, VduJTb ; Address of beginning of jump table LDR R9, [R10, R0, LSL #2] ; Get routine address from VduJTB STR R9, [WsPtr, #JVec] ; save address ADD R10, R10, #(VduQTb-VduJTb) LDRB R9, [R10, R0] ; Pick up QQ + length of queue RSBS R10, R9, #QQ ; -(length of queue) & test if none STRNEB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] ; yes, then set up Osbyte variable ADDNE R9, R9, WsPtr STRNE R9, [WsPtr, #QOffset] ; and QOffset MOVNE PC, R14 Push "R0,R14" BL PreWrchCursor ; exits with R6 = CursorFlags Pull "R0" 10 ADR R14, VduPrintExit Push R14 BL Vdu10 BL PostWrchCursor CLC ; also clears V ADD SP, SP, #4 Pull PC ; ; This is the only byte of a single byte Vdu sequence ; ; R6 = CursorFlags ; R11 = 0 (used to index VDUqueueItems) ; Vdu10 ROUT TST R6, #CursorsSplit ; are we cursor editing ? BNE Vdu15 Vdu10Continue ; TMD 31/7/87; bug fixed here - chars 8 to 13 should still go to printer if ; enabled, even if VDU is disabled CMP R0, #8 ; is char in range 8-13 ? RSBCSS R1, R0, #13 ; if so then we want to print it LDRCS R1, [WsPtr, #VduStatus] MOVCSS R1, R1, LSR #(Vdu2ModeBitPosn +1) ; providing printer enabled Pull R14, CS ; so pull old R14 TST R6, #VduDisabled ; are we disabled LDREQ PC, [WsPtr, #JVec] ; enabled, so go get em floyd ! TEQ R0, #6 ; disabled, so is it ACK (enable VDU) BICEQ R6, R6, #VduDisabled STREQ R6, [WsPtr, #CursorFlags] NUL ;Does nothing ESC ;Does nothing MOV PC, R14 ; return anyway ; ***************************************************************************** Vdu15 TEQ R0, #13 ; and is it a carriage return ? BNE Vdu10Continue Push "R0, R14" BIC R6, R6, #CursorsSplit ; then stop cursor editing STR R6, [WsPtr, #CursorFlags] MOV R1, #1 ; restore old Reg10Copy BL CursorOnOff Pull "R0, R14" B Vdu10Continue ; ***************************************************************************** Vdu20 ROUT Push "R0,R14" BL PreWrchCursor ; exits with R6 = CursorFlags Pull "R0" 05 ADR R14, VduPrintExit Push R14 BL TimWrch BL PostWrchCursor CLC ; also clears V ADD SP, SP, #4 Pull PC ; ***************************************************************************** VduJTb ; Table of addresses & NUL ; Does nothing & SOH ; Next char to printer only & STX ; Enable printer & ETX ; Disable printer & EOT ; Write text at text cursor & ENQ ; Write text at graphics cursor & NUL ; Enable VDU drivers & BEL ; Beep & BS ; Cursor left & HT ; Cursor right & VduLF ; Cursor down & VT ; Cursor up & FF ; Clear text area (CLS) & VduCR ; Carriage return & SO ; Page mode on & SI ; Page mode off & DLE ; Clear graphics area (CLG) & DC1 ; Define text colour (COLOUR) & DC2 ; Define graphics colour and action (GCOL) & DC3 ; Define logical colour & VDU20 ; Restore default logical colours & NAK ; Disable VDU drivers & SYN ; Select screen mode (MODE) & ETB ; Reprogram display character (VDU23,...) & CAN ; Define graphics window & EM ; (PLOT k,x,x,y,y) & DefaultWindows ; Restore default windows & ESC ; Does nothing & FS ; Define text window & GS ; Define graphics origin & RS ; Home cursor to "top left" & US ; Move text cursor (TAB x,y) & Delete ; Delete character (127) ASSERT QQ+9 < 256 VduQTb ; QQ + length of queue for each of the above DCB QQ+0, QQ+1, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0 DCB QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0 DCB QQ+0, QQ+1, QQ+2, QQ+5, QQ+0, QQ+0, QQ+1, QQ+9 DCB QQ+8, QQ+5, QQ+0, QQ+0, QQ+4, QQ+4, QQ+0, QQ+2 DCB QQ+0 ; (delete) ALIGN ; ***************************************************************************** WrchNbitTab & Wrch1bit-WrchNbitTab & Wrch2bit-WrchNbitTab & Wrch4bit-WrchNbitTab & Wrch8bit-WrchNbitTab & Wrch16bit-WrchNbitTab & Wrch32bit-WrchNbitTab WrchNbitDoubleTab & Wrch1bitDouble-WrchNbitDoubleTab CursorNbitTab & Cursor1bit-CursorNbitTab & Cursor2bit-CursorNbitTab & Cursor4bit-CursorNbitTab & Cursor8bit-CursorNbitTab & Cursor16bit-CursorNbitTab & Cursor32bit-CursorNbitTab & Cursor64bit-CursorNbitTab ; ***************************************************************************** ; ; SYN - Perform MODE change ; ; External routine ; ; in: Vdu queue contains mode number ; SYN ROUT ; Select screen mode (MODE) Push lr LDRB R2, [WsPtr, #QQ] ; Read mode number from queue BL ModeChangeSub Pull lr MOVVC pc, lr ; if no error, exit to Vdu ; (which calls PostWrchCursor) ; else drop thru into ... VduBadExit ; jumped to if an error in VDU code Push R0 ; save error pointer BL PostWrchCursor LDR R0, [R13], #8 ; get error pointer, junk next entry SETV Pull PC ; in: R2 = mode number / selector block ModeChangeSub ROUT ; Wrap the bulk of ModeChangeSub in some code that will free any new ; TTX workspace pointer if the mode change fails (or the pointer isn't ; claimed for any other reason) Entry MOV r0, #0 STR r0, [WsPtr, #TTXNewWorkspace] BL %FT01 LDR r2, [WsPtr, #TTXNewWorkspace] TEQ r2, #0 EXIT EQ MRS r3, CPSR MOV r4, r0 BL FreeSysHeapNode MSR CPSR_c, r3 MOV r0, r4 EXIT 01 Push lr MOV R1, #Service_PreModeChange IssueService TEQ R1, #0 ; was service claimed ? BNE %FT03 ; no, so continue CMP R0, #0 ; service claimed; generate error ? Pull PC, EQ ; no, just exit (V=0 from CMP) B %FT07 ; yes, then generate error 03 MOV R0, R2 ; put mode (possibly changed) in R0 MOV R2, R0, LSR #7 ; R2 = 0/1 if bit 7 of mode clear/set CMP r2, #2 ; if mode number >= 256 then mode selector MOVCS r2, #0 ; so no shadow LDROSB R1, Shadow TEQ R1, #0 ; if shadow 0 then force shadow mode MOVEQ R2, #1 BL FindOKMode ; out: R1 = mode we are going to use BVS %FT07 TEQ R0, R1 ; if substitute mode MOVNE R2, #0 ; then don't use shadow CMP r1, #&100 BICCC r10, r1, #&80 MOVCS r10, r1 MOV R11, R10 BL PushModeInfo BVS %FT07 ; [probably duff mode selector] ; Allocate new teletext workspace if required LDR R0, [R13, #wkModeFlags] TST R0, #ModeFlag_Teletext MOVNE R0, R13 BLNE TeletextAlloc BVS %FT07 Push R1 ; save proper mode ; Vet the mode - both to make sure the driver really is happy with it, ; and to cope with drivers which want to switch to different framebuffer ; types ADD R0, R13, #wkwordsize+4 Push "R2" BL DoFullVetMode Pull "R2" SUB R13, R13, #12 BEQ %FT041 ; not supported, complain TST R0, #GVVetMode2_ExtraBytes_Invalid BNE %FT041 ; Service_ModeExtension should have made sure ExtraBytes was valid ; R0, R3, R5 may contain important info STMIA R13, {R0, R3, R5} AND R0, R0, #GVVetMode2_ResultMask CMP R0, #GVVetMode2_Result_UnkFramestore BEQ %FT08 ; Driver doesn't know where mode is going to be, so we can't vet the memory requirement LDR R11, [R13, #16 + wkScreenSize] ; get screen size for this mode MOV R11, R11, LSL R2 ; total amount needed CMP R0, #GVVetMode2_Result_SysFramestore BNE %FT045 MOV R0, #2 SWI XOS_ReadDynamicArea SUBS R1, R11, R1 BLE %FT08 ; try to extend the amount of screen memory ! 0, "Need to fix ModeChangeSub to not leave CursorAddr, etc. pointing to unmapped pages during DA resize. Causes bad stuff should an abort occur/screen output be attempted!" ; Note that even enlarging the DA can leave the pointers in a bad state, due to the way the screen DA handler shuffles down/unmaps the lower mapping of VRAM before the higher copy is enlarged MOV R0, #2 ; expand screen memory SWI XOS_ChangeDynamicArea BVC %FT08 06 ADR R0, ErrorBlock_BadMODE 065 ADD R13, R13, #PushedInfoSize + 4*4 ; junk stacked info + mode no + vetmode2 info [ International BL TranslateError ] 07 SETV ; indicate error Pull PC 041 ADRL R0, ErrorBlock_ModeNotAvailable B %BT065 045 CMP R11, R5 BHI %BT06 ; ext. framestore not big enough ; valid mode and enough memory 08 LDR r0, [sp, #12] ; restore mode we are using CMP r0, #&100 ; if not mode selector BICCC r0, r0, #&80 ; then knock off shadow bit BCC %FT12 ; it's a mode selector, so copy it to our static mode selector block LDR r1, [WsPtr, #KernelModeSelector] ; point at block SUBS r3, r0, r1 ; if r0 -> 1st mode block position TEQNE r3, #4 ; or r0 -> 2nd mode block position MOVEQ r1, r0 ; then use it in place BEQ %FT09 LDR r3, [WsPtr, #DisplayModeNo] ; else check if current mode is a mode selector SUB r3, r3, r1 ; r3 = offset from start of block CMP r3, #8 ; if 0 or 4 EORCC r3, r3, #4 ; then make 4 or 0 (ie toggle between them) ADDCC r1, r1, r3 ; and add on base ASSERT (ModeSelector_ModeVars+4) :AND: 7 = 0 09 MOV r3, #0 10 LDR r6, [r0, r3] ; copy 1st word - after fixed bit this will be previous var value STR r6, [r1, r3] ADD r3, r3, #4 LDR r6, [r0, r3] ; copy 2nd word - after fixed bit this will be next var index STR r6, [r1, r3] ADD r3, r3, #4 CMP r3, #ModeSelector_ModeVars + 4 ; only exit if we've done the essential bit CMPCS r6, #-1 ; AND we've had a -1 as the var index (NOT as the value) CMPCC r3, #ModeSelector_MaxSize ; OR we've gone off the end of our block BCC %BT10 ; [we haven't, so loop] CMP r3, #ModeSelector_MaxSize ; if we did go off the end MOVCS r6, #-1 STRCS r6, [r1, #ModeSelector_MaxSize-4] ; then terminate it properly MOV r0, r1 ; point at static block 12 STR R0, [WsPtr, #DisplayModeNo] ; store the new display mode ; now issue Service_ModeChanging MOV R1, #Service_ModeChanging BL IssueModeService ; R13 -> mode variables 13 LDR R3, [R13, #16+wkScreenSize] STR R3, [WsPtr, #ScreenSize] ; store screensize BEFORE calling ; ConvertBankToAddress (was a bug!) Push "r0-r6" ; If driver handles memory allocation, must change mode before asking for memory ; (the case where we change mode after setting up the memory is only retained for backwards-compatibility, just in case something special like Aemulor is relying on it) LDR r0, [sp, #7*4] AND r0, r0, #GVVetMode2_ResultMask CMP r0, #GVVetMode2_Result_SysFramestore BEQ %FT581 CMP r0, #GVVetMode2_Result_ExtFramestore LDREQ r0, [sp, #8*4] LDREQ r1, [sp, #9*4] BEQ %FT580 ; Must be UnkFramestore ADD R0, R13, #wkwordsize+7*4+16 ; R0 -> VIDCList3 BL HardwareModeChange LDR r4, [WsPtr, #CurrentGraphicsVDriver] MOV r4, r4, LSL #24 ORR r4, r4, #GraphicsV_FramestoreAddress BL CallGraphicsV 580 ; for mapping in, round start address down and size up to megabyte boundaries ; r0 = physical start, r1= size ; so frame buffer is wholly contained within the mapped in area MOV r3, #1<<20 ; 1 Megabyte SUB r3, r3, #1 ; convert to mask MOV r4, r1 ; remember what was asked for AND r5, r0, r3 ; and offset from megabyte base TST r1, r3 ; non integer megabyte? BIC r2, r1, r3 ; (clear the bits) ADDNE r2, r2, #1<<20 ; yes.. up to next megabyte BIC r1, r0, r3 ; ensure megabyte boundary at start MOV r0, #OSMemReason_MapIOPermanent ; map in permanently ORR r0, r0, #1:SHL:8 ; buffered, uncached ORR r0, r0, #1:SHL:17 ; access permission specified (= usermode access) LDR lr, [WsPtr, #GraphicsVFeatures] TST lr, #GVDisplayFeature_HardwareScroll ORRNE r0, r0, #1:SHL:16 ; doubly map for hardware scrolling (n.b. assuming VRAM is megabtye aligned) SWI XOS_Memory BVS %FT581 ADD r0, r1, r5 ; reconstruct base phys address STR r0, [WsPtr, #TrueVideoPhysAddr] ; and update our copy STR r4, [WsPtr, #TotalScreenSize] ; what we asked for ADD r3, r3, r4 ; compute end ADD r3, r3, r5 ; and allow offset dfrom start STR r3, [WsPtr, #ScreenEndAddr] ; actual screen end MOV r14, #1 B %FT582 581 LDR r0, =ZeroPage LDR r0, [r0, #VideoPhysAddr] STR r0, [WsPtr, #TrueVideoPhysAddr] ; Point TrueVideoPhysAddr at the base of screen DA MOV r0, #2 SWI XOS_ReadDynamicArea STRVC r1, [WsPtr, #TotalScreenSize] ADDVC r0, r0, r1 STRVC r0, [WsPtr, #ScreenEndAddr] MOV r14, #0 582 Pull "r0-r6" STRB r14, [WsPtr, #ExternalFramestore] TEQ R2, #0 ; Shadowing or not ? LDR R3, [WsPtr, #VduStatus] BICEQ R3, R3, #Shadowing ORRNE R3, R3, #Shadowing STR R3, [WsPtr, #VduStatus] STRB R2, [WsPtr, #ScreenMemoryClaimed] ; only allow ADFS to claim ; if non-shadow (simplifies things!) BL ConvertBankToAddress ; R3 := default start for this bank STR R3, [WsPtr, #DriverBankAddr] STR R3, [WsPtr, #DisplayBankAddr] LDR R6, =ZeroPage ASSERT (ZeroPage :AND: 255) = 0 STRB R6, [R6, #OsbyteVars + :INDEX:MemDriver] ; indicate default STRB R6, [R6, #OsbyteVars + :INDEX:MemDisplay] ; for both of these LDR R6, [R13, #16+wkModeFlags] STR R6, [WsPtr, #DisplayModeFlags] ; initialise any values which SwitchOutput refers to LDR R4, [R13, #16+wkLineLength] STR R4, [WsPtr, #DisplayLineLength] ; now set up other mode variables by calling SwitchOutput ADD R3, WsPtr, #VduSaveArea+InitFlag MOV R2, #0 STR R2, [R3] ; indicate uninitialised TST R6, #ModeFlag_Teletext MOVNE R3, #0 ; if teletext, then no save area MOVEQ R3, #1 ; else MOS's save area MOV R1, #0 ; just in case MOV R0, #SpriteReason_SwitchOutputToSprite SWI XOS_SpriteOp ; now create other variables from simple ones LDR R3, [WsPtr, #NColour] STR R3, [WsPtr, #DisplayNColour] ASSERT YWindLimit = XWindLimit +4 ASSERT DisplayYWindLimit = DisplayXWindLimit +4 ADD R0, WsPtr, #XWindLimit LDMIA R0, {R3, R4} ADD R0, WsPtr, #DisplayXWindLimit STMIA R0, {R3, R4} ASSERT YEigFactor = XEigFactor +4 ASSERT DisplayYEigFactor = DisplayXEigFactor +4 ADD R0, WsPtr, #XEigFactor LDMIA R0, {R3, R4} ADD R0, WsPtr, #DisplayXEigFactor STMIA R0, {R3, R4} ASSERT Log2BPP = Log2BPC +4 ADD R0, WsPtr, #Log2BPC LDMIA R0, {R0, R1} ; R0 = Log2BPC; R1 = Log2BPP STRB R1, [WsPtr, #DisplayLog2BPP] SUB R3, R3, R0 ; adjust XEig for double pixels ADD R3, R3, R1 STRB R3, [WsPtr, #PointerXEigFactor] LDR R3, [R13, #16+wkModeFlags] STR R3, [WsPtr, #ModeFlags] ; finished doing other variables ; tell hardware to change mode, unless already done LDR r0, [r13], #16 AND r0, r0, #GVVetMode2_ResultMask CMP r0, #GVVetMode2_Result_UnkFramestore ADDNE R0, R13, #wkwordsize ; R0 -> VIDCList3 BLNE HardwareModeChange ADD R13, R13, #PushedInfoSize ; junk stacked data ; for backward compatibility, show that video DMA is enabled in ; MEMC soft copy (DON'T call OS_UpdateMEMC, which would also ; make redundant call to HAL) ; SavePSR R2 LDR R0, =ZeroPage WritePSRc SVC_mode+I_bit+F_bit, R14 LDR R1, [R0, #MEMC_CR_SoftCopy] ORR R1, R1, #(1 :SHL: 10) STR R1, [R0, #MEMC_CR_SoftCopy] RestPSR R2 BL SetVendDefault LDR R1, [WsPtr, #ScreenEndAddr] ; need to reload cos corrupt LDR R2, [WsPtr, #TotalScreenSize] SUB R0, R1, R2 ; R0 = Vstart BL SetVstart MOV R0, #0 STRB R0, [WsPtr, #PointerShapeNumber] STR R0, [WsPtr, #TeletextOffset] STR R0, [WsPtr, #CursorStack] ; restore cursor on a mode BL PalInit ; set default palette BL UnblankScreen BL SetMouseRectangle BL FF MOV R1, #Service_ModeChange BL IssueModeService CLRV ; indicate no error Pull PC ; return to caller ; ***************************************************************************** ; ; HardwareModeChange - Tell the video driver to change the mode ; ; in: R0 = VIDC list ; ; out: All regs preserved ; HardwareModeChange Push "R0-R4, LR" ;remember pixel rate (kHz) and border settings from VIDCList3 ; LDR R2, [R0, #VIDCList3_PixelRate] STR R2, [WsPtr, #PixelRate] LDR R2, [R0, #VIDCList3_HorizLeftBorder] STR R2, [WsPtr, #BorderL] LDR R2, [R0, #VIDCList3_VertiBottomBorder] STR R2, [WsPtr, #BorderB] LDR R2, [R0, #VIDCList3_HorizRightBorder] STR R2, [WsPtr, #BorderR] LDR R2, [R0, #VIDCList3_VertiTopBorder] STR R2, [WsPtr, #BorderT] ;remember DPMSState (if specified) from VIDCList3 ; MOV R2, #0 ; DPMSState = 0 if not specified in list ADD R1, R0, #VIDCList3_ControlList 20 LDR R3, [R1], #8 ; loop over the control parameter list CMP R3, #-1 BEQ %FT30 ; didn't find the DPMSState entry TEQ R3, #ControlList_DPMSState BNE %BT20 ; next control parameter LDR R2, [R1, #-4] ; read DPMSState value AND R2, R2, #3 ; only bits 0,1 valid 30 STRB R2, [WsPtr, #ScreenBlankDPMSState] ;kernel/HAL split - call the HAL to program video controller for mode, ; LDR R4, [WsPtr, #CurrentGraphicsVDriver] MOV R4, R4, LSL #24 ORR R4, R4, #GraphicsV_SetMode BL CallGraphicsV LDR R4, [WsPtr, #CurrentGraphicsVDriver] MOV R4, R4, LSL #24 ORR R4, R4, #GraphicsV_DisplayFeatures BL CallGraphicsV STR R0, [WsPtr, #GraphicsVFeatures] ; refresh cached features just in case something's happened to change them BL UpdateFalseVsync ; claim/release memory needed for software pointer TST R0, #GVDisplayFeature_HardwarePointer LDR R2, [WsPtr, #SWP_Under] BEQ %FT40 TEQ R2, #0 MOVNE R0, #0 STRNE R0, [WsPtr, #SWP_Under] MOVNE R0, #ModHandReason_Free SWINE XOS_Module B %FT50 40 TEQ R2, #0 BNE %FT50 ; Claim maximum amount needed MOV R0, #ModHandReason_Claim MOV R3, #32*32*4 SWI XOS_Module STRVC R2, [WsPtr, #SWP_Under] 50 ; Release mutex and reset state ; Note that we do this even if the pointer isn't needed, to ensure we ; don't get confused about its state MOV R2, #0 STR R2, [WsPtr, #SWP_Pos] STRB R2, [WsPtr, #SWP_Mutex] Pull "R0-R4, PC" MakeErrorBlock BadMODE LTORG ; The following symbols, apart from being used in NColourTable, ; are also used in constructing mode selectors for mode numbers in VduModes NColour_0 * 1 NColour_1 * 3 NColour_2 * 15 NColour_3 * 63 NColour_4 * &FFFF NColour_5 * &FFFFFFFF ; ***************************************************************************** ; ; IssueModeService - Issue service (either ModeChanging or ModeChange) ; ; in: R1 = service code ; ; out: R1 corrupted ; IssueModeService Entry "r2,r3" BL ReadMonitorType LDR r2, [WsPtr, #DisplayModeNo] IssueService EXIT ; ***************************************************************************** ; ; PushModeInfo - Push appropriate mode table and video controller params ; onto stack, having generated it by possibly issuing service ; ; in: R10 = mode to try for ; R11 = mode to use if service not claimed (and R10 is mode number) ; R10 and R11 should have bit 7 CLEAR (if mode numbers) ; ; out: If r10 is an invalid mode selector or invalid new format sprite word then ; V=1 ; r0 -> error ; stack flat (no pushed info) ; else ; V=0 ; Stack holds a mode table (size wkwordsize) and VIDCList ; type 3 (size VIDCList3Size) (total size PushedInfoSize) ; endif ; All other registers preserved ; PushModeInfoAnyMonitor ROUT SUB sp, sp, #PushedInfoSize Push "r2-r4,r7-r11, lr" MOV r3, #-1 MOV r7, #-1 ; indicate no VIDC stuff necessary CMP r10, #&100 ; is it a mode selector BCS PushModeInfoCommonNoService BranchIfKnownMode r10, PushModeInfoCommonNoService B PushModeInfoCommon PushModeInfo ROUT SUB sp, sp, #PushedInfoSize Push "r2-r4,r7-r11, lr" MOV r7, #0 ; indicate VIDC stuff IS necessary BL ReadMonitorType PushModeInfoCommon MOV r2, r10 ; r2 = original mode BL OfferModeExtension BEQ %FT30 ; [service claimed] CMP r2, #&100 ; service not claimed - check if mode selector MOVCC r10, r11 ; unrecognised mode number, so use substitute BCC PushModeInfoCommonNoService 25 ; service not claimed and it's a mode selector - return error "Screen mode not available" ADR r0, ErrorBlock_ModeNotAvailable 26 [ International BL TranslateError ] B %FT40 MakeErrorBlock ModeNotAvailable 30 TEQ r4, #0 ; if r4 returned zero, then a mode selector was used ; either initially or after translation from mode number BEQ %FT35 ; so no ws list LDR r2, [r4, #4]! ; else if claimed, then find ws base mode CMP r2, #&100 ; if ws base mode is a mode selector, it's invalid ANDCC r2, r2, #&7F ; else knock off shadow bit BCC %FT35 MOV r10, r11 ; invalid ws base mode, so pretend service not responded to ; and drop thru to PushModeInfoCommonNoService PushModeInfoCommonNoService MOV r2, r10 ; else use provided mode MOV r3, #0 MOV r4, #0 35 ADD r9, sp, #9*4 ; adjust for pushed registers CMP r2, #&100 BCC %FT45 BL GenerateModeSelectorVars ; also copes with new sprite mode word BVC %FT55 ; we got an error 40 SETV Pull "r2-r4,r7-r11,lr" ; restore registers ADD sp, sp, #PushedInfoSize ; junk stack frame MOV pc, lr ; exit VS, r0 -> error 45 ADRL r14, Vwstab LDR r10, [r14, r2, LSL #2] ADD r14, r14, r10 ; r14 -> mode table MOV r10, #wkwordsize-4 50 LDR r2, [r14, r10] STR r2, [r9, r10] SUBS r10, r10, #4 BCS %BT50 ; now change any variables specified in workspace block or mode selector overrides 55 TEQ r4, #0 ; if service was claimed ADDNE r4, r4, #4 ; then skip ws base mode BLNE ProcessModeVarPairs ; hopefully, R7 is still set from up there to be NZ if no VIDC stuff necessary CMP r7, #0 Pull "r2-r4,r7-r11, pc", NE ; if no VIDC stuff required, exit (NB V=0 from CMP) ; mjs Kernel/HAL split ; pushed video controller info is now hardware independent, it is a VIDCList type 3 TEQ R3, #0 ; if no module claimed service MOVEQ R2, R11 ; then use provided mode BEQ %FT62 59 ADD R14, R9, #wkwordsize ; R14 -> space for VIDCList3 ASSERT VIDCList3BaseSize = 64 LDMIA R3!, {R2,R4,R7-R11} ; 28 bytes STMIA R14!, {R2,R4,R7-R11} LDMIA R3!, {R2,R4,R7-R11} ; 56 bytes STMIA R14!, {R2,R4,R7-R11} LDMIA R3!, {R2,R4} ; 64 bytes STMIA R14!, {R2,R4} MOV R10, #VIDCList3Size-(VIDCList3BaseSize+4) ; this much space left for control list items (excluding terminator) 60 LDR R8, [R3], #4 SUBS R10, R10, #8 BLT %FT65 ; List too long, throw an error CMP R8, #-1 LDRNE R9, [R3], #4 STMNEIA R14!, {R8-R9} BNE %BT60 STR R8, [R14] ; Recalculate LineLength, ScreenSize based on the contents of the VIDC ; list ADD R9, SP, #9*4 ; adjust for pushed registers LDR R10, [R9, #wkwordsize + VIDCList3_SyncPol] AND R10, R10, #SyncPol_Interlace :OR: SyncPol_InterlaceFields TEQ R10, #SyncPol_Interlace :OR: SyncPol_InterlaceFields MOVEQ R10, #1 ; true interlace with 2 interleaved fields MOVNE R10, #0 LDR R2, [R9, #wkwordsize + VIDCList3_PixelDepth] LDR R4, [R9, #wkwordsize + VIDCList3_HorizDisplaySize] MOV R4, R4, LSL R2 ADD R4, R4, #7 MOV R4, R4, LSR #3 ADD R14, R9, #wkwordsize + VIDCList3_ControlList 61 LDMIA R14!, {R7, R8} CMP R7, #ControlList_ExtraBytes ADDEQ R4, R4, R8 CMP R7, #ControlList_Terminator BNE %BT61 STR R4, [R9, #wkLineLength] LDR R2, [R9, #wkwordsize + VIDCList3_VertiDisplaySize] MOV R2, R2, LSL R10 ; Calculate height from VIDC list too (YWindLimit may have been tampered with?) MUL R2, R4, R2 LDR R4, [R9, #wkModeFlags] TST R4, #ModeFlag_Teletext MOVNE R2, R2, LSL #1 ; teletext ScreenSize is actually enough for two screens STR R2, [R9, #wkScreenSize] CMP R10, #0 ORRNE R4, R4, #ModeFlag_InterlacedMode STRNE R4, [R9, #wkModeFlags] ; Make sure interlace is flagged as such LDR R2, [WsPtr, #GraphicsVFeatures] TST R2, #GVDisplayFeature_HardwareScroll ORREQ R4, R4, #ModeFlag_HardScrollDisabled STREQ R4, [R9, #wkModeFlags] CLRV Pull "R2-R4,R7-R11, PC" ; done 62 ; arrive here if service not claimed, R2 = provided mode number ; XXX possible to exit earlier? (right after OfferModeExtension?) B %BT25 65 ADRL r0, ErrorBlock_BuffOverflow B %BT26 ; ***************************************************************************** ; ; GenerateModeSelectorVars - Work out mode variables from mode selector ; or new format sprite mode word ; ; Note: the algorithms used to generate these variables are duplicated in ; s.vdu.vduswis in the OS_ReadModeVariable code. ; in: r2 = new format sprite word or pointer to mode selector ; r9 -> stack frame to store vars in ; ; out: If valid then ; V=0 ; r0 preserved ; else ; V=1 ; r0 -> error ; endif ; All other registers preserved ; GenerateModeSelectorVars Entry "r0,r1,r3-r8,r10-r12" ASSERT ModeSelector_Flags = 0 ASSERT ModeSelector_XRes = 4 ASSERT ModeSelector_YRes = 8 ASSERT ModeSelector_PixelDepth = 12 TST r2, #1 ; is it a new format sprite mode word? BNE %FT10 ; [yes, so skip] MOV r0, r2 BL ValidateModeSelector BVS %FT95 ; invalid - return error LDMIB r2, {r4-r6} ; r4 = xres; r5 = yres; r6 = pixdepth STR r6, [r9, #wkLog2BPC] ; log2bpc = log2bpp = pixdepth STR r6, [r9, #wkLog2BPP] ADR lr, NColourTable LDR lr, [lr, r6, LSL #2] ; load NColour value STR lr, [r9, #wkNColour] MOV lr, #0 STR lr, [r9, #wkYShftFactor] ; yshftfactor = 0 (obsolete) STR lr, [r9, #wkModeFlags] ; modeflags = 0 MOV lr, #1 STR lr, [r9, #wkXEigFactor] ; xeig = 1 CMP r5, r4, LSR #1 ; if yres < xres/2 MOVCC r7, #2 ; then yeig = 2 MOVCS r7, #1 ; else yeig = 1 STR r7, [r9, #wkYEigFactor] RSB r7, lr, r4, LSR #3 ; scrrcol = (xres >> 3) -1 STR r7, [r9, #wkScrRCol] RSB r7, lr, r5, LSR #3 ; scrbrow = (yres >> 3) -1 STR r7, [r9, #wkScrBRow] SUB r7, r4, #1 STR r7, [r9, #wkXWindLimit] ; xwindlimit = xres-1 SUB r7, r5, #1 STR r7, [r9, #wkYWindLimit] ; ywindlimit = yres-1 MOV r7, r4, LSL r6 ; r7 = xres << pixdepth MOV lr, r7, LSR #3 STR lr, [r9, #wkLineLength] ; linelen = (xres << pixdepth) >> 3 MUL r7, r5, r7 ; r7 = (xres * yres) << pixdepth MOV lr, r7, LSR #3 STR lr, [r9, #wkScreenSize] ; screensize = ((xres * yres) << pixdepth) >> 3 ADD r4, r2, #ModeSelector_ModeVars ; now do pairs of mode variables BL ProcessModeVarPairs ; Fixup teletext modes LDR r0, [r9, #wkModeFlags] TST r0, #ModeFlag_Teletext BEQ %FT09 ; Force the mode flags to be correct for our implementation [ HiResTTX ORR r0, r0, #ModeFlag_NonGraphic+ModeFlag_GapMode+ModeFlag_DoubleVertical | BIC r0, r0, #ModeFlag_DoubleVertical ORR r0, r0, #ModeFlag_NonGraphic+ModeFlag_GapMode ] STR r0, [r9, #wkModeFlags] ; Ensure colour depth is acceptable LDR r0, [r9, #wkNColour] CMP r0, #15 [ HiResTTX ADRLOL r0, ErrorBlock_BadPixelDepth BLO %FT90 CMP r0, #63 ADREQL r0, ErrorBlock_BadPixelDepth BEQ %FT90 | ADRNEL r0, ErrorBlock_BadPixelDepth BNE %FT90 ] ; Massage ScreenSize, needs to be large enough for two screen banks LDR r0, [r9, #wkScreenSize] MOV r0, r0, LSL #1 STR r0, [r9, #wkScreenSize] ; Clamp ScrRCol, ScrBRow LDR r0, [r9, #wkScrRCol] CMP r0, #254 ; TTXDoubleCounts is a byte array MOVHI r0, #254 LDR r7, [r2, #ModeSelector_XRes] MOV lr, #1 [ HiResTTX RSB r7, lr, r7, LSR #4 | RSB r7, lr, r7, LSR #3 ] CMP r0, r7 MOVHI r0, r7 STR r0, [r9, #wkScrRCol] LDR r0, [r9, #wkScrBRow] [ HiResTTX DivRem r7, r5, #20, lr, norem | DivRem r7, r5, #10, lr, norem ] CMP r0, r7 SUBHS r0, r7, #1 STR r0, [r9, #wkScrBRow] CLRV EXIT 09 ; We only have double-vertical char plotting routines for 1bpp LDR r0, [r9, #wkModeFlags] LDR r1, [r9, #wkLog2BPP] LDR r3, [r9, #wkLog2BPC] TST r0, #ModeFlag_DoubleVertical BEQ %FT091 CMP r1, #0 ; Also can't mix double-vertical with double-pixel, since that would also require another char plotting routine CMPEQ r3, #0 ADRNEL r0, ErrorBlock_BadPixelDepth BNE %FT90 091 ; We only support 2bpp BBC gap modes TST r0, #ModeFlag_BBCGapMode CMPNE r1, #1 ADRNEL r0, ErrorBlock_BadPixelDepth BNE %FT90 ; We don't support double-pixel modes higher than 16bpp (or regular modes higher than 32bpp) CMP r3, #5 ADRHIL r0, ErrorBlock_BadPixelDepth BHI %FT90 CLRV EXIT ; store info for new format sprite word in stack frame 10 MOV r0, #0 STR r0, [r9, #wkYShftFactor] ; yshftfactor = 0 STR r0, [r9, #wkModeFlags] ; modeflags = 0 AND r0, r2, #15<<27 ; get type CMP r0, #SpriteType_RISCOS5<<27 ; RISC OS 5 type? BEQ %FT50 CMP r0, #SpriteType_New64K<<27 ; 64K colour sprite? MOVEQ r0, #ModeFlag_64k STREQ r0, [r9, #wkModeFlags] ; Make a note of it MOVEQ r0, #SpriteType_New16bpp ; ... and treat as regular 16bpp MOVNE r0, r0, LSR #27 15 [ NoARMT2 MOV r1, r2, LSL #(31-13) MOV r1, r1, LSR #(31-13)+1 ; extract xdpi (bits 1..13) | UBFX r1, r2, #1, #13 ; extract xdpi (bits 1..13) ] TEQ r1, #180 ; 180 => xeig=0 MOVEQ r1, #0 BEQ %FT20 TEQ r1, #22 ; 22/23 => xeig=3 TEQNE r1, #23 MOVEQ r1, #3 BEQ %FT20 TEQ r1, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) CMPNE r1, #90 ; or 90 (EQ,CS if so) BNE %FT85 MOVCC r1, #2 ; 45 => xeig=2 MOVCS r1, #1 ; 90 => xeig=1 20 STR r1, [r9, #wkXEigFactor] [ NoARMT2 MOV r1, r2, LSL #(31-26) MOV r1, r1, LSR #(31-26)+14 ; extract ydpi (bits 14..26) | UBFX r1, r2, #14, #13 ; extract ydpi (bits 14..26) ] TEQ r1, #180 ; 180 => yeig=0 MOVEQ r1, #0 BEQ %FT21 TEQ r1, #22 ; 22/23 => yeig=3 TEQNE r1, #23 MOVEQ r1, #3 BEQ %FT21 TEQ r1, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) CMPNE r1, #90 ; or 90 (EQ,CS if so) BNE %FT85 MOVCC r1, #2 ; 45 => yeig=2 MOVCS r1, #1 ; 90 => yeig=1 21 STR r1, [r9, #wkYEigFactor] 25 CMP r0, #SpriteType_MAX ; check for legality - NB type 0 is impossible here because r2>=&100 MOVCS r0, #SpriteType_Substitute ; substitute if unknown ADRL lr, NSM_bpptable-4 LDR r0, [lr, r0, LSL #2] ; get the bpp from table ADR r1, NColourTable LDR r1, [r1, r0, LSL #2] STR r1, [r9, #wkNColour] 30 STR r0, [r9, #wkLog2BPC] STR r0, [r9, #wkLog2BPP] CLRV EXIT 50 TST r2, #&F0000 ; validate RO 5 sprite mode word TSTEQ r2, #&0000E MOVNE r0, #SpriteType_Substitute ; and try substitute if bad BNE %BT15 [ NoARMT2 MOV r1, r2, LSR #4 AND r1, r1, #3 ; extract XEigFactor (bits 4..5) | UBFX r1, r2, #4, #2 ; extract XEigFactor (bits 4..5) ] STR r1, [r9, #wkXEigFactor] [ NoARMT2 MOV r1, r2, LSR #6 AND r1, r1, #3 ; extract YEigFactor (bits 6..7) | UBFX r1, r2, #6, #2 ; extract YEigFactor (bits 6..7) ] STR r1, [r9, #wkYEigFactor] AND r1, r2, #&FF00 ; extract ModeFlags ; Validate ModeFlags. We only support RGB colourspace, so the only valid ; bits are the RGB and alpha flags TST r1, #&FF00-(ModeFlag_DataFormatSub_RGB+ModeFlag_DataFormatSub_Alpha) MOVNE r0, #SpriteType_Substitute ; try the substitute? BNE %BT15 MOV r0, r2, LSR #20 ANDS r0, r0, #127 ; extract type MOVEQ r0, #SpriteType_Substitute ; type 0 isn't valid! CMP r0, #SpriteType_New64K ORREQ r1, r1, #ModeFlag_64k MOVEQ r0, #SpriteType_New16bpp CMP r0, #SpriteType_New16bpp ; for palettised modes CMPLT r0, r1 ; flags must be zero MOVLT r0, #SpriteType_Substitute BLT %BT15 STR r1, [r9, #wkModeFlags] CMP r0, #SpriteType_New4K BNE %BT25 LDR r0, =4095 STR r0, [r9, #wkNColour] MOV r0, #4 B %BT30 85 ADR r0, ErrorBlock_Sprite_BadDPI 90 [ International BL TranslateError ] 95 STR r0, [sp] ; update saved r0 SETV ; indicate error EXIT NColourTable & NColour_0, NColour_1, NColour_2 & NColour_3, NColour_4, NColour_5 & NColour_5 ; CMYK sprite (not supported) & NColour_5 ; 24bpp sprite (not supported) & NColour_5 ; JPEG sprite (not supported) & NColour_4 ; 64K sprite & NColour_5, NColour_5, NColour_5, NColour_5, NColour_5 ; sprite types 11-15 & 4095 ; 4K sprite & NColour_5, NColour_5 ; YCbCr 422 & 420 (not supported) ASSERT . - NColourTable = (SpriteType_RO5MAX-1)*4 MakeErrorBlock BadPixelDepth MakeErrorBlock Sprite_BadDPI ; ***************************************************************************** ; ; ValidateModeSelector - Check a mode selector is valid ; ; in: r0 -> mode selector ; ; out: If OK, then ; V=0 ; All registers preserved ; else ; V=1 ; r0 -> error ; All other registers preserved ; endif ; ValidateModeSelector Entry LDR lr, [r0, #ModeSelector_Flags] AND lr, lr, #ModeSelectorFlags_FormatMask TEQ lr, #ModeSelectorFlags_ValidFormat ADRNE r0, ErrorBlock_BadMSFlags BNE %FT90 LDR lr, [r0, #ModeSelector_PixelDepth] CMP lr, #6 ADRCS r0, ErrorBlock_BadPixelDepth BCS %FT90 CLRV EXIT 90 [ International BL TranslateError | SETV ] EXIT MakeErrorBlock BadMSFlags ; ***************************************************************************** ; ; ProcessModeVarPairs - Modify stacked variable info from ; mode variable (index, value) pairs ; ; Internal routine used to do Service_ModeExtension workspace lists and ; mode selectors ; ; in: r4 -> first pair (may be none) ; r9 -> stack frame ; ; out: All registers preserved ProcessModeVarPairs Entry "r4, r8, r10" ADRL r14, RMVTab 10 LDR r10, [r4], #4 ; get next entry in ws table CMP r10, #-1 EXIT EQ ; no more to do CMP r10, #(SWIRVVTabModeEnd-SWIRVVTab) ; is it a mode variable ? BCS %BT10 ; no, then ignore LDRB r10, [r14, r10] ; load index out of RMVTab MOVS r10, r10, LSR #1 ; shift byte/word flag into carry LDR r8, [r4], #4 ; load value STRCCB r8, [r9, r10] ; either store byte STRCS r8, [r9, r10] ; or store word B %BT10 ; ***************************************************************************** ; ; OfferModeExtension - Issue mode extension service ; ; in: R2 = mode specifier ; R3 = monitor type ; ; out: EQ => service claimed, R3 -> VIDC list, R4 -> workspace list ; NE => service not claimed, R3,R4 preserved ; All other registers preserved ; OfferModeExtensionAnyMonitor ROUT MOV r3, #-1 OfferModeExtension ROUT Push "r1,r2,r4,r5,r14" ; TMD 10-Jan-94 - added code here to check for erroneous passing in of a sprite mode word. ; This prevents data aborts when modules try to index off a bad address. ; ; We could have done OS_ValidateAddress, but that would be rather slow, and mode selectors ; are of indeterminate length. ; ; If we detect one of these, we pretend the service wasn't claimed. Hopefully this should ; ensure that the mode change returns an error. ; Fixes bug MED-00483. BICS r14, r2, #&FF ; NE if not a mode number TSTNE r2, #3 ; NE if not a mode number, but invalid mode selector Pull "r1,r2,r4,r5,pc", NE ; so exit NE, pretending that service not claimed GetBandwidthAndSize r4, r5 MOV r1, #Service_ModeExtension IssueService TEQ r1, #0 ; if service claimed CMPNE r3, #-1 ; or if "don't care" monitortype BEQ %FT90 ; then we can't do any more CMP r2, #&100 ; if it's a mode selector BCS %FT90 ; then we can't help them either BranchIfNotKnownMode r2, %FA90 ; if we don't recognise screen mode number we can't either ; it is a known numbered mode, so create a mode selector on the stack that we can pass to service Push "r6,r7" SUB sp, sp, #ModeSelector_ModeVars+4 ; make room for block including terminator ADRL r6, Vwstab LDR r14, [r6, r2, LSL #2] ADD r6, r6, r14 BL ModeNumberToModeSelector ; R1, R7 corrupt MOV r1, #Service_ModeExtension MOV r2, sp IssueService TEQ r1, #0 BEQ %FT10 ; service was claimed ; not claimed, so try again with -1 as frame rate MOV r7, #-1 STR r7, [sp, #ModeSelector_FrameRate] IssueService TEQ r1, #0 10 ADD sp, sp, #ModeSelector_ModeVars+4 ; junk mode selector Pull "r6, r7" 90 CMP r2, #&100 ; if we started or ended up with a mode selector MOVCS r4, #0 ; then return r4 = 0 (if claimed) TEQ r1, #0 STREQ r4, [sp, #2*4] ; if service claimed, then return r4 from service, else preserve it Pull "r1,r2,r4,r5,pc" ; ***************************************************************************** ; ; ETB - Redefine character ; === & other stuff ; ; VDU 23,0,r,v,0| Talk to 6845 ! ; VDU 23,1,n,m,r,g,b| Program cursor ; VDU 23,2,n1..n8 Ecf pattern 1 ; VDU 23,3,n1..n8 Ecf pattern 2 ; VDU 23,4,n1..n8 Ecf pattern 3 ; VDU 23,5,n1..n8 Ecf pattern 4 ; VDU 23,6,n1..n8 Dot dash line style ; VDU 23,7,m,d,z| Scroll window directly ; VDU 23,8,t1,t2,x1,y1,x2,y2| Clear block ; VDU 23,9,n| Set 1st flash time ; VDU 23,10,n| Set 2nd flash time ; VDU 23,11| Default Ecf patterns ; VDU 23,12,n1..n8 Ecf pattern 1 (simple setting) ; VDU 23,13,n1..n8 Ecf pattern 2 (simple setting) ; VDU 23,14,n1..n8 Ecf pattern 3 (simple setting) ; VDU 23,15,n1..n8 Ecf pattern 4 (simple setting) ; VDU 23,16,x,y| Cursor movement control ; VDU 23,17,c,t| Set colour tints, ECF info, char sizes ; ; ETB LDRB R0, [WsPtr, #QQ+0] CMP R0, #32 ; defining a normal character ? BCS DefineChar LDR R2, [PC, R0, LSL #2] ADD PC, PC, R2 ; enters routine with R0 => byte after 23 ETBtab & Vdu23_0-ETBtab-4 & Vdu23_1-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & LineStyle-ETBtab-4 & Vdu23_7-ETBtab-4 & Vdu23_8-ETBtab-4 & Vdu23_9-ETBtab-4 & Vdu23_10-ETBtab-4 & DefaultEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & Vdu23_16-ETBtab-4 & Vdu23_17-ETBtab-4 & Vdu23_18-ETBtab-4 & Vdu23_19-ETBtab-4 & Vdu23_20-ETBtab-4 & Vdu23_21-ETBtab-4 & Vdu23_22-ETBtab-4 & Vdu23_23-ETBtab-4 & Vdu23_24-ETBtab-4 & Vdu23_25-ETBtab-4 & Vdu23_26-ETBtab-4 & Vdu23_27-ETBtab-4 & Vdu23_28-ETBtab-4 & Vdu23_29-ETBtab-4 & Vdu23_30-ETBtab-4 & Vdu23_31-ETBtab-4 ; NB All other labels for Vdu23 are in TMD files so I don't have to pester RCM ;Vdu23_18 ; Assigned to Teletext operations Vdu23_19 Vdu23_20 Vdu23_21 Vdu23_22 Vdu23_23 Vdu23_24 Vdu23_25 Vdu23_26 ; Vdu23_27 ; Assigned to Richard (well some of it, anyway) Vdu23_28 Vdu23_29 Vdu23_30 Vdu23_31 UnknownVdu23 ; R0 already contains first parameter to VDU23 MOV R10, #UKVDU23V Push "WsPtr, R14" ; calling a vector corrupts R12 BL VduQQVec ; so we have to preserve it Pull "WsPtr, PC", VC ; before we return to PostWrchCursor ; error in UKVDU23 vector, so go to vdu error exit Pull "WsPtr, R14" B VduBadExit ; ***************************************************************************** ; ; DLE ; CLG - Clear graphics window ; === ; ; On exit, R0..R11 corrupt ; DLE CLG ROUT GraphicsMode R0 MOVNE PC,LR ; check for graphics mode (changed by DDV 15/9/92) ADD R0, WsPtr, #BgEcfOraEor ; point at background colour STR R0, [WsPtr, #GColAdr] ADD R11, WsPtr, #GWLCol ; load window coordinates into LDMIA R11, {R0-R3} ; RectFill's parameter space LDR R6, [WsPtr, #CursorFlags] ; if clip box is not enabled TST R6, #ClipBoxEnableBit ; then goto code directly BEQ RectFillA Push R14 ; else merge graphics window (in R0-R3) BL MergeClipBox ; with clip box Pull R14 B RectFillA ; ***************************************************************************** ; ; DC2 ; GCol - Set Graphics action and colour ; ==== ; ; On entry, R0 holds GCol action ; R1 holds GCol colour, 0..127 means program fg ; 128..255 means program bg ; ; In 256-colour modes, the extra colours are accessed via TINT ; DC2 GCol ROUT LDRB R0, [WsPtr, #QQ+0] ; GCol action, eg store, eor etc. LDRB R1, [WsPtr, #QQ+1] ; GCol colour LDR R2, [WsPtr, #NColour] ; number of colours-1 TST R1, #&80 AND R1, R1, R2 ; limit colour to range available STREQ R0, [WsPtr, #GPLFMD] ; GCOL(a,0..127) is foreground STREQ R1, [WsPtr, #GFCOL] STRNE R0, [WsPtr, #GPLBMD] ; GCOL(a,128..255) is background STRNE R1, [WsPtr, #GBCOL] ; drop into SetColour to.... ; SetColour - Setup FgEcf & BgEcf, used after GCOL or setting of Ecfs ; ========= or default palette (does a gcol). SetColour Push R14 LDR R1, [WsPtr, #GPLFMD] ; setup FgEcf, maybe solid or Ecf LDR R0, [WsPtr, #GFCOL] ADD R2, WsPtr, #FgEcf LDR R3, [WsPtr, #GFTint] ; tint only used in 256 colour modes ADD R4, WsPtr, #FgPattern ; used if OS_SetColour call BL SetCol10 LDR R1, [WsPtr, #GPLBMD] ; and BgEcf LDR R0, [WsPtr, #GBCOL] ADD R2, WsPtr, #BgEcf LDR R3, [WsPtr, #GBTint] ADD R4, WsPtr, #BgPattern ; used if OS_SetColour call BL SetCol10 ADD R0, WsPtr, #FgEcf ; setup FgEcfOraEor ADD R1, WsPtr, #BgEcf ADD R2, WsPtr, #FgEcfOraEor LDR R3, [WsPtr, #GPLFMD] BL SetCol60 ADD R0, WsPtr, #BgEcf ; and BgEcfOraEor ADD R1, WsPtr, #FgEcf ADD R2, WsPtr, #BgEcfOraEor LDR R3, [WsPtr, #GPLBMD] BL SetCol60 ADD R0, WsPtr, #BgEcf ; and BgEcfStore ADD R1, WsPtr, #FgEcf ADD R2, WsPtr, #BgEcfStore MOV R3, #0 BL SetCol60 Pull PC ; SetCol10 - Internal to SetColour ; Build up an Ecf, given action and colour numbers ; ; On entry, R0 holds colour (0..255, where 127..255 means 0..127) ; R1 holds action (may indicate ecf) ; R2 holds address to write data (FgEcf or BgEcf) ; R3 holds tint information (only used in 256 colour modes) ; R4 holds pointer to suitable pattern table for OS_SetColour call SetCol10 ROUT ANDS R1, R1, #&F0 ; actions >=16 mean Ecf BNE SetCol30 Push R14 LDR R4, [WsPtr, #NColour] ; else use given colour number AND R0, R0, R4 AND R0, R0, #63 ; another bodge in the house of bodges TST R4, #&F0 ; if 256 colour (ie 8bpp) BLNE AddTintToColour ; then combine tint with colour ; R0 contains colour number for current mode LDR LR, [WsPtr, #BitsPerPix] 10 TEQ LR, #32 ORRNE R0, R0, R0, LSL LR ; replicate again MOVNE LR, LR, LSL #1 ; doubling the shift for each pass BNE %BT10 STR R0, [R2] STR R0, [R2, #4] STR R0, [R2, #8] STR R0, [R2, #12] STR R0, [R2, #16] STR R0, [R2, #20] STR R0, [R2, #24] STR R0, [R2, #28] Pull "PC" ; R1 = ecf number as 16,32,48,64,80,96 ; R2 -> destination ; R4 -> pattern block (if R1 =96!) SetCol30 CMP R1, #96 ; special internal plot? MOVCS R0, R4 ; yes, so point at pattern to be copied MOVCS R3, #1 ; col step =1 MOVCS R4, #0 ; row step =0 (already there!) BCS SetCol35 CMP R1, #80 ; 80 => giant ecf (>80 does same) ADDCS R0, WsPtr, #Ecf1 ; then point at ecf0 MOVCS R3, #8 ; col step=8 MOVCS R4, #(1-8*4) ; row step, back to 1st ecf on 1 byte BCS SetCol35 ADD R0, WsPtr, #(Ecf1-8) ADD R0, R0, R1, LSR #1 ; else point R0 at Ecf1,2,3 or 4 LDR R4, [WsPtr, #BitsPerPix] CMP R4, #16 BHI SetCol45 BEQ SetCol40 LDR R5, [WsPtr, #BytesPerChar] TEQ R4, R5 ; if BitsPerPix <> 'fudged' BitsPerPix BNE SetCol52 ; then double up the pixels ; else its a normal Ecf MOV R3, #0 ; col step=0, same byte each coloum MOV R4, #1 ; row step=1 SetCol35 MOV R5, #8 ; do 8 rows SetCol36 MOV R6, #4 ; of 4 columns SetCol37 LDRB R7, [R0], R3 ; read from source & move by col step STRB R7, [R2], #1 ; write to dest, update dest pointer SUBS R6, R6, #1 BNE SetCol37 ADD R0, R0, R4 ; step source pointer to next row SUBS R5, R5, #1 BNE SetCol36 MOV PC, R14 ; Generate 1x4 pattern for 16bpp ; ; R0 points to Ecf(n) ; R2 points to destination ; ; Uses R0,R2,R5,R6,R7 ; SetCol40 LDMIA R0, {R0,R6} ; Grab full pattern block EOR R5, R0, R0, ROR #16 ; &22221111 ^ &11112222 EOR R7, R6, R6, ROR #16 EOR R0, R0, R5, LSL #16 ; = &11111111 EOR R6, R6, R7, LSL #16 EOR R5, R5, R0 ; = &22222222 EOR R7, R7, R6 STMIA R2!,{R0,R5,R6,R7} ; Store 4 rows STMIA R2!,{R0,R5,R6,R7} ; 8 rows MOV PC, R14 ; Generate 1x2 pattern for 32bpp ; ; R0 points to Ecf(n) ; R2 points to destination ; ; Uses R0,R2,R5,R6,R7 ; SetCol45 LDMIA R0, {R0,R5} MOV R6,R0 MOV R7,R5 STMIA R2!,{R0,R5,R6,R7} STMIA R2!,{R0,R5,R6,R7} MOV PC, R14 ; Double up the pixels for Mode2 etc ; ; R0 points to Ecf(n) ; R2 points to destination ; ; Uses ; ; R3 - NColour used as PixMsk ; R4 - BitsPerPix ; R5 - BytesPerChar (unused) ; R6 - byte cntr 7..0 ; R7 - source byte ; R8 - ExtrtShftFact ; R9 - InsrtShftFact ; R10 - result word ; R11 - temp SetCol52 LDR R3, [WsPtr, #NColour] ; mask for extracting pixels from ecf TST R3, #&F0 ; ** if 256 colour mode MOVNE R3, #&FF ; ** then use &FF (TMD 25-Mar-87) LDR R4, [WsPtr, #BitsPerPix] MOV R6, #7 ; 8 bytes/rows to do SetCol54 LDRB R7, [R0, R6] ; get byte of Ecf(n) RSB R8, R4, #8 RSB R9, R4, #32 MOV R10, #0 ; clear result word SetCol57 AND R11, R3, R7, ROR R8 ; extract 1 pixel from Ecf ORR R10, R10, R11, LSL R9 ; double it into result word SUB R9, R9, R4 ORR R10, R10, R11, LSL R9 SUB R8, R8, R4 AND R8, R8, #7 SUBS R9, R9, R4 BGE SetCol57 ; process next pixel in result word STR R10, [R2, R6, LSL #2] ; write expanded word to (Fg/Bg)Ecf SUBS R6, R6, #1 BGE SetCol54 ; process next row/byte MOV PC, R14 ; Tables of full colours for 2,4 & 16 colour modes (256 colour modes ; use colour number directly). ; ; N.B. these are tables of bytes TBFullCol = &FF ; not used - remove sometime ; (DJS comment: don't bother!) = &00, &FF ; 2 colour mode = &00, &55, &AA, &FF ; 4 colour mode = &FF, &FF, &FF, &FF ; not used but cannot be removed = &FF, &FF, &FF, &FF ; (8 colour mode!) = &00, &11, &22, &33 ; 16 colour mode = &44, &55, &66, &77 = &88, &99, &AA, &BB = &CC, &DD, &EE, &FF ALIGN ; ***************************************************************************** ; ; SetCol60 - Build up an ecf, ORed and EORed appropriate to GCOL action ; ; Internal to SetColour ; ; in: R0 -> ecf colour (FgEcf/BgEcf) ; R1 -> transparent colour (BgEcf/FgEcf) ; R2 -> destination FgEcfOraEor/BgEcfOraEor/BgEcfStore ; R3 = gcol action number (may indicate ecf) ; ; uses: R4 = index into ecf (7..0) ; R5 = ecf colour word ; R6 = transparency mask, set to &FFFFFFFF for NO transparency ; R7 -> zgoo..zgee for gcol action ; R8 = mask for pixel under examination ; R9 = shift factor to move mask to next pixel (BytesPerChar) ; R10, R11 temporary ; SetCol60 ROUT MOV R4, #7 ; 7..0 words to process AND R3, R3, #&F ; extract action bits AND R11, R3, #7 ; 0-7 Store etc ; 8-15 ditto with transparency MOV R11, R11, LSL #2 ; 4 bits for each LDR R7, =TBscrmasks MOV R7, R7, ROR R11 ; relevant bits are in top 4 AND R7, R7, #&F0000000 ; isolate these bits (N,Z,C,V) SetCol70 LDR R5, [R0, R4, LSL #2] ; get ecf word TST R3, #8 ; if action < 8 MOVEQ R6, #&FFFFFFFF BEQ SetCol90 ; then not transparent ; else build transparency mask LDR R8, [WsPtr, #RAMMaskTb] ; fetch mask for leftmost pixel LDR R9, [WsPtr, #BytesPerChar] ; shift factor for next pixel LDR R6, [R1, R4, LSL #2] ; get 'transparent' colour EOR R6, R6, R5 SetCol80 TST R6, R8 ; if pixels the same, ; then it's transparent ORRNE R6, R6, R8 ; else set mask to plot it MOVS R8, R8, LSL R9 BNE SetCol80 SetCol90 MSR CPSR_f, R7 ; put bits into N, Z, C, V ; OO,EO,OE,EE MOVCC R10, R5 ; if ORing with &00000000 MOVCS R10, #&FFFFFFFF ; if ORing with &FFFFFFFF MVNVS R10, R10 ; if EORing with &FFFFFFFF ; MOVPL R5, R5 ; if ORing with &00000000 MOVMI R5, #&FFFFFFFF ; if ORing with &FFFFFFFF MVNEQ R5, R5 ; if EORing with &FFFFFFFF ; now R5 = OR mask, R10 = EOR mask AND R5, R5, R6 ; then clear 'transparent' AND R10, R10, R6 ; pixels LDR R11, [WsPtr, #ECFShift] MOV R5, R5, ROR R11 ; rotate OR and EOR masks MOV R10, R10, ROR R11 ; to correct for ECF X origin LDR R11, [WsPtr, #ECFYOffset] ADD R11, R11, R4 ; add on ECF Y offset AND R11, R11, #7 ; and wrap ADD R11, R2, R11, LSL #3 STMIA R11, {R5, R10} ; write to (Fg/Bg)EcfOraEor SUBS R4, R4, #1 BCS SetCol70 MOV PC, R14 ; ***************************************************************************** ; ; AddTintToColour - in 256 colour modes ; ; Internal to SetColour (derived from TMD's FudgeColour) ; ; in: R0 = colour (0..255), where 6 LSBits are used ; R3 = tint ; ; out: R0 holds colour byte with tint added ; R1-R3 preserved ; R4 undefined ; PSR preserved ; ! 0,"WARNING: AddTintToColour returns > 8 bit values now, check ECF handling!" AddTintToColour Push "R3,LR" AND R0, R0, #63 ; extract suitable set of bits AND R3, R3, #192 ; and another set ORR R0, R0, R3 BL ConvertGCOLToColourNumber Pull "R3,PC" ; ***************************************************************************** ; ; CAN - Define graphics window ; ; External routine ; ; in: The window is given by bytes in the vdu queue, as follows :- ; QQ+0 = leftLo ; QQ+1 = leftHi ; QQ+2 = bottomLo ; QQ+3 = bottomHi ; QQ+4 = rightLo ; QQ+5 = rightHi ; QQ+6 = topLo ; QQ+7 = topHi ; ; These are relative to the current graphics origin. ; The resultant window must obey the following rules :- ; RCol >= LCol ; TRow >= BRow ; LCol >= 0 ; BRow >= 0 ; YWindLimit >= TRow ; XWindLimit >= RCol ; CAN ROUT Push R14 ADD R8, WsPtr, #GCsX ; save ECursor away, cos EIG changes it LDMIA R8, {R6, R7} ; and we don't want it to! ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+5] ; rightHi ; LDRB R1, [WsPtr, #QQ+4] ; rightLo ; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend ; ; LDRB R1, [WsPtr, #QQ+7] ; topHi ; LDRB R2, [WsPtr, #QQ+6] ; topLo ; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+4 ;Get top right point ; *****End of change made by DJS MOV R2, #&FF ; convert external-to-internal BL EIG ; as absolute coordinates MOV R4, R0 ; move internal version of top right MOV R5, R1 ; out of harm's way ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+1] ; leftHi ; LDRB R1, [WsPtr, #QQ+0] ; leftLo ; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend ; ; LDRB R1, [WsPtr, #QQ+3] ; bottomHi ; LDRB R2, [WsPtr, #QQ+2] ; bottomLo ; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+0 ;Get bottom left point ; *****End of change made by DJS MOV R2, #&FF ; convert external-to-internal BL EIG ; as absolute coordinates ; For a valid window, the following must be true CMP R4, R0 ; RCol >= LCol CMPGE R5, R1 ; TRow >= BRow CMPGE R0, #0 ; LCol >= 0 CMPGE R1, #0 ; BRow >= 0 LDRGE R2, [WsPtr, #YWindLimit] ; YWindLimit >= TRow CMPGE R2, R5 LDRGE R2, [WsPtr, #XWindLimit] ; XWindLimit >= RCol CMPGE R2, R4 ADD R2, WsPtr, #GWLCol STMGEIA R2, {R0,R1, R4,R5} ; if the new window is OK, update it STMIA R8, {R6, R7} ; restore ECursor (EIG corrupted it) Pull PC ; ***************************************************************************** ; ; DefaultWindows - Restore default windows ; ; External routine, and called by mode change + switch output to sprite ; ; Set default text and graphics windows, ; Clear graphics origin and both cursors ; DefaultWindows ROUT Push R14 MOV R0, #0 MOV R1, #0 ADD R4, WsPtr, #GWLCol ASSERT YWindLimit = XWindLimit +4 ADD R2, WsPtr, #XWindLimit LDMIA R2, {R2,R3} ; R2 := XWindLimit; R3 := YWindLimit STMIA R4, {R0-R3} ; zero GWLCol, GWBRow ; GWRCol:=XWindLimit; GWTRow:=YWindLimit MOV R3, #0 LDR R1, [WsPtr, #ScrBRow] LDR R2, [WsPtr, #ScrRCol] ADD R4, WsPtr, #TWLCol ; zero TWLCol, TWTRow STMIA R4!, {R0-R3} ; TWRCol := ScrRCol; TWBRow := ScrBRow MOV R1, #0 MOV R2, #0 STMIA R4!, {R0-R3} ; zero OrgX, OrgY, GCsX, GCsY STMIA R4!, {R0-R3} ; zero OlderCsX, OlderCsY, OldCsX, OldCsY STMIA R4!, {R0-R3} ; zero GCsIX, GCsIY, NewPtX, NewPtY LDR R0, [WsPtr, #VduSprite] TEQ R0, #0 LDR R0, [WsPtr, #VduStatus] ; if not outputting to sprite BICEQ R0, R0, #Windowing ; then indicate no text window ORRNE R0, R0, #Windowing ; else indicate is text window STR R0, [WsPtr, #VduStatus] BL HomeVdu4 ; home TEXT cursor ; (even in VDU 5 mode) Pull PC ; ***************************************************************************** ; ; GS - Define graphics origin ; ; External routine ; ; in: The origin is given by bytes in the vdu queue, as follows :- ; QQ+0 = xLo ; QQ+1 = xHi ; QQ+2 = yLo ; QQ+3 = yHi ; ; The coordinates are in external 16 bit form. ; This does not move the windows, but does move the graphics cursor ; GS ROUT Push R14 ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+1] ; xHi ; LDRB R1, [WsPtr, #QQ+0] ; xLo ; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend ; LDRB R1, [WsPtr, #QQ+3] ; yHi ; LDRB R2, [WsPtr, #QQ+2] ; yLo ; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+0 ; *****End of change made by DJS ADD R2, WsPtr, #OrgX STMIA R2, {R0,R1} ; write the new origin BL IEG ; update external cursor Pull PC LTORG ;------------------------------------------------------------------------------ ; ; OS_SetColour implementation ; ------------ ; ; This call can be used to change the current GCOL/pattern table used for ; plotting with the VDU primitives. ; ; in R0 = flags / logical operation ; bit 0-3 = logical operation ; bit 4 = set => bg, else fg flag ; bit 5 = set => pattern block supplied ; bit 6 = set => set text colour ; bit 7 = set => read colour ; R1 = colour number / -> pattern block to use ; out - ; ;------------------------------------------------------------------------------ setcol_LogicOpMask * &0F setcol_FgBgFlag * &10 setcol_PatternFlag * &20 setcol_TextColour * &40 setcol_ReadFlag * &80 ASSERT WsPtr > 9 SWISetColour ROUT Push "R0-R9,WsPtr,R14" VDWS WsPtr ; Obtain base of the VDU driver workspace TST R0, #setcol_ReadFlag ; Are we reading? BNE %FT75 TST R0, #setcol_TextColour ; Are we changing the text colour? BNE %FT70 AND R2, R0, #setcol_LogicOpMask ; Get the logical operation ORR R2, R2, #&60 ; Mark as being a special kind of pattern TST R0, #setcol_FgBgFlag STREQ R2, [WsPtr, #GPLFMD] ; Store the relevant logical operation away for fg/bg STRNE R2, [WsPtr, #GPLBMD] ADDEQ R3, WsPtr, #FgPattern ADDNE R3, WsPtr, #BgPattern ; Setup the pointer to a store for the pattern TST R0, #setcol_PatternFlag ; Did the caller specify a pattern block? BNE %FT50 ; Yes so don't try to expand colour value to pattern MOV R2, #1 LDR R4, [WsPtr, #Log2BPP] ; Get the Log2 depth of the mode MOV R4, R2, ASL R4 ; R4 = bits per pixel RSB R2, R2, R2, LSL R4 ; Get a mask to extract only meaningful bits from word AND R1, R1, R2 ; Extract bits suitable for this depth of mode 10 TEQ R4, #32 ; Do we need to do any more replication ORRNE R1, R1, R1, LSL R4 ; Yes so or word with itself shifted MOVNE R4, R4, LSL #1 ; and double amount to shift next time BNE %BT10 MOV R2, #8 20 STR R1, [R3], #4 ; now copy word 8 times into block SUBS R2, R2, #1 BNE %BT20 B %FT60 50 LDMIA R1,{R0,R2,R4-R9} STMIA R3,{R0,R2,R4-R9} ; Copy the pattern into the buffer (assumes word aligned) 60 BL SetColour ; And then setup the internal GCOL tables 65 Pull "R0-R9,WsPtr,R14" ExitSWIHandler 70 TST R0, #setcol_FgBgFlag ; Store the foreground or background colour? STREQ R1, [WsPtr, #TextFgColour] STRNE R1, [WsPtr, #TextBgColour] LDR R0, [WsPtr, #CursorFlags] ; Indicate the text colour needs re-computing! ORR R0, R0, #TEUpdate STR R0, [WsPtr, #CursorFlags] B %BT65 ; Leave gracefully .... 75 ; Reading the colour... TST R0, #setcol_TextColour BEQ %FT80 ; Reading text colour TST R0, #setcol_FgBgFlag LDREQ R1, [WsPtr, #TextFgColour] LDRNE R1, [WsPtr, #TextBgColour] BIC R0, R0, #setcol_PatternFlag :OR: setcol_ReadFlag 77 ; Standard exit for reading the colour STMIA SP, {R0,R1} B %BT65 80 ; Reading graphics colour TST R0, #setcol_FgBgFlag LDREQ R2, [WsPtr, #GPLFMD] ; Get the relevant logical operation for fg/bg LDRNE R2, [WsPtr, #GPLBMD] ; SetColour setting - copy block ADDEQ R3, WsPtr, #FgEcf ADDNE R3, WsPtr, #BgEcf ; Copy the pattern to the user's buffer LDMIA R3,{R0,R3,R4-R9} STMIA R1,{R0,R3,R4-R9} ; Construct a suitable reason code AND R0, R2, #setcol_LogicOpMask ORRNE R0, R0, #setcol_FgBgFlag ORR R0, R0, #setcol_PatternFlag B %BT77 ; ***************************************************************************** ; ; HandleServiceDisplayStatus ; ; Called from kernel service call handler ; ; in: R0 = sub-reason ; R1 = Service_DisplayStatus ; R2 = GraphicsV driver number ; LR = return address ; ; out: R12 corrupt ; HandleServiceDisplayStatus ROUT ; We're only interested in DisplayStatus_Changing/DisplayStatus_Changed TEQ r0, #DisplayStatus_Changing TEQNE r0, #DisplayStatus_Changed MOVNE pc, lr Entry "r0-r4" ; We're only interested in the current driver VDWS WsPtr LDR r1, [WsPtr, #CurrentGraphicsVDriver] TEQ r1, r2 BNE %FT90 ; Translate this call into the corresponding Service_DisplayChanging calls ; DisplayStatus_Changing -> DisplayChanged_PreChanging ; DisplayStatus_Changed -> DisplayChanged_Changing, ; DisplayChanged_Changed ; This may sound odd, but that's how it fits with the way the ; DisplayChanged service call is designed. The ScreenModes module will ; recache its mode list when it receives DisplayChanged_Changing, so we ; must only issue the call once the driver has finished changing its ; configuration. TEQ r0, #DisplayStatus_Changed BEQ %FT50 MOV r0, #DisplayChanged_PreChanging MOV r1, #Service_DisplayChanged MOV r3, #DisplayChangedSub_ModeNotChanged IssueService EXIT 50 ; It was a DisplayStatus_Changed call. Recache any important values ; that we care about. MOV r4, r2, LSL #24 ORR r4, r4, #GraphicsV_DisplayFeatures BL CallGraphicsV STR r0, [WsPtr, #GraphicsVFeatures] BL UpdateFalseVsync ; Currently we assume that the driver's hardware ; scroll ability won't have been changed. ; Now issue the two DisplayChanged service calls MOV r0, #DisplayChanged_Changing MOV r1, #Service_DisplayChanged FRAMLDR r2 MOV r3, #DisplayChangedSub_ModeNotChanged IssueService MOV r0, #DisplayChanged_Changed IssueService 90 EXIT LTORG END