chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Sapphire / xfer / s / xload
1 ;
2 ; xfer.xload.s
3 ;
4 ; Simplified loading 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 ; xload attempts to unify the various loading routines you have to supply,
24 ; by providing a single interface.
25 ;
26 ; There are several main routines, xload_file, xload_initBuf,
27 ; xload_killBuf, xload_extend and xload_doneBuf, which are called from
28 ; the main load branch table.
29 ;
30 ; Loading of data is done with the call xload_block.  This just reads
31 ; a block of data somehow.  All the other routines are special interfaces to
32 ; xload_block.
33
34 ;----- How the error handling works -----------------------------------------
35 ;
36 ; The really tricky bit is passing of errors during a RAM transfer.
37 ; Errors can be returned at two places -- in the user code (e.g. running out
38 ; of memory) and by load's message handling if the receiver dies.  All
39 ; errors must be handled by user code, to release claimed memory etc.
40 ;
41 ; The error gets passed along a path like this:
42 ;
43 ; Error created by user code
44 ;
45 ; user code --> xload__startCo --> xload_failed
46 ;
47 ; Error created by remote receiver
48 ;
49 ; xload_failed --> xload__read --> user code --> xload__startCo
50
51 ;----- Main code ------------------------------------------------------------
52
53                 AREA    |Sapphire$$Code|,CODE,READONLY
54
55 ; --- xload_file ---
56 ;
57 ; On entry:     R0 == pointer to loader routine
58 ;               R1 == R10 value to pass to loader
59 ;               R2 == R12 value to pass to loader
60 ;               R3 == pointer to leafname of file (passed to loader in R0)
61 ;               R4 == pointer to filename to load from
62 ;               R5 == whether the file is safe (passed to loader in R1)
63 ;
64 ; On exit:      May return an error
65 ;
66 ; Use:          Calls a generalised loader routine to read data from a file.
67
68                 EXPORT  xload_file
69 xload_file      ROUT
70
71                 STMFD   R13!,{R0-R5,R10,R12,R14} ;Save lots of registers
72                 WSPACE  xload__wSpace           ;Find my workspace address
73
74                 ; --- First, try to allocate a buffer ---
75
76                 BL      xload__setBuff          ;Allocate the buffer nicely
77                 BVS     %99xload_file           ;If we couldn't, tidy up
78
79                 ; --- Set up the file for writing ---
80
81                 MOV     R1,R4                   ;Point at the file name
82                 MOV     R0,#&4F                 ;Lots of errors, no path
83                 SWI     XOS_Find                ;Try to open the file
84                 BVS     %98xload_file           ;Tidy up if it wouldn't open
85                 STR     R0,xload__file          ;Save the file handle away
86
87                 ; --- Set up flags and let rip ---
88
89                 LDR     R14,xload__flags        ;Load my current flags word
90                 AND     R14,R14,#xlFlag__inited ;Only leave inited flag
91                 STR     R14,xload__flags        ;Save the flags back again
92
93                 MOV     R14,#0                  ;Nothing read yet
94                 STR     R14,xload__buffUsed     ;So clear buffer size
95
96                 LDMIA   R13,{R2,R10,R12,R14}    ;Load the arguments out
97                 MOV     R0,R14                  ;Get the leafname in R0
98                 ADDS    R1,R1,#0                ;Clear overflow and carry
99                 LDR     R1,[R13,#16]            ;Load the safeness flag
100                 MOV     R14,PC                  ;Set up the return address
101                 MOV     PC,R2                   ;And call the saver routine
102                 WSPACE  xload__wSpace           ;Restore my workspace ptr
103                 BVS     %97xload_file           ;Tidy up if it failed
104
105                 ; --- Close the file ---
106
107                 MOV     R0,#0                   ;Close an open file
108                 LDR     R1,xload__file          ;Get the file handle ready
109                 SWI     OS_Find                 ;Close it
110
111                 ; --- Get rid of the buffer and return ---
112
113                 BL      xload__loseBuff         ;Free up the buffer space
114                 LDMFD   R13!,{R0-R5,R10,R12,R14} ;Unstack all the registers
115                 BICS    PC,R14,#V_flag          ;And return to caller
116
117                 ; --- Tidy up after various catastrophes ---
118
119 97xload_file    MOV     R10,R0                  ;Keep the error pointer
120                 MOV     R0,#0                   ;Close an open file
121                 LDR     R1,xload__file          ;Get the file handle ready
122                 SWI     OS_Find                 ;Close it
123                 MOV     R0,R10                  ;Restore the error pointer
124
125 98xload_file    BL      xload__loseBuff         ;Free up the buffer space
126
127 99xload_file    ADD     R13,R13,#4              ;Don't restore R0 on exit
128                 LDMFD   R13!,{R1-R5,R10,R12,R14} ;Unstack all the registers
129                 ORRS    PC,R14,#V_flag          ;And return to caller
130
131 ; --- xload_initBuf ---
132 ;
133 ; On entry:     R0 == pointer to loader routine
134 ;               R1 == R10 value to pass to loader
135 ;               R2 == R12 value to pass to loader
136 ;               R3 == pointer to leafname of file (passed to loader in R0)
137 ;
138 ; On exit:      R0 == pointer to load buffer
139 ;               R1 == size of load buffer
140 ;               May return an error
141 ;
142 ; Use:          Starts a RAM transfer and starts up a generalised load
143 ;               routine.
144
145                 EXPORT  xload_initBuf
146 xload_initBuf   ROUT
147
148                 STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
149                 WSPACE  xload__wSpace           ;Load my workspace address
150
151                 ; --- Firstly, allocate the buffer ---
152
153                 BL      xload__setBuff          ;Create the load buffer
154                 ADDVS   R13,R13,#8              ;If failed, unstack R0,R1
155                 BVS     %99xload_initBuf        ;And then return error
156
157                 ; --- Now create the coroutine ---
158
159                 ADR     R0,xload__startCo       ;Point to the coroutine
160                 MOV     R1,R13                  ;Point to saved corout info
161                 MOV     R2,R12                  ;Pass my workspace in R12
162                 MOV     R3,#0                   ;Default stack size please
163                 BL      coRout_create           ;Try to create the coroutine
164                 ADDVS   R13,R13,#8              ;Don't return R0,R1
165                 BVS     %98xload_initBuf        ;If it failed, tidy up
166                 STR     R0,xload__coRout        ;Save the couroutine handle
167
168                 ; --- Let xload__startCo save coroutine info ---
169
170                 BL      coRout_switch           ;Switch to it quickly
171                 ADD     R13,R13,#8              ;Don't return R0,R1
172
173                 ; --- Set up flags and bits of workspace ---
174
175                 LDR     R14,xload__flags        ;Load my flags word
176                 AND     R14,R14,#xlFlag__inited ;Clear all but initialised
177                 ORR     R14,R14,#xlFlag__ramTran ;We're doing RAM transfer
178                 STR     R14,xload__flags        ;Save the flags back
179                 MOV     R14,#0                  ;No data RAMmed in yet
180                 STR     R14,xload__rammed       ;So save this information
181
182                 ; --- Return the buffer information ---
183
184                 ADR     R14,xload__buffer       ;Find my buffer info
185                 LDMIA   R14,{R0,R1}             ;Load address and size
186                 LDMFD   R13!,{R2,R3,R12,R14}    ;Unstack my registers
187                 BICS    PC,R14,#V_flag          ;And return no error
188
189                 ; --- Things went wrong ---
190
191 98xload_initBuf BL      xload__loseBuff         ;Get rid of transfer buffer
192 99xload_initBuf LDMFD   R13!,{R2,R3,R12,R14}    ;Unstack my registers
193                 ORRS    PC,R14,#V_flag          ;And return the error
194
195                 LTORG
196
197 ; --- xload__startCo ---
198 ;
199 ; On entry:     R0 == my coroutine handle
200 ;               R10 == pointer to block containing (routine,R10,R12,leafname)
201 ;               R12 == my workspace
202 ;
203 ; On exit:      Returns through coRout_end
204 ;
205 ; Use:          Starts the coroutine for sending data by RAM transfer.  It
206 ;               handles errors reported by it, and terminates the transfer
207 ;               properly.
208 ;
209 ;               The information about the real client is stored on the
210 ;               main routine's stack.  Before it returns, therefore, we
211 ;               need to load it from there and save it somewhere so that
212 ;               it will be safe when we start the coroutine properly from
213 ;               xload_extend.  Therefore we actually start from xload_initBuf
214 ;               and save the information on the coroutine's stack, and
215 ;               switch back quickly.
216
217 xload__startCo  ROUT
218
219                 LDMIA   R10,{R0-R3}             ;Load the caller's registers
220                 STMFD   R13!,{R0-R3}            ;Save them on our stack
221                 MOV     R0,#0                   ;Return to main routine
222                 BL      coRout_switch           ;Switch back please
223
224                 LDR     R14,xload__flags        ;Load my flags word
225                 ORR     R14,R14,#xlFlag__started ;Coroutine has started now
226                 STR     R14,xload__flags        ;Save flags back again
227
228                 LDMFD   R13!,{R2,R10,R12,R14}   ;Load client's workspace
229                 MOV     R0,R14                  ;Pass leafname in R0
230                 MOV     R1,#0                   ;File is not safe
231                 MOV     R14,PC                  ;Set up a return address
232                 MOV     PC,R2                   ;And call the saver routine
233                 BVS     %90xload__startCo       ;If it failed, report error
234
235                 MOV     R14,#0                  ;A nice zero value
236                 WSPACE  xload__wSpace           ;Load my workspace pointer
237                 STR     R14,xload__coRout       ;Write over the coroutine
238                 LDR     R0,xload__buffer        ;Load the buffer address
239                 MOV     R1,#xload__buffSize     ;Get the current buffer size
240                 ADR     R14,xload__start        ;Point to load area
241                 STMIA   R14,{R0,R1}             ;Save the data in there
242                 B       coRout_end              ;Terminate coroutine
243
244                 ; --- Handle its return values ---
245
246 90
247                 WSPACE  xload__wSpace           ;Locate my workspace address
248                 LDR     R14,xload__flags        ;Load the flags word
249
250                 ORR     R14,R14,#xlFlag__error  ;Set the main error flag
251                 STR     R14,xload__flags        ;Save the flags back again
252                 STR     R0,xload__error         ;And save the error pointer
253                 B       coRout_end              ;And finish the coroutine
254
255                 LTORG
256
257 ; --- xload_killBuf ---
258 ;
259 ; On entry:     --
260 ;
261 ; On exit:      --
262 ;
263 ; Use:          Does a buffer destroy for a failed load operation.
264
265                 EXPORT  xload_killBuf
266 xload_killBuf   ROUT
267
268                 STMFD   R13!,{R0,R12,R14}       ;Save some registers
269                 WSPACE  xload__wSpace           ;Find my workspace address
270                 LDR     R14,xload__flags        ;Load my flags word
271                 TST     R14,#xlFlag__started    ;Has the coroutine started?
272                 LDMNEFD R13!,{R0,R12,PC}^       ;Yes -- this is an error then
273
274                 ; --- Destroy the buffer and the coroutine ---
275
276                 BL      xload__loseBuff         ;Get rid of the load buffer
277                 LDR     R0,xload__coRout        ;Load the coroutine handle
278                 BL      coRout_destroy          ;Destroy the coroutine
279                 LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
280
281                 LTORG
282
283 ; --- xload_extend ---
284 ;
285 ; On entry:     R1 == size of last buffer used for receiving
286 ;
287 ; On exit:      R0 == pointer to new buffer
288 ;               R1 == size of new buffer
289 ;               May return an error
290 ;
291 ; Use:          Performs a buffer extent operation during an xload RAM
292 ;               transfer.
293
294                 EXPORT  xload_extend
295 xload_extend    ROUT
296
297                 STMFD   R13!,{R12,R14}          ;Save some registers
298                 WSPACE  xload__wSpace           ;Find my workspace address
299
300                 ; --- Bump the amount of data received ---
301
302                 LDR     R14,xload__rammed       ;Find how much was sent
303                 ADD     R14,R14,R1              ;Add size of last buffer
304                 STR     R14,xload__rammed       ;And save the size back
305
306                 ; --- Let the coroutine do some loading ---
307
308                 BL      xload__resume           ;Let the coroutine run a bit
309                 LDR     R14,xload__flags        ;Load the coroutine's flags
310                 TST     R14,#xlFlag__error      ;Has it returned an error?
311                 BNE     %90xload_extend         ;Yes -- then return it
312
313                 ; --- Get the next buffer to send from xload__read ---
314
315                 ADR     R14,xload__start        ;Point to buffer data
316                 LDMIA   R14,{R0,R1}             ;Load the buffer data
317                 LDMFD   R13!,{R12,R14}          ;Unstack the registers
318                 BICS    PC,R14,#V_flag          ;And don't return an error
319
320                 ; --- Client had a wee problem ---
321
322 90xload_extend  LDR     R0,xload__error         ;Load the error pointer
323                 LDMFD   R13!,{R12,R14}          ;Unstack the registers
324                 ORRS    PC,R14,#V_flag          ;And return the error
325
326                 LTORG
327
328 ; --- xload_doneBuf ---
329 ;
330 ; On entry:     R1 == total size of data received
331 ;
332 ; On exit:      R0 corrupted
333 ;               May return an error
334 ;
335 ; Use:          Handles the last bufferful of a RAM load.
336
337                 EXPORT  xload_doneBuf
338 xload_doneBuf   ROUT
339
340                 STMFD   R13!,{R12,R14}          ;Save some registers
341                 WSPACE  xload__wSpace           ;Find my workspace address
342
343                 ; --- Work out how much of the last buffer was sent ---
344
345                 LDR     R14,xload__rammed       ;Find how much was sent
346                 SUB     R0,R1,R14               ;How much of last buffer?
347                 STR     R0,xload__length        ;And save the size back
348                 LDR     R14,xload__flags        ;Load the flags word
349                 ORR     R14,R14,#xlFlag__finish ;Set the finished flag
350                 STR     R14,xload__flags        ;Save the flags back again
351                 TST     R14,#xlFlag__started    ;Has the coroutine started?
352                 STREQ   R0,xload__buffUsed      ;No -- set buffer size
353
354                 ; --- Now let the coroutine finish off ---
355
356                 BL      xload__resume           ;Let the coroutine run a bit
357                 LDR     R14,xload__flags        ;Load the coroutine's flags
358                 TST     R14,#xlFlag__error      ;Has it returned an error?
359                 BNE     %90xload_doneBuf        ;Yes -- then return it
360
361                 ; --- Return to caller ---
362
363                 BL      xload__loseBuff         ;Don't want this any more
364                 LDMFD   R13!,{R12,R14}          ;Unstack the registers
365                 BICS    PC,R14,#V_flag          ;Don't return an error
366
367                 ; --- Coroutine hit a wee problem ---
368
369 90xload_doneBuf LDR     R0,xload__error         ;Load the error pointer
370                 LDMFD   R13!,{R12,R14}          ;Unstack the registers
371                 ORRS    PC,R14,#V_flag          ;And return the error
372
373                 LTORG
374
375 ; --- xload_done ---
376 ;
377 ; On entry:     --
378 ;
379 ; On exit:      --
380 ;
381 ; Use:          Tidies up after a successful load job.
382
383                 EXPORT  xload_done
384 xload_done      ROUT
385
386                 MOVS    PC,R14                  ;Nothing to do here
387
388 ; --- xload_failed ---
389 ;
390 ; On entry:     R0 == pointer to error block
391 ;
392 ; On exit:      --
393 ;
394 ; Use:          Tidies up a RAM transfer after an error.
395
396                 EXPORT  xload_failed
397 xload_failed    ROUT
398
399                 STMFD   R13!,{R12,R14}          ;Save some registers
400                 WSPACE  xload__wSpace           ;Find my workspace
401                 LDR     R14,xload__flags        ;Load my flags word
402                 TST     R14,#xlFlag__ramTran    ;Are we using RAM transfer?
403                 LDMEQFD R13!,{R12,PC}^          ;No -- return right now then
404
405                 ; --- Find out if the user has seen the error yet ---
406
407                 STMFD   R13!,{R0}               ;Save some more registers
408                 TST     R14,#xlFlag__error      ;Has he seen the error?
409                 BNE     %30xload_failed         ;Yes -- then don't switch
410
411                 ; --- Get xload__write to return an error ---
412
413                 ORR     R14,R14,#xlFlag__error  ;Set the error flag
414                 STR     R0,xload__error         ;And save the error pointer
415                 BL      xload__resume           ;Let the coroutine run a bit
416
417                 ; --- Now tidy everything up ---
418                 ;
419                 ; The coroutine should have killed itself by now
420
421 30xload_failed  BL      xload__loseBuff         ;Kill off the data buffer
422                 LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
423
424                 LTORG
425
426 ; --- xload__resume ---
427 ;
428 ; On entry:     --
429 ;
430 ; On exit:      --
431 ;
432 ; Use:          Lets the coroutine run for a bit.
433
434 xload__resume   ROUT
435
436                 STMFD   R13!,{R0,R1,R14}        ;Save some registers
437                 LDR     R0,xload__coRout        ;Load the coroutine handle
438                 CMP     R0,#0                   ;Has it finished yet?
439                 BLNE    coRout_switch           ;No -- run it a bit more then
440                 LDMNEFD R13!,{R0,R1,PC}^        ;And return to caller
441
442                 LDR     R0,xload__buffer        ;Load the buffer address
443                 MOV     R1,#xload__buffSize     ;Get the current buffer size
444                 ADR     R14,xload__start        ;Point to load area
445                 STMIA   R14,{R0,R1}             ;Save the data in there
446                 LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
447
448                 LTORG
449
450 ; --- xload__setBuff ---
451 ;
452 ; On entry:     --
453 ;
454 ; On exit:      May return an error
455 ;
456 ; Use:          Sets up the buffer for a data transfer.
457
458 xload__setBuff  ROUT
459
460                 STMFD   R13!,{R0-R3,R14}        ;Save some registers
461
462                 ; --- Allocate the buffer memory ---
463
464                 MOV     R0,#xload__buffSize     ;Get the buffer size
465                 BL      alloc                   ;Try to allocate the buffer
466                 BLCS    alloc_error             ;Get an error if it failed
467                 BCS     %90xload__setBuff       ;And tidy things up
468
469                 ; --- Set up los of variables ---
470
471                 ADR     R14,xload__buffer       ;Point at the buffer info
472                 MOV     R1,#xload__buffSize     ;No buffer used yet
473                 MOV     R2,#0                   ;Start buffer from beginning
474                 MOV     R3,#0                   ;No data sent yet either
475                 STMIA   R14,{R0-R3}             ;Save these values away
476                 LDMFD   R13!,{R0-R3,R14}        ;Restore all the registers
477                 BICS    PC,R14,#V_flag          ;And return with V clear
478
479                 ; --- Report an error ---
480
481 90              ADD     R13,R13,#4              ;Don't restore R0 on exit
482                 LDMFD   R13!,{R1-R3,R14}        ;Restore all the registers
483                 ORRS    PC,R14,#V_flag          ;And return with V set
484
485                 LTORG
486
487 ; --- xload__loseBuff ---
488 ;
489 ; On entry:     --
490 ;
491 ; On exit:      --
492 ;
493 ; Use:          Kills off the buffer.
494
495 xload__loseBuff ROUT
496
497                 STMFD   R13!,{R0,R14}           ;Save some registers
498                 LDR     R0,xload__buffer        ;Load the buffer address
499                 BL      free                    ;Free the buffer
500                 LDR     R14,xload__flags        ;Load my current flags word
501                 AND     R14,R14,#xlFlag__inited ;Only leave inited flag
502                 STR     R14,xload__flags        ;Save the flags back again
503                 LDMFD   R13!,{R0,PC}^           ;And return to caller
504
505                 LTORG
506
507 ; --- xload_byte ---
508 ;
509 ; On entry:     --
510 ;
511 ; On exit:      CC if data read OK, and
512 ;                 R0 == byte read
513 ;               else CC if end-of-file, and
514 ;                 R0 corrupted
515 ;               May return an error
516 ;
517 ; Use:          Reads a byte from the current input.
518
519                 EXPORT  xload_byte
520 xload_byte      ROUT
521
522                 STMFD   R13!,{R0-R2,R14}        ;Save some registers
523                 MOV     R0,R13                  ;Overwrite saved R0
524                 MOV     R1,#1                   ;Just read one byte
525                 BL      xload_block             ;Read it onto the stack
526                 STRVS   R0,[R13,#0]             ;If error, store pointer
527                 LDR     R0,[R13],#4             ;Load the byte/error pointer
528                 ANDVC   R0,R0,#&FF              ;If byte/EOF, kill other bits
529                 LDMFD   R13!,{R1,R2,PC}         ;And return to caller
530
531                 LTORG
532
533 ; --- xload_word ---
534 ;
535 ; On entry:     --
536 ;
537 ; On exit:      CC if data read OK, and
538 ;                 R0 == word read
539 ;               else CS if end-of-file and
540 ;                 R0 corrupted
541 ;               May return an error
542 ;
543 ; Use:          Reads a word from the current input.
544
545                 EXPORT  xload_word
546 xload_word      ROUT
547
548                 STMFD   R13!,{R0-R2,R14}        ;Save some registers
549                 MOV     R0,R13                  ;Overwrite saved R0
550                 MOV     R1,#4                   ;Just read one word
551                 BL      xload_block             ;Read it onto the stack
552                 STRVS   R0,[R13,#0]             ;If error, store pointer
553                 LDR     R0,[R13],#4             ;Load the byte/error pointer
554                 LDMFD   R13!,{R1,R2,PC}         ;And return to caller
555
556                 LTORG
557
558 ; --- xload_block ---
559 ;
560 ; On entry:     R0 == pointer to buffer to read
561 ;               R1 == size of buffer to read
562 ;
563 ; On exit:      R0, R1 preserved
564 ;               R2 == number of bytes read
565 ;               CC if more data available, CS for end-of-file
566 ;               May return an error
567 ;
568 ; Use:          Reads in a block of data.  Data is buffered, so this is
569 ;               fairly quick for reading small objects.  Large data blocks
570 ;               are read directly to avoid buffering overhead.
571
572                 EXPORT  xload_block
573 xload_block     ROUT
574
575                 CMP     R1,#0                   ;Is there anything there?
576                 MOVEQ   R2,#0                   ;Nothing read yet
577                 BICEQS  PC,R14,#V_flag          ;No -- return with no error
578
579                 STMFD   R13!,{R0,R1,R3-R8,R12,R14} ;Save a load of registers
580                 WSPACE  xload__wSpace           ;Load my workspace address
581                 MOV     R6,R0                   ;Keep his buffer address
582                 MOV     R7,R1                   ;Look after his buffer size
583                 MOV     R8,#0                   ;No data copied yet
584
585                 ; --- First, try to read from the buffer ---
586
587                 ADR     R14,xload__buffer       ;Point to the buff info
588                 LDMIA   R14,{R3-R5}             ;Load the buffer stuff
589 00xload_block   SUBS    R14,R4,R5               ;Find out how much there is
590                 BEQ     %20xload_block          ;No -- skip ahead then
591
592                 ; --- Read as much as we need from buffer ---
593
594                 CMP     R7,R14                  ;Is there enough there?
595                 MOVLT   R2,R7                   ;Yes -- get as much as we can
596                 MOVGE   R2,R14                  ;Otherwise empty the buffer
597                 ADD     R1,R3,R5                ;Get the correct address
598                 MOV     R0,R6                   ;Point at his buffer
599                 BL      fastMove                ;Copy the data across nicely
600
601                 ; --- Reset the buffer arguments ---
602
603                 ADD     R5,R5,R2                ;Add on the offset now
604                 ADD     R6,R6,R2                ;Bump up his buffer address
605                 SUBS    R7,R7,R2                ;And decrease the size
606                 ADD     R8,R8,R2                ;Bump amount of data read
607                 BEQ     %90xload_block          ;If no more to do, return
608
609                 ; --- Buffer was empty ---
610                 ;
611                 ; If he wants more than a buffer full, we should just read
612                 ; directly into his buffer.  Otherwise we fill the buffer
613                 ; and loop back again to copy data.
614
615 20xload_block   CMP     R7,#xload__buffSize     ;Does he want more?
616                 BGE     %50xload_block          ;Yes -- skip ahead then
617
618                 MOV     R0,R3                   ;Point to the buffer
619                 MOV     R1,#xload__buffSize     ;Get the buffer size
620                 BL      xload__read             ;Read data into the buffer
621                 BVS     %95xload_block          ;If it failed, return error
622                 MOVS    R4,R2                   ;Get the new buffer size
623                 MOV     R5,#0                   ;Haven't started on it yet
624                 BNE     %00xload_block          ;If anything read, go round
625                 B       %90xload_block          ;Otherwise we'd better stop
626
627                 ; --- Read data into his big buffer ---
628
629 50xload_block   MOV     R0,R6                   ;Point to his buffer
630                 MOV     R1,R7                   ;And get his buffer size
631                 BL      xload__read             ;Read data into the buffer
632                 BVS     %95xload_block          ;If it failed, return error
633                 ADD     R8,R8,R2                ;Bump by amount read
634
635                 ; --- Everything went OK ---
636
637 90xload_block   ADR     R14,xload__buffUsed     ;Point to the buff info
638                 STMIA   R14,{R4,R5}             ;Store new offsets
639                 MOV     R2,R8                   ;Get amount of data read
640
641                 LDR     R14,xload__total        ;Load the total data read
642                 ADD     R14,R14,R8              ;Add new amount read
643                 STR     R14,xload__total        ;And save back the new total
644
645                 LDR     R14,xload__flags        ;Load the flags word
646                 LDR     R1,[R13,#4]             ;Load amount he wanted
647                 CMP     R1,R2                   ;Did we read it all?
648                 ORRGT   R14,R14,#xlFlag__finish ;No -- set eof flag then
649                 STRGT   R14,xload__flags        ;Save the flags back
650
651                 LDMFD   R13!,{R0,R1,R3-R8,R12,R14} ;Unstack loads of regs
652                 BIC     R14,R14,#V_flag         ;Clear error indicator
653                 ORRGTS  PC,R14,#C_flag          ;Set Carry on exit if EOF
654                 BICLES  PC,R14,#C_flag          ;Otherwise clear it
655
656                 ; --- We had an error ---
657
658 95xload_block   ADD     R13,R13,#4              ;Don't restore R0 on exit
659                 LDMFD   R13!,{R1,R3-R8,R12,R14} ;Unstack loads of regs
660                 ORRS    PC,R14,#V_flag          ;Return the error condition
661
662                 LTORG
663
664 ; --- xload__read ---
665 ;
666 ; On entry:     R0 == pointer to buffer to read
667 ;               R1 == size of buffer to read
668 ;
669 ; On exit:      May return an error
670 ;               R2 == actual amount of data read
671 ;
672 ; Use:          Reads a block of data from the input stream.
673
674 xload__read     ROUT
675
676                 BIC     R14,R14,#V_flag         ;Clear error indicator
677                 MOV     R2,#0                   ;Nothing read yet
678                 CMP     R1,#0                   ;Is there anything there?
679                 MOVEQS  PC,R14                  ;No -- return with no error
680
681                 STMFD   R13!,{R14}              ;Save some registers
682                 LDR     R14,xload__flags        ;Find my flags word
683                 TST     R14,#xlFlag__finish     ;Is the transfer over?
684                 LDMNEFD R13!,{PC}^              ;Yes -- return right now
685                 TST     R14,#xlFlag__ramTran    ;Am I using RAM transfer?
686                 BNE     %50xload__read          ;Yes -- do that then
687
688                 ; --- Use OS_HeebieJeebie to read the data ---
689
690                 STMFD   R13!,{R0,R1,R3,R4}      ;Save some more registers
691                 MOV     R2,R0                   ;Point to the user's buffer
692                 MOV     R3,R1                   ;And get the buffer size
693                 LDR     R1,xload__file          ;Get the file's handle
694                 MOV     R0,#4                   ;Read at current position
695                 SWI     XOS_GBPB                ;Read the data in nicely
696                 STRVS   R0,[R13,#0]             ;If error, save error ptr
697                 LDRVC   R1,[R13,#4]             ;Load number of bytes wanted
698                 SUBVC   R2,R1,R3                ;Get number actually read
699                 LDMFD   R13!,{R0,R1,R3,R4,R14}  ;Unstack the registers
700                 ORRVSS  PC,R14,#V_flag          ;Return V set as required
701                 BICVCS  PC,R14,#V_flag
702
703                 ; --- Get the main coroutine to read the buffer ---
704
705 50xload__read   STMFD   R13!,{R0}               ;Save another register
706                 ADR     R14,xload__start        ;Point to the buffer info
707                 STMIA   R14,{R0,R1}             ;Save for main coroutine
708                 MOV     R0,#0                   ;Get magic coroutine handle
709                 BL      coRout_switch           ;And switch to main code
710                 LDR     R2,xload__length        ;Read data size read
711                 LDR     R14,xload__flags        ;Reload the flags
712                 TST     R14,#xlFlag__error      ;Was there a problem?
713                 LDMFD   R13!,{R0,R14}           ;Restore the registers
714                 BICEQS  PC,R14,#V_flag          ;No -- just clear V then
715                 LDRNE   R0,xload__error         ;Otherwise load error pointer
716                 ORRNES  PC,R14,#V_flag          ;And return with V set
717
718                 LTORG
719
720 xload__wSpace   DCD     0
721
722 ;----- Constants ------------------------------------------------------------
723
724 xload__buffSize EQU     1024                    ;1K buffer should be enough
725
726 ;----- Workspace ------------------------------------------------------------
727
728                 ^       0,R12
729 xload__wStart   #       0
730
731 xload__flags    #       4                       ;Various run-time flags
732 xload__coRout   #       0                       ;The load coroutine handle
733 xload__file     #       4                       ;The load file handle
734 xload__buffer   #       4                       ;Pointer to my 1K buffer
735 xload__buffUsed #       4                       ;Amount of data in buffer
736 xload__buffOff  #       4                       ;Offset reading from buffer
737 xload__total    #       4                       ;How much data read so far
738 xload__error    #       0                       ;Error pointer from corout
739 xload__start    #       4                       ;Start of buffer to send
740 xload__length   #       4                       ;Size of next buffer to send
741 xload__rammed   #       4                       ;Data RAMFetched so far
742
743 xload__wSize    EQU     {VAR}-xload__wStart
744
745 xlFlag__inited  EQU     (1<<0)                  ;Are we initialised already?
746 xlFlag__ramTran EQU     (1<<1)                  ;Are we doing RAM transfer?
747 xlFlag__finish  EQU     (1<<2)                  ;This is the very last block
748 xlFlag__error   EQU     (1<<3)                  ;Should return an error
749 xlFlag__started EQU     (1<<4)                  ;Coroutine has started
750
751                 AREA    |Sapphire$$LibData|,CODE,READONLY
752
753                 DCD     xload__wSize
754                 DCD     xload__wSpace
755                 DCD     0
756                 DCD     0
757
758 ;----- That's all, folks ----------------------------------------------------
759
760                 END