1
0
mirror of https://github.com/cc65/cc65.git synced 2024-11-05 23:05:24 +00:00
cc65/libsrc/cbm610/crt0.s

418 lines
9.2 KiB
ArmAsm
Raw Normal View History

;
; Startup code for cc65 (Plus/4 version)
;
; This must be the *first* file on the linker command line
;
.export _exit
.import initlib, donelib
.import push0, _main
.import __BSS_RUN__, __BSS_SIZE__
.import irq, nmi
.import k_irq, k_nmi, k_plot, k_udtim, k_scnkey
.include "zeropage.inc"
.include "io.inc"
; ------------------------------------------------------------------------
; Define and export the ZP variables for the CBM610 runtime
.exportzp sp, sreg, regsave
.exportzp ptr1, ptr2, ptr3, ptr4
.exportzp tmp1, tmp2, tmp3, tmp4
.exportzp regbank, zpspace
.exportzp crtc, sid, IPCcia, cia, acia, tpi1, tpi2
.exportzp ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
.zeropage
zpstart = *
sp: .res 2 ; Stack pointer
sreg: .res 2 ; Secondary register/high 16 bit for longs
regsave: .res 2 ; slot to save/restore (E)AX into
ptr1: .res 2
ptr2: .res 2
ptr3: .res 2
ptr4: .res 2
tmp1: .res 1
tmp2: .res 1
tmp3: .res 1
tmp4: .res 1
regbank: .res 6 ; 6 byte register bank
zpspace = * - zpstart ; Zero page space allocated
.code
; ------------------------------------------------------------------------
; BASIC header and a small BASIC program. Since it is not possible to start
; programs in other banks using SYS, the BASIC program will write a small
; machine code program into memory at $100 and start that machine code
; program. The machine code program will then start the machine language
; code in bank 1, which will initialize the system by copying stuff from
; the system bank, and start the application.
;
; Here's the basic program that's in the following lines:
;
; 10 for i=0 to 4
; 20 read j
; 30 poke 256+i,j
; 40 next i
; 50 sys 256
; 60 data 120,169,1,133,0
;
; The machine program in the data lines is:
;
; sei
; 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
; this, we will use the system memory ($00-$3FF) for initialization stuff
; that is overwritten later.
;
; To make things more simple, make the code of this module absolute.
.org $0001
Head: .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
; Since we need some vectors to access stuff in the system bank for our own,
; we will include them here, starting from $60:
.res $60-*
crtc: .word $d800
sid: .word $da00
IPCcia: .word $db00
cia: .word $dc00
acia: .word $dd00
tpi1: .word $de00
tpi2: .word $df00
ktab1: .word $ea29
ktab2: .word $ea89
ktab3: .word $eae9
ktab4: .word $eb49
time: .dword $0000
RecvBuf: .word $0100 ; RS232 received buffer
SendBuf: .word $0200 ; RS232 send buffer
; The code in the target bank when switching back will be put at the bottom
; of the stack. We will jump here to switch segments. The range $F2..$FF is
; not used by any kernal routine.
.res $F8-*
Back: ldx spsave
txs
lda IndReg
sta ExecReg
; The following code 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
; 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
; use the stack (since it's in page 1)!
tsx
stx spsave ; Save the system stackpointer
ldx #$FF
txs ; Set up our own stack
; Set the interrupt, NMI and other vectors
ldy #vectable_size
L0: lda vectable-1,y
sta $FF80,y
dey
bne L0
; Switch the indirect segment to the system bank
lda #$0F
sta IndReg
; Copy the kernal zero page ($90-$F2) from the system bank
lda #$90
sta ptr1
lda #$00
sta ptr1+1
ldy #$62-1
L1: lda (ptr1),y
sta $90,y
dey
bpl L1
; Copy the page 3 vectors in place
ldy #$00
L2: lda p3vectable,y
sta $300,y
iny
cpy #p3vectable_size
bne L2
; Copy the rest of page 3 from the system bank
lda #$00
sta ptr1
lda #$03
sta ptr1+1
L3: lda (ptr1),y
sta $300,y
iny
bne L3
; Set the indirect segment to bank we're executing in
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
; Clear full pages
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
Z4:
; Setup the C stack
lda #<$FF81
sta sp
lda #>$FF81
sta sp+1
; We expect to be in page 2 now
.if (* < $1FD)
jmp $200
.res $200-*
.endif
.if (* < $200)
.res $200-*,$EA
.endif
.if (* >= $2F0)
.error "Code range invalid"
.endif
; This code is in page 2, so we may now start calling subroutines safely,
; since the code we execute is no longer in the stack page.
; Call module constructors
jsr initlib
; Create the (empty) command line for the program
jsr push0 ; argc
jsr push0 ; argv
; Execute the program code
jmp Start
; ------------------------------------------------------------------------
; Additional data that we need for initialization and that's overwritten
; later
vectable:
jmp $0000 ; CINT
jmp $0000 ; IOINIT
jmp $0000 ; RAMTAS
jmp $0000 ; RESTOR
jmp $0000 ; VECTOR
jmp $0000 ; SETMSG
jmp $0000 ; SECOND
jmp $0000 ; TKSA
jmp $0000 ; MEMTOP
jmp $0000 ; MEMBOT
jmp k_scnkey ; SCNKEY
jmp $0000 ; SETTMO
jmp $0000 ; ACPTR
jmp $0000 ; CIOUT
jmp $0000 ; UNTLK
jmp $0000 ; UNLSN
jmp $0000 ; LISTEN
jmp $0000 ; TALK
jmp $0000 ; READST
jmp k_setlfs ; SETLFS
jmp k_setnam ; SETNAM
jmp $0000 ; OPEN
jmp $0000 ; CLOSE
jmp $0000 ; CHKIN
jmp $0000 ; CKOUT
jmp $0000 ; CLRCH
jmp $0000 ; BASIN
jmp $0000 ; BSOUT
jmp $0000 ; LOAD
jmp $0000 ; SAVE
jmp k_settim ; SETTIM
jmp k_rdtim ; RDTIM
jmp $0000 ; STOP
jmp $0000 ; GETIN
jmp $0000 ; CLALL
jmp k_udtim ; UDTIM
jmp k_screen ; SCREEN
jmp k_plot ; PLOT
jmp k_iobase ; IOBASE
sta ExecReg
rts
.byte $01 ; Filler
.word nmi
.word 0 ; Reset - not used
.word irq
vectable_size = * - vectable
p3vectable:
.word k_irq ; IRQ user vector
.word k_brk ; BRK user vector
.word k_nmi ; NMI user vector
p3vectable_size = * - p3vectable
; ------------------------------------------------------------------------
; This is the program code after setup. It starts at $400
.res $400-*
Start:
; Enable interrupts
cli
; Call the user code
ldy #4 ; Argument size
jsr _main ; call the users code
; Call module destructors. This is also the _exit entry.
_exit: jsr donelib ; Run module destructors
; Clear the start of the zero page, since it will be interpreted as a
; (garbage) BASIC program otherwise. This is also the default entry for
; the break vector.
k_brk: sei
lda #$00
ldx #$3E
Clear: sta $02,x
dex
bne Clear
; Setup the welcome code at the stack bottom in the system bank. Use
; the F4/F5 vector to access the system bank
lda #$0F
sta IndReg
ldy #$00
sty $F4
iny
sty $F5
ldy #reset_size-1
@L1: lda reset,y
sta ($F4),y
dey
bne @L1
jmp Back
; ------------------------------------------------------------------------
; Code that is copied into the system bank at $100 when switching back
reset: cli
jmp $8000 ; BASIC cold start
reset_size = * - reset
; ------------------------------------------------------------------------
; Code for a few simpler kernal calls goes here
k_iobase:
ldx cia
ldy cia+1
rts
k_screen:
ldx #80 ; Columns
ldy #25 ; Lines
rts
k_setlfs:
sta LogicalAdr
stx FirstAdr
sty SecondAdr
rts
k_setnam:
sta FileNameLen
lda $00,x
sta FileNameAdrLo
lda $01,x
sta FileNameAdrHi
lda $02,x
sta FileNameAdrSeg
rts
k_rdtim:
sei
lda time+0
ldx time+1
ldy time+2
cli
rts
k_settim:
sei
sta time+0
stx time+1
sty time+2
cli
rts
; -------------------------------------------------------------------------
; Data area - switch back to relocatable mode
.reloc
.data
spsave: .res 1