]> git.sur5r.net Git - cc65/blobdiff - libsrc/cbm510/crt0.s
remove superfluous ".code" line
[cc65] / libsrc / cbm510 / crt0.s
index 1b0deb8c9226537b2a50001fe2c578304daae938..ef2cb8c6295a8256597c2016d1e5dc6c2bc03e1b 100644 (file)
@@ -1,49 +1,21 @@
 ;
 ; Startup code for cc65 (CBM 500 version)
-;
-; This must be the *first* file on the linker command line
 ;
 
        .export         _exit
-       .import         initlib, donelib
-       .import         push0, _main
-       .import         __BSS_RUN__, __BSS_SIZE__
-       .import         irq, nmi
-               .import         k_irq, k_nmi, k_plot, k_udtim, k_scnkey
+        .export         __STARTUP__ : absolute = 1      ; Mark as startup
 
-       .include        "zeropage.inc"
-       .include        "io.inc"
+       .import         _clrscr, initlib, donelib, callirq_y
+       .import         push0, callmain
+       .import         __CHARRAM_START__, __CHARRAM_SIZE__, __VIDRAM_START__
+       .import         __BSS_RUN__, __BSS_SIZE__, __EXTZP_RUN__
+       .import         __INTERRUPTOR_COUNT__
+       .import         scnkey, UDTIM
 
+       .include        "zeropage.inc"
+        .include        "extzp.inc"
+       .include        "cbm510.inc"
 
-; ------------------------------------------------------------------------
-; Define and export the ZP variables for the CBM510 runtime
-
-       .exportzp       sp, sreg, regsave
-       .exportzp       ptr1, ptr2, ptr3, ptr4
-       .exportzp       tmp1, tmp2, tmp3, tmp4
-       .exportzp       regbank, zpspace
-       .exportzp       vic, sid, IPCcia, cia, acia, tpi1, tpi2
-       .exportzp       ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
-
-.zeropage
-
-zpstart        = *
-sp:            .res    2       ; Stack pointer
-sreg:          .res    2       ; Secondary register/high 16 bit for longs
-regsave:       .res    2       ; slot to save/restore (E)AX into
-ptr1:          .res    2
-ptr2:          .res    2
-ptr3:          .res    2
-ptr4:          .res    2
-tmp1:          .res    1
-tmp2:          .res    1
-tmp3:          .res    1
-tmp4:          .res    1
-regbank:       .res    6       ; 6 byte register bank
-
-zpspace        = * - zpstart           ; Zero page space allocated
-
-.code
 
 ; ------------------------------------------------------------------------
 ; BASIC header and a small BASIC program. Since it is not possible to start
@@ -74,112 +46,266 @@ zpspace   = * - zpstart           ; Zero page space allocated
 ; that is overwritten later.
 ;
 
-; To make things more simple, make the code of this module absolute.
+.segment        "BASICHDR"
 
-       .org    $0001
-Head:  .byte   $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
+        .byte          $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
        .byte   $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
        .byte   $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
        .byte   $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
        .byte   $30,$2c,$31,$36,$39,$2c,$30,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
 
