1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-24 11:31:31 +00:00
cc65/libsrc/plus4/crt0.s
Oliver Schmidt d8c31cf1d3 Renamed RAM to MAIN for all disk based targets.
The name RAM doesn't make much sense in general for a memeory area because i.e. the zero page is for sure RAM but is not part of the memory area named RAM.

For disk based targets it makes sense to put the disk file more into focus and here MAIN means the main part of the file - in contrast to some header.

Only for ROM based targets the name RAM is kept as it makes sense to focus on the difference between RAM and ROM.
2016-03-07 01:28:55 +01:00

203 lines
5.4 KiB
ArmAsm

;
; Startup code for cc65 (Plus/4 version)
;
.export _exit
.export brk_jmp
.export __STARTUP__ : absolute = 1 ; Mark as startup
.import callirq_y, initlib, donelib
.import callmain, zerobss
.import __INTERRUPTOR_COUNT__
.import __MAIN_START__, __MAIN_SIZE__ ; Linker generated
.import __STACKSIZE__ ; Linker generated
.importzp ST
.include "zeropage.inc"
.include "plus4.inc"
; ------------------------------------------------------------------------
; Constants
IRQInd = $500 ; JMP $0000 - used as indirect IRQ vector
; ------------------------------------------------------------------------
; Startup code
.segment "STARTUP"
Start:
; Save the zero-page locations that 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 the second charset.
lda #14
jsr $FFD2 ; BSOUT
; Save some system stuff; and, set up the stack. The stack starts at the top
; of the usable RAM.
tsx
stx spsave ; Save system stk ptr
lda #<(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__)
ldx #>(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__)
sta sp
stx sp+1
; Set up 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
stx $FFFE ; Install interrupt handler
sty $FFFF
cli ; Allow interrupts
; Clear the BSS data.
jsr zerobss
; Initialize irqcount, which means that, from now on, custom linked-in IRQ
; handlers will be called (via condes).
lda #.lobyte(__INTERRUPTOR_COUNT__*2)
sta irqcount
; Call the module constructors.
jsr initlib
; Push the command-line arguments; and, call main().
jsr callmain
; Back from main() [this is also the exit() entry]. Run the module destructors.
_exit: pha ; Save the return code
jsr donelib ; Run module destructors
; Disable the chained IRQ handlers.
lda #0
sta irqcount ; Disable custom IRQ handlers
; Copy back the zero-page stuff.
ldx #zpspace-1
L2: lda zpsave,x
sta sp,x
dex
bpl L2
; Place the program return code into BASIC's status variable.
pla
sta ST
; Restore the stack pointer.
ldx spsave
txs
; Enable the ROM; and, return to BASIC.
sta ENABLE_ROM
rts
; ------------------------------------------------------------------------
; 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 the stack, so that 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
; BRK handling
brk_jmp: jmp $0000
spsave: .res 1
irqcount: .byte 0
.segment "INIT"
zpsave: .res zpspace