]> git.sur5r.net Git - cc65/blobdiff - libsrc/plus4/crt0.s
Replaced whole bunch for Makefiles with a single generic Makefile.
[cc65] / libsrc / plus4 / crt0.s
index 3146e36742a6fab4720e3392a5e53babef0d1a8a..73460d82b367d08ef5cbcd946ecc8db6ed8a2850 100644 (file)
@@ -1,15 +1,17 @@
 ;
 ; Startup code for cc65 (Plus/4 version)
-;
-; This must be the *first* file on the linker command line
 ;
 
        .export         _exit
         .export         brk_jmp
+        .export         __STARTUP__ : absolute = 1      ; Mark as startup
 
-       .import         condes, initlib, donelib
-       .import         push0, callmain, zerobss
-       .import         __IRQFUNC_TABLE__, __IRQFUNC_COUNT__
+       .import         callirq_y, initlib, donelib
+       .import         callmain, zerobss
+       .import         __INTERRUPTOR_COUNT__
+       .import         __RAM_START__, __RAM_SIZE__     ; Linker generated
+       .import         __STACKSIZE__                   ; Linker generated
+       .importzp       ST
 
         .include        "zeropage.inc"
        .include        "plus4.inc"
 IRQInd                 = $500  ; JMP $0000 - used as indirect IRQ vector
 
 ; ------------------------------------------------------------------------
-; Place the startup code in a special segment to cope with the quirks of
-; plus/4 banking.
+; Startup code
 
 .segment               "STARTUP"
 
-        .word   Head            ; Load address
-Head:   .word   @Next
-        .word   1000            ; Line number
-        .byte   $9E,"4109"     ; SYS 4109
-        .byte   $00             ; End of BASIC line
-@Next:  .word   0               ; BASIC end marker
+Start:
 
-; ------------------------------------------------------------------------
-; Actual code
+; Save the zero page locations we need
 
         sei                     ; No interrupts since we're banking out the ROM
         sta     ENABLE_RAM
                ldx     #zpspace-1
 L1:    lda     sp,x
-       sta     zpsave,x        ; save the zero page locations we need
-       dex
+       sta     zpsave,x
+       dex
                bpl     L1
         sta     ENABLE_ROM
         cli
 
-; Close open files
+; Switch to second charset
 
-       jsr     $FFCC           ; CLRCH
+       lda     #14
+       jsr     $FFD2           ; BSOUT
 
-; Switch to second charset
+; Save system stuff and setup the stack. The stack starts at the top of the
+; usable RAM.
+
+               tsx
+               stx     spsave          ; save system stk ptr
 
-       lda     #14
-       jsr     $FFD2           ; BSOUT
+        lda     #<(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
+        sta     sp
+        lda     #>(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
+        sta     sp+1
 
 ; Setup the IRQ vector in the banked RAM and switch off the ROM
 
+        ldx     #<IRQ
+        ldy     #>IRQ
         sei                     ; No ints, handler not yet in place
         sta     ENABLE_RAM
-        lda     #<IRQ
-        sta     $FFFE           ; Install interrupt handler
-        lda     #>IRQ
-        sta     $FFFF
+        stx     $FFFE           ; Install interrupt handler
+        sty     $FFFF
         cli                     ; Allow interrupts
 
 ; Clear the BSS data
 
-       jsr     zerobss
+       jsr     zerobss
 
-; Save system stuff and setup the stack. The stack starts at the top of the
-; usable RAM.
+; Initialize irqcount, which means that from now own custom linked in IRQ
+; handlers (via condes) will be called.
 
-               tsx
-               stx     spsave          ; save system stk ptr
-
-        lda     #<$FD00
-        sta     sp
-        lda     #>$FD00
-        sta     sp+1
+        lda     #.lobyte(__INTERRUPTOR_COUNT__*2)
+        sta     irqcount
 
 ; Call module constructors
 
-       jsr     initlib
-
-; If we have IRQ functions, chain our stub into the IRQ vector
-
-        lda     #<__IRQFUNC_COUNT__
-       beq     NoIRQ1
-       lda     IRQVec
-               ldx     IRQVec+1
-       sta     IRQInd+1
-       stx     IRQInd+2
-       lda     #<IRQStub
-       ldx     #>IRQStub
-       sei
-       sta     IRQVec
-       stx     IRQVec+1
-       cli
+       jsr     initlib
 
 ; Push arguments and call main()
 
-NoIRQ1: jsr            callmain
-
-; Back from main (this is also the _exit entry). Reset the IRQ vector if
-; we chained it.
-
-_exit:  lda     #<__IRQFUNC_COUNT__
-       beq     NoIRQ2
-       lda     IRQInd+1
-       ldx     IRQInd+2
-       sei
-       sta     IRQVec
-       stx     IRQVec+1
-       cli
+       jsr     callmain
 
