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