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