chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Sapphire / xfer / s / xsave
1 ;
2 ; xfer.xsave.s
3 ;
4 ; Simplified saving with coroutines (MDW)
5 ;
6 ; © 1994 Straylight
7 ;
8
9 ;----- Standard header ------------------------------------------------------
10
11                 GET     libs:header
12                 GET     libs:swis
13
14 ;----- External dependencies ------------------------------------------------
15
16                 GET     sapphire:alloc
17                 GET     sapphire:coRoutine
18                 GET     sapphire:fastMove
19                 GET     sapphire:sapphire
20
21 ;----- How it all works -----------------------------------------------------
22 ;
23 ; xsave attempts to unify the two saving routines you have to give (the saver
24 ; and the sender) and provide the same interface to both.  For data sending
25 ; through RAM transfer, this has to be done using coroutines, but this is
26 ; fairly invisible to you.
27 ;
28 ; There are two main routines, xsave_save and xsave_send which start save
29 ; jobs.  They take a pointer to a save routine with R10 and R12 pointers.
30 ; xsave_save also takes a pointer to a filename.  The actual save routine
31 ; should be the same for both.
32 ;
33 ; Saving of data is done with the call xsave_block.  This just writes out
34 ; a block of data somehow.  All the other routines are special interfaces to
35 ; xsave_block.
36
37 ;----- How the error handling works -----------------------------------------
38 ;
39 ; The really tricky bit is passing of errors during a RAM transfer.
40 ; Errors can be returned at two places -- in the user code (e.g. running out
41 ; of memory) and by save's cunning message handling if the receiver dies.
42 ; All errors must be handled by user code, to release claimed memory etc.
43 ;
44 ; The error gets passed along a path like this:
45 ;
46 ; Error created by user code
47 ;
48 ; user code --> xsave__startCo --> xsave_failed
49 ;
50 ; Error created by remote receiver
51 ;
52 ; xsave_failed --> xsave__write --> user code --> xsave__startCo
53
54 ;----- Main code ------------------------------------------------------------
55
56                 AREA    |Sapphire$$Code|,CODE,READONLY
57
58 ; --- xsave_save ---
59 ;
60 ; On entry:     R0 == pointer to saver routine
61 ;               R1 == R10 value to pass to saver
62 ;               R2 == R12 value to pass to saver
63 ;               R3 == pointer to filename to save to
64 ;               R4 == filetype of file to save
65 ;
66 ; On exit:      May return an error
67 ;
68 ; Use:          Calls a generalised saver routine to write data to a file.
69
70                 EXPORT  xsave_save
71 xsave_save      ROUT
72
73                 STMFD   R13!,{R0-R5,R10,R12,R14} ;Save lots of registers
74                 WSPACE  xsave__wSpace           ;Find my workspace address
75
76                 ; --- First, try to allocate a buffer ---
77
78                 BL      xsave__setBuff          ;Allocate the buffer nicely
79                 BVS     %99xsave_save           ;If we couldn't, tidy up
80
81                 ; --- Set up the file for writing ---
82
83                 MOV     R1,R3                   ;Point at the file name
84                 MOV     R0,#&8F                 ;Lots of errors, no path
85                 SWI     XOS_Find                ;Try to open the file
86                 BVS     %98xsave_save           ;Tidy up if it wouldn't open
87                 STR     R0,xsave__file          ;Save the file handle away
88
89                 ; --- Set up flags and let rip ---
90
91                 LDR     R14,xsave__flags        ;Load my current flags word
92                 AND     R14,R14,#xsFlag__inited ;Only leave inited flag
93                 STR     R14,xsave__flags        ;Save the flags back again
94
95                 LDMIA   R13,{R0,R10,R12}        ;Load the arguments out
96                 ADDS    R0,R0,#0                ;Clear overflow and carry
97                 MOV     R14,PC                  ;Set up the return address
98                 MOV     PC,R0                   ;And call the saver routine
99                 WSPACE  xsave__wSpace           ;Restore my workspace ptr
100                 BVS     %97xsave_save           ;Tidy up if it failed
101
102                 ; --- Write the remainder of the file ---
103
104                 ADR     R14,xsave__buffer       ;Point to the buffer info
105                 LDMIA   R14,{R0,R1}             ;Load buffer addr and size
106                 BL      xsave__write            ;Write it out to the file
107                 BVS     %97xsave_save           ;Tidy up if it failed
108
109                 ; --- Close the file and set the filetype ---
110
111                 MOV     R0,#0                   ;Close an open file
112                 LDR     R1,xsave__file          ;Get the file handle ready
113                 SWI     OS_Find                 ;Close it
114
115                 MOV     R0,#18                  ;Set file type
116                 MOV     R1,R3                   ;Point to the filename
117                 MOV     R2,R4                   ;And get the filetype
118                 SWI     OS_File                 ;And set the filetype
119
120                 ; --- Get rid of the buffer and return ---
121
122                 BL      xsave__loseBuff         ;Free up the buffer space
123                 LDMFD   R13!,{R0-R5,R10,R12,R14} ;Unstack all the registers
124                 BICS    PC,R14,#V_flag          ;And return to caller
125
126                 ; --- Tidy up after various catastrophes ---
127
128 97xsave_save    MOV     R10,R0                  ;Keep the error pointer
129                 MOV     R0,#0                   ;Close an open file
130                 LDR     R1,xsave__file          ;Get the file handle ready
131                 SWI     OS_Find                 ;Close it
132                 MOV     R0,#6                   ;Delete the file now
133                 MOV     R1,R3                   ;Point to the filename
134                 SWI     XOS_File                ;Delete it as much as we can
135                 MOV     R0,R10                  ;Restore the error pointer
136
137 98xsave_save    BL      xsave__loseBuff         ;Free up the buffer space
138
139 99xsave_save    ADD     R13,R13,#4              ;Don't restore R0 on exit
140                 LDMFD   R13!,{R1-R5,R10,R12,R14} ;Unstack all the registers
141                 ORRS    PC,R14,#V_flag          ;And return to caller
142
143 ; --- xsave_send ---
144 ;
145 ; On entry:     R0 == pointer to saver routine
146 ;               R1 == R10 value to pass to saver
147 ;               R2 == R12 value to pass to saver
148 ;
149 ; On exit:      R0 == pointer to block to send
150 ;               R1 == size of block
151 ;               CS if this is the last block, else CC
152 ;               May return an error
153 ;
154 ; Use:          Calls a generalised saver routine to write data to another
155 ;               application, using RAM transfer.  Note that you must call
156 ;               this routine from your send entry point throughout the
157 ;               save operation.
158
159                 EXPORT  xsave_send
160 xsave_send      ROUT
161
162                 STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers away
163                 WSPACE  xsave__wSpace           ;Find my workspace address
164
165                 ; --- Find out if we need to set anything up ---
166
167                 LDR     R14,xsave__flags        ;Load my flags word
168                 TST     R14,#xsFlag__ramTran    ;Are we doing RAM transfer?
169                 BNE     %50xsave_send           ;Yes -- continue te job then
170
171                 ; --- Clear all the flags for now ---
172
173                 AND     R4,R14,#xsFlag__inited  ;Leave only `initialised'
174                 STR     R4,xsave__flags         ;And save these flags back
175
176                 ; --- Set things up for RAM transfer ---
177
178                 BL      xsave__setBuff          ;Set up my buffer nicely
179                 BVS     %99xsave_send           ;If it failed, tidy up
180
181                 ADR     R0,xsave__startCo       ;Point to my coroutine
182                 MOV     R1,R13                  ;Point R10 at the stack
183                 MOV     R2,R12                  ;Pass workspace in R12
184                 MOV     R3,#0                   ;Use a default stack
185                 BL      coRout_create           ;Create a coroutine
186                 BVS     %98xsave_send           ;If it failed, tidy up
187                 STR     R0,xsave__coRout        ;Save the coroutine handle
188
189                 ; --- Set up the flags properly now ---
190
191                 ORR     R4,R4,#xsFlag__ramTran  ;Say we're RAM transfering
192                 STR     R4,xsave__flags         ;And save these flags back
193
194                 ; --- Get some more data to send ---
195
196 50xsave_send    LDR     R0,xsave__coRout        ;Get the coroutine handle
197                 BL      coRout_switch           ;Switch to it for a bit
198
199                 LDR     R14,xsave__flags        ;Get the newly updated flags
200                 TST     R14,#xsFlag__error      ;Was there an error?
201                 LDRNE   R0,xsave__error         ;Yes -- load the error ptr
202                 BNE     %99xsave_send           ;And tidy everything up
203
204                 ; --- Get the returned block ---
205
206                 ADR     R0,xsave__start         ;Point to the block info
207                 LDMIA   R0,{R0,R1}              ;Load the start and length
208                 TST     R14,#xsFlag__finish     ;Has the transfer finished?
209                 ADD     R13,R13,#8              ;Don't restore R0,R1
210                 LDMFD   R13!,{R2-R4,R12,R14}    ;Unstack lots of registers
211                 ORRNES  PC,R14,#C_flag          ;If finished, set C flag
212                 BICEQS  PC,R14,#C_flag          ;Otherwise say more to come
213
214                 ; --- Handle errors from various things ---
215
216 98xsave_send    BL      xsave__loseBuff         ;Close the buffer
217
218 99xsave_send    ADD     R13,R13,#4              ;Don't restore R0 on exit
219                 LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack lots of registers
220                 ORRS    PC,R14,#V_flag          ;And return the error
221
222                 LTORG
223
224 ; --- xsave__startCo ---
225 ;
226 ; On entry:     R0 == my coroutine handle
227 ;               R10 == pointer to block containing (routine,R10,R12)
228 ;               R12 == my workspace
229 ;
230 ; On exit:      Returns through coRout_end
231 ;
232 ; Use:          Starts the coroutine for sending data by RAM transfer.  It
233 ;               handles errors reported by it, and terminates the transfer
234 ;               properly.
235
236 xsave__startCo  ROUT
237
238                 LDMIA   R10,{R0,R10,R12}        ;Load the caller's registers
239                 MOV     R14,PC                  ;Set up a return address
240                 MOV     PC,R0                   ;And call the saver routine
241
242                 ; --- Handle its return values ---
243
244                 WSPACE  xsave__wSpace           ;Locate my workspace address
245                 LDR     R14,xsave__flags        ;Load the flags word
246                 BVS     %90xsave__startCo       ;If error, handle it nicely
247
248                 ; --- Just return the current buffer state ---
249
250                 ORR     R14,R14,#xsFlag__finish ;Set the finished flag
251                 STR     R14,xsave__flags        ;Save the flags back again
252                 ADR     R14,xsave__buffer       ;Point to the buffer info
253                 LDMIA   R14,{R0,R1}             ;Load the start and size info
254                 ADR     R14,xsave__start        ;Point to return information
255                 STMIA   R14,{R0,R1}             ;Save this to be sent next
256                 B       coRout_end              ;And terminate the coroutine
257
258 90              ORR     R14,R14,#xsFlag__error  ;Set the main error flag
259                 STR     R14,xsave__flags        ;Save the flags back again
260                 STR     R0,xsave__error         ;And save the error pointer
261                 B       coRout_end              ;And finish the coroutine
262
263                 LTORG
264
265 ; --- xsave_done ---
266 ;
267 ; On entry:     --
268 ;
269 ; On exit:      --
270 ;
271 ; Use:          Tidies up after a successful save job.
272
273                 EXPORT  xsave_done
274 xsave_done      ROUT
275
276                 STMFD   R13!,{R12,R14}          ;Save some registers
277                 WSPACE  xsave__wSpace           ;Find my workspace
278                 LDR     R14,xsave__flags        ;Load my flags word
279                 TST     R14,#xsFlag__ramTran    ;Are we using RAM transfer?
280                 BLNE    xsave__loseBuff         ;Yes -- destroy the buffer
281                 LDMFD   R13!,{R12,PC}^          ;Return to caller
282
283                 LTORG
284
285 ; --- xsave_failed ---
286 ;
287 ; On entry:     R0 == pointer to error block
288 ;
289 ; On exit:      --
290 ;
291 ; Use:          Tidies up a RAM transfer after an error.
292
293                 EXPORT  xsave_failed
294 xsave_failed    ROUT
295
296                 STMFD   R13!,{R12,R14}          ;Save some registers
297                 WSPACE  xsave__wSpace           ;Find my workspace
298                 LDR     R14,xsave__flags        ;Load my flags word
299                 TST     R14,#xsFlag__ramTran    ;Are we using RAM transfer?
300                 LDMEQFD R13!,{R12,PC}^          ;No -- return right now then
301
302                 ; --- Find out if the user has seen the error yet ---
303                 ;
304                 ; We also don't want to inform the user if the save is
305                 ; complete -- his coroutine will already be destroyed.
306
307                 STMFD   R13!,{R0}               ;Save some more registers
308                 TST     R14,#xsFlag__finish :OR: xsFlag__error
309                 BNE     %30xsave_failed         ;Yes -- then don't switch
310
311                 ; --- Get xsave__write to return an error ---
312
313                 ORR     R14,R14,#xsFlag__error  ;Set the error flag
314                 STR     R0,xsave__error         ;And save the error pointer
315                 LDR     R0,xsave__coRout        ;Load the coroutine handle
316                 BL      coRout_switch           ;And switch to it
317
318                 ; --- Now tidy everything up ---
319                 ;
320                 ; The coroutine should have killed itself by now
321
322 30xsave_failed  BL      xsave__loseBuff         ;Kill off the data buffer
323                 LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
324
325                 LTORG
326
327 ; --- xsave__setBuff ---
328 ;
329 ; On entry:     --
330 ;
331 ; On exit:      May return an error
332 ;
333 ; Use:          Sets up the buffer for a data transfer.
334
335 xsave__setBuff  ROUT
336
337                 STMFD   R13!,{R0-R2,R14}        ;Save some registers
338
339                 ; --- Allocate the buffer memory ---
340
341                 MOV     R0,#xsave__buffSize     ;Get the buffer size
342                 BL      alloc                   ;Try to allocate the buffer
343                 BLCS    alloc_error             ;Get an error if it failed
344                 BCS     %90xsave__setBuff       ;And tidy things up
345
346                 ; --- Set up los of variables ---
347
348                 ADR     R14,xsave__buffer       ;Point at the buffer info
349                 MOV     R1,#0                   ;No buffer used yet
350                 MOV     R2,#0                   ;No data sent yet either
351                 STMIA   R14,{R0-R2}             ;Save these values away
352                 LDMFD   R13!,{R0-R2,R14}        ;Restore all the registers
353                 BICS    PC,R14,#V_flag          ;And return with V clear
354
355                 ; --- Report an error ---
356
357 90              ADD     R13,R13,#4              ;Don't restore R0 on exit
358                 LDMFD   R13!,{R1,R2,R14}        ;Restore all the registers
359                 ORRS    PC,R14,#V_flag          ;And return with V set
360
361                 LTORG
362
363 ; --- xsave__loseBuff ---
364 ;
365 ; On entry:     --
366 ;
367 ; On exit:      --
368 ;
369 ; Use:          Kills off the buffer.
370
371 xsave__loseBuff ROUT
372
373                 STMFD   R13!,{R0,R14}           ;Save some registers
374                 LDR     R0,xsave__buffer        ;Load the buffer address
375                 BL      free                    ;Free the buffer
376                 LDR     R14,xsave__flags        ;Load my current flags word
377                 AND     R14,R14,#xsFlag__inited ;Only leave inited flag
378                 STR     R14,xsave__flags        ;Save the flags back again
379                 LDMFD   R13!,{R0,PC}^           ;And return to caller
380
381                 LTORG
382
383 ; --- xsave_byte ---
384 ;
385 ; On entry:     R0 == byte to write in lowest 8 bits
386 ;
387 ; On exit:      May return an error
388 ;
389 ; Use:          Writes a single byte to the current output.
390
391                 EXPORT  xsave_byte
392 xsave_byte      ROUT
393
394                 STMFD   R13!,{R0,R1,R14}        ;Save some registers
395                 MOV     R0,R13                  ;Point to saved byte
396                 MOV     R1,#1                   ;Just write one byte
397                 BL      xsave_block             ;Send it to the output
398                 STRVS   R0,[R13,#0]             ;Save any error pointers
399                 LDMFD   R13!,{R0,R1,PC}         ;And return to caller
400
401                 LTORG
402
403 ; --- xsave_word ---
404 ;
405 ; On entry:     R0 == word to write
406 ;
407 ; On exit:      May return an error
408 ;
409 ; Use:          Writes a single word to the current output.
410
411                 EXPORT  xsave_word
412 xsave_word      ROUT
413
414                 STMFD   R13!,{R0,R1,R14}        ;Save some registers
415                 MOV     R0,R13                  ;Point to saved word
416                 MOV     R1,#4                   ;Just write one word
417                 BL      xsave_block             ;Send it to the output
418                 STRVS   R0,[R13,#0]             ;Save any error pointers
419                 LDMFD   R13!,{R0,R1,PC}         ;And return to caller
420
421                 LTORG
422
423 ; --- xsave_string ---
424 ;
425 ; On entry:     R0 == pointer to a control-terminated string
426 ;
427 ; On exit:      May return an error
428 ;
429 ; Use:          Writes a control-terminated string to the current output.
430 ;               The string is null terminated in the output file.
431
432                 EXPORT  xsave_string
433 xsave_string    ROUT
434
435                 STMFD   R13!,{R0,R14}           ;Save some registers
436 00xsave_string  LDRB    R14,[R0],#1             ;Load a byte from the string
437                 CMP     R14,#32                 ;Is it a control character?
438                 MOVLO   R14,#0                  ;Yes -- make it a zero then
439                 BL      xsave_byte              ;Write it out
440                 BVS     %90xsave_string         ;If it failed, return error
441                 BHS     %00xsave_string         ;Otherwise go round again
442                 LDMFD   R13!,{R0,R14}           ;Restore the registers
443                 BICS    PC,R14,#V_flag          ;And don't return an error
444
445 90xsave_string  ADD     R13,R13,#4              ;Don't restore R0 on exit
446                 LDMFD   R13!,{R14}              ;Restore the link register
447                 ORRS    PC,R14,#V_flag          ;And return an error
448
449                 LTORG
450
451 ; --- xsave_block ---
452 ;
453 ; On entry:     R0 == pointer to buffer to write
454 ;               R1 == size of buffer to write
455 ;
456 ; On exit:      May return an error
457 ;
458 ; Use:          Writes out a block of data.  Data is buffered, so this is
459 ;               fairly quick for reading small objects.  Large data blocks
460 ;               are sent directly to avoid buffering overhead.
461
462                 EXPORT  xsave_block
463 xsave_block     ROUT
464
465                 CMP     R1,#0                   ;Is there anything there?
466                 BICEQS  PC,R14,#V_flag          ;No -- return with no error
467
468                 STMFD   R13!,{R0-R4,R12,R14}    ;Save a load of registers
469                 WSPACE  xsave__wSpace           ;Load my workspace address
470
471                 ; --- Fix up the total data sent ---
472
473                 LDR     R14,xsave__total        ;Load the total sent so far
474                 ADD     R14,R14,R1              ;Add on the size of this one
475                 STR     R14,xsave__total        ;And save the total back
476
477                 ; --- Work out what we have to do ---
478
479                 CMP     R1,#xsave__buffSize     ;Is the block really big?
480                 BGE     %50xsave_block          ;Yes -- then deal with that
481
482                 ; --- Write as much as possible to the buffer ---
483
484                 ADR     R14,xsave__buffer       ;Point to buffer data
485                 LDMIA   R14,{R2,R3}             ;Load address and size
486                 RSB     R4,R3,#xsave__buffSize  ;How much is free in there?
487                 CMP     R1,R4                   ;Is there enough space?
488                 BLT     %30xsave_block          ;Yes -- just add some more
489
490                 ; --- Fill the buffer right up now ---
491
492                 MOV     R1,R0                   ;Point to the new block
493                 ADD     R0,R2,R3                ;Point to free part of buffer
494                 MOV     R2,R4                   ;And get the size to copy
495                 BL      fastMove                ;Copy it all over then
496                 LDR     R0,xsave__buffer        ;Point to the buffer
497                 MOV     R1,#xsave__buffSize     ;And get its full size
498                 BL      xsave__write            ;Write a bufferfull out
499                 BVS     %99xsave_block          ;Handle an error from this
500
501                 ; --- Fix up all the pointers ---
502
503                 LDMIA   R13,{R0,R1}             ;Reload the buffer addresses
504                 ADD     R0,R0,R2                ;Move on the block pointer
505                 SUB     R1,R1,R2                ;And chop off correctly
506                 LDR     R2,xsave__buffer        ;Point to the buffer start
507                 MOV     R3,#0                   ;And now it's empty
508
509                 ; --- Just top up the buffer then ---
510
511 30xsave_block   MOV     R14,R0                  ;Point to client's buffer
512                 ADD     R0,R2,R3                ;Point to free part of buff
513                 MOVS    R2,R1                   ;Get the block size to copy
514                 MOV     R1,R14                  ;Set up source pointer now
515                 BLNE    fastMove                ;Do the copy job now
516                 ADD     R3,R3,R2                ;Add on the block size
517                 STR     R3,xsave__buffUsed      ;Save the new buffer size
518                 B       %90xsave_block          ;And finish it all up
519
520                 ; --- Send a really big block ---
521
522 50xsave_block   ADR     R14,xsave__buffer       ;Point to buffer info
523                 LDMIA   R14,{R0,R1}             ;Load the buffer stuff
524                 BL      xsave__write            ;Write it all out
525                 BVS     %99xsave_block          ;Handle an error from this
526                 MOV     R14,#0                  ;Nothing left there now
527                 STR     R14,xsave__buffUsed     ;So clear the buffer size
528                 LDMIA   R13,{R0,R1}             ;Get caller's block size
529                 BL      xsave__write            ;Write it out nicely
530                 BVS     %99xsave_block          ;Handle an error from this
531
532 90xsave_block   LDMFD   R13!,{R0-R4,R12,R14}    ;Restore all the registers
533                 BICS    PC,R14,#V_flag          ;And return no errors
534
535 99xsave_block   ADD     R13,R13,#4              ;Don't restore R0 on exit
536                 LDMFD   R13!,{R1-R4,R12,R14}    ;Restore all the registers
537                 ORRS    PC,R14,#V_flag          ;And return the error
538
539                 LTORG
540
541 ; --- xsave__write ---
542 ;
543 ; On entry:     R0 == pointer to buffer to write
544 ;               R1 == size of buffer to write
545 ;
546 ; On exit:      May return an error
547 ;
548 ; Use:          Writes a block of data to the file or application.  This is
549 ;               one of the few bits of save/send dependent code in the
550 ;               module.
551
552 xsave__write    ROUT
553
554                 CMP     R1,#0                   ;Is there anything there?
555                 BICEQS  PC,R14,#V_flag          ;No -- return with no error
556
557                 STMFD   R13!,{R14}              ;Save some registers
558                 LDR     R14,xsave__flags        ;Find my flags word
559                 TST     R14,#xsFlag__ramTran    ;Am I using RAM transfer?
560                 BNE     %50xsave__write         ;Yes -- do that then
561
562                 ; --- Use OS_HeebieJeebie to send the data ---
563
564                 STMFD   R13!,{R0-R4}            ;Save some more registers
565                 MOV     R2,R0                   ;Point to the user's buffer
566                 MOV     R3,R1                   ;And get the buffer size
567                 LDR     R1,xsave__file          ;Get the file's handle
568                 MOV     R0,#2                   ;Write at current position
569                 SWI     XOS_GBPB                ;Write the data out nicely
570                 STRVS   R0,[R13,#0]             ;If error, save error pointer
571                 LDMFD   R13!,{R0-R4,R14}        ;Unstack the registers
572                 ORRVSS  PC,R14,#V_flag          ;Return V set as required
573                 BICVCS  PC,R14,#V_flag
574
575                 ; --- Get the main coroutine to send the buffer ---
576
577 50xsave__write  STMFD   R13!,{R0}               ;Save another register
578                 ADR     R14,xsave__start        ;Point to the buffer info
579                 STMIA   R14,{R0,R1}             ;Save for main coroutine
580                 MOV     R0,#0                   ;Get magic coroutine handle
581                 BL      coRout_switch           ;And switch to main code
582                 LDR     R14,xsave__flags        ;Reload the flags
583                 TST     R14,#xsFlag__error      ;Was there a problem?
584                 LDMFD   R13!,{R0,R14}           ;Restore the registers
585                 BICEQS  PC,R14,#V_flag          ;No -- just clear V then
586                 LDRNE   R0,xsave__error         ;Otherwise load error pointer
587                 ORRNES  PC,R14,#V_flag          ;And return with V set
588
589                 LTORG
590
591 xsave__wSpace   DCD     0
592
593 ;----- Constants ------------------------------------------------------------
594
595 xsave__buffSize EQU     1024                    ;1K buffer should be enough
596
597 ;----- Workspace ------------------------------------------------------------
598
599                 ^       0,R12
600 xsave__wStart   #       0
601
602 xsave__flags    #       4                       ;Various run-time flags
603 xsave__coRout   #       0                       ;The send coroutine handle
604 xsave__file     #       4                       ;The save file handle
605 xsave__buffer   #       4                       ;Pointer to my 1K buffer
606 xsave__buffUsed #       4                       ;Amount of data in buffer
607 xsave__total    #       4                       ;How much data sent so far
608 xsave__error    #       0                       ;Error pointer from corout
609 xsave__start    #       4                       ;Start of buffer to send
610 xsave__length   #       4                       ;Size of next buffer to send
611
612 xsave__wSize    EQU     {VAR}-xsave__wStart
613
614 xsFlag__inited  EQU     (1<<0)                  ;Are we initialised already?
615 xsFlag__ramTran EQU     (1<<1)                  ;Are we doing RAM transfer?
616 xsFlag__finish  EQU     (1<<2)                  ;This is the very last block
617 xsFlag__error   EQU     (1<<3)                  ;Should return an error
618
619                 AREA    |Sapphire$$LibData|,CODE,READONLY
620
621                 DCD     xsave__wSize
622                 DCD     xsave__wSpace
623                 DCD     0
624                 DCD     0
625
626 ;----- That's all, folks ----------------------------------------------------
627
628                 END