]> git.sur5r.net Git - cc65/blobdiff - libsrc/plus4/crt0.s
Replaced $30 by literal '0' for better readability.
[cc65] / libsrc / plus4 / crt0.s
index 72fce209d2017042d57eb4b5232f6bb4757a0e9c..f9e79db78675c3fafb46c04d27f9decc7e13038c 100644 (file)
 ;
 ; Startup code for cc65 (Plus/4 version)
-;
-; This must be the *first* file on the linker command line
 ;
 
        .export         _exit
-       .import         __hinit, push0, doatexit, _main
-       .import         initconio, doneconio, zerobss
+        .export         brk_jmp
+        .export         __STARTUP__ : absolute = 1      ; Mark as startup
+
+       .import         callirq_y, initlib, donelib
+       .import         callmain, zerobss
+       .import         __INTERRUPTOR_COUNT__
 
+        .include        "zeropage.inc"
        .include        "plus4.inc"
-       .include        "../cbm/cbm.inc"
+
 
 ; ------------------------------------------------------------------------
-; Define and export the ZP variables for the C64 runtime
-
-       .exportzp       sp, sreg, regsave
-       .exportzp       ptr1, ptr2, ptr3, ptr4
-       .exportzp       tmp1, tmp2, tmp3, tmp4
-       .exportzp       regbank, zpspace
-
-sp             =       $02             ; stack pointer
-sreg   =       $04             ; secondary register/high 16 bit for longs
-regsave        =       $06             ; slot to save/restore (E)AX into
-ptr1   =       $0A             ;
-ptr2   =       $0C
-ptr3   =       $0E
-ptr4   =       $10
-tmp1   =       $12
-tmp2   =       $13
-tmp3   =       $14
-tmp4   =       $15
-regbank        =       $16             ; 6 byte register bank
-zpspace        =       $1A             ; Zero page space allocated
+; Constants
+
+IRQInd                 = $500  ; JMP $0000 - used as indirect IRQ vector
 
 ; ------------------------------------------------------------------------
 ; BASIC header with a SYS call
 
-       .org    $0FFF
+.segment               "EXEHDR"
+
         .word   Head            ; Load address
 Head:   .word   @Next
-        .word   1000            ; Line number
-        .byte   $9E,"4109"     ; SYS 4109
+        .word   .version        ; Line number
+        .byte   $9E             ; SYS token
+        .byte   <(((Start / 1000) .mod 10) + '0')
+        .byte   <(((Start /  100) .mod 10) + '0')
+        .byte   <(((Start /   10) .mod 10) + '0')
+        .byte   <(((Start /    1) .mod 10) + '0')
         .byte   $00             ; End of BASIC line
 @Next:  .word   0               ; BASIC end marker
-       .reloc
 
 ; ------------------------------------------------------------------------
-; Actual code
+; Startup code
 
-       ldy     #zpspace-1
-L1:    lda     sp,y
-       sta     zpsave,y        ; save the zero page locations we need
-       dey
-               bpl     L1
+.segment               "STARTUP"
 
-; Close open files
+Start:
 
-       jsr     CLRCH
+; 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
+       dex
+               bpl     L1
+        sta     ENABLE_ROM
+        cli
 
 ; Switch to second charset
 
-       lda     #14
-       jsr     BSOUT
+       lda     #14
+       jsr     $FFD2           ; BSOUT
 
-; Clear the BSS data
+; Save system stuff and setup the stack. The stack starts at the top of the
+; usable RAM.
+
+               tsx
+               stx     spsave          ; save system stk ptr
 
-       jsr     zerobss
+        lda     #<$FD00
+        sta     sp
+        lda     #>$FD00
+        sta     sp+1
 
-; Save system stuff and setup the stack
+; Setup the IRQ vector in the banked RAM and switch off the ROM
 
-               tsx
-               stx     spsave          ; save system stk ptr
+        ldx     #<IRQ
+        ldy     #>IRQ
+        sei                     ; No ints, handler not yet in place
+        sta     ENABLE_RAM
+        stx     $FFFE           ; Install interrupt handler
+        sty     $FFFF
+        cli                     ; Allow interrupts
 
-       sec
-       jsr     MEMTOP          ; Get top memory
-       cpy     #$80            ; We can only use the low 32K :-(
-       bcc     MemOk
-       ldy     #$80
-       ldx     #$00
-MemOk: stx     sp
-       sty     sp+1            ; set argument stack ptr
+; Clear the BSS data
 
-; Initialize the heap
+       jsr     zerobss
 
-       jsr     __hinit
+; Initialize irqcount, which means that from now own custom linked in IRQ
+; handlers (via condes) will be called.
 
-; Initialize conio stuff
+        lda     #.lobyte(__INTERRUPTOR_COUNT__*2)
+        sta     irqcount
 
-       jsr     initconio
+; Call module constructors
 
-; Pass an empty command line
+       jsr     initlib
 
-               jsr     push0           ; argc
-       jsr     push0           ; argv
+; Push arguments and call main()
 
-       ldy     #4              ; Argument size
-               jsr     _main           ; call the users code
+       jsr     callmain
 
-; fall thru to exit...
+; Back from main (this is also the _exit entry). Run module destructors.
 
-_exit: jsr     doatexit        ; call exit functions
-       ldx     spsave
-       txs
+_exit:         pha                     ; Save the return code
+        jsr    donelib         ; Run module destructors
 
-; Reset the conio stuff
+; Disable chained IRQ handlers
 
-       jsr     doneconio
+       lda     #0
+        sta     irqcount        ; Disable custom IRQ handlers
 
 ; Copy back the zero page stuff
 
-       ldy     #zpspace-1
-L2:    lda     zpsave,y
-       sta     sp,y
-       dey
+       ldx     #zpspace-1
+L2:    lda     zpsave,x
+       sta     sp,x
+       dex
                bpl     L2
 
-; Reset changed vectors
+; Place the program return code into ST
 
-       jmp     RESTOR
+       pla
+       sta     ST
 
+; Restore the stack pointer
+
+               ldx     spsave
+               txs
+
+; Enable the ROM, reset changed vectors and return to BASIC
+
+        sta     ENABLE_ROM
+       jmp     $FF8A           ; RESTOR
+
+
+; ------------------------------------------------------------------------
+; 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:    cld                    ; Just to be sure
+       pha
+        txa
+        pha
+       tya
+       pha
+        tsx                     ; Get the stack pointer
+        lda     $0104,x         ; Get the saved status register
+        and     #$10            ; Test for BRK bit
+        bne     dobreak
+
+; 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
+               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     (IRQVec)        ; Jump indirect to kernal irq handler
+
+irq_ret:
+        sta     ENABLE_RAM      ; Switch back to RAM
+       pla
+       tay
+        pla
+        tax
+        pla
+        rti
+
+dobreak:
+        lda     brk_jmp+2       ; Check high byte of address
+        beq     nohandler
+        jmp     brk_jmp         ; Jump to the handler
+
+; No break handler installed, jump to ROM
+
+nohandler:
+        sta     ENABLE_ROM
+        jmp     (BRKVec)        ; Jump indirect to the break vector
+
+; ------------------------------------------------------------------------
+; Data
 
 .data
-zpsave:        .res    zpspace
 
-.bss
-spsave:        .res    1
+; BRK handling
+brk_jmp:        jmp     $0000
+
+spsave:                .res    1
+
+irqcount:       .byte   0
+
+.segment        "ZPSAVE"
+
+zpsave:                .res    zpspace