.include "atari.inc"
.include "save_area.inc"
+ .include "zeropage.inc"
.import __CHARGEN_START__
.export sram_init
BUFSZ_SIO = BUFSZ
.macro disable_rom
- .local cont
- ;dec enable_count
- ;bne cont
lda PORTB
and #$fe
sta PORTB
lda #>__CHARGEN_START__
sta CHBAS
sta CHBASE
-cont:
.endmacro
.macro enable_rom
- ;inc enable_count
lda PORTB
ora #1
sta PORTB
.segment "INIT"
-enable_count: .res 1
+;enable_count: .res 1
; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer
; disable ROMs
;inx
- stx enable_count
+ ;stx enable_count
disable_rom
; setup interrupt vectors
rts
+.segment "EXTZP" : zeropage
+
+zpptr1: .res 2
+zpptr2: .res 2
+
.segment "LOWBUFS"
; bounce buffers for CIO and SIO calls
-CIOV_buffer: .res BUFSZ_CIO
-SIOV_buffer: .res BUFSZ_SIO
+CIO_buffer: .res BUFSZ_CIO
+SIO_buffer: .res BUFSZ_SIO
.segment "LOWCODE"
+
; Interrupt handlers
; ------------------
; System request handlers
; -----------------------
+
+; for filenames we assume they will fit into our bounce buffer
+
+; one filename, terminated by "invalid character", located at ICBAL/ICBAH
+
+CIO_filename:
+ 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
+
+
+; 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
+
+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_write:
+ lda ICBLL,x
+ ora ICBLH,x
+ beq CIO_call_a ; special I/O through A register in case buffer length is 0
+
+ ;...
+ bne CIO_call_a
+
+
; CIO handler
; We have buffer pointer and length entries in the IOCB, but their
; usage depends on the function.
-; Some functions don't care about both (pointer and length), and some
-; only use the pointer (like e.g. OPEN), and some use both.
+; Some functions don't care about any of them (pointer and length),
+; 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, but let's preserve it for now.)
+; 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:
+ ;jmp CIOV_call
+ ;brk
+
; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
sta CIO_a
bcc CIO_read ; input (GETREC or GETCHR)
cmp #CLOSE
bcc CIO_write ; output (PUTREC or PUTCHR)
- beq CIO_pass ; pass through, buffer not used
+ 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 parameter in buffer, length not used
+ cmp #GETCWD
+ bcc CIO_filename ; filename as input parameter in buffer, length not used
beq CIO_read ; input
- bcs CIO_pass ; other command: assume no buffers
+ bcs CIO_call_a ; other commands: assume no buffer
+; not reached
+
+CIO_read:
+ lda ICBLL,x
+ ora ICBLH,x
+ beq CIO_call_a ; special I/O through A register in case buffer length is 0
+
+; 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
-.if 0 ; all crap
-; check if buffer is potentially used (buffer length != 0)
+; 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
- lda ICBLL,x
- ora ICBLH,x
- bne could_be
+ jsr restore_icba
pla
- jmp CIOV_call
+ plp
+ rts ; return with error
+
+no_err:
+ sta CIO_a
+ sty CIO_y
+
+ jsr copy_to_user ; copy data into user buffer
+ jsr restore_icba
+
+ 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
+
+br_loop:
+ jsr cmp_orig_len_cio_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
+
+br_last:
+ 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
-; buffer might be used by the request
+br_no_err:
+ 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
+
+; 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
+
+; update user buffer pointer (zpptr1)
+ 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
+
+; still something left to do (remaining length != 0)?
+ 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
-could_be:
-; check if buffer is inside ROM area
+; check if length is larger than bounce buffer size
+; 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
+
+
+; copy data from bounce buffer into user buffer
+; input: X - IOCB index
+; zpptr1 - pointer to user buffer
+; output: A - destroyed
+; 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
+copy_done:
+ 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
+
+
+; 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
- cmp #$C0 ; if buffer is above $C000, it's definitely inside ROM area
- bcs need_work
+ sta orig_ptr+1
+ rts
- lda ICBAL,x ; low byte of buffer address
- adc ICBLL,x ; low byte of buffer length
- lda ICBAH,x ; high byte (address)
- adc ICBLH,x ; high byte (length)
- cmp #$C0
- bcc CIOV_call ; no need to use bounce buffers, just forward call to CIO
-need_work:
+; 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
-; Check if length is bigger than the size of our bounce buffer.
-; If yes, we need to split the call into multiple calls.
-; @@@ FIXME: currently only supports bounce buffers < 256 bytes
- lda ICBLH,x ; high byte of length
- bne hard_work
- lda ICBLL,x ; low byte of length
- cmp #<BUFSZ_CIO
- beq little_work
- bcs hard_work
+; 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
-; Request buffer is smaller or equal to our bounce buffer.
-; Copy the data into the bounce buffer, set bounce buffer address
-; in the IOCB, call CIO, and copy the output data back.
-; @@@ TODO: check for read/write and do only one of the copy operations
-little_work:
+; 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
-; Request buffer is larger than our bounce buffer.
-hard_work:
+; copy file name pointed to by 'zpptr1' to bounce buffer 'CIO_buffer'
+; input: Y - index into file name buffer and CIO_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
+copy_fn_done:
+ rts
-.endif ; crap alert
-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
+; write IOCB buffer address into zpptr1
+; input: X - IOCB index
+; output: Y - 0 (for setup_zpptr1_y0, else unchanged)
+; A - destroyed
+setup_zpptr1_y0:
+ ldy #0
+setup_zpptr1:
+ lda ICBAL,x ; put buffer address into zp pointer
+ sta zpptr1
+ lda ICBAH,x
+ sta zpptr1+1
rts
+;---------------------------------------------------------
my_SIOV:
pha
plp
rts
+;---------------------------------------------------------
KEYBDV_wrapper:
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__)