2 ; Startup code for cc65 (C128 version)
4 ; This must be the *first* file on the linker command line
8 .export BRKStub, BRKOld, BRKInd
9 .import condes, initlib, donelib
10 .import initconio, doneconio, zerobss
12 .import __IRQFUNC_TABLE__, __IRQFUNC_COUNT__
13 .import __RAM_START__, __RAM_SIZE__
16 .include "../cbm/cbm.inc"
18 ; ------------------------------------------------------------------------
21 IRQInd = $2FD ; JMP $0000 - used as indirect IRQ vector
23 ; ------------------------------------------------------------------------
24 ; Define and export the ZP variables for the C64 runtime
26 .exportzp sp, sreg, regsave
27 .exportzp ptr1, ptr2, ptr3, ptr4
28 .exportzp tmp1, tmp2, tmp3, tmp4
29 .exportzp regbank, zpspace
34 sp: .res 2 ; Stack pointer
35 sreg: .res 2 ; Secondary register/high 16 bit for longs
36 regsave: .res 2 ; slot to save/restore (E)AX into
45 regbank: .res 6 ; 6 byte register bank
47 zpspace = * - zpstart ; Zero page space allocated
49 ; Place the startup code in a special segment to cope with the quirks of
50 ; c128 banking. Do also create an empty segment named "NMI" to avoid
51 ; warnings if the rs232 routines are not used.
58 ; ------------------------------------------------------------------------
59 ; BASIC header with a SYS call
62 .word Head ; Load address
64 .word 1000 ; Line number
65 .byte $9E,"7181" ; SYS 7181
66 .byte $00 ; End of BASIC line
67 @Next: .word 0 ; BASIC end marker
70 ; ------------------------------------------------------------------------
77 ; Switch to the second charset
82 ; Before doing anything else, we have to setup our banking configuration.
83 ; Otherwise just the lowest 16K are actually RAM. Writing through the ROM
84 ; to the underlying RAM works, but it is bad style.
86 lda MMU_CR ; Get current memory configuration...
87 pha ; ...and save it for later
88 lda #CC65_MMU_CFG ; Bank0 with kernal ROM
91 ; Save the zero page locations we need
103 ; Save system stuff and setup the stack
105 pla ; Get MMU setting
109 stx spsave ; Save the system stack pointer
111 lda #<(__RAM_START__ + __RAM_SIZE__)
113 lda #>(__RAM_START__ + __RAM_SIZE__)
114 sta sp+1 ; Set argument stack ptr
116 ; Call module constructors
120 ; Initialize conio stuff
124 ; If we have IRQ functions, chain our stub into the IRQ vector
126 lda #<__IRQFUNC_COUNT__
139 ; Pass an empty command line
141 NoIRQ1: jsr push0 ; argc
144 ldy #4 ; Argument size
145 jsr _main ; call the users code
147 ; This is also the _exit entry. Reset the IRQ vector if we chained it.
149 _exit: lda #<__IRQFUNC_COUNT__
158 ; Run module destructors
162 ; Reset the conio stuff
171 ; Copy back the zero page stuff
179 ; Reset the memory configuration
184 ; Done, restore kernal vectors in an attempt to cleanup
188 ; ------------------------------------------------------------------------
189 ; The C128 has ROM parallel to the RAM starting from $4000. The startup code
190 ; above will change this setting so that we have RAM from $0000-$BFFF. This
191 ; works quite well with the exception of interrupts: The interrupt handler
192 ; is in ROM, and the ROM switches back to the ROM configuration, which means
193 ; that parts of our program may not be accessible. Since the crt0 module is
194 ; the first module in the program, it will always be below $4000 and always
195 ; in RAM. So we place several short stubs here that switch back our ROM
196 ; config before calling our user defined handlers. These stubs are only
197 ; used if any other code uses the interrupt or break vectors. They are dead
198 ; code otherwise, but since there is no other way to keep them in low memory,
199 ; they have to go here.
202 cld ; Just to be sure
203 lda MMU_CR ; Get old register value
204 pha ; And save on stack
205 lda #CC65_MMU_CFG ; Bank 0 with kernal ROM
207 ldy #<(__IRQFUNC_COUNT__*2)
208 lda #<__IRQFUNC_TABLE__
209 ldx #>__IRQFUNC_TABLE__
210 jsr condes ; Call the functions
211 pla ; Get old register value
213 jmp IRQInd ; Jump to the save IRQ vector
217 pla ; Get original MMU_CR value
218 sta MMU_CR ; And set it
219 jmp BRKInd ; Jump indirect to break
222 ; ------------------------------------------------------------------------
228 ; Old break vector preceeded by a jump opcode
231 ; Indirect vectors preceeded by a jump opcode