]> git.sur5r.net Git - cc65/blobdiff - libsrc/atari/shadow_ram_handlers.s
Add sample linker configurations for Atari binary output in C.
[cc65] / libsrc / atari / shadow_ram_handlers.s
index 8c4400cbce5df2983b730c749851930bbdc4060e..a8ba611b6ca45407f15c465d9fd0ca63d906008b 100644 (file)
 ; Christian Groessler, chris@groessler.org, 2013
 ;
 
+;DEBUG           =       1
+CHKBUF          =       1       ; check if bounce buffering is needed (bounce buffering is always done if set to 0)
 
-.if .defined(__ATARIXL__)
+.ifdef __ATARIXL__
 
+SHRAM_HANDLERS  =       1
         .include        "atari.inc"
-       .include        "save_area.inc"
+        .include        "save_area.inc"
         .include        "zeropage.inc"
-       .import         __CHARGEN_START__
-
-       .export         sram_init
-       .export         KEYBDV_wrapper
-
-BUFSZ          =       128
-BUFSZ_CIO      =       BUFSZ
-BUFSZ_SIO      =       BUFSZ
-
-.macro disable_rom
-       lda     PORTB
-       and     #$fe
-       sta     PORTB
-       lda     #>__CHARGEN_START__
-       sta     CHBAS
-       sta     CHBASE
-.endmacro
-.macro enable_rom
-       lda     PORTB
-       ora     #1
-       sta     PORTB
-       lda     #$E0
-       sta     CHBAS
-       sta     CHBASE
-.endmacro
+        .include        "romswitch.inc"
+
+        .import         __CHARGEN_START__
 
-.segment "INIT"
+        .export         sram_init
+        .export         KEYBDV_handler
+        .export         CIO_handler
+        .export         SIO_handler
+        .export         SETVBV_handler
+        .export         XMOVE_handler
 
-;enable_count: .res    1
+BUFSZ           =       128     ; bounce buffer size
+BUFSZ_SIO       =       256
+
+.segment "ONCE"
 
 ; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer
 
 sram_init:
 
 ; disable all interrupts
-       sei
-       ldx     #0
-       stx     NMIEN           ; disable NMI
+        ldx     #0
+        stx     NMIEN           ; disable NMI
+        sei
 
 ; disable ROMs
-       ;inx
-       ;stx    enable_count
-       disable_rom
+        disable_rom
 
 ; setup interrupt vectors
-       lda     #<my_IRQ_han
-       sta     $fffe
-       lda     #>my_IRQ_han
-       sta     $ffff
-
-       lda     #<my_RESET_han
-       sta     $fffc
-       lda     #>my_RESET_han
-       sta     $fffd
-
-       lda     #<my_NMI_han
-       sta     $fffa
-       lda     #>my_NMI_han
-       sta     $fffb
-
-; setup pointers to CIOV and SIOV wrappers
-       lda     #$4C            ; JMP opcode
-       sta     CIOV
-       lda     #<my_CIOV
-       sta     CIOV+1
-       lda     #>my_CIOV
-       sta     CIOV+2
-       lda     #$4C            ; JMP opcode
-       sta     SIOV
-       lda     #<my_SIOV
-       sta     SIOV+1
-       lda     #>my_SIOV
-       sta     SIOV+2
+        lda     #<my_IRQ_han
+        sta     $fffe
+        lda     #>my_IRQ_han
+        sta     $ffff
+
+        lda     #<my_RESET_han
+        sta     $fffc
+        lda     #>my_RESET_han
+        sta     $fffd
+
+        lda     #<my_NMI_han
+        sta     $fffa
+        lda     #>my_NMI_han
+        sta     $fffb
 
 ; enable interrupts
-       lda     #$40
-       sta     NMIEN
-       cli
+        cli
+        lda     #$40
+        sta     NMIEN
 
-       rts
+        rts
 
 .segment        "EXTZP" : zeropage
 
-zpptr1:        .res    2
-;zpptr2:       .res    2
+zpptr1: .res    2
 
 
-.segment "LOWBUFS"
+.segment "LOWBSS"
 
 ; bounce buffers for CIO and SIO calls
-CIO_buffer:    .res    BUFSZ_CIO
-SIO_buffer:    .res    BUFSZ_SIO
+bounce_buffer:  .res    BUFSZ_SIO
 
 
 .segment "LOWCODE"
@@ -116,29 +87,71 @@ SIO_buffer:        .res    BUFSZ_SIO
 ; aren't being called here because the vectors are pointing to their
 ; original ROM locations.
 
-.macro int_wrap orgvec
-       .local  ret
-       pha
-       enable_rom
-       lda     #>ret
-       pha
-       lda     #<ret
-       pha
-       php
-       jmp     (orgvec)
-ret:   disable_rom
-       pla
-       rti
+.macro  int_wrap orgvec
+        .local  ret
+        pha
+        enable_rom_quick
+        lda     #>ret
+        pha
+        lda     #<ret
+        pha
+        php
+        jmp     (orgvec)
+ret:    disable_rom_quick
+        pla
+        rti
 .endmacro
 
 my_IRQ_han:
-       int_wrap IRQ_save
+.ifdef DEBUG
+        php
+        pha
+        tya
+        pha
+        ldy     #0
+        lda     (SAVMSC),y
+        clc
+        adc     #1
+        sta     (SAVMSC),y
+        pla
+        tay
+        pla
+        plp
+.endif
+        int_wrap $FFFE
 
 my_NMI_han:
