]> git.sur5r.net Git - cc65/blob - libsrc/cbm610/crt0.s
e14596d32ce21abe075ed50bb377d31295220f0e
[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, UDTIM
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
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 ; The code in the target bank when switching back will be put at the bottom
59 ; of the stack. We will jump here to switch segments. The range $F2..$FF is
60 ; not used by any kernal routine.
61
62 .segment        "STARTUP"
63
64 Back:   sei
65         ldx     spsave
66         txs
67         lda     IndReg
68         sta     ExecReg
69
70 ;------------------------------------------------------------------------------
71 ; We are at $100 now. The following snippet is a copy of the code that is poked
72 ; in the system bank memory by the basic header program, it's only for
73 ; documentation and not actually used here:
74
75         sei
76         lda     #$01
77         sta     ExecReg
78
79 ; This is the actual starting point of our code after switching banks for
80 ; startup. Beware: The following code will get overwritten as soon as we
81 ; use the stack (since it's in page 1)! We jump to another location, since
82 ; we need some space for subroutines that aren't used later.
83
84         jmp     Origin
85
86 ; Hardware vectors, copied to $FFFA
87
88 .proc   vectors
89         sta     ExecReg
90         rts
91         nop
92         .word   nmi             ; NMI vector
93         .word   0               ; Reset - not used
94         .word   irq             ; IRQ vector
95 .endproc
96
97 ; Initializers for the extended zeropage. See extzp.s
98
99 .proc   extzp
100         .word   $0100           ; sysp1
101         .word   $0300           ; sysp3
102         .word   $d800           ; crtc
103         .word   $da00           ; sid
104         .word   $db00           ; ipccia
105         .word   $dc00           ; cia
106         .word   $dd00           ; acia
107         .word   $de00           ; tpi1
108         .word   $df00           ; tpi2
109         .word   $ea29           ; ktab1
110         .word   $ea89           ; ktab2
111         .word   $eae9           ; ktab3
112         .word   $eb49           ; ktab4
113 .endproc
114
115 ; The following code is part of the kernal call subroutine. It is copied
116 ; to $FFAE
117
118 .proc   callsysbank_15
119         php
120         pha
121         lda     #$0F                    ; Bank 15
122         sta     IndReg
123         sei
124 .endproc
125
126 ; Save the old stack pointer from the system bank and setup our hw sp
127
128 Origin: tsx
129         stx     spsave          ; Save the system stackpointer
130         ldx     #$FE            ; Leave $1FF untouched for cross bank calls
131         txs                     ; Set up our own stack
132
133 ; Initialize the extended zeropage
134
135         ldx     #.sizeof(extzp)-1
136 L1:     lda     extzp,x
137         sta     <__EXTZP_RUN__,x
138         dex
139         bpl     L1
140
141 ; Set the interrupt, NMI and other vectors
142
143         ldy     #.sizeof(vectors)-1
144 L2:     lda     vectors,y
145         sta     $10000 - .sizeof(vectors),y
146         dey
147         bpl     L2
148
149 ; Switch the indirect segment to the system bank
150
151         lda     #$0F
152         sta     IndReg
153
154 ; Setup the C stack
155
156         lda     #.lobyte($FEB5 - .sizeof(callsysbank_15))
157         sta     sp
158         lda     #.hibyte($FEB5 - .sizeof(callsysbank_15))
159         sta     sp+1
160
161 ; Setup the subroutine and jump vector table that redirects kernal calls to
162 ; the system bank. Copy the bank switch routines starting at $FEB5 from the
163 ; system bank into the current bank.
164
165
166         ldy     #.sizeof(callsysbank_15)-1      ; Copy the modified part
167 @L1:    lda     callsysbank_15,y
168         sta     $FEB5 - .sizeof(callsysbank_15),y
169         dey
170         bpl     @L1
171
172         lda     #.lobyte($FEB5)                 ; Copy the ROM part
173         sta     ptr1
174         lda     #.hibyte($FEB5)
175         sta     ptr1+1
176         ldy     #$00
177 @L2:    lda     (ptr1),y
178         sta     $FEB5,y
179         iny
180         cpy     #<($FF6F-$FEB5)
181         bne     @L2
182
183 ; Setup the jump vector table
184
185         ldy     #$00
186         ldx     #45-1                   ; Number of vectors
187 @L3:    lda     #$20                    ; JSR opcode
188         sta     $FF6F,y
189         iny
190         lda     #.lobyte($FEB5 - .sizeof(callsysbank_15))
191         sta     $FF6F,y
192         iny
193         lda     #.hibyte($FEB5 - .sizeof(callsysbank_15))
194         sta     $FF6F,y
195         iny
196         dex
197         bpl     @L3
198
199 ; Copy the stack from the system bank into page 3
200
201         ldy     #$FF
202 L4:     lda     (sysp1),y
203         sta     $300,y
204         dey
205         cpy     spsave
206         bne     L4
207
208 ; Set the indirect segment to bank we're executing in
209
210         lda     ExecReg
211         sta     IndReg
212
213 ; Zero the BSS segment. We will do that here instead calling the routine
214 ; in the common library, since we have the memory anyway, and this way,
215 ; it's reused later.
216
217         lda     #<__BSS_RUN__
218         sta     ptr1
219         lda     #>__BSS_RUN__
220         sta     ptr1+1
221         lda     #0
222         tay
223
224 ; Clear full pages
225
226         ldx     #>__BSS_SIZE__
227         beq     Z2
228 Z1:     sta     (ptr1),y
229         iny
230         bne     Z1
231         inc     ptr1+1                  ; Next page
232         dex
233         bne     Z1
234
235 ; Clear the remaining page
236
237 Z2:     ldx     #<__BSS_SIZE__
238         beq     Z4
239 Z3:     sta     (ptr1),y
240         iny
241         dex
242         bne     Z3
243 Z4:     jmp     Init
244
245 ; ------------------------------------------------------------------------
246 ; We are at $200 now. We may now start calling subroutines safely, since
247 ; the code we execute is no longer in the stack page.
248
249 .segment        "PAGE2"
250
251 ; Call module constructors, enable chained IRQs afterwards.
252
253 Init:   jsr     initlib
254         lda     #.lobyte(__IRQFUNC_COUNT__*2)
255         sta     irqcount
256
257 ; Enable interrupts
258
259         cli
260
261 ; Push arguments and call main()
262
263         jsr     callmain
264
265 ; Disable Call module destructors. This is also the _exit entry and the default entry
266 ; point for the break vector.
267
268 _exit:  lda     #$00
269         sta     irqcount        ; Disable custom irq handlers
270         jsr     donelib         ; Run module destructors
271
272 ; Adress the system bank
273
274         lda     #$0F
275         sta     IndReg
276
277 ; Copy back the old system bank stack contents
278
279         ldy     #$FF
280 @L1:    lda     $300,y
281         sta     (sysp1),y
282         dey
283         cpy     spsave
284         bne     @L1
285
286 ; Setup the welcome code at the stack bottom in the system bank.
287
288         ldy     #$00
289         lda     #$58            ; CLI opcode
290         sta     (sysp1),y
291         iny
292         lda     #$60            ; RTS opcode
293         sta     (sysp1),y
294         jmp     Back
295
296 ; -------------------------------------------------------------------------
297 ; The IRQ handler goes into PAGE2. For performance reasons, and to allow
298 ; easier chaining, we do handle the IRQs in the execution bank (instead of
299 ; passing them to the system bank).
300
301 ; This is the mapping of the active irq register of the 6525 (tpi1):
302 ;
303 ; Bit   7       6       5       4       3       2       1       0
304 ;                               |       |       |       |       ^ 50 Hz
305 ;                               |       |       |       ^ SRQ IEEE 488
306 ;                               |       |       ^ cia
307 ;                               |       ^ IRQB ext. Port
308 ;                               ^ acia
309
310 irq:    pha
311         txa
312         pha
313         tya
314         pha
315         lda     IndReg
316         pha
317         lda     ExecReg
318         sta     IndReg                  ; Be sure to address our segment
319         tsx
320         lda     $105,x                  ; Get the flags from the stack
321         and     #$10                    ; Test break flag
322         bne     dobrk
323
324 ; It's an IRQ
325
326         cld
327
328 ; Call chained IRQ handlers
329
330         ldy     irqcount
331         beq     irqskip
332         lda     #<__IRQFUNC_TABLE__
333         ldx     #>__IRQFUNC_TABLE__
334         jsr     condes                  ; Call the functions
335
336 ; Done with chained IRQ handlers, check the TPI for IRQs and handle them
337
338 irqskip:lda     #$0F
339         sta     IndReg
340         ldy     #TPI::AIR
341         lda     (tpi1),y                ; Interrupt Register 6525
342         beq     noirq
343
344 ; 50/60Hz interrupt
345
346         cmp     #%00000001              ; ticker irq?
347         bne     irqend
348         jsr     SCNKEY                  ; Poll the keyboard
349         jsr     UDTIM                   ; Bump the time
350
351 ; Done
352
353 irqend: ldy     #TPI::AIR
354         sta     (tpi1),y                ; Clear interrupt
355
356 noirq:  pla
357         sta     IndReg
358         pla
359         tay
360         pla
361         tax
362         pla
363 nmi:    rti
364
365 dobrk:  jmp     (BRKVec)
366
367 ; -------------------------------------------------------------------------
368 ; udtim routine for the 610. We will not check for the stop key here, since
369 ; C programs will not use it.
370 ;
371
372 .proc   UDTIM
373
374         inc     time
375         bne     L9
376         inc     time+1
377         bne     L9
378         inc     time+2
379         bne     L9
380         inc     time+3
381 L9:     rts
382
383 .endproc
384
385 ; -------------------------------------------------------------------------
386 ; Page 3
387
388 .segment        "PAGE3"
389
390 BRKVec: .addr   _exit           ; BRK indirect vector
391
392
393 ; -------------------------------------------------------------------------
394 ; Data area.
395
396 .data
397 spsave: .res    1
398
399 .bss
400 irqcount:       .byte   0
401