-; Since we need some vectors to access stuff in the system bank for our own,
-; we will include them here, starting from $60:
+;------------------------------------------------------------------------------
+; A table that contains values that must be transfered from the system zero
+; page into out zero page. Contains pairs of bytes, first one is the address
+; in the system ZP, second one is our ZP address. The table goes into page 2,
+; but is declared here, because it is needed earlier.
+
+.SEGMENT        "PAGE2"
+
+.proc   transfer_table
+
+        .byte   $CA, CURS_Y
+        .byte   $CB, CURS_X
+        .byte   $EC, CHARCOLOR
+
+.endproc
+
+
+;------------------------------------------------------------------------------
+; Page 3 data. This page contains the break vector and the bankswitch
+; subroutine that is copied into high memory on startup. The space occupied by
+; this routine will later be used for a copy of the bank 15 stack. It must be
+; saved, since we're going to destroy it when calling bank 15.
+
+.segment        "PAGE3"
+
+BRKVec: .addr   _exit           ; BRK indirect vector
+
+.proc   callbank15
+
+        excrts  = $FEFE
+
+.org    $FEC3
+
+entry:  php
+        pha
+        lda     #$0F                    ; Bank 15
+        sta     IndReg
+        txa
+        pha
+        tya
+        pha
+        sei
+        ldy     #$FF
+        lda     (sysp1),y
+        tay
+        lda     ExecReg
+        sta     (sysp1),y
+        dey
+
+        lda     #.hibyte(excrts-1)
+        sta     (sysp1),y
+        dey
+        lda     #.lobyte(excrts-1)
+        sta     (sysp1),y
+
+        tya
+        sec
+        sbc     #7
+        sta     $1FF                    ; Save new sp
+        tay
+
+        tsx
+
+        pla
+        iny
+        sta     (sysp1),y
+        pla
+        iny
+        sta     (sysp1),y
+        pla
+        iny
+        sta     (sysp1),y
+        pla
+        iny
+        sta     (sysp1),y
+
+        lda     $105,x
+        sec
+        sbc     #3
+        iny
+        sta     (sysp1),y
+        lda     $106,x
+        sbc     #0
+        iny
+        sta     (sysp1),y
+
+        ldy     $1FF                    ; Restore sp in bank 15
+
+        lda     #.hibyte(expull-1)
+        sta     (sysp1),y
+        dey
+        lda     #.lobyte(expull-1)
+        sta     (sysp1),y
+        dey
+        pla
+        pla
+        tsx
+        stx     $1FF
+        tya
+        tax
+        txs
+        lda     IndReg
+        jmp     $FFF6
+
+expull: pla
+        tay
+        pla
+        tax
+        pla
+        plp
+        rts
 
-       .res    $60-*
+.if (expull <> $FF26)
+.error "Symbol expull must be aligned with kernal in bank 15"
+.endif
 
-vic:           .word   $d800
-sid:           .word   $da00
-IPCcia:                .word   $db00
-cia:                   .word   $dc00
-acia:                  .word   $dd00
-tpi1:          .word   $de00
-tpi2:                  .word   $df00
-ktab1:         .word   $eab1
-ktab2:         .word   $eb11
-ktab3:         .word   $eb71
-ktab4:         .word   $ebd1
-time:          .dword  $0000
-RecvBuf:       .word   $0100           ; RS232 received buffer
-SendBuf:       .word   $0200           ; RS232 send buffer
+.reloc
 
+.endproc
 
+;------------------------------------------------------------------------------
 ; The code in the target bank when switching back will be put at the bottom
 ; of the stack. We will jump here to switch segments. The range $F2..$FF is
 ; not used by any kernal routine.
 
-       .res    $F8-*
-Back:  ldx     spsave
-       txs
-       lda     IndReg
-       sta     ExecReg
+.segment        "STARTUP"
+
+Back:   sta    ExecReg
 
-; The following code is a copy of the code that is poked in the system bank
-; memory by the basic header program, it's only for documentation and not
-; actually used here:
+; We are at $100 now. The following snippet is a copy of the code that is poked
+; in the system bank memory by the basic header program, it's only for
+; documentation and not actually used here:
 
        sei
-       lda     #$01
+       lda     #$00
        sta     ExecReg
 
 ; This is the actual starting point of our code after switching banks for
 ; startup. Beware: The following code will get overwritten as soon as we
