; Christian Groessler, chris@groessler.org, 2013
;
-DEBUG = 1
+;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__
+
+ .export sram_init
+ .export KEYBDV_handler
+ .export CIO_handler
+ .export SIO_handler
+ .export SETVBV_handler
+ .export XMOVE_handler
-.segment "INIT"
+BUFSZ = 128 ; bounce buffer size
+BUFSZ_SIO = 256
-;enable_count: .res 1
+.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
- 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
+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"
; 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:
.ifdef DEBUG
- php
- pha
- tya
- pha
- ldy #0
- lda (SAVMSC),y
- clc
- adc #1
- sta (SAVMSC),y
- pla
- tay
- pla
- plp
+ php
+ pha
+ tya
+ pha
+ ldy #0
+ lda (SAVMSC),y
+ clc
+ adc #1
+ sta (SAVMSC),y
+ pla
+ tay
+ pla
+ plp
.endif
- int_wrap $FFFE
+ int_wrap $FFFE
my_NMI_han:
.ifdef DEBUG
- php
- pha
- tya
- pha
- ldy #39
- lda (SAVMSC),y
- clc
- adc #1
- sta (SAVMSC),y
- pla
- tay
- pla
- plp
+ 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
+ pha
+ txa
+ pha
+ tsx
+ lda $103,x
+ pha
+ plp
+ pla
+ tax
+ pla
+ int_wrap $FFFA
my_RESET_han:
- enable_rom
- jmp ($FFFC)
+ enable_rom
+ jmp ($FFFC)
; System request handlers
; 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
- 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
-
-
-
-CIO_call_a:
- lda CIO_a
+.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
-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
; 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
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
; 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
; 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__