-       int_wrap NMI_save
+.ifdef DEBUG
+        php
+        pha
+        tya
+        pha
+        ldy     #39
+        lda     (SAVMSC),y
+        clc
+        adc     #1
+        sta     (SAVMSC),y
+        pla
+        tay
+        pla
+        plp
+.endif
+; set I bit to interrupted value
+        pha
+        txa
+        pha
+        tsx
+        lda     $103,x
+        pha
+        plp
+        pla
+        tax
+        pla
+        int_wrap $FFFA
 
 my_RESET_han:
-       int_wrap RESET_save
+        enable_rom
+        jmp     ($FFFC)
 
 
 ; System request handlers
@@ -150,50 +163,38 @@ my_RESET_han:
 ; one filename, terminated by "invalid character", located at ICBAL/ICBAH
 
 CIO_filename:
-       jsr     setup_zpptr1_y0
-       jsr     copy_filename
+.if CHKBUF
+        jsr     chk_CIO_buf_fn
+        bcc     CIO_call_a
+.endif
+        jsr     setup_zpptr1_y0
+        jsr     copy_filename
 CIO_fn_cont:
-       jsr     ciobuf_to_iocb
-       ldy     CIO_y
-       jsr     CIO_call_a              ; call CIO (maybe A isn't needed, then we could call CIO_call)
-       php
-       pha
-;@@@ check if X is preserved over CIO call
-       jsr     restore_icba            ; restore original ICBAL/ICBAH
-       pla
-       plp
-       rts                             ; back to application
+        jsr     bncbuf_to_iocb
+        ldy     CIO_y
+        jsr     CIO_call_a              ; call CIO (maybe A isn't needed, then we could call CIO_call)
+        php
+        pha
+        jsr     restore_icba            ; restore original ICBAL/ICBAH
+        pla
+        plp
+        rts                             ; back to application
 
 
 ; two filenames, terminated and separated by "invalid character", located at ICBAL/ICBAH
 
 CIO_filename2:
-       jsr     setup_zpptr1_y0
-       jsr     copy_filename
-       iny
-       jsr     copy_filename
-       jmp     CIO_fn_cont
-
+.if CHKBUF
+        jsr     chk_CIO_buf_fn2
+        bcc     CIO_call_a
+.endif
+        jsr     setup_zpptr1_y0
+        jsr     copy_filename
+        iny
+        jsr     copy_filename
+        jmp     CIO_fn_cont
 
 
-CIO_call_a:
-       lda     CIO_a
-
-CIOV_call:
-       pha
-       lda     PORTB
-       sta     cur_CIOV_PORTB
-       enable_rom
-       pla
-       jsr     CIOV_org
-       php
-       pha
-       lda     cur_CIOV_PORTB
-       sta     PORTB
-       pla
-       plp
-       rts
-
 
 ; CIO handler
 ; We have buffer pointer and length entries in the IOCB, but their
@@ -202,195 +203,220 @@ CIOV_call:
 ; and some only use the pointer (like e.g. OPEN), and some use both.
 ; So we need function specific handlers to correctly deal with
 ; buffers which are overlapping with the ROM area.
-; All input and output registers need to be preserved (I'm not 100%
-; sure about Y as input, but let's preserve it for now.)
 ;
 ; FIXME: Currently only the requests used by the runtime lib are handled.
 
-my_CIOV:
+CIO_handler:
 
 ; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
 
-       sta     CIO_a
-       sty     CIO_y
-       stx     CIO_x
-
-       lda     ICCOM,x                 ; get function
-       cmp     #OPEN
-       beq     CIO_filename            ; filename as input parameter in buffer, length not used
-       cmp     #PUTREC
-       bcc     CIO_read                ; input (GETREC or GETCHR)
-       cmp     #CLOSE
-       bcc     CIO_write_jmp           ; output (PUTREC or PUTCHR)
-       beq     CIO_call_a              ; pass through, buffer not used
-       cmp     #RENAME                 ; 2 filenames as input parameters in buffer, length not used
-       beq     CIO_filename2
-       cmp     #GETCWD
-       bcc     CIO_filename            ; filename as input parameter in buffer, length not used
-       beq     CIO_read                ; input
-       bcs     CIO_call_a              ; other commands: assume no buffer
+        sta     CIO_a
+        sty     CIO_y
+        stx     CIO_x
+
+        lda     ICCOM,x                 ; get function
+        cmp     #OPEN
+        beq     CIO_filename            ; filename as input parameter in buffer, length not used
+        cmp     #PUTREC
+        bcc     CIO_read                ; input (GETREC or GETCHR)
+        cmp     #CLOSE
+        bcc     CIO_write_jmp           ; output (PUTREC or PUTCHR)
+        beq     CIO_call_a              ; pass through, buffer not used
+        cmp     #RENAME                 ; 2 filenames as input parameters in buffer, length not used
+        beq     CIO_filename2
+        cmp     #GETCWD
+        bcc     CIO_filename            ; filename as input parameter in buffer, length not used
+        beq     CIO_invalid             ; GETCWD not supported yet
+        bcs     CIO_call_a              ; other commands: assume no buffer
 ; not reached
 
+; enable ROM, call CIO, disable ROM
+
+CIO_call_a:
+        lda     CIO_a
+
+CIOV_call:
+        pha
+        lda     PORTB
+        sta     cur_CIOV_PORTB
+        enable_rom
+        pla
+        jsr     CIOV_org
+        php
+        pha
+        disable_rom_val cur_CIOV_PORTB
+        pla
+        plp
+        rts
+
+
 CIO_write_jmp:
-       jmp     CIO_write
+        jmp     CIO_write
 
+CIO_invalid:
+        lda     CIO_a
+        ldy     #DINVCM
+        rts
 
 ; READ handler
 ; ------------
 
 CIO_read:
-       lda     ICBLL,x
-       ora     ICBLH,x
-       beq     CIO_call_a              ; special I/O through A register in case buffer length is 0
+        lda     ICBLL,x
+        ora     ICBLH,x
+        beq     CIO_call_a              ; special I/O through A register in case buffer length is 0
 
-; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
+.if CHKBUF
+        jsr     chk_CIO_buf
+        bcc     CIO_call_a
+.endif
 
 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
 
-       lda     ICBLH,x                 ; get high byte of length
-       bne     big_read                ; not zero -> data too large for our buffers
-                                       ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
-       lda     #<BUFSZ_CIO
-       cmp     ICBLL,x
-       bcc     big_read
+        lda     ICBLH,x                 ; get high byte of length
+        bne     big_read                ; not zero -> data too large for our buffers
+                                        ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
+        lda     #<BUFSZ
+        cmp     ICBLL,x
+        bcc     big_read
 
 ; Data size fits into bounce buffer
 
-       jsr     setup_zpptr1
-       jsr     ciobuf_to_iocb
-       jsr     CIO_call_a              ; call CIO
-       php
-       bpl     @no_err
-       cpy     #EOFERR
-       beq     @no_err
-       pha
-       jsr     restore_icba
-       pla
-       plp
-       rts                             ; return with error
+        jsr     setup_zpptr1
+        jsr     bncbuf_to_iocb
+        jsr     CIO_call_a              ; call CIO
+        php
+        bpl     @no_err
+        cpy     #EOFERR
+        beq     @no_err
+        pha
+        jsr     restore_icba
+        pla
+        plp
+        rts                             ; return with error
 
 @no_err:
-       sta     CIO_a
-       sty     CIO_y
+        sta     CIO_a
+        sty     CIO_y
 
-       jsr     copy_to_user            ; copy data into user buffer
-       jsr     restore_icba
+        jsr     copy_to_user            ; copy data into user buffer
+        jsr     restore_icba
 
-       lda     CIO_a
-       ldy     CIO_y
-       plp
-       rts                             ; return with success
+        lda     CIO_a
+        ldy     CIO_y
+        plp
+        rts                             ; return with success
 
 ; Data size does not fit into bounce buffer
 
 big_read:
-       lda     #0
-       sta     retlen                  ; initialize return length
-       sta     retlen+1
-       jsr     iocblen_to_orig_len
-       jsr     iocbptr_to_orig_ptr
-       jsr     setup_zpptr1
-       jsr     ciobuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
+        lda     #0
+        sta     retlen                  ; initialize return length
+        sta     retlen+1
+        jsr     iocblen_to_orig_len
+        jsr     iocbptr_to_orig_ptr
+        jsr     setup_zpptr1
+        jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
 
 br_loop:
-       jsr     cmp_orig_len_cio_bufsz  ; is transfer length > bounce buffer size?
-       bcs     br_last                 ; no, last transfer, use remaining size
+        jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
+        bcs     br_last                 ; no, last transfer, use remaining size
 
-       lda     #>BUFSZ_CIO
-       sta     ICBLH,x                 ; set data length
-       lda     #<BUFSZ_CIO
-       sta     ICBLL,x
-       bne     br_cont
+        lda     #>BUFSZ
+        sta     ICBLH,x                 ; set data length
+        lda     #<BUFSZ
+        sta     ICBLL,x
+        bne     br_cont
 
 br_last:
-       lda     orig_len+1
-       sta     ICBLH,x                 ; set data length
-       lda     orig_len
-       sta     ICBLL,x
+        lda     orig_len+1
+        sta     ICBLH,x                 ; set data length
+        lda     orig_len
+        sta     ICBLL,x
 
 br_cont:
-       sta     req_len                 ; remember length of this request
-       lda     ICBLH,x
-       sta     req_len+1
-       jsr     CIO_call_a              ; do the request
-       php
-       bpl     br_no_err
-       cpy     #EOFERR
-       beq     br_no_err
-
-       pha
-       jsr     restore_icba
-       pla
-       plp
-       rts                             ; return with error
+        sta     req_len                 ; remember length of this request
+        lda     ICBLH,x
+        sta     req_len+1
+        jsr     CIO_call_a              ; do the request
+        php
+        bpl     br_no_err
+        cpy     #EOFERR
+        beq     br_no_err
+
+        pha
+        jsr     restore_icba
+        pla
+        plp
+        rts                             ; return with error
 
 br_no_err:
-       sta     CIO_a
-       sty     CIO_y
-       pla
-       sta     CIO_p
-       jsr     copy_to_user
+        sta     CIO_a
+        sty     CIO_y
+        pla
+        sta     CIO_p
+        jsr     copy_to_user
 
 ; update retlen
-       clc
-       lda     retlen
-       adc     ICBLL,x
-       sta     retlen
-       lda     retlen+1
-       adc     #0
-       sta     retlen+1
+        clc
+        lda     retlen
+        adc     ICBLL,x
+        sta     retlen
+        lda     retlen+1
+        adc     #0
+        sta     retlen+1
 
 ; if the request read less bytes than requested, we're done
-       lda     ICBLL,x
-       cmp     req_len
-       bne     br_done
-       lda     ICBLH,x
-       cmp     req_len+1
-       bne     br_done
+        lda     ICBLL,x
+        cmp     req_len
+        bne     br_done
+        lda     ICBLH,x
+        cmp     req_len+1
+        bne     br_done
 
 ; update user buffer pointer (zpptr1)
-       clc
-       lda     zpptr1
-       adc     ICBLL,x
-       sta     zpptr1
-       lda     zpptr1+1
-       adc     #0
-       sta     zpptr1+1
+        clc
+        lda     zpptr1
+        adc     ICBLL,x
+        sta     zpptr1
+        lda     zpptr1+1
+        adc     #0
+        sta     zpptr1+1
 
 ; update remaining length
-       sec
-       lda     orig_len
-       sbc     ICBLL,x
-       sta     orig_len
-       lda     orig_len+1
-       sbc     #0
-       sta     orig_len+1
+        sec
+        lda     orig_len
+        sbc     ICBLL,x
+        sta     orig_len
+        lda     orig_len+1
+        sbc     #0
+        sta     orig_len+1
 
 ; still something left to do (remaining length != 0)?
-       lda     orig_len
-       ora     orig_len+1
-       beq     br_done
-       jmp     br_loop
+        lda     orig_len
+        ora     orig_len+1
+        beq     br_done
+        jmp     br_loop
 
 ; done, write original buffer pointer and total transfer length to IOCB and return to application
 br_done:
-       lda     retlen
-       sta     ICBLL,x
-       lda     retlen+1
-       sta     ICBLH,x
-       jsr     orig_ptr_to_iocbptr
-       lda     CIO_p
-       pha
-       lda     CIO_a
-       ldy     CIO_y
-       plp
-       rts                             ; return with success
+        lda     retlen
+        sta     ICBLL,x
+        lda     retlen+1
+        sta     ICBLH,x
+        jsr     orig_ptr_to_iocbptr
+        lda     CIO_p
+        pha
+        lda     CIO_a
+        ldy     CIO_y
+        plp
+        rts                             ; return with success
 
 
 
 CIO_call_a_jmp:
-       jmp     CIO_call_a
+        jmp     CIO_call_a
 
 
 
@@ -399,136 +425,139 @@ CIO_call_a_jmp:
 
 
 CIO_write:
-       lda     ICBLL,x
-       ora     ICBLH,x
-       beq     CIO_call_a_jmp          ; special I/O through A register in case buffer length is 0
+        lda     ICBLL,x
+        ora     ICBLH,x
+        beq     CIO_call_a_jmp          ; special I/O through A register in case buffer length is 0
 
-; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
+.if CHKBUF
+        jsr     chk_CIO_buf
+        bcc     CIO_call_a_jmp
+.endif
 
 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
 ; Otherwise we can get away with a copy to the bounce buffer and the call.
 
-       lda     ICBLH,x                 ; get high byte of length
-       bne     big_write               ; not zero -> data too large for our buffers
-                                       ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
-       lda     #<BUFSZ_CIO
-       cmp     ICBLL,x
-       bcc     big_write
+        lda     ICBLH,x                 ; get high byte of length
+        bne     big_write               ; not zero -> data too large for our buffers
+                                        ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
+        lda     #<BUFSZ
+        cmp     ICBLL,x
+        bcc     big_write
 
 
 ; Data size fits into bounce buffer
 
-       jsr     setup_zpptr1
-       jsr     ciobuf_to_iocb
-       jsr     copy_from_user
-       ldy     CIO_y
-       jsr     CIO_call_a
-       php
-       pha
-       jsr     restore_icba
-       pla
-       plp
-       rts                             ; return to application
+        jsr     setup_zpptr1
+        jsr     bncbuf_to_iocb
+        jsr     copy_from_user
+        ldy     CIO_y
+        jsr     CIO_call_a
+        php
+        pha
+        jsr     restore_icba
+        pla
+        plp
+        rts                             ; return to application
 
 
 ; Data size does not fit into bounce buffer
 
 big_write:
-       lda     #0
-       sta     retlen                  ; initialize return length
-       sta     retlen+1
-       jsr     iocblen_to_orig_len
-       jsr     iocbptr_to_orig_ptr
-       jsr     setup_zpptr1
-       jsr     ciobuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
+        lda     #0
+        sta     retlen                  ; initialize return length
+        sta     retlen+1
+        jsr     iocblen_to_orig_len
+        jsr     iocbptr_to_orig_ptr
+        jsr     setup_zpptr1
+        jsr     bncbuf_to_iocb          ; let ICBAL/ICBAH point to bounce buffer
 
 bw_loop:
-       jsr     cmp_orig_len_cio_bufsz  ; is transfer length > bounce buffer size?
-       bcs     bw_last                 ; no, last transfer, use remaining size
+        jsr     cmp_orig_len_bnc_bufsz  ; is transfer length > bounce buffer size?
+        bcs     bw_last                 ; no, last transfer, use remaining size
 
-       lda     #>BUFSZ_CIO
-       sta     ICBLH,x                 ; set data length
-       lda     #<BUFSZ_CIO
-       sta     ICBLL,x
-       bne     bw_cont
+        lda     #>BUFSZ
+        sta     ICBLH,x                 ; set data length
+        lda     #<BUFSZ
+        sta     ICBLL,x
+        bne     bw_cont
 
 bw_last:
-       lda     orig_len+1
-       sta     ICBLH,x                 ; set data length
-       lda     orig_len
-       sta     ICBLL,x
+        lda     orig_len+1
+        sta     ICBLH,x                 ; set data length
+        lda     orig_len
+        sta     ICBLL,x
 
 bw_cont:
-       sta     req_len                 ; remember length of this request
-       lda     ICBLH,x
-       sta     req_len+1
-       jsr     copy_from_user
-       jsr     CIO_call_a              ; do the request
-       php
-       bpl     bw_no_err
+        sta     req_len                 ; remember length of this request
+        lda     ICBLH,x
+        sta     req_len+1
+        jsr     copy_from_user
+        jsr     CIO_call_a              ; do the request
+        php
+        bpl     bw_no_err
 
-       plp
-       rts                             ; error return
+        plp
+        rts                             ; error return
 
 bw_no_err:
-       sta     CIO_a
-       sty     CIO_y
-       pla
-       sta     CIO_p
+        sta     CIO_a
+        sty     CIO_y
+        pla
+        sta     CIO_p
 
 ; update retlen
-       clc
-       lda     retlen
-       adc     ICBLL,x
-       sta     retlen
-       lda     retlen+1
-       adc     #0
-       sta     retlen+1
+        clc
+        lda     retlen
+        adc     ICBLL,x
+        sta     retlen
+        lda     retlen+1
+        adc     #0
+        sta     retlen+1
 
 ; if the request wrote less bytes than requested, we're done
-       lda     ICBLL,x
-       cmp     req_len
-       bne     bw_done
-       lda     ICBLH,x
-       cmp     req_len+1
-       bne     bw_done
+        lda     ICBLL,x
+        cmp     req_len
+        bne     bw_done
+        lda     ICBLH,x
+        cmp     req_len+1
+        bne     bw_done
 
 ; update user buffer pointer (zpptr1)
-       clc
-       lda     zpptr1
-       adc     ICBLL,x
-       sta     zpptr1
-       lda     zpptr1+1
-       adc     #0
-       sta     zpptr1+1
+        clc
+        lda     zpptr1
+        adc     ICBLL,x
+        sta     zpptr1
+        lda     zpptr1+1
+        adc     #0
+        sta     zpptr1+1
 
 ; update remaining length
-       sec
-       lda     orig_len
-       sbc     ICBLL,x
-       sta     orig_len
-       lda     orig_len+1
-       sbc     #0
-       sta     orig_len+1
+        sec
+        lda     orig_len
+        sbc     ICBLL,x
+        sta     orig_len
+        lda     orig_len+1
+        sbc     #0
+        sta     orig_len+1
 
 ; still something left to do (remaining length != 0)?
-       lda     orig_len
-       ora     orig_len+1
-       beq     bw_done
-       jmp     bw_loop
+        lda     orig_len
+        ora     orig_len+1
+        beq     bw_done
+        jmp     bw_loop
 
 bw_done:
-       lda     retlen
-       sta     ICBLL,x
-       lda     retlen+1
-       sta     ICBLH,x
-       jsr     orig_ptr_to_iocbptr
-       lda     CIO_p
-       pha
-       lda     CIO_a
-       ldy     CIO_y
-       plp
-       rts                             ; return with success
+        lda     retlen
+        sta     ICBLL,x
+        lda     retlen+1
+        sta     ICBLH,x
+        jsr     orig_ptr_to_iocbptr
+        lda     CIO_p
+        pha
+        lda     CIO_a
+        ldy     CIO_y
+        plp
+        rts                             ; return with success
 
 
 
@@ -536,118 +565,118 @@ bw_done:
 ; input:   orig_len - length
 ; output:         A - destroyed
 ;                CF - 0/1 for larger/not larger
-cmp_orig_len_cio_bufsz:
-       sec
-       lda     #<BUFSZ_CIO
-       sbc     orig_len
-       lda     #>BUFSZ_CIO
-       sbc     orig_len+1
-       rts
+cmp_orig_len_bnc_bufsz:
+        sec
+        lda     #<BUFSZ
+        sbc     orig_len
+        lda     #>BUFSZ
+        sbc     orig_len+1
+        rts
 
 
 ; copy data from bounce buffer into user buffer
 ; input:   X - IOCB index
 ;     zpptr1 - pointer to user buffer
 ; output:  A - destroyed
-;         Y - 0
+;          Y - 0
 copy_to_user:
-       ldy     ICBLL,x                 ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
-       beq     @copy_done
-@copy: dey
-       lda     CIO_buffer,y
-       sta     (zpptr1),y
-       cpy     #0
-       bne     @copy
+        ldy     ICBLL,x                 ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
+        beq     @copy_done
+@copy:  dey
+        lda     bounce_buffer,y
+        sta     (zpptr1),y
+        cpy     #0
+        bne     @copy
 @copy_done:
-       rts
+        rts
 
 
 ; copy data from user buffer into bounce buffer
 ; input:   X - IOCB index
 ;     zpptr1 - pointer to user buffer
 ; output:  A - destroyed
-;         Y - 0
+;          Y - 0
 copy_from_user:
-       ldy     ICBLL,x                 ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
-       beq     @copy_done
-@copy: dey
-       lda     (zpptr1),y
-       sta     CIO_buffer,y
-       cpy     #0
-       bne     @copy
+        ldy     ICBLL,x                 ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
+        beq     @copy_done
+@copy:  dey
+        lda     (zpptr1),y
+        sta     bounce_buffer,y
+        cpy     #0
+        bne     @copy
 @copy_done:
-       rts
+        rts
 
 
 ; copy ICBLL/ICBLH to 'orig_len'
 ; input:   X - IOCB index
 ; output:  A - destroyed
 iocblen_to_orig_len:
-       lda     ICBLL,x
-       sta     orig_len
-       lda     ICBLH,x
-       sta     orig_len+1
-       rts
+        lda     ICBLL,x
+        sta     orig_len
+        lda     ICBLH,x
+        sta     orig_len+1
+        rts
 
 
 ; copy ICBAL/ICBAH to 'orig_ptr'
 ; input:   X - IOCB index
 ; output:  A - destroyed
 iocbptr_to_orig_ptr:
-       lda     ICBAL,x
-       sta     orig_ptr
-       lda     ICBAH,x
-       sta     orig_ptr+1
-       rts
+        lda     ICBAL,x
+        sta     orig_ptr
+        lda     ICBAH,x
+        sta     orig_ptr+1
+        rts
 
 
 ; copy 'orig_ptr' to ICBAL/ICBAH
 ; input:   X - IOCB index
 ; output:  A - destroyed
 orig_ptr_to_iocbptr:
-       lda     orig_ptr
-       sta     ICBAL,x
-       lda     orig_ptr+1
-       sta     ICBAH,x
-       rts
+        lda     orig_ptr
+        sta     ICBAL,x
+        lda     orig_ptr+1
+        sta     ICBAH,x
+        rts
 
 
 ; restore original contents of ICBAL/ICBAH from 'zpptr1'
 ; input:   X - IOCB index
 ; output:  A - destroyed
 restore_icba:
-       lda     zpptr1
-       sta     ICBAL,x
-       lda     zpptr1+1
-       sta     ICBAH,x
-       rts
+        lda     zpptr1
+        sta     ICBAL,x
+        lda     zpptr1+1
+        sta     ICBAH,x
+        rts
 
 
 ; put bounce buffer address into ICBAL/ICBAH
 ; input:   X - IOCB index
 ; output:  A - destroyed
-ciobuf_to_iocb:
-       lda     #<CIO_buffer
-       sta     ICBAL,x
-       lda     #>CIO_buffer
-       sta     ICBAH,x
-       rts
+bncbuf_to_iocb:
+        lda     #<bounce_buffer
+        sta     ICBAL,x
+        lda     #>bounce_buffer
+        sta     ICBAH,x
+        rts
 
 
-; copy file name pointed to by 'zpptr1' to bounce buffer 'CIO_buffer'
-; input:   Y - index into file name buffer and CIO_buffer
+; copy file name pointed to by 'zpptr1' to 'bounce_buffer'
+; input:   Y - index into file name buffer and bounce_buffer
 ; output:  Y - points to first invalid byte after file name
 ;          A - destroyed
 copy_filename:
-       lda     (zpptr1),y
-       sta     CIO_buffer,y
-       beq     copy_fn_done
-       iny
-       cmp     #ATEOL
-       bne     copy_filename
-       dey
+        lda     (zpptr1),y
+        sta     bounce_buffer,y
+        beq     copy_fn_done
+        iny
+        cmp     #ATEOL
+        bne     copy_filename
+        dey
 copy_fn_done:
-       rts
+        rts
 
 
 ; write IOCB buffer address into zpptr1
@@ -655,63 +684,438 @@ copy_fn_done:
 ; output:  Y - 0 (for setup_zpptr1_y0, else unchanged)
 ;          A - destroyed
 setup_zpptr1_y0:
-       ldy     #0
+        ldy     #0
 setup_zpptr1:
-       lda     ICBAL,x                 ; put buffer address into zp pointer
-       sta     zpptr1
-       lda     ICBAH,x
-       sta     zpptr1+1
-       rts
+        lda     ICBAL,x                 ; put buffer address into zp pointer
+        sta     zpptr1
+        lda     ICBAH,x
+        sta     zpptr1+1
+        rts
+
+
+.if CHKBUF
+
+; get length of file name pointed to by 'zpptr1'
+; input:   Y - index into file name
+; output:  Y - length
+;          A - destroyed
+get_fn_len:
+        lda     (zpptr1),y
+        beq     @done
+        iny
+        cmp     #ATEOL
+        bne     get_fn_len
+        dey
+@done:
+        rts
+
+
+chk_CIO_buf_fn2:
+        tya
+        pha
+        lda     ICBLL,x
+        pha
+        lda     ICBLH,x
+        pha
+        jsr     setup_zpptr1_y0
+        jsr     get_fn_len
+        iny                     ; include terminating zero
+        bne     fn_cont
+
+chk_CIO_buf_fn:
+        tya
+        pha
+        lda     ICBLL,x
+        pha
+        lda     ICBLH,x
+        pha
+        jsr     setup_zpptr1_y0
+fn_cont:jsr     get_fn_len
+        iny                     ; include terminating zero
+        tya
+        sta     ICBLL,x
+        lda     #0
+        sta     ICBLH,x
+        jsr     chk_CIO_buf
+        pla     
+        sta     ICBLH,x
+        pla     
+        sta     ICBLL,x
+        pla
+        tay
+        rts
+
+
+; check if a CIO input/output buffer overlaps with ROM area (>= $C000)
+; input:                      X - IOCB index
+;       ICBAL/ICBAH/ICBLL/ICBLH - buffer address and length
+; output:                    CF - 1/0 for overlap/no overlap
+;                             A - destroyed
+
+chk_CIO_buf:
+        lda     ICBAH,x
+        cmp     #$c0
+        bcc     @cont
+@ret:   
+.ifdef DEBUG
+        jsr     CIO_buf_noti
+.endif
+        rts
+
+@cont:  lda     ICBAL,x
+        clc
+        adc     ICBLL,x
+        lda     ICBAH,x
+        adc     ICBLH,x
+        bcs     @ret            ; ??? wraparound
+        cmp     #$c0
+.ifdef DEBUG
+        jsr     CIO_buf_noti
+.endif
+        rts
+
+.ifdef DEBUG
+; write to screen memory on 2nd line:
+; pos 0: # of accesses without buffering
+; pos 1: # of accesses with buffering
+CIO_buf_noti:
+        php
+        pha
+        tya
+        pha
+        bcc     @nobuf
+
+        inc     CIObnval_dobuf
+        jmp     @cont
+
+@nobuf: inc     CIObnval_nobuf
+
+@cont:  ldy     #40
+        lda     CIObnval_nobuf
+        sta     (SAVMSC),y
+        ldy     #41
+        lda     CIObnval_dobuf
+        sta     (SAVMSC),y
+
+        pla
+        tay
+        pla
+        plp
+        rts
+
+CIObnval_dobuf:
+        .byte   0
+CIObnval_nobuf:
+        .byte   0
+.endif
+
+.endif  ; .if CHKBUF
 
 ;---------------------------------------------------------
 
-my_SIOV:
-       pha
-       lda     PORTB
-       sta     cur_SIOV_PORTB
-       enable_rom
-       pla
-       jsr     SIOV_org
-       php
-       pha
-       lda     cur_SIOV_PORTB
-       sta     PORTB
-       pla
-       plp
-       rts
+; SIO handler
+; We only handle SIO_STAT, SIO_READ, SIO_WRITE, and SIO_WRITEV.
+; These are the only functions used by the runtime library currently.
+; For other function we return NVALID status code.
+
+SIO_handler:
+        lda     DCOMND                  ; get command
+        cmp     #SIO_STAT
+        beq     SIO_stat
+        cmp     #SIO_READ
+        beq     SIO_read
+        cmp     #SIO_WRITE
+        beq     SIO_write
+        cmp     #SIO_WRITEV
+        beq     SIO_write
+
+        ; unhandled command
+        lda     #NVALID
+SIO_err:sta     DSTATS
+        rts
+
+; SIO_STAT is always called with a low buffer (by the runtime)
+SIO_stat:
+        ; fall thru
+
+SIO_call:
+        lda     PORTB
+        sta     cur_SIOV_PORTB
+        enable_rom
+        jsr     SIOV_org
+        php
+        pha
+        disable_rom_val cur_SIOV_PORTB
+        pla
+        plp
+        rts
+
+
+; SIO read handler
+; ----------------
+
+SIO_read:
+
+.if CHKBUF
+        jsr     chk_SIO_buf
+        bcc     SIO_call
+.endif
+
+; we only support transfers <= bounce buffer size
+        jsr     cmp_sio_len_bnc_bufsz
+        bcs     sio_read_len_ok
+
+        lda     #DERROR         ; don't know a better status code for this
+        bne     SIO_err
+
+sio_read_len_ok:
+        lda     DBUFLO
+        sta     zpptr1          ; remember destination buffer address
+        lda     DBUFHI
+        sta     zpptr1+1
+
+        jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
+
+        jsr     SIO_call        ; do the operation
+        pha
+        lda     DSTATS          ; get status
+        bmi     sio_read_ret    ; error
+
+        ; copy data to user buffer
+sio_read_ok:
+        lda     DBYTHI          ; could be 1 for 256 bytes
+        beq     srok1
+        ldy     #0
+        beq     srok2
+srok1:  ldy     DBYTLO
+srok2:  dey
+sio_read_copy:
+        lda     bounce_buffer,y
+        sta     (zpptr1),y
+        dey
+        cpy     #$ff
+        bne     sio_read_copy
+
+sio_read_ret:
+        jsr     orgbuf_to_dbuf
+
+        pla
+        rts                     ; success return
+
+
+; SIO write handler
+; -----------------
+
+SIO_write:
+
+.if CHKBUF
+        jsr     chk_SIO_buf
+        bcc     SIO_call
+.endif
+
+; we only support transfers <= bounce buffer size
+        jsr     cmp_sio_len_bnc_bufsz
+        bcs     sio_write_len_ok
+
+        lda     #DERROR         ; don't know a better status code for this
+        jmp     SIO_err
+
+sio_write_len_ok:
+        lda     DBUFLO
+        sta     zpptr1          ; get source buffer address
+        lda     DBUFHI
+        sta     zpptr1+1
+
+        ; copy data from user buffer to bounce buffer
+        lda     DBYTHI          ; could be 1 for 256 bytes
+        beq     swok1
+        ldy     #0
+        beq     swok2
+swok1:  ldy     DBYTLO
+swok2:  dey
+sio_write_copy:
+        lda     (zpptr1),y
+        sta     bounce_buffer,y
+        dey
+        cpy     #$ff
+        bne     sio_write_copy
+
+        jsr     bncbuf_to_dbuf  ; put bounce buffer address to DBUFLO/DBUFHI
+
+        jsr     SIO_call        ; do the operation
+        pha
+        jsr     orgbuf_to_dbuf
+        pla
+        rts
+
+
+; check if SIO length is larger than bounce buffer size
+; input:   orig_len - length
+; output:         A - destroyed
+;                CF - 0/1 for larger/not larger
+cmp_sio_len_bnc_bufsz:
+        sec
+        lda     #<BUFSZ_SIO
+        sbc     DBYTLO
+        lda     #>BUFSZ_SIO
+        sbc     DBYTHI
+        rts
+
+; put bounce buffer address into DBUFLO/DBUFHI
+; input:   (--)
+; output:  A - destroyed
+bncbuf_to_dbuf:
+        lda     #<bounce_buffer
+        sta     DBUFLO
+        lda     #>bounce_buffer
+        sta     DBUFHI
+        rts
+
+; put original buffer address into DBUFLO/DBUFHI
+; input:   zpptr1 - original pointer
+; output:  A      - destroyed
+orgbuf_to_dbuf:
+        lda     zpptr1
+        sta     DBUFLO
+        lda     zpptr1+1
+        sta     DBUFHI
+        rts
+
+
+.if CHKBUF
+
+; check if a SIO input/output buffer overlaps with ROM area (>= $C000)
+; input: DBUFLO/DBUFHI/DBYTLO/DBYTHI - buffer address and length
+; output:                         CF - 1/0 for overlap/no overlap
+;                                  A - destroyed
+
+chk_SIO_buf:
+        lda     DBUFHI
+        cmp     #$c0
+        bcc     @cont
+@ret:
+.ifdef DEBUG
+        jsr     SIO_buf_noti
+.endif
+        rts
+
+@cont:  lda     DBUFLO
+        clc
+        adc     DBYTLO
+        lda     DBUFHI
+        adc     DBYTHI
+        bcs     @ret            ; ??? wraparound
+        cmp     #$c0
+.ifdef DEBUG
+        jsr     SIO_buf_noti
+.endif
+        rts
+
+.ifdef DEBUG
+; write to screen memory on 2nd line:
+; pos 38: # of accesses without buffering
+; pos 39: # of accesses with buffering
+SIO_buf_noti:
+        php
+        pha
+        tya
+        pha
+        bcc     @nobuf
+
+        inc     SIObnval_dobuf
+        jmp     @cont
+
+@nobuf: inc     SIObnval_nobuf
+
+@cont:  ldy     #78
+        lda     SIObnval_nobuf
+        sta     (SAVMSC),y
+        ldy     #79
+        lda     SIObnval_dobuf
+        sta     (SAVMSC),y
+
+        pla
+        tay
+        pla
+        plp
+        rts
+
+SIObnval_dobuf:
+        .byte   0
+SIObnval_nobuf:
+        .byte   0
+.endif
+
+.endif  ; .if CHKBUF
 
 ;---------------------------------------------------------
 
-KEYBDV_wrapper:
+KEYBDV_handler:
 
-       lda     #>(kret-1)
-       pha
-       lda     #<(kret-1)
-       pha
-       lda     PORTB
-       sta     cur_KEYBDV_PORTB
-       enable_rom
-       lda     KEYBDV+5
+        lda     #>(kret-1)
+        pha
+        lda     #<(kret-1)
+        pha
+        lda     PORTB
+        sta     cur_KEYBDV_PORTB
+        enable_rom
+        lda     KEYBDV+5
         pha
         lda     KEYBDV+4
         pha
-       rts             ; call keyboard handler
-kret:  pha
-       lda     cur_KEYBDV_PORTB
-       sta     PORTB
-       pla
-       rts
-
-CIO_a:                 .res    1
-CIO_x:                 .res    1
-CIO_y:                 .res    1
-CIO_p:                 .res    1
-cur_CIOV_PORTB:                .res    1
-cur_SIOV_PORTB:                .res    1
-cur_KEYBDV_PORTB:      .res    1
-orig_ptr:              .res    2
-orig_len:              .res    2
-req_len:               .res    2
-retlen:                        .res    2
-
-.endif ; .if .defined(__ATARIXL__)
+        rts             ; call keyboard handler
+kret:   pha
+        disable_rom_val cur_KEYBDV_PORTB
+        pla
+        rts
+
+;---------------------------------------------------------
+
+SETVBV_handler:
+
+        pha
+        lda     PORTB
+        sta     cur_SETVBV_PORTB
+        enable_rom
+        pla
+        jsr     SETVBV_org
+        php
+        pha
+        disable_rom_val cur_SETVBV_PORTB
+        pla
+        plp
+        rts
+
+;---------------------------------------------------------
+
+XMOVE_handler:
+
+        pha
+        lda     PORTB
+        sta     cur_XMOVE_PORTB
+        enable_rom
+        pla
+        jsr     XMOVE_org
+        php
+        pha
+        disable_rom_val cur_XMOVE_PORTB
+        pla
+        plp
+        rts
+
+
+CIO_a:                  .res    1
+CIO_x:                  .res    1
+CIO_y:                  .res    1
+CIO_p:                  .res    1
+cur_CIOV_PORTB:         .res    1
+cur_SIOV_PORTB:         .res    1
+cur_KEYBDV_PORTB:       .res    1
+cur_SETVBV_PORTB:       .res    1
+cur_XMOVE_PORTB:        .res    1
+orig_ptr:               .res    2
+orig_len:               .res    2
+req_len:                .res    2
+retlen:                 .res    2
+
+.endif  ; .ifdef __ATARIXL__