; 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 GBLL FixRemovePages FixRemovePages SETL {TRUE} MACRO BranchNotJustUs $label, $vector, $tmp1, $tmp2 MOV R11, #0 [ AssemblingArthur [ $tmp1=R11 LDR R12, [R11, #VecPtrTab+$vector*4]! ; load vector node | LDR R12, [R11, #VecPtrTab+$vector*4] ; load vector, leave R11=0 ] CMP R12, #&03800000 BCC $label | [ Module LDR $tmp1, [R11, #VecPtrTab+$vector*4] ; load vector node LDR R12, [$tmp1] ; get first address on chain EOR $tmp2, R12, #&01000000 CMP $tmp2, #&00020000 BCS $label | LDR $tmp1, [R11, #VecPtrTab+$vector*4] ; load vector node LDR R12, [$tmp1] ; get first address on chain [ $vector=SpriteV EOR $tmp2, R12, #&01600000 | RSB $tmp2, R12, #&01E00000 ] CMP $tmp2, #&10000 BCS $label ] ] MEND MACRO BranchNotJustUsWrch $label BranchNotJustUs $label, WrchV, R11, R14 MEND MACRO SWIEntry $swiname & OS_$swiname & SWI$swiname-(.+4) MEND [ :LNOT: AssemblingArthur SetUpSWIs ROUT LDR R1, =SvcTable ADR R2, SWITable 10 LDMIA R2!, {R3, R4} ; R3 = SWI number; R4 = address offset CMP R3, #-1 ; end of table ? ADDNE R4, R4, R2 ; no, then R4 = address STRNE R4, [R1, R3, LSL #2] BNE %BT10 MOV PC, R14 SWITable SWIEntry ReadVduVariables SWIEntry ReadPalette SWIEntry ReadModeVariable SWIEntry RemoveCursors SWIEntry RestoreCursors SWIEntry CheckModeValid SWIEntry ClaimScreenMemory SWIEntry Plot SWIEntry WriteN SWIEntry Write0 SWIEntry WriteS SWIEntry SetECFOrigin SWIEntry ChangedBox & -1 ] ; ***************************************************************************** ; ; 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 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 ; R0 = (width-(1 or sizex))DIV spacex SUB R7, R3, R1 ; R7 = height-(1-height reduction) DivRem R1, R7, R5, R3 ; 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 [ STB RVVT PixelRate ] SWIRVVTabEnd 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<Y => 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 LDR r11, [WsPtr, #ModeNo] ; get current mode 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 [ ModeSelectors ; 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 ; TMD 09-Dec-93 ; New algorithms for xeig, yeig from Roger: ; xeig = 1: yeig = 1 ; if yres<xres/2 OR yres<400 then yeig = 2 ; if (xres<<xeig)<(yres<<yeig) then xeig = 2 [ RogerEXEY RMVMS_XEigFactor LDR r2, [r0, #ModeSelector_XRes] LDR r11, [r0, #ModeSelector_YRes] CMP r11, r2, LSR #1 ; if yres < xres/2 CMPCS r11, #400 ; or yres < 400 MOVCC r11, r11, LSL #2 ; then yeig = 2 MOVCS r11, r11, LSL #1 ; else yeig = 1 CMP r11, r2, LSL #1 ; if (xres<<1) < (yres<<yeig) MOVHI r2, #2 ; then xeig = 2 MOVLS r2, #1 ; else 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 CMPCS r11, #400 ; or yres < 400 MOVCC r2, #2 ; then yeig = 2 MOVCS r2, #1 ; else yeig = 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 | ; else drop thru into ... ] 11 CMP r0, r11 ; if implicitly asking for current mode (and mode <> mode selector) BEQ RMVForCurrentMode ; then use optimised code 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) ; ; 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 MOVS r14, r0, LSR #27 ; shift type word into b4-b0 BEQ BadReadModeVar ; zero is bad cos mode >= 256 ;if it's an unknown one, apply a substitute CMP r14, #SpriteType_MAX MOVCS r14, #SpriteType_Substitute ; it's a valid type, now branch by the mode variable number 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 ; note, yes - I know this could be type-1, but at some point some new type ; will break the relationship so it's a table from day 1 to cope with this & 0, 1, 2, 3, 4, 5 NSM_eig_mask & &00001FFF NSM_yeig MOV r0, r0, LSR #14 ; move ydpi into b0-b12 B %FT10 NSM_xeig MOV r0, r0, LSR #1 ; move xdpi into b0-b12 10 LDR r14, =&00001FFF ; mask for dpi bits AND r0, r0, r14 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 NSM_yshftfactor MOV r2, #0 ; both these return zero 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 [ ModeSelectors CMP r1, #&100 ; if it's a mode number BICCC r10, r1, #&80 ; then knock off shadow bit MOVCS r10, r1 ; else don't | BIC r10, r1, #&80 ; only use substitute mode (11/8/88) ] 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) [ ModeSelectors 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, #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 [ ModeSelectors CMP r0, #&100 ; if it's a mode number BICCC r2, r0, #&80 ; then knock off shadow bit MOVCS r2, r0 ; else don't | BIC r2, r0, #&80 ] BL OfferModeExtension BNE %FT05 ; service claimed, so return with this number 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" [ ModeSelectors 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 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 ; ***************************************************************************** ; ; 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 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 ; ***************************************************************************** ; ; ReadSyncType - Read sync type ; ; out: R4 = sync type (0 or 1) ; Z set/clear on R4 ; All other registers preserved ; ReadSyncType ENTRY "r0-r2" MOV r0, #1 SWI XOS_ReadSysInfo ; out: r0 = mode, r1 = monitortype, r2 = sync MOVS r4, r2 ; move into r4 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 MOV R11, PC ; disable IRQs, so can be called from TST R11, #I_bit ; an IRQ routine TEQEQP R11, #I_bit 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 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 ; ***************************************************************************** ; ; 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, #Flag_NonGraphic ; thru normal chans BNE %FT10 Push "R0-R9,R14" ADR R14, %FT05 + SVC_mode ; R14 will have I_bit clear ; TMD 16-May-89: Next instruction used to be B PreWrchCursor2, a secondary ; entry point that didn't disable IRQs as they were assumed to be already ; off. However this caused a bug in RISC OS 2.00, since SWIs are now entered ; with the IRQ state of the caller, so this has now been changed back to ; use the primary entry point (PreWrchCursor) which does disable them. B PreWrchCursor ; this exits by MOVS PC, R14 so it ; clears the I_bit for us ; PreWrchCursor also exits with R6 = CursorFlags, needed for the ; EntryFromSWIPlot routine to do clip window calculations if necessary 05 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" TEQP PC, #SVC_mode ; 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) [ StrongARM LDRB R0, [R10], #1 Push PC ; need to get to %FT20 - push PC+12 (old ARM) or PC+8 (StrongARM) [ AssemblingArthur B PMFWrchDirect | LDR PC, =(MOSDriver + MOSPMFWrch) ] MOV R0,R0 ; NOP for PC+8 case | Push PC ; push address of %FT20 LDRB R0, [R10], #1 [ AssemblingArthur B PMFWrchDirect | LDR PC, =(MOSDriver + MOSPMFWrch) ] ] 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" TEQP PC, #SVC_mode ; 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 [ StrongARM BEQ %FT80 ; no more characters Push PC, NE ; need to get to %FT20 - push PC+12 (old ARM) or PC+8 (StrongARM) [ AssemblingArthur BNE PMFWrchDirect | LDRNE PC, =(MOSDriver + MOSPMFWrch) ] MOV R0,R0 ;NOP for PC+8 | Push PC, NE ; push address of %FT20 [ AssemblingArthur BNE PMFWrchDirect | LDRNE PC, =(MOSDriver + MOSPMFWrch) ] B %FT80 ; no more characters ] 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" TEQP PC, #SVC_mode ; enable interrupts BIC R10, R14, #ARM_CC_Mask ; 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 [ StrongARM BEQ %FT80 ; no more characters Push PC, NE ; need to get to %FT20 - push PC+12 (old ARM) or PC+8 (StrongARM) [ AssemblingArthur BNE PMFWrchDirect | LDRNE PC, =(MOSDriver + MOSPMFWrch) ] MOV R0,R0 ;NOP for PC+8 | Push PC, NE ; push address of %FT20 [ AssemblingArthur BNE PMFWrchDirect | LDRNE PC, =(MOSDriver + MOSPMFWrch) ] B %FT80 ; no more characters ] 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 ADD R10, R10, #3 BIC R10, R10, #3 ; round up to next word boundary AND R14, R14, #ARM_CC_Mask ; R14 = user PSR ORR R14, R14, R10 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 [ AssemblingArthur ; ***************************************************************************** ; ; RemovePages - Called by MOS when ChangeDynamicArea reduces the ; amount of screen memory ; ; in: R0 = - number of bytes being removed ; ; out: All registers preserved ; RemovePages ROUT Push "R0-R8,R12,R14" BL InsertRemovePagesCommon ADD R2, R0, #ScreenEndAdr ; end of remaining screen memory [ :LNOT: FixRemovePages CMP R3, R2 BCS %FT50 ; display starts in disappearing pages ] ; display starts in pages that remain SUB R5, R3, R0 ; new DisplayStart [ FixRemovePages 05 CMP R5, #ScreenEndAdr ; 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" | STR R5, [WsPtr, #DisplayStart] ] 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 R4, [WsPtr, #DisplayScreenStart] SUB R0, R4, R0 [ FixRemovePages LDR R3, [WsPtr, #TotalScreenSize] 25 CMP R0, #ScreenEndAdr ; ensure displayscreenstart in range too SUBCS R0, R0, R3 BCS %BT25 ] BL NewScreenStart 30 BL SetVendDefault Pull "R0-R8,R12,PC",,^ [ :LNOT: FixRemovePages ; display starts in disappearing pages 50 ADD R4, R3, R0 ; destination start MOV R0, R3 BL SetVinit ; set vinit and DisplayStart 60 LDMIA R3!, {R5-R8} STMIA R4!, {R5-R8} TEQ R3, #ScreenEndAdr BNE %BT60 B %BT30 ] ; ***************************************************************************** ; ; InsertPages - Called by MOS when ChangeDynamicArea increases the ; amount of screen memory ; ; in: R0 = number of bytes being added ; InsertPages ROUT Push "R0-R8,R12,R14" BL InsertRemovePagesCommon SUB R5, R3, R0 ; new DisplayStart STR R5, [WsPtr, #DisplayStart] ADD R2, R3, R1 ; end of block to copy MOV R3, #ScreenEndAdr SUB R4, R3, R0 10 TEQ R3, R2 LDMNEIA R3!, {R5-R8} STMNEIA R4!, {R5-R8} BNE %BT10 B InsertRemovePagesExit ; ***************************************************************************** InsertRemovePagesCommon ROUT VDWS WsPtr LDR R1, [WsPtr, #TotalScreenSize] ; old size MOV R4, #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 RSB R5, R4, #ScreenEndAdr ; 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 TEQP PC, #SVC_mode + I_bit ; 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" [ ModeSelectors ; ***************************************************************************** ; ; 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 ASSERT ScreenModeReason_SelectMode = 0 ASSERT ScreenModeReason_ReturnMode = 1 ASSERT ScreenModeReason_EnumerateModes = 2 ASSERT ScreenModeReason_SelectMonitorType = 3 ASSERT ScreenModeReason_Limit = 4 ScreenModeSub CMP r0, #ScreenModeReason_Limit ADDCC pc, pc, r0, LSL #2 B ScreenMode_Unknown B ScreenMode_SelectMode B ScreenMode_ReturnMode B ScreenMode_EnumerateModes B ScreenMode_SelectMonitorType ; unknown OS_ScreenMode reason code ScreenMode_Unknown ADR r0, ErrorBlock_ScreenModeBadReason ScreenMode_TranslateAndReturnError [ International Push lr BL TranslateError Pull lr ] ScreenMode_ReturnError SETV MOV pc, lr ; Temporary error blocks, so we don't have to claim Hdr:NewErrors every 5 mins. ErrorBlock_ScreenModeBadReason & 0 = "Zonk:Unknown OS_ScreenMode reason code", 0 ALIGN ;************************************************************************** ; ; 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" TEQP pc, #SVC_mode ; 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 ] ; Should not cause any problems on any machine. STB flag just to be safe though. [ STB :LAND: {TRUE} ; ***************************************************************************** ; ; VIDCDividerSWI - Entry point for SWI OS_VIDCDivider ; ; in: r0 = Value for divider - 1 ; ; out: r0 = Preserved or error if V set ; VIDCDividerSWI ENTRY "r0-r1,WsPtr" CMP r0, #8 ; Check the value is in range. BCC %FT10 ; Continue if so. PullEnv ; Else return an error. ADR r0, ErrorBlock_BadVIDCDivider ; Get address of error. [ International BL TranslateError ; Translate the error. ] ORR lr, lr, #V_bit ; Return with V bit set. ExitSWIHandler 10 VDWS WsPtr ; Get the VDU work space. LDR r1, [WsPtr, #VIDCControlCopy] ; Get the old control register value. BIC r1, r1, #7:SHL:CR_PixelDivShift ; Mask out the old divider. ORR r1, r1, r0, LSL #CR_PixelDivShift ; ORR in the new... STR r1, [WsPtr, #VIDCControlCopy] ; Write back to work space. MOV r0, #VIDC STR r1, [r0, #0] ; Write to VIDC also. PullEnv ; Done. ExitSWIHandler ] ErrorBlock_BadVIDCDivider & 0 = "BadVIDCDiv:Bad VIDC divider value.", 0 END