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