; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > $.Source.VduDriver ; ; ARTHUR OPERATING SYSTEM - Vdu Drivers ; ======================= ; ; Vdu driver code - Vdu queue, mode, default windows etc. ; ; Author R C Manby ; Date 5.9.86 ; GBLL NewStyleEcfs NewStyleEcfs SETL 1=1 GBLL DoVdu23_0_12 DoVdu23_0_12 SETL {FALSE} GBLL BleedinDaveBell BleedinDaveBell SETL {TRUE} GBLL LCDPowerCtrl LCDPowerCtrl SETL {TRUE} GET s.vdu.VduDecl GET s.vdu.VduGrafDec MACRO HostVdu Push "R0,R14" LDR R0, [R0, -R0] TEQ R0, #0 ADREQ R0, %FT01 SWIEQ OS_CLI Pull "R0,R14" B %FT02 01 = "HOSTVDU", 0 ALIGN 02 MEND MACRO Print $string Push "R0,R14" LDR R0, [R0, -R0] TEQ R0, #0 BNE %FT01 SWI OS_WriteS = "$string", 0 ALIGN SWI OS_ReadC Pull "R0,R14",CS SWICS OS_BreakPt SWI OS_NewLine 01 Pull "R0,R14" MEND MACRO RMVT $var, $BW [ "$BW"="B" = (wk$var-wkstart)*2 | [ "$BW"="W" = (wk$var-wkstart)*2 +1 | .... Invalid option on RMVT .... ] ] MEND MACRO RVVT $var ASSERT ($var >= 0) :LAND: ($var < &400) :LAND: (($var :AND: 3)=0) = $var :SHR: 2 MEND MACRO IssueService BL Issue_Service MEND MACRO MALIGN $length, $phase LCLA temp LCLS string temp SETA .-ArthurVduDriver [ "$phase"="" string SETS "ALIGN $length" | string SETS "ALIGN $length, $phase" ] $string temp SETA .-ArthurVduDriver-temp [ temp=0 ! 0, string :CC: " fitted exactly" | ! 0, string :CC: " wasted " :CC: :STR: temp ] MEND [ ModeSelectors ; Macro to load up video bandwidth and video memory size MACRO GetBandwidthAndSize $bw, $size [ MEMC_Type = "IOMD" MOV $size, #0 LDR $bw, [$size, #VideoBandwidth] ; load bandwidth LDR $size, [$size, #VideoSize] ; and total amount of video RAM | LDR $bw, =38400000 ; if no ARM600 then must be MEMC based LDR $size, =480*1024 ] MEND ] ; ***************************************************************************** ; Vdu status bits Vdu2ModeBitPosn * 0 Vdu2Mode * 1 :SHL: Vdu2ModeBitPosn Windowing * 1 :SHL: 3 Shadowing * 1 :SHL: 4 ; ***************************************************************************** ArthurVduDriver ; ***************************************************************************** ; ; VduInit - Once only initialisation of Vdu drivers eg after Break ; ======= ; VduInit ROUT Push R14 MOV R0, #0 STRB R0, [R0, #OsbyteVars + :INDEX: VDUqueueItems] ;purge queue STRB R0, [WsPtr, #ScreenBlankFlag] ; not blanked STR R0, [WsPtr, #CursorCounter] STR R0, [WsPtr, #CursorDesiredState] STR R0, [WsPtr, #VduStatus] STR R0, [WsPtr, #PointerHeights] ; zero all 4 heights STRB R0, [WsPtr, #PointerShapeNumber] ; make sure pointer off STR R0, [WsPtr, #CursorStack] ; 0 bits => on STR R0, [WsPtr, #VduSaveAreaPtr] ; indicate no save area yet STR R0, [WsPtr, #ClipBoxEnable] ; no clip box calculating LDR R0, =RangeC+SpriteReason_SwitchOutputToSprite STR R0, [WsPtr, #SpriteMaskSelect] MOV R0, #InitialCursorFlags ; TMD 25/9/86 STR R0, [WsPtr, #CursorFlags] ADRL R0, NUL ; point to MOV PC,R14 STR R0, [WsPtr, #WrchNbit] ; just in case ... ADRL R0, ExportedHLine STR R0, [WsPtr, #HLineAddr] ADD R0, WsPtr, #FgEcfOraEor STR R0, [WsPtr, #GcolOraEorAddr] MOV R0, #maxmode STR R0, [WsPtr, #MaxMode] ; constant now LDROSB R0, LastBREAK ; is it a hard reset ? TEQ R0, #0 BEQ %FT10 ; [no, don't reset font] [ VIDC_Type = "VIDC20" ; allocate buffer for Tim's whizzy text expansion. This now lives ; in the system heap, unless the claim request fails. If the request ; fails then the pointer points at the original buffer in the Vdu ; driver workspace. ; This allows the user to access depths upto 16 bit per pixel before ; strings things things become afoot at the Circle K. LDR R3, =TextExpandArea_Size BL ClaimSysHeapNode ; allocate buffer for heap data ADDVS R2, WsPtr, #TextExpand STR R2, [WsPtr, #TextExpandArea] [ ModeSelectors LDR R3, =ModeSelector_MaxSize+4 ; get block for two overlapping copies BL ClaimSysHeapNode ; of mode selector, 1 word apart STR R2, [WsPtr, #KernelModeSelector] ] ] ; now reset soft font from hard font MOV R1, #1 ; start at character 1*32 STRB R1, [WsPtr, #ScreenMemoryClaimed] ; can't claim memory till a mode change MOV R2, #7 ; copy 7 pages BL DoResetFont [ VIDC_Type = "VIDC20" [ GammaCorrection MOV r3, #(256+1+3)*4*4+3*256 ; logical and physical copies of both flash states ; plus 3 lookup tables for r,g,b | MOV r3, #(256+1+3)*4*2 ; soft copy of palette (2 flash states) ] BL ClaimSysHeapNode ; this had better succeed! STR r2, [WsPtr, #FirPalAddr] ADD r3, r2, #260*4 STR r3, [WsPtr, #SecPalAddr] ; now initialise entries for pointer palette so they will actually program pointer palettte ; because VDU20 doesn't change pointer palette MOV r3, #&50000000 MOV r4, #&60000000 MOV r5, #&70000000 ADD r2, r2, #260*4 ; store in 1st copy of logical STMDB r2, {r3-r5} ; (last 3 entries) ADD r2, r2, #260*4 STMDB r2, {r3-r5} ; store in 2nd copy of logical [ GammaCorrection ADD r2, r2, #260*4 STMDB r2, {r3-r5} ; store in 1st copy of physical ADD r2, r2, #260*4 STMDB r2, {r3-r5} ; store in 2nd copy of physical ; r2 now points off end of all 4 copies, ie start of rgb tables ; initialise red, green and blue transfer function tables to 1-1 mapping MOV r0, #0 05 STRB r0, [r2, #&200] ; store in blue table STRB r0, [r2, #&100] ; store in green table STRB r0, [r2], #1 ; store in red table, and advance ADD r0, r0, #1 CMP r0, #256 BCC %BT05 ] ] 10 BL SpriteInit LDR R0, [WsPtr, #TotalScreenSize] RSB R0, R0, #ScreenEndAdr STR R0, [WsPtr, #DisplayStart] STR R0, [WsPtr, #DisplayScreenStart] STR R0, [WsPtr, #ScreenStart] STR R0, [WsPtr, #CursorAddr] STR R0, [WsPtr, #InputCursorAddr] Pull PC LTORG ; ***************************************************************************** ; ; InitialiseMode - Select mode number given by ModeNo variable ; ; Called by MOS once before initialisation, and then afterwards ; before printing "RISC OS ..." ; ; in: - ; out: All registers may be corrupted (except R13_svc !) ; InitialiseMode ENTRY [ SoftResets MOV r0, #&FD ; read last reset type MOV r1, #0 MOV r2, #&FF SWI XOS_Byte CMP r1, #SoftReset LDREQ r0, =VduDriverWorkSpace+ModeNo LDREQ r0, [r0] ; use previous mode if a soft reset MOVNE r0, #1 ; otherwise read configured mode SWINE XOS_ReadSysInfo | MOV r0, #1 ; no need to check for soft reset, SWI XOS_ReadSysInfo ; always use configured value ] [ ModeSelectors MOV r1, r0 MOV r0, #ScreenModeReason_SelectMode SWI XOS_ScreenMode EXIT VC | SWI XOS_WriteI+22 SWIVC XOS_WriteC EXIT VC ] MOV r0, #114 ; failed, so get rid of any shadow MOV r1, #1 SWI XOS_Byte SWI XOS_WriteI+22 SWIVC XOS_WriteI+0 ; and if we can't get mode 0, we're really fooked!!! EXIT ; ;------------------------------------------------------------------------------ ; ; Vdu - Main VDU driver entry point ; === Queue up bytes and dispatch via JVec ; ; in: R0 = character to be printed ; ; out: C=1 <=> send character to printer if enabled ; Vdu ROUT MOV R11, #0 ; NB used later in Vdu07 as well LDRB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] MOVS R9, R10, LSL #24 ; move up to top byte (for sign extend) BEQ Vdu07 ; not queueing, then start Vdu sequence ; *****Comment made by DJS: Changing this to fall through if not queueing ; and branch if queueing might be a good idea - it would speed up all ; printable characters and simple cursor movements. LDR R8, [WsPtr, #QOffset] STRB R0, [R8, R9, ASR #24] ; add byte to queue ADD R10, R10, #1 ; move on pointer STRB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] CMP R10, #&100 ; finished sequence ? MOVCC PC, R14 ; no, then return (no printing) Push "R0, R14" BL PreWrchCursor ; exits with R6 = CursorFlags Pull "R0" 05 MOV R14, PC ADD R14, R14, #(VduPrintExit-%BT05-8) ; push address of SEC exit ; (with flags) Push R14 BL Vdu05 BL PostWrchCursor CLC ; also clears V Pull "R14,PC" VduPrintExit ; exit used if print required BL PostWrchCursor SEC ; also clears V Pull PC ; ***************************************************************************** Vdu05 ROUT TST R6, #VduDisabled ; VDU enabled ? LDREQ PC, [WsPtr, #JVec] ; yes, then do it (no printing) ; Queue sequence has just completed, but VDU is disabled ; Only interesting case is VDU 1 (SOH), which must still print ; the character if the printer is enabled LDR R10, [WsPtr, #JVec] ADR R11, SOH TEQ R10, R11 ; JVec -> SOH ? MOVNE PC, R14 ; no, then return (no printing) SOH LDR R1, [WsPtr, #VduStatus] ; in VDU 2 mode ? TST R1, #Vdu2Mode MOVEQ PC, R14 ; no, then return Push R14 BL MOSDoPrint Pull PC, VC ; good exit, so return Pull R14 ; bad exit, return with error B VduBadExit ; ***************************************************************************** Vdu07 ROUT AND R0, R0, #&FF ; Only look at bottom byte! CMP R0,#127 ;If DELETE, change R0 to 32 and MOVEQ R0,#32 ; drop through to control char code CMPNE R0,#31 ;Otherwise, branch to printable char BHI Vdu20 ; code if not a control char ; *****Further desirable change: Make printable characters fall through, ; control characters take the branch - speeding up printable characters is ; important! ADR R10, VduJTb ; Address of beginning of jump table LDR R9, [R10, R0, LSL #2] ; Get routine address from VduJTB STR R9, [WsPtr, #JVec] ; save address ADD R10, R10, #(VduQTb-VduJTb) LDRB R9, [R10, R0] ; Pick up QQ + length of queue RSBS R10, R9, #QQ ; -(length of queue) & test if none STRNEB R10, [R11, #OsbyteVars + :INDEX: VDUqueueItems] ; yes, then set up Osbyte variable ADDNE R9, R9, WsPtr STRNE R9, [WsPtr, #QOffset] ; and QOffset MOVNE PC, R14 Push "R0,R14" BL PreWrchCursor ; exits with R6 = CursorFlags Pull "R0" 10 MOV R14, PC ADD R14, R14, #(VduPrintExit-%BT10-8) ; push address of SEC exit ; (with flags) Push R14 BL Vdu10 BL PostWrchCursor CLC ; also clears V Pull "R14,PC" ; ; This is the only byte of a single byte Vdu sequence ; ; R6 = CursorFlags ; R11 = 0 (used to index VDUqueueItems) ; Vdu10 ROUT TST R6, #CursorsSplit ; are we cursor editing ? BNE Vdu15 Vdu10Continue ; TMD 31/7/87; bug fixed here - chars 8 to 13 should still go to printer if ; enabled, even if VDU is disabled CMP R0, #8 ; is char in range 8-13 ? RSBCSS R1, R0, #13 ; if so then we want to print it LDRCS R1, [WsPtr, #VduStatus] MOVCSS R1, R1, LSR #(Vdu2ModeBitPosn +1) ; providing printer enabled Pull R14, CS ; so pull old R14 TST R6, #VduDisabled ; are we disabled LDREQ PC, [WsPtr, #JVec] ; enabled, so go get em floyd ! TEQ R0, #6 ; disabled, so is it ACK (enable VDU) BICEQ R6, R6, #VduDisabled STREQ R6, [WsPtr, #CursorFlags] NUL ;Does nothing ESC ;Does nothing MOV PC, R14 ; return anyway ; ***************************************************************************** Vdu15 TEQ R0, #13 ; and is it a carriage return ? BNE Vdu10Continue Push "R0, R14" BIC R6, R6, #CursorsSplit ; then stop cursor editing STR R6, [WsPtr, #CursorFlags] MOV R1, #1 ; restore old Reg10Copy BL CursorOnOff Pull "R0, R14" B Vdu10Continue ; ***************************************************************************** Vdu20 ROUT Push "R0,R14" BL PreWrchCursor ; exits with R6 = CursorFlags Pull "R0" 05 MOV R14, PC ADD R14, R14, #(VduPrintExit-%BT05-8) ; push address of SEC exit ; (with flags) Push R14 BL TimWrch BL PostWrchCursor CLC ; also clears V Pull "R14,PC" ; ***************************************************************************** VduJTb ; Table of addresses & NUL ; Does nothing & SOH ; Next char to printer only & STX ; Enable printer & ETX ; Disable printer & EOT ; Write text at text cursor & ENQ ; Write text at graphics cursor & NUL ; Enable VDU drivers & BEL ; Beep & BS ; Cursor left & HT ; Cursor right & VduLF ; Cursor down & VT ; Cursor up & FF ; Clear text area (CLS) & VduCR ; Carriage return & SO ; Page mode on & SI ; Page mode off & DLE ; Clear graphics area (CLG) & DC1 ; Define text colour (COLOUR) & DC2 ; Define graphics colour and action (GCOL) & DC3 ; Define logical colour & VDU20 ; Restore default logical colours & NAK ; Disable VDU drivers & SYN ; Select screen mode (MODE) & ETB ; Reprogram display character (VDU23,...) & CAN ; Define graphics window & EM ; (PLOT k,x,x,y,y) & DefaultWindows ; Restore default windows & ESC ; Does nothing & FS ; Define text window & GS ; Define graphics origin & RS ; Home cursor to "top left" & US ; Move text cursor (TAB x,y) & Delete ; Delete character (127) ASSERT QQ+9 < 256 VduQTb ; QQ + length of queue for each of the above DCB QQ+0, QQ+1, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0 DCB QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0, QQ+0 DCB QQ+0, QQ+1, QQ+2, QQ+5, QQ+0, QQ+0, QQ+1, QQ+9 DCB QQ+8, QQ+5, QQ+0, QQ+0, QQ+4, QQ+4, QQ+0, QQ+2 DCB QQ+0 ; (delete) ALIGN ; ***************************************************************************** WrchNbitTab & Wrch1bit-WrchNbitTab & Wrch2bit-WrchNbitTab & Wrch4bit-WrchNbitTab & Wrch8bit-WrchNbitTab & Wrch16bit-WrchNbitTab & Wrch32bit-WrchNbitTab WrchNbitDoubleTab & Wrch1bitDouble-WrchNbitDoubleTab CursorNbitTab & Cursor1bit-CursorNbitTab & Cursor2bit-CursorNbitTab & Cursor4bit-CursorNbitTab & Cursor8bit-CursorNbitTab & Cursor16bit-CursorNbitTab & Cursor32bit-CursorNbitTab ; ***************************************************************************** ; ; SYN - Perform MODE change ; ; External routine ; ; in: Vdu queue contains mode number ; SYN ROUT ; Select screen mode (MODE) Push lr LDRB R2, [WsPtr, #QQ] ; Read mode number from queue BL ModeChangeSub Pull lr MOVVC pc, lr ; if no error, exit to Vdu ; (which calls PostWrchCursor) ; else drop thru into ... VduBadExit ; jumped to if an error in VDU code Push R0 ; save error pointer BL PostWrchCursor SETV Pull "R0, R14,PC" ModeChangeSub ROUT Push lr MOV r1, #0 STRB r1, [r1, #LCD_Active] ;Default to non-lcd active, single panel (mainly for Stork power-saving info) MOV R1, #Service_PreModeChange IssueService TEQ R1, #0 ; was service claimed ? BNE %FT03 ; no, so continue CMP R0, #0 ; service claimed; generate error ? Pull PC, EQ ; no, just exit (V=0 from CMP) B %FT07 ; yes, then generate error 03 MOV R0, R2 ; put mode (possibly changed) in R0 MOV R2, R0, LSR #7 ; R2 = 0/1 if bit 7 of mode clear/set [ ModeSelectors CMP r2, #2 ; if mode number >= 256 then mode selector MOVCS r2, #0 ; so no shadow ] LDROSB R1, Shadow TEQ R1, #0 ; if shadow 0 then force shadow mode MOVEQ R2, #1 BL FindOKMode ; out: R1 = mode we are going to use BVS %FT07 TEQ R0, R1 ; if substitute mode MOVNE R2, #0 ; then don't use shadow [ ModeSelectors CMP r1, #&100 BICCC r10, r1, #&80 MOVCS r10, r1 | BIC R10, R1, #&80 ] MOV R11, R10 BL PushModeInfo BVS %FT07 ; [probably duff mode selector] LDR R11, [R13, #wkScreenSize] ; get screen size for this mode LDR R9, [WsPtr, #TotalScreenSize] ; maximum allowed amount Push R1 ; save proper mode RSBS R1, R9, R11, LSL R2 ; extra amount we need BLS %FT08 ; enough memory, so skip ; try to extend the amount of screen memory MOV R0, #2 ; expand screen memory SWI XOS_ChangeDynamicArea BVC %FT08 ADD R13, R13, #PushedInfoSize + 1*4 ; junk stacked info + mode no. ADR R0, ErrorBlock_BadMODE [ International BL TranslateError ] 07 SETV ; indicate error Pull PC ; valid mode and enough memory 08 Pull R0 ; restore mode we are using [ ModeSelectors CMP r0, #&100 ; if not mode selector BICCC r0, r0, #&80 ; then knock off shadow bit BCC %FT12 ; it's a mode selector, so copy it to our static mode selector block LDR r1, [WsPtr, #KernelModeSelector] ; point at block SUBS r3, r0, r1 ; if r0 -> 1st mode block position TEQNE r3, #4 ; or r0 -> 2nd mode block position MOVEQ r1, r0 ; then use it in place BEQ %FT09 LDR r3, [WsPtr, #DisplayModeNo] ; else check if current mode is a mode selector SUB r3, r3, r1 ; r3 = offset from start of block CMP r3, #8 ; if 0 or 4 EORCC r3, r3, #4 ; then make 4 or 0 (ie toggle between them) ADDCC r1, r1, r3 ; and add on base ASSERT (ModeSelector_ModeVars+4) :AND: 7 = 0 09 MOV r3, #0 10 LDR r6, [r0, r3] ; copy 1st word - after fixed bit this will be previous var value STR r6, [r1, r3] ADD r3, r3, #4 LDR r6, [r0, r3] ; copy 2nd word - after fixed bit this will be next var index STR r6, [r1, r3] ADD r3, r3, #4 CMP r3, #ModeSelector_ModeVars + 4 ; only exit if we've done the essential bit CMPCS r6, #-1 ; AND we've had a -1 as the var index (NOT as the value) CMPCC r3, #ModeSelector_MaxSize ; OR we've gone off the end of our block BCC %BT10 ; [we haven't, so loop] CMP r3, #ModeSelector_MaxSize ; if we did go off the end MOVCS r6, #-1 STRCS r6, [r1, #ModeSelector_MaxSize-4] ; then terminate it properly MOV r0, r1 ; point at static block 12 | BIC R0, R0, #&80 ; knock out shadow bit ] STR R0, [WsPtr, #DisplayModeNo] ; store the new display mode ; now issue Service_ModeChanging MOV R1, #Service_ModeChanging BL IssueModeService [ LCDPowerCtrl ;Switch LCD off here if it is _not_ an LCD mode MOV R3, #0 LDRB R3, [R3, #LCD_Active] ANDS R0, R3, #&7F ;Pick out the lcd mode bits, ignoring the single/dual panel bit Push "r0-r1" MOVEQ R0, #0 LDREQ R1, =:NOT:(PortableControl_LCDEnable :OR: PortableControl_BacklightEnable) SWIEQ XPortable_Control Pull "r0-r1" ] ; R13 -> mode variables 13 LDR R3, [R13, #wkScreenSize] STR R3, [WsPtr, #ScreenSize] ; store screensize BEFORE calling ; ConvertBankToAddress (was a bug!) TEQ R2, #0 ; Shadowing or not ? LDR R3, [WsPtr, #VduStatus] BICEQ R3, R3, #Shadowing ORRNE R3, R3, #Shadowing STR R3, [WsPtr, #VduStatus] STRB R2, [WsPtr, #ScreenMemoryClaimed] ; only allow ADFS to claim ; if non-shadow (simplifies things!) BL ConvertBankToAddress ; R3 := default start for this bank STR R3, [WsPtr, #DriverBankAddr] STR R3, [WsPtr, #DisplayBankAddr] MOV R6, #0 STRB R6, [R6, #OsbyteVars + :INDEX:MemDriver] ; indicate default STRB R6, [R6, #OsbyteVars + :INDEX:MemDisplay] ; for both of these LDR R6, [R13, #wkModeFlags] STR R6, [WsPtr, #DisplayModeFlags] MOV R2, #wkend-wkdispstart ; number of bytes to do ADD R1, R13, #wkdispstart ADD R4, WsPtr, #PalIndex ; first display mode variable 15 LDR R3, [R1], #4 ; copy variables STR R3, [R4], #4 SUBS R2, R2, #4 ; loop until all done BNE %BT15 ; now set up other mode variables by calling SwitchOutput ADD R3, WsPtr, #VduSaveArea+InitFlag STR R2, [R3] ; indicate uninitialised (R2=0) TST R6, #Flag_Teletext MOVNE R3, #0 ; if teletext, then no save area MOVEQ R3, #1 ; else MOS's save area MOV R1, #0 ; just in case MOV R0, #SpriteReason_SwitchOutputToSprite SWI XOS_SpriteOp ; now create other variables from simple ones LDR R3, [WsPtr, #NColour] STR R3, [WsPtr, #DisplayNColour] ASSERT YWindLimit = XWindLimit +4 ASSERT DisplayYWindLimit = DisplayXWindLimit +4 ADD R0, WsPtr, #XWindLimit LDMIA R0, {R3, R4} ADD R0, WsPtr, #DisplayXWindLimit STMIA R0, {R3, R4} ASSERT YEigFactor = XEigFactor +4 ASSERT DisplayYEigFactor = DisplayXEigFactor +4 ADD R0, WsPtr, #XEigFactor LDMIA R0, {R3, R4} ADD R0, WsPtr, #DisplayXEigFactor STMIA R0, {R3, R4} ASSERT Log2BPP = Log2BPC +4 ADD R0, WsPtr, #Log2BPC LDMIA R0, {R0, R1} ; R0 = Log2BPC; R1 = Log2BPP SUB R3, R3, R0 ; adjust XEig for double pixels ADD R3, R3, R1 STR R3, [WsPtr, #PointerXEigFactor] ; finished doing other variables [ VIDC_Type = "VIDC20" LDROSB R2, TVInterlace TST R2, #1 MOVNE R4, #0 MOVEQ R4, #CR_Interlace | BL ReadSyncType ; out: r4 = configured sync (0 or 1) and NE if 1 MOVNE R4, #CompSync LDROSB R2, TVInterlace TST R2, #1 ORREQ R4, R4, #CR_Interlace ; 0 or &40 ] LDROSB R5, TVVertical MOV R5, R5, LSL #24 ; sign extend to 32 bits [ VIDC_Type = "VIDC20" MOV R5, R5, ASR #24-3 ; and multiply by 8 | MOV R5, R5, ASR #24-3-14 ; and multiply by 8*(2^14) ] LDR R1, [WsPtr, #ModeFlags] TST R1, #Flag_GapMode ; gap mode ? ADDNE R5, R5, R5, ASR #2 ; add on 2 rows if so TST R1, #Flag_DoubleVertical ; if double vertical ADDNE R5, R5, R5 ; then double it ADD R0, R13, #wkwordsize ; R0 -> table of VIDC parms MOV R7, R0 ; keep copy for if we go wrong [ VIDC_Type = "VIDC20" LDR R1, [R0, #(PseudoRegister_DPMSState:SHR:22)-&80*4] ; get DPMS state if specified CMP R1, #-1 ; if not specified MOVEQ R1, #0 ; then use zero ANDNE R1, R1, #3 ; else only use bits 0 and 1 STRB R1, [WsPtr, #ScreenBlankDPMSState] MOV R1, #0 ; always select 24MHz clock to feed into VIDC, and normal syncs | ; now set up the VIDC clock latch, before we program any VIDC registers ; and also set up the sync polarity while we're at it LDR R1, [R0, #(&E0-&80)] ; get CR with clock+sync bits EOR R1, R1, R4 ; adjust vertical/composite flag TST R1, #CompSync ; if doing composite sync BICNE R1, R1, #SyncControlMask ; then ensure normal syncs AND R1, R1, #ClockControlMask :OR: SyncControlMask ASSERT SyncControlShift = ClockControlShift+2 MOV R1, R1, LSR #ClockControlShift ] [ IO_Type <> "IOMD" LDR R3, =VIDCClockSelect STRB R1, [R3] ] [ {FALSE} ; TMD 02-Sep-92: This bit removed - no production h/w has this latch BL ReadMonitorType ; now mute sound pin if not monitortype 0 (sound pin = VGA test pin) TEQ R3, #0 ; if monitortype 0 then program 0 MOVNE R3, #1 ; else program 1 LDR R1, =IOEB_SoundSuppress STRB R3, [R1] ; OK to do this on old machines ] MOV R3, #VIDC ; point to VidC 18 [ VIDC_Type = "VIDC20" MOV R1, #124*4 ; number of bytes to do (register &FC is the pseudo one to tell ; the OS the real VIDC clock rate) | MOV R1, #31*4 ; number of bytes to do (register &FC is the pseudo one to tell ; the OS the real VIDC clock rate) ] [ {FALSE} ;DEBUGGING CODE - DUMPS THE VIDC REGISTER TABLE TO A FILE (DONE FOR LCDSUPPORT) Push "r0-r12" MOV r10, #0 LDRB r10, [r10, #LCD_Active] CMP r10, #2 Pull "r0-12", NE BNE %FT20 MOV r10, r0 MOV r11, r1 ! 0, "**** WARNING: VIDC List debugging assembled in ****" MOV r0, #&80 ADR r1, DbgFilename SWI XOS_Find Pull "r0-r12", VS BVS %FT20 MOV r1, r0 MOV r0, #2 MOV r2, r10 MOV r3, r11 SWI XOS_GBPB MOV r0, #0 SWI XOS_Find Pull "r0-r12" DbgFilename = "$.VIDCData", 0 ALIGN ] 20 LDR R2, [R0], #4 ; Get data from table CMP R2, #-1 ; unprogrammed register ? BEQ %FT80 ; then skip AND R6, R2, #&FF000000 TEQ R6, #HorizDisplayStart STREQ R2, [WsPtr, #CursorFudgeFactor] ; save for later ! 25 CMP R6, #VertiBorderStart RSBCSS R14, R6, #VertiCursorEnd BCC %FT40 ; not a vertical register ; programming one of the registers affected by *TV SUB R8, R2, R5 ; subtract offset TEQ R6, #VertiDisplayStart ; test for display start BICEQ R14, R8, #&FF000000 ; get rid of register bits STREQ R14, [WsPtr, #VertAdjust] ; save for pointer programming EOR R14, R8, R2 ; see if now programming different reg MOVS R14, R14, LSR #24 ; zero if OK MOVNE R5, #0 ; we've gone wrong, so set 0 adjust MOVNE R0, R7 ; and go back to the beginning BNE %BT18 MOV R2, R8 ; otherwise update register 40 [ VIDC_Type = "VIDC20" TEQ R6, #HorizSyncWidth ; if h.sync width register STREQ R2, [WsPtr, #HSWRSoftCopy] ; then save for DPMS stuff TEQ R6, #VertiSyncWidth ; likewise v.sync width STREQ R2, [WsPtr, #VSWRSoftCopy] TEQ R6, #VIDCExternal ; check for external register (which contains syncs) BNE %FT50 Push "r4" BL ReadSyncType Pull "r4" BICNE R2, R2, #(Ext_HSYNCbits :OR: Ext_VSYNCbits) ; if composite sync then don't invert syncs ORRNE R2, R2, #Ext_InvertCompVSYNC :OR: Ext_InvertCompHSYNC ; and force both syncs to be composite (because of lack of ; swap in A540 VIDC card) B %FT75 50 TEQ R6, #VIDCFSyn BNE %FT60 LDR R8, =FSyn_ResetValue ; set test bits on, and r > v STR R8, [R3] ; we may need some delay in here... LDR R8, =FSyn_ClearR :OR: FSyn_ClearV :OR: FSyn_ForceLow :OR: FSyn_ForceHigh ORR R2, R2, R8 BIC R2, R2, #FSyn_ForceHigh ; force test bits on, except this one STR R2, [R3] ; we may also need some delay in here... BIC R2, R2, R8 ; remove test bits B %FT75 60 [ MEMC_Type = "IOMD" TEQ r6, #VIDCDataControl BNE %FT65 BIC r2, r2, #DCR_BusBits MOV r14, #0 LDR r14, [r14, #VRAMWidth] CMP r14, #2 ; if using 64-bit wide VRAM ORRCS r2, r2, #DCR_Bus63_0 ; then data on all 64 bits ORRCC r2, r2, #DCR_Bus31_0 ; else for 32-bit wide VRAM or DRAM-only, ; data is on low 32 bits BCC %FT65 ; dual-bank VRAM, so HDWR value needs to be halved MOV r14, r2, LSL #(31-10) ; get HDWR bits at top - NB allow bit 10 to be used here! BIC r2, r2, r14, LSR #(31-10) ; knock off bits TST r14, #1 :SHL: (31-10) ; see if bottom bit would get knocked off ORRNE r2, r2, #DCR_HDis ; if so, then disable HDis mechanism (for eg mode 29) ORREQ r2, r2, r14, LSR #(31-9) ; otherwise, put bits back one bit further down 65 ] ] TEQ R6, #VIDCControl ; if control register BNE %FT75 ; programming control register, so EOR sync/interlace bits, save in soft copy ; then work out CursorFudgeFactor from HorizDisplayStart (in CursorFudgeFactor) ; and bits-per-pixel in control register EOR R2, R2, R4 ; then EOR sync/interlace bits [ VIDC_Type = "VIDC20" [ MorrisSupport ; MOV R10, #IOMD_Base ; LDRB R9, [R10, #IOMD_ID0] ; CMP R9, #&E7 ; LDRB R9, [R10, #IOMD_ID1] ; CMPEQ R9, #&D4 ; MOVNE R9, #32000 ;Morris clocks VIDC20L at 32Mhz ; LDREQ R9, =24000 ;RISC PC clocks VIDC20 at 24MHz MOV R9, #0 LDRB R9, [R9, #IOSystemType] TST R9, #IOST_7500 LDREQ R9, =24000 ;RISC PC clocks VIDC20 at 24MHz MOVNE R9, #32000 ;Morris clocks VIDC20L at 32Mhz ; | LDR R9, =24000 ] STR R9, [WsPtr, #VIDCClockSpeed] [ {FALSE} ; The following code computes the actual pixel rate used, but we don't actually ; need to know this! AND R8, R2, #3 CMP R8, #1 MOVEQ R9, #0 ; dunno what HCLK is, so assume 0 MOVCS R8, #1 ; r-modulus not used, so 1 BCS %FT71 ; PLL not used LDR R10, [R7, #(&D0-&80)*4] ; get FreqSyn register MOV R8, R10, LSR #8 AND R8, R8, #63 ADD R8, R8, #1 ; r8 = v-modulus MUL R9, R8, R9 AND R8, R10, #63 ADD R8, R8, #1 ; r8 = r-modulus 71 MOV R10, R2, LSR #2 AND R10, R10, #7 ADD R10, R10, #1 ; r10 = clock divider MUL R8, R10, R8 ; r8 = global divider DivRem R10, R9, R8, R11 ; r10 = pixel rate in kHz ] STR R2, [WsPtr, #VIDCControlCopy] ; and save in copy [ MEMC_Type = "IOMD" ; now compute FSIZE properly LDR R10, [R7, #(&94-&80)*4] ; get vertidisplayend BIC R10, R10, #&FF000000 LDR R8, [R7, #(&93-&80)*4] ; get vertidisplaystart BIC R8, R8, #&FF000000 SUB R10, R10, R8 ; verti displayed LDR R8, [R7, #(&90-&80)*4] ; verti total BIC R8, R8, #&FF000000 SUB R10, R8, R10 ADD R10, R10, #1 ; vidc parms are n-2, we want n-1 MOV R8, #IOMD_Base STRB R10, [R8, #IOMD_FSIZE] ] LDR R14, [WsPtr, #CursorFudgeFactor] ; R14 = horiz display start (-18) BIC R14, R14, #&FF000000 ADD R14, R14, #(18-17) ; horiz cursor start is programmed with n-17 STR R14, [WsPtr, #CursorFudgeFactor] | ; new algorithm for working out DMA request values from MemorySpeed, ; bits/pixel, pixel rate, and VIDC clock rate ; value n to program is >= (25-11v/m)/8 ; therefore n = 3-INT((11v/m-1)/8), forced into range 0..3, ; where m=memory rate (in kHz) ; v=screen memory rate (in kbytes/second (NOT Kbytes/second)) ; = */48 ; ; ie n = 3-INT((vc*vs*11/(48*m)-1)/8) LDR R9, [R7, #&FC-&80] ; see if the module has told us the real VIDC clock CMP R9, #-1 BNE %FT71 AND R8, R2, #ClockControlMask ; extract VIDC clock bits ADR R9, VIDCClockSpeeds LDR R9, [R9, R8, LSR #ClockControlShift-2] ; R9 = vc (in kHz) 71 STR R9, [WsPtr, #VIDCClockSpeed] ; store away for reading by RVV AND R8, R2, #15 ; pixel rate in 0,1, bits/pixel in 2,3 ADR R10, MemorySpeedTab ; now load memory rate relative to 24M LDRB R8, [R10, R8] ; R8 = vs MUL R8, R9, R8 ; R8 = vc*vs ADD R9, R8, R8, LSL #2 ; R9 = vc*vs*5 ADD R8, R8, R9, LSL #1 ; R8 = vc*vs*11 MOV R9, #0 LDR R9, [R9, #MemorySpeed] ; memory speed in kHz in bottom 16 bits BIC R9, R9, #&FF000000 BIC R9, R9, #&00FF0000 ; R9 = m ADD R9, R9, R9, LSL #1 ; R9 = m*3 MOV R9, R9, LSL #4 ; R9 = m*48 DivRem R10, R8, R9, R11 ; R10 = vc*vs*11/(48*m) SUB R10, R10, #1 ; R10 = vc*vs*11/(48*m)-1 MOVS R10, R10, ASR #3 ; R10 = (vc*vs*11/(48*m)-1)/8 MOVMI R10, #0 ; if going to be > 3 then make 3 RSBS R10, R10, #3 ; R10 = 3-(vc*vs*11/(48*m)-1)/8 MOVMI R10, #0 ; if -ve then make 0 BIC R2, R2, #(3:SHL:4) :OR: ClockControlMask ; knock out FIFO + clock bits ORR R2, R2, R10, LSL #4 ; put result in bits 4,5 STR R2, [WsPtr, #VIDCControlCopy] ; and save in copy LDR R14, [WsPtr, #CursorFudgeFactor] ; R14 = horiz display start BIC R14, R14, #&FF000000 ; lbpp = 0, 1, 2, 3 MOV R14, R14, LSR #14 ; R14 = (m-19, m-11, m-7, m-5)/2 MOV R8, R2, LSR #2 ; put bits 2,3 (lbpp) into bits 0,1 AND R8, R8, #3 ; just look at these bits RSB R8, R8, #3 ; R8 = 3, 2, 1, 0 MOV R9, #1 ADD R14, R14, R9, LSL R8 ; R14 = (m-3, m-3, m-3, m-3)/2 MOV R14, R14, LSL #1 ; R14 = m-3 SUB R14, R14, #3 ; R14 = m-6 STR R14, [WsPtr, #CursorFudgeFactor] ] 75 [ {FALSE} ; *** debugging Push "r0" MOV r0, r2 BL TubeDumpR0 Pull "r0" TubeString r8, r9, r10, " ",cc ; pad out to 10 chars ] [ StorkPowerSave TEQ R6, #VIDCExternal STREQ R2, [WsPtr, #VIDCExternalSoftCopy] TEQ R6, #VIDCFSyn STREQ R2, [WsPtr, #VIDCFSynSoftCopy] TEQ R6, #VIDCControl STREQ R2, [WsPtr, #VIDCControlSoftCopy] ] STR R2, [R3] ; stuff it into VidC 80 SUBS R1, R1, #4 BNE %BT20 ADD R13, R13, #PushedInfoSize ; junk stacked data MOV R0, #(1 :SHL: 10) ; enable video DMA ORR R1, R0, #(1 :SHL: 9) ; refresh only in vflyback SWI XOS_UpdateMEMC MOV R0, #VertiCursorStart + 0 ; program cursor start and end STR R0, [R3] MOV R0, #VertiCursorEnd + 0 ; to zero STR R0, [R3] BL SetVendDefault ; set to ScreenEndAdr-16 MOV R1, #ScreenEndAdr ; need to reload cos corrupt LDR R2, [WsPtr, #TotalScreenSize] SUB R0, R1, R2 ; R0 = Vstart BL SetVstart MOV R0, #0 STRB R0, [WsPtr, #PointerShapeNumber] STR R0, [WsPtr, #TeletextOffset] STR R0, [WsPtr, #CursorStack] ; restore cursor on a mode BL PalInit ; set default palette BL UnblankScreen BL SetMouseRectangle BL FF [ LCDPowerCtrl ;Switch the LCD on if LCD mode Push "r0" MOV R1, #0 LDRB R1, [R1, #LCD_Active] ANDS R1, R1, #&7F ;Check the LCD mode bits only, not the single/dual panel bit LDRNE R0, =(PortableControl_LCDEnable :OR: PortableControl_BacklightEnable) LDRNE R1, =:NOT:(PortableControl_LCDEnable :OR: PortableControl_BacklightEnable) SWINE XPortable_Control Pull "r0" ] MOV R1, #Service_ModeChange BL IssueModeService CLRV ; indicate no error Pull PC ; return to caller MakeErrorBlock BadMODE LTORG [ :LNOT: (VIDC_Type = "VIDC20") MemorySpeedTab = 2, 3, 4, 6, 4, 6, 8, 12, 8, 12, 16, 24, 16, 24, 32, 48 ALIGN VIDCClockSpeeds & 24000 & 25175 & 36000 & 00000 ] ; The following symbols, apart from being used in NColourTable, ; are also used in constructing mode selectors for mode numbers in VduModes NColour_0 * 1 NColour_1 * 3 NColour_2 * 15 NColour_3 * 63 NColour_4 * &FFFF NColour_5 * &FFFFFFFF GET s.vdu.VduModes ; ***************************************************************************** ; ; IssueModeService - Issue service (either ModeChanging or ModeChange) ; ; in: R1 = service code ; ; out: R1 corrupted ; IssueModeService ENTRY "r2,r3" BL ReadMonitorType LDR r2, [WsPtr, #DisplayModeNo] IssueService EXITS ; ***************************************************************************** ; ; PushModeInfo - Push appropriate mode table and VIDC parms ; onto stack, having generated it by possibly issuing service ; ; in: R10 = mode to try for (issue service if not in range 0..20,22..23) ; R11 = mode to use if service not claimed ; R10 and R11 should have bit 7 CLEAR ; ; out: If r10 is an invalid mode selector or invalid new format sprite word then ; V=1 ; r0 -> error ; stack flat ; else ; V=1 ; Stack holds a mode table (size wkwordsize) and VIDC parms (size 32*4) ; (total size PushedInfoSize) ; endif ; All other registers preserved ; PushModeInfoAnyMonitor ROUT SUB sp, sp, #PushedInfoSize Push "r2-r4,r7-r11, lr" MOV r3, #-1 MOV r7, #-1 ; indicate no VIDC stuff necessary [ ModeSelectors CMP r10, #&100 ; is it a mode selector BCS PushModeInfoCommonNoService ] BranchIfKnownMode r10, PushModeInfoCommonNoService B PushModeInfoCommon PushModeInfo ROUT SUB sp, sp, #PushedInfoSize Push "r2-r4,r7-r11, lr" MOV r7, #0 ; indicate VIDC stuff IS necessary BL ReadMonitorType PushModeInfoCommon MOV r2, r10 ; r2 = original mode BL OfferModeExtension [ ModeSelectors BEQ %FT30 ; [service claimed] CMP r2, #&100 ; service not claimed - check if mode selector MOVCC r10, r11 ; unrecognised mode number, so use substitute BCC PushModeInfoCommonNoService ; service not claimed and it's a mode selector - return error "Screen mode not available" ADR r0, ErrorBlock_ModeNotAvailable [ International BL TranslateError ] B %FT40 MakeErrorBlock ModeNotAvailable 30 TEQ r4, #0 ; if r4 returned zero, then a mode selector was used ; either initially or after translation from mode number BEQ %FT35 ; so no ws list LDR r2, [r4, #4]! ; else if claimed, then find ws base mode CMP r2, #&100 ; if ws base mode is a mode selector, it's invalid ANDCC r2, r2, #&7F ; else knock off shadow bit BCC %FT35 MOV r10, r11 ; invalid ws base mode, so pretend service not responded to ; and drop thru to PushModeInfoCommonNoService | MOVNE r10, r11 ; not claimed, so use substitute BNE PushModeInfoCommonNoService LDR r2, [r4, #4]! ; if claimed, then find ws base mode AND r2, r2, #&7F ; no funny business B %FT35 ] PushModeInfoCommonNoService MOV r2, r10 ; else use provided mode MOV r3, #0 MOV r4, #0 35 ADD r9, sp, #9*4 ; adjust for pushed registers [ ModeSelectors :LOR: {TRUE} ; mode selectors or sprite mode words CMP r2, #&100 BCC %FT45 BL GenerateModeSelectorVars ; also copes with new sprite mode word BVC %FT55 ; we got an error 40 SETV Pull "r2-r4,r7-r11,lr" ; restore registers ADD sp, sp, #PushedInfoSize ; junk stack frame MOV pc, lr ; exit VS, r0 -> error 45 ] 47 ADRL r14, Vwstab LDR r10, [r14, r2, LSL #2] ADD r14, r14, r10 ; r14 -> mode table MOV r10, #wkwordsize-4 50 LDR r2, [r14, r10] STR r2, [r9, r10] SUBS r10, r10, #4 BCS %BT50 ; now change any variables specified in workspace block or mode selector overrides 55 TEQ r4, #0 ; if service was claimed ADDNE r4, r4, #4 ; then skip ws base mode BLNE ProcessModeVarPairs ; hopefully, R7 is still set from up there to be NZ if no VIDC stuff necessary CMP r7, #0 Pull "r2-r4,r7-r11, pc", NE ; if no VIDC stuff required, exit (NB V=0 from CMP) ; now set up VIDC table, first from MOS table, then changes from module ; first clear out all 32 (or 128) VIDC entries with -1 ADD R14, R9, #wkwordsize MOV R10, #VIDCParmsSize MOV R8, #-1 60 STR R8, [R14], #4 SUBS R10, R10, #4 BNE %BT60 ; now copy over MOS's table ADD R9, R9, #wkwordsize-VIDCParmsSize TEQ R3, #0 ; if no module claimed service MOVEQ R2, R11 ; then use provided mode BEQ %FT62 [ VIDCListType3 LDR r2, [r3, #0] TEQ r2, #3 ; if VIDC list type 3 BEQ ProcessVIDCListType3 ; then don't copy any MOS data into table, just process list ] LDR r2, [r3, #4] ; else just load VIDC list base mode, and copy MOS's table for that 62 Push R3 BL ReadMonitorType ; get monitor type in R3 CMP R3, #NumMonitorTypes ; monitor type must be in range CMPCC R2, #NumModes ; and mode must be in range MOVCC R11, #NumModes MLACC R11, R3, R11, R2 ; then form monitortype*numberofmodes + modenumber MOVCS R11, #0 ; if illegal then use mode 0 monitortype 0 ADRL R14, BigVIDCTable ; point to big table LDR R11, [R14, R11, LSL #2] ; and load offset CMP R11, #-1 ; if table offset is valid ADDCC R11, R14, R11 ; then add to table address BLCC UpdateVIDCTable ; and fetch data Pull R3 [ VIDC_Type = "VIDC20" TEQ R3, #0 LDRNE R2, [R3, #0] ; get VIDC table type TSTNE R2, #2 ; test for VIDC20 compatible table ADDNE R11, R3, #8 ; if exists BLNE UpdateVIDCTable ; then modify parameters CLRV Pull "R2-R4,R7-R11, PC" ; ignore any second list for the time being (it's all coded in main list) | ; now copy modules changes TEQ R3, #0 ADDNE R11, R3, #8 ; if module list exists, then BLNE UpdateVIDCTable ; modify the table LDRNE R2, [R3, #0] ; get VIDC table type TSTNE R2, #1 ; bit 0 set if has second list BNE %FT70 ; has 2nd list 65 CLRV Pull "R2-R4,R7-R11, PC" ; if no module table, or no second list ; then exit 70 LDR R2, [R11], #4 CMP R2, #-1 BEQ %BT65 ; exit VC if found end of list MOV R7, R2, LSR #24 ; R7=type of data (0=pixel rate,1=sync, 2=real VIDC clock) BIC R2, R2, R7, LSL #24 ; knock out data type ; now the change to allow the real VIDC clock rate to be declared by the module CMP R7, #2 STREQ R2, [R13, #9*4+wkwordsize+&FC-&80] ; store in pseudo-register &FC BEQ %BT70 CMP R7, #1 BHI %BT70 ; if > 1 then unknown, so skip BEQ %FT90 ; if 1 then sync polarity specification ; R2 is requested pixel rate in kHz - scan through available pixel rates to ; find match MOV R3, #-1 ; least error so far MOV R4, #(0 :SHL: ClockControlShift) :OR: 3 ; clock and internal pixel rates merged ; bits 9 and 10 are clock rate ; bits 0 and 1 are internal pixel rate ; 0 => n/3, 1 => n/2, 2 => 2n/3, 3 => n 75 ADRL R9, VIDCClockSpeeds ; point at table of available rates LDR R9, [R9, R4, LSR #ClockControlShift-2] ; get clock rate TST R4, #2 MOVNE R9, R9, LSL #1 ; if bit 1 set then multiply by 2 TST R4, #1 MOVNE R10, R9, LSR #1 ; if bit 0 set then divide by 2 BNE %FT80 ; and skip MOV R7, #3 DivRem R10, R9, R7, R14 ; if bit 0 clear then divide by 3 80 SUBS R14, R10, R2 ; difference between desired and actual MOVEQ R8, R4 BEQ %FT85 ; found exact match, so use it RSBMI R14, R14, #0 ; get absolute error CMP R14, R3 ; if less than least error MOVCC R3, R14 ; then R3 = new least error MOVCC R8, R4 ; and R8 = best fit TST R4, #3 ; if not just tried pixel rate 0 SUBNE R4, R4, #1 ; then try next pixel rate BNE %BT75 ADD R4, R4, #1 :SHL: ClockControlShift ; move to next clock rate TEQ R4, #4 :SHL: ClockControlShift ; if not finished ORRNE R4, R4, #3 ; then set internal pixel rate to 3 BNE %BT75 ; and loop ; R8 is best fit, so store it in the VIDC list 85 ADD R9, R13, #9*4+wkwordsize+&E0-&80 ; point at control register LDR R10, [R9] ; get previously specified CR BIC R10, R10, #ClockControlMask ; knock out clock select BIC R10, R10, #3 ; and pixel rate select ORR R10, R10, R8 STR R10, [R9] B %BT70 ; go back and see if any more ; R2 = sync polarity specification ; bit 0 set => -ve Hsync ; bit 1 set => -ve Vsync 90 ADD R9, R13, #9*4+wkwordsize+&E0-&80 ; point at control register LDR R10, [R9] ; get previously specified CR BIC R10, R10, #SyncControlMask ; knock out sync selects ORR R10, R10, R2, LSL #SyncControlShift ; and insert new ones STR R10, [R9] B %BT70 ; go back and see if any more ] ; ***************************************************************************** ; ; GenerateModeSelectorVars - Work out mode variables from mode selector ; or new format sprite mode word ; ; Note: the algorithms used to generate these variables are duplicated in ; s.vdu.vduswis in the OS_ReadModeVariable code. ; in: r2 = new format sprite word or pointer to mode selector ; r9 -> stack frame to store vars in ; ; out: If valid then ; V=0 ; r0 preserved ; else ; V=1 ; r0 -> error ; endif ; All other registers preserved ; GenerateModeSelectorVars ENTRY "r0,r1,r3-r8,r10-r12" [ ModeSelectors ASSERT ModeSelector_Flags = 0 ASSERT ModeSelector_XRes = 4 ASSERT ModeSelector_YRes = 8 ASSERT ModeSelector_PixelDepth = 12 ] TST r2, #1 ; is it a new format sprite mode word? BNE %FT50 ; [yes, so skip] [ ModeSelectors MOV r0, r2 BL ValidateModeSelector BVS %FT95 ; invalid - return error LDMIB r2, {r4-r6} ; r4 = xres; r5 = yres; r6 = pixdepth STR r6, [r9, #wkLog2BPC] ; log2bpc = log2bpp = pixdepth STR r6, [r9, #wkLog2BPP] ADR lr, NColourTable LDR lr, [lr, r6, LSL #2] ; load NColour value STR lr, [r9, #wkNColour] ADR lr, PalIndexTable LDRB lr, [lr, r6] STR lr, [r9, #wkPalIndex] ADR lr, ECFIndexTable LDRB lr, [lr, r6] STR lr, [r9, #wkECFIndex] MOV lr, #0 STR lr, [r9, #wkYShftFactor] ; yshftfactor = 0 (obsolete) STR lr, [r9, #wkModeFlags] ; modeflags = 0 [ RogerEXEY ; TMD 09-Dec-93 ; New algorithms for xeig, yeig from Roger: ; xeig = 1: yeig = 1 ; if yres> 3) -1 STR r7, [r9, #wkScrRCol] RSB r7, lr, r5, LSR #3 ; scrbrow = (yres >> 3) -1 STR r7, [r9, #wkScrBRow] SUB r7, r4, #1 STR r7, [r9, #wkXWindLimit] ; xwindlimit = xres-1 SUB r7, r5, #1 STR r7, [r9, #wkYWindLimit] ; ywindlimit = yres-1 MOV r7, r4, LSL r6 ; r7 = xres << pixdepth MOV lr, r7, LSR #3 STR lr, [r9, #wkLineLength] ; linelen = (xres << pixdepth) >> 3 MUL r7, r5, r7 ; r7 = (xres * yres) << pixdepth MOV lr, r7, LSR #3 STR lr, [r9, #wkScreenSize] ; screensize = ((xres * yres) << pixdepth) >> 3 ADD r4, r2, #ModeSelector_ModeVars ; now do pairs of mode variables BL ProcessModeVarPairs CLRV EXIT | B %FT90 ; it's not a new format sprite word, and mode selectors not enabled ; so return error ] ; store info for new format sprite word in stack frame 50 MOV r0, #0 STR r0, [r9, #wkYShftFactor] ; yshftfactor = 0 STR r0, [r9, #wkModeFlags] ; modeflags = 0 MOV r0, r2, LSR #27 ; get type CMP r0, #SpriteType_MAX ; check for legality - NB type 0 is illegal because r2>=&100 MOVCS r0, #SpriteType_Substitute ; substitute if unknown ADRL lr, NSM_bpptable-4 LDR r0, [lr, r0, LSL #2] ; get the bpp from table STR r0, [r9, #wkLog2BPC] STR r0, [r9, #wkLog2BPP] ADR r1, NColourTable LDR r1, [r1, r0, LSL #2] STR r1, [r9, #wkNColour] ADR r1, PalIndexTable LDRB r1, [r1, r0] STR r1, [r9, #wkPalIndex] ADR r1, ECFIndexTable LDRB r1, [r1, r0] STR r1, [r9, #wkECFIndex] MOV r1, r2, LSL #(31-13) MOV r1, r1, LSR #(31-13)+1 ; extract xdpi (bits 1..13) TEQ r1, #180 ; 180 => xeig=0 MOVEQ r1, #0 BEQ %FT70 TEQ r1, #22 ; 22/23 => xeig=3 TEQNE r1, #23 MOVEQ r1, #3 BEQ %FT70 TEQ r1, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) CMPNE r1, #90 ; or 90 (EQ,CS if so) BNE %FT80 MOVCC r1, #2 ; 45 => xeig=2 MOVCS r1, #1 ; 90 => xeig=1 70 STR r1, [r9, #wkXEigFactor] MOV r1, r2, LSL #(31-26) MOV r1, r1, LSR #(31-26)+14 ; extract ydpi (bits 14..26) TEQ r1, #180 ; 180 => yeig=0 MOVEQ r1, #0 BEQ %FT71 TEQ r1, #22 ; 22/23 => yeig=3 TEQNE r1, #23 MOVEQ r1, #3 BEQ %FT71 TEQ r1, #(45 :SHL: 2), 2 ; check if 45 (EQ,CC if so) CMPNE r1, #90 ; or 90 (EQ,CS if so) BNE %FT80 MOVCC r1, #2 ; 45 => yeig=2 MOVCS r1, #1 ; 90 => yeig=1 71 STR r1, [r9, #wkYEigFactor] CLRV EXIT 80 ADR r0, ErrorBlock_Sprite_BadDPI 90 [ International BL TranslateError ] 95 STR r0, [sp] ; update saved r0 SETV ; indicate error EXIT NColourTable & NColour_0, NColour_1, NColour_2 & NColour_3, NColour_4, NColour_5 PalIndexTable = 0, 1, 2, 3, 6, 7 ALIGN ; makes ECFIndexTable more accessible ECFIndexTable = 4, 2, 3, 5, 5, 5 ALIGN MakeErrorBlock BadPixelDepth MakeErrorBlock Sprite_BadDPI [ ModeSelectors ; ***************************************************************************** ; ; ValidateModeSelector - Check a mode selector is valid ; ; in: r0 -> mode selector ; ; out: If OK, then ; V=0 ; All registers preserved ; else ; V=1 ; r0 -> error ; All other registers preserved ; endif ; ValidateModeSelector ENTRY LDR lr, [r0, #ModeSelector_Flags] AND lr, lr, #ModeSelectorFlags_FormatMask TEQ lr, #ModeSelectorFlags_ValidFormat ADRNE r0, ErrorBlock_BadMSFlags BNE %FT90 LDR lr, [r0, #ModeSelector_PixelDepth] CMP lr, #6 ADRCS r0, ErrorBlock_BadPixelDepth BCS %FT90 CLRV EXIT 90 [ International BL TranslateError ] SETV EXIT MakeErrorBlock BadMSFlags ] ; ***************************************************************************** ; ; ProcessModeVarPairs - Modify stacked variable info from ; mode variable (index, value) pairs ; ; Internal routine used to do Service_ModeExtension workspace lists and ; mode selectors ; ; in: r4 -> first pair (may be none) ; r9 -> stack frame ; ; out: All registers preserved ProcessModeVarPairs ENTRY "r4, r8, r10" ADRL r14, RMVTab 10 LDR r10, [r4], #4 ; get next entry in ws table CMP r10, #-1 EXIT EQ ; no more to do CMP r10, #(SWIRVVTabModeEnd-SWIRVVTab) ; is it a mode variable ? BCS %BT10 ; no, then ignore LDRB r10, [r14, r10] ; load index out of RMVTab MOVS r10, r10, LSR #1 ; shift byte/word flag into carry LDR r8, [r4], #4 ; load value STRCCB r8, [r9, r10] ; either store byte STRCS r8, [r9, r10] ; or store word B %BT10 [ VIDCListType3 ^ 4 VIDCList3_PixelDepth # 4 VIDCList3_HorizSyncWidth # 4 VIDCList3_HorizBackPorch # 4 VIDCList3_HorizLeftBorder # 4 VIDCList3_HorizDisplaySize # 4 VIDCList3_HorizRightBorder # 4 VIDCList3_HorizFrontPorch # 4 VIDCList3_VertiSyncWidth # 4 VIDCList3_VertiBackPorch # 4 VIDCList3_VertiTopBorder # 4 VIDCList3_VertiDisplaySize # 4 VIDCList3_VertiBottomBorder # 4 VIDCList3_VertiFrontPorch # 4 VIDCList3_PixelRate # 4 VIDCList3_SyncPol # 4 VIDCList3_ControlList # 0 ; Indices in control list ^ 1 ControlList_LCDMode # 1 ControlList_LCDDualPanelMode # 1 ControlList_LCDOffset0 # 1 ControlList_LCDOffset1 # 1 ControlList_HiResMode # 1 ControlList_DACControl # 1 ControlList_RGBPedestals # 1 ControlList_ExternalRegister # 1 ControlList_HClockSelect # 1 ControlList_RClockFrequency # 1 ControlList_DPMSState # 1 ControlList_InvalidReason # 0 ; ; ProcessVIDCListType3 - Convert type3 VIDC list into VIDC20 parameters ; ; in: r3 -> VIDC list (type 3) ; r9 -> VIDC table (where R9!(nn << 2) holds parameter for register nnxxxxxx ; for nn=80 to FF ; stacked r2-r4, r7-r11, lr ProcessVIDCListType3 ROUT LDR r2, [r3, #VIDCList3_HorizSyncWidth] BIC r2, r2, #1 ; must be even SUB r2, r2, #8 ; horiz parameters start off at n-8 ORR r14, r2, #HorizSyncWidth STR r14, [r9, #HorizSyncWidth :SHR: 22] LDR r4, [r3, #VIDCList3_HorizBackPorch] ADD r2, r2, r4 BIC r2, r2, #1 SUB r2, r2, #4 ; HBSR is N-12 ORR r14, r2, #HorizBorderStart STR r14, [r9, #HorizBorderStart :SHR: 22] LDR r4, [r3, #VIDCList3_HorizLeftBorder] ADD r2, r2, r4 BIC r2, r2, #1 SUB r2, r2, #6 ; HDSR is N-18 ORR r14, r2, #HorizDisplayStart STR r14, [r9, #HorizDisplayStart :SHR: 22] LDR r4, [r3, #VIDCList3_HorizDisplaySize] BIC r4, r4, #1 LDR r7, [r3, #VIDCList3_PixelDepth] MOV r10, r4, LSL r7 ; number of bits in one displayed raster (not needed later any more) ANDS r8, r10, #31 ; if line length not multiple of 32 MOVNE r8, #DCR_HDis ; then set HDis bit ORR r8, r8, r10, LSR #5 ; OR in number of words per line ; Note - the DCR_Bus bits get overridden and the HDWR bits modified further down the line by the mode change code ; on the basis of how much VRAM we've got, and on whether we have a dual-panel LCD or not... [ MEMC_Type = "IOMD" ORR r8, r8, #DCR_VRAMOff :OR: DCR_Bus31_0 :OR: DCR_Sync | ORR r8, r8, #DCR_VRAMOff :OR: DCR_Bus31_0 ] ORR r8, r8, #VIDCDataControl STR r8, [r9, #VIDCDataControl :SHR: 22] ADD r2, r2, r4 ; HDER is also N-18 ORR r14, r2, #HorizDisplayEnd STR r14, [r9, #HorizDisplayEnd :SHR: 22] LDR r4, [r3, #VIDCList3_HorizRightBorder] ADD r2, r2, r4 ADD r2, r2, #6 ; HBER is N-12 BIC r2, r2, #1 ORR r14, r2, #HorizBorderEnd STR r14, [r9, #HorizBorderEnd :SHR: 22] LDR r4, [r3, #VIDCList3_HorizFrontPorch] ADD r2, r2, r4 ADD r2, r2, #4 ; HCR is N-8 BIC r2, r2, #3 ; must be mult of 4 ORR r14, r2, #HorizCycle STR r14, [r9, #HorizCycle :SHR: 22] ADD r2, r2, #8 ; HIR is N/2 MOV r2, r2, LSR #1 ORR r14, r2, #HorizInterlace STR r14, [r9, #HorizInterlace :SHR: 22] LDR r2, [r3, #VIDCList3_VertiSyncWidth] SUB r2, r2, #2 ; vertical registers are N-2 ORR r14, r2, #VertiSyncWidth STR r14, [r9, #VertiSyncWidth :SHR: 22] LDR r4, [r3, #VIDCList3_VertiBackPorch] ADD r2, r2, r4 ORR r14, r2, #VertiBorderStart STR r14, [r9, #VertiBorderStart :SHR: 22] LDR r4, [r3, #VIDCList3_VertiTopBorder] ADD r2, r2, r4 ORR r14, r2, #VertiDisplayStart STR r14, [r9, #VertiDisplayStart :SHR: 22] LDR r4, [r3, #VIDCList3_VertiDisplaySize] ADD r2, r2, r4 ORR r14, r2, #VertiDisplayEnd STR r14, [r9, #VertiDisplayEnd :SHR: 22] LDR r4, [r3, #VIDCList3_VertiBottomBorder] ADD r2, r2, r4 ORR r14, r2, #VertiBorderEnd STR r14, [r9, #VertiBorderEnd :SHR: 22] LDR r4, [r3, #VIDCList3_VertiFrontPorch] ADD r2, r2, r4 ORR r14, r2, #VertiCycle STR r14, [r9, #VertiCycle :SHR: 22] LDR r4, [r3, #VIDCList3_SyncPol] MOV r14, #VIDCExternal TST r4, #1 ORRNE r14, r14, #Ext_InvertHSYNC TST r4, #2 ORRNE r14, r14, #Ext_InvertVSYNC ORR r14, r14, #Ext_DACsOn ORR r14, r14, #Ext_ERegExt STR r14, [r9, #VIDCExternal :SHR: 22] Push "r0, r1" LDR r0, [r3, #VIDCList3_PixelRate] ; get pixel rate MOV r10, r0, LSL r7 ; peak mem b/w (x 1E3 bits/sec) - save for FIFO calculation [ MorrisSupport ; MOV R14, #IOMD_Base ; LDRB R1, [R14, #IOMD_ID0] ; CMP R1, #&E7 ; LDRB R1, [R14, #IOMD_ID1] ; CMPEQ R1, #&D4 ; MOVNE R1, #32000 ;Morris clocks VIDC20L at 32Mhz ; LDREQ R1, =24000 ;RISC PC clocks VIDC20 at 24MHz MOV R1, #0 LDRB R1, [R1, #IOSystemType] TST R1, #IOST_7500 LDREQ R1, =24000 ;RISC PC clocks VIDC20 at 24MHz MOVNE R1, #32000 ;Morris clocks VIDC20L at 32Mhz ;>>>RCM says can we replace the above by ;>>> LDR R1, [WsPtr, #VIDCClockSpeed] | LDR r1, =rclk ; eventually will need to replace this if specified in control list ] BL ComputeModuli ; out: r0 = FSync bits, r1 = CR bits ORR r0, r0, #VIDCFSyn STR r0, [r9, #VIDCFSyn :SHR: 22] TEQ r7, #5 ; if 32 bpp, then stick in 6 not 5 MOVEQ r7, #6 ORR r0, r1, r7, LSL #5 ; now work out FIFO load position - r10 is b/w in thousands of bytes/sec [ {TRUE} ; do it by means of a binary chop on 3 bits ADR r4, FIFOLoadTable LDR r2, [r4, #4*4] ; load 0-3/4-7 split CMP r10, r2 MOVLS r7, #0 ; if <=, then bottom half MOVHI r7, #4 ; else top half ADDHI r4, r4, #4*4 ; and advance table pointer LDR r2, [r4, #2*4] CMP r10, r2 ORRHI r7, r7, #2 ADDHI r4, r4, #2*4 LDR r2, [r4, #1*4] CMP r10, r2 ORRHI r7, r7, #1 | CMP r10, #&10000 :SHL: 3 ; this value (65.536 Mbytes/sec) lies above the point at which 7 works ; and below the point at which 7 is needed MOVCC r7, #6 MOVCS r7, #7 ] ORR r0, r0, r7, LSL #CR_FIFOLoadShift ORR r0, r0, #VIDCControl STR r0, [r9, #VIDCControl :SHR: 22] ; Now go through VIDC control parameters list (not all indices can be handled yet) ADD r3, r3, #VIDCList3_ControlList-8 ; point at 1st entry -8 50 LDR r4, [r3, #8]! ; load next index CMP r4, #-1 ; if -1 then end of list BEQ %FT60 ; so skip CMP r4, #0 ; if non-zero (CS if zero) CMPNE r4, #ControlList_InvalidReason ; and if known reason LDRCC r2, [r3, #4] ; then load value BLCC ProcessControlListItem ; and process this item B %BT50 ; go onto next item in list [ {TRUE} FIFOLoadTable [ {TRUE} ; put a minimum of 4, cos 800 x 600 x 1bpp don't work otherwise & 0 ; dummy entry (not used) & 0 ; never use 0 & 0 ; use 1 up to (and including) here & 0 ; use 2 up to (and including) here & 0 ; use 3 up to (and including) here & 60000 :SHL: 3 ; use 4 up to (and including) here & 75000 :SHL: 3 ; use 5 up to (and including) here & 90000 :SHL: 3 ; use 6 up to (and including) here ; else use 7 | & 0 ; dummy entry (not used) & 0 ; never use 0 & 12000 :SHL: 3 ; use 1 up to (and including) here & 24000 :SHL: 3 ; use 2 up to (and including) here & 36000 :SHL: 3 ; use 3 up to (and including) here & 60000 :SHL: 3 ; use 4 up to (and including) here & 75000 :SHL: 3 ; use 5 up to (and including) here & 90000 :SHL: 3 ; use 6 up to (and including) here ; else use 7 ] ] 60 ; Now, for debugging purposes, output data to a file [ {FALSE} ! 0, "**** WARNING: Mode change debugging assembled in ****" MOV r0, #0 LDRB r0, [r0, #LCD_Active] CMP r0, #2 Pull "r0, r1, r2-r4, r7-r11, pc", NE MOV r0, #&80 ADR r1, ModeFilename SWI XOS_Find Pull "r0, r1, r2-r4, r7-r11, pc", VS MOV r1, r0 MOV r0, #2 ADD r2, r9, #VIDCParmsSize ; r2 -> data MOV r3, #VIDCParmsSize SWI XOS_GBPB MOV r0, #0 SWI XOS_Find Pull "r0, r1, r2-r4, r7-r11, pc" ModeFilename = "$.ModeData", 0 ALIGN | Pull "r0, r1, r2-r4, r7-r11, pc" ] ; ***************************************************************************** ; ; ProcessControlListItem ; ; in: r2 = value for item ; r4 = index for item (guaranteed in range) ; r9 -> VIDC register array ; ; out: r0-r2, r4, r7, r8, r10, r11 may be corrupted ; r3, r9, r12 must be preserved ProcessControlListItem ENTRY LDR pc, [pc, r4, LSL #2] NOP & ProcessControlListNOP ; 0 - NOP & ProcessControlListLCDMode ; 1 - LCD mode & ProcessControlListLCDDualPanelMode ; 2 - LCD dual-panel mode & ProcessControlListLCDOffsetRegister0 ; 3 - LCD offset register 0 & ProcessControlListLCDOffsetRegister1 ; 4 - LCD offset register 1 & ProcessControlListHiResMode ; 5 - Hi-res mode & ProcessControlListDACControl ; 6 - DAC control & ProcessControlListRGBPedestals ; 7 - RGB pedestal enables & ProcessControlListExternalRegister ; 8 - External register & ProcessControlListNOP ; 9 - HClk select/specify & ProcessControlListNOP ; 10 - RClk frequency & ProcessControlListDPMSState ; 11 - DPMS state ProcessControlListLCDMode MOV r0, #0 LDRB r1, [r0, #LCD_Active] ;Read the existing value AND r1, r1, #&80 ;Clear all but the single/dual bit, 'cos this might have been set already ORR r1, r1, r2 ;Bung our new lcdmode into the byte, and.... STRB r1, [r0, #LCD_Active] ;...store in the KernelWS which LCD mode we are in. MOV r1, #Ext_ECKOn ;Set the ECLK on CMP r2, #3 ;Was (is) it active-matrix? ORRNE r1, r1, #Ext_LCDGrey ;If not, set the LCD greyscaler 'on' 05 MOV r0, #VIDCExternal 10 MOV r7, r1 TEQ r2, #0 ; if value non-zero MOVNE r2, r1 ; then use value in r1 15 AND r2, r2, r7 ; ensure only relevant bits set LDR lr, [r9, r0, LSR #22] ; load word from register bank BIC lr, lr, r7 ; knock out bits in mask ORR lr, lr, r2 ; OR in new bits STR lr, [r9, r0, LSR #22] ; and store in array ProcessControlListNOP EXIT ProcessControlListHiResMode MOV r1, #Ext_HiResMono ; bit of a misnomer, it's not nec. mono B %BT05 ProcessControlListDACControl MOV r1, #Ext_DACsOn B %BT05 ProcessControlListRGBPedestals MOV r0, #VIDCExternal MOV r2, r2, LSL #Ext_PedsShift MOV r7, #Ext_PedsOn B %BT15 ProcessControlListExternalRegister MOV r0, #VIDCExternal MOV r7, #&FF B %BT15 ProcessControlListLCDDualPanelMode MOV r0, #0 LDRB r1, [r0, #LCD_Active] ORR r1, r1, #&80 ;Set the top bit & leave the rest as-is STRB r1, [r0, #LCD_Active] ;Store in the KernelWS that we are in dual-panel LCD mode. LDR r0, [r9, #VIDCDataControl :SHR: 22] MOV r1, r0, LSL #(31-10) ;Put HDWR bits to the top BIC r0, r0, r1, LSR #(31-10) ;knock off bits ORR r0, r0, r1, LSR #(31-11) ;Put back one bit further up (ie mul by 2) STR r0, [r9, #VIDCDataControl :SHR: 22] LDR r0, [r9, #VertiDisplayEnd :SHR: 22] LDR r1, [r9, #VertiDisplayStart :SHR: 22] BIC r0, r0, #VertiDisplayEnd BIC r1, r1, #VertiDisplayStart SUB r0, r0, r1 ;R0 = Vres ADD r1, r1, r0, LSR #1 ;R1 = Vres/2 + VDSR ORR r1, r1, #VertiDisplayEnd STR r1, [r9, #VertiDisplayEnd :SHR: 22] LDR r1, [r9, #VertiCycle :SHR: 22] BIC r1, r1, #VertiCycle SUB r1, r1, r0, LSR #1 ORR r1, r1, #VertiCycle STR r1, [r9, #VertiCycle :SHR: 22] LDR r1, [r9, #VertiBorderEnd :SHR: 22] BIC r1, r1, #VertiBorderEnd SUB r1, r1, r0, LSR #1 ORR r1, r1, #VertiBorderEnd STR r1, [r9, #VertiBorderEnd :SHR: 22] LDR r1, [r9, #VIDCExternal :SHR: 22] BIC r1, r1, #Ext_ERegExt ORR r1, r1, #Ext_ERegGreen STR r1, [r9, #VIDCExternal :SHR: 22] MOV r0, #VIDCControl MOV r1, #CR_DualPanel B %BT10 ProcessControlListLCDOffsetRegister0 MOV r0, #LCDOffsetRegister0 20 ORR r2, r2, r0 ; put high bits of register at top STR r2, [r9, r0, LSR #22] ; and store in array MOV r0, #VIDC ;ACTUALLY PROGRAM VIDC (I know I shouldn't but I don't care - I've got a cold) STR r2, [r0] EXIT ProcessControlListLCDOffsetRegister1 MOV r0, #LCDOffsetRegister1 B %BT20 ProcessControlListDPMSState MOV r0, #PseudoRegister_DPMSState ; pseudo-register holding DPMS state ORR r2, r2, r0 ; form combined value STR r2, [r9, r0, LSR #22] ; store in register EXIT ; ***************************************************************************** ; ; ComputeModuli - Work out VCO moduli for a given frequency ; ; in: r0 = desired frequency (kHz) ; r1 = rclk frequency (kHz) (normally 24000) ; ; out: r0 = bits to put in bits 0..15 of Frequency Synthesizer Register ; r1 = bits to put in bits 0..4 of Control Register rclk * 24000 ; Reference clock into VIDC20 (in kHz) VCO_Min * 55000 ; minimum VCO frequency (in kHz) VCO_Max * 110000 ; maximum VCO frequency (in kHz) fpshf * 11 ; Shift value for fixed point arithmetic ^ 0, sp BestDInOrOutOfRange # 4 BestRInOrOutOfRange # 4 BestVInOrOutOfRange # 4 BestDInRange # 4 BestRInRange # 4 BestVInRange # 4 BestRangeError # 4 ComputeModuliStack * :INDEX: @ ComputeModuli ENTRY "r2-r12", ComputeModuliStack MOV r12, #-1 ; smallest error for values in or out of VCO range MOV r11, #-1 ; smallest error for values in VCO range STR r11, BestDInRange STR r11, BestVInRange STR r11, BestRInRange STR r11, BestDInOrOutOfRange STR r11, BestVInOrOutOfRange STR r11, BestRInOrOutOfRange STR r11, BestRangeError MOV r5, r1 ; r5 = rclk frequency, normally 24000 (32000 on Morris) LDR r1, =VCO_Min ; r1 = minimum VCO frequency (in kHz) LDR r2, =VCO_Max ; r2 = maximum VCO frequency (in kHz) MOV r3, #1 ; r3 = D 10 MOV r4, #1 ; r4 = R 15 MUL r6, r0, r3 ; r6 = xD MUL r7, r6, r4 ; r7 = xRD ADD r7, r7, r5, LSR #1 ; r7 = xRD + vref/2 DivRem r8, r7, r5, r9 ; r8 = (xRD + vref/2) DIV vref = V value TEQ r4, #1 ; if R=1 then V must be 1, else it's no good BNE %FT20 TEQ r8, #1 BNE %FT50 BEQ %FT25 20 CMP r8, #2 ; if R<>1 then V must be in range 2..64 RSBCSS r7, r8, #64 BCC %FT50 ; V out of range, so skip 25 MUL r7, r5, r8 ; r7 = V * vref MOV r7, r7, LSL #fpshf ; r7 = (V * vref) << fixedpointshift DivRem r9, r7, r4, r14 ; r9 = ((V * vref) << fixedpointshift)/R = VCO frequency << fixedpointshift MOV r6, r9 DivRem r7, r9, r3, r14 ; r7 = output frequency << fixedpointshift SUBS r7, r7, r0, LSL #fpshf RSBCC r7, r7, #0 ; r7 = absolute error << fixedpointshift TEQ r4, #1 ; if R=1 then no need to check VCO range BEQ %FT27 ; because VCO won't be used, so it's a 1st class citizen CMP r6, r1, LSL #fpshf ; test if VCO freq >= min RSBCSS r14, r6, r2, LSL #fpshf ; and <= max BCC %FT40 ; not in range, so not a first class citizen 27 CMP r7, r11 BHI %FT40 ; worse than the best case for in VCO range, so ignore BCC %FT30 ; is definitely better than the best case for in or out LDR r14, BestRInRange ; is equal best for in, so check R value CMP r4, r14 ; is newR < bestR BCS %FT40 ; is greater or equal R value (ie not higher comp. freq., so not best) 30 MOV r11, r7 STR r3, BestDInRange STR r4, BestRInRange STR r8, BestVInRange MOV r14, #0 B %FT45 40 RSBS r14, r6, r1, LSL #fpshf ; r14 = min-this, if this entry on stack for register nn000000 ; or R9 + (nn << 2) -> ditto, for VIDC20 ; R11 -> change table, terminated with -1 ; ; out: R11 -> word after -1 terminator ; All other registers preserved (including PSR) ; [ MorrisSupport UpdateVIDCTable ROUT Push "R0,R14" MOV R0, #0 LDRB R0, [R0, #IOSystemType] TST R0, #IOST_7500 MOVEQ R0, #1 ;if rclk is 24MHz, stop at first -1 MOVNE R0, #2 ;if rclk is 32MHz, overwrite clock dividers with different data 10 LDR R14, [R11], #4 CMP R14, #-1 LDREQ R14, [R11], #4 ;EQ, on terminator, so skip it SUBEQS R0, R0, #1 Pull "R0,PC",EQ,^ ;EQ, quit on first (iff rclk=24MHz) or second terminator (iff rclk=32MHz) CMP R14, #&80000000 ; must be in range &80..&FF STRCS R14, [R9, R14, LSR #22] ; NB bits 23 and 22 are assumed to be zero B %BT10 | UpdateVIDCTable ROUT Push "R14" 10 LDR R14, [R11], #4 CMP R14, #-1 Pull "PC",EQ,^ CMP R14, #&80000000 ; must be in range &80..&FF [ VIDC_Type = "VIDC20" STRCS R14, [R9, R14, LSR #22] ; NB bits 23 and 22 are assumed to be zero | STRCS R14, [R9, R14, LSR #24] ] B %BT10 ] ; ***************************************************************************** ; ; OfferModeExtension - Issue mode extension service ; ; in: R2 = mode specifier ; ; out: EQ => service claimed, R3 -> VIDC list, R4 -> workspace list ; NE => service not claimed, R3,R4 preserved ; All other registers preserved ; OfferModeExtensionAnyMonitor ROUT MOV r3, #-1 OfferModeExtension ROUT [ ModeSelectors Push "r1,r2,r4,r5,r14" ; TMD 10-Jan-94 - added code here to check for erroneous passing in of a sprite mode word. ; This prevents data aborts when modules try to index off a bad address. ; ; We could have done OS_ValidateAddress, but that would be rather slow, and mode selectors ; are of indeterminate length. ; ; If we detect one of these, we pretend the service wasn't claimed. Hopefully this should ; ensure that the mode change returns an error. ; Fixes bug MED-00483. BICS r14, r2, #&FF ; NE if not a mode number TSTNE r2, #3 ; NE if not a mode number, but invalid mode selector Pull "r1,r2,r4,r5,pc", NE ; so exit NE, pretending that service not claimed GetBandwidthAndSize r4, r5 MOV r1, #Service_ModeExtension IssueService TEQ r1, #0 ; if service claimed CMPNE r3, #-1 ; or if "don't care" monitortype BEQ %FT90 ; then we can't do any more CMP r2, #&100 ; if it's a mode selector BCS %FT90 ; then we can't help them either BranchIfNotKnownMode r2, %FA90 ; if we don't recognise screen mode number we can't either ; it is a known numbered mode, so create a mode selector on the stack that we can pass to service Push "r6,r7" SUB sp, sp, #ModeSelector_ModeVars+4 ; make room for block including terminator MOV r6, #ModeSelectorFlags_ValidFormat STR r6, [sp, #ModeSelector_Flags] ADRL r6, FrameRateTable LDRB r6, [r6, r2] STR r6, [sp, #ModeSelector_FrameRate] ADRL r6, Vwstab LDR r14, [r6, r2, LSL #2] ADD r6, r6, r14 LDR r14, [r6, #wkLog2BPP] STR r14, [sp, #ModeSelector_PixelDepth] ; pixdepth = log2bpp LDR r7, [r6, #wkLog2BPC] SUB r14, r7, r14 ; r14 = log2bpc-log2bpp LDR r7, [r6, #wkXWindLimit] ADD r7, r7, #1 MOV r7, r7, LSL r14 STR r7, [sp, #ModeSelector_XRes] LDR r7, [r6, #wkYWindLimit] ADD r7, r7, #1 STR r7, [sp, #ModeSelector_YRes] MOV r7, #-1 STR r7, [sp, #ModeSelector_ModeVars] MOV r2, sp IssueService TEQ r1, #0 BEQ %FT10 ; service was claimed ; not claimed, so try again with -1 as frame rate MOV r7, #-1 STR r7, [sp, #ModeSelector_FrameRate] IssueService TEQ r1, #0 10 ADD sp, sp, #ModeSelector_ModeVars+4 ; junk mode selector Pull "r6, r7" 90 CMP r2, #&100 ; if we started or ended up with a mode selector MOVCS r4, #0 ; then return r4 = 0 (if claimed) TEQ r1, #0 STREQ r4, [sp, #2*4] ; if service claimed, then return r4 from service, else preserve it Pull "r1,r2,r4,r5,pc" | Push "r1, lr" MOV r1, #Service_ModeExtension IssueService TEQ r1, #0 Pull "r1, pc" ] ; ***************************************************************************** ; ; ETB - Redefine character ; === & other stuff ; ; VDU 23,0,r,v,0| Talk to 6845 ! ; VDU 23,1,n,m,r,g,b| Program cursor ; VDU 23,2,n1..n8 Ecf pattern 1 ; VDU 23,3,n1..n8 Ecf pattern 2 ; VDU 23,4,n1..n8 Ecf pattern 3 ; VDU 23,5,n1..n8 Ecf pattern 4 ; VDU 23,6,n1..n8 Dot dash line style ; VDU 23,7,m,d,z| Scroll window directly ; VDU 23,8,t1,t2,x1,y1,x2,y2| Clear block ; VDU 23,9,n| Set 1st flash time ; VDU 23,10,n| Set 2nd flash time ; VDU 23,11| Default Ecf patterns ; VDU 23,12,n1..n8 Ecf pattern 1 (simple setting) ; VDU 23,13,n1..n8 Ecf pattern 2 (simple setting) ; VDU 23,14,n1..n8 Ecf pattern 3 (simple setting) ; VDU 23,15,n1..n8 Ecf pattern 4 (simple setting) ; VDU 23,16,x,y| Cursor movement control ; VDU 23,17,c,t| Set colour tints, ECF info, char sizes ; ; ETB LDRB R0, [WsPtr, #QQ+0] CMP R0, #32 ; defining a normal character ? BCS DefineChar LDR R2, [PC, R0, LSL #2] ADD PC, PC, R2 ; enters routine with R0 => byte after 23 ETBtab & Vdu23_0-ETBtab-4 & Vdu23_1-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & ComplexEcfPattern-ETBtab-4 & LineStyle-ETBtab-4 & Vdu23_7-ETBtab-4 & Vdu23_8-ETBtab-4 & Vdu23_9-ETBtab-4 & Vdu23_10-ETBtab-4 & DefaultEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & SimpleEcfPattern-ETBtab-4 & Vdu23_16-ETBtab-4 & Vdu23_17-ETBtab-4 & Vdu23_18-ETBtab-4 & Vdu23_19-ETBtab-4 & Vdu23_20-ETBtab-4 & Vdu23_21-ETBtab-4 & Vdu23_22-ETBtab-4 & Vdu23_23-ETBtab-4 & Vdu23_24-ETBtab-4 & Vdu23_25-ETBtab-4 & Vdu23_26-ETBtab-4 & Vdu23_27-ETBtab-4 & Vdu23_28-ETBtab-4 & Vdu23_29-ETBtab-4 & Vdu23_30-ETBtab-4 & Vdu23_31-ETBtab-4 ; NB All other labels for Vdu23 are in TMD files so I don't have to pester RCM Vdu23_18 Vdu23_19 Vdu23_20 Vdu23_21 Vdu23_22 Vdu23_23 Vdu23_24 Vdu23_25 Vdu23_26 ; Vdu23_27 ; Assigned to Richard (well some of it, anyway) Vdu23_28 Vdu23_29 Vdu23_30 Vdu23_31 UnknownVdu23 ; R0 already contains first parameter to VDU23 MOV R10, #UKVDU23V Push "WsPtr, R14" ; calling a vector corrupts R12 BL VduQQVec ; so we have to preserve it Pull "WsPtr, PC", VC ; before we return to PostWrchCursor ; error in UKVDU23 vector, so go to vdu error exit Pull "WsPtr, R14" B VduBadExit ; ***************************************************************************** ; ; DLE ; CLG - Clear graphics window ; === ; ; On exit, R0..R11 corrupt ; DLE CLG ROUT GraphicsMode R0 MOVNE PC,LR ; check for graphics mode (changed by DDV 15/9/92) ADD R0, WsPtr, #BgEcfOraEor ; point at background colour STR R0, [WsPtr, #GColAdr] ADD R11, WsPtr, #GWLCol ; load window coordinates into LDMIA R11, {R0-R3} ; RectFill's parameter space LDR R6, [WsPtr, #CursorFlags] ; if clip box is not enabled TST R6, #ClipBoxEnableBit ; then goto code directly BEQ RectFillA Push R14 ; else merge graphics window (in R0-R3) BL MergeClipBox ; with clip box Pull R14 B RectFillA ; ***************************************************************************** ; ; DC2 ; GCol - Set Graphics action and colour ; ==== ; ; On entry, R0 holds GCol action ; R1 holds GCol colour, 0..127 means program fg ; 128..255 means program bg ; ; In 256-colour modes, the extra colours are accessed via TINT ; DC2 GCol ROUT LDRB R0, [WsPtr, #QQ+0] ; GCol action, eg store, eor etc. LDRB R1, [WsPtr, #QQ+1] ; GCol colour LDR R2, [WsPtr, #NColour] ; number of colours-1 TST R1, #&80 AND R1, R1, R2 ; limit colour to range available STREQ R0, [WsPtr, #GPLFMD] ; GCOL(a,0..127) is foreground STREQ R1, [WsPtr, #GFCOL] STRNE R0, [WsPtr, #GPLBMD] ; GCOL(a,128..255) is background STRNE R1, [WsPtr, #GBCOL] ; drop into SetColour to.... ; SetColour - Setup FgEcf & BgEcf, used after GCOL or setting of Ecfs ; ========= or default palette (does a gcol). SetColour Push R14 LDR R1, [WsPtr, #GPLFMD] ; setup FgEcf, maybe solid or Ecf LDR R0, [WsPtr, #GFCOL] ADD R2, WsPtr, #FgEcf LDR R3, [WsPtr, #GFTint] ; tint only used in 256 colour modes ADD R4, WsPtr, #FgPattern ; used if OS_SetColour call BL SetCol10 LDR R1, [WsPtr, #GPLBMD] ; and BgEcf LDR R0, [WsPtr, #GBCOL] ADD R2, WsPtr, #BgEcf LDR R3, [WsPtr, #GBTint] ADD R4, WsPtr, #BgPattern ; used if OS_SetColour call BL SetCol10 ADD R0, WsPtr, #FgEcf ; setup FgEcfOraEor ADD R1, WsPtr, #BgEcf ADD R2, WsPtr, #FgEcfOraEor LDR R3, [WsPtr, #GPLFMD] BL SetCol60 ADD R0, WsPtr, #BgEcf ; and BgEcfOraEor ADD R1, WsPtr, #FgEcf ADD R2, WsPtr, #BgEcfOraEor LDR R3, [WsPtr, #GPLBMD] BL SetCol60 ADD R0, WsPtr, #BgEcf ; and BgEcfStore ADD R1, WsPtr, #FgEcf ADD R2, WsPtr, #BgEcfStore MOV R3, #0 BL SetCol60 Pull PC ; SetCol10 - Internal to SetColour ; Build up an Ecf, given action and colour numbers ; ; On entry, R0 holds colour (0..255, where 127..255 means 0..127) ; R1 holds action (may indicate ecf) ; R2 holds address to write data (FgEcf or BgEcf) ; R3 holds tint information (only used in 256 colour modes) ; R4 holds pointer to suitable pattern table for OS_SetColour call SetCol10 ROUT ANDS R1, R1, #&F0 ; actions >=16 mean Ecf BNE SetCol30 Push R14 LDR R4, [WsPtr, #NColour] ; else use given colour number AND R0, R0, R4 AND R0, R0, #63 ; another bodge in the house of bodges TST R4, #&F0 ; if 256 colour (ie 8bpp) BLNE AddTintToColour ; then combine tint with colour ; R0 contains colour number for current mode LDR LR, [WsPtr, #BitsPerPix] 10 TEQ LR, #32 ORRNE R0, R0, R0, LSL LR ; replicate again MOVNE LR, LR, LSL #1 ; doubling the shift for each pass BNE %BT10 STR R0, [R2] STR R0, [R2, #4] STR R0, [R2, #8] STR R0, [R2, #12] STR R0, [R2, #16] STR R0, [R2, #20] STR R0, [R2, #24] STR R0, [R2, #28] Pull "PC" ; R1 = ecf number as 16,32,48,64,80,96 ; R2 -> destination ; R4 -> pattern block (if R1 =96!) SetCol30 CMP R1, #96 ; special internal plot? MOVCS R0, R4 ; yes, so point at pattern to be copied MOVCS R3, #1 ; col step =1 MOVCS R4, #0 ; row step =0 (already there!) BCS SetCol35 CMP R1, #80 ; 80 => giant ecf (>80 does same) ADDCS R0, WsPtr, #Ecf1 ; then point at ecf0 MOVCS R3, #8 ; col step=8 MOVCS R4, #(1-8*4) ; row step, back to 1st ecf on 1 byte BCS SetCol35 ADD R0, WsPtr, #(Ecf1-8) ADD R0, R0, R1, LSR #1 ; else point R0 at Ecf1,2,3 or 4 LDR R4, [WsPtr, #BitsPerPix] ; if BitsPerPix <> 'fudged' BitsPerPix LDR R5, [WsPtr, #BytesPerChar] TEQ R4, R5 BNE SetCol52 ; then double up the pixels ; else its a normal Ecf MOV R3, #0 ; col step=0, same byte each coloum MOV R4, #1 ; row step=1 SetCol35 MOV R5, #8 ; do 8 rows SetCol40 MOV R6, #4 ; of 4 columns SetCol50 LDRB R7, [R0], R3 ; read from source & move by col step STRB R7, [R2], #1 ; write to dest, update dest pointer SUBS R6, R6, #1 BNE SetCol50 ADD R0, R0, R4 ; step source pointer to next row SUBS R5, R5, #1 BNE SetCol40 MOV PC, R14 ; Double up the pixels for Mode2 etc ; ; R0 points to Ecf(n) ; R2 points to destination ; ; Uses ; ; R3 - NColour used as PixMsk ; R4 - BitsPerPix ; R5 - BytesPerChar (unused) ; R6 - byte cntr 7..0 ; R7 - source byte ; R8 - ExtrtShftFact ; R9 - InsrtShftFact ; R10 - result word ; R11 - temp SetCol52 LDR R3, [WsPtr, #NColour] ; mask for extracting pixels from ecf TST R3, #&F0 ; ** if 256 colour mode MOVNE R3, #&FF ; ** then use &FF (TMD 25-Mar-87) LDR R4, [WsPtr, #BitsPerPix] MOV R6, #7 ; 8 bytes/rows to do SetCol54 LDRB R7, [R0, R6] ; get byte of Ecf(n) RSB R8, R4, #8 RSB R9, R4, #32 MOV R10, #0 ; clear result word SetCol57 AND R11, R3, R7, ROR R8 ; extract 1 pixel from Ecf ORR R10, R10, R11, LSL R9 ; double it into result word SUB R9, R9, R4 ORR R10, R10, R11, LSL R9 SUB R8, R8, R4 AND R8, R8, #7 SUBS R9, R9, R4 BGE SetCol57 ; process next pixel in result word STR R10, [R2, R6, LSL #2] ; write expanded word to (Fg/Bg)Ecf SUBS R6, R6, #1 BGE SetCol54 ; process next row/byte MOV PC, R14 ; Tables of full colours for 2,4 & 16 colour modes (256 colour modes ; use colour number directly). ; ; N.B. these are tables of bytes TBFullCol = &FF ; not used - remove sometime ; (DJS comment: don't bother!) = &00, &FF ; 2 colour mode = &00, &55, &AA, &FF ; 4 colour mode = &FF, &FF, &FF, &FF ; not used but cannot be removed = &FF, &FF, &FF, &FF ; (8 colour mode!) = &00, &11, &22, &33 ; 16 colour mode = &44, &55, &66, &77 = &88, &99, &AA, &BB = &CC, &DD, &EE, &FF ALIGN ; ***************************************************************************** ; ; SetCol60 - Build up an ecf, ORed and EORed appropriate to GCOL action ; ; Internal to SetColour ; ; in: R0 -> ecf colour (FgEcf/BgEcf) ; R1 -> transparent colour (BgEcf/FgEcf) ; R2 -> destination FgEcfOraEor/BgEcfOraEor/BgEcfStore ; R3 = gcol action number (may indicate ecf) ; ; uses: R4 = index into ecf (7..0) ; R5 = ecf colour word ; R6 = transparency mask, set to &FFFFFFFF for NO transparency ; R7 -> zgoo..zgee for gcol action ; R8 = mask for pixel under examination ; R9 = shift factor to move mask to next pixel (BytesPerChar) ; R10, R11 temporary ; SetCol60 ROUT MOV R4, #7 ; 7..0 words to process AND R3, R3, #&F ; extract action bits AND R11, R3, #7 ; 0-7 Store etc ; 8-15 ditto with transparency MOV R11, R11, LSL #2 ; 4 bits for each LDR R7, =TBscrmasks MOV R7, R7, ROR R11 ; relevant bits are in top 4 AND R7, R7, #&F0000000 ; isolate these bits (N,Z,C,V) SetCol70 LDR R5, [R0, R4, LSL #2] ; get ecf word TST R3, #8 ; if action < 8 MOVEQ R6, #&FFFFFFFF BEQ SetCol90 ; then not transparent ; else build transparency mask LDR R8, [WsPtr, #RAMMaskTb] ; fetch mask for leftmost pixel LDR R9, [WsPtr, #BytesPerChar] ; shift factor for next pixel LDR R6, [R1, R4, LSL #2] ; get 'transparent' colour EOR R6, R6, R5 SetCol80 TST R6, R8 ; if pixels the same, ; then it's transparent ORRNE R6, R6, R8 ; else set mask to plot it MOVS R8, R8, LSL R9 BNE SetCol80 SetCol90 TEQP R7, #SVC_mode ; put bits into N, Z, C, V ; OO,EO,OE,EE MOVCC R10, R5 ; if ORing with &00000000 MOVCS R10, #&FFFFFFFF ; if ORing with &FFFFFFFF MVNVS R10, R10 ; if EORing with &FFFFFFFF ; MOVPL R5, R5 ; if ORing with &00000000 MOVMI R5, #&FFFFFFFF ; if ORing with &FFFFFFFF MVNEQ R5, R5 ; if EORing with &FFFFFFFF ; now R5 = OR mask, R10 = EOR mask AND R5, R5, R6 ; then clear 'transparent' AND R10, R10, R6 ; pixels LDR R11, [WsPtr, #ECFShift] MOV R5, R5, ROR R11 ; rotate OR and EOR masks MOV R10, R10, ROR R11 ; to correct for ECF X origin LDR R11, [WsPtr, #ECFYOffset] ADD R11, R11, R4 ; add on ECF Y offset AND R11, R11, #7 ; and wrap ADD R11, R2, R11, LSL #3 STMIA R11, {R5, R10} ; write to (Fg/Bg)EcfOraEor SUBS R4, R4, #1 BCS SetCol70 MOV PC, R14 ; ***************************************************************************** ; ; AddTintToColour - in 256 colour modes ; ; Internal to SetColour (derived from TMD's FudgeColour) ; ; in: R0 = colour (0..255), where 6 LSBits are used ; R3 = tint ; ; out: R0 holds colour byte with tint added ; R1-R3 preserved ; R4 undefined ; PSR preserved ; ! 0,"WARNING: AddTintToColour returns > 8 bit values now, check ECF handling!" AddTintToColour Push "R3,LR" AND R0, R0, #63 ; extract suitable set of bits AND R3, R3, #192 ; and another set ORR R0, R0, R3 BL ConvertGCOLToColourNumber Pull "R3,PC" ; ***************************************************************************** ; ; CAN - Define graphics window ; ; External routine ; ; in: The window is given by bytes in the vdu queue, as follows :- ; QQ+0 = leftLo ; QQ+1 = leftHi ; QQ+2 = bottomLo ; QQ+3 = bottomHi ; QQ+4 = rightLo ; QQ+5 = rightHi ; QQ+6 = topLo ; QQ+7 = topHi ; ; These are relative to the current graphics origin. ; The resultant window must obey the following rules :- ; RCol >= LCol ; TRow >= BRow ; LCol >= 0 ; BRow >= 0 ; YWindLimit >= TRow ; XWindLimit >= RCol ; CAN ROUT Push R14 ADD R8, WsPtr, #GCsX ; save ECursor away, cos EIG changes it LDMIA R8, {R6, R7} ; and we don't want it to! ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+5] ; rightHi ; LDRB R1, [WsPtr, #QQ+4] ; rightLo ; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend ; ; LDRB R1, [WsPtr, #QQ+7] ; topHi ; LDRB R2, [WsPtr, #QQ+6] ; topLo ; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+4 ;Get top right point ; *****End of change made by DJS MOV R2, #&FF ; convert external-to-internal BL EIG ; as absolute coordinates MOV R4, R0 ; move internal version of top right MOV R5, R1 ; out of harm's way ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+1] ; leftHi ; LDRB R1, [WsPtr, #QQ+0] ; leftLo ; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend ; ; LDRB R1, [WsPtr, #QQ+3] ; bottomHi ; LDRB R2, [WsPtr, #QQ+2] ; bottomLo ; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+0 ;Get bottom left point ; *****End of change made by DJS MOV R2, #&FF ; convert external-to-internal BL EIG ; as absolute coordinates ; For a valid window, the following must be true CMP R4, R0 ; RCol >= LCol CMPGE R5, R1 ; TRow >= BRow CMPGE R0, #0 ; LCol >= 0 CMPGE R1, #0 ; BRow >= 0 LDRGE R2, [WsPtr, #YWindLimit] ; YWindLimit >= TRow CMPGE R2, R5 LDRGE R2, [WsPtr, #XWindLimit] ; XWindLimit >= RCol CMPGE R2, R4 ADD R2, WsPtr, #GWLCol STMGEIA R2, {R0,R1, R4,R5} ; if the new window is OK, update it STMIA R8, {R6, R7} ; restore ECursor (EIG corrupted it) Pull PC ; ***************************************************************************** ; ; DefaultWindows - Restore default windows ; ; External routine, and called by mode change + switch output to sprite ; ; Set default text and graphics windows, ; Clear graphics origin and both cursors ; DefaultWindows ROUT Push R14 MOV R0, #0 MOV R1, #0 ADD R4, WsPtr, #GWLCol ASSERT YWindLimit = XWindLimit +4 ADD R2, WsPtr, #XWindLimit LDMIA R2, {R2,R3} ; R2 := XWindLimit; R3 := YWindLimit STMIA R4, {R0-R3} ; zero GWLCol, GWBRow ; GWRCol:=XWindLimit; GWTRow:=YWindLimit MOV R3, #0 LDR R1, [WsPtr, #ScrBRow] LDR R2, [WsPtr, #ScrRCol] ADD R4, WsPtr, #TWLCol ; zero TWLCol, TWTRow STMIA R4!, {R0-R3} ; TWRCol := ScrRCol; TWBRow := ScrBRow MOV R1, #0 MOV R2, #0 STMIA R4!, {R0-R3} ; zero OrgX, OrgY, GCsX, GCsY STMIA R4!, {R0-R3} ; zero OlderCsX, OlderCsY, OldCsX, OldCsY STMIA R4!, {R0-R3} ; zero GCsIX, GCsIY, NewPtX, NewPtY LDR R0, [WsPtr, #ModeFlags] TST R0, #Flag_HardScrollDisabled LDR R0, [WsPtr, #VduStatus] ; if not outputting to sprite BICEQ R0, R0, #Windowing ; then indicate no text window ORRNE R0, R0, #Windowing ; else indicate is text window STR R0, [WsPtr, #VduStatus] BL HomeVdu4 ; home TEXT cursor ; (even in VDU 5 mode) Pull PC ; ***************************************************************************** ; ; GS - Define graphics origin ; ; External routine ; ; in: The origin is given by bytes in the vdu queue, as follows :- ; QQ+0 = xLo ; QQ+1 = xHi ; QQ+2 = yLo ; QQ+3 = yHi ; ; The coordinates are in external 16 bit form. ; This does not move the windows, but does move the graphics cursor ; GS ROUT Push R14 ; *****Change made by DJS ; Original code was: ; LDRB R0, [WsPtr, #QQ+1] ; xHi ; LDRB R1, [WsPtr, #QQ+0] ; xLo ; PackXtnd R0,R0,R1 ; pack 2 bytes and sign extend ; LDRB R1, [WsPtr, #QQ+3] ; yHi ; LDRB R2, [WsPtr, #QQ+2] ; yLo ; PackXtnd R1,R1,R2 ; pack 2 bytes and sign extend LoadCoordPair R0, R1, WsPtr, QQ+0 ; *****End of change made by DJS ADD R2, WsPtr, #OrgX STMIA R2, {R0,R1} ; write the new origin BL IEG ; update external cursor Pull PC LTORG ;------------------------------------------------------------------------------ ; ; OS_SetColour implementation ; ------------ ; ; This call can be used to change the current GCOL/pattern table used for ; plotting with the VDU primitives. ; ; in R0 = flags / logical operation ; bit 0-3 = logical operation ; bit 4 = set => bg, else fg flag ; bit 5 = set => pattern block supplied ; bit 6 = set => set text colour ; bit 7 = set => read colour ; R1 = colour number / -> pattern block to use ; out - ; ;------------------------------------------------------------------------------ setcol_LogicOpMask * &0F setcol_FgBgFlag * &10 setcol_PatternFlag * &20 setcol_TextColour * &40 setcol_ReadFlag * &80 ASSERT WsPtr > 9 SWISetColour ROUT Push "R0-R9,WsPtr,R14" VDWS WsPtr ; Obtain base of the VDU driver workspace TST R0, #setcol_ReadFlag ; Are we reading? BNE %FT75 TST R0, #setcol_TextColour ; Are we changing the text colour? BNE %FT70 AND R2, R0, #setcol_LogicOpMask ; Get the logical operation ORR R2, R2, #&60 ; Mark as being a special kind of pattern TST R0, #setcol_FgBgFlag STREQ R2, [WsPtr, #GPLFMD] ; Store the relevant logical operation away for fg/bg STRNE R2, [WsPtr, #GPLBMD] ADDEQ R3, WsPtr, #FgPattern ADDNE R3, WsPtr, #BgPattern ; Setup the pointer to a store for the pattern TST R0, #setcol_PatternFlag ; Did the caller specify a pattern block? BNE %FT50 ; Yes so don't try to expand colour value to pattern MOV R2, #1 LDR R4, [WsPtr, #Log2BPP] ; Get the Log2 depth of the mode MOV R4, R2, ASL R4 ; R4 = bits per pixel RSB R2, R2, R2, LSL R4 ; Get a mask to extract only meaningful bits from word AND R1, R1, R2 ; Extract bits suitable for this depth of mode 10 TEQ R4, #32 ; Do we need to do any more replication ORRNE R1, R1, R1, LSL R4 ; Yes so or word with itself shifted MOVNE R4, R4, LSL #1 ; and double amount to shift next time BNE %BT10 MOV R2, #8 20 STR R1, [R3], #4 ; now copy word 8 times into block SUBS R2, R2, #1 BNE %BT20 B %FT60 50 LDMIA R1,{R0,R2,R4-R9} STMIA R3,{R0,R2,R4-R9} ; Copy the pattern into the buffer (assumes word aligned) 60 BL SetColour ; And then setup the internal GCOL tables 65 Pull "R0-R9,WsPtr,R14" ExitSWIHandler 70 TST R0, #setcol_FgBgFlag ; Store the foreground or background colour? STREQ R1, [WsPtr, #TextFgColour] STRNE R1, [WsPtr, #TextBgColour] LDR R0, [WsPtr, #CursorFlags] ; Indicate the text colour needs re-computing! ORR R0, R0, #TEUpdate STR R0, [WsPtr, #CursorFlags] B %BT65 ; Leave gracefully .... 75 ; Reading the colour... TST R0, #setcol_TextColour BEQ %FT80 ; Reading text colour TST R0, #setcol_FgBgFlag LDREQ R1, [WsPtr, #TextFgColour] LDRNE R1, [WsPtr, #TextBgColour] BIC R0, R0, #setcol_PatternFlag :OR: setcol_ReadFlag 77 ; Standard exit for reading the colour STMIA SP, {R0,R1} B %BT65 80 ; Reading graphics colour TST R0, #setcol_FgBgFlag LDREQ R2, [WsPtr, #GPLFMD] ; Get the relevant logical operation for fg/bg LDRNE R2, [WsPtr, #GPLBMD] ; SetColour setting - copy block ADDEQ R3, WsPtr, #FgEcf ADDNE R3, WsPtr, #BgEcf ; Copy the pattern to the user's buffer LDMIA R3,{R0,R3,R4-R9} STMIA R1,{R0,R3,R4-R9} ; Construct a suitable reason code AND R0, R2, #setcol_LogicOpMask ORRNE R0, R0, #setcol_FgBgFlag ORR R0, R0, #setcol_PatternFlag B %BT77 END