]> git.sur5r.net Git - cc65/blob - libsrc/atari/shadow_ram_handlers.s
more atarixl linker cfg file cleanups; adapt atarixl-overlay.cfg
[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 .if .defined(__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 ;       lda     cur_CIOV_PORTB
297 ;       sta     PORTB
298         pla
299         plp
300         rts
301
302
303 CIO_write_jmp:
304         jmp     CIO_write
305
306 CIO_invalid:
307         lda     CIO_a
308         ldy     #DINVCM
309         rts
310
311 ; READ handler
312 ; ------------
313
314 CIO_read:
315         lda     ICBLL,x
316         ora     ICBLH,x
317         beq     CIO_call_a              ; special I/O through A register in case buffer length is 0
318
319 .if CHKBUF
320         jsr     chk_CIO_buf
321         bcc     CIO_call_a
322 .endif
323
324 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
325 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
326
327         lda     ICBLH,x                 ; get high byte of length
328         bne     big_read                ; not zero -> data too large for our buffers
329                                         ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
330         lda     #<BUFSZ
331         cmp     ICBLL,x
332         bcc     big_read
333
334 ; Data size fits into bounce buffer
335
336         jsr     setup_zpptr1
337         jsr     bncbuf_to_iocb
338         jsr     CIO_call_a              ; call CIO
339         php
340         bpl     @no_err
341         cpy     #EOFERR
342         beq     @no_err
343         pha
344         jsr     restore_icba
345         pla
346         plp
347         rts                             ; return with error
348
349 @no_err:
350         sta     CIO_a
351         sty     CIO_y
352
353         jsr     copy_to_user            ; copy data into user buffer
354         jsr     restore_icba
355
356         lda     CIO_a
357         ldy     CIO_y
358         plp
359         rts                             ; return with success
360
361 ; Data size does not fit into bounce buffer
362
363 big_read:
364         lda     #0
365         sta     retlen                  ; initialize return length
366         sta     retlen+1
367         jsr     iocblen_to_orig_len
368         jsr     iocbptr_to_orig_ptr
369         jsr     setup_zpptr1
370         jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
371
372 br_loop:
373         jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
374         bcs     br_last                 ; no, last transfer, use remaining size
375
376         lda     #>BUFSZ
377         sta     ICBLH,x                 ; set data length
378         lda     #<BUFSZ
379         sta     ICBLL,x
380         bne     br_cont
381
382 br_last:
383         lda     orig_len+1
384         sta     ICBLH,x                 ; set data length
385         lda     orig_len
386         sta     ICBLL,x
387
388 br_cont:
389         sta     req_len                 ; remember length of this request
390         lda     ICBLH,x
391         sta     req_len+1
392         jsr     CIO_call_a              ; do the request
393         php
394         bpl     br_no_err
395         cpy     #EOFERR
396         beq     br_no_err
397
398         pha
399         jsr     restore_icba
400         pla
401         plp
402         rts                             ; return with error
403
404 br_no_err:
405         sta     CIO_a
406         sty     CIO_y
407         pla
408         sta     CIO_p
409         jsr     copy_to_user
410
411 ; update retlen
412         clc
413         lda     retlen
414         adc     ICBLL,x
415         sta     retlen
416         lda     retlen+1
417         adc     #0
418         sta     retlen+1
419
420 ; if the request read less bytes than requested, we're done
421         lda     ICBLL,x
422         cmp     req_len
423         bne     br_done
424         lda     ICBLH,x
425         cmp     req_len+1
426         bne     br_done
427
428 ; update user buffer pointer (zpptr1)
429         clc
430         lda     zpptr1
431         adc     ICBLL,x
432         sta     zpptr1
433         lda     zpptr1+1
434         adc     #0
435         sta     zpptr1+1
436
437 ; update remaining length
438         sec
439         lda     orig_len
440         sbc     ICBLL,x
441         sta     orig_len
442         lda     orig_len+1
443         sbc     #0
444         sta     orig_len+1
445
446 ; still something left to do (remaining length != 0)?
447         lda     orig_len
448         ora     orig_len+1
449         beq     br_done
450         jmp     br_loop
451
452 ; done, write original buffer pointer and total transfer length to IOCB and return to application
453 br_done:
454         lda     retlen
455         sta     ICBLL,x
456         lda     retlen+1
457         sta     ICBLH,x
458         jsr     orig_ptr_to_iocbptr
459         lda     CIO_p
460         pha
461         lda     CIO_a
462         ldy     CIO_y
463         plp
464         rts                             ; return with success
465
466
467
468 CIO_call_a_jmp:
469         jmp     CIO_call_a
470
471
472
473 ; WRITE handler
474 ; -------------
475
476
477 CIO_write:
478         lda     ICBLL,x
479         ora     ICBLH,x
480         beq     CIO_call_a_jmp          ; special I/O through A register in case buffer length is 0
481
482 .if CHKBUF
483         jsr     chk_CIO_buf
484         bcc     CIO_call_a_jmp
485 .endif
486
487 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
488 ; Otherwise we can get away with a copy to the bounce buffer and the call.
489
490         lda     ICBLH,x                 ; get high byte of length
491         bne     big_write               ; not zero -> data too large for our buffers
492                                         ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
493         lda     #<BUFSZ
494         cmp     ICBLL,x
495         bcc     big_write
496
497
498 ; Data size fits into bounce buffer
499
500         jsr     setup_zpptr1
501         jsr     bncbuf_to_iocb
502         jsr     copy_from_user
503         ldy     CIO_y
504         jsr     CIO_call_a
505         php
506         pha
507         jsr     restore_icba
508         pla
509         plp
510         rts                             ; return to application
511
512
513 ; Data size does not fit into bounce buffer
514
515 big_write:
516         lda     #0
517         sta     retlen                  ; initialize return length
518         sta     retlen+1
519         jsr     iocblen_to_orig_len
520         jsr     iocbptr_to_orig_ptr
521         jsr     setup_zpptr1
522         jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
523
524 bw_loop:
525         jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
526         bcs     bw_last                 ; no, last transfer, use remaining size
527
528         lda     #>BUFSZ
529         sta     ICBLH,x                 ; set data length
530         lda     #<BUFSZ
531         sta     ICBLL,x
532         bne     bw_cont
533
534 bw_last:
535         lda     orig_len+1
536         sta     ICBLH,x                 ; set data length
537         lda     orig_len
538         sta     ICBLL,x
539
540 bw_cont:
541         sta     req_len                 ; remember length of this request
542         lda     ICBLH,x
543         sta     req_len+1
544         jsr     copy_from_user
545         jsr     CIO_call_a              ; do the request
546         php
547         bpl     bw_no_err
548
549         plp
550         rts                             ; error return
551
552 bw_no_err:
553         sta     CIO_a
554         sty     CIO_y
555         pla
556         sta     CIO_p
557
558 ; update retlen
559         clc
560         lda     retlen
561         adc     ICBLL,x
562         sta     retlen
563         lda     retlen+1
564         adc     #0
565         sta     retlen+1
566
567 ; if the request wrote less bytes than requested, we're done
568         lda     ICBLL,x
569         cmp     req_len
570         bne     bw_done
571         lda     ICBLH,x
572         cmp     req_len+1
573         bne     bw_done
574
575 ; update user buffer pointer (zpptr1)
576         clc
577         lda     zpptr1
578         adc     ICBLL,x
579         sta     zpptr1
580         lda     zpptr1+1
581         adc     #0
582         sta     zpptr1+1
583
584 ; update remaining length
585         sec
586         lda     orig_len
587         sbc     ICBLL,x
588         sta     orig_len
589         lda     orig_len+1
590         sbc     #0
591         sta     orig_len+1
592
593 ; still something left to do (remaining length != 0)?
594         lda     orig_len
595         ora     orig_len+1
596         beq     bw_done
597         jmp     bw_loop
598
599 bw_done:
600         lda     retlen
601         sta     ICBLL,x
602         lda     retlen+1
603         sta     ICBLH,x
604         jsr     orig_ptr_to_iocbptr
605         lda     CIO_p
606         pha
607         lda     CIO_a
608         ldy     CIO_y
609         plp
610         rts                             ; return with success
611
612
613
614 ; check if length is larger than bounce buffer size
615 ; input:   orig_len - length
616 ; output:         A - destroyed
617 ;                CF - 0/1 for larger/not larger
618 cmp_orig_len_bnc_bufsz:
619         sec
620         lda     #<BUFSZ
621         sbc     orig_len
622         lda     #>BUFSZ
623         sbc     orig_len+1
624         rts
625
626
627 ; copy data from bounce buffer into user buffer
628 ; input:   X - IOCB index
629 ;     zpptr1 - pointer to user buffer
630 ; output:  A - destroyed
631 ;          Y - 0
632 copy_to_user:
633         ldy     ICBLL,x                 ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
634         beq     @copy_done
635 @copy:  dey
636         lda     bounce_buffer,y
637         sta     (zpptr1),y
638         cpy     #0
639         bne     @copy
640 @copy_done:
641         rts
642
643
644 ; copy data from user buffer into bounce buffer
645 ; input:   X - IOCB index
646 ;     zpptr1 - pointer to user buffer
647 ; output:  A - destroyed
648 ;          Y - 0
649 copy_from_user:
650         ldy     ICBLL,x                 ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
651         beq     @copy_done
652 @copy:  dey
653         lda     (zpptr1),y
654         sta     bounce_buffer,y
655         cpy     #0
656         bne     @copy
657 @copy_done:
658         rts
659
660
661 ; copy ICBLL/ICBLH to 'orig_len'
662 ; input:   X - IOCB index
663 ; output:  A - destroyed
664 iocblen_to_orig_len:
665         lda     ICBLL,x
666         sta     orig_len
667         lda     ICBLH,x
668         sta     orig_len+1
669         rts
670
671
672 ; copy ICBAL/ICBAH to 'orig_ptr'
673 ; input:   X - IOCB index
674 ; output:  A - destroyed
675 iocbptr_to_orig_ptr:
676         lda     ICBAL,x
677         sta     orig_ptr
678         lda     ICBAH,x
679         sta     orig_ptr+1
680         rts
681
682
683 ; copy 'orig_ptr' to ICBAL/ICBAH
684 ; input:   X - IOCB index
685 ; output:  A - destroyed
686 orig_ptr_to_iocbptr:
687         lda     orig_ptr
688         sta     ICBAL,x
689         lda     orig_ptr+1
690         sta     ICBAH,x
691         rts
692
693
694 ; restore original contents of ICBAL/ICBAH from 'zpptr1'
695 ; input:   X - IOCB index
696 ; output:  A - destroyed
697 restore_icba:
698         lda     zpptr1
699         sta     ICBAL,x
700         lda     zpptr1+1
701         sta     ICBAH,x
702         rts
703
704
705 ; put bounce buffer address into ICBAL/ICBAH
706 ; input:   X - IOCB index
707 ; output:  A - destroyed
708 bncbuf_to_iocb:
709         lda     #<bounce_buffer
710         sta     ICBAL,x
711         lda     #>bounce_buffer
712         sta     ICBAH,x
713         rts
714
715
716 ; copy file name pointed to by 'zpptr1' to 'bounce_buffer'
717 ; input:   Y - index into file name buffer and bounce_buffer
718 ; output:  Y - points to first invalid byte after file name
719 ;          A - destroyed
720 copy_filename:
721         lda     (zpptr1),y
722         sta     bounce_buffer,y
723         beq     copy_fn_done
724         iny
725         cmp     #ATEOL
726         bne     copy_filename
727         dey
728 copy_fn_done:
729         rts
730
731
732 ; write IOCB buffer address into zpptr1
733 ; input:   X - IOCB index
734 ; output:  Y - 0 (for setup_zpptr1_y0, else unchanged)
735 ;          A - destroyed
736 setup_zpptr1_y0:
737         ldy     #0
738 setup_zpptr1:
739         lda     ICBAL,x                 ; put buffer address into zp pointer
740         sta     zpptr1
741         lda     ICBAH,x
742         sta     zpptr1+1
743         rts
744
745
746 .if CHKBUF
747
748 ; get length of file name pointed to by 'zpptr1'
749 ; input:   Y - index into file name
750 ; output:  Y - length
751 ;          A - destroyed
752 get_fn_len:
753         lda     (zpptr1),y
754         beq     @done
755         iny
756         cmp     #ATEOL
757         bne     get_fn_len
758         dey
759 @done:
760         rts
761
762
763 chk_CIO_buf_fn2:
764         tya
765         pha
766         lda     ICBLL,x
767         pha
768         lda     ICBLH,x
769         pha
770         jsr     setup_zpptr1_y0
771         jsr     get_fn_len
772         iny                     ; include terminating zero
773         bne     fn_cont
774
775 chk_CIO_buf_fn:
776         tya
777         pha
778         lda     ICBLL,x
779         pha
780         lda     ICBLH,x
781         pha
782         jsr     setup_zpptr1_y0
783 fn_cont:jsr     get_fn_len
784         iny                     ; include terminating zero
785         tya
786         sta     ICBLL,x
787         lda     #0
788         sta     ICBLH,x
789         jsr     chk_CIO_buf
790         pla     
791         sta     ICBLH,x
792         pla     
793         sta     ICBLL,x
794         pla
795         tay
796         rts
797
798
799 ; check if a CIO input/output buffer overlaps with ROM area (>= $C000)
800 ; input:                      X - IOCB index
801 ;       ICBAL/ICBAH/ICBLL/ICBLH - buffer address and length
802 ; output:                    CF - 1/0 for overlap/no overlap
803 ;                             A - destroyed
804
805 chk_CIO_buf:
806         lda     ICBAH,x
807         cmp     #$c0
808         bcc     @cont
809 @ret:   
810 .ifdef DEBUG
811         jsr     CIO_buf_noti
812 .endif
813         rts
814
815 @cont:  lda     ICBAL,x
816         clc
817         adc     ICBLL,x
818         lda     ICBAH,x
819         adc     ICBLH,x
820         bcs     @ret            ; ??? wraparound
821         cmp     #$c0
822 .ifdef DEBUG
823         jsr     CIO_buf_noti
824 .endif
825         rts
826
827 .ifdef DEBUG
828 ; write to screen memory on 2nd line:
829 ; pos 0: # of accesses without buffering
830 ; pos 1: # of accesses with buffering
831 CIO_buf_noti:
832         php
833         pha
834         tya
835         pha
836         bcc     @nobuf
837
838         inc     CIObnval_dobuf
839         jmp     @cont
840
841 @nobuf: inc     CIObnval_nobuf
842
843 @cont:  ldy     #40
844         lda     CIObnval_nobuf
845         sta     (SAVMSC),y
846         ldy     #41
847         lda     CIObnval_dobuf
848         sta     (SAVMSC),y
849
850         pla
851         tay
852         pla
853         plp
854         rts
855
856 CIObnval_dobuf:
857         .byte   0
858 CIObnval_nobuf:
859         .byte   0
860 .endif
861
862 .endif  ; .if CHKBUF
863
864 ;---------------------------------------------------------
865
866 ; SIO handler
867 ; We only handle SIO_STAT, SIO_READ, SIO_WRITE, and SIO_WRITEV.
868 ; These are the only functions used by the runtime library currently.
869 ; For other function we return NVALID status code.
870
871 SIO_handler:
872         lda     DCOMND                  ; get command
873         cmp     #SIO_STAT
874         beq     SIO_stat
875         cmp     #SIO_READ
876         beq     SIO_read
877         cmp     #SIO_WRITE
878         beq     SIO_write
879         cmp     #SIO_WRITEV
880         beq     SIO_write
881
882         ; unhandled command
883         lda     #NVALID
884 SIO_err:sta     DSTATS
885         rts
886
887 ; SIO_STAT is always called with a low buffer (by the runtime)
888 SIO_stat:
889         ; fall thru
890
891 SIO_call:
892         lda     PORTB
893         sta     cur_SIOV_PORTB
894         enable_rom
895         jsr     SIOV_org
896         php
897         pha
898         disable_rom_val cur_SIOV_PORTB
899 ;       lda     cur_SIOV_PORTB
900 ;       sta     PORTB
901         pla
902         plp
903         rts
904
905
906 ; SIO read handler
907 ; ----------------
908
909 SIO_read:
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_read_len_ok
919
920         lda     #DERROR         ; don't know a better status code for this
921         bne     SIO_err
922
923 sio_read_len_ok:
924         lda     DBUFLO
925         sta     zpptr1          ; remember destination buffer address
926         lda     DBUFHI
927         sta     zpptr1+1
928
929         jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
930
931         jsr     SIO_call        ; do the operation
932         pha
933         lda     DSTATS          ; get status
934         bmi     sio_read_ret    ; error
935
936         ; copy data to user buffer
937 sio_read_ok:
938         lda     DBYTHI          ; could be 1 for 256 bytes
939         beq     srok1
940         ldy     #0
941         beq     srok2
942 srok1:  ldy     DBYTLO
943 srok2:  dey
944 sio_read_copy:
945         lda     bounce_buffer,y
946         sta     (zpptr1),y
947         dey
948         cpy     #$ff
949         bne     sio_read_copy
950
951 sio_read_ret:
952         jsr     orgbuf_to_dbuf
953
954         pla
955         rts                     ; success return
956
957
958 ; SIO write handler
959 ; -----------------
960
961 SIO_write:
962
963 .if CHKBUF
964         jsr     chk_SIO_buf
965         bcc     SIO_call
966 .endif
967
968 ; we only support transfers <= bounce buffer size
969         jsr     cmp_sio_len_bnc_bufsz
970         bcs     sio_write_len_ok
971
972         lda     #DERROR         ; don't know a better status code for this
973         jmp     SIO_err
974
975 sio_write_len_ok:
976         lda     DBUFLO
977         sta     zpptr1          ; get source buffer address
978         lda     DBUFHI
979         sta     zpptr1+1
980
981         ; copy data from user buffer to bounce buffer
982         lda     DBYTHI          ; could be 1 for 256 bytes
983         beq     swok1
984         ldy     #0
985         beq     swok2
986 swok1:  ldy     DBYTLO
987 swok2:  dey
988 sio_write_copy:
989         lda     (zpptr1),y
990         sta     bounce_buffer,y
991         dey
992         cpy     #$ff
993         bne     sio_write_copy
994
995         jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
996
997         jsr     SIO_call        ; do the operation
998         pha
999         jsr     orgbuf_to_dbuf
1000         pla
1001         rts
1002
1003
1004 ; check if SIO length is larger than bounce buffer size
1005 ; input:   orig_len - length
1006 ; output:         A - destroyed
1007 ;                CF - 0/1 for larger/not larger
1008 cmp_sio_len_bnc_bufsz:
1009         sec
1010         lda     #<BUFSZ_SIO
1011         sbc     DBYTLO
1012         lda     #>BUFSZ_SIO
1013         sbc     DBYTHI
1014         rts
1015
1016 ; put bounce buffer address into DBUFLO/DBUFHI
1017 ; input:   (--)
1018 ; output:  A - destroyed
1019 bncbuf_to_dbuf:
1020         lda     #<bounce_buffer
1021         sta     DBUFLO
1022         lda     #>bounce_buffer
1023         sta     DBUFHI
1024         rts
1025
1026 ; put original buffer address into DBUFLO/DBUFHI
1027 ; input:   zpptr1 - original pointer
1028 ; output:  A      - destroyed
1029 orgbuf_to_dbuf:
1030         lda     zpptr1
1031         sta     DBUFLO
1032         lda     zpptr1+1
1033         sta     DBUFHI
1034         rts
1035
1036
1037 .if CHKBUF
1038
1039 ; check if a SIO input/output buffer overlaps with ROM area (>= $C000)
1040 ; input: DBUFLO/DBUFHI/DBYTLO/DBYTHI - buffer address and length
1041 ; output:                         CF - 1/0 for overlap/no overlap
1042 ;                                  A - destroyed
1043
1044 chk_SIO_buf:
1045         lda     DBUFHI
1046         cmp     #$c0
1047         bcc     @cont
1048 @ret:
1049 .ifdef DEBUG
1050         jsr     SIO_buf_noti
1051 .endif
1052         rts
1053
1054 @cont:  lda     DBUFLO
1055         clc
1056         adc     DBYTLO
1057         lda     DBUFHI
1058         adc     DBYTHI
1059         bcs     @ret            ; ??? wraparound
1060         cmp     #$c0
1061 .ifdef DEBUG
1062         jsr     SIO_buf_noti
1063 .endif
1064         rts
1065
1066 .ifdef DEBUG
1067 ; write to screen memory on 2nd line:
1068 ; pos 38: # of accesses without buffering
1069 ; pos 39: # of accesses with buffering
1070 SIO_buf_noti:
1071         php
1072         pha
1073         tya
1074         pha
1075         bcc     @nobuf
1076
1077         inc     SIObnval_dobuf
1078         jmp     @cont
1079
1080 @nobuf: inc     SIObnval_nobuf
1081
1082 @cont:  ldy     #78
1083         lda     SIObnval_nobuf
1084         sta     (SAVMSC),y
1085         ldy     #79
1086         lda     SIObnval_dobuf
1087         sta     (SAVMSC),y
1088
1089         pla
1090         tay
1091         pla
1092         plp
1093         rts
1094
1095 SIObnval_dobuf:
1096         .byte   0
1097 SIObnval_nobuf:
1098         .byte   0
1099 .endif
1100
1101 .endif  ; .if CHKBUF
1102
1103 ;---------------------------------------------------------
1104
1105 KEYBDV_handler:
1106
1107         lda     #>(kret-1)
1108         pha
1109         lda     #<(kret-1)
1110         pha
1111         lda     PORTB
1112         sta     cur_KEYBDV_PORTB
1113         enable_rom
1114         lda     KEYBDV+5
1115         pha
1116         lda     KEYBDV+4
1117         pha
1118         rts             ; call keyboard handler
1119 kret:   pha
1120         disable_rom_val cur_KEYBDV_PORTB
1121 ;       lda     cur_KEYBDV_PORTB
1122 ;       sta     PORTB
1123         pla
1124         rts
1125
1126 ;---------------------------------------------------------
1127
1128 SETVBV_handler:
1129
1130         pha
1131         lda     PORTB
1132         sta     cur_SETVBV_PORTB
1133         enable_rom
1134         pla
1135         jsr     SETVBV_org
1136         php
1137         pha
1138         disable_rom_val cur_SETVBV_PORTB
1139 ;       lda     cur_SETVBV_PORTB
1140 ;       sta     PORTB
1141         pla
1142         plp
1143         rts
1144
1145 CIO_a:                  .res    1
1146 CIO_x:                  .res    1
1147 CIO_y:                  .res    1
1148 CIO_p:                  .res    1
1149 cur_CIOV_PORTB:         .res    1
1150 cur_SIOV_PORTB:         .res    1
1151 cur_KEYBDV_PORTB:       .res    1
1152 cur_SETVBV_PORTB:       .res    1
1153 orig_ptr:               .res    2
1154 orig_len:               .res    2
1155 req_len:                .res    2
1156 retlen:                 .res    2
1157
1158 .endif  ; .if .defined(__ATARIXL__)