2 ; Atari XL shadow RAM handlers
4 ; Christian Groessler, chris@groessler.org, 2013
9 .if .defined(__ATARIXL__)
12 .include "save_area.inc"
13 .include "zeropage.inc"
14 .import __CHARGEN_START__
17 .export KEYBDV_wrapper
27 lda #>__CHARGEN_START__
44 ; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer
48 ; disable all interrupts
51 stx NMIEN ; disable NMI
56 ; setup interrupt vectors
72 ; setup pointers to CIOV and SIOV wrappers
93 .segment "EXTZP" : zeropage
100 ; bounce buffers for CIO and SIO calls
101 CIO_buffer: .res BUFSZ_CIO
102 SIO_buffer: .res BUFSZ_SIO
111 ; The interrupt handlers don't look at the current state of PORTB and
112 ; unconditionally disable the ROMs on exit.
113 ; Please note that this works, since if the ROMs are enabled we anyway
114 ; aren't being called here because the vectors are pointing to their
115 ; original ROM locations.
117 .macro int_wrap orgvec
166 ; set I bit to interrupted value
184 ; System request handlers
185 ; -----------------------
188 ; for filenames we assume they will fit into our bounce buffer
190 ; one filename, terminated by "invalid character", located at ICBAL/ICBAH
198 jsr CIO_call_a ; call CIO (maybe A isn't needed, then we could call CIO_call)
201 jsr restore_icba ; restore original ICBAL/ICBAH
204 rts ; back to application
207 ; two filenames, terminated and separated by "invalid character", located at ICBAL/ICBAH
238 ; We have buffer pointer and length entries in the IOCB, but their
239 ; usage depends on the function.
240 ; Some functions don't care about any of them (pointer and length),
241 ; and some only use the pointer (like e.g. OPEN), and some use both.
242 ; So we need function specific handlers to correctly deal with
243 ; buffers which are overlapping with the ROM area.
244 ; All input and output registers need to be preserved (I'm not 100%
245 ; sure about Y as input, but let's preserve it for now.)
247 ; FIXME: Currently only the requests used by the runtime lib are handled.
251 ; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
257 lda ICCOM,x ; get function
259 beq CIO_filename ; filename as input parameter in buffer, length not used
261 bcc CIO_read ; input (GETREC or GETCHR)
263 bcc CIO_write_jmp ; output (PUTREC or PUTCHR)
264 beq CIO_call_a ; pass through, buffer not used
265 cmp #RENAME ; 2 filenames as input parameters in buffer, length not used
268 bcc CIO_filename ; filename as input parameter in buffer, length not used
270 bcs CIO_call_a ; other commands: assume no buffer
283 beq CIO_call_a ; special I/O through A register in case buffer length is 0
285 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
287 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
288 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
290 lda ICBLH,x ; get high byte of length
291 bne big_read ; not zero -> data too large for our buffers
292 ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
297 ; Data size fits into bounce buffer
301 jsr CIO_call_a ; call CIO
310 rts ; return with error
316 jsr copy_to_user ; copy data into user buffer
322 rts ; return with success
324 ; Data size does not fit into bounce buffer
328 sta retlen ; initialize return length
330 jsr iocblen_to_orig_len
331 jsr iocbptr_to_orig_ptr
333 jsr ciobuf_to_iocb ; let ICBAL/ICBAH point to bounce buffer
336 jsr cmp_orig_len_cio_bufsz ; is transfer length > bounce buffer size?
337 bcs br_last ; no, last transfer, use remaining size
340 sta ICBLH,x ; set data length
347 sta ICBLH,x ; set data length
352 sta req_len ; remember length of this request
355 jsr CIO_call_a ; do the request
365 rts ; return with error
383 ; if the request read less bytes than requested, we're done
391 ; update user buffer pointer (zpptr1)
400 ; update remaining length
409 ; still something left to do (remaining length != 0)?
415 ; done, write original buffer pointer and total transfer length to IOCB and return to application
421 jsr orig_ptr_to_iocbptr
427 rts ; return with success
443 beq CIO_call_a_jmp ; special I/O through A register in case buffer length is 0
445 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
447 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
448 ; Otherwise we can get away with a copy to the bounce buffer and the call.
450 lda ICBLH,x ; get high byte of length
451 bne big_write ; not zero -> data too large for our buffers
452 ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
458 ; Data size fits into bounce buffer
470 rts ; return to application
473 ; Data size does not fit into bounce buffer
477 sta retlen ; initialize return length
479 jsr iocblen_to_orig_len
480 jsr iocbptr_to_orig_ptr
482 jsr ciobuf_to_iocb ; let ICBAL/ICBAH point to bounce buffer
485 jsr cmp_orig_len_cio_bufsz ; is transfer length > bounce buffer size?
486 bcs bw_last ; no, last transfer, use remaining size
489 sta ICBLH,x ; set data length
496 sta ICBLH,x ; set data length
501 sta req_len ; remember length of this request
505 jsr CIO_call_a ; do the request
527 ; if the request wrote less bytes than requested, we're done
535 ; update user buffer pointer (zpptr1)
544 ; update remaining length
553 ; still something left to do (remaining length != 0)?
564 jsr orig_ptr_to_iocbptr
570 rts ; return with success
574 ; check if length is larger than bounce buffer size
575 ; input: orig_len - length
576 ; output: A - destroyed
577 ; CF - 0/1 for larger/not larger
578 cmp_orig_len_cio_bufsz:
587 ; copy data from bounce buffer into user buffer
588 ; input: X - IOCB index
589 ; zpptr1 - pointer to user buffer
590 ; output: A - destroyed
593 ldy ICBLL,x ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
604 ; copy data from user buffer into bounce buffer
605 ; input: X - IOCB index
606 ; zpptr1 - pointer to user buffer
607 ; output: A - destroyed
610 ldy ICBLL,x ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
621 ; copy ICBLL/ICBLH to 'orig_len'
622 ; input: X - IOCB index
623 ; output: A - destroyed
632 ; copy ICBAL/ICBAH to 'orig_ptr'
633 ; input: X - IOCB index
634 ; output: A - destroyed
643 ; copy 'orig_ptr' to ICBAL/ICBAH
644 ; input: X - IOCB index
645 ; output: A - destroyed
654 ; restore original contents of ICBAL/ICBAH from 'zpptr1'
655 ; input: X - IOCB index
656 ; output: A - destroyed
665 ; put bounce buffer address into ICBAL/ICBAH
666 ; input: X - IOCB index
667 ; output: A - destroyed
676 ; copy file name pointed to by 'zpptr1' to bounce buffer 'CIO_buffer'
677 ; input: Y - index into file name buffer and CIO_buffer
678 ; output: Y - points to first invalid byte after file name
692 ; write IOCB buffer address into zpptr1
693 ; input: X - IOCB index
694 ; output: Y - 0 (for setup_zpptr1_y0, else unchanged)
699 lda ICBAL,x ; put buffer address into zp pointer
705 ;---------------------------------------------------------
722 ;---------------------------------------------------------
737 rts ; call keyboard handler
748 cur_CIOV_PORTB: .res 1
749 cur_SIOV_PORTB: .res 1
750 cur_KEYBDV_PORTB: .res 1
756 .endif ; .if .defined(__ATARIXL__)