2 ; Atari XL shadow RAM handlers
4 ; Christian Groessler, chris@groessler.org, 2013
9 .if .defined(__ATARIXL__)
13 .include "save_area.inc"
14 .include "zeropage.inc"
15 .import __CHARGEN_START__
18 .export KEYBDV_handler
21 .export SETVBV_handler
23 BUFSZ = 128 ; bounce buffer size
30 lda #>__CHARGEN_START__
45 ; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer
49 ; disable all interrupts
52 stx NMIEN ; disable NMI
57 ; setup interrupt vectors
80 .segment "EXTZP" : zeropage
87 ; bounce buffers for CIO and SIO calls
88 bounce_buffer: .res BUFSZ_SIO
97 ; The interrupt handlers don't look at the current state of PORTB and
98 ; unconditionally disable the ROMs on exit.
99 ; Please note that this works, since if the ROMs are enabled we anyway
100 ; aren't being called here because the vectors are pointing to their
101 ; original ROM locations.
103 .macro int_wrap orgvec
152 ; set I bit to interrupted value
170 ; System request handlers
171 ; -----------------------
174 ; for filenames we assume they will fit into our bounce buffer
176 ; one filename, terminated by "invalid character", located at ICBAL/ICBAH
184 jsr CIO_call_a ; call CIO (maybe A isn't needed, then we could call CIO_call)
187 jsr restore_icba ; restore original ICBAL/ICBAH
190 rts ; back to application
193 ; two filenames, terminated and separated by "invalid character", located at ICBAL/ICBAH
203 ; enable ROM, call CIO, disable ROM
225 ; We have buffer pointer and length entries in the IOCB, but their
226 ; usage depends on the function.
227 ; Some functions don't care about any of them (pointer and length),
228 ; and some only use the pointer (like e.g. OPEN), and some use both.
229 ; So we need function specific handlers to correctly deal with
230 ; buffers which are overlapping with the ROM area.
232 ; FIXME: Currently only the requests used by the runtime lib are handled.
236 ; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
242 lda ICCOM,x ; get function
244 beq CIO_filename ; filename as input parameter in buffer, length not used
246 bcc CIO_read ; input (GETREC or GETCHR)
248 bcc CIO_write_jmp ; output (PUTREC or PUTCHR)
249 beq CIO_call_a ; pass through, buffer not used
250 cmp #RENAME ; 2 filenames as input parameters in buffer, length not used
253 bcc CIO_filename ; filename as input parameter in buffer, length not used
254 beq CIO_invalid ; GETCWD not supported yet
255 bcs CIO_call_a ; other commands: assume no buffer
272 beq CIO_call_a ; special I/O through A register in case buffer length is 0
274 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
276 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
277 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
279 lda ICBLH,x ; get high byte of length
280 bne big_read ; not zero -> data too large for our buffers
281 ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
286 ; Data size fits into bounce buffer
290 jsr CIO_call_a ; call CIO
299 rts ; return with error
305 jsr copy_to_user ; copy data into user buffer
311 rts ; return with success
313 ; Data size does not fit into bounce buffer
317 sta retlen ; initialize return length
319 jsr iocblen_to_orig_len
320 jsr iocbptr_to_orig_ptr
322 jsr bncbuf_to_iocb ; let ICBAL/ICBAH point to bounce buffer
325 jsr cmp_orig_len_bnc_bufsz ; is transfer length > bounce buffer size?
326 bcs br_last ; no, last transfer, use remaining size
329 sta ICBLH,x ; set data length
336 sta ICBLH,x ; set data length
341 sta req_len ; remember length of this request
344 jsr CIO_call_a ; do the request
354 rts ; return with error
372 ; if the request read less bytes than requested, we're done
380 ; update user buffer pointer (zpptr1)
389 ; update remaining length
398 ; still something left to do (remaining length != 0)?
404 ; done, write original buffer pointer and total transfer length to IOCB and return to application
410 jsr orig_ptr_to_iocbptr
416 rts ; return with success
432 beq CIO_call_a_jmp ; special I/O through A register in case buffer length is 0
434 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
436 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
437 ; Otherwise we can get away with a copy to the bounce buffer and the call.
439 lda ICBLH,x ; get high byte of length
440 bne big_write ; not zero -> data too large for our buffers
441 ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
447 ; Data size fits into bounce buffer
459 rts ; return to application
462 ; Data size does not fit into bounce buffer
466 sta retlen ; initialize return length
468 jsr iocblen_to_orig_len
469 jsr iocbptr_to_orig_ptr
471 jsr bncbuf_to_iocb ; let ICBAL/ICBAH point to bounce buffer
474 jsr cmp_orig_len_bnc_bufsz ; is transfer length > bounce buffer size?
475 bcs bw_last ; no, last transfer, use remaining size
478 sta ICBLH,x ; set data length
485 sta ICBLH,x ; set data length
490 sta req_len ; remember length of this request
494 jsr CIO_call_a ; do the request
516 ; if the request wrote less bytes than requested, we're done
524 ; update user buffer pointer (zpptr1)
533 ; update remaining length
542 ; still something left to do (remaining length != 0)?
553 jsr orig_ptr_to_iocbptr
559 rts ; return with success
563 ; check if length is larger than bounce buffer size
564 ; input: orig_len - length
565 ; output: A - destroyed
566 ; CF - 0/1 for larger/not larger
567 cmp_orig_len_bnc_bufsz:
576 ; copy data from bounce buffer into user buffer
577 ; input: X - IOCB index
578 ; zpptr1 - pointer to user buffer
579 ; output: A - destroyed
582 ldy ICBLL,x ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
593 ; copy data from user buffer into bounce buffer
594 ; input: X - IOCB index
595 ; zpptr1 - pointer to user buffer
596 ; output: A - destroyed
599 ldy ICBLL,x ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
610 ; copy ICBLL/ICBLH to 'orig_len'
611 ; input: X - IOCB index
612 ; output: A - destroyed
621 ; copy ICBAL/ICBAH to 'orig_ptr'
622 ; input: X - IOCB index
623 ; output: A - destroyed
632 ; copy 'orig_ptr' to ICBAL/ICBAH
633 ; input: X - IOCB index
634 ; output: A - destroyed
643 ; restore original contents of ICBAL/ICBAH from 'zpptr1'
644 ; input: X - IOCB index
645 ; output: A - destroyed
654 ; put bounce buffer address into ICBAL/ICBAH
655 ; input: X - IOCB index
656 ; output: A - destroyed
665 ; copy file name pointed to by 'zpptr1' to 'bounce_buffer'
666 ; input: Y - index into file name buffer and bounce_buffer
667 ; output: Y - points to first invalid byte after file name
681 ; write IOCB buffer address into zpptr1
682 ; input: X - IOCB index
683 ; output: Y - 0 (for setup_zpptr1_y0, else unchanged)
688 lda ICBAL,x ; put buffer address into zp pointer
694 ;---------------------------------------------------------
697 ; We only handle SIO_STAT, SIO_READ, SIO_WRITE, and SIO_WRITEV.
698 ; These are the only functions used by the runtime library currently.
699 ; For other function we return NVALID status code.
702 lda DCOMND ; get command
717 ; SIO_STAT is always called with a low buffer (by the runtime)
740 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
742 ; we only support transfers <= bounce buffer size
743 jsr cmp_sio_len_bnc_bufsz
746 lda #DERROR ; don't know a better status code for this
751 sta zpptr1 ; remember destination buffer address
755 jsr bncbuf_to_dbuf ; put bounce buffer address to DBUFLO/DBUFHI
757 jsr SIO_call ; do the operation
759 lda DSTATS ; get status
760 bmi sio_read_ret ; error
762 ; copy data to user buffer
764 lda DBYTHI ; could be 1 for 256 bytes
789 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
791 ; we only support transfers <= bounce buffer size
792 jsr cmp_sio_len_bnc_bufsz
795 lda #DERROR ; don't know a better status code for this
800 sta zpptr1 ; get source buffer address
804 ; copy data from user buffer to bounce buffer
805 lda DBYTHI ; could be 1 for 256 bytes
818 jsr bncbuf_to_dbuf ; put bounce buffer address to DBUFLO/DBUFHI
820 jsr SIO_call ; do the operation
827 ; check if SIO length is larger than bounce buffer size
828 ; input: orig_len - length
829 ; output: A - destroyed
830 ; CF - 0/1 for larger/not larger
831 cmp_sio_len_bnc_bufsz:
839 ; put bounce buffer address into DBUFLO/DBUFHI
841 ; output: A - destroyed
849 ; put original buffer address into DBUFLO/DBUFHI
850 ; input: zpptr1 - original pointer
851 ; output: A - destroyed
860 ;---------------------------------------------------------
875 rts ; call keyboard handler
882 ;---------------------------------------------------------
904 cur_CIOV_PORTB: .res 1
905 cur_SIOV_PORTB: .res 1
906 cur_KEYBDV_PORTB: .res 1
907 cur_SETVBV_PORTB: .res 1
913 .endif ; .if .defined(__ATARIXL__)