2 ; Startup code for cc65 (CBM 500 version)
4 ; This must be the *first* file on the linker command line
8 .import _clrscr, initlib, donelib
10 .import __CHARRAM_START__, __CHARRAM_SIZE__, __VIDRAM_START__
11 .import __BSS_RUN__, __BSS_SIZE__
13 .import k_irq, k_nmi, k_plot, k_udtim, k_scnkey
15 .include "zeropage.inc"
19 ; ------------------------------------------------------------------------
20 ; Define and export the ZP variables for the CBM510 runtime
22 .exportzp sp, sreg, regsave
23 .exportzp ptr1, ptr2, ptr3, ptr4
24 .exportzp tmp1, tmp2, tmp3, tmp4
25 .exportzp regbank, zpspace
26 .exportzp vic, sid, cia1, cia2, acia, tpi1, tpi2
27 .exportzp ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
32 sp: .res 2 ; Stack pointer
33 sreg: .res 2 ; Secondary register/high 16 bit for longs
34 regsave: .res 2 ; slot to save/restore (E)AX into
43 regbank: .res 6 ; 6 byte register bank
45 zpspace = * - zpstart ; Zero page space allocated
49 ; ------------------------------------------------------------------------
50 ; BASIC header and a small BASIC program. Since it is not possible to start
51 ; programs in other banks using SYS, the BASIC program will write a small
52 ; machine code program into memory at $100 and start that machine code
53 ; program. The machine code program will then start the machine language
54 ; code in bank 0, which will initialize the system by copying stuff from
55 ; the system bank, and start the application.
57 ; Here's the basic program that's in the following lines:
64 ; 60 data 120,169,0,133,0
66 ; The machine program in the data lines is:
70 ; sta $00 <-- Switch to bank 0 after this command
72 ; Initialization is not only complex because of the jumping from one bank
73 ; into another. but also because we want to save memory, and because of
74 ; this, we will use the system memory ($00-$3FF) for initialization stuff
75 ; that is overwritten later.
78 ; To make things more simple, make the code of this module absolute.
81 Head: .byte $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
82 .byte $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
83 .byte $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
84 .byte $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
85 .byte $30,$2c,$31,$36,$39,$2c,$30,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
87 ; Since we need some vectors to access stuff in the system bank for our own,
88 ; we will include them here, starting from $60:
104 RecvBuf: .word $0100 ; RS232 received buffer
105 SendBuf: .word $0200 ; RS232 send buffer
108 ; The code in the target bank when switching back will be put at the bottom
109 ; of the stack. We will jump here to switch segments. The range $F2..$FF is
110 ; not used by any kernal routine.
118 ; The following code is a copy of the code that is poked in the system bank
119 ; memory by the basic header program, it's only for documentation and not
120 ; actually used here:
126 ; This is the actual starting point of our code after switching banks for
127 ; startup. Beware: The following code will get overwritten as soon as we
128 ; use the stack (since it's in page 1)!
131 stx spsave ; Save the system stackpointer
133 txs ; Set up our own stack
135 ; Set the interrupt, NMI and other vectors
143 ; Switch the indirect segment to the system bank
148 ; Copy the kernal zero page ($90-$F2) from the system bank
160 ; Copy the page 3 vectors in place
169 ; Copy the rest of page 3 from the system bank
180 ; Set the indirect segment to bank we're executing in
185 ; Zero the BSS segment. We will do that here instead calling the routine
186 ; in the common library, since we have the memory anyway, and this way,
203 inc ptr1+1 ; Next page
207 ; Clear the remaining page
209 Z2: ldx #<__BSS_SIZE__
224 ; We expect to be in page 2 now
234 .error "Code range invalid"
237 ; This code is in page 2, so we may now start calling subroutines safely,
238 ; since the code we execute is no longer in the stack page.
240 ; Copy the character rom from the system bank into the execution bank
246 lda #<__CHARRAM_START__
248 lda #>__CHARRAM_START__
250 lda #>__CHARRAM_SIZE__ ; 16 * 256 bytes to copy
254 sta IndReg ; Access the system bank
256 sta __VIDRAM_START__,y
261 ccopy2: lda __VIDRAM_START__,y
266 inc ptr2+1 ; Bump high pointer bytes
270 ; Clear the video memory. We will do this before switching the video to bank 0
271 ; to avoid garbage when doing so.
275 ; Reprogram the VIC so that the text screen and the character ROM is in the
276 ; execution bank. This is done in three steps:
278 lda #$0F ; We need access to the system bank
281 ; Place the VIC video RAM into bank 0
292 ; Set bit 14/15 of the VIC address range to the high bits of __VIDRAM_START__
293 ; PC6/PC7 (VICBANKSEL 0/1) = 11
299 ora #<((>__VIDRAM_START__) & $C0)
302 ; Set the VIC base address register to the addresses of the video and
309 ora #<(((__VIDRAM_START__ >> 6) & $F0) | ((__CHARRAM_START__ >> 10) & $0E) | $02)
311 ; ora #<(((>__VIDRAM_START__) << 2) & $F0)
314 ; Switch back to the execution bank
319 ; Call module constructors
323 ; Create the (empty) command line for the program
328 ; Execute the program code
332 ; ------------------------------------------------------------------------
333 ; Additional data that we need for initialization and that's overwritten
347 jmp k_scnkey ; SCNKEY
356 jmp k_setlfs ; SETLFS
357 jmp k_setnam ; SETNAM
367 jmp k_settim ; SETTIM
373 jmp k_screen ; SCREEN
375 jmp k_iobase ; IOBASE
380 .word 0 ; Reset - not used
382 vectable_size = * - vectable
385 .word k_irq ; IRQ user vector
386 .word k_brk ; BRK user vector
387 .word k_nmi ; NMI user vector
388 p3vectable_size = * - p3vectable
391 ; ------------------------------------------------------------------------
392 ; This is the program code after setup. It starts at $400
404 ldy #4 ; Argument size
405 jsr _main ; call the users code
407 ; Call module destructors. This is also the _exit entry.
409 _exit: jsr donelib ; Run module destructors
411 ; We need access to the system bank now
416 ; Switch back the video to the system bank
430 ; Clear the start of the zero page, since it will be interpreted as a
431 ; (garbage) BASIC program otherwise. This is also the default entry for
441 ; Setup the welcome code at the stack bottom in the system bank. Use
442 ; the F4/F5 vector to access the system bank
455 ; ------------------------------------------------------------------------
456 ; Code that is copied into the system bank at $100 when switching back
459 jmp $8000 ; BASIC cold start
460 reset_size = * - reset
462 ; ------------------------------------------------------------------------
463 ; Code for a few simpler kernal calls goes here
507 ; -------------------------------------------------------------------------
508 ; Data area - switch back to relocatable mode