Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / seh
1 ;
2 ; seh.s
3 ;
4 ; Structured Exception Handling, the Sapphire way
5 ;
6 ; © 1995-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
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)
16 ; any later version.
17 ;
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.
22 ;
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.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 GET sapphire:except
37 GET sapphire:msgs
38 GET sapphire:sapphire
39
40 ;----- Main code ------------------------------------------------------------
41
42 AREA |Sapphire$$Code|,CODE,READONLY
43
44 ; --- seh_try ---
45 ;
46 ; On entry: R0 == pointer to catch definition block
47 ;
48 ; On exit: R13 dropped by a (small) amount
49 ;
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.
56 ;
57 ; The catch block has the following format:
58 ;
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
64 ; ...
65 ; word 0
66 ;
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.
72
73 EXPORT seh_try
74 seh_try ROUT
75
76 SUB R13,R13,#16 ;Leave space for our record
77 STMFD R13!,{R0,R12,R14} ;Save some registers
78
79 ; --- Save caller's R10 and R12 ---
80
81 ADD R14,R13,#16 ;Point to area in frame
82 STMIA R14,{R0,R10,R12} ;Save the registers away
83
84 ; --- Now fiddle with the try list ---
85
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
93
94 LTORG
95
96 ; --- seh_unTry ---
97 ;
98 ; On entry: --
99 ;
100 ; On exit: R13 moved to position before corresponding seh_try
101 ;
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.
105
106 EXPORT seh_unTry
107 seh_unTry ROUT
108
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
117
118 LTORG
119
120 ; --- seh_throw ---
121 ;
122 ; On entry: R0 == exception to match
123 ; R1-R3 == useful bits of information
124 ;
125 ; On exit: Doesn't return, unless you've done something /really/ odd
126 ;
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
129 ; the program.
130
131 EXPORT seh_throw
132 seh_throw ROUT
133
134 WSPACE seh__wSpace ;Find my workspace
135 LDR R9,seh__currList ;Find the current list
136
137 ; --- Now go through the list ---
138
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
145
146 ; --- Now find a matching catch ---
147
148 MOV R14,#&00FF ;Build &FFFF
149 ORR R14,R14,#&FF00 ;Because it's useful
150
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
163
164 SUB PC,R7,#4 ;Go and do the exception
165
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
169
170 ; --- No catch blocks found ---
171 ;
172 ; Oh dear. Things go very badly now.
173
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
179
180 seh__noHandler DCD 1
181 DCB "sehNOHND",0
182
183 LTORG
184
185 ; --- seh_throwErrors ---
186 ;
187 ; On entry: --
188 ;
189 ; On exit: --
190 ;
191 ; Use: Sets up an except-style error handler to throw errors
192 ; as SEH exceptions.
193
194 EXPORT seh_throwErrors
195 seh_throwErrors ROUT
196
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
203
204 seh__handler ADD R0,PC,#0 ;Point to `resume point'
205 MOVS PC,R14 ;And return to except
206
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
210
211 LTORG
212
213 ; --- seh_setListBase ---
214 ;
215 ; On entry: R0 == pointer to try block list base, or 0 to use global
216 ;
217 ; On exit: --
218 ;
219 ; Use: Sets the try block list base. This should only be used by
220 ; coroutine providers, like coRoutine and thread.
221
222 EXPORT seh_setListBase
223 seh_setListBase ROUT
224
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
231
232 LTORG
233
234 ; --- seh_init ---
235 ;
236 ; On entry: --
237 ;
238 ; On exit: --
239 ;
240 ; Use: Initialises SEH's facilities.
241
242 EXPORT seh_init
243 seh_init ROUT
244
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
250
251 LTORG
252
253 seh__wSpace DCD 0
254
255 ;----- Workspace ------------------------------------------------------------
256
257 ^ 0,R12
258 seh__wStart # 0
259
260 seh__tryList # 4 ;The global try list head
261 seh__currList # 4 ;Address of current list
262
263 seh__wSize EQU {VAR}-seh__wStart
264
265 AREA |Sapphire$$LibData|,CODE,READONLY
266
267 DCD seh__wSize
268 DCD seh__wSpace
269 DCD 0
270 DCD seh_init
271
272 ;----- That's all, folks ----------------------------------------------------
273
274 END