2 ; Startup code for cc65 (Apple2 version)
5 .export _exit, done, return
6 .export __STARTUP__ : absolute = 1 ; Mark as startup
8 .import initlib, donelib
9 .import callmain, callirq
10 .import __RAM_START__ , __RAM_LAST__ ; Linker generated
11 .import __MOVE_START__, __MOVE_LAST__ ; Linker generated
12 .import __LC_START__ , __LC_LAST__ ; Linker generated
13 .import __ZPSAVE_RUN__, __INIT_SIZE__ ; Linker generated
14 .import __INTERRUPTOR_COUNT__ ; Linker generated
16 .include "zeropage.inc"
21 ; ------------------------------------------------------------------------
25 .addr __RAM_START__ ; Start address
26 .word __ZPSAVE_RUN__ - __RAM_START__ + \
27 __MOVE_LAST__ - __MOVE_START__ ; Size
29 ; ------------------------------------------------------------------------
33 ; ProDOS TechRefMan, chapter 5.2.1:
34 ; "For maximum interrupt efficiency, a system program should not
35 ; use more than the upper 3/4 of the stack."
37 txs ; Init stack pointer
39 ; Switch in LC bank 2 for W/O
43 ; Set source start address
44 lda #<(__ZPSAVE_RUN__ + __INIT_SIZE__)
45 ldy #>(__ZPSAVE_RUN__ + __INIT_SIZE__)
49 ; Set source last address
50 lda #<(__ZPSAVE_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
51 ldy #>(__ZPSAVE_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
55 ; Set destination last address
61 ; Call into Applesoft Block Transfer Utility - which handles zero
62 ; sized blocks well - to move content of the LC memory area
65 ; Set source start address
71 ; Set source last address
72 lda #<(__ZPSAVE_RUN__ + __INIT_SIZE__)
73 ldy #>(__ZPSAVE_RUN__ + __INIT_SIZE__)
77 ; Set destination last address
83 ; Call into Applesoft Block Transfer Utility - which handles moving
84 ; overlapping blocks upwards well - to move the INIT segment
87 ; Delegate all further processing to keep the STARTUP segment small
90 ; Avoid re-entrance of donelib. This is also the _exit entry
93 jsr reset ; Setup RESET vector
95 ; Switch in ROM in case it wasn't already switched in by a RESET
98 ; Call module destructors
101 ; Check for valid interrupt vector table entry number
105 ; Deallocate interrupt vector table entry
106 dec i_param ; Adjust parameter count
107 jsr $BF00 ; MLI call entry point
108 .byte $41 ; Dealloc interrupt
111 ; Restore the original RESET vector
118 ; Copy back the zero page stuff
125 ; ProDOS TechRefMan, chapter 5.2.1:
126 ; "System programs should set the stack pointer to $FF at the
127 ; warm-start entry point."
129 txs ; Re-init stack pointer
134 ; ------------------------------------------------------------------------
138 ; Save the zero page locations we need
148 ; Save the original RESET vector
155 ; ProDOS TechRefMan, chapter 5.3.5:
156 ; "Your system program should place in the RESET vector the
157 ; address of a routine that ... closes the files."
160 jsr reset ; Setup RESET vector
163 ldy $BF00 ; MLI call entry point
164 cpy #$4C ; Is MLI present? (JMP opcode)
167 ; Check ProDOS system bit map
168 lda $BF6F ; protection for pages $B8 - $BF
169 cmp #%00000001 ; exactly system global page is protected
172 ; No BASIC.SYSTEM so quit to ProDOS dispatcher instead
178 ; No BASIC.SYSTEM so use addr of ProDOS system global page
181 bne :+ ; Branch always
183 ; Get highest available mem addr from BASIC interpreter
191 ; Check for interruptors
192 lda #<__INTERRUPTOR_COUNT__
196 cpy #$4C ; Is MLI present? (JMP opcode)
199 ; Allocate interrupt vector table entry
200 jsr $BF00 ; MLI call entry point
201 .byte $40 ; Alloc interrupt
205 ; Enable interrupts as old ProDOS versions (i.e. 1.1.1)
206 ; jump to SYS and BIN programs with interrupts disabled
209 ; Call module constructors
212 ; Switch in LC bank 2 for R/O
215 ; Push arguments and call main()
218 ; Print error message and return
219 prterr: ldx #msglen-1
226 errmsg: .ifdef __APPLE2ENH__
227 .byte $8D, 't'|$80, 'p'|$80, 'u'|$80, 'r'|$80, 'r'|$80
228 .byte 'e'|$80, 't'|$80, 'n'|$80, 'i'|$80, ' '|$80, 'c'|$80
229 .byte 'o'|$80, 'l'|$80, 'l'|$80, 'a'|$80, ' '|$80, 'o'|$80
230 .byte 't'|$80, ' '|$80, 'd'|$80, 'e'|$80, 'l'|$80, 'i'|$80
231 .byte 'a'|$80, 'F'|$80, $8D
233 .byte $8D, 'T'|$80, 'P'|$80, 'U'|$80, 'R'|$80, 'R'|$80
234 .byte 'E'|$80, 'T'|$80, 'N'|$80, 'I'|$80, ' '|$80, 'C'|$80
235 .byte 'O'|$80, 'L'|$80, 'L'|$80, 'A'|$80, ' '|$80, 'O'|$80
236 .byte 'T'|$80, ' '|$80, 'D'|$80, 'E'|$80, 'L'|$80, 'I'|$80
237 .byte 'A'|$80, 'F'|$80, $8D
242 ; ------------------------------------------------------------------------
246 ; ProDOS TechRefMan, chapter 6.2:
247 ; "Each installed routine must begin with a CLD instruction."
250 ; Call interruptors and check for success
254 ; ProDOS TechRefMan, chapter 6.2:
255 ; "When the routine that can process the interrupt is called, it
256 ; should ... return (via an RTS) with the carry flag clear."
260 ; ProDOS TechRefMan, chapter 6.2:
261 ; "When a routine that cannot process the interrupt is called,
262 ; it should return (via an RTS) with the cary flag set ..."
273 ; Quit to ProDOS dispatcher
274 quit: jsr $BF00 ; MLI call entry point
278 ; ------------------------------------------------------------------------
282 ; MLI parameter list for quit
283 q_param:.byte $04 ; param_count
284 .byte $00 ; quit_type
285 .word $0000 ; reserved
287 .word $0000 ; reserved
289 ; ------------------------------------------------------------------------
293 ; MLI parameter list for (de)alloc interrupt
294 i_param:.byte $02 ; param_count
295 int_num:.byte $00 ; int_num
296 .addr intptr ; int_code
298 ; Location to jump to when we're done
301 ; ------------------------------------------------------------------------
307 ; ------------------------------------------------------------------------