]> git.sur5r.net Git - cc65/blob - libsrc/cbm510/crt0.s
More P500 support
[cc65] / libsrc / cbm510 / crt0.s
1 ;
2 ; Startup code for cc65 (CBM 500 version)
3 ;
4 ; This must be the *first* file on the linker command line
5 ;
6
7         .export         _exit
8         .import         _clrscr, initlib, donelib
9         .import         push0, _main
10         .import         __BSS_RUN__, __BSS_SIZE__
11         .import         irq, nmi
12         .import         k_irq, k_nmi, k_plot, k_udtim, k_scnkey
13
14         .include        "zeropage.inc"
15         .include        "io.inc"
16
17
18 ; ------------------------------------------------------------------------
19 ; Define and export the ZP variables for the CBM510 runtime
20
21         .exportzp       sp, sreg, regsave
22         .exportzp       ptr1, ptr2, ptr3, ptr4
23         .exportzp       tmp1, tmp2, tmp3, tmp4
24         .exportzp       regbank, zpspace
25         .exportzp       vic, sid, cia1, cia2, acia, tpi1, tpi2
26         .exportzp       ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
27
28 .zeropage
29
30 zpstart = *
31 sp:             .res    2       ; Stack pointer
32 sreg:           .res    2       ; Secondary register/high 16 bit for longs
33 regsave:        .res    2       ; slot to save/restore (E)AX into
34 ptr1:           .res    2
35 ptr2:           .res    2
36 ptr3:           .res    2
37 ptr4:           .res    2
38 tmp1:           .res    1
39 tmp2:           .res    1
40 tmp3:           .res    1
41 tmp4:           .res    1
42 regbank:        .res    6       ; 6 byte register bank
43
44 zpspace = * - zpstart           ; Zero page space allocated
45
46 .code
47
48 ; ------------------------------------------------------------------------
49 ; BASIC header and a small BASIC program. Since it is not possible to start
50 ; programs in other banks using SYS, the BASIC program will write a small
51 ; machine code program into memory at $100 and start that machine code
52 ; program. The machine code program will then start the machine language
53 ; code in bank 0, which will initialize the system by copying stuff from
54 ; the system bank, and start the application.
55 ;
56 ; Here's the basic program that's in the following lines:
57 ;
58 ; 10 for i=0 to 4
59 ; 20 read j
60 ; 30 poke 256+i,j
61 ; 40 next i
62 ; 50 sys 256
63 ; 60 data 120,169,0,133,0
64 ;
65 ; The machine program in the data lines is:
66 ;
67 ; sei
68 ; lda     #$00
69 ; sta     $00           <-- Switch to bank 0 after this command
70 ;
71 ; Initialization is not only complex because of the jumping from one bank
72 ; into another. but also because we want to save memory, and because of
73 ; this, we will use the system memory ($00-$3FF) for initialization stuff
74 ; that is overwritten later.
75 ;
76
77 ; To make things more simple, make the code of this module absolute.
78
79         .org    $0001
80 Head:   .byte   $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
81         .byte   $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
82         .byte   $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
83         .byte   $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
84         .byte   $30,$2c,$31,$36,$39,$2c,$30,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
85
86 ; Since we need some vectors to access stuff in the system bank for our own,
87 ; we will include them here, starting from $60:
88
89         .res    $60-*
90
91 vic:            .word   $d800
92 sid:            .word   $da00
93 cia1:           .word   $db00
94 cia2:           .word   $dc00
95 acia:           .word   $dd00
96 tpi1:           .word   $de00
97 tpi2:           .word   $df00
98 ktab1:          .word   $eab1
99 ktab2:          .word   $eb11
100 ktab3:          .word   $eb71
101 ktab4:          .word   $ebd1
102 time:           .dword  $0000
103 RecvBuf:        .word   $0100           ; RS232 received buffer
104 SendBuf:        .word   $0200           ; RS232 send buffer
105
106
107 ; The code in the target bank when switching back will be put at the bottom
108 ; of the stack. We will jump here to switch segments. The range $F2..$FF is
109 ; not used by any kernal routine.
110
111         .res    $F8-*
112 Back:   ldx     spsave
113         txs
114         lda     IndReg
115         sta     ExecReg
116
117 ; The following code is a copy of the code that is poked in the system bank
118 ; memory by the basic header program, it's only for documentation and not
119 ; actually used here:
120
121         sei
122         lda     #$00
123         sta     ExecReg
124
125 ; This is the actual starting point of our code after switching banks for
126 ; startup. Beware: The following code will get overwritten as soon as we
127 ; use the stack (since it's in page 1)!
128
129         tsx
130         stx     spsave          ; Save the system stackpointer
131         ldx     #$FF
132         txs                     ; Set up our own stack
133
134 ; Set the interrupt, NMI and other vectors
135
136         ldy     #vectable_size
137 L0:     lda     vectable-1,y
138         sta     $FF80,y
139         dey
140         bne     L0
141
142 ; Switch the indirect segment to the system bank
143
144         lda     #$0F
145         sta     IndReg
146
147 ; Copy the kernal zero page ($90-$F2) from the system bank
148
149         lda     #$90
150         sta     ptr1
151         lda     #$00
152         sta     ptr1+1
153         ldy     #$62-1
154 L1:     lda     (ptr1),y
155         sta     $90,y
156         dey
157         bpl     L1
158
159 ; Copy the page 3 vectors in place
160
161         ldy     #$00
162 L2:     lda     p3vectable,y
163         sta     $300,y
164         iny
165         cpy     #p3vectable_size
166         bne     L2
167
168 ; Copy the rest of page 3 from the system bank
169
170         lda     #$00
171         sta     ptr1
172         lda     #$03
173         sta     ptr1+1
174 L3:     lda     (ptr1),y
175         sta     $300,y
176         iny
177         bne     L3
178
179 ; Set the indirect segment to bank we're executing in
180
181         lda     ExecReg
182         sta     IndReg
183
184 ; Zero the BSS segment. We will do that here instead calling the routine
185 ; in the common library, since we have the memory anyway, and this way,
186 ; it's reused later.
187
188         lda     #<__BSS_RUN__
189         sta     ptr1
190         lda     #>__BSS_RUN__
191         sta     ptr1+1
192         lda     #0
193         tay
194
195 ; Clear full pages
196
197         ldx     #>__BSS_SIZE__
198         beq     Z2
199 Z1:     sta     (ptr1),y
200         iny
201         bne     Z1
202         inc     ptr1+1                  ; Next page
203         dex
204         bne     Z1
205
206 ; Clear the remaining page
207
208 Z2:     ldx     #<__BSS_SIZE__
209         beq     Z4
210 Z3:     sta     (ptr1),y
211         iny
212         dex
213         bne     Z3
214 Z4:
215
216 ; Setup the C stack
217
218         lda     #<$FF81
219         sta     sp
220         lda     #>$FF81
221         sta     sp+1
222
223 ; We expect to be in page 2 now
224
225 .if     (* < $1FD)
226         jmp     $200
227         .res    $200-*
228 .endif
229 .if     (* < $200)
230         .res    $200-*,$EA
231 .endif
232 .if     (* >= $2F0)
233 .error  "Code range invalid"
234 .endif
235
236 ; This code is in page 2, so we may now start calling subroutines safely,
237 ; since the code we execute is no longer in the stack page.
238
239 ; Clear the video memory. We will do this before switching the video to bank 0
240 ; to avoid garbage when doing so.
241
242         jsr     _clrscr
243
244 ; Reprogram the VIC so that the text screen is at $F800 in the execution bank
245 ; This is done in three steps:
246
247         lda     #$0F                    ; We need access to the system bank
248         sta     IndReg
249
250 ; Place the VIC video RAM into bank 0
251 ; CA (STATVID) = 0
252
253         ldy     #tpiCtrlReg
254         lda     (tpi1),y
255         sta     vidsave+0
256         and     #$CF
257         ora     #$20
258         sta     (tpi1),y
259
260 ; Set bit 14/15 of the VIC address range to the high bits of VIDEO_RAM
261 ; PC6/PC7 (VICBANKSEL 0/1) = 11
262
263         ldy     #tpiPortC
264         lda     (tpi2),y
265         sta     vidsave+1
266         and     #$3F
267         ora     #((>VIDEO_RAM) & $C0)
268         sta     (tpi2),y
269
270 ; Set bits 10-13 of the VIC address range to address F800
271
272         ldy     #VIC_VIDEO_ADR
273         lda     (vic),y
274         sta     vidsave+2
275         and     #$0F
276         ora     #(((>VIDEO_RAM) & $3F) << 2)
277         sta     (vic),y
278
279 ; Switch back to the execution bank
280
281         lda     ExecReg
282         sta     IndReg
283
284 ; Call module constructors
285
286         jsr     initlib
287
288 ; Create the (empty) command line for the program
289
290         jsr     push0           ; argc
291         jsr     push0           ; argv
292
293 ; Execute the program code
294
295         jmp     Start
296
297 ; ------------------------------------------------------------------------
298 ; Additional data that we need for initialization and that's overwritten
299 ; later
300
301 vectable:
302         jmp     $0000           ; CINT
303         jmp     $0000           ; IOINIT
304         jmp     $0000           ; RAMTAS
305         jmp     $0000           ; RESTOR
306         jmp     $0000           ; VECTOR
307         jmp     $0000           ; SETMSG
308         jmp     $0000           ; SECOND
309         jmp     $0000           ; TKSA
310         jmp     $0000           ; MEMTOP
311         jmp     $0000           ; MEMBOT
312         jmp     k_scnkey        ; SCNKEY
313         jmp     $0000           ; SETTMO
314         jmp     $0000           ; ACPTR
315         jmp     $0000           ; CIOUT
316         jmp     $0000           ; UNTLK
317         jmp     $0000           ; UNLSN
318         jmp     $0000           ; LISTEN
319         jmp     $0000           ; TALK
320         jmp     $0000           ; READST
321         jmp     k_setlfs        ; SETLFS
322         jmp     k_setnam        ; SETNAM
323         jmp     $0000           ; OPEN
324         jmp     $0000           ; CLOSE
325         jmp     $0000           ; CHKIN
326         jmp     $0000           ; CKOUT
327         jmp     $0000           ; CLRCH
328         jmp     $0000           ; BASIN
329         jmp     $0000           ; BSOUT
330         jmp     $0000           ; LOAD
331         jmp     $0000           ; SAVE
332         jmp     k_settim        ; SETTIM
333         jmp     k_rdtim         ; RDTIM
334         jmp     $0000           ; STOP
335         jmp     $0000           ; GETIN
336         jmp     $0000           ; CLALL
337         jmp     k_udtim         ; UDTIM
338         jmp     k_screen        ; SCREEN
339         jmp     k_plot          ; PLOT
340         jmp     k_iobase        ; IOBASE
341         sta     ExecReg
342         rts
343         .byte   $01             ; Filler
344         .word   nmi
345         .word   0               ; Reset - not used
346         .word   irq
347 vectable_size   = * - vectable
348
349 p3vectable:
350         .word   k_irq           ; IRQ user vector
351         .word   k_brk           ; BRK user vector
352         .word   k_nmi           ; NMI user vector
353 p3vectable_size = * - p3vectable
354
355
356 ; ------------------------------------------------------------------------
357 ; This is the program code after setup. It starts at $400
358
359         .res    $400-*
360
361 Start:
362
363 ; Enable interrupts
364
365         cli
366
367 ; Call the user code
368
369         ldy     #4              ; Argument size
370         jsr     _main           ; call the users code
371
372 ; Call module destructors. This is also the _exit entry.
373
374 _exit:  jsr     donelib         ; Run module destructors
375
376 ; We need access to the system bank now
377
378         lda     #$0F
379         sta     IndReg
380
381 ; Switch back the video to the system bank
382
383         ldy     #tpiCtrlReg
384         lda     vidsave+0
385         sta     (tpi1),y
386
387         ldy     #tpiPortC
388         lda     vidsave+1
389         sta     (tpi2),y
390
391         ldy     #VIC_VIDEO_ADR
392         lda     vidsave+2
393         sta     (vic),y
394
395 ; Clear the start of the zero page, since it will be interpreted as a
396 ; (garbage) BASIC program otherwise. This is also the default entry for
397 ; the break vector.
398
399 k_brk:  sei
400         lda     #$00
401         ldx     #$3E
402 Clear:  sta     $02,x
403         dex
404         bne     Clear
405
406 ; Setup the welcome code at the stack bottom in the system bank. Use
407 ; the F4/F5 vector to access the system bank
408
409         ldy     #$00
410         sty     $F4
411         iny
412         sty     $F5
413         ldy     #reset_size-1
414 @L1:    lda     reset,y
415         sta     ($F4),y
416         dey
417         bne     @L1
418         jmp     Back
419
420 ; ------------------------------------------------------------------------
421 ; Code that is copied into the system bank at $100 when switching back
422
423 reset:  cli
424         jmp     $8000                   ; BASIC cold start
425 reset_size = * - reset
426
427 ; ------------------------------------------------------------------------
428 ; Code for a few simpler kernal calls goes here
429
430 k_iobase:
431         ldx     cia2
432         ldy     cia2+1
433         rts
434
435 k_screen:
436         ldx     #40             ; Columns
437         ldy     #25             ; Lines
438         rts
439
440 k_setlfs:
441         sta     LogicalAdr
442         stx     FirstAdr
443         sty     SecondAdr
444         rts
445
446 k_setnam:
447         sta     FileNameLen
448         lda     $00,x
449         sta     FileNameAdrLo
450         lda     $01,x
451         sta     FileNameAdrHi
452         lda     $02,x
453         sta     FileNameAdrSeg
454         rts
455
456 k_rdtim:
457         sei
458         lda     time+0
459         ldx     time+1
460         ldy     time+2
461         cli
462         rts
463
464 k_settim:
465         sei
466         sta     time+0
467         stx     time+1
468         sty     time+2
469         cli
470         rts
471
472 ; -------------------------------------------------------------------------
473 ; Data area - switch back to relocatable mode
474
475         .reloc
476
477 .data
478 spsave: .res    1
479 vidsave:.res    3
480
481