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