;
; Startup code for cc65 (CBM 600/700 version)
-;
-; This must be the *first* file on the linker command line
;
- .export _exit, BRKVec
+ .export _exit, BRKVec
+ .export __STARTUP__ : absolute = 1 ; Mark as startup
- .import callirq_y, initlib, donelib
- .import push0, callmain
- .import __BSS_RUN__, __BSS_SIZE__, __EXTZP_RUN__
- .import __INTERRUPTOR_COUNT__
- .import scnkey, UDTIM
+ .import callirq_y, initlib, donelib
+ .import push0, callmain
+ .import __BSS_RUN__, __BSS_SIZE__, __EXTZP_RUN__
+ .import __INTERRUPTOR_COUNT__
+ .import scnkey, UDTIM
- .include "zeropage.inc"
+ .include "zeropage.inc"
.include "extzp.inc"
- .include "cbm610.inc"
+ .include "cbm610.inc"
; ------------------------------------------------------------------------
; The machine program in the data lines is:
;
; sei
-; lda #$01
-; sta $00 <-- Switch to bank 1 after this command
+; lda #$01
+; sta $00 <-- Switch to bank 1 after this command
;
; Initialization is not only complex because of the jumping from one bank
; into another. but also because we want to save memory, and because of
; that is overwritten later.
;
-.segment "BASICHDR"
+.segment "EXEHDR"
- .byte $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
- .byte $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
- .byte $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
- .byte $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
- .byte $30,$2c,$31,$36,$39,$2c,$31,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
+ .byte $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
+ .byte $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
+ .byte $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
+ .byte $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
+ .byte $30,$2c,$31,$36,$39,$2c,$31,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
;------------------------------------------------------------------------------
; A table that contains values that must be transfered from the system zero
.proc transfer_table
+ .byte $9F, DEVNUM
.byte $CA, CURS_Y
.byte $CB, CURS_X
.byte $CC, graphmode
.proc callbank15
- excrts = $FF05
+ excrts := $FF05 ; In bank 15 rom
.org $FECB
.segment "STARTUP"
-Back: sta ExecReg
+Back: sta ExecReg
; We are at $100 now. The following snippet is a copy of the code that is poked
; in the system bank memory by the basic header program, it's only for
; documentation and not actually used here:
- sei
- lda #$01
- sta ExecReg
+ sei
+ lda #$01
+ sta ExecReg
; This is the actual starting point of our code after switching banks for
; startup. Beware: The following code will get overwritten as soon as we
sta ExecReg
rts
nop
- .word nmi ; NMI vector
- .word 0 ; Reset - not used
- .word irq ; IRQ vector
+ .word nmi ; NMI vector
+ .word 0 ; Reset - not used
+ .word irq ; IRQ vector
.endproc
; Initializers for the extended zeropage. See extzp.s
.proc extzp
.word $0100 ; sysp1
.word $0300 ; sysp3
- .word $d800 ; crtc
- .word $da00 ; sid
- .word $db00 ; ipccia
- .word $dc00 ; cia
- .word $dd00 ; acia
- .word $de00 ; tpi1
- .word $df00 ; tpi2
- .word $ea29 ; ktab1
- .word $ea89 ; ktab2
- .word $eae9 ; ktab3
- .word $eb49 ; ktab4
+ .word $d800 ; crtc
+ .word $da00 ; sid
+ .word $db00 ; ipccia
+ .word $dc00 ; cia
+ .word $dd00 ; acia
+ .word $de00 ; tpi1
+ .word $df00 ; tpi2
+ .word $ea29 ; ktab1
+ .word $ea89 ; ktab2
+ .word $eae9 ; ktab3
+ .word $eb49 ; ktab4
.endproc
; Switch the indirect segment to the system bank
-Origin: lda #$0F
- sta IndReg
+Origin: lda #$0F
+ sta IndReg
; Initialize the extended zeropage
txa
ldy #$FF
sta (sysp1),y ; Save system stack point into $F:$1FF
- ldx #$FE ; Leave $1FF untouched for cross bank calls
- txs ; Set up our own stack
+ ldx #$FE ; Leave $1FF untouched for cross bank calls
+ txs ; Set up our own stack
; Copy stuff from the system zeropage to ours
; Set the interrupt, NMI and other vectors
- ldx #.sizeof(vectors)-1
-L3: lda vectors,x
- sta $10000 - .sizeof(vectors),x
- dex
- bpl L3
+ ldx #.sizeof(vectors)-1
+L3: lda vectors,x
+ sta $10000 - .sizeof(vectors),x
+ dex
+ bpl L3
; Setup the C stack
- lda #.lobyte(callbank15::entry)
- sta sp
- lda #.hibyte(callbank15::entry)
- sta sp+1
+ lda #.lobyte(callbank15::entry)
+ sta sp
+ lda #.hibyte(callbank15::entry)
+ sta sp+1
; Setup the subroutine and jump vector table that redirects kernal calls to
; the system bank.
; Set the indirect segment to bank we're executing in
- lda ExecReg
- sta IndReg
+ lda ExecReg
+ sta IndReg
; Zero the BSS segment. We will do that here instead calling the routine
; in the common library, since we have the memory anyway, and this way,
; it's reused later.
- lda #<__BSS_RUN__
- sta ptr1
- lda #>__BSS_RUN__
- sta ptr1+1
- lda #0
- tay
+ lda #<__BSS_RUN__
+ sta ptr1
+ lda #>__BSS_RUN__
+ sta ptr1+1
+ lda #0
+ tay
; Clear full pages
- ldx #>__BSS_SIZE__
- beq Z2
-Z1: sta (ptr1),y
- iny
- bne Z1
- inc ptr1+1 ; Next page
- dex
- bne Z1
+ ldx #>__BSS_SIZE__
+ beq Z2
+Z1: sta (ptr1),y
+ iny
+ bne Z1
+ inc ptr1+1 ; Next page
+ dex
+ bne Z1
; Clear the remaining page
-Z2: ldx #<__BSS_SIZE__
- beq Z4
-Z3: sta (ptr1),y
- iny
- dex
- bne Z3
+Z2: ldx #<__BSS_SIZE__
+ beq Z4
+Z3: sta (ptr1),y
+ iny
+ dex
+ bne Z3
Z4: jmp Init
; ------------------------------------------------------------------------
Init: lda #.lobyte(__INTERRUPTOR_COUNT__*2)
sta irqcount
- cli
+ cli
; Call module constructors.
- jsr initlib
+ jsr initlib
; Push arguments and call main()
- jsr callmain
+ jsr callmain
; Call module destructors. This is also the _exit entry and the default entry
; point for the break vector.
-_exit: pha ; Save the return code
- jsr donelib ; Run module destructors
- lda #$00
+_exit: pha ; Save the return code
+ jsr donelib ; Run module destructors
+ lda #$00
sta irqcount ; Disable custom irq handlers
; Address the system bank
; Place the program return code into ST
- pla
- ldy #$9C ; ST
- sta (sysp0),y
+ pla
+ ldy #$9C ; ST
+ sta (sysp0),y
; Setup the welcome code at the stack bottom in the system bank.
iny
lda #$60 ; RTS opcode
sta (sysp1),y
- lda IndReg
+ lda IndReg
sei
- txs
+ txs
jmp Back
; -------------------------------------------------------------------------
; easier chaining, we do handle the IRQs in the execution bank (instead of
; passing them to the system bank).
-; This is the mapping of the active irq register of the 6525 (tpi1):
+; This is the mapping of the active irq register of the 6525 (tpi1):
;
; Bit 7 6 5 4 3 2 1 0
; | | | | ^ 50 Hz
pha
lda ExecReg
sta IndReg ; Be sure to address our segment
- tsx
- lda $105,x ; Get the flags from the stack
- and #$10 ; Test break flag
- bne dobrk
+ tsx
+ lda $105,x ; Get the flags from the stack
+ and #$10 ; Test break flag
+ bne dobrk
; It's an IRQ
; Call chained IRQ handlers
- ldy irqcount
+ ldy irqcount
beq irqskip
- jsr callirq_y ; Call the functions
+ jsr callirq_y ; Call the functions
; Done with chained IRQ handlers, check the TPI for IRQs and handle them
-irqskip:lda #$0F
- sta IndReg
- ldy #TPI::AIR
- lda (tpi1),y ; Interrupt Register 6525
- beq noirq
+irqskip:lda #$0F
+ sta IndReg
+ ldy #TPI::AIR
+ lda (tpi1),y ; Interrupt Register 6525
+ beq noirq
; 50/60Hz interrupt
- cmp #%00000001 ; ticker irq?
- bne irqend
- jsr scnkey ; Poll the keyboard
- jsr UDTIM ; Bump the time
+ cmp #%00000001 ; ticker irq?
+ bne irqend
+ jsr scnkey ; Poll the keyboard
+ jsr UDTIM ; Bump the time
; Done
-irqend: ldy #TPI::AIR
- sta (tpi1),y ; Clear interrupt
+irqend: ldy #TPI::AIR
+ sta (tpi1),y ; Clear interrupt
-noirq: pla
+noirq: pla
sta IndReg
pla
tay
pla
tax
pla
-nmi: rti
+nmi: rti
-dobrk: jmp (BRKVec)
+dobrk: jmp (BRKVec)
; -------------------------------------------------------------------------
; Data area.