File: shadow_ram_prepare.s

package info (click to toggle)
cc65 2.19-2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 20,268 kB
  • sloc: ansic: 117,151; asm: 66,339; pascal: 4,248; makefile: 1,009; perl: 607
file content (408 lines) | stat: -rw-r--r-- 9,706 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
;
; 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     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

; ------------------------------------------------------------------------
; EXE load chunk header

.segment        "SRPREPHDR"

        .word   __SRPREP_LOAD__
        .word   __SRPREPCHNK_LAST__ - 1

; ------------------------------------------------------------------------
; Actual code

.segment        "SRPREP"

; ***** entry point *****

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     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, 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
        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 #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
        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__