home *** CD-ROM | disk | FTP | other *** search
- ; > vsimanass
-
- ; Assembler code for vsi manager
-
- .include "a.IncAsm"
- .cinclude "c:h.swis"
-
- .area WA$$data
-
- .EXTERN VSI_Check
- .EXTERN VSI_Service
- .EXTERN Image$$ZI$$PBase
- .EXTERN Image$$ZI$$PLimit
-
- VSI_ZI_Base:: .ADDRESS Image$$ZI$$PBase
- VSI_ZI_Limit:: .ADDRESS Image$$ZI$$PLimit
-
-
- VSI_Old_Abort_Pre:: .LONG 0 ; void (*VSI_Old_Abort_Pre)(void);
- VSI_Old_Abort_Adr:: .LONG 0 ; void (*VSI_Old_Abort_Adr)(void);
-
-
- VSI_Stack:: .LONG 0
-
- RegDump: .LONG 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
- RestartPC: .LONG 0
-
- VSI_RegDump: .LONG 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
- VSI_RestartPC:: .LONG 0
-
-
-
- ; Special code to deal with an emulated floating point
- ; operation having a data abort
- ; ********************************************************
- ; ***** Rather heuristic and may fail with Risc-OS 3 *****
- ; ********************************************************
- ; Must be in supervisor mode in a module
- ; The stack must have the registers in and nothing else.
- ; and the saved pc should be for user mode.
- ; Fp emulator seems to update all the registers correctly for
- ; a data abort except the PC - whew, thank you Acorn.
-
- Fp_Stack: .LONG 0x01C01FC0 ; stack top-0x40, may change
-
- Fp_data_abort:
- MOV r0, #0
- LDR r1, Fp_Stack
- CMP sp, r1
- BNE Do_Old_Abort
- AND r2, lr, #0x0C000003
- CMP r2, #3
- BNE Do_Old_Abort
- LDR r3, [r1, #4*pc]
- TST r3, #0x0C000003
- BNE Do_Old_Abort
- ADR r0, RegDump
- LDMIA sp!, {r1-r8}
- STMIA r0!, {r1-r8}
- LDMIA sp!, {r1-r7, lr}
- ADD lr, lr, #4 ; Make it look like a data abort
- STMIA r0!, {r1-r7, lr}
- B Fp_Comeback
-
- ; Pre-Fetch Abort
- ; Undefined instruction in last word of page will
- ; cause a pre-fetch abort first. This is handled
- ; in Load_Page.
-
- VSI_Int_Abort_Pre::
- STR r0, RegDump
- ADR r0, RegDump+4
- STMIA r0, {r1-lr}^ ; Dump User registers
- MOV r0, r0 ; NOP
- STR lr, RegDump+4*pc
- MVN r0, #0 ; Pre-Fetch , bit 20 set for read
- TST lr, #0x0C000003 ; Only handle VSI in User mode
- BNE Do_Old_Abort
- SUB r1, lr, #4 ; -> op to retry
- STR r1, RestartPC
- BIC r1, r1, #Status_bits ; VSI address
- B Load_Page
-
- ; Data Abort
- ; Restore any base address
- ; Calculate address causing fault, or at least pointer
- ; into valid page before the fault.
-
- VSI_Int_Abort_Adr::
- STR r0, RegDump
- ADR r0, RegDump+4
- STMIA r0, {r1-lr}^ ; Dump User registers
- MOV r0, r0 ; NOP
- STR lr, RegDump+4*pc
- TST lr, #0x0C000003 ; Only handle VSI in user mode
- BNE Fp_data_abort ; Do special Emulated Fp frig
- Fp_Comeback:
- SUB r1, lr, #8 ; -> op to retry
- STR r1, RestartPC
- BIC r1, r1, #Status_bits
-
- ; Now analyse the failing operation
- ; r0 op code
- ; r1 VSI address
- ; r2 ->RegDump
- ; r3 base register number
-
- ADR r2, RegDump
- ; LDRT r0, [r1] ; Get failing op
- LDR r0, [r1] ; Get failing op
- MOV r3, r0, LSR #16
- AND r3, r3, #15 ; Get base register number
- LDR r1, [r2, r3, LSL #2] ; And get the value
- AND r7, r0, #0x0E000000
- CMP r7, #0x04000000
- CMPNE r7, #0x06000000
- BEQ ldrstr
- CMP r7, #0x08000000
- BEQ ldmstm
- CMP r7, #0x0C000000
- BEQ ldcstc
- AND r7, r0, #0x0FB00000 ; & 0x0FB00FF0 = 0x01000090
- CMP r7, #0x01000000
- ANDEQ r7, r0, #0x00000FF0
- CMPEQ r7, #0x00000090
- BNE Do_Old_Abort
- swp:
-
- ; Bit 20 = 0 for write op so leave op code in r0 unchanged
- B Load_Page
-
- ; Code for handling LDM, STM
- ; Restore base if necessary (not if pc)
- ; Calculate start transfer address
-
- ldmstm: AND r5, r0, #0x00A00000
- CMP r5, #0x00800000 ; increment, no writeback
- BEQ indexedup
- MOV r5, #0 ; Size of register list
- MOVS r6, r0, LSL #16 ; Top bits contain register list
- regcount: ADDNE r5, r5, #4 ; 4 bytes per register
- SUB r7, r6, #1 ; expose next 1 bit
- ANDS r6, r7, r6
- BNE regcount
- TST r0, #0x00200000 ; Writeback?
- CMPNE r3, #pc ; does not apply to pc
- BEQ NoWriteback
- TST r0, #0x00800000 ; Add offset to base?
- SUBNE r1, r1, r5 ; Reverse writeback
- ADDEQ r1, r1, r5
- STR r1, [r2, r3, LSL #2] ; Base register restored
- NoWriteback:
- TST r0, #0x00800000 ; Add offset to base?
- BNE indexedup ; Split incrementing and decrementing
- SUB r1, r1, r5
- TST r0, #0x01000000 ; Pre-indexing?
- ADDEQ r1, r1, #4
- B Load_Page
-
- indexedup: TST r0, #0x01000000
- ADDNE r1, r1, #4
- B Load_Page
-
- ; Code for handling LDR and STR
- ; Base does not need to be restored.
- ; Immediate constant is 0..4095
- ; Register offset is as for basic op except no shift by register.
-
- ldrstr: CMP r3, #pc
- BICEQ r1, r1, #0xFC000003 ; Mask if base is pc
- TST r0, #0x01000000 ; Pre-indexing?
- BEQ Load_Page
- TST r0, #0x02000000 ; index is register?
- BNE indexreg
- MOV r5, r0, LSL #20
- TST r0, #0x00800000 ; Add offset to base?
- ADDNE r1, r1, r5, LSR #20
- SUBEQ r1, r1, r5, LSR #20
- B Load_Page
-
- indexreg: AND r4, r0, #0x0000000F ; contains index register
- LDR r4, [r2, r4, LSL #2] ; And index value, keep psr if pc
- AND r5, r0, #0x00000FF0 ; Get shift operand
- ORR r5, r5, #0xE0000000+4 ; Cond AL, Index register
- ORR r5, r5, #(1<<12)+(1<<16) ; base register, result
- TST r0, #0x00800000 ; Add offset to base?
- ORRNE r5, r5, #0x00800000 ; add
- ORREQ r5, r5, #0x00400000 ; sub
- STR r5, IndexAdd ; mea maxima culpa
- MOV r0, r0 ; NOP
- IndexAdd: ADD r1, r1, r4, LSL #2 ; ***** OVERWRITTEN OPERATION *****
- B Load_Page
-
- ; Code for handling Coprocessor data transfer
- ; , not that I've got one! Same code works for
- ; the floating point emulator.
-
- ldcstc: CMP r3, #pc
- BICEQ r1, r1, #0xFC000003 ; Mask if base is pc
- AND r5, r0, #0x000000FF
- TST r0, #0x00200000 ; Write-back?
- CMPNE r3, #pc ; does not apply to pc
- BEQ ldc_NoWriteback
- TST r0, #0x00800000 ; Add offset to base?
- SUBNE r1, r1, r5, LSL #2 ; Reverse writeback
- ADDEQ r1, r1, r5, LSL #2
- STR r1, [r2, r3, LSL #2] ; Base register restored
- ldc_NoWriteback:
- TST r0, #0x01000000 ; Pre-indexing?
- BEQ Load_Page
- TST r0, #0x00800000 ; Add offset to base?
- ADDNE r1, r1, r5, LSL #2
- SUBEQ r1, r1, r5, LSL #2
- B Load_Page
-
- ; Do old abort if anything wrong
- ; Only registers r0 to r7 at most changed
- ; before such an error is detected
-
- Do_Old_Abort:
- CMN r0, #1
- ADR r0, RegDump
- LDMIA r0, {r0-lr}^
- MOV r0, r0
- LDR lr, RegDump+4*pc
- LDREQ pc, VSI_Old_Abort_Pre
- LDRNE pc, VSI_Old_Abort_Adr
-
- ; Load Page
- ; Try to load a page of virtual store
- ; r0 = op, -1 if Pre_Fetch, bit 20 = 0 write else read
- ; not used here
- ; r1 = address to load
-
- Load_Page:
- MOV sl, sp, ASR #20
- MOV sl, sl, ASL #20
- LDR r2, RegDump+4*sp
- BL VSI_Check
- CMP r0, #0
- BMI Do_Old_Abort
-
- ; Start up in user mode with interrupts enabled
- ; Should not cause another VSI interrupt whilst
- ; dealing with this one.
-
- TEQP pc, #0
- MOV r0, r0
-
- CMP r0, #0
- BNE Load_InUse
-
- ADR r0, RegDump
- ADR r1, VSI_RegDump
- LDMIA r0!, {r2-r9}
- STMIA r1!, {r2-r9}
- LDMIA r0!, {r2-r9}
- STMIA r1!, {r2-r9}
- LDR r0, RestartPC
- STR r0, VSI_RestartPC
-
- Load_InUse:
- LDR sl, VSI_Stack
- LDR sp, [sl, #12] ; stack_size
- ADD sp, sp, sl
- ADD sl, sl, #0x230
- BL VSI_Service
-
- ; Restore registers and return
-
- VSI_Restore_Regs::
- LDR r0, VSI_RestartPC
- STR r0, VSI_RegDump+4*pc
- ADR r0, VSI_RegDump
- LDMIA r0, {r0-pc}^
-