home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 2
/
AUCD2.iso
/
program
/
vista.arc
/
s
/
tasm
Wrap
Text File
|
1996-01-17
|
22KB
|
778 lines
; **************************************************************************
; Copyright 1995 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
;
; C++ WIMP CLASS LIBRARY
; for RISC OS
; **************************************************************************
;
; E A S Y C + + U S E R L I C E N C E
; ----------------------------------------
;
; This library is copyright. It is supplied as part of Easy C++ as
; source. The library may NOT be copied nor placed in any publically
; accessible place (eg a Bulletin Board). 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.
;
; *************************************************************************
;
; assembly language for thread package
;
AREA |Threads$code|, CODE, READONLY
XEasyDebug_RegisterThreads EQU 0x8304a + 0x20000
XEasyDebug_YieldThread EQU 0x8304b + 0x20000
R0 RN 0
R1 RN 1
R2 RN 2
R3 RN 3
R4 RN 4
R5 RN 5
R6 RN 6
R7 RN 7
R8 RN 8
R9 RN 9
R10 RN 10
R11 RN 11
R12 RN 12
R13 RN 13
R14 RN 14
R15 RN 15
PC RN 15
link RN 14
SP RN 13
vp RN 12 ; variable pointer
F0 FN 0
F1 FN 1
F2 FN 2
F3 FN 3
F4 FN 4
F5 FN 5
F6 FN 6
F7 FN 7
; SWI numbers
OS_WriteC EQU 0
OS_WriteS EQU 1
OS_WriteO EQU 2
OS_Newline EQU 3
OS_ReadC EQU 4
OS_CLI EQU 5
OS_Byte EQU 6
OS_Word EQU 7
OS_File EQU 8
OS_Args EQU 9
OS_Bget EQU 10
OS_Bput EQU 11
OS_Gbpb EQU 12
OS_Find EQU 13
OS_ReadLine EQU 14
OS_Control EQU 15
OS_GetEnv EQU 16
OS_Exit EQU 17
OS_SetEnv EQU 18
OS_IntOn EQU 19
OS_IntOff EQU 20
OS_CallBack EQU 21
OS_EnterOS EQU 22
OS_BreakPt EQU 23
OS_BreakCntrl EQU 24
OS_UnusedSWI EQU 25
OS_UpdateMEMC EQU 26
OS_SetCallBack EQU 27
OS_Mouse EQU 28
OS_Heap EQU 29
OS_Module EQU 30
OS_Claim EQU 31
OS_Release EQU 32
OS_ReadUnsigned EQU 33
OS_GenerateEvent EQU 34
OS_ReadVarVal EQU 35
OS_SetVarVal EQU 36
OS_GSInit EQU 37
OS_GSRead EQU 38
OS_GSTrans EQU 39
OS_BinaryToDecimal EQU 40
OS_FSControl EQU 41
OS_ChangeDynamicArea EQU 42
OS_GenerateError EQU 43
OS_ReadEscapeState EQU 44
OS_EvaluateExpression EQU 45
OS_SpriteOp EQU 46
OS_ReadPalette EQU 47
OS_ServiceCall EQU 48
OS_ReadVduVariables EQU 49
OS_ReadPoint EQU 50
OS_UpCall EQU 51
OS_CallAVector EQU 52
OS_ReadModeVariable EQU 53
OS_RemoveCursors EQU 54
OS_RestoreCursors EQU 55
OS_SWINumberToString EQU 56
OS_SWINumberFromString EQU 57
OS_ValidateAddress EQU 58
OS_CallAfter EQU 59
OS_CallEvery EQU 60
OS_RemoveTickerEvent EQU 61
OS_InstallKeyHandler EQU 62
OS_CheckModeValid EQU 63
OS_ChangeEnvironment EQU 64
OS_ClaimScreenMemory EQU 65
OS_ReadMonotonicTime EQU 66
OS_PrettyPrint EQU &44
OS_Plot EQU &45
OS_WriteN EQU &46
OS_HeapSort EQU &4F
OS_CRC EQU &5B
OS_ConvertStandardDateAndTime EQU 192
OS_ConvertDateAndTime EQU 193
OS_ConvertHex1 EQU 208
OS_ConvertHex2 EQU 209
OS_ConvertHex4 EQU 210
OS_ConvertHex6 EQU 211
OS_ConvertHex8 EQU 212
OS_ConvertCardinal1 EQU 213
OS_ConvertCardinal2 EQU 214
OS_ConvertCardinal3 EQU 215
OS_ConvertCardinal4 EQU 216
OS_ConvertInteger1 EQU 217
OS_ConvertInteger2 EQU 218
OS_ConvertInteger3 EQU 219
OS_ConvertInteger4 EQU 220
OS_ConvertBinary1 EQU 221
OS_ConvertBinary2 EQU 222
OS_ConvertBinary3 EQU 223
OS_ConvertBinary4 EQU 224
OS_ConvertSpacedCardinal1 EQU 225
OS_ConvertSpacedCardinal2 EQU 226
OS_ConvertSpacedCardinal3 EQU 227
OS_ConvertSpacedCardinal4 EQU 228
OS_ConvertSpacedInteger1 EQU 229
OS_ConvertSpacedInteger2 EQU 230
OS_ConvertSpacedInteger3 EQU 231
OS_ConvertSpacedInteger4 EQU 232
OS_ConvertFixedNetStation EQU 233
OS_ConvertNetStation EQU 234
OS_WriteI EQU 256
XOS_WriteC EQU 2_100000000000000000+0
XOS_WriteS EQU 2_100000000000000000+1
XOS_WriteO EQU 2_100000000000000000+2
XOS_Newline EQU 2_100000000000000000+3
XOS_ReadC EQU 2_100000000000000000+4
XOS_CLI EQU 2_100000000000000000+5
XOS_Byte EQU 2_100000000000000000+6
XOS_Word EQU 2_100000000000000000+7
XOS_File EQU 2_100000000000000000+8
XOS_Args EQU 2_100000000000000000+9
XOS_Bget EQU 2_100000000000000000+10
XOS_Bput EQU 2_100000000000000000+11
XOS_Gbpb EQU 2_100000000000000000+12
XOS_Find EQU 2_100000000000000000+13
XOS_ReadLine EQU 2_100000000000000000+14
XOS_Control EQU 2_100000000000000000+15
XOS_GetEnv EQU 2_100000000000000000+16
XOS_Exit EQU 2_100000000000000000+17
XOS_SetEnv EQU 2_100000000000000000+18
XOS_IntOn EQU 2_100000000000000000+19
XOS_IntOff EQU 2_100000000000000000+20
XOS_CallBack EQU 2_100000000000000000+21
XOS_EnterOS EQU 2_100000000000000000+22
XOS_BreakPt EQU 2_100000000000000000+23
XOS_BreakCntrl EQU 2_100000000000000000+24
XOS_UnusedSWI EQU 2_100000000000000000+25
XOS_UpdateMEMC EQU 2_100000000000000000+26
XOS_SetCallBack EQU 2_100000000000000000+27
XOS_Mouse EQU 2_100000000000000000+28
XOS_Heap EQU 2_100000000000000000+29
XOS_Module EQU 2_100000000000000000+30
XOS_Claim EQU 2_100000000000000000+31
XOS_Release EQU 2_100000000000000000+32
XOS_ReadUnsigned EQU 2_100000000000000000+33
XOS_GenerateEvent EQU 2_100000000000000000+34
XOS_ReadVarVal EQU 2_100000000000000000+35
XOS_SetVarVal EQU 2_100000000000000000+36
XOS_GSInit EQU 2_100000000000000000+37
XOS_GSRead EQU 2_100000000000000000+38
XOS_GSTrans EQU 2_100000000000000000+39
XOS_BinaryToDecimal EQU 2_100000000000000000+40
XOS_FSControl EQU 2_100000000000000000+41
XOS_ChangeDynamicArea EQU 2_100000000000000000+42
XOS_GenerateError EQU 2_100000000000000000+43
XOS_ReadEscapeState EQU 2_100000000000000000+44
XOS_EvaluateExpression EQU 2_100000000000000000+45
XOS_SpriteOp EQU 2_100000000000000000+46
XOS_ReadPalette EQU 2_100000000000000000+47
XOS_ServiceCall EQU 2_100000000000000000+48
XOS_ReadVduVariables EQU 2_100000000000000000+49
XOS_ReadPoint EQU 2_100000000000000000+50
XOS_UpCall EQU 2_100000000000000000+51
XOS_CallAVector EQU 2_100000000000000000+52
XOS_ReadModeVariable EQU 2_100000000000000000+53
XOS_RemoveCursors EQU 2_100000000000000000+54
XOS_RestoreCursors EQU 2_100000000000000000+55
XOS_SWINumberToString EQU 2_100000000000000000+56
XOS_SWINumberFromString EQU 2_100000000000000000+57
XOS_ValidateAddress EQU 2_100000000000000000+58
XOS_CallAfter EQU 2_100000000000000000+59
XOS_CallEvery EQU 2_100000000000000000+60
XOS_RemoveTickerEvent EQU 2_100000000000000000+61
XOS_InstallKeyHandler EQU 2_100000000000000000+62
XOS_CheckModeValid EQU 2_100000000000000000+63
XOS_ChangeEnvironment EQU 2_100000000000000000+64
XOS_ClaimScreenMemory EQU 2_100000000000000000+65
XOS_ReadMonotonicTime EQU 2_100000000000000000+66
XOS_PrettyPrint EQU 2_100000000000000000+&44
XOS_Plot EQU 2_100000000000000000+&45
XOS_WriteN EQU 2_100000000000000000+&46
XOS_ConvertStandardDateAndTime EQU 2_100000000000000000+192
XOS_ConvertDateAndTime EQU 2_100000000000000000+193
XOS_ConvertHex1 EQU 2_100000000000000000+208
XOS_ConvertHex2 EQU 2_100000000000000000+209
XOS_ConvertHex4 EQU 2_100000000000000000+210
XOS_ConvertHex6 EQU 2_100000000000000000+211
XOS_ConvertHex8 EQU 2_100000000000000000+212
XOS_ConvertCardinal1 EQU 2_100000000000000000+213
XOS_ConvertCardinal2 EQU 2_100000000000000000+214
XOS_ConvertCardinal3 EQU 2_100000000000000000+215
XOS_ConvertCardinal4 EQU 2_100000000000000000+216
XOS_ConvertInteger1 EQU 2_100000000000000000+217
XOS_ConvertInteger2 EQU 2_100000000000000000+218
XOS_ConvertInteger3 EQU 2_100000000000000000+219
XOS_ConvertInteger4 EQU 2_100000000000000000+220
XOS_ConvertBinary1 EQU 2_100000000000000000+221
XOS_ConvertBinary2 EQU 2_100000000000000000+222
XOS_ConvertBinary3 EQU 2_100000000000000000+223
XOS_ConvertBinary4 EQU 2_100000000000000000+224
XOS_ConvertSpacedCardinal1 EQU 2_100000000000000000+225
XOS_ConvertSpacedCardinal2 EQU 2_100000000000000000+226
XOS_ConvertSpacedCardinal3 EQU 2_100000000000000000+227
XOS_ConvertSpacedCardinal4 EQU 2_100000000000000000+228
XOS_ConvertSpacedInteger1 EQU 2_100000000000000000+229
XOS_ConvertSpacedInteger2 EQU 2_100000000000000000+230
XOS_ConvertSpacedInteger3 EQU 2_100000000000000000+231
XOS_ConvertSpacedInteger4 EQU 2_100000000000000000+232
XOS_ConvertFixedNetStation EQU 2_100000000000000000+233
XOS_ConvertNetStation EQU 2_100000000000000000+234
XOS_WriteI EQU 2_100000000000000000+256
wimp_Initialise EQU &400c0
wimp_Poll EQU &400c7
wimp_Closedown EQU &400dd
wimp_ReportError EQU &400df
wimp_SendMessage EQU &400e7
wimp_BlockCopy EQU &400eb
wimp_SlotSize EQU &400ec
wimp_ClaimFreeMemory EQU &400ee
wimp_CommandWindow EQU &400ef
wimp_TransferBlock EQU &400f1
wimp_ReadSysInfo EQU &400f2
wimp_StartTask EQU &400de
Xwimp_Initialise EQU 2_100000000000000000+&400c0
Xwimp_Poll EQU 2_100000000000000000+&400c7
Xwimp_Closedown EQU 2_100000000000000000+&400dd
Xwimp_ReportError EQU 2_100000000000000000+&400df
Xwimp_SendMessage EQU 2_100000000000000000+&400e7
Xwimp_BlockCopy EQU 2_100000000000000000+&400eb
Xwimp_SlotSize EQU 2_100000000000000000+&400ec
Xwimp_ClaimFreeMemory EQU 2_100000000000000000+&400ee
Xwimp_CommandWindow EQU 2_100000000000000000+&400ef
Xwimp_TransferBlock EQU 2_100000000000000000+&400f1
Xwimp_ReadSysInfo EQU 2_100000000000000000+&400f2
Xwimp_StartTask EQU 2_100000000000000000+&400de
DDEUtils_ThrowbackStart EQU &42587
DDEUtils_ThrowbackSend EQU &42588
DDEUtils_ThrowbackEnd EQU &42589
XDDEUtils_ThrowbackStart EQU 2_100000000000000000+&42587
XDDEUtils_ThrowbackSend EQU 2_100000000000000000+&42588
XDDEUtils_ThrowbackEnd EQU 2_100000000000000000+&42589
Throwback_ReasonProcessing EQU 0
Throwback_ReasonErrorDetails EQU 1
Throwback_ReasonInfoDetails EQU 2
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}^
Int_bit EQU (1 << 27)
USR_mode EQU 0
FIQ_mode EQU 1
IRQ_mode EQU 2
SVC_mode EQU 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}^
END