]> git.sur5r.net Git - cc65/blobdiff - libsrc/apple2/crt0.s
ld65: implement '--allow-multiple-definition' command line parameter
[cc65] / libsrc / apple2 / crt0.s
index bd2c9d83621d7627575625cbc69634fb9aec328a..60a8516d1f9188f4a1d0c3b956817106f5e9014d 100644 (file)
@@ -1,27 +1,19 @@
 ;
-; Startup code for cc65 (Apple2 version)
+; Oliver Schmidt, 2009-09-15
 ;
-; This must be the *first* file on the linker command line
+; Startup code for cc65 (Apple2 version)
 ;
 
-        .export         _exit
-        .import         zerobss
-        .import        initlib, donelib
-        .import        callmain, callirq
-        .import         COUT
-        .import                __STARTUP_LOAD__, __BSS_LOAD__  ; Linker generated
-        .import                __INTERRUPTOR_COUNT__           ; Linker generated
+        .export         _exit, done, return
+        .export         __STARTUP__ : absolute = 1      ; Mark as startup
+
+        .import         initlib, donelib
+        .import         zerobss, callmain
+        .import         __ONCE_LOAD__, __ONCE_SIZE__    ; Linker generated
+        .import         __LC_START__, __LC_LAST__       ; Linker generated
 
         .include        "zeropage.inc"
         .include        "apple2.inc"
-        .include        "mli.inc"
-
-; ------------------------------------------------------------------------
-
-        .segment        "EXEHDR"
-
-        .addr           __STARTUP_LOAD__                ; Start address
-        .word           __BSS_LOAD__ - __STARTUP_LOAD__        ; Size
 
 ; ------------------------------------------------------------------------
 
         ; "For maximum interrupt efficiency, a system program should not
         ;  use more than the upper 3/4 of the stack."
         ldx     #$FF
-        txs                            ; Init stack pointer
+        txs                     ; Init stack pointer
 
-        ; Delegate all further processing to keep STARTUP small
+        ; Save space by putting some of the start-up code in the ONCE segment,
+        ; which can be re-used by the BSS segment, the heap and the C stack.
         jsr     init
 
-        ; Avoid re-entrance of donelib. This is also the _exit entry
+        ; Clear the BSS data.
+        jsr     zerobss
+
+        ; Push the command-line arguments; and, call main().
+        jsr     callmain
+
+        ; Avoid a re-entrance of donelib. This is also the exit() entry.
 _exit:  ldx     #<exit
         lda     #>exit
-        jsr     reset          ; Setup RESET vector
-
-        ; Check for valid interrupt vector table entry number
-        lda     intnum
-        beq     :+
+        jsr     reset           ; Setup RESET vector
 
-        ; Deallocate interrupt vector table entry
-        dec     params         ; Adjust parameter count
-        jsr     ENTRY
-        .byte   $41            ; Dealloc interrupt
-        .addr   params
+        ; Switch in ROM, in case it wasn't already switched in by a RESET.
+        bit     $C082
 
-        ; Call module destructors
-:       jsr     donelib
+        ; Call the module destructors.
+        jsr     donelib
 
-        ; Restore the original RESET vector
+        ; Restore the original RESET vector.
 exit:   ldx     #$02
 :       lda     rvsave,x
         sta     SOFTEV,x
         dex
         bpl     :-
 
-        ; Copy back the zero page stuff
+        ; Copy back the zero-page stuff.
         ldx     #zpspace-1
 :       lda     zpsave,x
         sta     sp,x
@@ -74,131 +66,136 @@ exit:   ldx     #$02
         ldx     #$FF
         txs                     ; Re-init stack pointer
 
-        ; Back to DOS
-        jmp     DOSWARM
+        ; We're done
+        jmp     done
 
 ; ------------------------------------------------------------------------
 
-        .segment        "INIT"
+        .segment        "ONCE"
 
-        ; Save the zero page locations we need
+        ; Save the zero-page locations that we need.
 init:   ldx     #zpspace-1
 :       lda     sp,x
         sta     zpsave,x
         dex
         bpl     :-
 
-        ; Save the original RESET vector
+        ; Save the original RESET vector.
         ldx     #$02
 :       lda     SOFTEV,x
         sta     rvsave,x
         dex
         bpl     :-
 
+        ; Check for ProDOS.
+        ldy     $BF00           ; MLI call entry point
+        cpy     #$4C            ; Is MLI present? (JMP opcode)
+        bne     basic
+
+        ; Check the ProDOS system bit map.
+        lda     $BF6F           ; Protection for pages $B8 - $BF
+        cmp     #%00000001      ; Exactly system global page is protected
+        bne     basic
+
+        ; No BASIC.SYSTEM; so, quit to the ProDOS dispatcher instead.
+        lda     #<quit
+        ldx     #>quit
+        sta     done+1
+        stx     done+2
+
+        ; No BASIC.SYSTEM; so, use the addr of the ProDOS system global page.
+        lda     #<$BF00
+        ldx     #>$BF00
+        bne     :+              ; Branch always
+
+        ; Get the highest available mem addr from the BASIC interpreter.
+basic:  lda     HIMEM
+        ldx     HIMEM+1
+
+        ; Set up the C stack.
+:       sta     sp
+        stx     sp+1
+
         ; ProDOS TechRefMan, chapter 5.3.5:
         ; "Your system program should place in the RESET vector the
         ;  address of a routine that ... closes the files."
         ldx     #<_exit
         lda     #>_exit
-        jsr     reset          ; Setup RESET vector
-                
-        ; Clear the BSS data
-        jsr     zerobss
-
-        ; Setup the stack
-        lda     HIMEM
-        sta     sp
-        lda     HIMEM+1
-        sta     sp+1                   ; Set argument stack ptr
+        jsr     reset           ; Setup RESET vector
 
