]> git.sur5r.net Git - cc65/blob - libsrc/apple2/crt0.s
ba4e0dcf14a04c1c7aa81422c131a2079c1b7d75
[cc65] / libsrc / apple2 / crt0.s
1 ;
2 ; Oliver Schmidt, 2009-09-15
3 ;
4 ; Startup code for cc65 (Apple2 version)
5 ;
6
7         .export         _exit, done, return
8         .export         __STARTUP__ : absolute = 1      ; Mark as startup
9         .import         zerobss
10         .import         initlib, donelib
11         .import         callmain, callirq
12         .import         __LC_START__, __LC_LAST__       ; Linker generated
13         .import         __INIT_RUN__, __INIT_SIZE__     ; Linker generated
14         .import         __ZPSAVE_RUN__                  ; Linker generated
15         .import         __INTERRUPTOR_COUNT__           ; Linker generated
16
17         .include        "zeropage.inc"
18         .include        "apple2.inc"
19
20 ; ------------------------------------------------------------------------
21
22         .segment        "STARTUP"
23
24         ; ProDOS TechRefMan, chapter 5.2.1:
25         ; "For maximum interrupt efficiency, a system program should not
26         ;  use more than the upper 3/4 of the stack."
27         ldx     #$FF
28         txs                     ; Init stack pointer
29
30         ; Switch in LC bank 2 for W/O
31         bit     $C081
32         bit     $C081
33
34         ; Set source start address
35         lda     #<(__ZPSAVE_RUN__ + __INIT_SIZE__)
36         ldy     #>(__ZPSAVE_RUN__ + __INIT_SIZE__)
37         sta     $9B
38         sty     $9C
39
40         ; Set source last address
41         lda     #<(__ZPSAVE_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
42         ldy     #>(__ZPSAVE_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
43         sta     $96
44         sty     $97
45
46         ; Set destination last address
47         lda     #<__LC_LAST__
48         ldy     #>__LC_LAST__
49         sta     $94
50         sty     $95
51
52         ; Call into Applesoft Block Transfer Utility - which handles zero
53         ; sized blocks well - to move content of the LC memory area
54         jsr     $D396           ; BLTU + 3
55
56         ; Set source start address
57         lda     #<__ZPSAVE_RUN__
58         ldy     #>__ZPSAVE_RUN__
59         sta     $9B
60         sty     $9C
61
62         ; Set source last address
63         lda     #<(__ZPSAVE_RUN__ + __INIT_SIZE__)
64         ldy     #>(__ZPSAVE_RUN__ + __INIT_SIZE__)
65         sta     $96
66         sty     $97
67
68         ; Set destination last address
69         lda     #<(__INIT_RUN__ + __INIT_SIZE__)
70         ldy     #>(__INIT_RUN__ + __INIT_SIZE__)
71         sta     $94
72         sty     $95
73
74         ; Call into Applesoft Block Transfer Utility - which handles moving
75         ; overlapping blocks upwards well - to move the INIT segment
76         jsr     $D396           ; BLTU + 3
77
78         ; Delegate all further processing to keep the STARTUP segment small
79         jsr     init
80
81         ; Avoid re-entrance of donelib. This is also the _exit entry
82 _exit:  ldx     #<exit
83         lda     #>exit
84         jsr     reset           ; Setup RESET vector
85
86         ; Switch in ROM in case it wasn't already switched in by a RESET
87         bit     $C082
88
89         ; Call module destructors
90         jsr     donelib
91
92         ; Check for valid interrupt vector table entry number
93         lda     int_num
94         beq     exit
95
96         ; Deallocate interrupt vector table entry
97         dec     i_param         ; Adjust parameter count
98         jsr     $BF00           ; MLI call entry point
99         .byte   $41             ; Dealloc interrupt
100         .addr   i_param
101
102         ; Restore the original RESET vector
103 exit:   ldx     #$02
104 :       lda     rvsave,x
105         sta     SOFTEV,x
106         dex
107         bpl     :-
108
109         ; Copy back the zero page stuff
110         ldx     #zpspace-1
111 :       lda     zpsave,x
112         sta     sp,x
113         dex
114         bpl     :-
115
116         ; ProDOS TechRefMan, chapter 5.2.1:
117         ; "System programs should set the stack pointer to $FF at the
118         ;  warm-start entry point."
119         ldx     #$FF
120         txs                     ; Re-init stack pointer
121
122         ; We're done
123         jmp     (done)
124
125 ; ------------------------------------------------------------------------
126
127         .segment        "INIT"
128
129         ; Save the zero page locations we need
130 init:   ldx     #zpspace-1
131 :       lda     sp,x
132         sta     zpsave,x
133         dex
134         bpl     :-
135
136         ; Clear the BSS data
137         jsr     zerobss
138
139         ; Save the original RESET vector
140         ldx     #$02
141 :       lda     SOFTEV,x
142         sta     rvsave,x
143         dex
144         bpl     :-
145
146         ; ProDOS TechRefMan, chapter 5.3.5:
147         ; "Your system program should place in the RESET vector the
148         ;  address of a routine that ... closes the files."
149         ldx     #<_exit
150         lda     #>_exit
151         jsr     reset           ; Setup RESET vector
152
153         ; Check for ProDOS
154         ldy     $BF00           ; MLI call entry point
155         cpy     #$4C            ; Is MLI present? (JMP opcode)
156         bne     basic
157         
158         ; Check ProDOS system bit map
159         lda     $BF6F           ; Protection for pages $B8 - $BF
160         cmp     #%00000001      ; Exactly system global page is protected
161         bne     basic
162
163         ; No BASIC.SYSTEM so quit to ProDOS dispatcher instead
164         lda     #<quit
165         ldx     #>quit
166         sta     done
167         stx     done+1
168         
169         ; No BASIC.SYSTEM so use addr of ProDOS system global page
170         lda     #<$BF00
171         ldx     #>$BF00
172         bne     :+              ; Branch always
173
174         ; Get highest available mem addr from BASIC interpreter
175 basic:  lda     HIMEM
176         ldx     HIMEM+1
177
178         ; Setup the C stack
179 :       sta     sp
180         stx     sp+1
181
182         ; Check for interruptors
183         lda     #<__INTERRUPTOR_COUNT__
184         beq     :+
185
186         ; Check for ProDOS
187         cpy     #$4C            ; Is MLI present? (JMP opcode)
188         bne     prterr
189
190         ; Allocate interrupt vector table entry
191         jsr     $BF00           ; MLI call entry point
192         .byte   $40             ; Alloc interrupt
193         .addr   i_param
194         bcs     prterr
195
196         ; Enable interrupts as old ProDOS versions (i.e. 1.1.1)
197         ; jump to SYS and BIN programs with interrupts disabled
198         cli
199
200         ; Call module constructors
201 :       jsr     initlib
202
203         ; Switch in LC bank 2 for R/O
204         bit     $C080
205
206         ; Push arguments and call main()
207         jmp     callmain
208
209         ; Print error message and return
210 prterr: ldx     #msglen-1
211 :       lda     errmsg,x
212         jsr     $FDED           ; COUT
213         dex
214         bpl     :-
215         rts
216
217 errmsg: .ifdef  __APPLE2ENH__
218         .byte   $8D,     't'|$80, 'p'|$80, 'u'|$80, 'r'|$80, 'r'|$80
219         .byte   'e'|$80, 't'|$80, 'n'|$80, 'i'|$80, ' '|$80, 'c'|$80
220         .byte   'o'|$80, 'l'|$80, 'l'|$80, 'a'|$80, ' '|$80, 'o'|$80
221         .byte   't'|$80, ' '|$80, 'd'|$80, 'e'|$80, 'l'|$80, 'i'|$80
222         .byte   'a'|$80, 'F'|$80, $8D
223         .else
224         .byte   $8D,     'T'|$80, 'P'|$80, 'U'|$80, 'R'|$80, 'R'|$80
225         .byte   'E'|$80, 'T'|$80, 'N'|$80, 'I'|$80, ' '|$80, 'C'|$80
226         .byte   'O'|$80, 'L'|$80, 'L'|$80, 'A'|$80, ' '|$80, 'O'|$80
227         .byte   'T'|$80, ' '|$80, 'D'|$80, 'E'|$80, 'L'|$80, 'I'|$80
228         .byte   'A'|$80, 'F'|$80, $8D
229         .endif
230
231 msglen = * - errmsg
232
233 ; ------------------------------------------------------------------------
234
235         .segment        "LOWCODE"
236
237         ; ProDOS TechRefMan, chapter 6.2:
238         ; "Each installed routine must begin with a CLD instruction."
239 intptr: cld
240
241         ; Call interruptors and check for success
242         jsr     callirq
243         bcc     :+
244
245         ; ProDOS TechRefMan, chapter 6.2:
246         ; "When the routine that can process the interrupt is called, it
247         ;  should ... return (via an RTS) with the carry flag clear."
248         clc
249         rts
250
251         ; ProDOS TechRefMan, chapter 6.2:
252         ; "When a routine that cannot process the interrupt is called,
253         ;  it should return (via an RTS) with the cary flag set ..."
254 :       sec
255         rts
256
257         ; Setup RESET vector
258 reset:  stx     SOFTEV
259         sta     SOFTEV+1
260         eor     #$A5
261         sta     PWREDUP
262 return: rts
263
264         ; Quit to ProDOS dispatcher
265 quit:   jsr     $BF00           ; MLI call entry point
266         .byte   $65             ; Quit
267         .word   q_param
268
269 ; ------------------------------------------------------------------------
270
271         .rodata
272
273         ; MLI parameter list for quit        
274 q_param:.byte   $04             ; param_count
275         .byte   $00             ; quit_type
276         .word   $0000           ; reserved
277         .byte   $00             ; reserved
278         .word   $0000           ; reserved
279         
280 ; ------------------------------------------------------------------------
281
282         .data
283
284         ; MLI parameter list for (de)alloc interrupt
285 i_param:.byte   $02             ; param_count
286 int_num:.byte   $00             ; int_num
287         .addr   intptr          ; int_code
288
289         ; Location to jump to when we're done
290 done:   .addr   DOSWARM
291
292 ; ------------------------------------------------------------------------
293
294         .segment        "ZPSAVE"
295
296 zpsave: .res    zpspace
297
298 ; ------------------------------------------------------------------------
299
300         .bss
301
302 rvsave: .res    3