home *** CD-ROM | disk | FTP | other *** search
- // **************************************************************************
- // Copyright 1996 David Allison
- //
- // VV VV IIIIII SSSSS TTTTTT AA
- // VV VV II SS TT AA AA
- // VV VV II SSSS TT AA AA
- // VV VV II SS TT AAAAAAAA
- // VV IIIIII SSSS TT AA AA
- //
- // MULTI-THREADED C++ WIMP CLASS LIBRARY
- // for RISC OS
- // **************************************************************************
- //
- // P U B L I C D O M A I N L I C E N C E
- // -------------------------------------------
- //
- // This library is copyright. You may not sell the library for
- // profit, but you may sell products which use it providing
- // those products are presented as executable code and are not
- // libraries themselves. The library is supplied without any
- // warranty and the copyright owner cannot be held responsible for
- // damage resulting from failure of any part of this library.
- //
- // See the User Manual for details of the licence.
- //
- // *************************************************************************
-
-
- //
- // assembly language for thread package
- //
-
- #include <kernel.h>
- #include <string.h>
-
- #define XEasyDebug_RegisterThreads 0x8304a|0x20000
- #define XEasyDebug_YieldThread 0x8304b|0x20000
-
- #pragma asm
-
- IMPORT context_switch__13ThreadManagerFv
- IMPORT start2__6ThreadFv
-
- ;
- ; call the start2 member function for a thread. This actually starts the thread
- ; running
- ;
-
- ; entry:
- ; R0 = thread
-
- .thread_call_start2 EXPORT thread_call_start2
- B start2__6ThreadFv
-
- .thread_get_time EXPORT thread_get_time
- STMFD SP!,{link} ; may be called in SVC mode
- SWI OS_ReadMonotonicTime
- LDMFD SP!,{PC}^
-
-
- #define Int_bit (1 << 27)
-
- #define USR_mode 0
- #define FIQ_mode 1
- #define IRQ_mode 2
- #define SVC_mode 3
-
-
- ;
- ; claim the callback vector
- ;
-
- ; entry:
- ; R0 = thread manager address. This is passed to the callback in R12
-
- .thread_claim_callback
- EXPORT thread_claim_callback
- STMFD SP!,{R0-R3,link}
- MOV R2,R0
- MOV R0,#7
- ADR R1,callback
- LDR R3,thread_callback_regs
- SWI XOS_ChangeEnvironment
- STR R1,old_callback
- STR R2,old_callback_r12
- STR R3,old_callback_regs
- LDMFD SP!,{R0-R3,PC}^
-
- .old_callback
- DCD 0
- .old_callback_r12
- DCD 0
- .old_callback_regs
- DCD 0
-
-
- ;
- ; release the callback vector
- ;
-
-
- .thread_release_callback
- EXPORT thread_release_callback
- STMFD SP!,{R0-R3,link}
- MOV R0,#7
- LDR R1,old_callback
- LDR R2,old_callback_r12
- LDR R3,old_callback_regs
- SWI XOS_ChangeEnvironment
- LDMFD SP!,{R0-R3,PC}^
-
- ;
- ; start a ticker which will set the callback flag every clock tick
- ;
-
- ; entry:
- ; R0 = address of thread manager
-
- .thread_start_ticker
- EXPORT thread_start_ticker
- LDR R2,alien_control
- CMP R2,#0
- MOVNES PC,link
- STMFD SP!,{R0-R2,link}
- MOV R2,R0
- MOV R0,#1
- STR R0,thread_worksemaphore
- LDR R0,thread_poll_rate
- ADR R1,call_every
- SWI XOS_CallEvery
- LDMFD SP!,{R0-R2,PC}^
-
- ;
- ; stop the ticker running
- ;
-
- ; entry:
- ; R0 = thread manager
-
- .thread_stop_ticker
- EXPORT thread_stop_ticker
- LDR R2,alien_control
- CMP R2,#0
- MOVNES PC,link
- STMFD SP!,{R0-R1,link}
- MOV R1,R0
- ADR R0,call_every
- SWI XOS_RemoveTickerEvent
- LDMFD SP!,{R0-R1,PC}^
-
- ;
- ; init the thread system for use with a debugger
- ;
-
- ; entry:
- ; R0 = thread manager
-
- .thread_init EXPORT thread_init
- STMFD SP!,{R0-R8,link}
- MOV R5,R0
- BL claim_heap_modifiers
- ADR R0,thread_worksemaphore
- LDR R1,ctx_swtch
- ADR R2,thread_callback_regs
- LDR R3,thread_poll_rate
- ADR R4,thread_system_running
- SWI XEasyDebug_RegisterThreads
- MOVVS R1,#0 ; no SWI: not under control
- STRVS R1,alien_control
- LDMVSFD SP!,{R0-R8,PC}^
- CMP R0,#2 ; module running?
- MOVEQ R0,#1 ; yes, under control
- MOVNE R0,#0 ; no, we're on our own
- STR R0,alien_control
- LDMFD SP!,{R0-R8,PC}^
-
- ; this variable tells us whether we are being controlled by some outside influence
- ; EasyDebug controls the threads for us if so
-
- .alien_control
- DCD 0
-
- .ctx_swtch
- DCD context_switch__13ThreadManagerFv
-
- .thread_system_running
- EXPORT thread_system_running
- DCD 0
-
- .thread_worksemaphore ; flag for callbacks
- EXPORT thread_worksemaphore
- DCD 0
-
- .thread_callback_regs ; current register save area
- EXPORT thread_callback_regs
- DCD 0
-
- .thread_poll_rate ; quantum poll rate
- EXPORT thread_poll_rate
- DCD 0
-
- ;
- ; disable interrupts by setting the semaphore to non zero
- ;
-
- .thread_disable_ints
- EXPORT thread_disable_ints
- MOV R0,#1
- B write_ints
-
- ;
- ; enable the interrupts by setting the semaphore to 0
-
- ;
- .thread_enable_ints
- EXPORT thread_enable_ints
- MOV R0,#0
- .write_ints
- STR R0,thread_worksemaphore
- MOVS PC,link
-
- .int_state
- LDR R0,thread_worksemaphore
- MOVS PC,link
- ;
- ; the ticker calls this every clock tick
- ;
-
- .call_every
- STMFD SP!,{R0,R1,link}
- LDR R0,thread_worksemaphore
- ADD R0,R0,#1
- STR R0,thread_worksemaphore
- CMP R0,#1
- LDMNEFD SP!,{R0,R1,PC}^
- MOV R1,pc ; save current processor state
- TEQP pc,#Int_bit+SVC_mode ; disable processor interrupts
- MOV R0,R0
- STMFD SP!,{link}
- MOV R0,R12 ; load thread manager
- BL thread_claim_callback ; claim the callbacks
- SWI XOS_SetCallBack ; set the OS callback flag
- LDMFD SP!,{link}
- TEQP R1,#0 ; restore processor state
- MOV R0,R0
- LDMFD SP!,{R0,R1,PC}^
-
- ;
- ; called in usr mode by a thread wishing to give up the processor
- ;
-
- ; entry:
- ; R0 = thread manager
-
- .thread_yield
- EXPORT thread_yield
- LDR R1,alien_control
- CMP R1,#0
- SWINE XEasyDebug_YieldThread
- MOVNES PC,link
- STMFD SP!,{R0-R2,link}
- MOV R1,#1
- STR R1,thread_worksemaphore
- BL thread_claim_callback
- SWI XOS_SetCallBack
- MOV R0,#0
- MOV R1,#1
- SWI XOS_Byte ; force a callback
- LDMFD SP!,{R0-R2,PC}^
-
- ;
- ; this is called when the OS is returning from SVC mode to USR mode
- ;
-
- .callback
- MOV R0,#1
- STR R0,thread_worksemaphore ; disable callbacks
-
- TEQP PC,#SVC_mode ; enable ints
- MOV R0,R0
- MOV R4,R12 ; save thread manager
- BL thread_release_callback ; release the callback handler
-
- ; save floating point regs in save area
-
- LDR R1,thread_callback_regs
- ADD R1,R1,#16*4
- STFE F0,[R1,#0]
- STFE F1,[R1,#12]
- STFE F2,[R1,#12*2]
- STFE F3,[R1,#12*3]
- STFE F4,[R1,#12*4]
- STFE F5,[R1,#12*5]
- STFE F6,[R1,#12*6]
- STFE F7,[R1,#12*7]
- RFS R0 ; read floating status
- STR R0,[R1,#12*8]
-
- TEQP PC,#USR_mode ; into user mode
- MOV R0,R0
-
- MOV fp,#0 ; no frame pointer
- MOV R0,R4 ; get the thread manager into "this" pointer
- BL context_switch__13ThreadManagerFv ; switch to another thread
-
- SWI OS_EnterOS ; back to supervisor mode
- MOV R0,R0
-
- ; now reload the registers from the save area
-
- LDR R1,thread_callback_regs
- ADD R1,R1,#16*4
- LDFE F0,[R1,#0]
- LDFE F1,[R1,#12]
- LDFE F2,[R1,#12*2]
- LDFE F3,[R1,#12*3]
- LDFE F4,[R1,#12*4]
- LDFE F5,[R1,#12*5]
- LDFE F6,[R1,#12*6]
- LDFE F7,[R1,#12*7]
- LDR R0,[R1,#12*8]
- WFS R0 ; write floating status
-
- MOV R0,#0
- STR R0,thread_worksemaphore ; enable the interrupts
- SUB R14,R1,#16*4 ; get address of USR mode integer registers
- LDMIA R14,{R0-R14}^ ; load USR mode regs
- MOV R0,R0
- TEQP PC,#Int_bit+SVC_mode ; disable ints
- MOV R0,R0
- LDR R14,[R14,#15*4] ; load the old PC value
- MOVS PC,R14 ; return
-
- ; entry:
- ; R0 = save area
-
- .thread_init_save_area
- EXPORT thread_init_save_area
- STMFD SP!,{R0,R1,link}
- ADD R1,R0,#16*4
- STFE F0,[R1,#0]
- STFE F1,[R1,#12]
- STFE F2,[R1,#12*2]
- STFE F3,[R1,#12*3]
- STFE F4,[R1,#12*4]
- STFE F5,[R1,#12*5]
- STFE F6,[R1,#12*6]
- STFE F7,[R1,#12*7]
- RFS R0 ; read floating status
- STR R0,[R1,#12*8]
- LDMFD SP!,{R0,R1,PC}^
-
-
- ;
- ; claim the functions that modify the heap.
- ;
-
- ; this claims the following functions:
- ; malloc
- ; free
- ; calloc
- ; realloc
-
- ; and makes sure that the threads are diabled on each call
-
-
- .claimed_malloc
- DCD 0
-
- .my_malloc
- STMFD SP!,{R4-R5,link}
- MOV R4,R0
- BL int_state
- MOV R5,R0
- BL thread_disable_ints
- MOV R0,R4
- MOV R14,PC
- LDR PC,claimed_malloc
- MOV R4,R0
- CMP R5,#0
- BLEQ thread_enable_ints
- MOV R0,R4
- LDMFD SP!,{R4-R5,PC}^
-
- .claimed_free
- DCD 0
-
- .my_free
- STMFD SP!,{R4-R5,link}
- MOV R4,R0
- BL int_state
- MOV R5,R0
- BL thread_disable_ints
- MOV R0,R4
- MOV R14,PC
- LDR PC,claimed_free
- MOV R4,R0
- CMP R5,#0
- BLEQ thread_enable_ints
- MOV R0,R4
- LDMFD SP!,{R4-R5,PC}^
-
- .claimed_calloc
- DCD 0
-
- .my_calloc
- STMFD SP!,{R4-R5,link}
- MOV R4,R0
- BL int_state
- MOV R5,R0
- BL thread_disable_ints
- MOV R0,R4
- MOV R14,PC
- LDR PC,claimed_calloc
- MOV R4,R0
- CMP R5,#0
- BLEQ thread_enable_ints
- MOV R0,R4
- LDMFD SP!,{R4-R5,PC}^
-
- .claimed_realloc
- DCD 0
-
- .my_realloc
- STMFD SP!,{R4-R5,link}
- MOV R4,R0
- BL int_state
- MOV R5,R0
- BL thread_disable_ints
- MOV R0,R4
- MOV R14,PC
- LDR PC,claimed_realloc
- MOV R4,R0
- CMP R5,#0
- BLEQ thread_enable_ints
- MOV R0,R4
- LDMFD SP!,{R4-R5,PC}^
-
-
- IMPORT malloc
- IMPORT free
- IMPORT realloc
- IMPORT calloc
-
- .malloc_addr
- DCD malloc
- .free_addr
- DCD free
- .realloc_addr
- DCD realloc
- .calloc_addr
- DCD calloc
-
- .claim_heap_modifiers
- STMFD SP!,{link}
- LDR R0,malloc_addr ; get address of malloc
- ADR R1,claimed_malloc
- ADR R2,my_malloc
- BL claim_vector
- LDR R0,free_addr ; get address of free
- ADR R1,claimed_free
- ADR R2,my_free
- BL claim_vector
- LDR R0,calloc_addr ; get address of calloc
- ADR R1,claimed_calloc
- ADR R2,my_calloc
- BL claim_vector
- LDR R0,realloc_addr ; get address of realloc
- ADR R1,claimed_realloc
- ADR R2,my_realloc
- BL claim_vector
- LDMFD SP!,{PC}^
-
- ;
- ; claim a vector
- ;
-
- ; entry:
- ; R0 = address of vector to claim
- ; R1 = address of word to hold old vector address
- ; R2 = new vector address
-
- .claim_vector
- STMFD SP!,{R0-R3,link}
- MOV R3,R0
- LDR R0,[R3,#0] ; get B instruction
- BIC R0,R0,#0xff000000 ; offset in words
- MOV R0,R0,LSL #2 ; offset in bytes
- ADD R0,R0,R3 ; add to malloc address
- ADD R0,R0,#8 ; add for pipelining
- STR R0,[R1,#0] ; store in old place
- SUB R0,R2,R3 ; calc offset from branch to routine
- SUB R0,R0,#8 ; remove pipelining
- MOV R0,R0,LSR #2 ; in words
- ORR R0,R0,#0xEA000000 ; make branch
- STR R0,[R3,#0] ; store in vector position
- LDMFD SP!,{R0-R3,PC}^
-
-
- #pragma endasm
-