-        ; Call module constructors
+        ; Call the module constructors.
         jsr     initlib
 
-        ; Check for interruptors
-        lda     #<__INTERRUPTOR_COUNT__
-        beq     :+
-
-        ; Check for ProDOS
-        lda     ENTRY
-        cmp     #$4C           ; Is MLI present? (JMP opcode)
-        bne     prterr
-
-        ; Allocate interrupt vector table entry
-        jsr     ENTRY
-        .byte   $40            ; Alloc interrupt
-        .addr   params
-        bcs     prterr
-
-        ; Push arguments and call main()
-:       jmp     callmain
-
-        ; Print error message and return
-prterr: ldx     #msglen-1
-:       lda     errmsg,x
-        jsr     COUT
-        dex
-        bpl     :-
+        ; Switch in LC bank 2 for W/O.
+        bit     $C081
+        bit     $C081
+
+        ; Set the source start address.
+        ; Aka __LC_LOAD__ iff segment LC exists.
+        lda     #<(__ONCE_LOAD__ + __ONCE_SIZE__)
+        ldy     #>(__ONCE_LOAD__ + __ONCE_SIZE__)
+        sta     $9B
+        sty     $9C
+
+        ; Set the source last address.
+        ; Aka __LC_LOAD__ + __LC_SIZE__ iff segment LC exists.
+        lda     #<((__ONCE_LOAD__ + __ONCE_SIZE__) + (__LC_LAST__ - __LC_START__))
+        ldy     #>((__ONCE_LOAD__ + __ONCE_SIZE__) + (__LC_LAST__ - __LC_START__))
+        sta     $96
+        sty     $97
+
+        ; Set the destination last address.
+        ; Aka __LC_RUN__ + __LC_SIZE__ iff segment LC exists.
+        lda     #<__LC_LAST__
+        ldy     #>__LC_LAST__
+        sta     $94
+        sty     $95
+
+        ; Call into Applesoft Block Transfer Up -- which handles zero-
+        ; sized blocks well -- to move the content of the LC memory area.
+        jsr     $D39A           ; BLTU2
+
+        ; Switch in LC bank 2 for R/O and return.
+        bit     $C080
         rts
 
-errmsg: .ifdef  __APPLE2ENH__
-        .byte   $8D,     't'|$80, 'p'|$80, 'u'|$80, 'r'|$80, 'r'|$80
-        .byte   'e'|$80, 't'|$80, 'n'|$80, 'i'|$80, ' '|$80, 'c'|$80
-        .byte   'o'|$80, 'l'|$80, 'l'|$80, 'a'|$80, ' '|$80, 'o'|$80
-        .byte   't'|$80, ' '|$80, 'd'|$80, 'e'|$80, 'l'|$80, 'i'|$80
-        .byte   'a'|$80, 'F'|$80, $8D
-        .else
-        .byte   $8D,     'T'|$80, 'P'|$80, 'U'|$80, 'R'|$80, 'R'|$80
-        .byte   'E'|$80, 'T'|$80, 'N'|$80, 'I'|$80, ' '|$80, 'C'|$80
-        .byte   'O'|$80, 'L'|$80, 'L'|$80, 'A'|$80, ' '|$80, 'O'|$80
-        .byte   'T'|$80, ' '|$80, 'D'|$80, 'E'|$80, 'L'|$80, 'I'|$80
-        .byte   'A'|$80, 'F'|$80, $8D
-        .endif
-
-msglen = * - errmsg
-
 ; ------------------------------------------------------------------------
 
-        .segment        "LOWCODE"
+        .code
+
+        ; Set up the RESET vector.
+reset:  stx     SOFTEV
+        sta     SOFTEV+1
+        eor     #$A5
+        sta     PWREDUP
+return: rts
 
-        ; ProDOS TechRefMan, chapter 6.2:
-        ; "Each installed routine must begin with a CLD instruction."
-intrpt: cld
+        ; Quit to the ProDOS dispatcher.
+quit:   jsr     $BF00           ; MLI call entry point
+        .byte   $65             ; Quit
+        .word   q_param
 
-        ; Call interruptors and check for success
-        jsr     callirq
-        bcc    :+
+; ------------------------------------------------------------------------
 
-        ; ProDOS TechRefMan, chapter 6.2:
-        ; "When the routine that can process the interrupt is called, it
-        ;  should ... return (via an RTS) with the carry flag clear."
-        clc
-        rts
+        .rodata
 
-        ; ProDOS TechRefMan, chapter 6.2:
-        ; "When a routine that cannot process the interrupt is called,
-        ;  it should return (via an RTS) with the cary flag set ..."
-:       sec
-        rts
+        ; MLI parameter list for quit
+q_param:.byte   $04             ; param_count
+        .byte   $00             ; quit_type
+        .word   $0000           ; reserved
+        .byte   $00             ; reserved
+        .word   $0000           ; reserved
 
 ; ------------------------------------------------------------------------
 
-        .code
+        .data
 
-        ; Setup RESET vector
-reset:  stx     SOFTEV
-        sta     SOFTEV+1
-        eor     #$A5
-        sta     PWREDUP
-        rts
+        ; Final jump when we're done
+done:   jmp     DOSWARM         ; Potentially patched at runtime
 
 ; ------------------------------------------------------------------------
 
-        .data
+        .segment        "INIT"
 
 zpsave: .res    zpspace
-
 rvsave: .res    3
-
-params: .byte   $02            ; Parameter count
-intnum: .byte   $00            ; Interrupt number
-        .addr   intrpt         ; Interrupt handler
\ No newline at end of file