]> git.sur5r.net Git - cc65/blob - libsrc/cbm510/crt0.s
We need to have the character data in the VIC bank to make sprites work.
[cc65] / libsrc / cbm510 / crt0.s
1 ;
2 ; Startup code for cc65 (CBM 500 version)
3 ;
4 ; This must be the *first* file on the linker command line
5 ;
6
7         .export         _exit
8         .import         _clrscr, initlib, donelib
9         .import         push0, _main
10         .import         __CHARRAM_START__, __CHARRAM_SIZE__, __VIDRAM_START__
11         .import         __BSS_RUN__, __BSS_SIZE__
12         .import         irq, nmi
13         .import         k_irq, k_nmi, k_plot, k_udtim, k_scnkey
14
15         .include        "zeropage.inc"
16         .include        "io.inc"
17
18
19 ; ------------------------------------------------------------------------
20 ; Define and export the ZP variables for the CBM510 runtime
21
22         .exportzp       sp, sreg, regsave
23         .exportzp       ptr1, ptr2, ptr3, ptr4
24         .exportzp       tmp1, tmp2, tmp3, tmp4
25         .exportzp       regbank, zpspace
26         .exportzp       vic, sid, cia1, cia2, acia, tpi1, tpi2
27         .exportzp       ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
28
29 .zeropage
30
31 zpstart = *
32 sp:             .res    2       ; Stack pointer
33 sreg:           .res    2       ; Secondary register/high 16 bit for longs
34 regsave:        .res    2       ; slot to save/restore (E)AX into
35 ptr1:           .res    2
36 ptr2:           .res    2
37 ptr3:           .res    2
38 ptr4:           .res    2
39 tmp1:           .res    1
40 tmp2:           .res    1
41 tmp3:           .res    1
42 tmp4:           .res    1
43 regbank:        .res    6       ; 6 byte register bank
44
45 zpspace = * - zpstart           ; Zero page space allocated
46
47 .code
48
49 ; ------------------------------------------------------------------------
50 ; BASIC header and a small BASIC program. Since it is not possible to start
51 ; programs in other banks using SYS, the BASIC program will write a small
52 ; machine code program into memory at $100 and start that machine code
53 ; program. The machine code program will then start the machine language
54 ; code in bank 0, which will initialize the system by copying stuff from
55 ; the system bank, and start the application.
56 ;
57 ; Here's the basic program that's in the following lines:
58 ;
59 ; 10 for i=0 to 4
60 ; 20 read j
61 ; 30 poke 256+i,j
62 ; 40 next i
63 ; 50 sys 256
64 ; 60 data 120,169,0,133,0
65 ;
66 ; The machine program in the data lines is:
67 ;
68 ; sei
69 ; lda     #$00
70 ; sta     $00           <-- Switch to bank 0 after this command
71 ;
72 ; Initialization is not only complex because of the jumping from one bank
73 ; into another. but also because we want to save memory, and because of
74 ; this, we will use the system memory ($00-$3FF) for initialization stuff
75 ; that is overwritten later.
76 ;
77
78 ; To make things more simple, make the code of this module absolute.
79
80         .org    $0001
81 Head:   .byte   $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
82         .byte   $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
83         .byte   $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
84         .byte   $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
85         .byte   $30,$2c,$31,$36,$39,$2c,$30,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
86
87 ; Since we need some vectors to access stuff in the system bank for our own,
88 ; we will include them here, starting from $60:
89
90         .res    $60-*
91
92 vic:            .word   $d800
93 sid:            .word   $da00
94 cia1:           .word   $db00
95 cia2:           .word   $dc00
96 acia:           .word   $dd00
97 tpi1:           .word   $de00
98 tpi2:           .word   $df00
99 ktab1:          .word   $eab1
100 ktab2:          .word   $eb11
101 ktab3:          .word   $eb71
102 ktab4:          .word   $ebd1
103 time:           .dword  $0000
104 RecvBuf:        .word   $0100           ; RS232 received buffer
105 SendBuf:        .word   $0200           ; RS232 send buffer
106
107
108 ; The code in the target bank when switching back will be put at the bottom
109 ; of the stack. We will jump here to switch segments. The range $F2..$FF is
110 ; not used by any kernal routine.
111
112         .res    $F8-*
113 Back:   ldx     spsave
114         txs
115         lda     IndReg
116         sta     ExecReg
117
118 ; The following code is a copy of the code that is poked in the system bank
119 ; memory by the basic header program, it's only for documentation and not
120 ; actually used here:
121
122         sei
123         lda     #$00
124         sta     ExecReg
125
126 ; This is the actual starting point of our code after switching banks for
127 ; startup. Beware: The following code will get overwritten as soon as we
128 ; use the stack (since it's in page 1)!
129
130         tsx
131         stx     spsave          ; Save the system stackpointer
132         ldx     #$FF
133         txs                     ; Set up our own stack
134
135 ; Set the interrupt, NMI and other vectors
136
137         ldy     #vectable_size
138 L0:     lda     vectable-1,y
139         sta     $FF80,y
140         dey
141         bne     L0
142
143 ; Switch the indirect segment to the system bank
144
145         lda     #$0F
146         sta     IndReg
147
148 ; Copy the kernal zero page ($90-$F2) from the system bank
149
150         lda     #$90
151         sta     ptr1
152         lda     #$00
153         sta     ptr1+1
154         ldy     #$62-1
155 L1:     lda     (ptr1),y
156         sta     $90,y
157         dey
158         bpl     L1
159
160 ; Copy the page 3 vectors in place
161
162         ldy     #$00
163 L2:     lda     p3vectable,y
164         sta     $300,y
165         iny
166         cpy     #p3vectable_size
167         bne     L2
168
169 ; Copy the rest of page 3 from the system bank
170
171         lda     #$00
172         sta     ptr1
173         lda     #$03
174         sta     ptr1+1
175 L3:     lda     (ptr1),y
176         sta     $300,y
177         iny
178         bne     L3
179
180 ; Set the indirect segment to bank we're executing in
181
182         lda     ExecReg
183         sta     IndReg
184
185 ; Zero the BSS segment. We will do that here instead calling the routine
186 ; in the common library, since we have the memory anyway, and this way,
187 ; it's reused later.
188
189         lda     #<__BSS_RUN__
190         sta     ptr1
191         lda     #>__BSS_RUN__
192         sta     ptr1+1
193         lda     #0
194         tay
195
196 ; Clear full pages
197
198         ldx     #>__BSS_SIZE__
199         beq     Z2
200 Z1:     sta     (ptr1),y
201         iny
202         bne     Z1
203         inc     ptr1+1                  ; Next page
204         dex
205         bne     Z1
206
207 ; Clear the remaining page
208
209 Z2:     ldx     #<__BSS_SIZE__
210         beq     Z4
211 Z3:     sta     (ptr1),y
212         iny
213         dex
214         bne     Z3
215 Z4:
216
217 ; Setup the C stack
218
219         lda     #<$FF81
220         sta     sp
221         lda     #>$FF81
222         sta     sp+1
223
224 ; We expect to be in page 2 now
225
226 .if     (* < $1FD)
227         jmp     $200
228         .res    $200-*
229 .endif
230 .if     (* < $200)
231         .res    $200-*,$EA
232 .endif
233 .if     (* >= $2F0)
234 .error  "Code range invalid"
235 .endif
236
237 ; This code is in page 2, so we may now start calling subroutines safely,
238 ; since the code we execute is no longer in the stack page.
239
240 ; Copy the character rom from the system bank into the execution bank
241
242         lda     #<$C000
243         sta     ptr1
244         lda     #>$C000
245         sta     ptr1+1
246         lda     #<__CHARRAM_START__
247         sta     ptr2
248         lda     #>__CHARRAM_START__
249         sta     ptr2+1
250         lda     #>__CHARRAM_SIZE__      ; 16 * 256 bytes to copy
251         sta     tmp1
252         ldy     #$00
253 ccopy:  lda     #$0F
254         sta     IndReg                  ; Access the system bank
255 ccopy1: lda     (ptr1),y
256         sta     __VIDRAM_START__,y
257         iny
258         bne     ccopy1
259         lda     ExecReg
260         sta     IndReg
261 ccopy2: lda     __VIDRAM_START__,y
262         sta     (ptr2),y
263         iny
264         bne     ccopy2
265         inc     ptr1+1
266         inc     ptr2+1                  ; Bump high pointer bytes
267         dec     tmp1
268         bne     ccopy
269
270 ; Clear the video memory. We will do this before switching the video to bank 0
271 ; to avoid garbage when doing so.
272
273         jsr     _clrscr
274
275 ; Reprogram the VIC so that the text screen and the character ROM is in the
276 ; execution bank. This is done in three steps:
277
278         lda     #$0F                    ; We need access to the system bank
279         sta     IndReg
280
281 ; Place the VIC video RAM into bank 0
282 ; CA (STATVID)   = 0
283 ; CB (VICDOTSEL) = 0
284
285         ldy     #tpiCtrlReg
286         lda     (tpi1),y
287         sta     vidsave+0
288         and     #%00001111
289         ora     #%10100000
290         sta     (tpi1),y
291
292 ; Set bit 14/15 of the VIC address range to the high bits of __VIDRAM_START__
293 ; PC6/PC7 (VICBANKSEL 0/1) = 11
294
295         ldy     #tpiPortC
296         lda     (tpi2),y
297         sta     vidsave+1
298         and     #$3F
299         ora     #<((>__VIDRAM_START__) & $C0)
300         sta     (tpi2),y
301
302 ; Set the VIC base address register to the addresses of the video and
303 ; character RAM.
304
305         ldy     #VIC_VIDEO_ADR
306         lda     (vic),y
307         sta     vidsave+2
308         and     #$01
309         ora     #<(((__VIDRAM_START__ >> 6) & $F0) | ((__CHARRAM_START__ >> 10) & $0E) | $02)
310 ;       and     #$0F
311 ;       ora     #<(((>__VIDRAM_START__) << 2) & $F0)
312         sta     (vic),y
313
314 ; Switch back to the execution bank
315
316         lda     ExecReg
317         sta     IndReg
318
319 ; Call module constructors
320
321         jsr     initlib
322
323 ; Create the (empty) command line for the program
324
325         jsr     push0           ; argc
326         jsr     push0           ; argv
327
328 ; Execute the program code
329
330         jmp     Start
331
332 ; ------------------------------------------------------------------------
333 ; Additional data that we need for initialization and that's overwritten
334 ; later
335
336 vectable:
337         jmp     $0000           ; CINT
338         jmp     $0000           ; IOINIT
339         jmp     $0000           ; RAMTAS
340         jmp     $0000           ; RESTOR
341         jmp     $0000           ; VECTOR
342         jmp     $0000           ; SETMSG
343         jmp     $0000           ; SECOND
344         jmp     $0000           ; TKSA
345         jmp     $0000           ; MEMTOP
346         jmp     $0000           ; MEMBOT
347         jmp     k_scnkey        ; SCNKEY
348         jmp     $0000           ; SETTMO
349         jmp     $0000           ; ACPTR
350         jmp     $0000           ; CIOUT
351         jmp     $0000           ; UNTLK
352         jmp     $0000           ; UNLSN
353         jmp     $0000           ; LISTEN
354         jmp     $0000           ; TALK
355         jmp     $0000           ; READST
356         jmp     k_setlfs        ; SETLFS
357         jmp     k_setnam        ; SETNAM
358         jmp     $0000           ; OPEN
359         jmp     $0000           ; CLOSE
360         jmp     $0000           ; CHKIN
361         jmp     $0000           ; CKOUT
362         jmp     $0000           ; CLRCH
363         jmp     $0000           ; BASIN
364         jmp     $0000           ; BSOUT
365         jmp     $0000           ; LOAD
366         jmp     $0000           ; SAVE
367         jmp     k_settim        ; SETTIM
368         jmp     k_rdtim         ; RDTIM
369         jmp     $0000           ; STOP
370         jmp     $0000           ; GETIN
371         jmp     $0000           ; CLALL
372         jmp     k_udtim         ; UDTIM
373         jmp     k_screen        ; SCREEN
374         jmp     k_plot          ; PLOT
375         jmp     k_iobase        ; IOBASE
376         sta     ExecReg
377         rts
378         .byte   $01             ; Filler
379         .word   nmi
380         .word   0               ; Reset - not used
381         .word   irq
382 vectable_size   = * - vectable
383
384 p3vectable:
385         .word   k_irq           ; IRQ user vector
386         .word   k_brk           ; BRK user vector
387         .word   k_nmi           ; NMI user vector
388 p3vectable_size = * - p3vectable
389
390
391 ; ------------------------------------------------------------------------
392 ; This is the program code after setup. It starts at $400
393
394         .res    $400-*
395
396 Start:
397
398 ; Enable interrupts
399
400         cli
401
402 ; Call the user code
403
404         ldy     #4              ; Argument size
405         jsr     _main           ; call the users code
406
407 ; Call module destructors. This is also the _exit entry.
408
409 _exit:  jsr     donelib         ; Run module destructors
410
411 ; We need access to the system bank now
412
413         lda     #$0F
414         sta     IndReg
415
416 ; Switch back the video to the system bank
417
418         ldy     #tpiCtrlReg
419         lda     vidsave+0
420         sta     (tpi1),y
421
422         ldy     #tpiPortC
423         lda     vidsave+1
424         sta     (tpi2),y
425
426         ldy     #VIC_VIDEO_ADR
427         lda     vidsave+2
428         sta     (vic),y
429
430 ; Clear the start of the zero page, since it will be interpreted as a
431 ; (garbage) BASIC program otherwise. This is also the default entry for
432 ; the break vector.
433
434 k_brk:  sei
435         lda     #$00
436         ldx     #$3E
437 Clear:  sta     $02,x
438         dex
439         bne     Clear
440
441 ; Setup the welcome code at the stack bottom in the system bank. Use
442 ; the F4/F5 vector to access the system bank
443
444         ldy     #$00
445         sty     $F4
446         iny
447         sty     $F5
448         ldy     #reset_size-1
449 @L1:    lda     reset,y
450         sta     ($F4),y
451         dey
452         bne     @L1
453         jmp     Back
454
455 ; ------------------------------------------------------------------------
456 ; Code that is copied into the system bank at $100 when switching back
457
458 reset:  cli
459         jmp     $8000                   ; BASIC cold start
460 reset_size = * - reset
461
462 ; ------------------------------------------------------------------------
463 ; Code for a few simpler kernal calls goes here
464
465 k_iobase:
466         ldx     cia2
467         ldy     cia2+1
468         rts
469
470 k_screen:
471         ldx     #40             ; Columns
472         ldy     #25             ; Lines
473         rts
474
475 k_setlfs:
476         sta     LogicalAdr
477         stx     FirstAdr
478         sty     SecondAdr
479         rts
480
481 k_setnam:
482         sta     FileNameLen
483         lda     $00,x
484         sta     FileNameAdrLo
485         lda     $01,x
486         sta     FileNameAdrHi
487         lda     $02,x
488         sta     FileNameAdrSeg
489         rts
490
491 k_rdtim:
492         sei
493         lda     time+0
494         ldx     time+1
495         ldy     time+2
496         cli
497         rts
498
499 k_settim:
500         sei
501         sta     time+0
502         stx     time+1
503         sty     time+2
504         cli
505         rts
506
507 ; -------------------------------------------------------------------------
508 ; Data area - switch back to relocatable mode
509
510         .reloc
511
512 .data
513 spsave: .res    1
514 vidsave:.res    3
515
516