]> git.sur5r.net Git - cc65/blob - libsrc/plus4/crt0.s
Minor comment adjustment.
[cc65] / libsrc / plus4 / crt0.s
1 ;
2 ; Startup code for cc65 (Plus/4 version)
3 ;
4
5         .export         _exit
6         .export         brk_jmp
7         .export         __STARTUP__ : absolute = 1      ; Mark as startup
8
9         .import         callirq_y, initlib, donelib
10         .import         callmain, zerobss
11         .import         __INTERRUPTOR_COUNT__
12
13         .include        "zeropage.inc"
14         .include        "plus4.inc"
15
16
17 ; ------------------------------------------------------------------------
18 ; Constants
19
20 IRQInd          = $500  ; JMP $0000 - used as indirect IRQ vector
21
22 ; ------------------------------------------------------------------------
23 ; BASIC header with a SYS call
24
25 .segment        "EXEHDR"
26
27         .word   Head            ; Load address
28 Head:   .word   @Next
29         .word   .version        ; Line number
30         .byte   $9E             ; SYS token
31         .byte   <(((Start / 1000) .mod 10) + '0')
32         .byte   <(((Start /  100) .mod 10) + '0')
33         .byte   <(((Start /   10) .mod 10) + '0')
34         .byte   <(((Start /    1) .mod 10) + '0')
35         .byte   $00             ; End of BASIC line
36 @Next:  .word   0               ; BASIC end marker
37
38 ; ------------------------------------------------------------------------
39 ; Startup code
40
41 .segment        "STARTUP"
42
43 Start:
44
45 ; Save the zero page locations we need
46
47         sei                     ; No interrupts since we're banking out the ROM
48         sta     ENABLE_RAM
49         ldx     #zpspace-1
50 L1:     lda     sp,x
51         sta     zpsave,x
52         dex
53         bpl     L1
54         sta     ENABLE_ROM
55         cli
56
57 ; Switch to second charset
58
59         lda     #14
60         jsr     $FFD2           ; BSOUT
61
62 ; Save system stuff and setup the stack. The stack starts at the top of the
63 ; usable RAM.
64
65         tsx
66         stx     spsave          ; save system stk ptr
67
68         lda     #<$FD00
69         sta     sp
70         lda     #>$FD00
71         sta     sp+1
72
73 ; Setup the IRQ vector in the banked RAM and switch off the ROM
74
75         ldx     #<IRQ
76         ldy     #>IRQ
77         sei                     ; No ints, handler not yet in place
78         sta     ENABLE_RAM
79         stx     $FFFE           ; Install interrupt handler
80         sty     $FFFF
81         cli                     ; Allow interrupts
82
83 ; Clear the BSS data
84
85         jsr     zerobss
86
87 ; Initialize irqcount, which means that from now own custom linked in IRQ
88 ; handlers (via condes) will be called.
89
90         lda     #.lobyte(__INTERRUPTOR_COUNT__*2)
91         sta     irqcount
92
93 ; Call module constructors
94
95         jsr     initlib
96
97 ; Push arguments and call main()
98
99         jsr     callmain
100
101 ; Back from main (this is also the _exit entry). Run module destructors.
102
103 _exit:  pha                     ; Save the return code
104         jsr     donelib         ; Run module destructors
105
106 ; Disable chained IRQ handlers
107
108         lda     #0
109         sta     irqcount        ; Disable custom IRQ handlers
110
111 ; Copy back the zero page stuff
112
113         ldx     #zpspace-1
114 L2:     lda     zpsave,x
115         sta     sp,x
116         dex
117         bpl     L2
118
119 ; Place the program return code into ST
120
121         pla
122         sta     ST
123
124 ; Restore the stack pointer
125
126         ldx     spsave
127         txs
128
129 ; Enable the ROM, reset changed vectors and return to BASIC
130
131         sta     ENABLE_ROM
132         jmp     $FF8A           ; RESTOR
133
134
135 ; ------------------------------------------------------------------------
136 ; IRQ handler. The handler in the ROM enables the kernal and jumps to
137 ; $CE00, where the ROM code checks for a BRK or IRQ and branches via the
138 ; indirect vectors at $314/$316.
139 ; To make our stub as fast as possible, we skip the whole part of the ROM
140 ; handler and jump to the indirect vectors directly. We do also call our
141 ; own interrupt handlers if we have any, so they need not use $314.
142
143 .segment        "LOWCODE"
144
145 IRQ:    cld                     ; Just to be sure
146         pha
147         txa
148         pha
149         tya
150         pha
151         tsx                     ; Get the stack pointer
152         lda     $0104,x         ; Get the saved status register
153         and     #$10            ; Test for BRK bit
154         bne     dobreak
155
156 ; It's an IRQ and RAM is enabled. If we have handlers, call them. We will use
157 ; a flag here instead of loading __INTERRUPTOR_COUNT__ directly, since the
158 ; condes function is not reentrant. The irqcount flag will be set/reset from
159 ; the main code, to avoid races.
160
161         ldy     irqcount
162         beq     @L1
163         jsr     callirq_y       ; Call the IRQ functions
164
165 ; Since the ROM handler will end with an RTI, we have to fake an IRQ return
166 ; on stack, so we get control of the CPU after the ROM handler and can switch
167 ; back to RAM.
168
169 @L1:    lda     #>irq_ret       ; Push new return address
170         pha
171         lda     #<irq_ret
172         pha
173         php                     ; Push faked IRQ frame on stack
174         pha                     ; Push faked A register
175         pha                     ; Push faked X register
176         pha                     ; Push faked Y register
177         sta     ENABLE_ROM      ; Switch to ROM
178         jmp     (IRQVec)        ; Jump indirect to kernal irq handler
179
180 irq_ret:
181         sta     ENABLE_RAM      ; Switch back to RAM
182         pla
183         tay
184         pla
185         tax
186         pla
187         rti
188
189 dobreak:
190         lda     brk_jmp+2       ; Check high byte of address
191         beq     nohandler
192         jmp     brk_jmp         ; Jump to the handler
193
194 ; No break handler installed, jump to ROM
195
196 nohandler:
197         sta     ENABLE_ROM
198         jmp     (BRKVec)        ; Jump indirect to the break vector
199
200 ; ------------------------------------------------------------------------
201 ; Data
202
203 .data
204
205 ; BRK handling
206 brk_jmp:        jmp     $0000
207
208 spsave:         .res    1
209
210 irqcount:       .byte   0
211
212 .segment        "ZPSAVE"
213
214 zpsave:         .res    zpspace
215
216