-; use the stack (since it's in page 1)!
+; use the stack (since it's in page 1)! We jump to another location, since
+; we need some space for subroutines that aren't used later.
 
-       tsx
-               stx     spsave          ; Save the system stackpointer
-       ldx     #$FF
-       txs                     ; Set up our own stack
+        jmp     Origin
 
-; Set the interrupt, NMI and other vectors
+; Hardware vectors, copied to $FFFA
 
-       ldy     #vectable_size
-L0:    lda     vectable-1,y
-       sta     $FF80,y
-       dey
-               bne     L0
+.proc   vectors
+        sta     ExecReg
+        rts
+        nop
+               .word   nmi             ; NMI vector
+               .word   0               ; Reset - not used
+               .word   irq             ; IRQ vector
+.endproc
+
+; Initializers for the extended zeropage. See extzp.s
+
+.proc   extzp
+        .word   $0100           ; sysp1
+        .word   $0300           ; sysp3
+        .word          $d800           ; vic
+       .word   $da00           ; sid
+       .word   $db00           ; cia1
+       .word   $dc00           ; cia2
+       .word   $dd00           ; acia
+       .word   $de00           ; tpi1
+       .word   $df00           ; tpi2
+       .word   $eab1           ; ktab1
+       .word   $eb11           ; ktab2
+       .word   $eb71           ; ktab3
+       .word   $ebd1           ; ktab4
+.endproc
 
 ; Switch the indirect segment to the system bank
 
-       lda     #$0F
+Origin: lda    #$0F
        sta     IndReg
 
-; Copy the kernal zero page ($90-$F2) from the system bank
+; Initialize the extended zeropage
+
+        ldx     #.sizeof(extzp)-1
+L1:     lda     extzp,x
+        sta     <__EXTZP_RUN__,x
+        dex
+        bpl     L1
+
+; Save the old stack pointer from the system bank and setup our hw sp
+
+        tsx
+        txa
+        ldy     #$FF
+        sta     (sysp1),y       ; Save system stack point into $F:$1FF
+       ldx     #$FE            ; Leave $1FF untouched for cross bank calls
+       txs                     ; Set up our own stack
+
+; Copy stuff from the system zeropage to ours
+
+        lda     #.sizeof(transfer_table)
+        sta     ktmp
+L2:     ldx     ktmp
+        ldy     transfer_table-2,x
+        lda     transfer_table-1,x
+        tax
+        lda     (sysp0),y
+        sta     $00,x
+        dec     ktmp
+        dec     ktmp
+        bne     L2
 
-       lda     #$90
-       sta     ptr1
-       lda     #$00
-       sta     ptr1+1
-       ldy     #$62-1
-L1:    lda     (ptr1),y
-       sta     $90,y
-       dey
-       bpl     L1
+; Set the interrupt, NMI and other vectors
 
-; Copy the page 3 vectors in place
+       ldx     #.sizeof(vectors)-1
+L3:            lda     vectors,x
+       sta     $10000 - .sizeof(vectors),x
+       dex
+               bpl     L3
 
-       ldy     #$00
-L2:    lda     p3vectable,y
-       sta     $300,y
-       iny
-       cpy     #p3vectable_size
-               bne     L2
+; Setup the C stack
 
-; Copy the rest of page 3 from the system bank
+       lda     #.lobyte(callbank15::entry)
+       sta     sp
+       lda     #.hibyte(callbank15::entry)
+       sta     sp+1
 
-       lda     #$00
-       sta     ptr1
-       lda     #$03
-       sta     ptr1+1
-L3:    lda     (ptr1),y
-       sta     $300,y
-       iny
-       bne     L3
+; Setup the subroutine and jump vector table that redirects kernal calls to
+; the system bank.
+
+        ldy     #.sizeof(callbank15)
+@L1:    lda     callbank15-1,y
+        sta     callbank15::entry-1,y
+        dey
+        bne     @L1
+
+; Setup the jump vector table. Y is zero on entry.
+
+        ldx     #45-1                   ; Number of vectors
+@L2:    lda     #$20                    ; JSR opcode
+        sta     $FF6F,y
+        iny
+        lda     #.lobyte(callbank15::entry)
+        sta     $FF6F,y
+        iny
+        lda     #.hibyte(callbank15::entry)
+        sta     $FF6F,y
+        iny
+        dex
+        bpl     @L2
 
 ; Set the indirect segment to bank we're executing in
 
-       lda     ExecReg
-       sta     IndReg
+       lda     ExecReg
+       sta     IndReg
 
 ; Zero the BSS segment. We will do that here instead calling the routine
 ; in the common library, since we have the memory anyway, and this way,
@@ -200,7 +326,7 @@ Z1: sta     (ptr1),y
        iny
        bne     Z1
        inc     ptr1+1                  ; Next page
-       dex
+       dex
        bne     Z1
 
 ; Clear the remaining page
@@ -211,208 +337,248 @@ Z3:     sta     (ptr1),y
        iny
        dex
        bne     Z3
-Z4:
+Z4:     jmp     Init
 
-; Setup the C stack
+; ------------------------------------------------------------------------
+; We are at $200 now. We may now start calling subroutines safely, since
+; the code we execute is no longer in the stack page.
 
-       lda     #<$FF81
-       sta     sp
-               lda     #>$FF81
-       sta     sp+1
+.segment        "PAGE2"
 
-; We expect to be in page 2 now
+; Copy the character rom from the system bank into the execution bank
 
-.if    (* < $1FD)
-       jmp     $200
-       .res    $200-*
-.endif
-.if    (* < $200)
-       .res    $200-*,$EA
-.endif
-.if            (* >= $2F0)
-.error "Code range invalid"
-.endif
+Init:   lda     #<$C000
+       sta     ptr1
+       lda     #>$C000
+       sta     ptr1+1
+        lda    #<__CHARRAM_START__
+       sta     ptr2
+       lda     #>__CHARRAM_START__
+       sta     ptr2+1
+               lda     #>__CHARRAM_SIZE__      ; 16 * 256 bytes to copy
+       sta     tmp1
+       ldy     #$00
+ccopy: lda     #$0F
+       sta     IndReg                  ; Access the system bank
+ccopy1:        lda     (ptr1),y
+               sta     __VIDRAM_START__,y
+               iny
+               bne     ccopy1
+               lda     ExecReg
+               sta     IndReg
+ccopy2:        lda     __VIDRAM_START__,y
+               sta     (ptr2),y
+               iny
+               bne     ccopy2
+               inc     ptr1+1
+               inc     ptr2+1                  ; Bump high pointer bytes
+               dec     tmp1
+               bne     ccopy
+
+; Clear the video memory. We will do this before switching the video to bank 0
+; to avoid garbage when doing so.
+
+        jsr     _clrscr
+
+; Reprogram the VIC so that the text screen and the character ROM is in the
+; execution bank. This is done in three steps:
+
+        lda     #$0F                   ; We need access to the system bank
+               sta     IndReg
+
+; Place the VIC video RAM into bank 0
+; CA (STATVID)   = 0
+; CB (VICDOTSEL) = 0
+
+               ldy     #TPI::CR
+               lda     (tpi1),y
+               sta     vidsave+0
+               and     #%00001111
+               ora     #%10100000
+               sta     (tpi1),y
+
+; Set bit 14/15 of the VIC address range to the high bits of __VIDRAM_START__
+; PC6/PC7 (VICBANKSEL 0/1) = 11
+
+               ldy     #TPI::PRC
+               lda     (tpi2),y
+               sta     vidsave+1
+               and     #$3F
+               ora     #<((>__VIDRAM_START__) & $C0)
+               sta     (tpi2),y
+
+; Set the VIC base address register to the addresses of the video and
+; character RAM.
+
+        ldy    #VIC_VIDEO_ADR
+               lda     (vic),y
+               sta     vidsave+2
+       and     #$01
+               ora     #<(((__VIDRAM_START__ >> 6) & $F0) | ((__CHARRAM_START__ >> 10) & $0E) | $02)
+;              and     #$0F
+;              ora     #<(((>__VIDRAM_START__) << 2) & $F0)
+               sta     (vic),y
+
+; Switch back to the execution bank
+
+        lda     ExecReg
+               sta     IndReg
+
+; Activate chained interrupt handlers, then enable interrupts.
+
+        lda     #.lobyte(__INTERRUPTOR_COUNT__*2)
+        sta     irqcount
+       cli
 
-; This code is in page 2, so we may now start calling subroutines safely,
-; since the code we execute is no longer in the stack page.
-; Call module constructors
+; Call module constructors.
 
-       jsr     initlib
+        jsr    initlib
 
-; Create the (empty) command line for the program
+; Push arguments and call main()
 
-               jsr     push0           ; argc
-               jsr     push0           ; argv
+               jsr     callmain
 
-; Execute the program code
+; Call module destructors. This is also the _exit entry and the default entry
+; point for the break vector.
 
-       jmp     Start
+_exit:  pha                    ; Save the return code on stack
+        jsr    donelib         ; Run module destructors
+       lda     #$00
+        sta     irqcount        ; Disable custom irq handlers
 
-; ------------------------------------------------------------------------
-; Additional data that we need for initialization and that's overwritten
-; later
-
-vectable:
-       jmp     $0000           ; CINT
-       jmp     $0000           ; IOINIT
-       jmp     $0000           ; RAMTAS
-       jmp     $0000           ; RESTOR
-       jmp     $0000           ; VECTOR
-       jmp     $0000           ; SETMSG
-       jmp     $0000           ; SECOND
-       jmp     $0000           ; TKSA
-       jmp     $0000           ; MEMTOP
-       jmp     $0000           ; MEMBOT
-       jmp     k_scnkey        ; SCNKEY
-       jmp     $0000           ; SETTMO
-       jmp     $0000           ; ACPTR
-       jmp     $0000           ; CIOUT
-       jmp     $0000           ; UNTLK
-       jmp     $0000           ; UNLSN
-       jmp     $0000           ; LISTEN
-       jmp     $0000           ; TALK
-       jmp     $0000           ; READST
-               jmp     k_setlfs        ; SETLFS
-               jmp     k_setnam        ; SETNAM
-       jmp     $0000           ; OPEN
-       jmp     $0000           ; CLOSE
-       jmp     $0000           ; CHKIN
-       jmp     $0000           ; CKOUT
-       jmp     $0000           ; CLRCH
-       jmp     $0000           ; BASIN
-       jmp     $0000           ; BSOUT
-       jmp     $0000           ; LOAD
-       jmp     $0000           ; SAVE
-       jmp     k_settim        ; SETTIM
-               jmp     k_rdtim         ; RDTIM
-       jmp     $0000           ; STOP
-       jmp     $0000           ; GETIN
-       jmp     $0000           ; CLALL
-       jmp     k_udtim         ; UDTIM
-       jmp     k_screen        ; SCREEN
-       jmp     k_plot          ; PLOT
-       jmp     k_iobase        ; IOBASE
-       sta     ExecReg
-       rts
-       .byte   $01             ; Filler
-               .word   nmi
-               .word   0               ; Reset - not used
-               .word   irq
-vectable_size  = * - vectable
+; Address the system bank
 
-p3vectable:
-       .word   k_irq           ; IRQ user vector
-       .word   k_brk           ; BRK user vector
-       .word   k_nmi           ; NMI user vector
-p3vectable_size        = * - p3vectable
+        lda     #$0F
+        sta     IndReg
 
+; Switch back the video to the system bank
 
-; ------------------------------------------------------------------------
-; This is the program code after setup. It starts at $400
-
-       .res    $400-*
+       ldy     #TPI::CR
+       lda     vidsave+0
+       sta     (tpi1),y
 
-Start:
+       ldy     #TPI::PRC
+       lda     vidsave+1
+       sta     (tpi2),y
 
-; Enable interrupts
+        ldy    #VIC_VIDEO_ADR
+       lda     vidsave+2
+       sta     (vic),y
 
-       cli
+; Copy stuff back from our zeropage to the systems
 
-; Call the user code
+.if 0
+        lda     #.sizeof(transfer_table)
+        sta     ktmp
+@L0:    ldx     ktmp
+        ldy     transfer_table-2,x
+        lda     transfer_table-1,x
+        tax
+        lda     $00,x
+        sta     (sysp0),y
+        dec     ktmp
+        dec     ktmp
+        bne     @L0
+.endif
 
-               ldy     #4              ; Argument size
-               jsr     _main           ; call the users code
+; Place the program return code into ST
 
-; Call module destructors. This is also the _exit entry.
+       pla
+       ldy     #$9C            ; ST
+       sta     (sysp0),y
 
-_exit: jsr     donelib         ; Run module destructors
+; Setup the welcome code at the stack bottom in the system bank.
 
-; Clear the start of the zero page, since it will be interpreted as a
-; (garbage) BASIC program otherwise. This is also the default entry for
-; the break vector.
+        ldy     #$FF
+        lda     (sysp1),y       ; Load system bank sp
+        tax
+        iny                     ; Y = 0
+        lda     #$58            ; CLI opcode
+        sta     (sysp1),y
+        iny
+        lda     #$60            ; RTS opcode
+        sta     (sysp1),y
+       lda     IndReg
+        sei
+       txs
+        jmp     Back
 
-k_brk: sei
-       lda     #$00
-       ldx     #$3E
-Clear: sta     $02,x
-       dex
-       bne     Clear
+; -------------------------------------------------------------------------
+; The IRQ handler goes into PAGE2. For performance reasons, and to allow
+; easier chaining, we do handle the IRQs in the execution bank (instead of
+; passing them to the system bank).
 
-; Setup the welcome code at the stack bottom in the system bank. Use
-; the F4/F5 vector to access the system bank
+; This is the mapping of the active irq register of the        6525 (tpi1):
+;
+; Bit   7       6       5       4       3       2       1       0
+;                               |       |       |       |       ^ 50 Hz
+;                               |       |       |       ^ SRQ IEEE 488
+;                               |       |       ^ cia
+;                               |       ^ IRQB ext. Port
+;                               ^ acia
+
+irq:    pha
+        txa
+        pha
+        tya
+        pha
+        lda     IndReg
+        pha
+        lda     ExecReg
+        sta     IndReg                  ; Be sure to address our segment
+       tsx
+               lda     $105,x                  ; Get the flags from the stack
+       and     #$10                    ; Test break flag
+               bne     dobrk
+
+; It's an IRQ
+
+        cld
+
+; Call chained IRQ handlers
+
+               ldy     irqcount
+        beq     irqskip
+               jsr     callirq_y               ; Call the functions
+
+; Done with chained IRQ handlers, check the TPI for IRQs and handle them
+
+irqskip:lda    #$0F
+       sta     IndReg
+       ldy     #TPI::AIR
+       lda     (tpi1),y                ; Interrupt Register 6525
+       beq     noirq
 
-       lda     #$0F
-       sta     IndReg
-       ldy     #$00
-               sty     $F4
-       iny
-       sty     $F5
-       ldy     #reset_size-1
-@L1:   lda     reset,y
-       sta     ($F4),y
-       dey
-       bne     @L1
-       jmp     Back
+; 50/60Hz interrupt
 
-; ------------------------------------------------------------------------
-; Code that is copied into the system bank at $100 when switching back
+       cmp     #%00000001              ; ticker irq?
+       bne     irqend
+               jsr     scnkey                  ; Poll the keyboard
+        jsr    UDTIM                   ; Bump the time
 
-reset: cli
-       jmp     $8000                   ; BASIC cold start
-reset_size = * - reset
+; Done
 
-; ------------------------------------------------------------------------
-; Code for a few simpler kernal calls goes here
-
-k_iobase:
-       ldx     cia
-       ldy     cia+1
-       rts
-
-k_screen:
-               ldx     #40             ; Columns
-       ldy     #25             ; Lines
-       rts
-
-k_setlfs:
-        sta     LogicalAdr
-        stx     FirstAdr
-        sty     SecondAdr
-        rts
+irqend:        ldy     #TPI::AIR
+               sta     (tpi1),y                ; Clear interrupt
 
-k_setnam:
-        sta     FileNameLen
-        lda     $00,x
-        sta     FileNameAdrLo
-        lda     $01,x
-        sta     FileNameAdrHi
-        lda     $02,x
-        sta     FileNameAdrSeg
-        rts
+noirq: pla
+        sta     IndReg
+        pla
+        tay
+        pla
+        tax
+        pla
+nmi:   rti
 
-k_rdtim:
-       sei
-       lda     time+0
-       ldx     time+1
-       ldy     time+2
-       cli
-       rts
-
-k_settim:
-       sei
-       sta     time+0
-       stx     time+1
-       sty     time+2
-       cli
-       rts
+dobrk:  jmp    (BRKVec)
 
 ; -------------------------------------------------------------------------
-; Data area - switch back to relocatable mode
-
-       .reloc
+; Data area
 
 .data
-spsave:        .res    1
+vidsave:.res   3
 
+.bss
+irqcount:       .byte   0