chiark / gitweb /
JPEG support and other fixes from Nick Clark
[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