chiark / gitweb /
JPEG support and other fixes from Nick Clark
[ssr] / StraySrc / Libraries / Sapphire / s / coRoutine
1 ;
2 ; coRoutine.s
3 ;
4 ; Basic coroutine handling (MDW)
5 ;
6 ; © 1994-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 ;----- External dependencies ------------------------------------------------
33
34                 GET     sapphire:alloc
35                 GET     sapphire:sapphire
36                 GET     sapphire:seh
37                 GET     sapphire:suballoc
38
39 ;----- Main code ------------------------------------------------------------
40
41                 AREA    |Sapphire$$Code|,CODE,READONLY
42
43 coRout__stkSize EQU     1024
44
45 ; --- coRout_create ---
46 ;
47 ; On entry:     R0 == pointer to coroutine
48 ;               R1 == R10 value to pass to coroutine
49 ;               R2 == R12 value to pass to coroutine
50 ;               R3 == size of stack to pass (0 for default)
51 ;
52 ; On exit:      R0 == coroutine handle
53 ;               May return an error
54 ;
55 ; Use:          Creates a new coroutine.  It may be given control using
56 ;               coRout_switch.  Its registers are on entry:
57 ;
58 ;               R0 == its coroutine handle
59 ;               R10 == value passed to coRout_create in R1
60 ;               R12 == value passed to coRout_create in R2
61 ;               R13 == pointer to the stack created for it
62
63                 EXPORT  coRout_create
64 coRout_create   ROUT
65
66                 STMFD   R13!,{R0-R4,R14}        ;Save some registers away
67
68                 ; --- Allocate a coroutine block ---
69
70                 MOV     R0,#coRout__blkSize     ;Get the block size ready
71                 BL      sub_alloc               ;Allocate the block
72                 BVS     %99coRout_create        ;Quit if it failed
73                 MOV     R4,R0                   ;Keep the block pointer
74
75                 ; --- Allocate a stack ---
76
77                 CMP     R3,#0                   ;Does he want default stack?
78                 MOVEQ   R3,#coRout__stkSize     ;Yes -- give it to him
79                 MOV     R0,R3                   ;Get the size in R0
80                 BL      alloc                   ;Try to allocate the stack
81                 BLCS    alloc_error             ;If it failed, get an error
82                 BCS     %98coRout_create        ;And quit if it didn't work
83                 STR     R0,[R4,#coRout__stack]  ;Save the stack pointer away
84
85                 ; --- Set up the try list ---
86
87                 MOV     R14,#0                  ;Must clear the list head
88                 STR     R14,[R4,#coRout__tryList] ;Save that away for later
89
90                 ; --- Fix everything up right ---
91
92                 ADD     R0,R0,R3                ;Point to the stack top
93                 ADR     R3,coRout__start        ;Point to the start routine
94                 MOV     R14,PC                  ;Get the processor flags
95                 AND     R14,R14,#&FC000003      ;Leave only the flags
96                 ORR     R14,R3,R14              ;And add them on to it
97                 MOV     R3,R2                   ;Get coroutine's R12 in R3
98                 MOV     R2,R11                  ;Point to scratchpad in R2
99                 STMFD   R0!,{R1-R3,R14}         ;And save all that lot away
100                 SUB     R0,R0,#32               ;Don't care about other regs
101                 LDR     R14,[R13,#0]            ;Load the coroutine address
102                 STMFD   R0!,{R4,R14}            ;Save them in R0 and R1
103                 STR     R0,[R4,#coRout__sp]     ;And save its stack pointer
104
105                 ; --- Return to caller ---
106
107                 MOV     R0,R4                   ;Point to the coroutine block
108                 ADD     R13,R13,#4              ;Don't restore caller's R0
109                 LDMFD   R13!,{R1-R4,R14}        ;And return to caller
110                 BICS    PC,R14,#V_flag
111
112                 ; --- Handle errors ---
113
114 98coRout_create MOV     R3,R0                   ;Save the error pointer
115                 MOV     R0,R4                   ;Point to the coroutine block
116                 MOV     R1,#coRout__blkSize     ;Get the block's size
117                 BL      sub_free                ;Free the block nicely
118                 MOV     R0,R3                   ;Restore the error pointer
119
120 99coRout_create ADD     R13,R13,#4              ;Don't restore caller's R0
121                 LDMFD   R13!,{R1-R4,R14}        ;And return to caller
122                 ORRS    PC,R14,#V_flag
123
124                 LTORG
125
126 ; --- coRout_switch ---
127 ;
128 ; On entry:     R0 == coroutine to switch to, or 0 for main
129 ;
130 ; On exit:      --
131 ;
132 ; Use:          Switches context to another coroutine.
133
134                 EXPORT  coRout_switch
135 coRout_switch   ROUT
136
137                 STMFD   R13!,{R12,R14}          ;Save some registers
138                 WSPACE  coRout__wSpace          ;Find my workspace address
139                 LDR     R14,coRout__current     ;Get the current coroutine
140                 CMP     R14,R0                  ;Switch to current one?
141                 LDMEQFD R13!,{R12,PC}^          ;Silly sausage!
142
143                 ; --- Perform a context switch ---
144
145                 STMFD   R13!,{R0-R11}           ;Save all the other registers
146                 MOV     R1,R14                  ;Move this to another reg
147                 STR     R0,coRout__current      ;Save the new coroutine
148                 BL      seh_setListBase         ;Use this try list now
149                 CMP     R1,#0                   ;Are we running main routine?
150                 ADREQ   R1,coRout__main         ;Yes -- point to dummy block
151                 CMP     R0,#0                   ;Do we switch to main routine
152                 ADREQ   R0,coRout__main         ;Yes -- point to dummy block
153                 STR     R13,[R1,#coRout__sp]    ;Save the new stack pointer
154                 LDR     R13,[R0,#coRout__sp]    ;Get a new stack pointer
155                 LDMFD   R13!,{R0-R12,PC}^       ;And switch context to it
156
157                 LTORG
158
159 ; --- coRout_destroy ---
160 ;
161 ; On entry:     R0 == coroutine handle to destroy
162 ;
163 ; On exit:      --
164 ;
165 ; Use:          Destroys a coroutine.
166
167                 EXPORT  coRout_destroy
168 coRout_destroy  ROUT
169
170                 STMFD   R13!,{R12,R14}          ;Save some registers away
171                 WSPACE  coRout__wSpace          ;Find my workspace address
172                 LDR     R14,coRout__current     ;Get the current coroutine
173                 CMP     R14,R0                  ;Terminate the current one?
174                 LDMEQFD R13!,{R12,R14}          ;Yes -- unstack registers
175                 BEQ     coRout_end              ;And end it normally
176
177                 ; --- Now just destroy a coroutine ---
178
179                 STMFD   R13!,{R0,R1}            ;Save some registers
180                 MOV     R1,R0                   ;Keep the coroutine handle
181                 LDR     R0,[R1,#coRout__stack]  ;Find the stack's address
182                 BL      free                    ;Free up the space it took
183                 MOV     R0,R1                   ;Point at the coroutine blk
184                 MOV     R1,#coRout__blkSize     ;Get the coroutine block size
185                 BL      sub_free                ;And dispose of that too
186                 LDMFD   R13!,{R0,R1,R12,PC}^    ;And return to caller
187
188                 LTORG
189
190 ; --- coRout__start ---
191 ;
192 ; On entry:     R0 == coroutine handle
193 ;               R1 == pointer to coroutine code
194 ;
195 ; On exit:      R14 == pointer to coRout_end
196 ;
197 ; Use:          Sets up a coroutine so that when it returns, it calls
198 ;               coRout_end and dies properly.
199
200 coRout__start   ROUT
201
202                 ; --- Set up a handler to kill the coroutine ---
203
204                 ADR     R0,coRout__catch        ;Point to our catch handler
205                 BL      seh_try                 ;Register that nicely
206
207                 ; --- Now start up the coroutine proper ---
208
209                 MOV     R14,PC                  ;Set up the return address
210                 MOV     PC,R1                   ;And call the main code
211
212                 ; --- Fall through into coRout_end when done ---
213
214 ; --- coRout_end ---
215 ;
216 ; On entry:     --
217 ;
218 ; On exit:      Doesn't.
219 ;
220 ; Use:          Terminates the current coroutine.
221
222                 EXPORT  coRout_end
223 coRout_end      ROUT
224
225                 ; --- Destroy the current coroutine ---
226
227                 WSPACE  coRout__wSpace          ;Find my workspace
228                 LDR     R13,coRout__main+coRout__sp ;Return to main stack
229                 LDR     R1,coRout__current      ;Get the current coroutine
230                 LDR     R0,[R1,#coRout__stack]  ;Find the stack's address
231                 BL      free                    ;Free up the space it took
232                 MOV     R0,R1                   ;Point at the coroutine blk
233                 MOV     R1,#coRout__blkSize     ;Get the coroutine block size
234                 BL      sub_free                ;And dispose of that too
235
236                 ; --- Now rejoin the main routine ---
237
238                 MOV     R0,#0                   ;Going back to main routine
239                 STR     R0,coRout__current      ;So remember that
240                 BL      seh_setListBase         ;Use main exception list
241                 LDMFD   R13!,{R0-R12,PC}^       ;And rejoin everything nicely
242
243                 LTORG
244
245 ; --- Exception handling ---
246
247 coRout__catch   MOVS    PC,R14                  ;No need for tidy-up
248                 DCD     -1                      ;Catch all exceptions
249                 B       coRout__throw           ;And throw them on again
250                 DCD     0
251
252 coRout__throw   WSPACE  coRout__wSpace          ;Find my workspace
253                 LDR     R13,coRout__main+coRout__sp ;Return to main stack
254                 STMFD   R13!,{R0-R3}            ;Remember the exception
255                 LDR     R1,coRout__current      ;Load the old coroutine hnd
256                 LDR     R0,[R1,#coRout__stack]  ;Find the stack's address
257                 BL      free                    ;Free up the space it took
258                 MOV     R0,R1                   ;Point at the coroutine blk
259                 MOV     R1,#coRout__blkSize     ;Get the coroutine block size
260                 BL      sub_free                ;And dispose of that too
261
262                 MOV     R0,#0                   ;Going back to main routine
263                 STR     R0,coRout__current      ;So remember that
264                 BL      seh_setListBase         ;Use main exception list
265                 LDMFD   R13!,{R0-R3}            ;Restore exception
266                 B       seh_throw               ;And raise it again
267
268 coRout__wSpace  DCD     0
269
270 ;----- Coroutine blocks -----------------------------------------------------
271
272                 ^       0
273 coRout__tryList #       4                       ;SEH try list head for stack
274 coRout__stack   #       4                       ;Pointer to the stack
275 coRout__sp      #       4                       ;Coroutine's current R13
276 coRout__blkSize #       0                       ;Size of a coroutine block
277
278 ;----- Workspace ------------------------------------------------------------
279
280                 ^       0,R12
281 coRout__wStart  #       0
282
283 coRout__current #       4                       ;The current coroutine or 0
284 coRout__main    #       coRout__blkSize         ;Dummy coroutine block
285
286 coRout__wSize   EQU     {VAR}-coRout__wStart
287
288                 AREA    |Sapphire$$LibData|,CODE,READONLY
289
290                 DCD     coRout__wSize
291                 DCD     coRout__wSpace
292                 DCD     0
293                 DCD     0
294
295 ;----- That's all, folks ----------------------------------------------------
296
297                 END