home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 2
/
AUCD2.iso
/
program
/
vista.arc
/
c
/
tasm
< prev
next >
Wrap
Text File
|
1996-02-01
|
12KB
|
501 lines
// **************************************************************************
// 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