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.
245 ; FIXME: Currently only the requests used by the runtime lib are handled.
249 ; @@@ TODO: check X for valid IOCB index ((X < $80) and ((X & $F) == 0))
255 lda ICCOM,x ; get function
257 beq CIO_filename ; filename as input parameter in buffer, length not used
259 bcc CIO_read ; input (GETREC or GETCHR)
261 bcc CIO_write_jmp ; output (PUTREC or PUTCHR)
262 beq CIO_call_a ; pass through, buffer not used
263 cmp #RENAME ; 2 filenames as input parameters in buffer, length not used
266 bcc CIO_filename ; filename as input parameter in buffer, length not used
267 beq CIO_invalid ; GETCWD not supported yet
268 bcs CIO_call_a ; other commands: assume no buffer
285 beq CIO_call_a ; special I/O through A register in case buffer length is 0
287 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
289 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
290 ; Otherwise we can get away with one call and a copy to the final destination afterwards.
292 lda ICBLH,x ; get high byte of length
293 bne big_read ; not zero -> data too large for our buffers
294 ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
299 ; Data size fits into bounce buffer
303 jsr CIO_call_a ; call CIO
312 rts ; return with error
318 jsr copy_to_user ; copy data into user buffer
324 rts ; return with success
326 ; Data size does not fit into bounce buffer
330 sta retlen ; initialize return length
332 jsr iocblen_to_orig_len
333 jsr iocbptr_to_orig_ptr
335 jsr ciobuf_to_iocb ; let ICBAL/ICBAH point to bounce buffer
338 jsr cmp_orig_len_cio_bufsz ; is transfer length > bounce buffer size?
339 bcs br_last ; no, last transfer, use remaining size
342 sta ICBLH,x ; set data length
349 sta ICBLH,x ; set data length
354 sta req_len ; remember length of this request
357 jsr CIO_call_a ; do the request
367 rts ; return with error
385 ; if the request read less bytes than requested, we're done
393 ; update user buffer pointer (zpptr1)
402 ; update remaining length
411 ; still something left to do (remaining length != 0)?
417 ; done, write original buffer pointer and total transfer length to IOCB and return to application
423 jsr orig_ptr_to_iocbptr
429 rts ; return with success
445 beq CIO_call_a_jmp ; special I/O through A register in case buffer length is 0
447 ; @@@ TODO: check if bounce buffer is really needed because buffer is in ROM area
449 ; If the data length is larger than our bounce buffer, we have to split the request into smaller ones.
450 ; Otherwise we can get away with a copy to the bounce buffer and the call.
452 lda ICBLH,x ; get high byte of length
453 bne big_write ; not zero -> data too large for our buffers
454 ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES
460 ; Data size fits into bounce buffer
472 rts ; return to application
475 ; Data size does not fit into bounce buffer
479 sta retlen ; initialize return length
481 jsr iocblen_to_orig_len
482 jsr iocbptr_to_orig_ptr
484 jsr ciobuf_to_iocb ; let ICBAL/ICBAH point to bounce buffer
487 jsr cmp_orig_len_cio_bufsz ; is transfer length > bounce buffer size?
488 bcs bw_last ; no, last transfer, use remaining size
491 sta ICBLH,x ; set data length
498 sta ICBLH,x ; set data length
503 sta req_len ; remember length of this request
507 jsr CIO_call_a ; do the request
529 ; if the request wrote less bytes than requested, we're done
537 ; update user buffer pointer (zpptr1)
546 ; update remaining length
555 ; still something left to do (remaining length != 0)?
566 jsr orig_ptr_to_iocbptr
572 rts ; return with success
576 ; check if length is larger than bounce buffer size
577 ; input: orig_len - length
578 ; output: A - destroyed
579 ; CF - 0/1 for larger/not larger
580 cmp_orig_len_cio_bufsz:
589 ; copy data from bounce buffer into user buffer
590 ; input: X - IOCB index
591 ; zpptr1 - pointer to user buffer
592 ; output: A - destroyed
595 ldy ICBLL,x ; get # of bytes read (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
606 ; copy data from user buffer into bounce buffer
607 ; input: X - IOCB index
608 ; zpptr1 - pointer to user buffer
609 ; output: A - destroyed
612 ldy ICBLL,x ; get # of bytes to write (CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES)
623 ; copy ICBLL/ICBLH to 'orig_len'
624 ; input: X - IOCB index
625 ; output: A - destroyed
634 ; copy ICBAL/ICBAH to 'orig_ptr'
635 ; input: X - IOCB index
636 ; output: A - destroyed
645 ; copy 'orig_ptr' to ICBAL/ICBAH
646 ; input: X - IOCB index
647 ; output: A - destroyed
656 ; restore original contents of ICBAL/ICBAH from 'zpptr1'
657 ; input: X - IOCB index
658 ; output: A - destroyed
667 ; put bounce buffer address into ICBAL/ICBAH
668 ; input: X - IOCB index
669 ; output: A - destroyed
678 ; copy file name pointed to by 'zpptr1' to bounce buffer 'CIO_buffer'
679 ; input: Y - index into file name buffer and CIO_buffer
680 ; output: Y - points to first invalid byte after file name
694 ; write IOCB buffer address into zpptr1
695 ; input: X - IOCB index
696 ; output: Y - 0 (for setup_zpptr1_y0, else unchanged)
701 lda ICBAL,x ; put buffer address into zp pointer
707 ;---------------------------------------------------------
724 ;---------------------------------------------------------
739 rts ; call keyboard handler
750 cur_CIOV_PORTB: .res 1
751 cur_SIOV_PORTB: .res 1
752 cur_KEYBDV_PORTB: .res 1
758 .endif ; .if .defined(__ATARIXL__)