Create readable text `.bas' for each tokenized BASIC `,ffb' file.
[ssr] / StraySrc / Libraries / Core / TearSupt / bs / tearSupt.bas
diff --git a/StraySrc/Libraries/Core/TearSupt/bs/tearSupt.bas b/StraySrc/Libraries/Core/TearSupt/bs/tearSupt.bas
new file mode 100644 (file)
index 0000000..20b3426
--- /dev/null
@@ -0,0 +1,812 @@
+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%
+