4 ; Structured Exception Handling, the Sapphire way
6 ; © 1995-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Sapphire library.
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ;----- Standard header ------------------------------------------------------
34 ;----- External dependencies ------------------------------------------------
40 ;----- Main code ------------------------------------------------------------
42 AREA |Sapphire$$Code|,CODE,READONLY
46 ; On entry: R0 == pointer to catch definition block
48 ; On exit: R13 dropped by a (small) amount
50 ; Use: Inserts an exception handler at the current position.
51 ; Exceptions are matched against those described in the catch
52 ; block. If there is a handler for the exception, the
53 ; corresponding handler is called, and expected to resume
54 ; normally. Otherwise the tidy-up routine is called and we
55 ; unwind the stack further to find an appropriate handler.
57 ; The catch block has the following format:
59 ; word B to tidy-up routine
60 ; word 1st exception mask
61 ; word 1st B to catch routine
62 ; word 2nd exception mask
63 ; word 2nd B to catch routine
67 ; An exception mask contains two halfwords. Bits 16-31 are the
68 ; class to match, or -1 for all classes. Bits 0-15 are the
69 ; subtype to match, or -1 for all subtypes. You can do really
70 ; odd things if you set bits 16-31 to -1 and leave 0-15
71 ; matching specific subtypes -- do this at your own risk.
76 SUB R13,R13,#16 ;Leave space for our record
77 STMFD R13!,{R0,R12,R14} ;Save some registers
79 ; --- Save caller's R10 and R12 ---
81 ADD R14,R13,#16 ;Point to area in frame
82 STMIA R14,{R0,R10,R12} ;Save the registers away
84 ; --- Now fiddle with the try list ---
86 WSPACE seh__wSpace ;Find my workspace
87 LDR R14,seh__currList ;Find the current list
88 LDR R0,[R14,#0] ;Load the current value
89 STR R0,[R13,#12] ;Save that away nicely
90 ADD R0,R13,#12 ;Point to the frame we made
91 STR R0,[R14,#0] ;This is the new list head
92 LDMFD R13!,{R0,R12,PC}^ ;And return to caller
100 ; On exit: R13 moved to position before corresponding seh_try
102 ; Use: Removes the try block marker in the stack at the current
103 ; position. Note that the stack will be unwound to where it
104 ; was when seh_try was called.
109 STMFD R13!,{R0,R1,R12,R14} ;Save some registers
110 MOV R1,R13 ;Remember this stack frame
111 WSPACE seh__wSpace ;Find my workspace
112 LDR R14,seh__currList ;Find the current list
113 LDR R13,[R14,#0] ;Load the unwound stack ptr
114 LDR R0,[R13],#16 ;Load the old list position
115 STR R0,[R14,#0] ;Store this away nicely
116 LDMIA R1,{R0,R1,R12,PC}^ ;And return to caller
122 ; On entry: R0 == exception to match
123 ; R1-R3 == useful bits of information
125 ; On exit: Doesn't return, unless you've done something /really/ odd
127 ; Use: Throws an exception. The stack is unwound until we find
128 ; a handler which can cope. If there is no handler, we abort
134 WSPACE seh__wSpace ;Find my workspace
135 LDR R9,seh__currList ;Find the current list
137 ; --- Now go through the list ---
139 05 LDR R13,[R9,#0] ;Get the top try block
140 CMP R13,#0 ;Have we run out of trys?
141 BEQ %90seh_throw ;Yes -- oh deary me
142 LDR R14,[R13],#4 ;Load the previous pointer
143 STR R14,[R9,#0] ;And store it away
144 LDMIA R13!,{R8,R10,R12} ;Load useful things out
146 ; --- Now find a matching catch ---
148 MOV R14,#&00FF ;Build &FFFF
149 ORR R14,R14,#&FF00 ;Because it's useful
151 ADD R7,R8,#4 ;Skip past tidy-up routine
152 01 LDR R6,[R7],#8 ;Load the exception mask
153 CMP R6,#0 ;Have we finished here?
154 BEQ %10seh_throw ;Yes -- deal with this then
155 MOV R5,R6,LSL #16 ;Isolate the bottom half
156 CMP R5,R14,LSL #16 ;Is it a wildcard?
157 CMPNE R5,R0,LSL #16 ;Or does it match?
158 BNE %b01 ;No -- move on then
159 MOV R5,R6,LSR #16 ;Isolate the top half
160 CMP R5,R14 ;Is it a wildcard?
161 CMPNE R5,R0,LSR #16 ;Or does it match?
162 BNE %b01 ;No -- move on then
164 SUB PC,R7,#4 ;Go and do the exception
166 10seh_throw MOV R14,PC ;Set up return address
167 MOV PC,R8 ;So call tidy-up code
168 B %b05 ;And try another block
170 ; --- No catch blocks found ---
172 ; Oh dear. Things go very badly now.
174 90seh_throw MOV R2,R0 ;Get the exception type
175 LDR R13,sapph_stackBase ;Find a stack somewhere
176 ADR R0,seh__noHandler ;Point to the error block
177 BL msgs_error ;Translate it nicely
178 B except_fatal ;Report a fatal error
185 ; --- seh_throwErrors ---
191 ; Use: Sets up an except-style error handler to throw errors
194 EXPORT seh_throwErrors
197 STMFD R13!,{R0-R2,R14} ;Save some registers
198 ADR R0,seh__handler ;Point to the handler
199 MOV R1,#0 ;Don't care about R12
200 MOV R2,#0 ;Don't even care about R13
201 BL except_returnPt ;Register that nicely
202 LDMFD R13!,{R0-R2,PC}^ ;And return to caller
204 seh__handler ADD R0,PC,#0 ;Point to `resume point'
205 MOVS PC,R14 ;And return to except
207 ADD R1,R11,#4 ;Point to error message
208 MOV R0,#&00010000 ;Exception number for error
209 B seh_throw ;Throw it to the handler
213 ; --- seh_setListBase ---
215 ; On entry: R0 == pointer to try block list base, or 0 to use global
219 ; Use: Sets the try block list base. This should only be used by
220 ; coroutine providers, like coRoutine and thread.
222 EXPORT seh_setListBase
225 STMFD R13!,{R12,R14} ;Save some registers
226 WSPACE seh__wSpace ;Find my workspace
227 MOVS R14,R0 ;Get the value to save
228 ADREQ R14,seh__tryList ;If zero, use our pointer
229 STR R14,seh__currList ;Store away in the block
230 LDMFD R13!,{R12,PC}^ ;And return to caller
240 ; Use: Initialises SEH's facilities.
245 STMFD R13!,{R12,R14} ;Save some registers
246 WSPACE seh__wSpace ;Find my workspace
247 ADR R14,seh__tryList ;Find the global list
248 STR R14,seh__currList ;This is the current one
249 LDMFD R13!,{R12,PC}^ ;And return to caller
255 ;----- Workspace ------------------------------------------------------------
260 seh__tryList # 4 ;The global try list head
261 seh__currList # 4 ;Address of current list
263 seh__wSize EQU {VAR}-seh__wStart
265 AREA |Sapphire$$LibData|,CODE,READONLY
272 ;----- That's all, folks ----------------------------------------------------