]> git.sur5r.net Git - cc65/blob - libsrc/atari/shadow_ram_handlers.s
rename LOWDATA segment to LOWBSS
[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
26 BUFSZ           =       128     ; bounce buffer size
27 BUFSZ_SIO       =       256
28
29 .segment "INIT"
30
31 ; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer
32
33 sram_init:
34
35 ; disable all interrupts
36         ldx     #0
37         stx     NMIEN           ; disable NMI
38         sei
39
40 ; disable ROMs
41         disable_rom
42
43 ; setup interrupt vectors
44         lda     #<my_IRQ_han
45         sta     $fffe
46         lda     #>my_IRQ_han
47         sta     $ffff
48
49         lda     #<my_RESET_han
50         sta     $fffc
51         lda     #>my_RESET_han
52         sta     $fffd
53
54         lda     #<my_NMI_han
55         sta     $fffa
56         lda     #>my_NMI_han
57         sta     $fffb
58
59 ; enable interrupts
60         cli
61         lda     #$40
62         sta     NMIEN
63
64         rts
65
66 .segment        "EXTZP" : zeropage
67
68 zpptr1: .res    2
69
70
71 .segment "LOWBSS"
72
73 ; bounce buffers for CIO and SIO calls
74 bounce_buffer:  .res    BUFSZ_SIO
75
76
77 .segment "LOWCODE"
78
79
80 ; Interrupt handlers
81 ; ------------------
82
83 ; The interrupt handlers don't look at the current state of PORTB and
84 ; unconditionally disable the ROMs on exit.
85 ; Please note that this works, since if the ROMs are enabled we anyway
86 ; aren't being called here because the vectors are pointing to their
87 ; original ROM locations.
88
89 .macro  int_wrap orgvec
90         .local  ret
91         pha
92         enable_rom_quick
93         lda     #>ret
94         pha
95         lda     #<ret
96         pha
97         php
98         jmp     (orgvec)
99 ret:    disable_rom_quick
100         pla
101         rti
102 .endmacro
103
104 my_IRQ_han:
105 .ifdef DEBUG
106         php
107         pha
108         tya
109         pha
110         ldy     #0
111         lda     (SAVMSC),y
112         clc
113         adc     #1
114         sta     (SAVMSC),y
115         pla
116         tay
117         pla
118         plp
119 .endif
120         int_wrap $FFFE
121
122 my_NMI_han:
123 .ifdef DEBUG
124         php
125         pha
126         tya
127         pha
128         ldy     #39
129         lda     (SAVMSC),y
130         clc
131         adc     #1
132         sta     (SAVMSC),y
133         pla
134         tay
135         pla
136         plp
137 .endif
138 ; set I bit to interrupted value
139         pha
140         txa
141         pha
142         tsx
143         lda     $103,x
144         pha
145         plp
146         pla
147         tax
148         pla
149         int_wrap $FFFA
150
151 my_RESET_han:
152         enable_rom
153         jmp     ($FFFC)
154
155
156 ; System request handlers
157 ; -----------------------
158
159
160 ; for filenames we assume they will fit into our bounce buffer
161
162 ; one filename, terminated by "invalid character", located at ICBAL/ICBAH
163
164 CIO_filename:
165 .if CHKBUF
166         jsr     chk_CIO_buf_fn
167         bcc     CIO_call_a
168 .endif
169         jsr     setup_zpptr1_y0
170         jsr     copy_filename
171 CIO_fn_cont:
172         jsr     bncbuf_to_iocb
173         ldy     CIO_y
174         jsr     CIO_call_a              ; call CIO (maybe A isn't needed, then we could call CIO_call)
175         php
176         pha
177         jsr     restore_icba            ; restore original ICBAL/ICBAH
178         pla
179         plp
180         rts                             ; back to application
181
182
183 ; two filenames, terminated and separated by "invalid character", located at ICBAL/ICBAH
184
185 CIO_filename2:
186 .if CHKBUF
187         jsr     chk_CIO_buf_fn2
188         bcc     CIO_call_a
189 .endif
190         jsr     setup_zpptr1_y0
191         jsr     copy_filename
192         iny
193         jsr     copy_filename
194         jmp     CIO_fn_cont
195
196
197
198 ; CIO handler
199 ; We have buffer pointer and length entries in the IOCB, but their
200 ; usage depends on the function.
201 ; Some functions don't care about any of them (pointer and length),
202 ; and some only use the pointer (like e.g. OPEN), and some use both.
203 ; So we need function specific handlers to correctly deal with
204 ; buffers which are overlapping with the ROM area.
205 ;
206 ; FIXME: Currently only the requests used by the runtime lib are handled.
207
208 CIO_handler:
209
210 ; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
211
212         sta     CIO_a
213         sty     CIO_y
214         stx     CIO_x
215
216         lda     ICCOM,x                 ; get function
217         cmp     #OPEN
218         beq     CIO_filename            ; filename as input parameter in buffer, length not used
219         cmp     #PUTREC
220         bcc     CIO_read                ; input (GETREC or GETCHR)
221         cmp     #CLOSE
222         bcc     CIO_write_jmp           ; output (PUTREC or PUTCHR)
223         beq     CIO_call_a              ; pass through, buffer not used
224         cmp     #RENAME                 ; 2 filenames as input parameters in buffer, length not used
225         beq     CIO_filename2
226         cmp     #GETCWD
227         bcc     CIO_filename            ; filename as input parameter in buffer, length not used
228         beq     CIO_invalid             ; GETCWD not supported yet
229         bcs     CIO_call_a              ; other commands: assume no buffer
230 ; not reached
231
232 ; enable ROM, call CIO, disable ROM
233
234 CIO_call_a:
235         lda     CIO_a
236
237 CIOV_call:
238         pha
239         lda     PORTB
240         sta     cur_CIOV_PORTB
241         enable_rom
242         pla
243         jsr     CIOV_org
244         php
245         pha
246         disable_rom_val cur_CIOV_PORTB
247         pla
248         plp
249         rts
250
251
252 CIO_write_jmp:
253         jmp     CIO_write
254
255 CIO_invalid:
256         lda     CIO_a
257         ldy     #DINVCM
258         rts
259
260 ; READ handler
261 ; ------------
262
263 CIO_read:
264         lda     ICBLL,x
265         ora     ICBLH,x
266         beq     CIO_call_a              ; special I/O through A register in case buffer length is 0
267
268 .if CHKBUF
269         jsr     chk_CIO_buf
270         bcc     CIO_call_a
271 .endif
272
273 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
274 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
275
276         lda     ICBLH,x                 ; get high byte of length
277         bne     big_read                ; not zero -> data too large for our buffers
278                                         ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
279         lda     #<BUFSZ
280         cmp     ICBLL,x
281         bcc     big_read
282
283 ; Data size fits into bounce buffer
284
285         jsr     setup_zpptr1
286         jsr     bncbuf_to_iocb
287         jsr     CIO_call_a              ; call CIO
288         php
289         bpl     @no_err
290         cpy     #EOFERR
291         beq     @no_err
292         pha
293         jsr     restore_icba
294         pla
295         plp
296         rts                             ; return with error
297
298 @no_err:
299         sta     CIO_a
300         sty     CIO_y
301
302         jsr     copy_to_user            ; copy data into user buffer
303         jsr     restore_icba
304
305         lda     CIO_a
306         ldy     CIO_y
307         plp
308         rts                             ; return with success
309
310 ; Data size does not fit into bounce buffer
311
312 big_read:
313         lda     #0
314         sta     retlen                  ; initialize return length
315         sta     retlen+1
316         jsr     iocblen_to_orig_len
317         jsr     iocbptr_to_orig_ptr
318         jsr     setup_zpptr1
319         jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
320
321 br_loop:
322         jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
323         bcs     br_last                 ; no, last transfer, use remaining size
324
325         lda     #>BUFSZ
326         sta     ICBLH,x                 ; set data length
327         lda     #<BUFSZ
328         sta     ICBLL,x
329         bne     br_cont
330
331 br_last:
332         lda     orig_len+1
333         sta     ICBLH,x                 ; set data length
334         lda     orig_len
335         sta     ICBLL,x
336
337 br_cont:
338         sta     req_len                 ; remember length of this request
339         lda     ICBLH,x
340         sta     req_len+1
341         jsr     CIO_call_a              ; do the request
342         php
343         bpl     br_no_err
344         cpy     #EOFERR
345         beq     br_no_err
346
347         pha
348         jsr     restore_icba
349         pla
350         plp
351         rts                             ; return with error
352
353 br_no_err:
354         sta     CIO_a
355         sty     CIO_y
356         pla
357         sta     CIO_p
358         jsr     copy_to_user
359
360 ; update retlen
361         clc
362         lda     retlen
363         adc     ICBLL,x
364         sta     retlen
365         lda     retlen+1
366         adc     #0
367         sta     retlen+1
368
369 ; if the request read less bytes than requested, we're done
370         lda     ICBLL,x
371         cmp     req_len
372         bne     br_done
373         lda     ICBLH,x
374         cmp     req_len+1
375         bne     br_done
376
377 ; update user buffer pointer (zpptr1)
378         clc
379         lda     zpptr1
380         adc     ICBLL,x
381         sta     zpptr1
382         lda     zpptr1+1
383         adc     #0
384         sta     zpptr1+1
385
386 ; update remaining length
387         sec
388         lda     orig_len
389         sbc     ICBLL,x
390         sta     orig_len
391         lda     orig_len+1
392         sbc     #0
393         sta     orig_len+1
394
395 ; still something left to do (remaining length != 0)?
396         lda     orig_len
397         ora     orig_len+1
398         beq     br_done
399         jmp     br_loop
400
401 ; done, write original buffer pointer and total transfer length to IOCB and return to application
402 br_done:
403         lda     retlen
404         sta     ICBLL,x
405         lda     retlen+1
406         sta     ICBLH,x
407         jsr     orig_ptr_to_iocbptr
408         lda     CIO_p
409         pha
410         lda     CIO_a
411         ldy     CIO_y
412         plp
413         rts                             ; return with success
414
415
416
417 CIO_call_a_jmp:
418         jmp     CIO_call_a
419
420
421
422 ; WRITE handler
423 ; -------------
424
425
426 CIO_write:
427         lda     ICBLL,x
428         ora     ICBLH,x
429         beq     CIO_call_a_jmp          ; special I/O through A register in case buffer length is 0
430
431 .if CHKBUF
432         jsr     chk_CIO_buf
433         bcc     CIO_call_a_jmp
434 .endif
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 .if CHKBUF
696
697 ; get length of file name pointed to by 'zpptr1'
698 ; input:   Y - index into file name
699 ; output:  Y - length
700 ;          A - destroyed
701 get_fn_len:
702         lda     (zpptr1),y
703         beq     @done
704         iny
705         cmp     #ATEOL
706         bne     get_fn_len
707         dey
708 @done:
709         rts
710
711
712 chk_CIO_buf_fn2:
713         tya
714         pha
715         lda     ICBLL,x
716         pha
717         lda     ICBLH,x
718         pha
719         jsr     setup_zpptr1_y0
720         jsr     get_fn_len
721         iny                     ; include terminating zero
722         bne     fn_cont
723
724 chk_CIO_buf_fn:
725         tya
726         pha
727         lda     ICBLL,x
728         pha
729         lda     ICBLH,x
730         pha
731         jsr     setup_zpptr1_y0
732 fn_cont:jsr     get_fn_len
733         iny                     ; include terminating zero
734         tya
735         sta     ICBLL,x
736         lda     #0
737         sta     ICBLH,x
738         jsr     chk_CIO_buf
739         pla     
740         sta     ICBLH,x
741         pla     
742         sta     ICBLL,x
743         pla
744         tay
745         rts
746
747
748 ; check if a CIO input/output buffer overlaps with ROM area (>= $C000)
749 ; input:                      X - IOCB index
750 ;       ICBAL/ICBAH/ICBLL/ICBLH - buffer address and length
751 ; output:                    CF - 1/0 for overlap/no overlap
752 ;                             A - destroyed
753
754 chk_CIO_buf:
755         lda     ICBAH,x
756         cmp     #$c0
757         bcc     @cont
758 @ret:   
759 .ifdef DEBUG
760         jsr     CIO_buf_noti
761 .endif
762         rts
763
764 @cont:  lda     ICBAL,x
765         clc
766         adc     ICBLL,x
767         lda     ICBAH,x
768         adc     ICBLH,x
769         bcs     @ret            ; ??? wraparound
770         cmp     #$c0
771 .ifdef DEBUG
772         jsr     CIO_buf_noti
773 .endif
774         rts
775
776 .ifdef DEBUG
777 ; write to screen memory on 2nd line:
778 ; pos 0: # of accesses without buffering
779 ; pos 1: # of accesses with buffering
780 CIO_buf_noti:
781         php
782         pha
783         tya
784         pha
785         bcc     @nobuf
786
787         inc     CIObnval_dobuf
788         jmp     @cont
789
790 @nobuf: inc     CIObnval_nobuf
791
792 @cont:  ldy     #40
793         lda     CIObnval_nobuf
794         sta     (SAVMSC),y
795         ldy     #41
796         lda     CIObnval_dobuf
797         sta     (SAVMSC),y
798
799         pla
800         tay
801         pla
802         plp
803         rts
804
805 CIObnval_dobuf:
806         .byte   0
807 CIObnval_nobuf:
808         .byte   0
809 .endif
810
811 .endif  ; .if CHKBUF
812
813 ;---------------------------------------------------------
814
815 ; SIO handler
816 ; We only handle SIO_STAT, SIO_READ, SIO_WRITE, and SIO_WRITEV.
817 ; These are the only functions used by the runtime library currently.
818 ; For other function we return NVALID status code.
819
820 SIO_handler:
821         lda     DCOMND                  ; get command
822         cmp     #SIO_STAT
823         beq     SIO_stat
824         cmp     #SIO_READ
825         beq     SIO_read
826         cmp     #SIO_WRITE
827         beq     SIO_write
828         cmp     #SIO_WRITEV
829         beq     SIO_write
830
831         ; unhandled command
832         lda     #NVALID
833 SIO_err:sta     DSTATS
834         rts
835
836 ; SIO_STAT is always called with a low buffer (by the runtime)
837 SIO_stat:
838         ; fall thru
839
840 SIO_call:
841         lda     PORTB
842         sta     cur_SIOV_PORTB
843         enable_rom
844         jsr     SIOV_org
845         php
846         pha
847         disable_rom_val cur_SIOV_PORTB
848         pla
849         plp
850         rts
851
852
853 ; SIO read handler
854 ; ----------------
855
856 SIO_read:
857
858 .if CHKBUF
859         jsr     chk_SIO_buf
860         bcc     SIO_call
861 .endif
862
863 ; we only support transfers <= bounce buffer size
864         jsr     cmp_sio_len_bnc_bufsz
865         bcs     sio_read_len_ok
866
867         lda     #DERROR         ; don't know a better status code for this
868         bne     SIO_err
869
870 sio_read_len_ok:
871         lda     DBUFLO
872         sta     zpptr1          ; remember destination buffer address
873         lda     DBUFHI
874         sta     zpptr1+1
875
876         jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
877
878         jsr     SIO_call        ; do the operation
879         pha
880         lda     DSTATS          ; get status
881         bmi     sio_read_ret    ; error
882
883         ; copy data to user buffer
884 sio_read_ok:
885         lda     DBYTHI          ; could be 1 for 256 bytes
886         beq     srok1
887         ldy     #0
888         beq     srok2
889 srok1:  ldy     DBYTLO
890 srok2:  dey
891 sio_read_copy:
892         lda     bounce_buffer,y
893         sta     (zpptr1),y
894         dey
895         cpy     #$ff
896         bne     sio_read_copy
897
898 sio_read_ret:
899         jsr     orgbuf_to_dbuf
900
901         pla
902         rts                     ; success return
903
904
905 ; SIO write handler
906 ; -----------------
907
908 SIO_write:
909
910 .if CHKBUF
911         jsr     chk_SIO_buf
912         bcc     SIO_call
913 .endif
914
915 ; we only support transfers <= bounce buffer size
916         jsr     cmp_sio_len_bnc_bufsz
917         bcs     sio_write_len_ok
918
919         lda     #DERROR         ; don't know a better status code for this
920         jmp     SIO_err
921
922 sio_write_len_ok:
923         lda     DBUFLO
924         sta     zpptr1          ; get source buffer address
925         lda     DBUFHI
926         sta     zpptr1+1
927
928         ; copy data from user buffer to bounce buffer
929         lda     DBYTHI          ; could be 1 for 256 bytes
930         beq     swok1
931         ldy     #0
932         beq     swok2
933 swok1:  ldy     DBYTLO
934 swok2:  dey
935 sio_write_copy:
936         lda     (zpptr1),y
937         sta     bounce_buffer,y
938         dey
939         cpy     #$ff
940         bne     sio_write_copy
941
942         jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
943
944         jsr     SIO_call        ; do the operation
945         pha
946         jsr     orgbuf_to_dbuf
947         pla
948         rts
949
950
951 ; check if SIO length is larger than bounce buffer size
952 ; input:   orig_len - length
953 ; output:         A - destroyed
954 ;                CF - 0/1 for larger/not larger
955 cmp_sio_len_bnc_bufsz:
956         sec
957         lda     #<BUFSZ_SIO
958         sbc     DBYTLO
959         lda     #>BUFSZ_SIO
960         sbc     DBYTHI
961         rts
962
963 ; put bounce buffer address into DBUFLO/DBUFHI
964 ; input:   (--)
965 ; output:  A - destroyed
966 bncbuf_to_dbuf:
967         lda     #<bounce_buffer
968         sta     DBUFLO
969         lda     #>bounce_buffer
970         sta     DBUFHI
971         rts
972
973 ; put original buffer address into DBUFLO/DBUFHI
974 ; input:   zpptr1 - original pointer
975 ; output:  A      - destroyed
976 orgbuf_to_dbuf:
977         lda     zpptr1
978         sta     DBUFLO
979         lda     zpptr1+1
980         sta     DBUFHI
981         rts
982
983
984 .if CHKBUF
985
986 ; check if a SIO input/output buffer overlaps with ROM area (>= $C000)
987 ; input: DBUFLO/DBUFHI/DBYTLO/DBYTHI - buffer address and length
988 ; output:                         CF - 1/0 for overlap/no overlap
989 ;                                  A - destroyed
990
991 chk_SIO_buf:
992         lda     DBUFHI
993         cmp     #$c0
994         bcc     @cont
995 @ret:
996 .ifdef DEBUG
997         jsr     SIO_buf_noti
998 .endif
999         rts
1000
1001 @cont:  lda     DBUFLO
1002         clc
1003         adc     DBYTLO
1004         lda     DBUFHI
1005         adc     DBYTHI
1006         bcs     @ret            ; ??? wraparound
1007         cmp     #$c0
1008 .ifdef DEBUG
1009         jsr     SIO_buf_noti
1010 .endif
1011         rts
1012
1013 .ifdef DEBUG
1014 ; write to screen memory on 2nd line:
1015 ; pos 38: # of accesses without buffering
1016 ; pos 39: # of accesses with buffering
1017 SIO_buf_noti:
1018         php
1019         pha
1020         tya
1021         pha
1022         bcc     @nobuf
1023
1024         inc     SIObnval_dobuf
1025         jmp     @cont
1026
1027 @nobuf: inc     SIObnval_nobuf
1028
1029 @cont:  ldy     #78
1030         lda     SIObnval_nobuf
1031         sta     (SAVMSC),y
1032         ldy     #79
1033         lda     SIObnval_dobuf
1034         sta     (SAVMSC),y
1035
1036         pla
1037         tay
1038         pla
1039         plp
1040         rts
1041
1042 SIObnval_dobuf:
1043         .byte   0
1044 SIObnval_nobuf:
1045         .byte   0
1046 .endif
1047
1048 .endif  ; .if CHKBUF
1049
1050 ;---------------------------------------------------------
1051
1052 KEYBDV_handler:
1053
1054         lda     #>(kret-1)
1055         pha
1056         lda     #<(kret-1)
1057         pha
1058         lda     PORTB
1059         sta     cur_KEYBDV_PORTB
1060         enable_rom
1061         lda     KEYBDV+5
1062         pha
1063         lda     KEYBDV+4
1064         pha
1065         rts             ; call keyboard handler
1066 kret:   pha
1067         disable_rom_val cur_KEYBDV_PORTB
1068         pla
1069         rts
1070
1071 ;---------------------------------------------------------
1072
1073 SETVBV_handler:
1074
1075         pha
1076         lda     PORTB
1077         sta     cur_SETVBV_PORTB
1078         enable_rom
1079         pla
1080         jsr     SETVBV_org
1081         php
1082         pha
1083         disable_rom_val cur_SETVBV_PORTB
1084         pla
1085         plp
1086         rts
1087
1088 CIO_a:                  .res    1
1089 CIO_x:                  .res    1
1090 CIO_y:                  .res    1
1091 CIO_p:                  .res    1
1092 cur_CIOV_PORTB:         .res    1
1093 cur_SIOV_PORTB:         .res    1
1094 cur_KEYBDV_PORTB:       .res    1
1095 cur_SETVBV_PORTB:       .res    1
1096 orig_ptr:               .res    2
1097 orig_len:               .res    2
1098 req_len:                .res    2
1099 retlen:                 .res    2
1100
1101 .endif  ; .ifdef __ATARIXL__