; Christian Groessler, chris@groessler.org, 2013
;
-DEBUG = 1
+;DEBUG = 1
-.if .defined(__ATARIXL__)
+.ifdef __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__
- .import zpsave
+ .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"
+ .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
+ .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
+; EXE load chunk header
.segment "SRPREPHDR"
.word __SRPREP_LOAD__
- .word __SRPREP_LOAD__ + __SRPREP_SIZE__ + __SHADOW_RAM_SIZE__ - 1
+ .word __SRPREPCHNK_LAST__ - 1
; ------------------------------------------------------------------------
; Actual code
.segment "SRPREP"
+; ***** entry point *****
+
sramprep:
- print_string "in 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
-
- lda $fffe
- sta IRQ_save
- lda $ffff
- sta IRQ_save+1
- lda $fffc
- sta RESET_save
- lda $fffd
- sta RESET_save+1
- lda $fffa
- sta NMI_save
- lda $fffb
- sta NMI_save+1
+ 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
-
-
-; ... change system memory variables bla
-
-CMPVAL = 64+255+992 ; you may ask, why these values... @@@ document
-
-sys_ok: lda #<__SAVEAREA_LOAD__
- sec
- sbc #<CMPVAL
- sta MEMTOP
- sta APPMHI
- lda #>__SAVEAREA_LOAD__
- sbc #>CMPVAL
- sta MEMTOP+1
- sta APPMHI+1
-
- lda #>__SAVEAREA_LOAD__ - 1
- sta RAMTOP
-
-
-
-; ... issue a GRAPHICS 0 call (copied'n'pasted from TGI drivers)
-
-
- ldx #$50 ; take any IOCB, hopefully free (@@@ fixme)
+ 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
+ ; reopen it in Graphics 0
lda #OPEN
sta ICCOM,x
lda #OPNIN | OPNOT
lda #>screen_device_length
sta ICBLH,x
jsr CIOV_org
- bpl okoko
-
- print_string "Internal error, aborting..."
- jsr delay
- jsr delay
- jsr delay
-
- jmp (DOSVEC) ; abort loading
+ 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
-okoko:
-
- ; Now close it again; we don't need it anymore :)
+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 "Stage #2 OK"
- jsr delay
+ print_string "copy chargen to low memory"
.endif
+ lda #>__SRPREPCHNK_LAST__
+ sta ptr3+1
+ lda #<__SRPREPCHNK_LAST__
+ sta ptr3
+ beq cg_addr_ok
-; Save the zero page locations we need
-
- ldx #zpspace-1
-L1: lda sp,x
- sta zpsave,x
- dex
- bpl L1
+ ; page align the new chargen address
+ inc ptr3+1
+ lda #0
+ sta ptr3
-; copy chargen to low memory
+cg_addr_ok:
- 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
+ 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
+ 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
- ; page align the new chargen address
- inc ptr3+1
- lda #0
- sta ptr3
+.ifdef DEBUG
+ print_string "now setting up high memory"
+.endif
-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
+; 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 chargen to its new 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
+; 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 #2 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
- sta PORTB
- lda #$40
- sta NMIEN ; enable VB again
- cli ; and enable IRQs
+ 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"
-; my 6502 fu is rusty, so I took a routine from the internet (http://www.obelisk.demon.co.uk/6502/algorithms.html)
-
+; 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
+.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
-.byte "HERE ****************** HERE ***************>>>>>>"
+; clean up after a fatal error
-sramsize:
- .word __SHADOW_RAM_SIZE__
+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
-l: jsr delay1
- clc
- sbc #0
- bne l
- rts
-
-delay1: ldx #0
- ldy #0
-loop: dey
- bne loop
- dex
- bne loop
- rts
+.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
-screen_device: .byte "S:",0
+.ifdef DEBUG
+
+.byte "HERE ****************** HERE ***************>>>>>>"
+
+sramsize:
+ .word __SHADOW_RAM_SIZE__
+
+.endif ; .ifdef DEBUG
+
+screen_device: .byte "S:",0
screen_device_length = * - screen_device
- .byte " ** srprep ** end-->"
+.ifdef DEBUG
+ .byte " ** srprep ** end-->"
+.endif
; ------------------------------------------------------------------------
-; Provide an empty SHADOW_RAM segment in order that the linker is happy
-; if the user program doesn't have a SHADOW_RAM segment.
+; 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"
; ------------------------------------------------------------------------
-; Chunk "trailer" - sets INITAD
+; EXE load chunk "trailer" - sets INITAD
.segment "SRPREPTRL"
.word INITAD
.word INITAD+1
- .word __SRPREP_LOAD__
+ .word sramprep
-.endif ; .if .defined(__ATARIXL__)
+.endif ; .ifdef __ATARIXL__