;
; 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
+ .export sramprep
.import __SRPREP_LOAD__, __SRPREP_SIZE__
- .import __SHADOW_RAM_LOAD__, __SHADOW_RAM_SIZE__
- .import __CHARGEN_LOAD__, __CHARGEN_SIZE__
- .import __SAVEAREA_LOAD__
+ .import __SHADOW_RAM_LOAD__, __SHADOW_RAM_SIZE__
+ .import __SHADOW_RAM_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
+ .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__ - 1
+ .word __SRPREP_LOAD__ + __SRPREP_SIZE__ + __SHADOW_RAM_SIZE__ - 1
; ------------------------------------------------------------------------
; Actual code
.segment "SRPREP"
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
-; disable BASIC
+ 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 PORTB
- ora #2
- sta PORTB
+; disable BASIC
+ lda PORTB
+ ora #2
+ sta PORTB
-; ... change memory bla
+ .include "xlmemchk.inc" ; calculate lowest address used and new value for RAMTOP
-CMPVAL = 64+255+992 ; you may ask, why these values... @@@ document
+ ldx lowadr
+ stx MEMTOP
+ lda lowadr+1
+ sta MEMTOP+1
+ lda lodadr+1
+ sta RAMTOP
-sys_ok: lda #<__SAVEAREA_LOAD__
- sec
- sbc #<CMPVAL
- sta MEMTOP
- sta APPMHI
- lda #>__SAVEAREA_LOAD__
- sbc #>CMPVAL
- sta MEMTOP+1
- sta APPMHI+1
+ ; set APPMHI to MEMLO (+ 1 for sanity)
+ lda MEMLO
+ clc
+ adc #1
+ sta APPMHI
+ lda MEMLO+1
+ adc #0
+ sta APPMHI+1
- lda #>__SAVEAREA_LOAD__ - 1
- sta RAMTOP
-
-
-; ... issue ar GRAPHICS 0 call (copied'n'pasted from TGI drivers)
+; issue a GRAPHICS 0 call (copied'n'pasted from TGI drivers) to move screen memory down
- ldx #$50 ; take any IOCB, hopefully free (@@@ fixme)
+ 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 ICBLL,x
lda #>screen_device_length
sta ICBLH,x
- jsr CIOV
- bpl okoko
-
- print_string "GR 0 FAILED"
- jsr delay
- jsr delay
- jsr delay
+ jsr CIOV_org
+ bpl scrok
- jmp xxx
+; 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
-
- print_string "GR 0 OKOKO"
- jsr delay
+ jsr CIOV_org
+; copy chargen to low memory
+.ifdef DEBUG
+ print_string "copy chargen to low 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 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
+
+.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
+
+ 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
+ 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
-xxx:
+.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
+
+.ifdef DEBUG
+
+.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
+.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
+.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.
+
+.segment "SHADOW_RAM"
+
; ------------------------------------------------------------------------
-; 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 ; .if .defined(__ATARIXL__)