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