; 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.VduSWIs MACRO BranchNotJustUs $label, $vector, $tmp1, $tmp2 LDR R11, =ZeroPage [ $tmp1=R11 LDR R12, [R11, #VecPtrTab+$vector*4]! ; load vector node | LDR R12, [R11, #VecPtrTab+$vector*4] ; load vector, leave R11=0 ] CMP R12, #&FC000000 ; fudge BCC $label MEND MACRO BranchNotJustUsWrch $label BranchNotJustUs $label, WrchV, R11, R14 MEND MACRO SWIEntry $swiname & OS_$swiname & SWI$swiname-(.+4) MEND ; ***************************************************************************** ; ; SWIRVV - SWI ReadVduVariables handler ; ; in: R0 -> input block ; R1 -> output block ; ; out: All registers preserved ; ; The input block consists of a string of words, terminated by -1 ; Each word indicates which VDU variable to read. ; The (word) values of these variables are put in sequence into the ; output block (no terminator is put in this block). Invalid variables ; are returned as zero. SWIRVV ROUT SWIReadVduVariables ; alternative symbol used for init'ing TST R0, #3 ; input block not aligned TSTEQ R1, #3 ; or output block not aligned ExitSWIHandler NE ; then exit Push R9 VDWS WsPtr MOV R10, #0 ; offset into both blocks 10 LDR R11, [R0, R10] CMP R11, #-1 ; end of block ? Pull R9, EQ ExitSWIHandler EQ CMP R11, #&100 ; is it fudged "code" variable BCS %FT30 ; yes, then use special code CMP R11, #(SWIRVVTabModeEnd-SWIRVVTab) ; a mode variable ADRCC R9, SWIRVVTab ; if so then point to them BCC %FT20 SUB R11, R11, #&80 ; base for non-mode variables CMP R11, #(SWIRVVTabEnd-SWIRVVTabModeEnd) ADRCCL R9, SWIRVVTabModeEnd BCC %FT20 SUB R11, R11, #&40 ; base for GraphicsV variables CMP R11, #(SWIRVVTabGraphicsVEnd-SWIRVVTabEnd) ADRCCL R9, SWIRVVTabEnd 20 LDRCCB R11, [R9, R11] ; yes, then load offset LDRCC R11, [WsPtr, R11, LSL #2] ; and then load variable MOVCS R11, #0 ; no, then put zero in it 25 STR R11, [R1, R10] ADD R10, R10, #4 B %BT10 ; Special code to read window width for Bruce et al. 30 SUB R11, R11, #&100 CMP R11, #2 ; 0 => WindowWidth, 1 => WindowHeight BCS %BT20 ; not one of those, so illegal Push "R0-R7" LDR R6, [WsPtr, #CursorFlags] TST R6, #Vdu5Bit ADDEQ R4, WsPtr, #TWLCol ; if VDU 4 mode, use text window ADDNE R4, WsPtr, #GWLCol ; else use graphics window LDMIA R4, {R0-R3} SUB R0, R2, R0 ; R0 = horizontal width -1 SUB R1, R1, R3 ; R1 = vertical height -1 BEQ %FT32 ADD R2, WsPtr, #GCharSizes ; R2=GCharSizeX; R3=GCharSizeY LDMIA R2, {R2-R5} ; R4=GCharSpaceX; R5=GCharSpaceY TST R6, #2 ; if going from right to left SUBNE R2, R2, #1 ; then width reduction = sizex-1 MOVEQ R2, #0 ; else 0 TST R6, #4 ; if going from bottom to top RSBNE R3, R3, #1 ; then -height reduction = 1-sizey MOVEQ R3, #0 ; else 0 SUB R7, R0, R2 ; R7 = width-1-(width reduction) DivRem R0, R7, R4, R2, norem ; R0 = (width-(1 or sizex))DIV spacex SUB R7, R3, R1 ; R7 = height-(1-height reduction) DivRem R1, R7, R5, R3, norem ; R1 = (height-(1 or sizey))DIV spacey 32 TST R6, #8 ; are X and Y reversed ? EORNE R0, R0, R1 ; yes, then swap EORNE R1, R0, R1 EORNE R0, R0, R1 TST R6, #Vdu5Bit BNE %FT35 TST R6, #1 ; is it "81 column mode ?" and VDU 4 ADDNE R0, R0, #1 ; yes, then extra column 35 TEQ R11, #0 ; reading width ? MOVEQ R11, R0 ; yes, then use X MOVNE R11, R1 ; no, use Y Pull "R0-R7" ; restore registers B %BT25 ; and store result away SWIRVVTab ; Note these first variables should be the same as in SWI ReadModeVariable RVVT ModeFlags RVVT ScrRCol RVVT ScrBRow RVVT NColour RVVT XEigFactor RVVT YEigFactor RVVT LineLength RVVT ScreenSize RVVT YShftFactor RVVT Log2BPP RVVT Log2BPC RVVT XWindLimit RVVT YWindLimit SWIRVVTabModeEnd RVVT GWLCol RVVT GWBRow RVVT GWRCol RVVT GWTRow RVVT TWLCol RVVT TWBRow RVVT TWRCol RVVT TWTRow RVVT OrgX RVVT OrgY RVVT GCsX RVVT GCsY RVVT OlderCsX RVVT OlderCsY RVVT OldCsX RVVT OldCsY RVVT GCsIX RVVT GCsIY RVVT NewPtX RVVT NewPtY RVVT ScreenStart RVVT DisplayStart RVVT TotalScreenSize RVVT GPLFMD RVVT GPLBMD RVVT GFCOL RVVT GBCOL RVVT TForeCol RVVT TBackCol RVVT GFTint RVVT GBTint RVVT TFTint RVVT TBTint RVVT MaxMode RVVT GCharSizeX RVVT GCharSizeY RVVT GCharSpaceX RVVT GCharSpaceY RVVT HLineAddr RVVT TCharSizeX RVVT TCharSizeY RVVT TCharSpaceX RVVT TCharSpaceY RVVT GcolOraEorAddr RVVT VIDCClockSpeed RVVT PixelRate RVVT BorderL RVVT BorderB RVVT BorderR RVVT BorderT SWIRVVTabEnd RVVT CurrentGraphicsVDriver SWIRVVTabGraphicsVEnd ALIGN [ {FALSE} ; ***************************************************************************** ; ; SWISetVduVariables - SWI OS_SetVduVariables handler ; ; in: R0 -> block of variable numbers (word aligned) ; R1 -> block of variable values (word aligned) ; ; out: All registers preserved ; ; The block pointed to by R0 consists of a string of words, terminated ; by -1. Each word indicates which variable to write. The corresponding ; value in the R1 block is written to this variable. Invalid variables ; are ignored. ; SWISetVduVariables ROUT TST R0, #3 ; index block not aligned TSTEQ R1, #3 ; or value block not aligned ExitSWIHandler NE ; then exit Push R9 VDWS WsPtr MOV R10, #0 ; offset into both blocks 10 LDR R11, [R0, R10] CMP R11, #-1 ; end of block ? Pull R9, EQ ExitSWIHandler EQ TEQ R11, #VduExt_XEigFactor TEQNE R11, #VduExt_YEigFactor BNE %FT25 CMP R11, #(SWIRVVTabModeEnd-SWIRVVTab) ; a mode variable ADRCC R9, SWIRVVTab ; if so then point to them SUBCS R11, R11, #&80 ; base for non-mode variables ADRCS R9, SWIRVVTabModeEnd 20 LDRB R11, [R9, R11] ; yes, then load offset LDR R9, [R1, R10] ; load value STR R9, [WsPtr, R11, LSL #2] ; store in variable Push "R0-R5,R14" BL IEG ; update ext. cursor ; on exit, R2=XEigFactor, R3=YEigFactor SUBS R0, R2, R3 ; XEigFactor-YEigFactor MOVLT R0, #2 ; X 2 (vert rect) MOVGT R0, #1 ; X>Y => 1 (horz rect) else 0 (square) STR R0, [WsPtr, #AspectRatio] ; mouse bounding box, mouse position ??? Pull "R0-R5,R14" 25 ADD R10, R10, #4 B %BT10 ] ; ***************************************************************************** ; ; SWIReadModeVar - Handler for SWI OS_ReadModeVariable ; ; in: R0 = screen mode you want the information for, -1 => current mode ; R1 = number of variable to read ; ; out: R2 = value of variable ; ; Note: the algorithms used to derive the variables for mode selectors ; are duplicated in source.vdudriver, in GenerateModeSelectorVars SWIReadModeVar ROUT SWIReadModeVariable ; alternative symbol used for init'ing Push "R0,R1,R14" CMP R1, #(RMVTabEnd-RMVTab) ; valid variable number ? BCS BadReadModeVar ; no, then exit ; AMG - note that the new sprite mode word code assumes that this ; test has been done! VDWS WsPtr ; AMG - add readmodevariable returns for new format sprite mode words. Much of ; this is munging the word passed in. A new sprite mode word can be ; distinguished from a pointer to a mode selector structure because ; b0 will be set in the new sprite mode word. 11/3/93 ; TMD - serious optimisation introduced 17-Feb-93 ; TMD - additional optimisation for current mode added 16-Mar-93 ; AMG - Fix bug MED-00414 ... need to support eig=0 modes here 26-Oct-93 CMP r0, #-1 ; if explicitly asking for current mode BEQ RMVForCurrentMode ; then use optimised code CMP r0, #&100 BCC %FT11 ; an old style mode number, branch past ; the new code below TST r0, #&01 BNE NewSpriteModeWord ; b0 set, so it is a NewSpriteModeWord ; rather than a pointer to a mode selector ; it's a mode selector, so check if valid first BL ValidateModeSelector BVS BadReadModeVar ; check if variable is in workspace list ADD r10, r0, #ModeSelector_ModeVars ; point at list BL CheckWorkspaceList ; check list BCC GoodReadModeVar ; [it was in list, so exit] ; not in list, so deduce from other parms ; (we know the variable number is in range) LDR pc, [pc, r1, LSL #2] NOP & RMVMS_ModeFlags & RMVMS_ScrRCol & RMVMS_ScrBRow & RMVMS_NColour & RMVMS_XEigFactor & RMVMS_YEigFactor & RMVMS_LineLength & RMVMS_ScreenSize & RMVMS_YShftFactor & RMVMS_Log2BPP & RMVMS_Log2BPC & RMVMS_XWindLimit & RMVMS_YWindLimit RMVMS_ModeFlags RMVMS_YShftFactor MOV r2, #0 ; default modeflags, yshftfactor = 0 B GoodReadModeVar RMVMS_ScrRCol LDR r2, [r0, #ModeSelector_XRes] ; default scrcol = (xres>>3)-1 MOV r2, r2, LSR #3 SUB r2, r2, #1 B GoodReadModeVar RMVMS_ScrBRow LDR r2, [r0, #ModeSelector_YRes] ; default scrbrow = (yres>>3)-1 MOV r2, r2, LSR #3 SUB r2, r2, #1 B GoodReadModeVar RMVMS_NColour LDR r2, [r0, #ModeSelector_PixelDepth] CMP r2, #6 ; if pixel depth is sensible ADRCCL r11, NColourTable ; then lookup in table LDRCC r2, [r11, r2, LSL #2] MOVCS r2, #1 ; else return 1 B GoodReadModeVar RMVMS_XEigFactor MOV r2, #1 ; default xeig = 1 B GoodReadModeVar RMVMS_YEigFactor LDR r2, [r0, #ModeSelector_XRes] LDR r11, [r0, #ModeSelector_YRes] CMP r11, r2, LSR #1 ; if yres < xres/2 MOVCC r2, #2 ; then yeig = 2 MOVCS r2, #1 ; else yeig = 1 B GoodReadModeVar RMVMS_LineLength LDR r2, [r0, #ModeSelector_XRes] RMVMS_ShiftByPixDepthMinus3 LDR r11, [r0, #ModeSelector_PixelDepth] CMP r11, #6 ; if out of range MOVCS r11, #0 ; use log2bpp=0 MOV r2, r2, LSL r11 MOV r2, r2, LSR #3 ; ll = (xres << pixdepth) >> 3 B GoodReadModeVar RMVMS_ScreenSize LDR r2, [r0, #ModeSelector_XRes] LDR r11, [r0, #ModeSelector_YRes] MUL r2, r11, r2 ; xres * yres B RMVMS_ShiftByPixDepthMinus3 RMVMS_Log2BPP RMVMS_Log2BPC LDR r2, [r0, #ModeSelector_PixelDepth] CMP r2, #6 ; range check MOVCS r2, #0 B GoodReadModeVar RMVMS_XWindLimit LDR r2, [r0, #ModeSelector_XRes] ; default xwindlimit = xres-1 SUB r2, r2, #1 B GoodReadModeVar RMVMS_YWindLimit LDR r2, [r0, #ModeSelector_YRes] ; default ywindlimit = yres-1 SUB r2, r2, #1 B GoodReadModeVar 11 BIC r11, r0, #&80 ; clear shadow bit BranchIfKnownMode r11, %FA50 ; not known mode, so look Push "r2-r4" MOV r2, r11 BL OfferModeExtensionAnyMonitor MOVEQ r11, r4 ; if service responded to, save pointer to workspace list Pull "r2-r4" BNE BadReadModeVar ; exit if mode not known about ; now search down list checking for variable number ADD r10, r11, #8 ; skip list type and base mode BL CheckWorkspaceList ; look up variable in list BCC GoodReadModeVar ; if there then exit ; not in workspace list provided, so use base mode to look up in MOS's table LDR r11, [r11, #4] ; load workspace list base mode BranchIfKnownMode r11, %FA50 ; panic - base mode unrecognised ; existing code simply loads off end of table! - instead of that, return value zero ; alternatively we could return carry set, but that might cause backward compatibility problems (maybe) MOV r2, #0 B GoodReadModeVar 50 ADR r10, RMVTab LDRB r10, [r10, r1] ; R10 = offset in each mode table * 2 ; if bit 0 set, then word value ADRL r14, Vwstab LDR r11, [r14, r11, LSL #2] ; get offset to table for this mode ADD r11, r11, r14 ; convert to pointer MOVS r10, r10, LSR #1 ; put byte/word flag into carry LDRCCB r2, [r11, r10] ; load either a byte LDRCS r2, [r11, r10] ; or a word out of table ; and drop thru to GoodModeVar GoodReadModeVar Pull "R0,R1,R14" BIC R14, R14, #C_bit ; indicate successful read ExitSWIHandler BadReadModeVar Pull "R0,R1,R14" ORR R14, R14, #C_bit ; indicate bad read ExitSWIHandler ; CheckWorkspaceList - Check a mode variable (index, value) list for a match ; in: r1 = variable number ; r10 -> list ; ; out: If match found, then ; r2 = value ; C=0 ; else ; C=1 ; endif ; r10 corrupted in both cases CheckWorkspaceList Entry 10 LDR r14, [r10], #8 ; load next index (and skip index+value) CMP r14, #-1 ; if end of list EXIT EQ ; then not in workspace list, so exit (C=1 from CMP) TEQ r14, r1 BNE %BT10 LDR r2, [r10, #-4] ; load value of variable CLC ; clear carry EXIT RMVForCurrentMode ADR r10, MVToVVTable LDR r10, [r10, r1, LSL #2] LDR r2, [WsPtr, r10] B GoodReadModeVar MVToVVTable & ModeFlags & ScrRCol & ScrBRow & NColour & XEigFactor & YEigFactor & LineLength & ScreenSize & YShftFactor & Log2BPP & Log2BPC & XWindLimit & YWindLimit ; Note these should be the same as the first few in SWI ReadVduVariables RMVTab RMVT ModeFlags, W ; was B RMVT ScrRCol, W ; was B RMVT ScrBRow, W ; was B RMVT NColour, W RMVT XEigFactor, W ; was B RMVT YEigFactor, W ; was B RMVT LineLength, W RMVT ScreenSize, W RMVT YShftFactor, W ; was B RMVT Log2BPP, W ; was B RMVT Log2BPC, W ; was B RMVT XWindLimit, W RMVT YWindLimit, W RMVTabEnd ALIGN ; ***************************************************************************** ; ; NewSpriteModeWord, called from ReadModeVariable ; ; in: R0 = new sprite mode word ; R1 = number of variable to read ; (R0,R1,R14 stacked & corruptible) ; ; out: R2 = value of variable ; ; Return parameters as follows: ; (Unknown types will return an error. Invalid mode variable numbers will already ; have been weeded out at the entry to ReadModeVariable) ; 0 ModeFlags Error ; 1 ScrRCol Error ; 2 ScrBRow Error ; 3 NColour derived from bpp passed in (255 for 8bpp) ; 4 XEigFactor returns 0,1,2 for 180,90,45 dpi, error otherwise ; 5 YEigFactor as XEigFactor ; 6 LineLength Error ; 7 ScreenSize Error ; 8 YShftFactor Error ; 9 Log2BPP returns 0,1,2,3,4,5 for T=1-6, error otherwise ; 10 Log2BPC as Log2BPP ; 11 XWindLimit Error ; 12 YWindLimit Error NewSpriteModeWord ROUT ; validate the sprite type. Types 1-6 only at present. Type 0 is a ; mode number, but if it comes this way, it's bad, since mode >= 256 MOV r14, r0, LSR #27 ; shift type word into b4-b0 ANDS r14, r14, #&F ; discard wide mask bit BEQ BadReadModeVar ; zero is bad cos mode >= 256 ;if it's a RISC OS 5 sprite mode word, deal with it elsewhere CMP r14, #SpriteType_RISCOS5 BEQ RISCOS5SpriteModeWord ;if it's an unknown one, apply a substitute CMP r14, #SpriteType_RO5MAX MOVCS r14, #SpriteType_Substitute ; it's a valid type, now branch by the mode variable number 15 ADR r2, NewSpriteModeWordRoutines ADD pc, r2, r1, LSL #2 ; and despatch it NewSpriteModeWordRoutines B NSM_modeflags ; 0 ModeFlags (zero) B BadReadModeVar ; 1 ScrRCol Error B BadReadModeVar ; 2 ScrBRow Error B NSM_ncol ; 3 NColour B NSM_xeig ; 4 XEigFactor B NSM_yeig ; 5 YEigFactor B BadReadModeVar ; 6 LineLength Error B BadReadModeVar ; 7 ScreenSize Error B NSM_yshftfactor ; 8 YShftFactor (zero) B NSM_bpp ; 9 Log2BPP B NSM_bpp ; 10 Log2BPC as Log2BPP B BadReadModeVar ; 11 XWindLimit Error B BadReadModeVar ; 12 YWindLimit Error ; entry conditions here ; r14 - sprite type in b0-b6 for a word offset ; r0 - mode word ; r1 - mode variable (no longer needed at this point) NSM_ncol ; r14 is already the type bits shifted down to b0-b6, ie a word offset ADRL r2, NColourTable -4 ; results table (adjust for T=0 never occurring here) LDR r2, [r2, r14, LSL #2] ; pull the correct value CMP r2, #63 MOVEQ r2, #255 ; make sure we return 255 not 63 B GoodReadModeVar ; and return happily NSM_bpp ADR r2, NSM_bpptable-4 ; (adjusted for T=0 never occurring here) LDR r2, [r2, r14, LSL #2] B GoodReadModeVar NSM_bpptable & 0, 1, 2, 3, 4, 5 & 5, 5, 5 ; CMYK, 24bpp, JPEG (not supported) & 4 ; 64K sprite & 5, 5, 5, 5, 5 ; types 11-15 (reserved) & 4 ; 4K sprite & 5, 5 ; YCbCr 422 & 420 (not supported) NSM_yeig [ NoARMT2 MOV r0, r0, LSR #14 ; move ydpi into b0-b12 | UBFX r0, r0, #14, #13 ; move ydpi into b0-b12 ] B %FT20 NSM_xeig [ NoARMT2 MOV r0, r0, LSR #1 ; move xdpi into b0-b12 20 LDR r14, =&00001FFF ; mask for dpi bits AND r0, r0, r14 | UBFX r0, r0, #1, #13 ; move xdpi into b0-b12 20 ] CMP r0, #180 MOVEQ r2, #0 BEQ GoodReadModeVar CMP r0, #22 CMPNE r0, #23 MOVEQ r2, #3 BEQ GoodReadModeVar TEQ r0, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) CMPNE r0, #90 ; or 90 (EQ,CS if so) BNE BadReadModeVar MOVCC r2, #2 ; 45 => xeig=2 MOVCS r2, #1 ; 90 => xeig=1 B GoodReadModeVar NSM_modeflags CMP r14, #SpriteType_New64K MOVEQ r2, #ModeFlag_64k MOVNE r2, #0 B GoodReadModeVar NSM_yshftfactor MOV r2, #0 B GoodReadModeVar RISCOS5SpriteModeWord TST r0, #&F0000 ; validate RO 5 sprite mode word TSTEQ r0, #&0000E MOVNE r14, #SpriteType_Substitute ; and try substitute if bad BNE %BT15 ; From this point on, assume it really is a RISC OS 5 sprite mode word, and throw errors for anything we don't recognise MOV r14, r0, LSR #20 ANDS r14, r14, #127 BEQ BadReadModeVar ; type 0 isn't valid CMP r14, #SpriteType_RO5MAX BGE BadReadModeVar ADR r2, RO5SpriteModeWordRoutines ADD pc, r2, r1, LSL #2 ; and despatch it RO5SpriteModeWordRoutines B RO5SM_modeflags ; 0 ModeFlags (zero) B BadReadModeVar ; 1 ScrRCol Error B BadReadModeVar ; 2 ScrBRow Error B NSM_ncol ; 3 NColour B RO5SM_xeig ; 4 XEigFactor B RO5SM_yeig ; 5 YEigFactor B BadReadModeVar ; 6 LineLength Error B BadReadModeVar ; 7 ScreenSize Error B NSM_yshftfactor ; 8 YShftFactor (zero) B NSM_bpp ; 9 Log2BPP B NSM_bpp ; 10 Log2BPC as Log2BPP B BadReadModeVar ; 11 XWindLimit Error B BadReadModeVar ; 12 YWindLimit Error RO5SM_modeflags AND r2, r0, #&FF00 ; Validate ModeFlags. We only support RGB colourspace, so the only valid ; bits are the RGB and alpha flags TST r2, #&FF00-(ModeFlag_DataFormatSub_RGB+ModeFlag_DataFormatSub_Alpha) BNE BadReadModeVar ; Add in the 64K flag if necessary CMP r14, #SpriteType_New64K ORREQ r2, r2, #ModeFlag_64k B GoodReadModeVar RO5SM_xeig [ NoARMT2 MOV r2, r0, LSR #4 AND r2, r2, #3 | UBFX r2, r0, #4, #2 ] B GoodReadModeVar RO5SM_yeig [ NoARMT2 MOV r2, r0, LSR #6 AND r2, r2, #3 | UBFX r2, r0, #6, #2 ] B GoodReadModeVar ; ***************************************************************************** ; ; SWICheckModeValid - The 'Can I get into this mode?' call ; ; in: r0 = mode you want to get into (may be pointer to mode selector) ; out: C=0 => yes you can, r0 preserved ; C=1 => no you can't ... ; r0 = -1 => ... because the mode doesn't exist ; r1 = substitute mode ; r1 = -2 => not enough memory for even the substitute mode ! ; r0 = -2 => ... because not enough memory ; SWICheckModeValid ROUT VDWS WsPtr Push "r1,r9,lr" BL FindOKMode ; out: r1 = substitute mode BVS %FT90 CMP r1, #&100 ; if it's a mode number BICCC r10, r1, #&80 ; then knock off shadow bit MOVCS r10, r1 ; else don't MOV r11, r10 BL PushModeInfo BVS %FT90 LDR r11, [r13, #wkScreenSize] ; get screen size for this mode ADD r13, r13, #PushedInfoSize ; junk stacked mode table + VIDC info MOV r10, r1, LSR #7 ; 'shadow' bit (NB will be 0 or 1) CMP r10, #2 ; except if its a mode selector MOVCS r10, #0 ; in which case no shadow LDROSB r9, Shadow TEQ r0, r1 ; if substitute different from original MOV r0, r1 ; (always set r0 to be substitute mode) MOVNE r14, #-1 ; then indicate original is silly MOVEQ r14, #0 ; else indicate sensible TEQEQ r9, #0 ; and if shadow 0 MOVEQ r10, #1 ; then force shadow mode LDR r9, [WsPtr, #GraphicsVFeatures] TST r9, #GVDisplayFeature_VariableFramestore MOVNE r9, #-1 ; treat as unlimited memory if variable ; framestore (driver should have ; rejected the VetMode call from ; FindOKMode if it doesn't have enough) LDREQ r9, [WsPtr, #TotalScreenSize] ; maximum allowed amount CMP r9, r11, LSL r10 ; compare with this (*2 if shadow) ; C=0 => No room TEQ r14, #0 ; NZ => silly, CC => no room MOV r1, #-2 ; for if silly mode and bad space Pull r1, EQ ; if not silly, restore old R1 ADDNE r13, r13, #4 ; else junk stacked R1 MOVHI r1, r0 ; silly mode, ok space, R1=subst. mode MOVCC r0, #-2 ; if no room, indicate it MOVNE r0, #-1 ; but silly overrides this Pull "r9, r14" CMP r0, #-2 ; C=1 => bad exit BICCC r14, r14, #C_bit ORRCS r14, r14, #C_bit ExitSWIHandler ; exit point in case of error from FindOKMode or PushModeInfo 90 Pull "r1, r9, r14" MOV r0, #-1 ; indicate no such mode MOV r1, #-2 ; and no substitute mode ORR r14, r14, #C_bit ExitSWIHandler ; ***************************************************************************** ; ; FindOKMode - Convert mode number into an appropriate one for ; this monitor type ; ; in: r0 = original mode specifier ; ; out: If no error, then ; r0 preserved ; r1 = appropriate mode specifier ; V = 0 ; else ; r0 -> error ; r1 corrupted ; V = 1 ; endif ; All other registers preserved ; FindOKMode ROUT Push "r0,r2-r4,r10,r11,lr" BL ReadMonitorType CMP r0, #&100 ; if it's a mode number BICCC r2, r0, #&80 ; then knock off shadow bit MOVCS r2, r0 ; else don't BL OfferModeExtension BNE %FT05 ; service claimed ; mjs Kernel/HAL split ; call GraphicsV vetting routine to possibly disallow mode ; Push "r0-r4, r12" MOV r0,r3 MOV r1,r4 [ {FALSE} ; There are so many pixel formats now that it's better to let the driver do one check itself rather than doing one here and then one in the driver ;we'll do the vet on whether h/w supports the pixel depth ourselves LDR r2,[r0,#VIDCList3_PixelDepth] MOV r3,#1 MOV r3,r3,LSL r2 ; bits per pixel Push "r0-r2" LDR r4, [WsPtr, #CurrentGraphicsVDriver] MOV r4, r4, LSL #24 ORR r4, r4, #GraphicsV_DisplayFeatures BL CallGraphicsV TEQ r4,#0 TSTEQ r3,r1 Pull "r0-r2" MOVEQ r0,#1 BEQ %FT04 ; not supported ] ;now any vet the driver might want to do LDR r4, [WsPtr, #CurrentGraphicsVDriver] MOV r4, r4, LSL #24 ORR r4, r4, #GraphicsV_VetMode BL CallGraphicsV TEQ r4, #0 MOVNE r0, #0 04 CMP r0,#0 Pull "r0-r4,r12" BNE %FT05 ; driver says "Oi, Kernel, No!" ; service claimed and happy HAL so return with this mode MOV r1, r0 CLRV Pull "r0,r2-r4,r10,r11,pc" 05 ; not claimed, so r2 (=mode without shadow) and r3 (=monitortype) are preserved Pull "r0" CMP r0, #&100 ; if a mode selector and not responded to BCS %FT30 ; then return error MOV r10, r2 ; mode without shadow bits MOV r1, r0 ; start from existing mode CMP r3, #NumMonitorTypes ; monitor type must be in range BCS %FT10 ; if not then must issue service CMPCC r10, #NumModes ; and mode must be in range MOVCC r11, #NumModes MLACC r11, r3, r11, r10 ; then form monitortype*numberofmodes + modenumber ADRCCL r14, BigVIDCTable ; point to big table LDRCC r11, [r14, r11, LSL #2] ; and load offset CMPCC r11, #-1 ; CS if mode number or monitor type out of range, or if not known in table BCC %FT20 ; else it's known about, so OK ; known monitor type, but unknown mode, so find substitute ADR r14, SubstModeTable LDR r11, [r14, r3, LSL #2] TEQ r11, #0 ; if r0=0, monitor type is actually unknown - issue service call BEQ %FT10 ADD r1, r11, r14 05 BL FindSubstitute Pull "r2-r4,r10,r11, pc" ; exit VC or VS ; unknown monitor type, so offer service 10 ; if monitor type 7 (file), and requesting mode 7, try some alternative teletext modes before asking for external help TEQ r3, #7 TEQEQ r10, #7 BNE %FT19 Push "r0,r3" ; Build up a temporary mode selector (however, needs to be in a static buffer to allow return via OS_CheckModeValid) ADD r10, WsPtr, #TempModeSelector ADR r0, AltTTXModeProto MOV r2, #AltTTXMode_Size 11 SUBS r2, r2, #4 LDR r3, [r0, r2] STR r3, [r10, r2] BNE %BT11 ; For each resolution, try all the pixel formats supported by the driver ADR r11, AltTTXModes 12 LDMIA r11!, {r3, r4} CMP r3, #-1 BEQ %FT18 ASSERT ModeSelector_XRes = 4 ASSERT ModeSelector_YRes = 8 ASSERT ModeSelector_PixelDepth = 12 MOV r14, #2 ; Start at 4BPP and work up STMIB r10, {r3, r4, r14} 13 LDR r4, [WsPtr, #CurrentGraphicsVDriver] MOV r4, r4, LSL #24 ORR r4, r4, #GraphicsV_PixelFormats BL CallGraphicsV CMP r4, #0 BNE %FT18 ; Look for pixel formats that match the current Log2BPP CMP r1, #0 BEQ %FT18 14 ASSERT GVPixelFormat_NColour = 0 ASSERT GVPixelFormat_ModeFlags = 4 ASSERT GVPixelFormat_Log2BPP = 8 ASSERT GVPixelFormat_Size = 12 LDMIA r0!, {r2-r4} LDR r14, [r10, #ModeSelector_PixelDepth] CMP r4, r14 BNE %FT17 STR r2, [r10, #AltTTXMode_NColour] ORR r3, r3, #ModeFlag_Teletext+ModeFlag_GapMode STR r3, [r10, #AltTTXMode_Flags] Push "r0" BL PushModeInfo ADDVC r13, r13, #PushedInfoSize Pull "r0" MOVVC r1, r10 Pull "r0,r3",VC BVC %FT20 17 SUBS r1, r1, #1 BNE %BT14 ; Try next BPP LDR r14, [r10, #ModeSelector_PixelDepth] ADD r14, r14, #1 CMP r14, #6 STRLO r14, [r10, #ModeSelector_PixelDepth] BLO %BT13 ; Try next resolution B %BT12 18 Pull "r0,r3" MOV r10, #7 19 MOV r2, r10 MOV r1, #Service_ModeTranslation IssueService TEQ r1, #0 MOVEQ r1, r2 ; if claimed, then use module's mode BEQ %FT20 ; unknown monitor type ; if monitor type 7 (file), use substitution table for VGA (reasonable assumption) TEQ r3, #7 ADREQ r1, SubstType3 BEQ %BT05 MOV r1, #0 ; else panic and use mode 0 20 CLRV Pull "r2-r4,r10,r11, pc" 30 ADRL r0, ErrorBlock_ModeNotAvailable ; then return error [ International BL TranslateError | SETV ; error exit ] Pull "r2-r4,r10,r11, pc" SubstModeTable & SubstType01-SubstModeTable & SubstType01-SubstModeTable & SubstType2-SubstModeTable & SubstType3-SubstModeTable & SubstType4-SubstModeTable & 0 & 0 & 0 & SubstType8-SubstModeTable SubstType01 = 0, 8, 12, 15 SubstType2 = 23, 23, 23, 23 SubstType3 = 25, 26, 27, 28 SubstType4 = 29, 30, 31, 32 SubstType8 = 44, 45, 46, 46 ; Alternate teletext modes ; Primary use case for this list of alternatives is when EDID is in use, so we only list modes which might typically show up in EDID. AltTTXModes [ :LNOT: HiResTTX DCD 640, 350 DCD 640, 400 DCD 720, 400 DCD 640, 480 DCD 720, 480 | ; For HiResTTX it makes sense to include the native teletext resolution, so that we can try the other colour depths that are available (failure to get native mode 7 might have only been due to unsupported colour depth) DCD 640, 500 ] DCD 720, 576 DCD 800, 600 DCD 1280, 720 DCD -1 AltTTXModeProto DCD 1 DCD 0 ; width DCD 0 ; height DCD 2 ; Log2BPP DCD -1 DCD VduExt_ModeFlags AltTTXMode_Flags * . - AltTTXModeProto DCD 0 DCD VduExt_ScrRCol DCD 39 DCD VduExt_ScrBRow DCD 24 DCD VduExt_NColour AltTTXMode_NColour * . - AltTTXModeProto DCD 15 DCD -1 AltTTXMode_Size * . - AltTTXModeProto LTORG ; ***************************************************************************** ; ; FindSubstitute - Find substitute mode with right no. of bpp ; ; in: r1 -> table of 4 bytes; subst. modes for 1, 2, 4, 8 bpp respectively ; r10 = mode specifier to be tested (shadow bit clear) ; ; out: If no error, then ; r0 preserved ; r1 = substitute mode ; V=0 ; else ; r0 -> error ; r1 preserved ; endif ; r11 corrupted, all other registers preserved ; FindSubstitute Entry MOV r11, #0 BL PushModeInfoAnyMonitor EXIT VS ; if error, then exit now LDR r11, [r13, #wkLog2BPP] ADD r13, r13, #PushedInfoSize CMP r11, #4 MOVCS r11, #0 Push "r0-r4" LDR r4, [WsPtr, #CurrentGraphicsVDriver] MOV r4, r4, LSL #24 ORR r4, r4, #GraphicsV_DisplayFeatures BL CallGraphicsV ; see if h/w supports this BPP TEQ r4, #0 MOVEQ r2, r1 MOVNE r2, #2_111111 MOV r3, #1 MOV r3, r3, LSL r11 TST r2, r3 MOVEQ r11, #3 ; if not, use 8 BPP (assumed best chance for a mode number) Pull "r0-r4" LDRB r1, [r1, r11] CLRV EXIT ; ***************************************************************************** ; ; ReadMonitorType - Read monitor type ; ; out: R3 = monitor type ; All other registers preserved ; ReadMonitorType Entry "r0-r2" MOV r0, #1 SWI XOS_ReadSysInfo ; out: r0 = mode, r1 = monitortype, r2 = sync MOV r3, r1 ; move into r3 EXIT ; ***************************************************************************** ; ; SWIClaimScreenMemory - Claim unused screen memory (for ADFS etc.) ; ; in: R0 = 0 => release, 1 => claim ; R1 = length you require ; ; out: (for claim) ; C=0 => success ; R1 = actual length ; R2 = address ; ; C=1 => failure ; R1 = length you could have ; SWIClaimScreenMemory ROUT MRS R11, CPSR ; disable IRQs, so can be called from ORR R11, R11, #I32_bit ; an IRQ routine MSR CPSR_c, R11 VDWS WsPtr TEQ R0, #0 ; 0 => release STREQB R0, [WsPtr, #ScreenMemoryClaimed] ; indicate free again ExitSWIHandler EQ ; is claim LDRB R10, [WsPtr, #ScreenMemoryClaimed] TEQ R10, #0 ; already claimed (NZ) MOVNE R1, #0 ; indicate you could have zero bytes BNE %FT10 ; failure exit LDRB R10, [WsPtr, #ExternalFramestore] TEQ R10, #0 BNE %FT15 LDR R10, [WsPtr, #TotalScreenSize] LDR R11, [WsPtr, #ScreenSize] SUB R10, R10, R11 ; amount available CMP R1, R10 ; is this enough MOV R1, R10 ; tell him how much he could have BHI %FT10 ; if not enough, then exit MOV R10, #1 ; indicate now claimed STRB R10, [WsPtr, #ScreenMemoryClaimed] LDR R2, [WsPtr, #DisplayStart] ADD R2, R2, R11 ; R2 -> start of usable area BIC R14, R14, #C_bit ExitSWIHandler 10 ORR R14, R14, #C_bit ExitSWIHandler ; using external framestore - they can have the whole screen memory DA 15 Push "R0,R1,R14" MOV R0, #2 SWI XOS_ReadDynamicArea ; R0 -> start, R1 = len MOVVC R10, R0 MOVVC R11, R1 MOVVS R11, #0 Pull "R0,R1,R14" CMP R1, R11 ; is this enough MOV R1, R11 ; tell him how much he could have BHI %BT10 ; if not enough, then exit MOV R11, #1 ; indicate now claimed STRB R11, [WsPtr, #ScreenMemoryClaimed] MOV R2, R10 BIC R14, R14, #C_bit ExitSWIHandler ; ***************************************************************************** ; ; SWIPlot - PLOT R0,R1,R2 ; ; in: R0 = plot code ; R1 = X coordinate ; R2 = Y coordinate ; ; out: - ; SWIPlot ROUT CMP R0, #256 ; is plot code >= 256 ? ExitSWIHandler CS ; yes, then do nothing ; (for future expansion) BranchNotJustUs %F10, WrchV, R12, R12 LDRB R12, [R11, #OsbyteVars + :INDEX: WrchDest] LDRB R10, [R11, #OsbyteVars + :INDEX: SpoolFileH] ORRS R10, R10, R12 LDREQB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] TEQEQ R10, #0 VDWS WsPtr LDREQ R10, [WsPtr, #CursorFlags] TSTEQ R10, #VduDisabled ; if VDU disabled, go thru normal stuff LDREQ R10, [WsPtr, #ModeFlags] ; if non-graphic, then send TSTEQ R10, #ModeFlag_NonGraphic ; thru normal chans BNE %FT10 Push "R0-R9,R14" BL PreWrchCursor WritePSRc SVC_mode, R14 ; interrupts on LDMFD R13, {R0-R2} MOV R3, R0 ; save plot code MOV R0, R1, LSL #16 MOV R0, R0, ASR #16 ; R0 := sign extended X coord MOV R1, R2, LSL #16 MOV R1, R1, ASR #16 ; R1 := sign extended Y coord MOV R2, R3 MOV R9, #1 ; indicate entry from SWI Plot BL EntryFromSWIPlot BL PostWrchCursor Pull "R0-R9,R14" ExitSWIHandler SWIPlotBadExit STR R0, [R13] ; save error block pointer in saved R0 BL PostWrchCursor Pull "R0-R9,R14" ORR R14, R14, #V_bit ExitSWIHandler 10 Push "R0,R14" SWI XOS_WriteI+25 ; send 25 SWIVC XOS_WriteC ; send plot code ANDVC R0, R1, #&FF SWIVC XOS_WriteC ; send X (lo) MOVVC R0, R1, LSR #8 SWIVC XOS_WriteC ; send X (hi) ANDVC R0, R2, #&FF SWIVC XOS_WriteC ; send Y (lo) MOVVC R0, R2, LSR #8 SWIVC XOS_WriteC ; send Y (hi) Pull "R0,R14", VC ; if no error, pull stacked R0 and R14 ExitSWIHandler VC ADD R13, R13, #4 ; if error, junk stacked R0 Pull "R14" ORR R14, R14, #V_bit ; and set V bit in link ExitSWIHandler ; ***************************************************************************** ; ; SWIRemoveCursors - Remove input and output cursors for screen bashing ; ; out: All registers preserved (R10-R12 preserved by Sam) ; SWIRemoveCursors Push "R0-R4,R6,R8-R9,R14" VDWS WsPtr BL PreWrchCursor Pull "R0-R4,R6,R8-R9,R14" ExitSWIHandler ; ***************************************************************************** ; ; SWIRestoreCursors - Restore input and output cursors after screen bash ; ; out: All registers preserved (R10-R12 preserved by Sam) ; SWIRestoreCursors Push "R0-R4,R6,R8-R9,R14" VDWS WsPtr BL PostWrchCursor Pull "R0-R4,R6,R8-R9,R14" ExitSWIHandler ; ***************************************************************************** ; ; SWIWriteN - Write R1 bytes from address R0 to wrch ; ; in: R0 -> string ; R1 -> number of chars to print ; ; out: - ; SWIWriteN ROUT Push "R0,R1,R14" WritePSRc SVC_mode, R14 ; enable interrupts BranchNotJustUsWrch %F70 ; R11 now points to either vector node or 1st address on chain, as appropriate ; R12 holds current value of this location, to be checked each time MOV R10, R0 10 SUBS R1, R1, #1 BCC %FT90 ; count has expired (V=0) LDRB R0, [R10], #1 Push PC ; need to get to %FT20 - push PC+12 (old ARM) or PC+8 (StrongARM) B PMFWrchDirect MOV R0,R0 ; NOP for PC+8 case 20 BVS %FT90 LDR R0, [R11] TEQ R0, R12 ; vector still the same ? BEQ %BT10 ; yes, then loop B %FT75 ; no, do rest with wrch 70 ADDS R10, R0, #0 ; R10 := R0 and V := 0 75 ADD R11, R10, R1 TEQ R10, R11 80 LDRNEB R0, [R10], #1 SWINE XOS_WriteC MOVVS R10, R11 TEQ R10, R11 BNE %BT80 90 Pull "R0,R1,R14", VC ; if no error, pull stacked R0,R1 & R14 ExitSWIHandler VC ADD R13, R13, #4 ; if error, junk stacked R0 Pull "R1,R14" ORR R14, R14, #V_bit ; and set V bit in link ExitSWIHandler ; ***************************************************************************** ; ; SWIWrite0 - Write a zero-terminated string pointed to by R0 ; ; in: R0 -> string ; ; out: R0 -> char after the zero ; SWIWrite0 ROUT Push "R14" WritePSRc SVC_mode, R10 ; enable interrupts MOV R10, R0 ; R10 -> string BranchNotJustUsWrch %F70 ; R11 now points to either vector node or 1st address on chain, as appropriate ; R12 holds current value of this location, to be checked each time 10 LDRB R0, [R10], #1 CMP R0, #0 BEQ %FT80 ; no more characters Push PC, NE ; need to get to %FT20 - push PC+12 (old ARM) or PC+8 (StrongARM) BNE PMFWrchDirect MOV R0,R0 ;NOP for PC+8 20 BVS %FT80 LDR R0, [R11] TEQ R0, R12 ; vector still the same ? BEQ %BT10 ; yes, then loop ; no, then drop thru ; and do rest with Wrch 70 LDRB R0, [R10], #1 CMP R0, #0 ; (V:=0) SWINE XOS_WriteC BGT %BT70 ; branch if no error and not terminated 80 MOVVC R0, R10 ; if no error, R0 -> char after zero Pull "R14" ORRVS R14, R14, #V_bit ExitSWIHandler ; ***************************************************************************** ; ; SWIWriteS - Write a zero-terminated in-line string ; ; in: R14 -> first char of string (but has PSR bits in it) ; ; out: - ; SWIWriteS ROUT Push "R0, R14" WritePSRc SVC_mode, R10 ; enable interrupts ; return address is on the stack, above our R0, R14, and SWI number LDR R10, [R13, #12] BranchNotJustUsWrch %F70 ; R11 now points to either vector node or 1st address on chain, as appropriate ; R12 holds current value of this location, to be checked each time 10 LDRB R0, [R10], #1 CMP R0, #0 BEQ %FT80 ; no more characters Push PC, NE ; need to get to %FT20 - push PC+12 (old ARM) or PC+8 (StrongARM) BNE PMFWrchDirect MOV R0,R0 ;NOP for PC+8 20 BVS %FT80 LDR R0, [R11] TEQ R0, R12 ; vector still the same ? BEQ %BT10 ; yes, then loop ; no, then drop thru ; and do rest with Wrch 70 LDRB R0, [R10], #1 CMP R0, #0 ; (V:=0) SWINE XOS_WriteC BGT %BT70 ; branch if no error and not terminated 80 BVS %FT90 Pull "R0, R14" 85 TST R14, #T32_bit ADDNE R10, R10, #1 ; if Thumb BICNE R10, R10, #1 ; round up to next halfword boundary ADDEQ R10, R10, #3 ; else BICEQ R10, R10, #3 ; round up to next word boundary STR R10, [R13, #4] ; Poke new address into stack ExitSWIHandler 90 Pull "R11, R14" ; junk the stacked R0 ORR R14, R14, #V_bit 95 LDRB R11, [R10], #1 ; skip to the zero terminator TEQ R11, #0 BNE %BT95 B %BT85 ; ***************************************************************************** ; ; RemovePages - Called by MOS when ChangeDynamicArea reduces the ; amount of screen memory ; ; in: R0 = - number of bytes being removed ; R4 = current size ; ; out: All registers preserved ; RemovePages ROUT Push "R0-R8,R12,R14" BL InsertRemovePagesCommon BNE RemovePages_ExternalFramestore LDR R14, [WsPtr, #ScreenEndAddr] ADD R2, R0, R14 ; end of remaining screen memory ; display starts in pages that remain SUB R5, R3, R0 ; new DisplayStart 05 CMP R5, R14 ; if off end of 1st copy SUBCS R5, R5, R4 ; then repeatedly subtract off new size BCS %BT05 ; until in range Push "R0-R2" MOV R0, R5 ; put new display start in r0 BL SetVinit ; this updates DisplayStart Pull "R0-R2" ADD R3, R3, R4 ; end of area to copy +1 CMP R3, R2 BLS %FT20 ; nothing to copy SUB R4, R3, R0 ; destination end 10 LDMDB R3!, {R5-R8} ; load 4 words (minimum amount) STMDB R4!, {R5-R8} ; store 4 words TEQ R3, R2 BNE %BT10 20 InsertRemovePagesExit LDR R14, [WsPtr, #ScreenEndAddr] LDR R4, [WsPtr, #DisplayScreenStart] SUB R0, R4, R0 LDR R3, [WsPtr, #TotalScreenSize] 25 CMP R0, R14 ; ensure displayscreenstart in range too SUBCS R0, R0, R3 BCS %BT25 BL NewScreenStart 30 BL SetVendDefault Pull "R0-R8,R12,PC" ; in: R0 = - number of bytes being removed ; R4 = current size RemovePages_ExternalFramestore [ {FALSE} ; Should do the copy, but need access to address ADD R3, R3, R4 ; end of area to copy +1 CMP R3, R2 BLS %FT20 ; nothing to copy SUB R4, R3, R0 ; destination end 10 LDMDB R3!, {R5-R8} ; load 4 words (minimum amount) STMDB R4!, {R5-R8} ; store 4 words TEQ R3, R2 BNE %BT10 20 ] InsertRemovePages_ExternalFramestoreExit Pull "R0-R8,R12,PC" ; ***************************************************************************** ; ; InsertPages - Called by MOS when ChangeDynamicArea increases the ; amount of screen memory ; ; in: R0 = number of bytes being added ; R4 = new size ; InsertPages ROUT Push "R0-R8,R12,R14" BL InsertRemovePagesCommon BNE InsertPages_ExternalFramestore SUB R5, R3, R0 ; new DisplayStart STR R5, [WsPtr, #DisplayStart] ADD R2, R3, R1 ; end of block to copy LDR R3, [WsPtr, #ScreenEndAddr] SUB R4, R3, R0 10 TEQ R3, R2 LDMNEIA R3!, {R5-R8} STMNEIA R4!, {R5-R8} BNE %BT10 B InsertRemovePagesExit InsertPages_ExternalFramestore ; Should do copy here B InsertRemovePages_ExternalFramestoreExit ; ***************************************************************************** InsertRemovePagesCommon ROUT VDWS WsPtr LDRB R1, [WsPtr, #ExternalFramestore] TEQ R1, #0 MOVNE PC, R14 LDR R1, [WsPtr, #TotalScreenSize] ; old size LDR R4, =ZeroPage ASSERT (ZeroPage :AND: 255) = 0 STRB R4, [R4, #OsbyteVars + :INDEX:MemDriver] ; indicate default STRB R4, [R4, #OsbyteVars + :INDEX:MemDisplay] ; for both of these LDR R4, [WsPtr, #VduStatus] ; not shadowing any more BIC R4, R4, #Shadowing STR R4, [WsPtr, #VduStatus] ADD R4, R1, R0 ; length of remaining screen memory STR R4, [WsPtr, #TotalScreenSize] ; new size LDR R3, [WsPtr, #ScreenEndAddr] RSB R5, R4, R3 ; start of remaining screen memory STR R5, [WsPtr, #DriverBankAddr] STR R5, [WsPtr, #DisplayBankAddr] LDR R3, [WsPtr, #DisplayStart] MOV PC, R14 ; ***************************************************************************** ; ; SWIChangedBox - Entry point for SWI OS_ChangedBox ; ; in: R0 = 0 => disable clip box calculations ; 1 => enable clip box calculations ; 2 => reset clip box to null ; -1 => do nothing ; ; out: R0 = old enable state (0 => disabled, 1 => enabled) ; R1 -> clipbox info, consisting of 5 words ; [R1, #0] = disable/enable flag (in bit 0) ; [R1, #4] = internal X-coord of left edge of box ; [R1, #8] = internal Y-coord of bottom edge of box ; [R1, #12] = internal X-coord of right edge of box ; [R1, #16] = internal Y-coord of top edge of box ; SWIChangedBox ROUT VDWS WsPtr MOV R1, WsPtr LDR R10, [R1, #ClipBoxEnable]! ; R10 = old state, R1 -> state CMP R0, #2 ; known reason ? BHI %FT10 ; no, then just read state BEQ %FT20 ; reset rectangle to null STR R0, [R1] ; then store R0 in ClipBoxEnable WritePSRc SVC_mode + I_bit, R11 ; disable IRQs to update CursorFlags TST R0, #1 LDR R0, [WsPtr, #CursorFlags] BICEQ R0, R0, #ClipBoxEnableBit ORRNE R0, R0, #ClipBoxEnableBit STR R0, [WsPtr, #CursorFlags] 10 MOV R0, R10 ; R0 = old state ExitSWIHandler 20 Push "R4-R7" ADR R0, NullRectangle LDMIA R0, {R4-R7} STMIB R1, {R4-R7} ; store over coordinates Pull "R4-R7" B %BT10 NullRectangle & &7FFFFFFF, &7FFFFFFF, &80000000, &80000000 ; ***************************************************************************** ; ; SetClipBoxToFullScreen - Called by FF ; ; in: WsPtr -> VduDriverWorkSpace ; ; out: R0-R4 corrupted ; PSR preserved ; ASSERT YWindLimit = XWindLimit +4 SetClipBoxToFullScreen ROUT ADD R4, WsPtr, #XWindLimit LDMIA R4, {R2, R3} MOV R0, #0 MOV R1, #0 ADD R4, WsPtr, #ClipBoxCoords STMIA R4, {R0-R3} MOV PC, R14 ; ***************************************************************************** ; ; MergeClipBox - Merge a given rectangle into clip box ; ; in: R0..R3 = Left, bottom, right, top of rectangle to merge ; WsPtr -> VduDriverWorkSpace ; ; out: All registers preserved ; MergeClipBox ROUT Push "R4-R8, R14" ADD R8, WsPtr, #ClipBoxCoords LDMIA R8, {R4-R7} BL MergeClipBoxes STMIA R8, {R4-R7} Pull "R4-R8, PC" MergeClipBoxes ROUT CMP R0, R4 MOVLT R4, R0 CMP R1, R5 MOVLT R5, R1 CMP R2, R6 MOVGT R6, R2 CMP R3, R7 MOVGT R7, R3 MOV PC, R14 ; ***************************************************************************** ; ; DoPlotClipBox - Compute clip box for a PLOT command ; ; in: R2 = plot code ; ; out: R0-R2 preserved ; DoPlotClipBox ROUT TST R2, #3 ; (R2 AND 3)=0 => move operation ADRNE R11, ClipBoxPlotTable LDRNEB R11, [R11, R2, LSR #3] ; get 'type' of this plot TEQNE R11, #0 ; 0 => don't change clip window MOVEQ PC, R14 Push "R0-R2, R14" CMP R11, #3 ; if 1..3 BLS ClipLastR11Points ; then use last R11 points CMP R11, #ClipIndex_Ellipse BCC ClipFullWindow ; flood fill => merge graphics window BEQ ClipEllipse CMP R11, #ClipIndex_LineFill BCC ClipParallelogram BEQ ClipLineFill Pull "R0-R2, PC" ClipIndex_FloodFill * 4 ClipIndex_Ellipse * 5 ClipIndex_Parallelogram * 6 ClipIndex_LineFill * 7 ClipBoxPlotTable = 2,2,2,2,2,2,2,2 ; 00..38 line drawing = 1 ; 40 point plot = ClipIndex_LineFill ; 48 line fill = 3 ; 50 triangle = ClipIndex_LineFill ; 58 line fill = 2 ; 60 rectangle fill = ClipIndex_LineFill ; 68 line fill = ClipIndex_Parallelogram ; 70 parallelogram = ClipIndex_LineFill ; 78 line fill = ClipIndex_FloodFill ; 80 flood fill = ClipIndex_FloodFill ; 88 flood fill = 0,0,0,0,0 ; 90..B0 circle things ; (done in GenCircleParm) = 0 ; B8 block copy/move (done in code) = ClipIndex_Ellipse ; C0 ellipse outline = ClipIndex_Ellipse ; C8 ellipse fill = 0, 0, 0 ; D0..E0 do nothing = 0 ; E8 sprite plot (done in SWI SpriteOp) = 0, 0 ; F0,F8 do nothing ALIGN ClipLastR11Points ROUT ADD R10, WsPtr, #NewPtX BL MergeR11PointsFromR10 Pull "R0-R2, PC" MergeR11PointsFromR10 ROUT Push R14 LDMIA R10, {R4,R5} ; get last point MOV R6, R4 ; right=left MOV R7, R5 ; top=bottom SUBS R11, R11, #1 BEQ %FT10 05 LDMDB R10!, {R0,R1} ; get another point (X,Y) MOV R2, R0 MOV R3, R1 BL MergeClipBoxes SUBS R11, R11, #1 ; one less point to do BNE %BT05 10 ; now clip this to graphics window ADD R10, WsPtr, #GWLCol LDMIA R10, {R0-R3} CMP R4, R0 MOVGE R0, R4 CMP R5, R1 MOVGE R1, R5 CMP R6, R2 MOVLE R2, R6 CMP R7, R3 MOVLE R3, R7 CMP R2, R0 CMPGE R3, R1 BLGE MergeClipBox ; if R>=L and T>=B then merge Pull PC ClipLineFill ROUT ADD R10, WsPtr, #GWLCol LDMIA R10, {R0-R3} ADD R10, WsPtr, #NewPtX LDMIA R10, {R4-R5} CMP R4, R0 ; if point is inside window CMPGE R2, R4 CMPGE R5, R1 CMPGE R3, R5 MOVGE R1, R5 ; then top=bottom=Y MOVGE R3, R5 ; and left=GWLCol, right=GWRCol BLGE MergeClipBox Pull "R0-R2, PC" ClipParallelogram ROUT ADD R10, WsPtr, #OldCsX LDMIA R10, {R0-R5} ; load up last 3 points ClipParallelRegs ADD R6, R0, R4 ; 4th point = 1st + 3rd - 2nd SUB R6, R6, R2 ADD R7, R1, R5 SUB R7, R7, R3 Push "R0-R7" ; stack all four points ADD R10, R13, #6*4 ; point R10 at last point MOV R11, #4 ; 4 points to merge BL MergeR11PointsFromR10 ADD R13, R13, #8*4 ; junk stacked points Pull "R0-R2, PC" ClipEllipse ROUT ADD R10, WsPtr, #OldCsX LDMIA R10, {R0-R5} ; last 3 points (AX,AY,BX,BY,CX,CY) SUB R6, R2, R0 ; R6 = BX-AX ADD R0, R0, R2 ; R0 = AX+BX SUB R0, R0, R4 ; R0 = AX+BX-CX ADD R2, R4, R6 ; R2 = CX+BX-AX SUB R4, R4, R6 ; R4 = CX-(BX-AX) = CX+AX-BX RSB R1, R5, R1, LSL #1 ; R1 = 2*AY-CY MOV R3, R5 ; R3 = CY B ClipParallelRegs ClipFullWindow ROUT ADD R10, WsPtr, #GWLCol ; merge graphics window with LDMIA R10, {R0-R3} ; clip rectangle (which can be larger) BL MergeClipBox Pull "R0-R2, PC" ; ***************************************************************************** ; ; ClipBlockCopyMove - Calculate clip box for block copy/move ; ; in: R0-R7 = SrcL, SrcB, SrcR, SrcT, DestL, DestB, DestR, DestT ; R8 = 0 => move, 2 => copy ; ; out: R0-R7 preserved ; R8-R11 undefined ; ClipBlockCopyMove ROUT Push "R0-R7, R14" ADD R10, R13, #6*4 ; R10 -> last point (DestR,DestT) RSB R11, R8, #4 ; R11 = 4 if move, 2 if copy ; (number of points to merge) BL MergeR11PointsFromR10 Pull "R0-R7, PC" ; ***************************************************************************** ; ; ClipCircle - Add circle bounding box to clip box ; ; in: R0 = radius of circle in square pixels ; R5, R6 = CentreX, CentreY ; R7 = AspectRatio (0 => square, 1 => flat rect, 2 => tall rect) ; ; out: R0-R7 preserved ; R8-R11 undefined ; ClipCircle ROUT Push "R0-R7,R14" CMP R7, #1 MOVEQ R8, R0, LSR #1 ; if flat then dX = rad/2 MOVNE R8, R0 ; else dX = rad MOVHI R9, R0, LSR #1 ; if tall then dY = rad/2 MOVLS R9, R0 ; else dY = rad SUB R0, R5, R8 ; left SUB R1, R6, R9 ; bottom ADD R2, R5, R8 ; right ADD R3, R6, R9 ; top Push "R0-R3" ADD R10, R13, #2*4 ; point R10 at last point MOV R11, #2 ; 2 points to merge BL MergeR11PointsFromR10 ADD R13, R13, #4*4 ; junk stacked points Pull "R0-R7,PC" ; ***************************************************************************** ; ; ClipCursorCell - Add current cursor cell to clip box ; ; in: - ; ; out: All registers preserved ; ClipCursorCell ROUT ASSERT CursorY = CursorX +4 Push "R0-R3, R14" ADD R0, WsPtr, #CursorX LDMIA R0, {R0, R1} MOV R2, R0 ; RCol = LCol MOV R3, R1 ; TRow = BRow BL ClipTextArea Pull "R0-R3, PC" ; ***************************************************************************** ; ; ClipTextArea - Add a text area to the clip box ; ; in: R0 = LCol of area ; R1 = BRow of area ; R2 = RCol of area ; R3 = TRow of area ; ; out: All registers preserved ; ClipTextArea ROUT Push "R0-R3, R14" MOV R0, R0, LSL #3 ; left = LCol*8 MOV R2, R2, LSL #3 ADD R2, R2, #7 ; right = RCol*8 + 7 LDR R14, [WsPtr, #RowMult] MUL R3, R14, R3 ; TRow * RowMult MLA R1, R14, R1, R14 ; (BRow+1) * RowMult LDR R14, [WsPtr, #YWindLimit] SUB R3, R14, R3 ; top = YWindLimit-TRow*RowMult SUB R1, R14, R1 ADD R1, R1, #1 ; bot = YWindLimit-(BRow+1)*Mult+1 BL MergeClipBox Pull "R0-R3, PC" ; ***************************************************************************** ; ; ClipScroll - Add clip box when scrolling ; ; in: R0 = 0 => add text window ; R0 <> 0 => set to full screen ; ; out: All registers preserved ; ClipScroll ROUT Push "R0-R4, R14" CMP R0, #1 ; if scrolling screen BLCS SetClipBoxToFullScreen ; set to full screen ADDCC R4, WsPtr, #TWLCol ; else add text window LDMCCIA R4, {R0-R3} BLCC ClipTextArea Pull "R0-R4, PC" ; ***************************************************************************** ; ; ClipSpritePlot - Compute and merge sprite plot bounding box ; ; in: R0 = unclipped X-coord (internal) ; R1 = clipped topY (internal) ; R2 = width of sprite in words ; R3 = height of sprite -1 ; R4 = GWLCol ; R5 = height reduction ; R6 = GWRCol ; R8 -> sprite ; ; out: All registers preserved ; ClipSpritePlot ROUT Push "R0-R11, R14" ADD R9, R8, #spLBit LDMIA R9, {R9, R10} ; R9 = spLBit; R10 = spRBit ADD R2, R9, R2, LSL #5 ; R2 = width*32+spLBit RSB R10, R10, #32 ; R10 = 32-spRBit SUB R2, R2, R10 ; R2 = width in bits-1 LDR R9, [WsPtr, #Log2BPC] ADD R2, R0, R2, LSR R9 ; R2 = unclipped rightX CMP R0, R4 MOVLT R0, R4 ; R0 = clipped leftX CMP R2, R6 MOVGT R2, R6 ; R2 = clipped rightX SUB R3, R3, R5 ; R3 = no. of lines on screen -1 SUB R1, R1, R3 ; R1 = clipped botY ADD R3, R1, R3 ; R3 = clipped topY CMP R2, R0 ; if right>=left CMPGE R3, R1 ; and top>=bot BLGE MergeClipBox ; then add rectangle Pull "R0-R11, PC" ; ***************************************************************************** ; ; ScreenModeSWI - Entry point for SWI OS_ScreenMode ; ; in: r0 = reason code ; Other registers depend on reason code ; ; out: Depends on reason code ; ScreenModeSWI Entry BL ScreenModeSub PullEnv ORRVS lr, lr, #V_bit ExitSWIHandler MACRO SMEntry $name ASSERT . - ScreenModeSub_Table = ScreenModeReason_$name * 4 B ScreenMode_$name MEND MACRO SMEntry2 $name ASSERT . - ScreenModeSub_Table2 = (ScreenModeReason_$name - ScreenModeReason_RegisterDriver) * 4 B ScreenMode_$name MEND ScreenModeSub CMP r0, #ScreenModeReason_Limit1 ADDCC pc, pc, r0, LSL #2 B %FT10 ScreenModeSub_Table SMEntry SelectMode SMEntry ReturnMode SMEntry EnumerateModes SMEntry SelectMonitorType SMEntry ConfigureAcceleration SMEntry CleanCache SMEntry ForceCleanCache SMEntry CountScreenBanks SMEntry SelectDisplayBank SMEntry SelectVDUBank SMEntry CopyBank SMEntry SelectDevice SMEntry ROL_DeviceDetails SMEntry ModeStringToSpecifier SMEntry ModeSpecifierToString SMEntry SelectModeByString 10 SUB r10, r0, #ScreenModeReason_RegisterDriver CMP r10, #ScreenModeReason_Limit2-ScreenModeReason_RegisterDriver ADDCC pc, pc, r10, LSL #2 B ScreenMode_Unknown ScreenModeSub_Table2 SMEntry2 RegisterDriver SMEntry2 StartDriver SMEntry2 StopDriver SMEntry2 DeregisterDriver SMEntry2 EnumerateDrivers ; unknown OS_ScreenMode reason code ScreenMode_CountScreenBanks ScreenMode_SelectDisplayBank ScreenMode_SelectVDUBank ScreenMode_CopyBank ScreenMode_ROL_DeviceDetails ScreenMode_Unknown ADR r0, ErrorBlock_ScreenModeBadReason ScreenMode_TranslateAndReturnError [ International Push lr BL TranslateError Pull lr ] ScreenMode_ReturnError SETV MOV pc, lr MakeErrorBlock ScreenModeBadReason MakeErrorBlock BadGDriver MakeErrorBlock TooManyGDrivers ;************************************************************************** ; ; ScreenMode_SelectMode - Select a screen mode ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (0) ; r1 = mode specifier ; ; out: r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_SelectMode Entry "r0-r9" WritePSRc SVC_mode, WsPtr ; enable IRQs VDWS WsPtr BL PreWrchCursor ; remove cursor LDR r2, [sp, #1*4] ; reload mode specifier BL ModeChangeSub ; perform mode change BVS %FT90 BL PostWrchCursor ; if no error, then restore cursor CLRV ; indicate no error EXIT ; and exit 90 STR r0, [sp] ; overwrite stacked r0 with error ptr BL PostWrchCursor ; restore cursor SETV ; indicate error EXIT ; and exit ;************************************************************************** ; ; ScreenMode_ReturnMode - Return current screen mode specifier ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (1) ; ; out: r1 = mode specifier ; r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_ReturnMode ROUT VDWS WsPtr LDR r1, [WsPtr, #ModeNo] CLRV MOV pc, lr ;************************************************************************** ; ; ScreenMode_EnumerateModes - Enumerate screen modes ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (2) ; r2 = enumeration index (0 to start from beginning) ; r6 -> block to return data into, or 0 to just count entries ; r7 = size of block if r6<>0, or zero if r6=0 ; ; out: r1 = 0 if service claimed, otherwise r1<>0 ; r2 = updated enumeration index ; r6 = updated block pointer ; r7 = size of remaining free area in block ; r10-r12 may be corrupted ; All other registers are preserved ; ScreenMode_EnumerateModes Entry "r3-r5" MOV r1, #Service_EnumerateScreenModes BL ReadMonitorType GetBandwidthAndSize r4, r5 BL Issue_Service EXIT ;************************************************************************** ; ; ScreenMode_SelectMonitorType - Select current monitor type ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (3) ; r1 = monitor type to set, or -1 to restore from configured value ; ; out: r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_SelectMonitorType Entry "r0" VDWS WsPtr CMP r1, #-1 ; if not restoring configured value BNE %FT10 ; then skip BL Read_Configd_MonitorType ; else read CMOS value (returns in r0) MOV r1, r0 10 STR r1, [WsPtr, #CurrentMonitorType] ; update current value EXIT ;************************************************************************** ; ; ScreenMode_ConfigureAcceleration - Configure screen memory cacheability ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (4) ; r1 = flags: ; bit 0 : set to suspend cached screen until mode change ; bit 1 : set to suspend screen cleaning ; bit 2 : set to disable hardware acceleration ; other : reserved, must be 0 ; or -1 to read current value ; r2 = number of VSyncs between automatic screen cleaning (1-3), or -1 ; to read current value ; ; out: r1 = new flag state ; r2 = new number of VSyncs between automatic screen cleaning ; r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_ConfigureAcceleration ; Screen caching isn't supported yet. Just return dummy values. MOV r1,#1 MOV r2,#1 MOV pc,lr ;************************************************************************** ; ; ScreenMode_CleanCache - Clean screen memory from cache, if cache enabled ; ScreenMode_ForceCleanCache - Force clean of screen memory from cache ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (5 or 6) ; ; out: r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_CleanCache ScreenMode_ForceCleanCache ; Screen caching isn't supported yet. Just do nothing. MOV pc,lr ;************************************************************************** ; ; ScreenMode_SelectDevice ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (11) ; r1 = new device/driver number, or -1 to read current ; ; out: r1 = previous (or current, if reading) driver number ; r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_SelectDevice ROUT Entry "r0,r2-r5" VDWS WsPtr LDR r5, [WsPtr, #CurrentGraphicsVDriver] CMP r1, #-1 MOVEQ r1, r5 CMP r1, r5 EXIT EQ ; Validate this selection CMP r1, #GraphicsVInvalid BEQ %FT01 CMP r1, #MaxGraphicsVDrivers BHS %FT20 LDR r10, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers LDR r11, [r10, r1, LSL #2] CMP r11, #0 LDRNE r0, [r11, #GVDriver_StateFlags] TSTNE r0, #GVDriverState_Started BEQ %FT20 01 CMP r5, #GraphicsVInvalid BEQ %FT10 ! 0, "GVTODO - API to disable a driver" 10 ; Issue pre-changing service call because we're about to change the VDU ; vars MOV r0, #DisplayChanged_PreChanging MOV r2, r1 MOV r1, #Service_DisplayChanged MOV r3, #DisplayChangedSub_ModeChanged IssueService ; Update current driver VDU var STR r2, [WsPtr, #CurrentGraphicsVDriver] ; Issue service call to indicate change is coming MOV r0, #DisplayChanged_Changing IssueService ; Call InitialiseMode to select a mode to use for this new driver CMP r2, #GraphicsVInvalid BLNE InitialiseMode BVS %FT15 ; Success! MOV r0, #DisplayChanged_Changed IssueService MOV r1, r5 EXIT 15 ; Something went wrong trying to activate the new driver ; Try and restore the old one STR r0, [sp] ; Return the error to the caller STR r5, [WsPtr, #CurrentGraphicsVDriver] MOV r0, #DisplayChanged_Changing MOV r2, r5 IssueService CMP r5, #GraphicsVInvalid BLNE InitialiseMode ; TODO - Try harder if this 2nd call fails (e.g. try all drivers in turn) MOV r0, #DisplayChanged_Changed IssueService MOV r1, r5 SETV EXIT 20 PullEnv ADR r0, ErrorBlock_BadGDriver B ScreenMode_TranslateAndReturnError ;************************************************************************** ; ; ScreenMode_ModeStringToSpecifier ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (13) ; r1 = pointer to mode string ; r2 = pointer to mode specifier to fill in ; r3 = size of mode specifier ; ; out: r0 = error, or preserved ; r10-r12 may be corrupted ; All other registers preserved ; ; Flags in R8 strtospec_got_xres * 1 ; X encountered strtospec_got_yres * 2 ; Y encountered strtospec_got_colours * 4 ; C, G, or T encountered strtospec_got_layout * 8 ; L encountered strtospec_is_ttx * 16 ; we're selecting a teletext mode strtospec_got_ttx_rcol * 32 ; TX encountered strtospec_got_ttx_brow * 64 ; TY encountered ScreenMode_ModeStringToSpecifier ROUT Entry "r1-r9" MOV r10, r2 ADD r9, r2, #ModeSelector_ModeVars SUBS r3, r3, #ModeSelector_ModeVars+4 ; Must at least be big enough for base block and list terminator BLT strtospec_overflow MOV r0, #ModeSelectorFlags_ValidFormat STR r0, [r2, #ModeSelector_Flags] ; Find first parameter strtospec_findfirst LDRB r0, [r1], #1 CMP r0, #32 BLO strtospec_badstring CMP r0, #"," BEQ strtospec_findfirst ; Is it a mode number? SUB r4, r0, #"0" CMP r4, #9 BHI strtospec_nonumber ; Must have space for at least four mode variables ; NColour, ModeFlags, XEigFactor, YEigFactor SUBS r3, r3, #4*8 BLT strtospec_overflow SUB r1, r1, #1 MOV r0, #10 :OR: (1:SHL:30) ; base 10, 0-255 SWI XOS_ReadUnsigned EXIT VS ; Read the mode variables and use them to initialise the selector MOV r8, r1 MOV r0, r2 MOV r1, #VduExt_XWindLimit SWI XOS_ReadModeVariable ADDVC r4, r2, #1 MOVVC r1, #VduExt_YWindLimit SWIVC XOS_ReadModeVariable ADDVC r5, r2, #1 MOVVC r1, #VduExt_Log2BPP SWIVC XOS_ReadModeVariable MOVVC r6, r2 MOVVC r7, #-1 ASSERT ModeSelector_XRes = 4 ASSERT ModeSelector_YRes = 8 ASSERT ModeSelector_PixelDepth = 12 ASSERT ModeSelector_FrameRate = 16 STMVCIB r10, {r4-r7} MOVVC r1, #VduExt_NColour SWIVC XOS_ReadModeVariable STMVCIA r9!, {r1,r2} MOVVC r1, #VduExt_ModeFlags SWIVC XOS_ReadModeVariable LDRVC lr, =ModeFlag_FullPalette :OR: ModeFlag_64k :OR: ModeFlag_ChromaSubsampleMode :OR: ModeFlag_DataFormat_Mask ANDVC r2, r2, lr ; Only keep the pixel format flags? STMVCIA r9!, {r1,r2} MOVVC r1, #VduExt_XEigFactor SWIVC XOS_ReadModeVariable STMVCIA r9!, {r1,r2} MOVVC r1, #VduExt_YEigFactor SWIVC XOS_ReadModeVariable EXIT VS STMIA r9!, {r1,r2} MOV r1, r8 MOV r8, #0 ; Fall through... strtospec_scanloop ; Process the rest of the string LDRB r0, [r1], #1 CMP r0, #32 BLO strtospec_done CMPNE r0, #"," BEQ strtospec_scanloop strtospec_check ASCII_UpperCase r0, lr CMP R0,#"E" BEQ strtospec_get_eig_factors CMP R0,#"X" BEQ strtospec_get_xres CMP R0,#"Y" BEQ strtospec_get_yres CMP R0,#"C" BEQ strtospec_get_colours CMP R0,#"G" BEQ strtospec_get_greys CMP R0,#"F" BEQ strtospec_get_frame CMP R0,#"L" BEQ strtospec_get_layout CMP R0,#"T" BEQ strtospec_get_ttx_colours ; Fall through... strtospec_badstring PullEnv ADRL r0, ErrorBlock_BadParameters ; Match the *wimpmode error B ScreenMode_TranslateAndReturnError strtospec_overflow PullEnv ADRL r0, ErrorBlock_BuffOverflow B ScreenMode_TranslateAndReturnError strtospec_nonumber MOV r4, #-1 ; xres MOV r5, #-1 ; yres MOV r6, #-1 ; bpp MOV r7, #-1 ; framerate ASSERT ModeSelector_XRes = 4 ASSERT ModeSelector_YRes = 8 ASSERT ModeSelector_PixelDepth = 12 ASSERT ModeSelector_FrameRate = 16 STMIB r10, {r4-r7} MOV r8, #0 ; flags of which base parameters we've found, to detect duplicates B strtospec_check strtospec_get_eig_factors LDRB R0,[R1],#1 ASCII_UpperCase R0,R14 CMP R0,#"X" ; only EX EY allowed MOVEQ R0,#VduExt_XEigFactor CMP R0,#"Y" MOVEQ R0,#VduExt_YEigFactor CMPNE R0,#VduExt_XEigFactor BNE strtospec_badstring Push "R0" MOV R0,#&2000000a ; base 10 MOV R2,#3 ; only allow 0-3 (note OS can cope with 4) SWI XOS_ReadUnsigned ADDVS sp,sp,#4 BVS strtospec_badstring Pull "R0" ADR lr, strtospec_scanloop ; Fall through... strtospec_setvar ROUT ; Set mode variable R0 to value R2 ; corrupts r4,r5 ADD r4,r10,#ModeSelector_ModeVars 05 TEQ r4,r9 BEQ %FT10 LDR r5,[r4],#8 CMP r5,r0 BNE %BT05 STR r2,[r4,#-4] MOV pc,lr 10 SUBS r3,r3,#8 BLT strtospec_overflow STMIA r9!,{r0,r2} MOV pc,lr strtospec_get_xres TST r8, #strtospec_got_xres BNE strtospec_badstring ; only one x allowed MOV r0, #10 SWI XOS_ReadUnsigned BVS strtospec_badstring STR r2, [r10, #ModeSelector_XRes] ORR r8, r8, #strtospec_got_xres B strtospec_scanloop strtospec_get_yres TST r8, #strtospec_got_yres BNE strtospec_badstring ; only one y allowed MOV r0, #10 SWI XOS_ReadUnsigned BVS strtospec_badstring STR r2, [r10, #ModeSelector_YRes] ORR r8, r8, #strtospec_got_yres B strtospec_scanloop strtospec_get_frame MOV r0, #10 SWI XOS_ReadUnsigned BVS strtospec_badstring STR r2, [r10, #ModeSelector_FrameRate] B strtospec_scanloop strtospec_get_ttx_colours LDRB R0,[R1] ASCII_UpperCase R0,R14 MOV R2,#strtospec_got_ttx_rcol MOV R4,#VduExt_ScrRCol CMP R0,#"X" MOVNE R2,#strtospec_got_ttx_brow MOVNE R4,#VduExt_ScrBRow CMPNE R0,#"Y" BEQ strtospec_get_ttx_size ; Set the "is teletext" flag ORR R8,R8,#strtospec_is_ttx ; Fall through... strtospec_get_colours ROUT TST r8, #strtospec_got_colours BNE strtospec_badstring ; only one C or G allowed ; only 2,4,16,64,256,4K,32T,32K,64T,64K,16M are valid MOV r0, #10 SWI XOS_ReadUnsigned BVS strtospec_badstring CMP R2,#2 ADREQ R0,pixelformat_2col BEQ strtospec_setpixelformat CMP R2,#4 BNE %FT05 LDRB R0,[R1] ASCII_UpperCase R0,R14 CMP R0,#"K" CMPNE R0,#"T" ADREQ R0,pixelformat_4k ADRNE R0,pixelformat_4col ADDEQ R1,R1,#1 B strtospec_setpixelformat 05 CMP R2,#16 BNE %FT10 LDRB R0,[R1] ASCII_UpperCase R0,R14 CMP R0,#"M" ADREQ R0,pixelformat_32bpp ADRNE R0,pixelformat_16col ADDEQ R1,R1,#1 B strtospec_setpixelformat 10 CMP R2,#64 BNE %FT15 LDRB R0,[R1] ASCII_UpperCase R0,R14 CMP R0,#"K" CMPNE R0,#"T" ADREQ R0,pixelformat_64k ADRNE R0,pixelformat_64col ADDEQ R1,R1,#1 B strtospec_setpixelformat 15 CMP R2,#256 ADREQ R0,pixelformat_256col BEQ strtospec_setpixelformat CMP R2,#32 BNE strtospec_badstring LDRB R0,[R1] ASCII_UpperCase R0,R14 CMP R0,#"K" CMPNE R0,#"T" BNE strtospec_badstring ADR R0,pixelformat_32k ADD R1,R1,#1 strtospec_setpixelformat ROUT ORR r8, r8, #strtospec_got_colours ASSERT GVPixelFormat_NColour = 0 ASSERT GVPixelFormat_ModeFlags = 4 ASSERT GVPixelFormat_Log2BPP = 8 LDMIA r0, {r2,r6-r7} MOV r0, #VduExt_NColour BL strtospec_setvar STR r7, [r10, #ModeSelector_PixelDepth] ; Merge new ModeFlags into any existing ones ADD r4, r10, #ModeSelector_ModeVars TST r8, #strtospec_is_ttx ; ROL spec says these should both be set for teletext ORRNE r6, r6, #ModeFlag_Teletext+ModeFlag_GapMode 05 TEQ r4, r9 BEQ %FT10 LDR r5, [r4], #8 CMP r5, #VduExt_ModeFlags BNE %BT05 LDR r2, [r4,#-4] BIC r2, r2, #ModeFlag_FullPalette :OR: ModeFlag_64k :OR: ModeFlag_GreyscalePalette ORR r2, r2, r6 ; Make sure it's RGB family ASSERT ModeFlag_DataFormatFamily_RGB = 0 TST r2, #ModeFlag_DataFormatFamily_Mask BICNE r2, r2, #ModeFlag_DataFormat_Mask ; Clear family & sub-family STR r2, [r4,#-4] B strtospec_scanloop 10 SUBS r3,r3,#8 BLT strtospec_overflow MOV r0, #VduExt_ModeFlags STMIA r9!,{r0,r6} B strtospec_scanloop strtospec_get_greys TST R8,#strtospec_got_colours BNE strtospec_badstring ; only one C or G allowed MOV r0, #10 SWI XOS_ReadUnsigned BVS strtospec_badstring ; 2, 4, 16, 256, 16M allowed CMP R2,#2 ADREQ R0,pixelformat_2grey BEQ strtospec_setpixelformat CMP R2,#4 ADREQ R0,pixelformat_4grey BEQ strtospec_setpixelformat CMP R2,#256 ADREQ R0,pixelformat_256grey BEQ strtospec_setpixelformat CMP R2,#16 BNE strtospec_badstring LDRB R0,[R1] ASCII_UpperCase R0,R14 CMP R0,#"M" ADREQ R0,pixelformat_24bpp ADRNE R0,pixelformat_16grey ADDEQ R1,R1,#1 B strtospec_setpixelformat strtospec_get_layout ROUT TST R8,#strtospec_got_layout BNE strtospec_badstring ; only one L allowed MOV R7,#0 LDRB R0,[R1],#1 ASCII_UpperCase R0,R14 CMP R0,#"A" ORREQ R7,R7,#ModeFlag_DataFormatSub_Alpha CMPNE R0,#"T" BNE strtospec_badstring LDRB R0,[R1],#1 ASCII_UpperCase R0,R14 CMP R0,#32 BLT strtospec_badstring LDRB R2,[R1],#1 CMP R2,#"G" CMPNE R2,#"g" BNE strtospec_badstring LDRB R2,[R1],#1 ASCII_UpperCase R2,R14 EOR R2,R0,R2 CMP R2,#"R" :EOR: "B" BNE strtospec_badstring CMP R0,#"R" ORREQ R7,R7,#ModeFlag_DataFormatSub_RGB CMPNE R0,#"B" BNE strtospec_badstring ; Merge new ModeFlags into any existing ones ADD r4, r10, #ModeSelector_ModeVars ORR r8, r8, #strtospec_got_layout 05 TEQ r4, r9 BEQ %FT10 LDR r5, [r4], #8 CMP r5, #VduExt_ModeFlags BNE %BT05 LDR r2, [r4,#-4] ; Must be RGB family ASSERT ModeFlag_DataFormatFamily_RGB = 0 TST r2, #ModeFlag_DataFormatFamily_Mask BNE strtospec_badstring BIC r2, r2, #ModeFlag_DataFormatSub_Mask ORR r2, r2, r7 STR r2, [r4,#-4] B strtospec_scanloop 10 SUBS r3,r3,#8 BLT strtospec_overflow MOV r0, #VduExt_ModeFlags STMIA r9!,{r0,r7} B strtospec_scanloop ; R2 = R8 flag bit ; R4 = mode variable number strtospec_get_ttx_size TST r8, r2 BNE strtospec_badstring ADD r1, r1, #1 ORR r8, r8, r2 MOV r0, #10 SWI XOS_ReadUnsigned BVS strtospec_badstring SUBS r2, r2, #1 BLO strtospec_badstring MOV r0, r4 ADR lr, strtospec_scanloop B strtospec_setvar strtospec_done ; Did we find everything necessary? ASSERT ModeSelector_XRes = 4 ASSERT ModeSelector_YRes = 8 ASSERT ModeSelector_PixelDepth = 12 LDMIB r10,{r0-r2} CMP r0,#-1 CMPNE r1,#-1 CMPNE r2,#-1 BEQ strtospec_badstring ; TX and TY are only valid if T is also used EOR r0, r8, #strtospec_is_ttx TST r8, #strtospec_got_ttx_rcol+strtospec_got_ttx_brow TSTNE r0, #strtospec_is_ttx BNE strtospec_badstring ; Terminate the control list and exit MOV r0, #-1 STR r0,[r9] MOV r0, #ScreenModeReason_ModeStringToSpecifier EXIT ASSERT GVPixelFormat_NColour = 0 ASSERT GVPixelFormat_ModeFlags = 4 ASSERT GVPixelFormat_Log2BPP = 8 ASSERT GVPixelFormat_Size = 12 pixelformat_list pixelformat_2col DCD 1,0,0 DCB "C2",0,0 pixelformat_4col DCD 3,0,1 DCB "C4",0,0 pixelformat_16col DCD 15,0,2 DCB "C16",0 pixelformat_64col DCD 63,0,3 DCB "C64",0 pixelformat_256col DCD 255,ModeFlag_FullPalette,3 DCB "C256" pixelformat_4k DCD 4095,0,4 DCB "C4K",0 pixelformat_32k DCD 65535,0,4 DCB "C32K" pixelformat_64k DCD 65535,ModeFlag_64k,4 DCB "C64K" pixelformat_32bpp DCD -1,0,5 DCB "C16M" pixelformat_2grey DCD 1,ModeFlag_GreyscalePalette,0 DCB "G2",0,0 pixelformat_4grey DCD 3,ModeFlag_GreyscalePalette,1 DCB "G4",0,0 pixelformat_16grey DCD 15,ModeFlag_GreyscalePalette,2 DCB "G16",0 pixelformat_256grey DCD 255,ModeFlag_FullPalette+ModeFlag_GreyscalePalette,3 DCB "G256" pixelformat_24bpp DCD 16777215,0,6 DCB "G16M" pixelformat_end spectostr_ex DCB "E" spectostr_x DCB "X",0 spectostr_y DCB "Y",0 ALIGN ;************************************************************************** ; ; ScreenMode_ModeSpecifierToString ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (14) ; r1 = pointer to mode specifier ; r2 = pointer to mode string to fill in ; r3 = size of mode string ; ; out: r3 = -ve size of buffer required, if not big enough ; 0 if string was filled in ; r10-r12 may be corrupted ; All other registers preserved ; ; Write values in the following order for consistency with other code: ; ; X... Y... (C...|G...|T...) [L...] [EX...] [EY...] [F...] [TX...] [TY...] ; ScreenMode_ModeSpecifierToString ROUT Entry "r1-r9",8 CMP r1,#256 BLO %FT90 ; No mode numbers, please! LDR r0,[r1,#ModeSelector_Flags] AND r0,r0,#ModeSelectorFlags_FormatMask CMP r0,#ModeSelectorFlags_ValidFormat BNE %FT90 MOV r4,#0 ; Current string length ADR r0,spectostr_x LDR r5,[r1,#ModeSelector_XRes] BL spectostr_write ADR r0,spectostr_y LDR r5,[r1,#ModeSelector_YRes] BL spectostr_write ; Process the variable list to get the other parameters LDR r8,[r1,#ModeSelector_PixelDepth] ; Get Log2BPP CMP r8,#3 MOVEQ r7,#ModeFlag_FullPalette ; Default ModeFlags MOVNE r7,#0 ; MOV r5,#1 MOV r6,r5,LSL r8 MOV r6,r5,LSL r6 SUB r6,r6,#1 ; Default NColour ADD r1, r1, #ModeSelector_ModeVars MOV r9, #-1 ; XEig MOV r10, #-1 ; YEig 10 LDR r0, [r1], #8 CMP r0, #VduExt_ModeFlags LDREQ r7, [r1,#-4] CMP r0, #VduExt_NColour LDREQ r6, [r1,#-4] CMP r0, #VduExt_XEigFactor LDREQ r9, [r1,#-4] CMP r0, #VduExt_YEigFactor LDREQ r10, [r1,#-4] CMP r0, #-1 BNE %BT10 ; Give up now if this is non RGB ASSERT ModeFlag_DataFormatFamily_RGB = 0 TST r7, #ModeFlag_DataFormatFamily_Mask BNE %FT90 ; Stash the original flags for the teletext check Push "r7" ; Mask out the uninteresting bits LDR r0,=ModeFlag_FullPalette :OR: ModeFlag_64k :OR: ModeFlag_ChromaSubsampleMode :OR: ModeFlag_DataFormat_Mask AND r7,r7,r0 ; Determine the colour format ADR r0,pixelformat_list 20 LDMIA r0!,{r5,r11,lr} CMP r5,r6 AND r5,r7,#ModeFlag_FullPalette :OR: ModeFlag_64k :OR: ModeFlag_GreyscalePalette CMPEQ r5,r11 CMPEQ r8,lr LDR r5,[r0],#4 BEQ %FT30 ADR r5,pixelformat_end CMP r0,r5 BNE %BT20 ADD sp,sp,#4 ; junk r7 B %FT90 30 ; Munge string to say 'T' if it's teletext ; This will also remove the grey-ness from greyscale teletext... but ; we don't support those at the moment anyway (could perhaps use 'TG'?) Pull "r7" TST r7, #ModeFlag_Teletext BICNE r5,r5,#&FF ORRNE r5,r5,#'T' MOV r6,#0 STMIA sp,{r5,r6} ; Push string onto stack to get it null terminated MOV r0,sp BL spectostr_writestr ; Write L... if necessary ANDS r14,r7,#ModeFlag_DataFormatSub_Mask BEQ %FT40 ASSERT ModeFlag_DataFormatSub_Mask = &C:SHL:12 SUB r14,r14,#1:SHL:14 ADR r0,spectostr_l ADD r0,r0,r14,LSR #14-3 BL spectostr_writestr 40 ; Write eigen values CMP r9,#-1 ADR r0,spectostr_ex MOV r5,r9 BLNE spectostr_write CMP r10,#-1 ADR r0,spectostr_ey MOV r5,r10 BLNE spectostr_write ; Write the framerate FRAMLDR r1 LDR r5,[r1,#ModeSelector_FrameRate] ADR r0,spectostr_f CMP r5,#-1 BLNE spectostr_write ; Write text resolution if teletext mode TST r7,#ModeFlag_Teletext BEQ %FT60 ADD r1,r1,#ModeSelector_ModeVars 50 LDR r14,[r1],#8 CMP r14,#-1 BEQ %FT60 ADR r0,spectostr_tx CMP r14,#VduExt_ScrRCol ADRNE r0,spectostr_ty CMPNE r14,#VduExt_ScrBRow BNE %BT50 LDR r5,[r1,#-4] ADD r5,r5,#1 ADR lr,%BT50 B spectostr_write 60 ; Finish CMP r4,r3 MOV r0,#0 STRLTB r0,[r2,r4] ; Terminate string if space available ADD r4,r4,#1 SUBGE r0,r0,r4 FRAMSTR r0,,r3 ; Set to 0 or -(total length) MOV r0,#ScreenModeReason_ModeSpecifierToString CLRV EXIT spectostr_ey DCB "EY",0 spectostr_f DCB "F",0 spectostr_tx DCB "TX",0 spectostr_ty DCB "TY",0 ALIGN 90 PullEnv ADRL r0, ErrorBlock_BadParameters B ScreenMode_TranslateAndReturnError spectostr_write ROUT ; Write string R0 followed by number R5 ; R0 corrupted Push "lr" BL spectostr_writestr Push "r1-r5" ADD r0,sp,#4*4 MOV r2,#-1 MOV r3,#4 MOV r4,#ConvertToCardinal SWI XOS_ConvertVariform MVN r2,r2 ; Get length, excluding terminator LDMIB sp,{r1,r3-r4} ; get stacked r2, r3-r4 ADD r1,r1,r4 ; Position to write to ADD r4,r4,r2 ; Increment written length STR r4,[sp,#12] CMP r4,r3 ; Is there space? ADD r0,sp,#4*4 MOV r3,#4 MOV r4,#ConvertToCardinal SWILE XOS_ConvertVariform Pull "r1-r5,pc" spectostr_writestr ROUT ; Write string R0 ; R0 corrupted Push "lr" ; Do we need a leading space? CMP r4,#0 MOVNE lr,#32 BNE %FT10 05 LDRB lr,[r0],#1 CMP lr,#0 Pull "pc",EQ 10 CMP r4,r3 STRLTB lr,[r2,r4] ADD r4,r4,#1 B %BT05 spectostr_l DCB "LTRGB",0,0,0 DCB "LABGR",0,0,0 DCB "LARGB",0,0,0 ;************************************************************************** ; ; ScreenMode_SelectModeByString ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (15) ; r1 = pointer to mode string ; ; out: r0 = error, or preserved ; r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_SelectModeByString ROUT Entry "r1-r3", ModeSelector_MaxSize MOV r0, #ScreenModeReason_ModeStringToSpecifier MOV r2, sp MOV r3, #ModeSelector_MaxSize SWI XOS_ScreenMode MOVVC r0, #ScreenModeReason_SelectMode MOVVC r1, r2 SWIVC XOS_ScreenMode MOVVC r0, #ScreenModeReason_SelectModeByString EXIT ;************************************************************************** ; ; ScreenMode_RegisterDriver ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (64) ; r1 = flags (reserved, sbz) ; r2 = driver name string (static, null-terminated) ; ; out: r0 = driver number ; r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_RegisterDriver ROUT TEQ r1, #0 ADRNEL r0, ErrorBlock_BadParameters BNE ScreenMode_TranslateAndReturnError Entry "r1-r4" LDR r10, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers MOV r4, #0 05 LDR r11, [r10], #4 CMP r11, #0 BEQ %FT10 ADD r4, r4, #1 CMP r4, #MaxGraphicsVDrivers BNE %BT05 ADRL r0, ErrorBlock_TooManyGDrivers PullEnv B ScreenMode_TranslateAndReturnError 10 MOV r3, #GVDriver_Size BL ClaimSysHeapNode EXIT VS LDMIA sp, {r1,r3} ASSERT GVDriver_RegisterFlags = 0 ASSERT GVDriver_Name = 4 ASSERT GVDriver_StateFlags = 8 MOV r11, #0 STMIA r2, {r1,r3,r11} STR r2, [r10, #-4] MOV r0, r4 EXIT ;************************************************************************** ; ; ScreenMode_StartDriver ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (65) ; r1 = driver number ; ; out: r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_StartDriver ROUT Entry "r0-r3" VDWS WsPtr ; Validate driver number CMP r1, #MaxGraphicsVDrivers BHS %FT10 LDR r10, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers LDR r11, [r10, r1, LSL #2] CMP r11, #0 LDRNE r0, [r11, #GVDriver_StateFlags] EORNE r0, r0, #GVDriverState_Started TSTNE r0, #GVDriverState_Started BEQ %FT10 ; Mark as started STR r0, [r11, #GVDriver_StateFlags] ; Issue a service call to indicate new driver is ready to go ; For simplicity ROL's Service_DisplayStatus is used. However the ; display descriptor is empty as we don't (currently) use them. MOV r0, #DisplayStatus_Registered MOV r2, r1 MOV r1, #Service_DisplayStatus ADR r3, dummy_display_descriptor IssueService ; If we don't have a driver yet, use this one LDR r0, [WsPtr, #CurrentGraphicsVDriver] CMP r0, #GraphicsVInvalid MOVEQ r0, #ScreenModeReason_SelectDevice MOVEQ r1, r2 SWIEQ XOS_ScreenMode ; Swallow any error - just because the driver can't be used as the default driver it doesn't mean that it failed to start CLRV EXIT 10 PullEnv ADRL r0, ErrorBlock_BadGDriver B ScreenMode_TranslateAndReturnError dummy_display_descriptor DCD 0 ;************************************************************************** ; ; ScreenMode_StopDriver ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (66) ; r1 = driver number ; ; out: r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_StopDriver ROUT Entry "r0-r3" VDWS WsPtr ; Validate driver number CMP r1, #MaxGraphicsVDrivers BHS %FT10 LDR r10, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers LDR r11, [r10, r1, LSL #2] CMP r11, #0 LDRNE r0, [r11, #GVDriver_StateFlags] TSTNE r0, #GVDriverState_Started BEQ %FT10 ; Deactivate driver if it's currently in use LDR r0, [WsPtr, #CurrentGraphicsVDriver] CMP r0, r1 MOVEQ r0, #ScreenModeReason_SelectDevice MOVEQ r1, #GraphicsVInvalid SWIEQ XOS_ScreenMode ; Give up if the driver failed to stop (shouldn't really happen, as it'll be the driver making the call to StopDriver) STRVS r0, [sp] EXIT VS ; Issue Service_DisplayStatus to indicate driver stopping MOV r0, #DisplayStatus_Deregistered MOV r2, r1 MOV r1, #Service_DisplayStatus MOV r3, #0 IssueService ; Mark as stopped LDR r0, [r11, #GVDriver_StateFlags] BIC r0, r0, #GVDriverState_Started STR r0, [r11, #GVDriver_StateFlags] EXIT 10 PullEnv ADRL r0, ErrorBlock_BadGDriver B ScreenMode_TranslateAndReturnError ;************************************************************************** ; ; ScreenMode_DeregisterDriver ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (67) ; r1 = driver number ; ; out: r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_DeregisterDriver ROUT Entry "r0-r2" ; Validate driver number CMP r1, #MaxGraphicsVDrivers BHS %FT10 LDR r10, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers LDR r2, [r10, r1, LSL #2]! CMP r2, #0 LDRNE r1, [r2, #GVDriver_StateFlags] EORNE r1, r1, #GVDriverState_Started TSTNE r1, #GVDriverState_Started BEQ %FT10 ; Mark as free MOV r1, #0 STR r1, [r10] ; Free the heap block BL FreeSysHeapNode CLRV ; Ignore heap errors, the driver is still freed EXIT 10 PullEnv ADRL r0, ErrorBlock_BadGDriver B ScreenMode_TranslateAndReturnError ;************************************************************************** ; ; ScreenMode_EnumerateDrivers ; ; Internal routine called by ScreenModeSWI ; ; in: r0 = reason code (68) ; r1 = driver number to return details of ; or GraphicsVInvalid to return id of first driver ; r2 = flags (reserved, sbz) ; ; out: r1 = next driver number ; or GraphicsVInvalid if reached end of list ; r2 = driver flags on registration ; r3 = driver name string ; r4 = driver state ; 0 = unallocated/invalid driver (r2, r3 invalid) ; 1 = allocated ; 2 = started ; r10-r12 may be corrupted ; All other registers preserved ; ScreenMode_EnumerateDrivers ROUT ; Validate flags TEQ r2, #0 ADRNEL r0, ErrorBlock_BadParameters BNE ScreenMode_TranslateAndReturnError Entry "r5-r6" ; Return information on requested driver LDR r10, =ZeroPage+VduDriverWorkSpace+GraphicsVDrivers CMP r1, #MaxGraphicsVDrivers LDRLO r11, [r10, r1, LSL #2] MOVHS r11, #0 CMP r11, #0 ASSERT GVDriver_RegisterFlags = 0 ASSERT GVDriver_Name = 4 ASSERT GVDriver_StateFlags = 8 LDMNEIA r11, {r2-r4} ASSERT GVDriverState_Started = 1 ANDNE r4, r4, #1 ADDNE r4, r4, #1 MOVEQ r2, #0 MOVEQ r3, #0 MOVEQ r4, #0 ; Work out next driver number CMP r1, #GraphicsVInvalid MOVEQ r1, #0 BEQ %FT20 10 CMP r1, #MaxGraphicsVDrivers-1 MOVHS r1, #GraphicsVInvalid BHS %FT90 ADD r1, r1, #1 20 LDR r11, [r10, r1, LSL #2] CMP r11, #0 BEQ %BT10 90 EXIT END