SYMBOLS {
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__RESERVED_MEMORY__: type = weak, value = $0000;
+ 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;
+ SYSCHK: file = %O, start = $2E00, size = $0E00;
+
+# "shadow RAM preparation" load chunk
+ SRPREPHDR: file = %O, start = $0000, size = $0004;
+ SRPREP: file = %O, start = %S, size = $7C20 - %S - $04FF; # $04FF: space for temp. chargen buffer, page 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 +
+ __SAVEAREA_SIZE__ +
- __LOWBUFS_SIZE__ +
- __ZPSAVE_SIZE__, size = $D000 -
++ __LOWBUFS_SIZE__, size = $D000 -
+ __STACKSIZE__ -
+ %S -
+ __SAVEAREA_SIZE__ -
- __LOWBUFS_SIZE__ -
- __ZPSAVE_SIZE__;
++ __LOWBUFS_SIZE__;
+
+# address of relocated character generator
+ CHARGEN: file = "", define = yes, start = $D800, size = $0400;
+
+# memory beneath the ROM
+ RAM_BELOW_ROM: file = "", start = $DC00, size = $FFF0 - $DC00;
+
+# defines entry point into program
+ TRAILER: file = %O, start = $0000, size = $0006;
}
+
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 = SYSCHK, type = rw, define = yes, optional = yes;
+
+ SRPREPHDR: load = SRPREPHDR, type = ro;
+ SAVEAREA: load = SRPREP, type = bss, define = yes; # shared btw. SRPREP and RAM
+ LOWBUFS: load = SRPREP, type = bss, define = yes;
- ZPSAVE: load = SRPREP, type = bss, define = yes;
+ SRPREP: load = SRPREP, type = rw, define = yes;
+ SHADOW_RAM: load = SRPREP, run = RAM_BELOW_ROM, 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,
.import initlib, donelib
.import callmain, zerobss
- .import __STARTUP_LOAD__, __ZPSAVE_LOAD__, __BSS_LOAD__
+ .import __STARTUP_LOAD__, __BSS_LOAD__
.import __RESERVED_MEMORY__
- .import __RAM_START__, __RAM_SIZE__
- .import zpsave
- .import sram_init
++ .import __RAM_START__, __RAM_SIZE__
+.if .defined(__ATARIXL__)
- .import scrdev
- .import findfreeiocb
++ .import sram_init
++ .import scrdev
++ .import findfreeiocb
++ .include "save_area.inc"
+.endif
.include "zeropage.inc"
.include "atari.inc"
.segment "EXEHDR"
.word $FFFF
- .segment "MAINHDR"
+
+.if .defined(__ATARIXL__)
++.segment "MAINHDR"
+.endif
+
.word __STARTUP_LOAD__
- .if .defined(__ATARIXL__)
.word __BSS_LOAD__ - 1
- .else
- .word __ZPSAVE_LOAD__ - 1
- .endif
; ------------------------------------------------------------------------
; Actual code
; Real entry point:
- .if .not .defined(__ATARIXL__) ; already done in previous load chunk
-
- ; Save the zero page locations we need
-
- ldx #zpspace-1
- L1: lda sp,x
- sta zpsave,x
- dex
- bpl L1
-
- .else
-
- jsr sram_init
-
++.if .defined(__ATARIXL__)
++ jsr sram_init
+.endif
+
; Clear the BSS data
jsr zerobss
; 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
sta APPMHI+1
sta sp+1 ; setup runtime stack part 2
- lda #<(__RAM_START__ + __RAM_SIZE__ - 1)
- sta sp
- lda #>(__RAM_START__ + __RAM_SIZE__ - 1)
- sta sp+1
+.else
+
++ lda #<(__RAM_START__ + __RAM_SIZE__ - 1)
++ sta sp
++ lda #>(__RAM_START__ + __RAM_SIZE__ - 1)
++ sta sp+1
+
+.endif
+
; Call module constructors
jsr initlib
lda old_shflok
sta SHFLOK
- .if .not .defined(__ATARIXL__)
-
; Restore APPMHI
-- lda appmsav
++ lda APPMHI_save
sta APPMHI
-- lda appmsav+1
++ lda APPMHI_save+1
sta APPMHI+1
- .else
++.if .defined(__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
- lda APPMHI_save
- sta APPMHI
- lda APPMHI_save+1
- sta APPMHI+1
++ 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)
+
- jsr findfreeiocb
++ 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 ICBAL,x
+ lda #>scrdev
+ sta ICBAH,x
+ lda #3
+ sta ICBLL,x
+ lda #0
+ sta ICBLH,x
+ jsr CIOV_org
+; add error checking here...
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV_org
+
+.endif
+
-
- ; Copy back the zero page stuff
-
- ldx #zpspace-1
- L2: lda zpsave,x
- sta sp,x
- dex
- bpl L2
-
; Turn on cursor
- inx
+ ldx #0
stx CRSINH
; Back to DOS
.bss
spsave: .res 1
-appmsav: .res 1
old_shflok: .res 1
old_lmargin: .res 1
- appmsav: .res 1
+.if .not .defined(__ATARIXL__)
++APPMHI_save: .res 2
+.endif
- .segment "AUTOSTRT"
- .word RUNAD ; defined in atari.h
+
+ .segment "AUTOSTRT"
+ .word RUNAD ; defined in atari.inc
.word RUNAD+1
.word __STARTUP_LOAD__ + 1
--- /dev/null
- .import zpsave
+;
+; 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
+
+.if .defined(__ATARIXL__)
+
+ .export sramprep
+ .import __SRPREP_LOAD__, __SRPREP_SIZE__
+ .import __SHADOW_RAM_LOAD__, __SHADOW_RAM_SIZE__
+ .import __SHADOW_RAM_RUN__
+ .import __CHARGEN_START__, __CHARGEN_SIZE__
+ .import __SAVEAREA_LOAD__
- ; Save the zero page locations we need
-
- ldx #zpspace-1
- L1: lda sp,x
- sta zpsave,x
- dex
- bpl L1
-
+
+ .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 ICBAL,x ; address
+ 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
+
+; ------------------------------------------------------------------------
+; Chunk header
+
+.segment "SRPREPHDR"
+
+ .word __SRPREP_LOAD__
+ .word __SRPREP_LOAD__ + __SRPREP_SIZE__ + __SHADOW_RAM_SIZE__ - 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
+ lda CIOV ; zero-page wrapper
+ sta ZP_CIOV_save
+ lda CIOV+1
+ sta ZP_CIOV_save+1
+ lda CIOV+2
+ sta ZP_CIOV_save+2
+ lda SIOV ; zero-page wrapper
+ sta ZP_SIOV_save
+ lda SIOV+1
+ sta ZP_SIOV_save+1
+ lda SIOV+2
+ sta ZP_SIOV_save+2
+
+; disable BASIC
+
+ lda PORTB
+ ora #2
+ sta PORTB
+
+ .include "xlmemchk.inc" ; calculate lowest address used and new value for RAMTOP
+
+ ldx lowadr
+ stx MEMTOP
+ stx APPMHI
+ lda lowadr+1
+ sta MEMTOP+1
+ sta APPMHI+1
+ lda lodadr+1
+ sta RAMTOP
+
+
+; ... issue a GRAPHICS 0 call (copied'n'pasted from TGI drivers)
+
+
+ jsr findfreeiocb
+.ifdef DEBUG ; only check in debug version, this shouldn't happen normally(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 ICBAL,x
+ lda #>screen_device
+ sta ICBAH,x
+ lda #<screen_device_length
+ sta ICBLL,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
+
+.ifdef DEBUG
+ print_string "copy chargen to low memory"
+ print_string "set up high memory"
+.endif
+
+ lda #>(__SRPREP_LOAD__ + __SRPREP_SIZE__ + __SHADOW_RAM_SIZE__)
+ sta ptr3+1
+ lda #<(__SRPREP_LOAD__ + __SRPREP_SIZE__ + __SHADOW_RAM_SIZE__)
+ sta ptr3
+ beq cg_addr_ok
+
+ ; page align the new chargen address
+ inc ptr3+1
+ lda #0
+ sta ptr3
+
+cg_addr_ok:
+ lda #<DCSORG
+ sta ptr1
+ lda #>DCSORG
+ sta ptr1+1
+ lda ptr3
+ sta ptr2
+ lda ptr3+1
+ sta ptr2+1
+ lda #>__CHARGEN_SIZE__
+ sta tmp2
+ lda #<__CHARGEN_SIZE__
+ sta tmp2+1
+ jsr memcopy
+
+; TODO: switch to this temp. chargen
+
+; disable ROMs
+ sei
+ ldx #0
+ stx NMIEN ; disable NMI
+ lda PORTB
+ and #$fe
+ sta PORTB ; now ROM is mapped out
+
+; copy shadow RAM contents to their destination
+
+ 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 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
+ sta PORTB
+ lda #$40
+ sta NMIEN ; enable VB again
+ cli ; and enable IRQs
+
+.ifdef DEBUG
+ print_string "Stage #2 OK"
+ jsr delay
+.endif
+ rts
+
+.include "findfreeiocb.inc"
+
+; my 6502 fu is rusty, so I took a routine from the internet (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
+
+
+.byte "HERE ****************** HERE ***************>>>>>>"
+
+sramsize:
+ .word __SHADOW_RAM_SIZE__
+
+; 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
+
+screen_device: .byte "S:",0
+screen_device_length = * - screen_device
+
+ .byte " ** srprep ** end-->"
+
+; ------------------------------------------------------------------------
+; Provide an empty SHADOW_RAM segment in order that the linker is happy
+; if the user program doesn't have a SHADOW_RAM segment.
+
+.segment "SHADOW_RAM"
+
+
+; ------------------------------------------------------------------------
+; Chunk "trailer" - sets INITAD
+
+.segment "SRPREPTRL"
+
+ .word INITAD
+ .word INITAD+1
+ .word __SRPREP_LOAD__
+
+.endif ; .if .defined(__ATARIXL__)