diff --git a/asminc/atari.inc b/asminc/atari.inc index d976d6475..c60f6642d 100644 --- a/asminc/atari.inc +++ b/asminc/atari.inc @@ -1002,9 +1002,21 @@ CASETV = $E440 ;cassette handler vector table DISKIV = $E450 ;vector to initialize DIO DSKINV = $E453 ;vector to DIO +.ifdef __ATARIXL__ +.ifndef SHRAM_HANDLERS +.import CIO_handler, SIO_handler, SETVBV_handler +.endif +.define CIOV CIO_handler +.define SIOV SIO_handler +.define SETVBV SETVBV_handler +CIOV_org = $E456 ;vector to CIO +SIOV_org = $E459 ;vector to SIO +SETVBV_org = $E45C ;vector to set VBLANK parameters +.else CIOV = $E456 ;vector to CIO SIOV = $E459 ;vector to SIO SETVBV = $E45C ;vector to set VBLANK parameters +.endif SYSVBV = $E45F ;vector to process immediate VBLANK XITVBV = $E462 ;vector to process deferred VBLANK SIOINV = $E465 ;vector to initialize SIO diff --git a/cfg/atarixl-largehimem.cfg b/cfg/atarixl-largehimem.cfg new file mode 100644 index 000000000..d34494772 --- /dev/null +++ b/cfg/atarixl-largehimem.cfg @@ -0,0 +1,91 @@ +# This config file provides a single big upper memory block (HIDDEN_RAM). +# To achieve this, it relocates the character generator from $E000 to CHARGEN. +# The runtime library must be compiled with CHARGEN_RELOC for this config +# file to work. See libsrc/atari/Makefile.inc. + +FEATURES { + STARTADDRESS: default = $2400; +} + +SYMBOLS { + __STACKSIZE__: type = weak, value = $0800; # 2k stack + __STARTADDRESS__: type = export, value = %S; + syschk: type = import; # force inclusion of SYSCHK + sramprep: type = import; # force inclusion of SRPREP +} + +MEMORY { + ZP: file = "", define = yes, start = $0082, size = $007E; + +# just $FFFF + HEADER: file = %O, start = $0000, size = $0002; + +# "system check" load chunk + SYSCHKHDR: file = %O, start = $0000, size = $0004; + SYSCHKCHNK: file = %O, start = $2E00, size = $0300; + SYSCHKTRL: file = %O, start = $0000, size = $0006; + +# "shadow RAM preparation" load chunk + SRPREPHDR: file = %O, start = $0000, size = $0004; + SRPREPCHNK: file = %O, define = yes, start = %S, size = $7C20 - %S - $07FF; # $07FF: space for temp. chargen buffer, 1K aligned + SRPREPTRL: file = %O, start = $0000, size = $0006; + +# "main program" load chunk + MAINHDR: file = %O, start = $0000, size = $0004; + RAM: file = %O, define = yes, start = %S + + __LOWDATA_SIZE__, size = $D000 - + __STACKSIZE__ - + %S - + __LOWDATA_SIZE__; + +# defines entry point into program + TRAILER: file = %O, start = $0000, size = $0006; + +# address of relocated character generator + CHARGEN: file = "", define = yes, start = $D800, size = $0400; + +# memory beneath the ROM + HIDDEN_RAM: file = "", define = yes, start = $DC00, size = $FFF0 - $DC00; +} + +SEGMENTS { + EXEHDR: load = HEADER, type = ro; + + SYSCHKHDR: load = SYSCHKHDR, type = ro, optional = yes; + SYSCHK: load = SYSCHKCHNK, type = rw, define = yes, optional = yes; + SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; + + SRPREPHDR: load = SRPREPHDR, type = ro; + LOWDATA: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREP and RAM + SRPREP: load = SRPREPCHNK, type = rw, define = yes; + SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; + SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; + SRPREPTRL: load = SRPREPTRL, type = ro; + + MAINHDR: load = MAINHDR, type = ro; + STARTUP: load = RAM, type = ro, define = yes; + LOWCODE: load = RAM, type = ro, define = yes, optional = yes; + INIT: load = RAM, type = ro, optional = yes; + CODE: load = RAM, type = ro, define = yes; + RODATA: load = RAM, type = ro; + DATA: load = RAM, type = rw; + BSS: load = RAM, type = bss, define = yes; + ZEROPAGE: load = ZP, type = zp; + EXTZP: load = ZP, type = zp, optional = yes; + AUTOSTRT: load = TRAILER, type = ro; +} +FEATURES { + CONDES: type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__, + segment = INIT; + CONDES: type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__, + segment = RODATA; + CONDES: type = interruptor, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__, + segment = RODATA, + import = __CALLIRQ__; +} diff --git a/cfg/atarixl-overlay.cfg b/cfg/atarixl-overlay.cfg index 02becd29b..a07d8b27a 100644 --- a/cfg/atarixl-overlay.cfg +++ b/cfg/atarixl-overlay.cfg @@ -1,48 +1,100 @@ FEATURES { - STARTADDRESS: default = $2E00; + STARTADDRESS: default = $2400; } + SYMBOLS { __STACKSIZE__: type = weak, value = $0800; # 2k stack __OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay - __RESERVED_MEMORY__: type = weak, value = $0000; + __STARTADDRESS__: type = export, value = %S; + syschk: type = import; # force inclusion of SYSCHK + sramprep: type = import; # force inclusion of SRPREP } + MEMORY { - ZP: file = "", define = yes, start = $0082, size = $007E; - HEADER: file = %O, start = $0000, size = $0006; - RAM: file = %O, start = %S + __OVERLAYSIZE__, size = $BC20 - __STACKSIZE__ - __OVERLAYSIZE__ - %S; - TRAILER: file = %O, start = $0000, size = $0006; - OVL1: file = "%O.1", start = %S, size = __OVERLAYSIZE__; - OVL2: file = "%O.2", start = %S, size = __OVERLAYSIZE__; - OVL3: file = "%O.3", start = %S, size = __OVERLAYSIZE__; - OVL4: file = "%O.4", start = %S, size = __OVERLAYSIZE__; - OVL5: file = "%O.5", start = %S, size = __OVERLAYSIZE__; - OVL6: file = "%O.6", start = %S, size = __OVERLAYSIZE__; - OVL7: file = "%O.7", start = %S, size = __OVERLAYSIZE__; - OVL8: file = "%O.8", start = %S, size = __OVERLAYSIZE__; - OVL9: file = "%O.9", start = %S, size = __OVERLAYSIZE__; + ZP: file = "", define = yes, start = $0082, size = $007E; + +# just $FFFF + HEADER: file = %O, start = $0000, size = $0002; + +# "system check" load chunk + SYSCHKHDR: file = %O, start = $0000, size = $0004; + SYSCHKCHNK: file = %O, start = $2E00, size = $0300; + SYSCHKTRL: file = %O, start = $0000, size = $0006; + +# "shadow RAM preparation" load chunk + SRPREPHDR: file = %O, start = $0000, size = $0004; + SRPREPCHNK: file = %O, define = yes, start = %S + __OVERLAYSIZE__, size = $7C20 - %S - __OVERLAYSIZE__ - $07FF; # $07FF: space for temp. chargen buffer, 1K aligned + SRPREPTRL: file = %O, start = $0000, size = $0006; + +# "main program" load chunk + MAINHDR: file = %O, start = $0000, size = $0004; + RAM: file = %O, define = yes, start = %S + + __OVERLAYSIZE__ + + __LOWDATA_SIZE__, size = $D000 - + __STACKSIZE__ - + %S - + __OVERLAYSIZE__ - + __LOWDATA_SIZE__; + +# defines entry point into program + TRAILER: file = %O, start = $0000, size = $0006; + +# memory beneath the ROM preceeding the character generator + HIDDEN_RAM2: file = "", define = yes, start = $D800, size = $0800; + +# address of relocated character generator (same addess as ROM version) + CHARGEN: file = "", define = yes, start = $E000, size = $0400; + +# memory beneath the ROM + HIDDEN_RAM: file = "", define = yes, start = $E400, size = $FFF0 - $E400; + +# overlays + OVL1: file = "%O.1", start = %S, size = __OVERLAYSIZE__; + OVL2: file = "%O.2", start = %S, size = __OVERLAYSIZE__; + OVL3: file = "%O.3", start = %S, size = __OVERLAYSIZE__; + OVL4: file = "%O.4", start = %S, size = __OVERLAYSIZE__; + OVL5: file = "%O.5", start = %S, size = __OVERLAYSIZE__; + OVL6: file = "%O.6", start = %S, size = __OVERLAYSIZE__; + OVL7: file = "%O.7", start = %S, size = __OVERLAYSIZE__; + OVL8: file = "%O.8", start = %S, size = __OVERLAYSIZE__; + OVL9: file = "%O.9", start = %S, size = __OVERLAYSIZE__; } + SEGMENTS { - EXEHDR: load = HEADER, type = ro; - STARTUP: load = RAM, type = ro, define = yes; - LOWCODE: load = RAM, type = ro, define = yes, optional = yes; - INIT: load = RAM, type = ro, optional = yes; - CODE: load = RAM, type = ro, define = yes; - RODATA: load = RAM, type = ro; - DATA: load = RAM, type = rw; - ZPSAVE: load = RAM, type = bss, define = yes; - BSS: load = RAM, type = bss, define = yes; - ZEROPAGE: load = ZP, type = zp; - EXTZP: load = ZP, type = zp, optional = yes; - AUTOSTRT: load = TRAILER, type = ro; - OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes; - OVERLAY2: load = OVL2, type = ro, define = yes, optional = yes; - OVERLAY3: load = OVL3, type = ro, define = yes, optional = yes; - OVERLAY4: load = OVL4, type = ro, define = yes, optional = yes; - OVERLAY5: load = OVL5, type = ro, define = yes, optional = yes; - OVERLAY6: load = OVL6, type = ro, define = yes, optional = yes; - OVERLAY7: load = OVL7, type = ro, define = yes, optional = yes; - OVERLAY8: load = OVL8, type = ro, define = yes, optional = yes; - OVERLAY9: load = OVL9, type = ro, define = yes, optional = yes; + EXEHDR: load = HEADER, type = ro; + + SYSCHKHDR: load = SYSCHKHDR, type = ro, optional = yes; + SYSCHK: load = SYSCHKCHNK, type = rw, define = yes, optional = yes; + SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; + + SRPREPHDR: load = SRPREPHDR, type = ro; + LOWDATA: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREP and RAM + SRPREP: load = SRPREPCHNK, type = rw, define = yes; + SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; + SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM2, type = rw, define = yes, optional = yes; + SRPREPTRL: load = SRPREPTRL, type = ro; + + MAINHDR: load = MAINHDR, type = ro; + STARTUP: load = RAM, type = ro, define = yes; + LOWCODE: load = RAM, type = ro, define = yes, optional = yes; + INIT: load = RAM, type = ro, optional = yes; + CODE: load = RAM, type = ro, define = yes; + RODATA: load = RAM, type = ro; + DATA: load = RAM, type = rw; + BSS: load = RAM, type = bss, define = yes; + ZEROPAGE: load = ZP, type = zp; + EXTZP: load = ZP, type = zp, optional = yes; + AUTOSTRT: load = TRAILER, type = ro; + + OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes; + OVERLAY2: load = OVL2, type = ro, define = yes, optional = yes; + OVERLAY3: load = OVL3, type = ro, define = yes, optional = yes; + OVERLAY4: load = OVL4, type = ro, define = yes, optional = yes; + OVERLAY5: load = OVL5, type = ro, define = yes, optional = yes; + OVERLAY6: load = OVL6, type = ro, define = yes, optional = yes; + OVERLAY7: load = OVL7, type = ro, define = yes, optional = yes; + OVERLAY8: load = OVL8, type = ro, define = yes, optional = yes; + OVERLAY9: load = OVL9, type = ro, define = yes, optional = yes; } FEATURES { CONDES: type = constructor, diff --git a/cfg/atarixl.cfg b/cfg/atarixl.cfg index a82f64f74..55a14a5e0 100644 --- a/cfg/atarixl.cfg +++ b/cfg/atarixl.cfg @@ -1,28 +1,76 @@ FEATURES { - STARTADDRESS: default = $2E00; + STARTADDRESS: default = $2400; } + SYMBOLS { __STACKSIZE__: type = weak, value = $0800; # 2k stack - __RESERVED_MEMORY__: type = weak, value = $0000; + __STARTADDRESS__: type = export, value = %S; + syschk: type = import; # force inclusion of SYSCHK + sramprep: type = import; # force inclusion of SRPREP } + MEMORY { - ZP: file = "", define = yes, start = $0082, size = $007E; - HEADER: file = %O, start = $0000, size = $0006; - RAM: file = %O, start = %S, size = $BC20 - __STACKSIZE__ - %S; - TRAILER: file = %O, start = $0000, size = $0006; + ZP: file = "", define = yes, start = $0082, size = $007E; + +# just $FFFF + HEADER: file = %O, start = $0000, size = $0002; + +# "system check" load chunk + SYSCHKHDR: file = %O, start = $0000, size = $0004; + SYSCHKCHNK: file = %O, start = $2E00, size = $0300; + SYSCHKTRL: file = %O, start = $0000, size = $0006; + +# "shadow RAM preparation" load chunk + SRPREPHDR: file = %O, start = $0000, size = $0004; + SRPREPCHNK: file = %O, define = yes, start = %S, size = $7C20 - %S - $07FF; # $07FF: space for temp. chargen buffer, 1K aligned + SRPREPTRL: file = %O, start = $0000, size = $0006; + +# "main program" load chunk + MAINHDR: file = %O, start = $0000, size = $0004; + RAM: file = %O, define = yes, start = %S + + __LOWDATA_SIZE__, size = $D000 - + __STACKSIZE__ - + %S - + __LOWDATA_SIZE__; + +# defines entry point into program + TRAILER: file = %O, start = $0000, size = $0006; + +# memory beneath the ROM preceeding the character generator + HIDDEN_RAM2: file = "", define = yes, start = $D800, size = $0800; + +# address of relocated character generator (same addess as ROM version) + CHARGEN: file = "", define = yes, start = $E000, size = $0400; + +# memory beneath the ROM + HIDDEN_RAM: file = "", define = yes, start = $E400, size = $FFF0 - $E400; } + SEGMENTS { - EXEHDR: load = HEADER, type = ro; - STARTUP: load = RAM, type = ro, define = yes; - LOWCODE: load = RAM, type = ro, define = yes, optional = yes; - INIT: load = RAM, type = ro, optional = yes; - CODE: load = RAM, type = ro, define = yes; - RODATA: load = RAM, type = ro; - DATA: load = RAM, type = rw; - BSS: load = RAM, type = bss, define = yes; - ZEROPAGE: load = ZP, type = zp; - EXTZP: load = ZP, type = zp, optional = yes; - AUTOSTRT: load = TRAILER, type = ro; + EXEHDR: load = HEADER, type = ro; + + SYSCHKHDR: load = SYSCHKHDR, type = ro, optional = yes; + SYSCHK: load = SYSCHKCHNK, type = rw, define = yes, optional = yes; + SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; + + SRPREPHDR: load = SRPREPHDR, type = ro; + LOWDATA: load = SRPREPCHNK, type = bss, define = yes; # shared btw. SRPREP and RAM + SRPREP: load = SRPREPCHNK, type = rw, define = yes; + SHADOW_RAM: load = SRPREPCHNK, run = HIDDEN_RAM, type = rw, define = yes, optional = yes; + SHADOW_RAM2: load = SRPREPCHNK, run = HIDDEN_RAM2, type = rw, define = yes, optional = yes; + SRPREPTRL: load = SRPREPTRL, type = ro; + + MAINHDR: load = MAINHDR, type = ro; + STARTUP: load = RAM, type = ro, define = yes; + LOWCODE: load = RAM, type = ro, define = yes, optional = yes; + INIT: load = RAM, type = ro, optional = yes; + CODE: load = RAM, type = ro, define = yes; + RODATA: load = RAM, type = ro; + DATA: load = RAM, type = rw; + BSS: load = RAM, type = bss, define = yes; + ZEROPAGE: load = ZP, type = zp; + EXTZP: load = ZP, type = zp, optional = yes; + AUTOSTRT: load = TRAILER, type = ro; } FEATURES { CONDES: type = constructor, diff --git a/libsrc/atari/Makefile.inc b/libsrc/atari/Makefile.inc index d12b54058..af5a17e59 100644 --- a/libsrc/atari/Makefile.inc +++ b/libsrc/atari/Makefile.inc @@ -14,3 +14,20 @@ # needs DEFAULT_DEVICE to be defined, otherwise no effect CA65FLAGS += -D NUMDRVS=4 -D LINEBUF=80 -D UCASE_FILENAME=1 -D DEFAULT_DEVICE=1 -D DYNAMIC_DD=1 + +# The following defines are only used by the 'atarixl' target: +# +# CHARGEN_RELOC - If defined, CHBAS and CHBASE are updated when +# enabling or disabling the ROM. +# If the ROM is enabled, $E0 is written to CHBAS +# and CHBASE. +# If the ROM is disabled, the upper byte of +# __CHARGEN_START__ is written to CHBAS and CHBASE. +# USEWSYNC - If defined, the code waits for horizontal retrace +# before switching the ROM and updating CHBAS and +# CHBASE. This define only has effect if CHARGEN_RELOC +# is also defined. + +# Disabled by default, you should enable it if the linker script relocates the +# character generator (like atarixl-largehimem.cfg). +#CA65FLAGS += -D CHARGEN_RELOC -D USEWSYNC diff --git a/libsrc/atari/cgetc.s b/libsrc/atari/cgetc.s index f8948a5bc..54fe85bb4 100644 --- a/libsrc/atari/cgetc.s +++ b/libsrc/atari/cgetc.s @@ -7,22 +7,28 @@ .include "atari.inc" .export _cgetc,setcursor + .import KEYBDV_handler .import cursor,mul40 _cgetc: jsr setcursor + lda #12 + sta ICAX1Z ; fix problems with direct call to KEYBDV +.ifndef __ATARIXL__ jsr @1 +.else + jsr KEYBDV_handler +.endif ldx #0 rts +.ifndef __ATARIXL__ @1: lda KEYBDV+5 pha lda KEYBDV+4 pha - lda #12 - sta ICAX1Z ; fix problems with direct call to KEYBDV rts - +.endif .proc setcursor diff --git a/libsrc/atari/crt0.s b/libsrc/atari/crt0.s index 85a3ffcde..72a0c3198 100644 --- a/libsrc/atari/crt0.s +++ b/libsrc/atari/crt0.s @@ -15,6 +15,14 @@ .import callmain, zerobss .import __STARTUP_LOAD__, __BSS_LOAD__ .import __RESERVED_MEMORY__ + .import __RAM_START__, __RAM_SIZE__ +.ifdef __ATARIXL__ + .import __STACKSIZE__ + .import sram_init + .import scrdev + .import findfreeiocb + .include "save_area.inc" +.endif .include "zeropage.inc" .include "atari.inc" @@ -25,6 +33,11 @@ .segment "EXEHDR" .word $FFFF + +.ifdef __ATARIXL__ +.segment "MAINHDR" +.endif + .word __STARTUP_LOAD__ .word __BSS_LOAD__ - 1 @@ -40,6 +53,12 @@ ; Real entry point: +start: + +.ifdef __ATARIXL__ + jsr sram_init +.endif + ; Clear the BSS data jsr zerobss @@ -47,14 +66,16 @@ ; Setup the stack tsx - stx spsave + stx SP_save + +.ifndef __ATARIXL__ ; Report memory usage lda APPMHI - sta appmsav ; remember old APPMHI value + sta APPMHI_save ; remember old APPMHI value lda APPMHI+1 - sta appmsav+1 + sta APPMHI_save+1 sec lda MEMTOP @@ -66,6 +87,15 @@ sta APPMHI+1 sta sp+1 ; setup runtime stack part 2 +.else + + lda #<(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__) + sta sp + lda #>(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__) + sta sp+1 + +.endif + ; Call module constructors jsr initlib @@ -73,14 +103,14 @@ ; Set left margin to 0 lda LMARGN - sta old_lmargin + sta LMARGN_save ldy #0 sty LMARGN ; Set keyb to upper/lowercase mode ldx SHFLOK - stx old_shflok + stx SHFLOK_save sty SHFLOK ; Initialize conio stuff @@ -98,26 +128,71 @@ _exit: jsr donelib ; Run module destructors ; Restore system stuff - ldx spsave + ldx SP_save txs ; Restore stack pointer ; Restore left margin - lda old_lmargin + lda LMARGN_save sta LMARGN ; Restore kb mode - lda old_shflok + lda SHFLOK_save sta SHFLOK ; Restore APPMHI - lda appmsav + lda APPMHI_save sta APPMHI - lda appmsav+1 + lda APPMHI_save+1 sta APPMHI+1 +.ifdef __ATARIXL__ + +; Atari XL target stuff... + + lda PORTB_save + sta PORTB + lda RAMTOP_save + sta RAMTOP + lda MEMTOP_save + sta MEMTOP + lda MEMTOP_save+1 + sta MEMTOP+1 + + +; Issue a GRAPHICS 0 call (copied'n'pasted from TGI drivers) in +; order to restore screen memory to its defailt location just +; before the ROM. + + jsr findfreeiocb + + ; Reopen it in Graphics 0 + lda #OPEN + sta ICCOM,x + lda #OPNIN | OPNOT + sta ICAX1,x + lda #0 + sta ICAX2,x + lda #scrdev + sta ICBAH,x + lda #3 + sta ICBLL,x + lda #0 + sta ICBLH,x + jsr CIOV_org +; No error checking here, shouldn't happen(tm), and no way to +; recover anyway. + + lda #CLOSE + sta ICCOM,x + jsr CIOV_org + +.endif + ; Turn on cursor ldx #0 @@ -133,13 +208,15 @@ _exit: jsr donelib ; Run module destructors .bss -spsave: .res 1 -appmsav: .res 1 -old_shflok: .res 1 -old_lmargin: .res 1 +SP_save: .res 1 +SHFLOK_save: .res 1 +LMARGN_save: .res 1 +.ifndef __ATARIXL__ +APPMHI_save: .res 2 +.endif .segment "AUTOSTRT" .word RUNAD ; defined in atari.inc .word RUNAD+1 - .word __STARTUP_LOAD__ + 1 + .word start diff --git a/libsrc/atari/graphics.s b/libsrc/atari/graphics.s index 1c6856296..ab26ed0da 100644 --- a/libsrc/atari/graphics.s +++ b/libsrc/atari/graphics.s @@ -15,6 +15,7 @@ .import clriocb .import fdtoiocb .import newfd + .import scrdev .importzp tmp1,tmp2,tmp3 .include "atari.inc" @@ -105,8 +106,3 @@ cioerr: sty tmp3 ; remember error code jmp __mappederrno .endproc ; __graphics - - - .rodata - -scrdev: .byte "S:", 0 diff --git a/libsrc/atari/irq.s b/libsrc/atari/irq.s index 9a433ca00..8ec1b12df 100644 --- a/libsrc/atari/irq.s +++ b/libsrc/atari/irq.s @@ -6,6 +6,10 @@ .import callirq .include "atari.inc" +.ifdef __ATARIXL__ + .import __CHARGEN_START__ + .include "romswitch.inc" +.endif ; ------------------------------------------------------------------------ @@ -39,7 +43,29 @@ doneirq: IRQStub: cld ; Just to be sure +.ifdef __ATARIXL__ + pha +.ifdef CHARGEN_RELOC + lda CHBAS + pha +.endif + lda PORTB + pha + and #$FE + sta PORTB ; disable ROM + set_chbase >__CHARGEN_START__ +.endif jsr callirq ; Call the functions +.ifdef __ATARIXL__ + pla + sta PORTB ; restore old ROM setting +.ifdef CHARGEN_RELOC + pla + sta CHBAS + sta CHBASE +.endif + pla +.endif jmp IRQInd ; Jump to the saved IRQ vector ; ------------------------------------------------------------------------ diff --git a/libsrc/atari/libref.s b/libsrc/atari/libref.s index 8d9ff3e08..171bd6de6 100644 --- a/libsrc/atari/libref.s +++ b/libsrc/atari/libref.s @@ -7,4 +7,9 @@ em_libref := _exit joy_libref := _exit +.ifdef __ATARIXL__ + .import CIO_handler +tgi_libref := CIO_handler +.else tgi_libref := _exit +.endif diff --git a/libsrc/atari/ostype.s b/libsrc/atari/ostype.s index d93b3ab88..7248582a6 100644 --- a/libsrc/atari/ostype.s +++ b/libsrc/atari/ostype.s @@ -40,8 +40,40 @@ .export _get_ostype -.proc _get_ostype + .include "atari.inc" + .include "romswitch.inc" +.ifdef __ATARIXL__ + + .import __CHARGEN_START__ + .segment "LOWCODE" + +.macro disable_rom_save_a + pha + disable_rom + pla +.endmacro + +.else ; above atarixl, below atari + +.macro disable_rom_save_a +.endmacro + +.endif ; .ifdef __ATARIXL__ + + +; unknown ROM + +_unknown: + lda #0 + tax + disable_rom_save_a + rts + + +_get_ostype: + + enable_rom lda $fcd8 cmp #$a2 beq _400800 @@ -63,13 +95,7 @@ and #%00111000 ora #%11 _fin: ldx #0 - rts - -; unknown ROM - -_unknown: - lda #0 - tax + disable_rom_save_a rts ; 1200XL ROM @@ -148,5 +174,3 @@ _400800_3: lda #%00010001 bne _fin - -.endproc diff --git a/libsrc/atari/romswitch.inc b/libsrc/atari/romswitch.inc new file mode 100644 index 000000000..7169f2b39 --- /dev/null +++ b/libsrc/atari/romswitch.inc @@ -0,0 +1,101 @@ +; +; Macros to disable and enable the ROM on Atari XL systems. +; +; Christian Groessler, chris@groessler.org, 19-Sep-2013 +; +; +; Defines which modify the operation of the macros: +; +; CHARGEN_RELOC: If defined, CHBAS and CHBASE are updated when +; enabling or disabling the ROM. +; If the ROM is enabled, $E0 is written to CHBAS +; and CHBASE. +; If the ROM is disabled, the upper byte of +; __CHARGEN_START__ is written to CHBAS and CHBASE. +; USEWSYNC: If defined, the code waits for horizontal retrace +; before switching the ROM and updating CHBAS and +; CHBASE. This define only has effect if CHARGEN_RELOC +; is also defined. + + +.ifdef __ATARIXL__ + +.ifdef CHARGEN_RELOC + +.macro set_chbase val + lda #val + sta CHBAS + sta CHBASE +.endmacro + +.else + +.macro set_chbase val +.endmacro + +.endif ; .ifdef CHARGEN_RELOC + + +.if .defined(USEWSYNC) .and .defined(CHARGEN_RELOC) + +.macro wsync + sta WSYNC +.endmacro + +.else ; above + +.macro wsync +.endmacro + +.endif + + +; "disable ROM" macros + +.macro disable_rom + lda PORTB + and #$fe + wsync + sta PORTB + set_chbase >__CHARGEN_START__ +.endmacro + +.macro disable_rom_quick + lda PORTB + and #$fe + sta PORTB + set_chbase >__CHARGEN_START__ +.endmacro + +.macro disable_rom_val val + lda val + wsync + sta PORTB + set_chbase >__CHARGEN_START__ +.endmacro + +; "enable ROM" macros + +.macro enable_rom + lda PORTB + ora #1 + wsync + sta PORTB + set_chbase $E0 +.endmacro + +.macro enable_rom_quick + lda PORTB + ora #1 + sta PORTB + set_chbase $E0 +.endmacro + +.else ; above __ATARIXL__, below not + +.macro disable_rom +.endmacro +.macro enable_rom +.endmacro + +.endif diff --git a/libsrc/atari/save_area.inc b/libsrc/atari/save_area.inc new file mode 100644 index 000000000..ac433fded --- /dev/null +++ b/libsrc/atari/save_area.inc @@ -0,0 +1,13 @@ +; +; Atari XL, shared data between 2nd load chunk and main chunk, header file +; +; Contains old values of modified system variables and ports. +; +; Christian Groessler, chris@groessler.org, 2013 +; + +.import SAVMSC_save +.import MEMTOP_save +.import APPMHI_save +.import RAMTOP_save +.import PORTB_save diff --git a/libsrc/atari/save_area.s b/libsrc/atari/save_area.s new file mode 100644 index 000000000..e46f3631e --- /dev/null +++ b/libsrc/atari/save_area.s @@ -0,0 +1,25 @@ +; +; Atari XL, shared data between 2nd load chunk and main chunk, definition file +; +; Contains old values of modified system variables and ports. +; +; Christian Groessler, chris@groessler.org, 2013 +; + +.ifdef __ATARIXL__ + +.export SAVMSC_save +.export MEMTOP_save +.export APPMHI_save +.export RAMTOP_save +.export PORTB_save + +.segment "LOWDATA" + +SAVMSC_save: .res 2 +MEMTOP_save: .res 2 +APPMHI_save: .res 2 +RAMTOP_save: .res 1 +PORTB_save: .res 1 + +.endif diff --git a/libsrc/atari/scrdev.s b/libsrc/atari/scrdev.s new file mode 100644 index 000000000..2d6ff3e07 --- /dev/null +++ b/libsrc/atari/scrdev.s @@ -0,0 +1,7 @@ +; Name of the "screen" device + + .export scrdev + + .rodata + +scrdev: .byte "S:", 0 diff --git a/libsrc/atari/shadow_ram_handlers.s b/libsrc/atari/shadow_ram_handlers.s new file mode 100644 index 000000000..a01363318 --- /dev/null +++ b/libsrc/atari/shadow_ram_handlers.s @@ -0,0 +1,1101 @@ +; +; Atari XL shadow RAM handlers +; +; Christian Groessler, chris@groessler.org, 2013 +; + +;DEBUG = 1 +CHKBUF = 1 ; check if bounce buffering is needed (bounce buffering is always done if set to 0) + +.ifdef __ATARIXL__ + +SHRAM_HANDLERS = 1 + .include "atari.inc" + .include "save_area.inc" + .include "zeropage.inc" + .include "romswitch.inc" + + .import __CHARGEN_START__ + + .export sram_init + .export KEYBDV_handler + .export CIO_handler + .export SIO_handler + .export SETVBV_handler + +BUFSZ = 128 ; bounce buffer size +BUFSZ_SIO = 256 + +.segment "INIT" + +; Turn off ROMs, install system and interrupt wrappers, set new chargen pointer + +sram_init: + +; disable all interrupts + ldx #0 + stx NMIEN ; disable NMI + sei + +; disable ROMs + disable_rom + +; setup interrupt vectors + lda #my_IRQ_han + sta $ffff + + lda #my_RESET_han + sta $fffd + + lda #my_NMI_han + sta $fffb + +; enable interrupts + cli + lda #$40 + sta NMIEN + + rts + +.segment "EXTZP" : zeropage + +zpptr1: .res 2 + + +.segment "LOWDATA" + +; bounce buffers for CIO and SIO calls +bounce_buffer: .res BUFSZ_SIO + + +.segment "LOWCODE" + + +; Interrupt handlers +; ------------------ + +; The interrupt handlers don't look at the current state of PORTB and +; unconditionally disable the ROMs on exit. +; Please note that this works, since if the ROMs are enabled we anyway +; aren't being called here because the vectors are pointing to their +; original ROM locations. + +.macro int_wrap orgvec + .local ret + pha + enable_rom_quick + lda #>ret + pha + lda # data too large for our buffers + ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES + lda # bounce buffer size? + bcs br_last ; no, last transfer, use remaining size + + lda #>BUFSZ + sta ICBLH,x ; set data length + lda # data too large for our buffers + ; CHANGE HERE TO SUPPORT BOUNCE BUFFERS > 255 BYTES + lda # bounce buffer size? + bcs bw_last ; no, last transfer, use remaining size + + lda #>BUFSZ + sta ICBLH,x ; set data length + 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 +copy_to_user: + 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 + + +; copy data from user buffer into bounce buffer +; input: X - IOCB index +; zpptr1 - pointer to user buffer +; output: A - destroyed +; 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 bounce_buffer,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 + 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 + + +; 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 + + +; put bounce buffer address into ICBAL/ICBAH +; input: X - IOCB index +; output: A - destroyed +bncbuf_to_iocb: + lda #bounce_buffer + sta ICBAH,x + rts + + +; 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 bounce_buffer,y + beq copy_fn_done + iny + cmp #ATEOL + bne copy_filename + dey +copy_fn_done: + rts + + +; 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 + + +.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 + +;--------------------------------------------------------- + +; 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 DBYTHI + rts + +; put bounce buffer address into DBUFLO/DBUFHI +; input: (--) +; output: A - destroyed +bncbuf_to_dbuf: + 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_handler: + + 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 + 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 + +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 +orig_ptr: .res 2 +orig_len: .res 2 +req_len: .res 2 +retlen: .res 2 + +.endif ; .ifdef __ATARIXL__ diff --git a/libsrc/atari/shadow_ram_prepare.s b/libsrc/atari/shadow_ram_prepare.s new file mode 100644 index 000000000..a08aa8cfe --- /dev/null +++ b/libsrc/atari/shadow_ram_prepare.s @@ -0,0 +1,405 @@ +; +; Atari XL shadow RAM preparation routines +; +; Tasks: +; - move screen memory below load address +; - copy ROM chargen to its new place +; - copy shadow RAM contents to their destination +; +; Christian Groessler, chris@groessler.org, 2013 +; + +;DEBUG = 1 + +.ifdef __ATARIXL__ + + .export sramprep + .import __SRPREP_LOAD__, __SRPREPCHNK_LAST__ + .import __SHADOW_RAM_LOAD__, __SHADOW_RAM_SIZE__, __SHADOW_RAM_RUN__ + .import __SHADOW_RAM2_LOAD__, __SHADOW_RAM2_SIZE__, __SHADOW_RAM2_RUN__ + .import __CHARGEN_START__, __CHARGEN_SIZE__ + .import __STARTADDRESS__ ; needed by xlmemchk.inc + + .include "zeropage.inc" + .include "atari.inc" + .include "save_area.inc" + +.macro print_string text + .local start, cont + jmp cont +start: .byte text, ATEOL +cont: ldx #0 ; channel 0 + lda #start + sta ICBAH,x + lda #<(cont - start) + sta ICBLL,x ; length + lda #>(cont - start) + sta ICBLH,x + lda #PUTCHR + sta ICCOM,x + jsr CIOV_org +.endmacro + +; ------------------------------------------------------------------------ +; EXE load chunk header + +.segment "SRPREPHDR" + + .word __SRPREP_LOAD__ + .word __SRPREPCHNK_LAST__ - 1 + +; ------------------------------------------------------------------------ +; Actual code + +.segment "SRPREP" + +sramprep: +.ifdef DEBUG + print_string "entering stage #2" +.endif + +; save values of modified system variables and ports + + lda RAMTOP + sta RAMTOP_save + lda MEMTOP + sta MEMTOP_save + lda MEMTOP+1 + sta MEMTOP_save+1 + lda APPMHI + sta APPMHI_save + lda APPMHI+1 + sta APPMHI_save+1 + lda PORTB + sta PORTB_save + +; disable BASIC + + lda PORTB + ora #2 + sta PORTB + + .include "xlmemchk.inc" ; calculate lowest address used and new value for RAMTOP + + ldx lowadr + stx MEMTOP + lda lowadr+1 + sta MEMTOP+1 + lda lodadr+1 + sta RAMTOP + + ; set APPMHI to MEMLO (+ 1 for sanity) + lda MEMLO + clc + adc #1 + sta APPMHI + lda MEMLO+1 + adc #0 + sta APPMHI+1 + + +; issue a GRAPHICS 0 call (copied'n'pasted from TGI drivers) to move screen memory down + + + jsr findfreeiocb +.ifdef DEBUG ; only check in debug version, this shouldn't really happen(tm) + beq iocbok + print_string "Internal error, no free IOCB!" + jsr delay + jsr delay + jsr delay + jsr restore ; restore stuff we've changed + jmp (DOSVEC) ; abort loading +iocbok: +.endif + + ; Reopen it in Graphics 0 + lda #OPEN + sta ICCOM,x + lda #OPNIN | OPNOT + sta ICAX1,x + lda #0 + sta ICAX2,x + lda #screen_device + sta ICBAH,x + lda #screen_device_length + sta ICBLH,x + jsr CIOV_org + bpl scrok + +; shouldn't happen(tm) + print_string "Internal error, aborting..." + jsr delay + jsr delay + jsr delay + jsr restore ; restore stuff we've changed + jmp (DOSVEC) ; abort loading + + +scrok: ; now close it again -- we don't need it anymore + lda #CLOSE + sta ICCOM,x + jsr CIOV_org + + +; copy chargen to low memory, just after the next possible address beyond our loaded chunk data + +.ifdef DEBUG + print_string "copy chargen to low memory" +.endif + + lda #>__SRPREPCHNK_LAST__ + sta ptr3+1 + lda #<__SRPREPCHNK_LAST__ + sta ptr3 + beq cg_addr_ok + + ; page align the new chargen address + inc ptr3+1 + lda #0 + sta ptr3 + +cg_addr_ok: + + lda ptr3+1 + and #3 + beq cg_addr_ok2 + + ; align to next 1K boundary + lda ptr3+1 + and #$fc + clc + adc #4 + sta ptr3+1 + +cg_addr_ok2: + + lda #DCSORG + sta ptr1+1 + lda ptr3 + sta ptr2 + lda ptr3+1 + pha ; needed later to set CHBAS/CHBASE + sta ptr2+1 + lda #>__CHARGEN_SIZE__ + sta tmp2 + lda #<__CHARGEN_SIZE__ + sta tmp1 + jsr memcopy + +.ifdef DEBUG + print_string "now setting up high memory" +.endif + +; disable ROM + sei + ldx #0 + stx NMIEN ; disable NMI + lda PORTB + and #$fe + tax + pla ; get temp. chargen address + sta WSYNC ; wait for horiz. retrace + stx PORTB ; now ROM is mapped out + +; switch to temporary chargen + + sta CHBASE + sta CHBAS + +; copy shadow RAM contents to their destination (segment SHADOW_RAM) + + lda #<__SHADOW_RAM_SIZE__ + bne do_copy + lda #>__SHADOW_RAM_SIZE__ + beq no_copy ; we have no shadow RAM contents + + ; ptr1 - src; ptr2 - dest; tmp1, tmp2 - len +do_copy:lda #<__SHADOW_RAM_LOAD__ + sta ptr1 + lda #>__SHADOW_RAM_LOAD__ + sta ptr1+1 + lda #<__SHADOW_RAM_RUN__ + sta ptr2 + lda #>__SHADOW_RAM_RUN__ + sta ptr2+1 + lda #<__SHADOW_RAM_SIZE__ + sta tmp1 + lda #>__SHADOW_RAM_SIZE__ + sta tmp2 + + jsr memcopy + +no_copy: + +; copy shadow RAM #2 contents to their destination (segment SHADOW_RAM2) + + lda #<__SHADOW_RAM2_SIZE__ + bne do_copy2 + lda #>__SHADOW_RAM2_SIZE__ + beq no_copy2 ; we have no shadow RAM contents + + ; ptr1 - src; ptr2 - dest; tmp1, tmp2 - len +do_copy2: + lda #<__SHADOW_RAM2_LOAD__ + sta ptr1 + lda #>__SHADOW_RAM2_LOAD__ + sta ptr1+1 + lda #<__SHADOW_RAM2_RUN__ + sta ptr2 + lda #>__SHADOW_RAM2_RUN__ + sta ptr2+1 + lda #<__SHADOW_RAM2_SIZE__ + sta tmp1 + lda #>__SHADOW_RAM2_SIZE__ + sta tmp2 + + jsr memcopy + +no_copy2: + +; copy chargen to its new (final) location + + lda ptr3 + sta ptr1 + lda ptr3+1 + sta ptr1+1 + lda #<__CHARGEN_START__ + sta ptr2 + lda #>__CHARGEN_START__ + sta ptr2+1 + lda #>__CHARGEN_SIZE__ + sta tmp2 + lda #<__CHARGEN_SIZE__ + sta tmp1 + jsr memcopy + +; re-enable ROM + + lda PORTB + ora #1 + ldx #>DCSORG + sta WSYNC ; wait for horiz. retrace + sta PORTB + stx CHBASE + stx CHBAS + lda #$40 + sta NMIEN ; enable VB again + cli ; and enable IRQs + +.ifdef DEBUG + print_string "Stage #2 OK" + print_string "loading main chunk" + jsr delay +.endif + rts + +.include "findfreeiocb.inc" + +; routine taken from http://www.obelisk.demon.co.uk/6502/algorithms.html +; +; copy memory +; ptr1 - source +; ptr2 - destination +; tmp2:tmp1 - len + +.proc memcopy + + ldy #0 + ldx tmp2 + beq last +pagecp: lda (ptr1),y + sta (ptr2),y + iny + bne pagecp + inc ptr1+1 + inc ptr2+1 + dex + bne pagecp +last: cpy tmp1 + beq done + lda (ptr1),y + sta (ptr2),y + iny + bne last +done: rts + +.endproc + + +; clean up after a fatal error + +restore:lda RAMTOP_save + sta RAMTOP + lda MEMTOP_save + sta MEMTOP + lda MEMTOP_save+1 + sta MEMTOP+1 + lda APPMHI_save + sta APPMHI + lda APPMHI_save+1 + sta APPMHI+1 + rts + +; short delay +.proc delay + + lda #10 +@loop: jsr delay1 + clc + sbc #0 + bne @loop + rts + +delay1: ldx #0 + ldy #0 +@loop: dey + bne @loop + dex + bne @loop + rts + +.endproc + +.ifdef DEBUG + +.byte "HERE ****************** HERE ***************>>>>>>" + +sramsize: + .word __SHADOW_RAM_SIZE__ + +.endif ; .ifdef DEBUG + +screen_device: .byte "S:",0 +screen_device_length = * - screen_device + +.ifdef DEBUG + .byte " ** srprep ** end-->" +.endif + +; ------------------------------------------------------------------------ +; Provide empty SHADOW_RAM and SHADOW_RAM2 segments in order that the +; linker is happy if the user program doesn't have these segments. + +.segment "SHADOW_RAM" +.segment "SHADOW_RAM2" + + +; ------------------------------------------------------------------------ +; EXE load chunk "trailer" - sets INITAD + +.segment "SRPREPTRL" + + .word INITAD + .word INITAD+1 + .word sramprep + +.endif ; .ifdef __ATARIXL__ diff --git a/libsrc/atari/sysrmdir.s b/libsrc/atari/sysrmdir.s index 126c11cca..3f5b9e447 100644 --- a/libsrc/atari/sysrmdir.s +++ b/libsrc/atari/sysrmdir.s @@ -8,7 +8,6 @@ ; .include "atari.inc" - .include "errno.inc" .export __sysrmdir .import __sysremove .import __dos_type @@ -17,7 +16,6 @@ .ifdef UCASE_FILENAME .import ucase_fn .import addysp - .importzp sreg .importzp tmp3 .ifdef DEFAULT_DEVICE .importzp tmp2 diff --git a/libsrc/atari/system_check.s b/libsrc/atari/system_check.s new file mode 100644 index 000000000..5a23546f0 --- /dev/null +++ b/libsrc/atari/system_check.s @@ -0,0 +1,157 @@ +; +; Atari XL startup system check +; +; This routine gets loaded prior to the main part of the executable +; and checks if the system is compatible to run the program. +; It checks whether the system is an XL type one and that enough +; memory is installed (which isn't the case for a 600XL). +; If the system doesn't qualify, the loading of the main program +; is aborted by jumping to DOSVEC. +; +; Christian Groessler, chris@groessler.org, 2013 +; + +;DEBUG = 1 + +.ifdef __ATARIXL__ + + .export syschk + .import __SYSCHK_LOAD__ + .import __STARTADDRESS__ ; needed by xlmemchk.inc + + .include "zeropage.inc" + .include "atari.inc" + + +.macro print_string text + .local start, cont + jmp cont +start: .byte text, ATEOL +cont: ldx #0 ; channel 0 + lda #start + sta ICBAH,x + lda #<(cont - start) + sta ICBLL,x ; length + lda #>(cont - start) + sta ICBLH,x + lda #PUTCHR + sta ICCOM,x + jsr CIOV_org +.endmacro +.macro print_string2 addr, len + + ldx #0 ; channel 0 + lda #addr + sta ICBAH,x + lda #len + sta ICBLH,x + lda #PUTCHR + sta ICCOM,x + jsr CIOV_org + +.endmacro + + +; ------------------------------------------------------------------------ +; Chunk header + +.segment "SYSCHKHDR" + + .word __SYSCHK_LOAD__ + .word end - 1 + +; ------------------------------------------------------------------------ +; Actual code + +.segment "SYSCHK" + +; no XL machine +no_xl: print_string "This program needs an XL machine." + jmp fail + +; entry point +syschk: + lda $fcd8 ; from ostype.s + cmp #$a2 + beq no_xl + +; we have an XL machine, now check memory + lda RAMSIZ + cmp #$80 + bcs sys_ok + +; not enough memory + print_string "Not enough memory." +fail: jsr delay + jmp (DOSVEC) + + +sys_ok: + .include "xlmemchk.inc" ; calculate lowest address we will use when we move the screen buffer down + + sec + lda MEMLO + sbc lowadr + lda MEMLO+1 + sbc lowadr+1 + bcc memlo_ok + +; load address was too low + print_string2 lmemerr_txt, lmemerr_txt_len + jsr delay ; long text takes longer to read, give user additional time + jmp fail + +; all is well(tm), launch the application +memlo_ok: +.ifdef DEBUG + print_string "Stage #1 OK" + jsr delay +.endif + rts + + +lmemerr_txt: + .byte "Not enough memory to move screen", ATEOL + .byte "memory to low memory. Consider using", ATEOL + .byte "a higher load address.", ATEOL +lmemerr_txt_len = * - lmemerr_txt + + +; short delay +.proc delay + + lda #10 +l: jsr delay1 + clc + sbc #0 + bne l + rts + +delay1: ldx #0 + ldy #0 +loop: dey + bne loop + dex + bne loop + rts + +.endproc + +end: + +; ------------------------------------------------------------------------ +; Chunk "trailer" - sets INITAD + +.segment "SYSCHKTRL" + + .word INITAD + .word INITAD+1 + .word syschk + +.endif ; .ifdef __ATARIXL__ diff --git a/libsrc/atari/tgi/atari_tgi_common.inc b/libsrc/atari/tgi/atari_tgi_common.inc index 7dba884fa..0d7972d34 100644 --- a/libsrc/atari/tgi/atari_tgi_common.inc +++ b/libsrc/atari/tgi/atari_tgi_common.inc @@ -4,6 +4,12 @@ .macpack longbranch +.ifdef __ATARIXL__ + CIO_vec := my_CIOV +.else + CIO_vec := CIOV +.endif + ; ****************************************************************************** ; ---------------------------------------------------------------------- @@ -18,7 +24,7 @@ .byte $74, $67, $69 ; "tgi" .byte TGI_API_VERSION ; TGI API version number - .addr $0000 ; Library reference +libref: .addr $0000 ; Library reference .word x_res ; X resolution .word y_res ; Y resolution .byte colors ; Number of drawing colors @@ -111,6 +117,10 @@ text_dir: .byte 0 ; Text direction, +.ifdef __ATARIXL__ + my_CIOV: + .byte $4C, 0, 0 +.endif .code ; ****************************************************************************** @@ -161,6 +171,17 @@ screen_device_length := * - screen_device stx mask +.ifdef __ATARIXL__ + + ; setup pointer to CIO + + lda libref + sta my_CIOV+1 + lda libref+1 + sta my_CIOV+2 +.endif + + ; Find a free IOCB lda #$70 search: tax @@ -202,7 +223,7 @@ switch: lda #OPEN sta ICBLL,x lda #>screen_device_length sta ICBLH,x - jsr CIOV + jsr CIO_vec .if ::pages = 2 ; Reserve 8K of high memory @@ -212,7 +233,7 @@ switch: lda #OPEN ; Close and reopen graphics lda #CLOSE sta ICCOM,x - jsr CIOV + jsr CIO_vec ; Reopen graphics lda #OPEN sta ICCOM,x @@ -228,7 +249,7 @@ switch: lda #OPEN sta ICBLL,x lda #>screen_device_length sta ICBLH,x - jsr CIOV + jsr CIO_vec ; Save screen pointers lda SAVMSC + 1 sta p0scr @@ -271,7 +292,7 @@ exit: sta error ; Close the S: device lda #CLOSE sta ICCOM,x - jsr CIOV + jsr CIO_vec ; Reopen it in Graphics 0 lda #OPEN @@ -288,12 +309,12 @@ exit: sta error sta ICBLL,x lda #>screen_device_length sta ICBLH,x - jsr CIOV + jsr CIO_vec ; Now close it again; we don't need it anymore :) lda #CLOSE sta ICCOM,x - jmp CIOV + jmp CIO_vec .endproc ; ****************************************************************************** @@ -640,7 +661,7 @@ done10: .endif sta ATACHR - jmp CIOV + jmp CIO_vec .else ; USE_CIO_LINE diff --git a/libsrc/atari/xlmemchk.inc b/libsrc/atari/xlmemchk.inc new file mode 100644 index 000000000..f8be1c137 --- /dev/null +++ b/libsrc/atari/xlmemchk.inc @@ -0,0 +1,119 @@ +; +; Christian Groessler, Jun-2013 +; +; This routine is used in preparation to move the screen memory +; in front of the program. +; +; It calculates the value to put into RAMTOP for a subsequent +; "GRAPHICS 0" call, and the lowest address which will be used +; by the screen memory afterwards. +; +; inputs: +; __STARTADDRESS__ - load address of the program +; outputs: +; lodadr - (high byte only) value to +; write into RAMTOP +; lowadr - lowest address occupied by +; screen data +; + + +; When setting a display mode, the ROM takes the RAMTOP value +; and subtracts the size of the screen memory from it. This will +; become the new screen memory address. +; From this address it subtracts the size of the display list. +; This will become the new display list address. +; Screen memory cannot cross 4K boundaries and a display list +; cannot cross a 1K boundary. +; +; Work out a sane value for RAMTOP to prevent boundary crossing. +; RAMTOP is only one byte, it counts in memory pages. +; +; The ROM doesn't do this boundary checking, since it doesn't +; expect RAMTOP to have (rather) arbitrary values. For a +; "GRAPHICS 0" call and RAMTOP representing the possible physically +; available memory, boundary crossing cannot happen. + + +SCRBUFSZ = (40 * 24) ; size of mode 0 screen buffer +DLSZ = 32 ; size of mode 0 display list + + +scrmemtst: + +; subtract screen memory size from our load address + + lda lodadr + sec + sbc #SCRBUFSZ + sta tstadr+1 + +; check if a 4K boundary is crossed + + lda lodadr+1 + and #$f0 + sta tmp + lda tstadr+1 + and #$f0 + cmp tmp + beq scrmemok + +; if lodadr is at an exact 4K boundary, it's still ok + + lda lodadr+1 + and #$0f + beq scrmemok + +; 4K boundary will be crossed, use this 4K boundary address as lodadr + +al4k: lda lodadr+1 + and #$f0 + sta lodadr+1 + bne scrmemtst +; not reached + +.ifdef DEBUG +.byte "XLMEMCHK:>" +.endif +lodadr: .word __STARTADDRESS__ & $FF00 ; our program's load address, rounded down to page boundary +tstadr: .res 2 +lowadr: .res 2 +tmp: .res 1 + + +; subtract display list size from calculated screen address + +scrmemok: + lda tstadr + sec + sbc #DLSZ + sta lowadr+1 + +.if 0 ; this cannot happen +; check if a 1K boundary is crossed + + lda tstadr+1 + and #$fc + sta tmp + lda lowadr+1 + and #$fc + cmp tmp + bne al4k ; 1K boundary will be crossed, decrease lodadr +.endif + +; address of display list is ok +; decrease lowadr by two + + lda lowadr + sec + sbc #2 + sta lowadr + bcs dec_cont + dec lowadr+1 +dec_cont: