]> git.sur5r.net Git - cc65/blob - libsrc/atari/shadow_ram_handlers.s
56ddc76c3fc4d2e50bdac8addf6192ef2d6d851d
[cc65] / libsrc / atari / shadow_ram_handlers.s
1 ;
2 ; Atari XL shadow RAM handlers
3 ;
4 ; Christian Groessler, chris@groessler.org, 2013
5 ;
6
7 DEBUG   =       1
8
9 .if .defined(__ATARIXL__)
10
11         SHRAM_HANDLERS  = 1
12         .include        "atari.inc"
13         .include        "save_area.inc"
14         .include        "zeropage.inc"
15         .import         __CHARGEN_START__
16
17         .export         sram_init
18         .export         KEYBDV_handler
19         .export         CIO_handler
20         .export         SIO_handler
21         .export         SETVBV_handler
22
23 BUFSZ           =       128             ; bounce buffer size
24 BUFSZ_SIO       =       256
25
26 .macro  disable_rom
27         lda     PORTB
28         and     #$fe
29         sta     PORTB
30         lda     #>__CHARGEN_START__
31         sta     CHBAS
32         sta     CHBASE
33 .endmacro
34 .macro  enable_rom
35         lda     PORTB
36         ora     #1
37         sta     PORTB
38         lda     #$E0
39         sta     CHBAS
40         sta     CHBASE
41 .endmacro
42
43 .segment "INIT"
44
45 ; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer
46
47 sram_init:
48
49 ; disable all interrupts
50         sei
51         ldx     #0
52         stx     NMIEN           ; disable NMI
53
54 ; disable ROMs
55         disable_rom
56
57 ; setup interrupt vectors
58         lda     #<my_IRQ_han
59         sta     $fffe
60         lda     #>my_IRQ_han
61         sta     $ffff
62
63         lda     #<my_RESET_han
64         sta     $fffc
65         lda     #>my_RESET_han
66         sta     $fffd
67
68         lda     #<my_NMI_han
69         sta     $fffa
70         lda     #>my_NMI_han
71         sta     $fffb
72
73 ; enable interrupts
74         lda     #$40
75         sta     NMIEN
76         cli
77
78         rts
79
80 .segment        "EXTZP" : zeropage
81
82 zpptr1: .res    2
83
84
85 .segment "LOWBUFS"
86
87 ; bounce buffers for CIO and SIO calls
88 bounce_buffer:  .res    BUFSZ_SIO
89
90
91 .segment "LOWCODE"
92
93
94 ; Interrupt handlers
95 ; ------------------
96
97 ; The interrupt handlers don't look at the current state of PORTB and
98 ; unconditionally disable the ROMs on exit.
99 ; Please note that this works, since if the ROMs are enabled we anyway
100 ; aren't being called here because the vectors are pointing to their
101 ; original ROM locations.
102
103 .macro  int_wrap orgvec
104         .local  ret
105         pha
106         enable_rom
107         lda     #>ret
108         pha
109         lda     #<ret
110         pha
111         php
112         jmp     (orgvec)
113 ret:    disable_rom
114         pla
115         rti
116 .endmacro
117
118 my_IRQ_han:
119 .ifdef DEBUG
120         php
121         pha
122         tya
123         pha
124         ldy     #0
125         lda     (SAVMSC),y
126         clc
127         adc     #1
128         sta     (SAVMSC),y
129         pla
130         tay
131         pla
132         plp
133 .endif
134         int_wrap $FFFE
135
136 my_NMI_han:
137 .ifdef DEBUG
138         php
139         pha
140         tya
141         pha
142         ldy     #39
143         lda     (SAVMSC),y
144         clc
145         adc     #1
146         sta     (SAVMSC),y
147         pla
148         tay
149         pla
150         plp
151 .endif
152 ; set I bit to interrupted value
153         pha
154         txa
155         pha
156         tsx
157         lda     $103,x
158         pha
159         plp
160         pla
161         tax
162         pla
163         int_wrap $FFFA
164
165 my_RESET_han:
166         enable_rom
167         jmp     ($FFFC)
168
169
170 ; System request handlers
171 ; -----------------------
172
173
174 ; for filenames we assume they will fit into our bounce buffer
175
176 ; one filename, terminated by "invalid character", located at ICBAL/ICBAH
177
178 CIO_filename:
179         jsr     setup_zpptr1_y0
180         jsr     copy_filename
181 CIO_fn_cont:
182         jsr     bncbuf_to_iocb
183         ldy     CIO_y
184         jsr     CIO_call_a              ; call CIO (maybe A isn't needed, then we could call CIO_call)
185         php
186         pha
187         jsr     restore_icba            ; restore original ICBAL/ICBAH
188         pla
189         plp
190         rts                             ; back to application
191
192
193 ; two filenames, terminated and separated by "invalid character", located at ICBAL/ICBAH
194
195 CIO_filename2:
196         jsr     setup_zpptr1_y0
197         jsr     copy_filename
198         iny
199         jsr     copy_filename
200         jmp     CIO_fn_cont
201
202
203 ; enable ROM, call CIO, disable ROM
204
205 CIO_call_a:
206         lda     CIO_a
207
208 CIOV_call:
209         pha
210         lda     PORTB
211         sta     cur_CIOV_PORTB
212         enable_rom
213         pla
214         jsr     CIOV_org
215         php
216         pha
217         lda     cur_CIOV_PORTB
218         sta     PORTB
219         pla
220         plp
221         rts
222
223
224 ; CIO handler
225 ; We have buffer pointer and length entries in the IOCB, but their
226 ; usage depends on the function.
227 ; Some functions don't care about any of them (pointer and length),
228 ; and some only use the pointer (like e.g. OPEN), and some use both.
229 ; So we need function specific handlers to correctly deal with
230 ; buffers which are overlapping with the ROM area.
231 ;
232 ; FIXME: Currently only the requests used by the runtime lib are handled.
233
234 CIO_handler:
235
236 ; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
237
238         sta     CIO_a
239         sty     CIO_y
240         stx     CIO_x
241
242         lda     ICCOM,x                 ; get function
243         cmp     #OPEN
244         beq     CIO_filename            ; filename as input parameter in buffer, length not used
245         cmp     #PUTREC
246         bcc     CIO_read                ; input (GETREC or GETCHR)
247         cmp     #CLOSE
248         bcc     CIO_write_jmp           ; output (PUTREC or PUTCHR)
249         beq     CIO_call_a              ; pass through, buffer not used
250         cmp     #RENAME                 ; 2 filenames as input parameters in buffer, length not used
251         beq     CIO_filename2
252         cmp     #GETCWD
253         bcc     CIO_filename            ; filename as input parameter in buffer, length not used
254         beq     CIO_invalid             ; GETCWD not supported yet
255         bcs     CIO_call_a              ; other commands: assume no buffer
256 ; not reached
257
258 CIO_write_jmp:
259         jmp     CIO_write
260
261 CIO_invalid:
262         lda     CIO_a
263         ldy     #DINVCM
264         rts
265
266 ; READ handler
267 ; ------------
268
269 CIO_read:
270         lda     ICBLL,x
271         ora     ICBLH,x
272         beq     CIO_call_a              ; special I/O through A register in case buffer length is 0
273
274 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
275
276 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
277 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
278
279         lda     ICBLH,x                 ; get high byte of length
280         bne     big_read                ; not zero -> data too large for our buffers
281                                         ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
282         lda     #<BUFSZ
283         cmp     ICBLL,x
284         bcc     big_read
285
286 ; Data size fits into bounce buffer
287
288         jsr     setup_zpptr1
289         jsr     bncbuf_to_iocb
290         jsr     CIO_call_a              ; call CIO
291         php
292         bpl     @no_err
293         cpy     #EOFERR
294         beq     @no_err
295         pha
296         jsr     restore_icba
297         pla
298         plp
299         rts                             ; return with error
300
301 @no_err:
302         sta     CIO_a
303         sty     CIO_y
304
305         jsr     copy_to_user            ; copy data into user buffer
306         jsr     restore_icba
307
308         lda     CIO_a
309         ldy     CIO_y
310         plp
311         rts                             ; return with success
312
313 ; Data size does not fit into bounce buffer
314
315 big_read:
316         lda     #0
317         sta     retlen                  ; initialize return length
318         sta     retlen+1
319         jsr     iocblen_to_orig_len
320         jsr     iocbptr_to_orig_ptr
321         jsr     setup_zpptr1
322         jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
323
324 br_loop:
325         jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
326         bcs     br_last                 ; no, last transfer, use remaining size
327
328         lda     #>BUFSZ
329         sta     ICBLH,x                 ; set data length
330         lda     #<BUFSZ
331         sta     ICBLL,x
332         bne     br_cont
333
334 br_last:
335         lda     orig_len+1
336         sta     ICBLH,x                 ; set data length
337         lda     orig_len
338         sta     ICBLL,x
339
340 br_cont:
341         sta     req_len                 ; remember length of this request
342         lda     ICBLH,x
343         sta     req_len+1
344         jsr     CIO_call_a              ; do the request
345         php
346         bpl     br_no_err
347         cpy     #EOFERR
348         beq     br_no_err
349
350         pha
351         jsr     restore_icba
352         pla
353         plp
354         rts                             ; return with error
355
356 br_no_err:
357         sta     CIO_a
358         sty     CIO_y
359         pla
360         sta     CIO_p
361         jsr     copy_to_user
362
363 ; update retlen
364         clc
365         lda     retlen
366         adc     ICBLL,x
367         sta     retlen
368         lda     retlen+1
369         adc     #0
370         sta     retlen+1
371
372 ; if the request read less bytes than requested, we're done
373         lda     ICBLL,x
374         cmp     req_len
375         bne     br_done
376         lda     ICBLH,x
377         cmp     req_len+1
378         bne     br_done
379
380 ; update user buffer pointer (zpptr1)
381         clc
382         lda     zpptr1
383         adc     ICBLL,x
384         sta     zpptr1
385         lda     zpptr1+1
386         adc     #0
387         sta     zpptr1+1
388
389 ; update remaining length
390         sec
391         lda     orig_len
392         sbc     ICBLL,x
393         sta     orig_len
394         lda     orig_len+1
395         sbc     #0
396         sta     orig_len+1
397
398 ; still something left to do (remaining length != 0)?
399         lda     orig_len
400         ora     orig_len+1
401         beq     br_done
402         jmp     br_loop
403
404 ; done, write original buffer pointer and total transfer length to IOCB and return to application
405 br_done:
406         lda     retlen
407         sta     ICBLL,x
408         lda     retlen+1
409         sta     ICBLH,x
410         jsr     orig_ptr_to_iocbptr
411         lda     CIO_p
412         pha
413         lda     CIO_a
414         ldy     CIO_y
415         plp
416         rts                             ; return with success
417
418
419
420 CIO_call_a_jmp:
421         jmp     CIO_call_a
422
423
424
425 ; WRITE handler
426 ; -------------
427
428
429 CIO_write:
430         lda     ICBLL,x
431         ora     ICBLH,x
432         beq     CIO_call_a_jmp          ; special I/O through A register in case buffer length is 0
433
434 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
435
436 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
437 ; Otherwise we can get away with a copy to the bounce buffer and the call.
438
439         lda     ICBLH,x                 ; get high byte of length
440         bne     big_write               ; not zero -> data too large for our buffers
441                                         ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
442         lda     #<BUFSZ
443         cmp     ICBLL,x
444         bcc     big_write
445
446
447 ; Data size fits into bounce buffer
448
449         jsr     setup_zpptr1
450         jsr     bncbuf_to_iocb
451         jsr     copy_from_user
452         ldy     CIO_y
453         jsr     CIO_call_a
454         php
455         pha
456         jsr     restore_icba
457         pla
458         plp
459         rts                             ; return to application
460
461
462 ; Data size does not fit into bounce buffer
463
464 big_write:
465         lda     #0
466         sta     retlen                  ; initialize return length
467         sta     retlen+1
468         jsr     iocblen_to_orig_len
469         jsr     iocbptr_to_orig_ptr
470         jsr     setup_zpptr1
471         jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
472
473 bw_loop:
474         jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
475         bcs     bw_last                 ; no, last transfer, use remaining size
476
477         lda     #>BUFSZ
478         sta     ICBLH,x                 ; set data length
479         lda     #<BUFSZ
480         sta     ICBLL,x
481         bne     bw_cont
482
483 bw_last:
484         lda     orig_len+1
485         sta     ICBLH,x                 ; set data length
486         lda     orig_len
487         sta     ICBLL,x
488
489 bw_cont:
490         sta     req_len                 ; remember length of this request
491         lda     ICBLH,x
492         sta     req_len+1
493         jsr     copy_from_user
494         jsr     CIO_call_a              ; do the request
495         php
496         bpl     bw_no_err
497
498         plp
499         rts                             ; error return
500
501 bw_no_err:
502         sta     CIO_a
503         sty     CIO_y
504         pla
505         sta     CIO_p
506
507 ; update retlen
508         clc
509         lda     retlen
510         adc     ICBLL,x
511         sta     retlen
512         lda     retlen+1
513         adc     #0
514         sta     retlen+1
515
516 ; if the request wrote less bytes than requested, we're done
517         lda     ICBLL,x
518         cmp     req_len
519         bne     bw_done
520         lda     ICBLH,x
521         cmp     req_len+1
522         bne     bw_done
523
524 ; update user buffer pointer (zpptr1)
525         clc
526         lda     zpptr1
527         adc     ICBLL,x
528         sta     zpptr1
529         lda     zpptr1+1
530         adc     #0
531         sta     zpptr1+1
532
533 ; update remaining length
534         sec
535         lda     orig_len
536         sbc     ICBLL,x
537         sta     orig_len
538         lda     orig_len+1
539         sbc     #0
540         sta     orig_len+1
541
542 ; still something left to do (remaining length != 0)?
543         lda     orig_len
544         ora     orig_len+1
545         beq     bw_done
546         jmp     bw_loop
547
548 bw_done:
549         lda     retlen
550         sta     ICBLL,x
551         lda     retlen+1
552         sta     ICBLH,x
553         jsr     orig_ptr_to_iocbptr
554         lda     CIO_p
555         pha
556         lda     CIO_a
557         ldy     CIO_y
558         plp
559         rts                             ; return with success
560
561
562
563 ; check if length is larger than bounce buffer size
564 ; input:   orig_len - length
565 ; output:         A - destroyed
566 ;                CF - 0/1 for larger/not larger
567 cmp_orig_len_bnc_bufsz:
568         sec
569         lda     #<BUFSZ
570         sbc     orig_len
571         lda     #>BUFSZ
572         sbc     orig_len+1
573         rts
574
575
576 ; copy data from bounce buffer into user buffer
577 ; input:   X - IOCB index
578 ;     zpptr1 - pointer to user buffer
579 ; output:  A - destroyed
580 ;          Y - 0
581 copy_to_user:
582         ldy     ICBLL,x                 ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
583         beq     @copy_done
584 @copy:  dey
585         lda     bounce_buffer,y
586         sta     (zpptr1),y
587         cpy     #0
588         bne     @copy
589 @copy_done:
590         rts
591
592
593 ; copy data from user buffer into bounce buffer
594 ; input:   X - IOCB index
595 ;     zpptr1 - pointer to user buffer
596 ; output:  A - destroyed
597 ;          Y - 0
598 copy_from_user:
599         ldy     ICBLL,x                 ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
600         beq     @copy_done
601 @copy:  dey
602         lda     (zpptr1),y
603         sta     bounce_buffer,y
604         cpy     #0
605         bne     @copy
606 @copy_done:
607         rts
608
609
610 ; copy ICBLL/ICBLH to 'orig_len'
611 ; input:   X - IOCB index
612 ; output:  A - destroyed
613 iocblen_to_orig_len:
614         lda     ICBLL,x
615         sta     orig_len
616         lda     ICBLH,x
617         sta     orig_len+1
618         rts
619
620
621 ; copy ICBAL/ICBAH to 'orig_ptr'
622 ; input:   X - IOCB index
623 ; output:  A - destroyed
624 iocbptr_to_orig_ptr:
625         lda     ICBAL,x
626         sta     orig_ptr
627         lda     ICBAH,x
628         sta     orig_ptr+1
629         rts
630
631
632 ; copy 'orig_ptr' to ICBAL/ICBAH
633 ; input:   X - IOCB index
634 ; output:  A - destroyed
635 orig_ptr_to_iocbptr:
636         lda     orig_ptr
637         sta     ICBAL,x
638         lda     orig_ptr+1
639         sta     ICBAH,x
640         rts
641
642
643 ; restore original contents of ICBAL/ICBAH from 'zpptr1'
644 ; input:   X - IOCB index
645 ; output:  A - destroyed
646 restore_icba:
647         lda     zpptr1
648         sta     ICBAL,x
649         lda     zpptr1+1
650         sta     ICBAH,x
651         rts
652
653
654 ; put bounce buffer address into ICBAL/ICBAH
655 ; input:   X - IOCB index
656 ; output:  A - destroyed
657 bncbuf_to_iocb:
658         lda     #<bounce_buffer
659         sta     ICBAL,x
660         lda     #>bounce_buffer
661         sta     ICBAH,x
662         rts
663
664
665 ; copy file name pointed to by 'zpptr1' to 'bounce_buffer'
666 ; input:   Y - index into file name buffer and bounce_buffer
667 ; output:  Y - points to first invalid byte after file name
668 ;          A - destroyed
669 copy_filename:
670         lda     (zpptr1),y
671         sta     bounce_buffer,y
672         beq     copy_fn_done
673         iny
674         cmp     #ATEOL
675         bne     copy_filename
676         dey
677 copy_fn_done:
678         rts
679
680
681 ; write IOCB buffer address into zpptr1
682 ; input:   X - IOCB index
683 ; output:  Y - 0 (for setup_zpptr1_y0, else unchanged)
684 ;          A - destroyed
685 setup_zpptr1_y0:
686         ldy     #0
687 setup_zpptr1:
688         lda     ICBAL,x                 ; put buffer address into zp pointer
689         sta     zpptr1
690         lda     ICBAH,x
691         sta     zpptr1+1
692         rts
693
694 ;---------------------------------------------------------
695
696 ; SIO handler
697 ; We only handle SIO_STAT, SIO_READ, SIO_WRITE, and SIO_WRITEV.
698 ; These are the only functions used by the runtime library currently.
699 ; For other function we return NVALID status code.
700
701 SIO_handler:
702         lda     DCOMND                  ; get command
703         cmp     #SIO_STAT
704         beq     SIO_stat
705         cmp     #SIO_READ
706         beq     SIO_read
707         cmp     #SIO_WRITE
708         beq     SIO_write
709         cmp     #SIO_WRITEV
710         beq     SIO_write
711
712         ; unhandled command
713         lda     #NVALID
714 SIO_err:sta     DSTATS
715         rts
716
717 ; SIO_STAT is always called with a low buffer (by the runtime)
718 SIO_stat:
719         ; fall thru
720
721 SIO_call:
722         lda     PORTB
723         sta     cur_SIOV_PORTB
724         enable_rom
725         jsr     SIOV_org
726         php
727         pha
728         lda     cur_SIOV_PORTB
729         sta     PORTB
730         pla
731         plp
732         rts
733
734
735 ; SIO read handler
736 ; ----------------
737
738 SIO_read:
739
740 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
741
742 ; we only support transfers <= bounce buffer size
743         jsr     cmp_sio_len_bnc_bufsz
744         bcs     sio_read_len_ok
745
746         lda     #DERROR         ; don't know a better status code for this
747         bne     SIO_err
748
749 sio_read_len_ok:
750         lda     DBUFLO
751         sta     zpptr1          ; remember destination buffer address
752         lda     DBUFHI
753         sta     zpptr1+1
754
755         jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
756
757         jsr     SIO_call        ; do the operation
758         pha
759         lda     DSTATS          ; get status
760         bmi     sio_read_ret    ; error
761
762         ; copy data to user buffer
763 sio_read_ok:
764         lda     DBYTHI          ; could be 1 for 256 bytes
765         beq     srok1
766         ldy     #0
767         beq     srok2
768 srok1:  ldy     DBYTLO
769 srok2:  dey
770 sio_read_copy:
771         lda     bounce_buffer,y
772         sta     (zpptr1),y
773         dey
774         cpy     #$ff
775         bne     sio_read_copy
776
777 sio_read_ret:
778         jsr     orgbuf_to_dbuf
779
780         pla
781         rts                     ; success return
782
783
784 ; SIO write handler
785 ; -----------------
786
787 SIO_write:
788
789 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
790
791 ; we only support transfers <= bounce buffer size
792         jsr     cmp_sio_len_bnc_bufsz
793         bcs     sio_write_len_ok
794
795         lda     #DERROR         ; don't know a better status code for this
796         bne     SIO_err
797
798 sio_write_len_ok:
799         lda     DBUFLO
800         sta     zpptr1          ; get source buffer address
801         lda     DBUFHI
802         sta     zpptr1+1
803
804         ; copy data from user buffer to bounce buffer
805         lda     DBYTHI          ; could be 1 for 256 bytes
806         beq     swok1
807         ldy     #0
808         beq     swok2
809 swok1:  ldy     DBYTLO
810 swok2:  dey
811 sio_write_copy:
812         lda     (zpptr1),y
813         sta     bounce_buffer,y
814         dey
815         cpy     #$ff
816         bne     sio_write_copy
817
818         jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
819
820         jsr     SIO_call        ; do the operation
821         pha
822         jsr     orgbuf_to_dbuf
823         pla
824         rts
825
826
827 ; check if SIO length is larger than bounce buffer size
828 ; input:   orig_len - length
829 ; output:         A - destroyed
830 ;                CF - 0/1 for larger/not larger
831 cmp_sio_len_bnc_bufsz:
832         sec
833         lda     #<BUFSZ_SIO
834         sbc     DBYTLO
835         lda     #>BUFSZ_SIO
836         sbc     DBYTHI
837         rts
838
839 ; put bounce buffer address into DBUFLO/DBUFHI
840 ; input:   (--)
841 ; output:  A - destroyed
842 bncbuf_to_dbuf:
843         lda     #<bounce_buffer
844         sta     DBUFLO
845         lda     #>bounce_buffer
846         sta     DBUFHI
847         rts
848
849 ; put original buffer address into DBUFLO/DBUFHI
850 ; input:   zpptr1 - original pointer
851 ; output:  A      - destroyed
852 orgbuf_to_dbuf:
853         lda     zpptr1
854         sta     DBUFLO
855         lda     zpptr1+1
856         sta     DBUFHI
857         rts
858
859
860 ;---------------------------------------------------------
861
862 KEYBDV_handler:
863
864         lda     #>(kret-1)
865         pha
866         lda     #<(kret-1)
867         pha
868         lda     PORTB
869         sta     cur_KEYBDV_PORTB
870         enable_rom
871         lda     KEYBDV+5
872         pha
873         lda     KEYBDV+4
874         pha
875         rts             ; call keyboard handler
876 kret:   pha
877         lda     cur_KEYBDV_PORTB
878         sta     PORTB
879         pla
880         rts
881
882 ;---------------------------------------------------------
883
884 SETVBV_handler:
885
886         pha
887         lda     PORTB
888         sta     cur_SETVBV_PORTB
889         enable_rom
890         pla
891         jsr     SETVBV_org
892         php
893         pha
894         lda     cur_SETVBV_PORTB
895         sta     PORTB
896         pla
897         plp
898         rts
899
900 CIO_a:                  .res    1
901 CIO_x:                  .res    1
902 CIO_y:                  .res    1
903 CIO_p:                  .res    1
904 cur_CIOV_PORTB:         .res    1
905 cur_SIOV_PORTB:         .res    1
906 cur_KEYBDV_PORTB:       .res    1
907 cur_SETVBV_PORTB:       .res    1
908 orig_ptr:               .res    2
909 orig_len:               .res    2
910 req_len:                .res    2
911 retlen:                 .res    2
912
913 .endif  ; .if .defined(__ATARIXL__)