--- /dev/null
+REM
+REM tearSupt.bs
+REM
+REM TearoffSupport code (encrypted)
+REM
+REM © 1994-1998 Straylight
+REM
+
+REM ----- Licensing note ----------------------------------------------------
+REM
+REM This file is part of Straylight's Tearoff Menu System (TMS), but it's
+REM distributed with Straylight's core libraries (corelib).
+REM
+REM TMS is free software; you can redistribute it and/or modify
+REM it under the terms of the GNU General Public License as published by
+REM the Free Software Foundation; either version 2, or (at your option)
+REM any later version
+REM
+REM TMS is distributed in the hope that it will be useful,
+REM but WITHOUT ANY WARRANTY; without even the implied warranty of
+REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+REM GNU General Public License for more details.
+REM
+REM You should have received a copy of the GNU General Public License
+REM along with Corelib. If not, write to the Free Software Foundation,
+REM 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+LIBRARY "libs:BAS"
+
+ON ERROR ERROR 0,REPORT$+" ["+STR$(ERL)+"]"
+PROCbas_init
+PROCbas_aofInit(&4000)
+
+XOS_ClaimProcessorVector=&20069
+XOS_SynchroniseCodeAreas=&2006E
+
+PRINT "Assembling...";
+
+ts_version=110
+
+FOR o=4 TO 6 STEP 2
+[ opt o
+ FNpass
+
+;----- TearoffSupport interface code ----------------------------------------
+
+ FNarea("Asm$$Code","CODE,READONLY")
+
+; --- tearSupport_init ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Initialises tearSupport
+
+ FNexport("tearSupport_init")
+.tearSupport_init
+
+ stmfd r13!,{r0-r4,r12,r14} ;Save some registers
+ mvn r0,#0 ;Find address of TearSupport
+ swi "XOS_ChangeEnvironment" ;Find the address then
+ bvc tSupt_init10 ;If resident, skip install
+
+ ; --- We need to set up the RMA block ---
+
+.tSupt_init00 ldr r3,ts__image ;Load RMA block size wanted
+ mov r0,#6 ;Allocate RMA space
+ swi "OS_Module" ;Try to allocate anyway
+ mov r1,r2 ;Keep pointer to RMA block
+
+ ; --- Copy the program across and decrypt it ---
+
+ adr r0,ts__image+4 ;Point to encrypted image
+ ldr r3,FNlitw(ts__imageEnd-ts__image-4)
+ ldr r12,FNlitw(&1b9a7f83) ;IV for decryption process
+
+.tSupt_init05 ldr r4,[r0],#4 ;Get a word from the image
+ eor r14,r12,r4,ror #24 ;Decrypt the word
+ str r14,[r2],#4 ;Store the word in the block
+ mov r12,r4 ;Update IV from ciphertext
+ subs r3,r3,#4 ;Decrement the size counter
+ bgt tSupt_init05 ;More to do -- loop
+
+ ; --- Be friendly to StrongARM ---
+ ;
+ ; By spooky coincidence, these registers are set up already.
+
+ mov r0,#1 ;Synchronise address range
+ sub r2,r2,#4 ;Because Acorn are weird...
+ swi XOS_SynchroniseCodeAreas ;Go and do that, please
+
+ ; --- Initialise the image ---
+
+ mov r14,pc ;Get return address
+ add pc,r1,#0 ;Call the initialise routine
+ str r1,ts__image ;Store base address away
+ ldmfd r13!,{r0-r4,r12,pc}^ ;Return to caller
+
+ ; --- It's already resident ---
+
+.tSupt_init10 cmp r2,#ts_version ;Which version is in there?
+ strcs r1,ts__image ;New enough -- store base
+ ldmcsfd r13!,{r0-r4,r12,pc}^ ;And return to caller
+
+ adr r0,ts__tooOld ;Point to error message
+ swi "OS_GenerateError" ;And raise merry hell
+ ldmfd r13!,{r0-r4,r12,pc}^ ;Return to caller
+
+.ts__tooOld dcd 1
+ dcb "Tearoff support code is too old"
+ dcb 0
+
+ FNltorg
+
+; --- tearSupport_opened ---
+;
+; On entry; R0 == task handle of task which opened tearoff menu
+;
+; On exit; --
+;
+; Use; Informs TearSupport that a transient tearoff menu has been
+; opened, and which task owns the menu.
+
+ FNexport("tearSupport_opened")
+.tearSupport_opened
+
+ stmfd r13!,{r12,r14}
+ ldr r12,ts__image
+ mov r14,pc
+ add pc,r12,#4
+ ldmfd r13!,{r12,pc}^
+
+; --- tearSupport_closed ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Informs TearSupport that a transient tearoff menu has been
+; closed, and that support is no longer required for it.
+
+ FNexport("tearSupport_closed")
+.tearSupport_closed
+
+ stmfd r13!,{r12,r14}
+ ldr r12,ts__image
+ mov r14,pc
+ add pc,r12,#8
+ ldmfd r13!,{r12,pc}^
+
+; --- tearSupport_switch ---
+;
+; On entry; R0 == 1 to disable, 0 to enable trapping
+;
+; On exit; --
+;
+; Use; Enables or disables trapping of Wimp_CreateMenu while a
+; transient tearoff menu is open. This is intended to allow
+; use of Wimp_CreateMenu by the transient tearoff owner while
+; a transient tearoff is open (e.g. to close Wimp menus).
+
+ FNexport("tearSupport_switch")
+.tearSupport_switch
+
+ stmfd r13!,{r12,r14}
+ ldr r12,ts__image
+ mov r14,pc
+ add pc,r12,#12
+ ldmfd r13!,{r12,pc}^
+
+;----- The actual TearoffSupport code ---------------------------------------
+
+; --- Structure of the code ---
+;
+; Since this chunk is going to be copied into the RMA, we need to be able to
+; interface with it. We stick a branch table on the beginning and encrypt
+; everything else.
+
+ FNnoReloc
+
+.ts__image dcd ts__wSize+ts__wSpace-ts__image-4
+ b ts_init
+ b ts_opened
+ b ts_closed
+ b ts_switch
+ b ts_unload
+
+;----- Initialisation -------------------------------------------------------
+
+; --- ts_init ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Initialises the TearSupport system.
+
+.ts_init stmfd r13!,{r0-r2,r14} ;Stack link register nicely
+ FNadrl (r12,ts__wSpace) ;Find workspace address
+ mov r0,#0 ;A nice 0 value
+ str r0,[r12,#ts_useCount] ;Stuff it in the usage count
+ str r0,[r12,#ts_owner] ;No task using me yet
+ strb r0,[r12,#ts_swiCaught] ;Remember we're not on SWIV
+
+ mov r0,#ChangeEnvV ;Trap OS_ChangeEnvironment
+ adr r1,ts_changeEnv ;Point to my handler
+ mov r2,r12 ;Pass my workspace pointer
+ swi "XOS_Claim" ;Claim the vector nicely
+
+ ; --- Read the OS version ---
+
+ mov r0,#129 ;Load the OS version number
+ mov r1,#0 ;Set up OS_Byte arguments
+ mov r2,#255 ;For most obscure OS call
+ swi "OS_Byte" ;Read the version number
+ strb r1,[r12,#ts_osVersion] ;Save this away for later
+
+ ; --- I think that's it ---
+
+ ldmfd r13!,{r0-r2,pc}^ ;Return to caller happy
+
+ FNltorg
+
+; --- ts_unload ---
+;
+; On entry; --
+;
+; On exit; V clear if unloaded OK, otherwise V set
+;
+; Use; Attempts to remove TearSupt from memory, to replace it with
+; a later version. If we can't close down, because we're in
+; use, we return an error.
+
+.ts_unload bic r14,r14,#&10000000 ;Clear the V flag
+ stmfd r13!,{r0-r2,r14} ;Save some registers
+ FNadrl (r12,ts__wSpace) ;Find the workspace address
+
+ ; --- Free all the vectors ---
+
+ mov r0,#ChangeEnvV ;Trap OS_ChangeEnvironment
+ adr r1,ts_changeEnv ;Point to my handler
+ mov r2,r12 ;Pass my workspace pointer
+ swi "XOS_Release" ;Let go of that
+
+ bl ts_closed ;Pretend the transient closed
+
+ ; --- Deallocate my memory ---
+ ;
+ ; This is a bit tricky, because I'm in it. I have to
+ ; copy a bit of myself onto the stack, and call that. Yuk.
+
+ adr r14,ts__return ;Point to return code
+ ldmia r14,{r0-r2} ;Load the code out
+ stmfd r13!,{r0-r2} ;Save it onto the stack
+
+ adr r2,ts__image+4 ;Point to the block base
+ mov r0,#7 ;Deallocate an RMA block
+ mov pc,r13 ;Call return code
+
+.ts__return swi "OS_Module" ;Deallocate the memory
+ add r13,r13,#12 ;Point to stack frame
+ ldmfd r13!,{r0-r2,pc}^ ;Return without mishap
+
+ FNltorg
+
+; --- Vector numbers ---
+]
+MouseV = &1A
+InsV = &14
+ChangeEnvV = &1E
+[ opt o
+
+; --- ts_opened ---
+;
+; On entry; R0 == task handle attempting to open tearoff transient
+;
+; On exit; --
+;
+; Use; Informs the TearSupt system that a task is opening a
+; transient tearoff menu.
+
+
+.ts_opened stmfd r13!,{r0-r2,r11,r12,r14}
+ mov r11,r0 ;Look after the task handle
+ FNadrl (r12,ts__wSpace) ;Find my workspace address
+
+ ; --- Make sure we need to do this ---
+
+ ldr r0,[r12,#ts_useCount] ;Get the counter
+ cmp r0,#0 ;Am I currently running?
+ bne ts_opened00 ;Yes -- skip this little bit
+
+ ; --- Claim event vector ---
+
+ swi "XOS_Mouse" ;Get the current mouse pos
+ str r2,[r12,#ts_mouseState] ;Store it in workspace
+
+ mov r0,#MouseV ;Vector number
+ adr r1,ts_mouse ;Point to event handler
+ mov r2,r12 ;Point to workspace
+ swi "XOS_Claim" ;Try it and see
+
+ mov r0,#InsV ;Vector number
+ adr r1,ts_insert ;Point to event handler
+ mov r2,r12 ;Point to workspace
+ swi "XOS_Claim" ;Try it and see
+
+ addvs r13,r13,#4
+ ldmvsfd r13!,{r1,r2,r11,r12,pc} ;Can't see this failing, but
+
+ bl ts_swiClaim
+
+ ; --- Update my tables and leave ---
+
+.ts_opened00 ldr r0,[r12,#ts_owner] ;Who's using me at the mo?
+ cmp r0,r11 ;Is it someone else?
+ cmpne r0,#0 ;Make sure s'not a ghost
+ blne ts_escape_cb ;Tell the appl to close
+ str r11,[r12,#ts_owner] ;Store the new handle
+
+ ldr r0,[r12,#ts_useCount] ;Find my usage counter
+ add r0,r0,#1 ;Bump it
+ str r0,[r12,#ts_useCount] ;And store it back for later
+
+ ldmfd r13!,{r0-r2,r11,r12,pc}^
+
+ FNltorg
+
+; --- ts_closed ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Informs TearSupt that the transient tearoff has been closed.
+; If no transient is open, no action is performed.
+
+.ts_closed stmfd r13!,{r12,r14} ;Save some registers
+ adr r12,ts__wSpace ;Find my workspace address
+ ldr r14,[r12,#ts_useCount] ;Find out my counter thing
+ cmp r14,#0 ;Is it zero?
+ ldmeqfd r13!,{r12,pc}^ ;Someone's being silly
+ subs r14,r14,#1 ;Decrement the counter
+ str r14,[r12,#ts_useCount] ;Store for later
+ ldmnefd r13!,{r12,pc}^ ;Return if still nonzero
+
+ ; --- Remove handlers and things ---
+
+ stmfd r13!,{r0-r2} ;Save some more registers
+ bl ts_swiRelease ;Release SWI vector patch
+
+ mov r0,#InsV ;Vector number
+ adr r1,ts_insert ;Point to handler code
+ mov r2,r12 ;Point to workspace
+ swi "XOS_Release" ;Let go of the vector
+
+ mov r0,#MouseV ;Vector number
+ adr r1,ts_mouse ;Point to handler code
+ mov r2,r12 ;Point to workspace
+ swi "XOS_Release" ;Let go of the vector
+
+ ldmfd r13!,{r0-r2,r12,pc}^ ;Return to caller
+
+ FNltorg
+
+; --- ts_switch ---
+;
+; On entry; R0 == 1 to suspend trapping, 0 to unsuspend
+;
+; On exit; --
+;
+; Use; Enables or disables trapping of Wimp_CreateMenu, to enable
+; TMS implementations to close Wimp menus where necessary.
+
+.ts_switch stmfd r13!,{r12,r14} ;Save some registers
+ adr r12,ts__wSpace ;Find my workspace
+ strb r0,[r12,#ts_swiThreaded] ;Disable the SWI patch
+ ldmfd r13!,{r12,pc}^ ;And return to caller
+
+ FNltorg
+
+;----- The handlers and callbacks -------------------------------------------
+
+; --- ts_changeEnv ---
+;
+; On entry; As for OS_ChangeEnvironment
+;
+; On exit; R0 == address of TearSupt, if R0 == -1 on entry
+;
+; Use; Traps odd calls to OS_ChangeEnvironment to allow TearSupt
+; to be located.
+
+.ts_changeEnv cmn r0,#1 ;Is it our special env code?
+ adreq r1,ts__image+4 ;Yes -- return ptr to base
+ moveq r2,#ts_version ;And get the version number
+ ldmeqfd r13!,{pc}^ ;And claim the vector
+ movs pc,r14 ;Otherwise pass on vector
+
+; --- ts_insert ---
+;
+; On entry; R0 == byte inserted into buffer
+; R1 == buffer number
+;
+; On exit; --
+;
+; Use; Inspects all insertions into buffers, and traps attempts
+; to insert escape keypresses, converting these to requests
+; to close the current transient tearoff.
+
+.ts_insert cmp r0,#27 ;Make sure it's an escape
+ cmpeq r1,#0 ;And it's from the keyboard
+ movnes pc,r14 ;If not, give up and leave
+ stmfd r13!,{r14} ;Save a register
+ ldr r14,[r12,#ts_owner] ;Get my owner's ID
+ cmn r14,#1 ;Is it valid?
+ ldmeqfd r13!,{pc}^ ;No -- then return to caller
+
+ ; --- Mess about with the processor status ---
+
+ stmfd r13!,{r0,r1,r8} ;Store registers away
+ mov r8,pc ;Get PC with PSR
+ teqp pc,#3 ;Enter SVC mode
+ mov r0,r0 ;Avoid contention of R13/R14
+ stmfd r13!,{r14} ;Stack return address
+ adr r0,ts_escape_cb ;Point to callback routine
+ mov r1,r12 ;Point to workspace
+ swi "XOS_AddCallBack" ;Add the callback routine
+ ldmfd r13!,{r14} ;Restore R14_svc
+ teqp r8,#0 ;Restore old PSR values
+ mov r0,r0 ;No-op to keep ARM happy
+ ldmfd r13!,{r0,r1,r8,pc}^ ;Return to caller
+
+ FNltorg
+
+; --- ts_mouse ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Inspects all mouse positions returned by OS_Mouse, and sends
+; them to the current transient owner.
+
+.ts_mouse stmfd r13!,{r10-r12,r14} ;Stack some registers
+
+ ; --- Pass on the vector, leaving ourself on the stack ---
+ ;
+ ; Modified from Acorn's code to avoid dependency on
+ ; possibly non-compatible PC+12 behaviour.
+
+ mov r14,pc ;Get current program counter
+ add r14,r14,#12 ;Point at our processing code
+ stmfd r13!,{r14} ;Make us get called back
+ add r12,r13,#4 ;Point to saved R10 on stack
+ ldmia r12,{r10-r12,pc} ;Call next routine on vector
+
+ ; --- The vector has now completed nicely ---
+
+ ldr r12,[r13,#8] ;Get my stacked r12
+
+ stmfd r13!,{r0-r3} ;Stack some registers for me
+ ldr r0,[r12,#ts_mouseState] ;Get old mouse state
+ str r2,[r12,#ts_mouseState] ;Store as the old state
+ bics r2,r2,r0 ;Find out what changed
+ ldmeqfd r13!,{r0-r3,r10-r12,r14,pc} ;If nothing then return
+
+ ; --- A button was clicked -- tell our client ---
+
+ add r1,r12,#ts_message+20 ;Point to message buffer
+ swi "XWimp_GetPointerInfo" ;Get pointer info
+ sub r1,r1,#20 ;Point to base of message
+ mov r0,#40 ;Length of message
+ str r0,[r1,#0] ;Store in message block
+ mov r0,#0 ;This isn't a reply
+ str r0,[r1,#12] ;So zero the your_ref
+ ldr r0,FNlitw(&4A340) ;The magic message number
+ str r0,[r1,#16] ;Fill it in
+ mov r0,#17 ;Don't want it bouncing
+ ldr r2,[r12,#ts_owner] ;Find my owner application
+ swi "XWimp_SendMessage" ;Send it the message
+
+ ldmfd r13!,{r0-r3,r10-r12,r14,pc} ;We're a happy bunny
+
+ FNltorg
+
+; --- ts_escape_cb ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Sends a message to the transient tearoff owner, to tell
+; it to close the transient. This is usually as a result of
+; the user pressing escape or another task calling
+; Wimp_CreateMenu.
+
+.ts_escape_cb stmfd r13!,{r0-r3,r14} ;Save some registers
+ add r1,r12,#ts_message ;Point to message buffer
+ mov r0,#20 ;Length of message
+ str r0,[r1,#0] ;Store in message block
+ mov r0,#0 ;This isn't a reply
+ str r0,[r1,#12] ;So zero the your_ref
+ ldr r0,FNlitw(&4A341) ;The magic message number
+ str r0,[r1,#16] ;Fill it in
+ mov r0,#17 ;Don't want it bouncing
+ ldr r2,[r12,#ts_owner] ;Find my owner application
+ swi "XWimp_SendMessage" ;Send it the message
+ mvn r0,#0 ;Stop it happening again
+ str r0,[r12,#ts_owner] ;Won't happen now!
+ ldmfd r13!,{r0-r3,pc}^ ;Don't worry. Be happy.
+
+ FNltorg
+
+;----- SWI vector handling --------------------------------------------------
+;
+; Warning; this section contains some really heavy stuff. If you're nervous,
+; you may wish to seek medical advice before looking at this code. We can't
+; accept any responsibility for any loss or disability incurred as a result
+; of reading this source.
+
+; --- ts_swiClaim ---
+;
+; On entry; --
+;
+; On exit; --
+;
+; Use; Sets up the SWI vector patch.
+
+.ts_swiClaim stmfd r13!,{r0-r3,r14} ;Stack some registers
+ ldrb r0,[r12,#ts_swiCaught] ;Have we done it already?
+ cmp r0,#0 ;Just check
+ ldmnefd r13!,{r0-r3,pc}^ ;If so, just carry on
+
+ ldrb r14,[r12,#ts_osVersion] ;Get the OS version
+ cmp r14,#&a5 ;Is this a RISC PC?
+ bcs ts_swiClaim50 ;Yes -- do special things
+
+ mov r0,#0 ;Point to hardware vectors
+ ldr r1,[r0,#&08] ;Get the SWIV instruction
+ str r1,[r12,#ts_oldSWIinstr] ;Remember this instruction
+ and r2,r1,#&0F000000 ;Get the basic instruction
+ cmp r2,#&0A000000 ;Is it a branch?
+ beq ts_swiClaim00 ;Yes -- handle that
+
+ ; --- Mangle an LDR PC,[PC,#...] ---
+
+ ldr r2,FNlitw(&FFF) ;Mask off LDR bits
+ and r2,r1,r2 ;Get the offset of LDR
+ tst r1,#1<<23 ;Check the sign bit
+ addne r3,r2,#&10 ;If additive, then add offset
+ rsbeq r3,r2,#&10 ;If subtractive, subtract ;-)
+ str r3,[r12,#ts_oldSWIaddr] ;Store this address away
+ b ts_swiClaim01 ;Now insert our branch code
+
+ ; --- Mangle a B ... ---
+
+.ts_swiClaim00 bic r2,r1,#&FF000000 ;Clear instruction bits
+ add r2,r2,#4 ;Take pipeline into account
+ mov r2,r2,lsl #2 ;Word align the result
+ bic r2,r2,#&FC000003 ;Turn it into a real address
+ str r2,[r12,#ts_dummySWIptr] ;Store this in our pointer
+ add r3,r12,#ts_dummySWIptr ;Point to this pointer
+ str r3,[r12,#ts_oldSWIaddr] ;Store *this* address away
+
+ ; --- Now insert our own instruction ---
+
+.ts_swiClaim01 adr r1,ts_swiClaimer ;Point to the routine
+ mov r1,r1,lsr #2 ;Shift off bottom zero bits
+ sub r1,r1,#4 ;Adjust the address of branch
+ orr r1,r1,#&EA000000 ;Make it a branch instr
+ str r1,[r12,#ts_newSWIinstr] ;Store this new instruction
+ swi "OS_EnterOS" ;We're messing with SWI vect
+ str r1,[r0,#8] ;This is now the SWI vector
+ teqp pc,#0 ;Back to user mode
+ mov r0,r0 ;No-op for strange reasons
+ mov r0,#1 ;We've now patched SWIV
+ strb r0,[r12,#ts_swiCaught] ;So remember this
+ mov r0,#0 ;Not yet threaded, though
+ strb r0,[r12,#ts_swiThreaded]
+ ldmfd r13!,{r0-r3,pc}^ ;Return to caller
+
+ ; --- We have an OS call to do this ---
+
+.ts_swiClaim50 mov r0,#2 ;Claim SWI vector
+ orr r0,r0,#256 ;Set the `claim' flag
+ adr r1,ts_swi610 ;Point to handler routine
+ swi "XOS_IntOff" ;Stop all SWIs for a bit
+ swi XOS_ClaimProcessorVector
+ str r1,[r12,#ts_dummySWIptr] ;Save old handler address
+ add r3,r12,#ts_dummySWIptr ;Point to this pointer
+ str r3,[r12,#ts_oldSWIaddr] ;And store *this* address
+ swi "XOS_IntOn" ;We can handle SWIs again now
+
+ mov r0,#1 ;We've now patched SWIV
+ strb r0,[r12,#ts_swiCaught] ;So remember this
+ mov r0,#0 ;Not yet threaded, though
+ strb r0,[r12,#ts_swiThreaded]
+
+ ldmfd r13!,{r0-r3,pc}^ ;Return to caller
+
+ FNltorg
+
+; --- ts_swiRelease ---
+;
+; On entry; --
+;
+; On exit; CS if patch removed OK, else CC
+;
+; Use; Attempts to remove the SWI vector patch. If this can't be
+; done, then the patch is left in.
+
+.ts_swiRelease stmfd r13!,{r0-r2,r14} ;Stack registers
+ ldrb r0,[r12,#ts_swiCaught] ;Is the vector trapped?
+ cmp r0,#0 ;Quick check...
+ ldmeqfd r13!,{r0-r2,pc}^ ;No -- return then
+
+ ; --- Check if this is a RISC PC ---
+
+ ldrb r0,[r12,#ts_osVersion] ;Load the OS version
+ cmp r0,#&a5 ;Is this a RISC PC
+ bcs ts_swiRel50 ;Yes -- do different things
+
+ mov r0,#0 ;Point to hardware vectors
+ ldr r1,[r0,#8] ;Get SWI vector instruction
+ ldr r2,[r12,#ts_newSWIinstr] ;Get our one
+ cmp r1,r2 ;Are they the same?
+ bne ts_swiRel90 ;No -- couldn't reset it
+
+ ldr r1,[r12,#ts_oldSWIinstr] ;Get the old version then
+ swi "OS_EnterOS" ;We're messing with SWI vect
+ str r1,[r0,#8] ;Reinstate the old vector
+ teqp pc,#0 ;Back to user mode
+ mov r0,r0 ;Wait for things to settle
+ strb r0,[r12,#ts_swiCaught] ;SWIV no longer patched
+ ldmfd r13!,{r0-r2,r14} ;Return to caller
+ orrs pc,r14,#1<<29 ;Setting C to say *YES*
+
+ ; --- Release SWI vector using OS call ---
+
+.ts_swiRel50 mov r0,#2 ;Releasing the SWI vector
+ ldr r1,[r12,#ts_dummySWIptr] ;Load address of old claimer
+ adr r2,ts_swi610 ;Point to expected handler
+ swi XOS_ClaimProcessorVector
+ bvs ts_swiRel90 ;Error -- couldn't do it
+
+ mov r14,#0 ;Clear claimed flag
+ strb r14,[r12,#ts_swiCaught] ;SWIV no longer patched
+ ldmfd r13!,{r0-r2,r14} ;Return to caller
+ orrs pc,r14,#1<<29 ;Setting C to say *YES*
+
+ ; --- Couldn't do it ---
+
+.ts_swiRel90 ldmfd r13!,{r0-r2,r14} ;Restore registers
+ bics pc,r14,#1<<29 ;But clear C on exit
+
+ FNltorg
+
+; --- ts_swi610 ---
+;
+; On entry; R0-R8 == arguments to SWI
+; R9-R12 == random values from the OS
+; R13 == supervisor stack pointer
+; R14 == return address from client
+;
+; On exit; R0-R8 == returned from SWI
+; R9-R13 *AND SPSR_svc* preserved
+;
+; Use; Intercepts all SWI calls in the system, catching
+; Wimp_CreateMenus and informing the transient owner of them.
+
+.ts_swi610 stmfd r13!,{r10-r12,r14,pc} ;Stack some registers
+
+ ; --- Move into 26 bit mode ---
+
+ dcd &e14fb000 ;mrs r11,spsr_all
+ stmfd r13!,{r11} ;Save this on the stack
+ and r12,r11,#&f0000003 ;Get the processor status
+ orr r14,r14,r12 ;Add it to the R14 value
+ and r12,r11,#&c0 ;Get the interrupt flags
+ orr r14,r14,r12,lsl #20 ;Put them into R14 too
+ dcd &e10fb000 ;mrs r11,cpsr_all
+ bic r11,r11,#&1f ;Clear all the mode bits
+ orr r11,r11,#&03 ;Set SVC_26
+ dcd &e129f00b ;msr cpsr_all,r11
+
+ ; --- Now find out about the SWI ---
+
+ adr r12,ts__wSpace ;Point to workspace pointer
+ ldrb r10,[r12,#ts_swiThreaded] ;Is this routine threaded?
+ cmp r10,#0 ;Check now, or forever...
+ bne ts_swi610_00 ;If so, skip onwards
+ bic r10,r14,#&FC000003 ;Mask off saved PSR bits
+ ldr r11,[r10,#-4] ;Get SWI instruction
+ ldr r10,FNlitw(&FFF20000) ;Mask off silly SWI bits
+ bic r11,r11,r10 ;Get the pure SWI number
+ ldr r10,FNlitw(FNswiNum("Wimp_CreateMenu"))
+ cmp r10,r11 ;See if it's interesting
+ beq ts_swi610_10 ;Yes -- process it nicely
+
+.ts_swi610_00 ldmfd r13!,{r14} ;Load the saved SPSR
+ dcd &e169f00e ;msr spsr_all,r14
+
+ ldr r14,[r12,#ts_oldSWIaddr] ;Point to old pointer
+ ldr r14,[r14,#0] ;Dereference the pointer
+ str r14,[r13,#16] ;Overwrite PC on the stack
+ ldmfd r13!,{r10-r12,r14,pc} ;Pass on to real SWI routine
+
+ ; --- Wimp_CreateMenu handling ---
+
+.ts_swi610_10 mov r10,#1 ;Set the threaded flag
+ strb r10,[r12,#ts_swiThreaded] ;Remember we're in here
+
+ bl ts_escape_cb ;Send out the close message
+
+.ts_swi610_01 mov r10,#0 ;Not threaded any more
+ strb r10,[r12,#ts_swiThreaded] ;Store this for others
+ b ts_swi610_00 ;And continue main thread
+
+ FNltorg
+
+; --- ts_swiClaimer ---
+;
+; On entry; R0-R8 == arguments to SWI
+; R9-R12 == random values from the OS
+; R13 == supervisor stack pointer
+; R14 == return address from client
+;
+; On exit; R0-R8 == returned from SWI
+; R9-R13 preserved
+;
+; Use; Intercepts all SWI calls in the system, catching
+; Wimp_CreateMenus and informing the transient owner of them.
+
+.ts_swiClaimer stmfd r13!,{r10-r12,r14,pc} ;Stack some registers
+ adr r12,ts__wSpace ;Point to workspace pointer
+ ldrb r10,[r12,#ts_swiThreaded] ;Is this routine threaded?
+ cmp r10,#0 ;Check now, or forever...
+ bne ts_swiClaimer00 ;If so, skip onwards
+ bic r10,r14,#&FC000003 ;Mask off saved PSR bits
+ ldr r11,[r10,#-4] ;Get SWI instruction
+ ldr r10,FNlitw(&FFF20000) ;Mask off silly SWI bits
+ bic r11,r11,r10 ;Get the pure SWI number
+ ldr r10,FNlitw(FNswiNum("Wimp_CreateMenu"))
+ cmp r10,r11 ;See if it's interesting
+ beq ts_swiClaimer10 ;Yes -- process it nicely
+
+.ts_swiClaimer00
+ ldr r14,[r12,#ts_oldSWIaddr] ;Point to old pointer
+ ldr r14,[r14,#0] ;Dereference the pointer
+ str r14,[r13,#16] ;Overwrite PC on the stack
+ ldmfd r13!,{r10-r12,r14,pc} ;Pass on to real SWI routine
+
+ ; --- Wimp_CreateMenu handling ---
+
+.ts_swiClaimer10
+ mov r10,#1 ;Set the threaded flag
+ strb r10,[r12,#ts_swiThreaded] ;Remember we're in here
+
+ bl ts_escape_cb ;Send out the close message
+
+.ts_swiClaimer01
+ mov r10,#0 ;Not threaded any more
+ strb r10,[r12,#ts_swiThreaded] ;Store this for others
+ b ts_swiClaimer00 ;And continue main thread
+
+ FNltorg
+
+.ts__wSpace
+.ts__imageEnd
+]
+
+ PROCws_start
+ts_useCount =FNws_word
+ts_owner =FNws_word
+ts_mouseState =FNws_word
+ts_newMouse =FNws_word
+ts_oldSWIaddr =FNws_word
+ts_dummySWIptr =FNws_word
+ts_oldSWIinstr =FNws_word
+ts_newSWIinstr =FNws_word
+ts_swiCaught =FNws_byte
+ts_swiThreaded =FNws_byte
+ts_osVersion =FNws_byte
+ PROCws_align
+ts_message =FNws (40)
+ts__wSize =FNws (0)
+
+NEXT
+
+PRINT '"Encrypting...";
+
+REM --- Encrypt the RMA resident section ---
+
+iv%=&1b9a7f83
+FOR i%=ts__image+4 TO ts__imageEnd STEP 4
+ x%=i%!(O%-P%) EOR iv%
+ x%=(x%>>>8) OR (x%<<24)
+ i%!(O%-P%)=x%
+ iv%=x%
+NEXT
+
+PRINT '"Saving...";
+PROCbas_aofSave
+PRINT '"Done"
+END
+
+DEF FNswiNum(swi$)
+LOCAL swin%
+SYS "OS_SWINumberFromString",,swi$ TO swin%
+=swin%
+