-; Run module destructors.
+; Back from main (this is also the _exit entry). Run module destructors.
 
-NoIRQ2:        jsr     donelib         ; Run module destructors
+_exit:         pha                     ; Save the return code
+        jsr    donelib         ; Run module destructors
 
-; Restore system stuff
+; Disable chained IRQ handlers
 
-       ldx     spsave
-       txs
+       lda     #0
+        sta     irqcount        ; Disable custom IRQ handlers
 
 ; Copy back the zero page stuff
 
-       ldx     #zpspace-1
+       ldx     #zpspace-1
 L2:    lda     zpsave,x
-       sta     sp,x
-       dex
+       sta     sp,x
+       dex
                bpl     L2
 
-; Enable the ROM, reset changed vectors and return to BASIC
+; Place the program return code into ST
 
-        sta     ENABLE_ROM
-       jmp     $FF8A           ; RESTOR
+       pla
+       sta     ST
+
+; Restore the stack pointer
+
+               ldx     spsave
+               txs
 
+; Enable the ROM and return to BASIC
+
+        sta     ENABLE_ROM
+               rts
 
 ; ------------------------------------------------------------------------
-; IRQ handler
+; IRQ handler. The handler in the ROM enables the kernal and jumps to
+; $CE00, where the ROM code checks for a BRK or IRQ and branches via the
+; indirect vectors at $314/$316.
+; To make our stub as fast as possible, we skip the whole part of the ROM
+; handler and jump to the indirect vectors directly. We do also call our
+; own interrupt handlers if we have any, so they need not use $314.
 
 .segment        "LOWCODE"
 
-IRQ:    pha
+IRQ:    cld                    ; Just to be sure
+       pha
         txa
         pha
+       tya
+       pha
         tsx                     ; Get the stack pointer
-        lda     $0103,x         ; Get the saved status register
-        tax                     ; Save for later
+        lda     $0104,x         ; Get the saved status register
         and     #$10            ; Test for BRK bit
         bne     dobreak
-        lda     #>irq_ret       ; Push new return address
+
+; It's an IRQ and RAM is enabled. If we have handlers, call them. We will use
+; a flag here instead of loading __INTERRUPTOR_COUNT__ directly, since the
+; condes function is not reentrant. The irqcount flag will be set/reset from
+; the main code, to avoid races.
+
+       ldy     irqcount
+       beq     @L1
+        jsr     callirq_y       ; Call the IRQ functions
+
+; Since the ROM handler will end with an RTI, we have to fake an IRQ return
+; on stack, so we get control of the CPU after the ROM handler and can switch
+; back to RAM.
+
+@L1:    lda     #>irq_ret       ; Push new return address
         pha
         lda     #<irq_ret
         pha
-        txa
-        pha
+               php                     ; Push faked IRQ frame on stack
+       pha                     ; Push faked A register
+       pha                     ; Push faked X register
+       pha                     ; Push faked Y register
         sta     ENABLE_ROM      ; Switch to ROM
-        jmp     ($FFFE)         ; Jump to kernal irq handler
+        jmp     (IRQVec)        ; Jump indirect to kernal irq handler
 
 irq_ret:
         sta     ENABLE_RAM      ; Switch back to RAM
+       pla
+       tay
         pla
         tax
         pla
@@ -175,38 +180,23 @@ dobreak:
 ; No break handler installed, jump to ROM
 
 nohandler:
-        tya
-        pha                     ; ROM handler expects Y on stack
         sta     ENABLE_ROM
         jmp     (BRKVec)        ; Jump indirect to the break vector
 
-; ------------------------------------------------------------------------
-; Stub for the IRQ chain. Is used only if there are IRQs defined. Needed in
-; low memory because of the banking.
-
-.segment        "LOWCODE"
-
-IRQStub:
-        cld                     ; Just to be sure
-        sta     ENABLE_RAM      ; Switch to RAM
-       ldy     #<(__IRQFUNC_COUNT__*2)
-               lda     #<__IRQFUNC_TABLE__
-       ldx     #>__IRQFUNC_TABLE__
-       jsr     condes                  ; Call the IRQ functions
-       sta     ENABLE_ROM
-               jmp     IRQInd                  ; Jump to the saved IRQ vector
-
 ; ------------------------------------------------------------------------
 ; Data
 
 .data
-zpsave:                .res    zpspace
 
 ; BRK handling
 brk_jmp:        jmp     $0000
 
-.bss
 spsave:                .res    1
 
+irqcount:       .byte   0
+
+.segment        "ZPSAVE"
+
+zpsave:                .res    zpspace