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