Next Previous Contents

## 3. Startup Code Definition

In the cc65 toolset, a startup routine must be defined that is executed when the CPU is reset. This startup code is marked with the STARTUP segment name, which was defined in the system configuration file as being in read only memory. The standard convention used in the predefined libraries is that this code is resident in the crt0 module. For this custom system, all that needs to be done is to perform a little bit of 6502 housekeeping, set up the C-level stack pointer, initialize the memory storage, and call the C-level routine `main ()`. The following code was used for the crt0 module, defined in the file "crt0.s":

> `

>     ; ---------------------------------------------------------------------------
>     ; crt0.s
>     ; ---------------------------------------------------------------------------
>     ;
>     ; Startup code for cc65 (Single Board Computer version)

>     .export   _init, _exit
>     .import   _main

>     .export   __STARTUP__ : absolute = 1        ; Mark as startup
>     .import   __RAM_START__, __RAM_SIZE__       ; Linker generated

>     .import    copydata, zerobss, initlib, donelib

>     .include  "zeropage.inc"

>     ; ---------------------------------------------------------------------------
>     ; Place the startup code in a special segment

>     .segment  "STARTUP"

>     ; ---------------------------------------------------------------------------
>     ; A little light 6502 housekeeping

>     _init:    LDX     #$FF                 ; Initialize stack pointer to $01FF
>               TXS
>               CLD                          ; Clear decimal mode

>     ; ---------------------------------------------------------------------------
>     ; Set cc65 argument stack pointer

>               LDA     #<(__RAM_START__ + __RAM_SIZE__)
>               STA     sp
>               LDA     #>(__RAM_START__ + __RAM_SIZE__)
>               STA     sp+1

>     ; ---------------------------------------------------------------------------
>     ; Initialize memory storage

>               JSR     zerobss              ; Clear BSS segment
>               JSR     copydata             ; Initialize DATA segment
>               JSR     initlib              ; Run constructors

>     ; ---------------------------------------------------------------------------
>     ; Call main()

>               JSR     _main

>     ; ---------------------------------------------------------------------------
>     ; Back from main (this is also the _exit entry):  force a software break

>     _exit:    JSR     donelib              ; Run destructors
>               BRK

> `

The following discussion explains the purpose of several important assembler level directives in this file.

> `

>     .export   _init, _exit

> `

This line instructs the assembler that the symbols `_init` and `_exit` are to be accessible from other modules. In this example, `_init` is the location that the CPU should jump to when reset, and `_exit` is the location that will be called when the program is finished.

> `

>     .import   _main

> `

This line instructs the assembler to import the symbol `_main` from another module. cc65 names all C-level routines as {underscore}{name} in assembler, thus the `main ()` routine in C is named `_main` in the assembler. This is how the startup code will link to the C-level code.

> `

>     .export   __STARTUP__ : absolute = 1        ; Mark as startup

> `

This line marks this code as startup code (code that is executed when the processor is reset), which will then be automatically linked into the executable code.

> `

>     .import   __RAM_START__, __RAM_SIZE__       ; Linker generated

> `

This line imports the RAM starting address and RAM size constants, which are used to initialize the cc65 C-level argument stack pointer.

> `

>     .segment  "STARTUP"

> `

This line instructs the assembler that the code is to be placed in the STARTUP segment of memory.

> `

>               JSR     zerobss              ; Clear BSS segment
>               JSR     copydata             ; Initialize DATA segment
>               JSR     initlib              ; Run constructors

> `

These three lines initialize the external (global) and system variables. The first line sets the BSS segment -- the memory locations used for external variables -- to 0. The second line copies the initialization value stored in ROM to the RAM locations used for initialized external variables. The last line runs the constructors that are used to initialize the system run-time variables.

> `

>               JSR     _main

> `

This is the actual call to the C-level `main ()` routine, which is called after the startup code completes.

> `

>     _exit:    JSR     donelib              ; Run destructors
>               BRK

> `

This is the code that will be executed when `main ()` terminates. The first thing that must be done is run the destructors via a call to `donelib`. Then the program can terminate. In this example, the program is expected to run forever. Therefore, there needs to be a way of indicating when something has gone wrong and the system needs to be shut down, requiring a restart only by a hard reset. The BRK instruction will be used to indicate a software fault. This is advantageous because cc65 uses the BRK instruction as the fill byte in the final binary code. In addition, the hardware has been designed to force the data lines to $00 for all illegal memory accesses, thereby also forcing a BRK instruction into the CPU.

Next Previous Contents