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