]> git.sur5r.net Git - cc65/blob - libsrc/cbm610/crt0.s
Two fixes from Stefan Haubenthal
[cc65] / libsrc / cbm610 / crt0.s
1 ;
2 ; Startup code for cc65 (CBM 600/700 version)
3 ;
4 ; This must be the *first* file on the linker command line
5 ;
6
7         .export         _exit, BRKVec
8
9         .import         condes, initlib, donelib
10         .import         push0, callmain
11         .import         __BSS_RUN__, __BSS_SIZE__, __EXTZP_RUN__
12         .import         __IRQFUNC_TABLE__, __IRQFUNC_COUNT__
13         .import         scnkey, UDTIM
14
15         .include        "zeropage.inc"
16         .include        "extzp.inc"
17         .include        "cbm610.inc"
18
19
20 ; ------------------------------------------------------------------------
21 ; BASIC header and a small BASIC program. Since it is not possible to start
22 ; programs in other banks using SYS, the BASIC program will write a small
23 ; machine code program into memory at $100 and start that machine code
24 ; program. The machine code program will then start the machine language
25 ; code in bank 1, which will initialize the system by copying stuff from
26 ; the system bank, and start the application.
27 ;
28 ; Here's the basic program that's in the following lines:
29 ;
30 ; 10 for i=0 to 4
31 ; 20 read j
32 ; 30 poke 256+i,j
33 ; 40 next i
34 ; 50 sys 256
35 ; 60 data 120,169,1,133,0
36 ;
37 ; The machine program in the data lines is:
38 ;
39 ; sei
40 ; lda     #$01
41 ; sta     $00           <-- Switch to bank 1 after this command
42 ;
43 ; Initialization is not only complex because of the jumping from one bank
44 ; into another. but also because we want to save memory, and because of
45 ; this, we will use the system memory ($00-$3FF) for initialization stuff
46 ; that is overwritten later.
47 ;
48
49 .segment        "BASICHDR"
50
51         .byte   $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
52         .byte   $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
53         .byte   $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
54         .byte   $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
55         .byte   $30,$2c,$31,$36,$39,$2c,$31,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
56
57 ;------------------------------------------------------------------------------
58 ; A table that contains values that must be transfered from the system zero
59 ; page into out zero page. Contains pairs of bytes, first one is the address
60 ; in the system ZP, second one is our ZP address. The table goes into page 2,
61 ; but is declared here, because it is needed earlier.
62
63 .SEGMENT        "PAGE2"
64
65 .proc   transfer_table
66
67         .byte   $CA, CURS_Y
68         .byte   $CB, CURS_X
69         .byte   $CC, graphmode
70         .byte   $D4, config
71
72 .endproc
73
74
75 ;------------------------------------------------------------------------------
76 ; Page 3 data. This page contains the break vector and the bankswitch
77 ; subroutine that is copied into high memory on startup. The space occupied by
78 ; this routine will later be used for a copy of the bank 15 stack. It must be
79 ; saved, since we're going to destroy it when calling bank 15.
80
81 .segment        "PAGE3"
82
83 BRKVec: .addr   _exit           ; BRK indirect vector
84
85 .proc   callbank15
86
87         excrts  = $FF05
88
89 .org    $FECB
90
91 entry:  php
92         pha
93         lda     #$0F                    ; Bank 15
94         sta     IndReg
95         txa
96         pha
97         tya
98         pha
99         sei
100         ldy     #$FF
101         lda     (sysp1),y
102         tay
103         lda     ExecReg
104         sta     (sysp1),y
105         dey
106
107         lda     #.hibyte(excrts-1)
108         sta     (sysp1),y
109         dey
110         lda     #.lobyte(excrts-1)
111         sta     (sysp1),y
112
113         tya
114         sec
115         sbc     #7
116         sta     $1FF                    ; Save new sp
117         tay
118
119         tsx
120
121         pla
122         iny
123         sta     (sysp1),y
124         pla
125         iny
126         sta     (sysp1),y
127         pla
128         iny
129         sta     (sysp1),y
130         pla
131         iny
132         sta     (sysp1),y
133
134         lda     $105,x
135         sec
136         sbc     #3
137         iny
138         sta     (sysp1),y
139         lda     $106,x
140         sbc     #0
141         iny
142         sta     (sysp1),y
143
144         ldy     $1FF                    ; Restore sp in bank 15
145
146         lda     #.hibyte(expull-1)
147         sta     (sysp1),y
148         dey
149         lda     #.lobyte(expull-1)
150         sta     (sysp1),y
151         dey
152         pla
153         pla
154         tsx
155         stx     $1FF
156         tya
157         tax
158         txs
159         lda     IndReg
160         jmp     $FFF6
161
162 expull: pla
163         tay
164         pla
165         tax
166         pla
167         plp
168         rts
169
170 .if (expull <> $FF2E)
171 .error "Symbol expull must be aligned with kernal in bank 15"
172 .endif
173
174 .reloc
175
176 .endproc
177
178 ;------------------------------------------------------------------------------
179 ; The code in the target bank when switching back will be put at the bottom
180 ; of the stack. We will jump here to switch segments. The range $F2..$FF is
181 ; not used by any kernal routine.
182
183 .segment        "STARTUP"
184
185 Back:   sta     ExecReg
186
187 ; We are at $100 now. The following snippet is a copy of the code that is poked
188 ; in the system bank memory by the basic header program, it's only for
189 ; documentation and not actually used here:
190
191         sei
192         lda     #$01
193         sta     ExecReg
194
195 ; This is the actual starting point of our code after switching banks for
196 ; startup. Beware: The following code will get overwritten as soon as we
197 ; use the stack (since it's in page 1)! We jump to another location, since
198 ; we need some space for subroutines that aren't used later.
199
200         jmp     Origin
201
202 ; Hardware vectors, copied to $FFF6
203
204 .proc   vectors
205         sta     ExecReg
206         rts
207         nop
208         .word   nmi             ; NMI vector
209         .word   0               ; Reset - not used
210         .word   irq             ; IRQ vector
211 .endproc
212
213 ; Initializers for the extended zeropage. See extzp.s
214
215 .proc   extzp
216         .word   $0100           ; sysp1
217         .word   $0300           ; sysp3
218         .word   $d800           ; crtc
219         .word   $da00           ; sid
220         .word   $db00           ; ipccia
221         .word   $dc00           ; cia
222         .word   $dd00           ; acia
223         .word   $de00           ; tpi1
224         .word   $df00           ; tpi2
225         .word   $ea29           ; ktab1
226         .word   $ea89           ; ktab2
227         .word   $eae9           ; ktab3
228         .word   $eb49           ; ktab4
229 .endproc
230
231 ; Switch the indirect segment to the system bank
232
233 Origin: lda     #$0F
234         sta     IndReg
235
236 ; Initialize the extended zeropage
237
238         ldx     #.sizeof(extzp)-1
239 L1:     lda     extzp,x
240         sta     <__EXTZP_RUN__,x
241         dex
242         bpl     L1
243
244 ; Save the old stack pointer from the system bank and setup our hw sp
245
246         tsx
247         txa
248         ldy     #$FF
249         sta     (sysp1),y       ; Save system stack point into $F:$1FF
250         ldx     #$FE            ; Leave $1FF untouched for cross bank calls
251         txs                     ; Set up our own stack
252
253 ; Copy stuff from the system zeropage to ours
254
255         lda     #.sizeof(transfer_table)
256         sta     ktmp
257 L2:     ldx     ktmp
258         ldy     transfer_table-2,x
259         lda     transfer_table-1,x
260         tax
261         lda     (sysp0),y
262         sta     $00,x
263         dec     ktmp
264         dec     ktmp
265         bne     L2
266
267 ; Set the interrupt, NMI and other vectors
268
269         ldx     #.sizeof(vectors)-1
270 L3:     lda     vectors,x
271         sta     $10000 - .sizeof(vectors),x
272         dex
273         bpl     L3
274
275 ; Setup the C stack
276
277         lda     #.lobyte(callbank15::entry)
278         sta     sp
279         lda     #.hibyte(callbank15::entry)
280         sta     sp+1
281
282 ; Setup the subroutine and jump vector table that redirects kernal calls to
283 ; the system bank.
284
285         ldy     #.sizeof(callbank15)
286 @L1:    lda     callbank15-1,y
287         sta     callbank15::entry-1,y
288         dey
289         bne     @L1
290
291 ; Setup the jump vector table. Y is zero on entry.
292
293         ldx     #45-1                   ; Number of vectors
294 @L2:    lda     #$20                    ; JSR opcode
295         sta     $FF6F,y
296         iny
297         lda     #.lobyte(callbank15::entry)
298         sta     $FF6F,y
299         iny
300         lda     #.hibyte(callbank15::entry)
301         sta     $FF6F,y
302         iny
303         dex
304         bpl     @L2
305
306 ; Set the indirect segment to bank we're executing in
307
308         lda     ExecReg
309         sta     IndReg
310
311 ; Zero the BSS segment. We will do that here instead calling the routine
312 ; in the common library, since we have the memory anyway, and this way,
313 ; it's reused later.
314
315         lda     #<__BSS_RUN__
316         sta     ptr1
317         lda     #>__BSS_RUN__
318         sta     ptr1+1
319         lda     #0
320         tay
321
322 ; Clear full pages
323
324         ldx     #>__BSS_SIZE__
325         beq     Z2
326 Z1:     sta     (ptr1),y
327         iny
328         bne     Z1
329         inc     ptr1+1                  ; Next page
330         dex
331         bne     Z1
332
333 ; Clear the remaining page
334
335 Z2:     ldx     #<__BSS_SIZE__
336         beq     Z4
337 Z3:     sta     (ptr1),y
338         iny
339         dex
340         bne     Z3
341 Z4:     jmp     Init
342
343 ; ------------------------------------------------------------------------
344 ; We are at $200 now. We may now start calling subroutines safely, since
345 ; the code we execute is no longer in the stack page.
346
347 .segment        "PAGE2"
348
349 ; Call module constructors, enable chained IRQs afterwards.
350
351 Init:   jsr     initlib
352         lda     #.lobyte(__IRQFUNC_COUNT__*2)
353         sta     irqcount
354
355 ; Enable interrupts
356
357         cli
358
359 ; Push arguments and call main()
360
361         jsr     callmain
362
363 ; Call module destructors. This is also the _exit entry and the default entry
364 ; point for the break vector.
365
366 _exit:  lda     #$00
367         sta     irqcount        ; Disable custom irq handlers
368         jsr     donelib         ; Run module destructors
369
370 ; Address the system bank
371
372         lda     #$0F
373         sta     IndReg
374
375 ; Copy stuff back from our zeropage to the systems
376
377 .if 0
378         lda     #.sizeof(transfer_table)
379         sta     ktmp
380 @L0:    ldx     ktmp
381         ldy     transfer_table-2,x
382         lda     transfer_table-1,x
383         tax
384         lda     $00,x
385         sta     (sysp0),y
386         dec     ktmp
387         dec     ktmp
388         bne     @L0
389 .endif
390
391 ; Setup the welcome code at the stack bottom in the system bank.
392
393         ldy     #$FF
394         lda     (sysp1),y       ; Load system bank sp
395         tax
396         iny                     ; Y = 0
397         lda     #$58            ; CLI opcode
398         sta     (sysp1),y
399         iny
400         lda     #$60            ; RTS opcode
401         sta     (sysp1),y
402         lda     IndReg
403         sei
404         txs
405         jmp     Back
406
407 ; -------------------------------------------------------------------------
408 ; The IRQ handler goes into PAGE2. For performance reasons, and to allow
409 ; easier chaining, we do handle the IRQs in the execution bank (instead of
410 ; passing them to the system bank).
411
412 ; This is the mapping of the active irq register of the 6525 (tpi1):
413 ;
414 ; Bit   7       6       5       4       3       2       1       0
415 ;                               |       |       |       |       ^ 50 Hz
416 ;                               |       |       |       ^ SRQ IEEE 488
417 ;                               |       |       ^ cia
418 ;                               |       ^ IRQB ext. Port
419 ;                               ^ acia
420
421 irq:    pha
422         txa
423         pha
424         tya
425         pha
426         lda     IndReg
427         pha
428         lda     ExecReg
429         sta     IndReg                  ; Be sure to address our segment
430         tsx
431         lda     $105,x                  ; Get the flags from the stack
432         and     #$10                    ; Test break flag
433         bne     dobrk
434
435 ; It's an IRQ
436
437         cld
438
439 ; Call chained IRQ handlers
440
441         ldy     irqcount
442         beq     irqskip
443         lda     #<__IRQFUNC_TABLE__
444         ldx     #>__IRQFUNC_TABLE__
445         jsr     condes                  ; Call the functions
446
447 ; Done with chained IRQ handlers, check the TPI for IRQs and handle them
448
449 irqskip:lda     #$0F
450         sta     IndReg
451         ldy     #TPI::AIR
452         lda     (tpi1),y                ; Interrupt Register 6525
453         beq     noirq
454
455 ; 50/60Hz interrupt
456
457         cmp     #%00000001              ; ticker irq?
458         bne     irqend
459         jsr     scnkey                  ; Poll the keyboard
460         jsr     UDTIM                   ; Bump the time
461
462 ; Done
463
464 irqend: ldy     #TPI::AIR
465         sta     (tpi1),y                ; Clear interrupt
466
467 noirq:  pla
468         sta     IndReg
469         pla
470         tay
471         pla
472         tax
473         pla
474 nmi:    rti
475
476 dobrk:  jmp     (BRKVec)
477
478 ; -------------------------------------------------------------------------
479 ; Data area.
480
481 .bss
482 irqcount:       .byte   0
483