9. Target specifics

This chapter describes the built-in target-specific support.

The support is enabled using the --target option which has the following effects:

  • Select a suitable default --core.

  • Enable preprocessor macros to identify the target and core used. This can be used for conditional compilation, in both the compiler and the assembler.

  • Additional target specific header files can be included using #include <file.h>.

  • Enable certain language extensions to suit the target, if applicable. This will also affect certain aspects of the code generator to take advantage of extensions and capabilities of the target.

  • When using --target the linker will assume a RAM based system where a program is loaded into memory and data sections are initialized by loading the data in place. This is a sensible default, but can be controlled using the --rom-code and --copy-initialize options.

The installation comes with header files, pre-built target specific board support link libraries and linker control files.

9.1. Board support

Enabling board support in the linker requires two conditions: First, specify the appropriate --target option. Second, use a supplied linker control file whose name corresponds to the board support.

For example, this means that to select to link with a Commander X16 board support you need to specify:

$ ln6502  --target=x16  cx16-plain.scm  [object-files]

For a MEGA65 target you would specify:

$ ln6502  --target=mega65  mega65-plain.scm  [object-files]

Note

If you need to alter the supplied linker rules file or create your own, name it with the same prefix name as the board support one. The linker will first look in the current directory for the .scm file, then in the installation directory.

The following table gives an overview of the board support definition.

Table 9.1 Board support definitions

--target

name

core

kernel/OS

.scm prefix

PRG entry

C64

Commodore 64

6502

Kernal

c64-

0x801

MEGA65

MEGA65

45GS02

Kernel

mega65-

0x2001

CX16

Commander X16

65C02

Kernel

cx16-

0x801

9.2. Commodore 64

The Commodore 64 is a well-known classic computer using the 6502 core. The Calypsi C compiler tool chain supports creating Commodore 64 friendly interrupt functions using the kernal_interrupt attribute. While the Commodore 64 has the ability to swap in and out overlayed ROMs, it is otherwise a plain 64K addressed machine.

Board support

The board support includes C header files, a link library and linker control files. They originate from Commodore 64 board support project. The current variant is built from commit hash d9c0ff8d5a4dae6937e58a88ced346e645182b5a.

The header files come from the LLVM MOS SDK project. The current variant is built from commit hash a1ae3437888ef0a597f69019611390eb8159c2e4.

Header files

The supplied header files are:

Table 9.2 Commodore 64 header files

include path

description

#include <c64.h>

Includes all Commodore 64 headers

#include <_6526.h>

6526 Complex Interface Adapter

#include <_sid.h>

SID sound chip

#include <_vic2.h>

VIC-II graphics chip

Pre-built library

The Commodore 64 library, which includes startup code, exit handling, and I/O adaption between the C library and the C64 Kernal, comes pre-built. Your application is automatically linked with it if you specify --target=64 and use a linker rules file starting with the c64- prefix:

$ ln6502  --target=c64  c64-plain.scm  [object-files]

The installation provides several library variants to accommodate different compiler settings, such as double size. The linker automatically selects a compatible variant for your application.

Linker rules

The linker rules use the c64- prefix. If you create your own linker rules file, naming it with this prefix ensures automatic linking with the supplied pre-built Commodore 64 library.

c64-plain.scm

(define memories
  '((memory program
            (address (#x801 . #x9fff)) (type any)
            (section (programStart #x801) (startup #x80e)))
    (memory zeroPage (address (#x2 . #xff)) (type ram) (qualifier zpage))
    (memory stackPage (address (#x100 . #x1ff)) (type ram))
    (memory freeSpace (address (#x02a7 . #x02ff)) (section zpsave))
    (memory upperdata
            (address (#xc000 . #xcfff))
            (section cstack zdata heap))
    ))

This memory system uses the full BASIC RAM area, allowing data to reside in the 0xc000 to 0xcfff area.

Preserving the zero page

The C compiler runtime reserves approximately 50 bytes of zero page space. On a Commodore 64, the BASIC runtime reserves most of the zero page. Returning to BASIC with a corrupted state can make the BASIC runtime unstable.

If your application needs to return safely to BASIC, request these zero page locations be preserved. To enable preserving the C runtime zero page area, add the following line to your application:

#pragma require __preserve_zp

Note

If you run the application multiple times in RAM, non-zero static storage variables are left with their previous value and are not reinitialized when the --target=c64 option is used. To properly initialize such variables on each run, you need to also use the --rom-code option.

9.3. MEGA65

The MEGA65 is a new 8 bit computer inspired by the Commodore 65. It comes with a 45GS02 instruction set which is a superset of the 6502 instruction set. The 45GS02 provides both additional instructions as well as new addressing modes.

The cc6502 compiler can generate code for the 45GS02 instruction set and it can also make use of its additional addressing modes. The 45GS02 provides 32 bit addressing modes to allow access the full memory space. The alternative bank system provided by the MEGA65 is not used by cc6502 compiler when accessing data beyond 64K.

Code banking on the other hand makes use of an 8K slot and the MAP instruction of the 45GS02.

The math co-processor on the MEGA65 is supported by the compiler which means it will inline integer multiply and unsigned divide. While the math unit is used, interrupts are disabled to prevent a potential race condition if an interrupt function also uses the math unit.

Board support

The board support includes C header files, a link library and linker control files. They originate from MEGA65 board support project. The current variant is built from commit hash d9c0ff8d5a4dae6937e58a88ced346e645182b5a.

The header files come from the LLVM MOS SDK project. The current variant is built from commit hash a1ae3437888ef0a597f69019611390eb8159c2e4.

Header files

The supplied header files are:

Table 9.3 MEGA65 header files

include path

description

#include <mega65.h>

Includes all MEGA65 headers

#include <_sid.h>

SID sound chip

#include <_vic2.h>

VIC-II graphics chip

#include <_vic3.h>

VIC-III graphics chip

#include <_vic4.h>

VIC-IV graphics chip

#include <_6526.h>

6526 Complex Interface Adapter

#include <_45E100.h>

45E100 Fast Ethernet controller

Pre-built library

The MEGA65 library includes startup code, exit handling and I/O adaption between the C library and the MEGA65 kernel. It comes pre-built and your application will automatically be linked with it if you specify --target=mega65 and use a linker rules file starting with the mega65- prefix:

$ ln6502  --target=mega65  mega65-plain.scm  [object-files]

The installation provides several library variants to accommodate different compiler settings, such as double size. The linker automatically selects a compatible variant for your application.

Linker rules

The linker rules are named with the mega65- prefix. If you create your own linker rules file, it is a good idea to name it with this prefix, as this will make the linker automatically link with the supplied pre-built MEGA65 library.

mega65-plain.scm

(define memories
  '((memory program
            (address (#x2001 . #x9fff)) (type any)
            (section (programStart #x2001) (startup #x200e)))
    (memory zeroPage (address (#x2 . #x7f)) (type ram) (qualifier zpage)
        (section (registers #x2)))
    (memory stackPage (address (#x100 . #x1ff)) (type ram))
    (memory freeSpace (address (#x1600 . #x1eff)) (section zpsave))
    ))

This describes memory system that uses the full BASIC memory area and keeps everything in the first 64K bank.

mega65-banked.scm

(define memories
  '((memory program
            (address (#x2001 . #x9fff)) (type any)
            (section (programStart #x2001) (startup #x200e)))
    (memory zeroPage (address (#x2 . #x7f)) (type ram) (qualifier zpage)
        (section (registers #x2)))
    (memory stackPage (address (#x100 . #x1ff)) (type ram))
    (memory freeSpace (address (#x1600 . #x1eff)) (section zpsave))
    (memory bank1  (address (#x10000 . #x1ffff)) (type data) (qualifier far))
    (memory bank45 (address (#x40000 . #x5ffff)) (type data) (qualifier far))
    ))

This describes memory system that uses the full BASIC memory area and allows Far data to be located in bank 1, 4 and 5.

Notes on 45GS02 instruction set

The assembler syntax used mostly follows the MEGA65 book. The 45GS02 uses some overloaded opcodes, e.g. for NOP and NEG instructions which may change the meaning depending of the instruction that follows. This is recognized and handled by the Calypsi tools.

Conditional long branch instruction deviates from the MEGA65 book in that they are prefixed by an L character, e.g. LBCC for a long branch on carry clear. This is done to distinguish them from the normal short form.

Data beyond 64K

The memory space attributes provided by the cc6502 compiler allows transparent access to the full memory. There are two pointer attributes far and huge which allows access to the full system memory. They differ in that far limits the object size to a single bank which is 64K. Any far C object is allocated into one such bank and is not allowed to cross a bank boundary.

If you need to use larger objects, then you can use the huge memory space. A huge object can be as large as the system memory allows.

Accessing data beyond 64K with either far or huge comes with some additional cost in terms of code space and execution time.

Note

The reason that far uses fictive 64K banks is to give better code generation as pointers arithmetics only need to update the lower 16 bits rather than the full 32-bit address.

Code beyond 64K

To access code outside the 64K memory the MAP instruction in the 45GS02 is used. This allows for mapping an 8K bank of code at a time to the slot at address 0xa000-0xbfff by default.

Preserving the zero page

The C compiler runtime reserves roughly 50 bytes of zero page space. On a MEGA65 the zero page is mostly reserved by the BASIC runtime. Returning to BASIC with a corrupted state can make the BASIC runtime unstable.

If your application needs to return safely to BASIC, request these zero page locations be preserved. To enable preserving the C runtime zero page area, add the following line to your application:

#pragma require __preserve_zp

Note

If you run the application multiple times in RAM, non-zero static storage variables are left with their previous value and are not reinitialized when the --target=mega65 option is used. To properly initialize such variables on each run, you need to also use the --rom-code option.

9.4. Commander X16

The Commander X16 system is based around a 64K memory space with RAM and ROM banking. The VERA graphics chip holds the keeps the video memory in a separate memory that is not directly addressable by the 65C02 CPU.

The Commander X16 board support currently do not provide mechanisms to automatically handle banked memory or the VERA video RAM.

The kernel used is based on the Commodore 64 kernel. There is support for creating kernel friendly interrupt functions using the kernal_interrupt attribute.

Board support

The board support includes C header files, a link library and linker control files. They originate from Commander X16 board support project. The current variant is built from commit hash d9c0ff8d5a4dae6937e58a88ced346e645182b5a.

The header files come from the LLVM MOS SDK project. The current variant is built from commit hash a1ae3437888ef0a597f69019611390eb8159c2e4.

Header files

The supplied header files are:

Table 9.4 Commander X16 header files

include path

description

#include <cx16.h>

Includes all Commander X16 headers

#include <_6522.h>

6522 Versatile Interface Adapter

Pre-built library

The Commander X16 library includes startup code, exit handling and I/O adaption between the C library and the Commander X16 kernel. It comes pre-built and your application will automatically be linked with it if you specify --target=x16 and use a linker rules file starting with the cx16- prefix:

$ ln6502  --target=cx16  cx16-plain.scm  [object-files]

The installation provides several library variants to accommodate different compiler settings, such as double size. The linker automatically selects a compatible variant for your application.

Linker rules

The linker rules are named with the cx16- prefix. If you create your own linker rules file, it is a good idea to name it with this prefix, as this will make the linker automatically link with the supplied pre-built Commander X16 library.

cx16-plain.scm

(define memories
  '((memory program
            (address (#x801 . #x9fff)) (type any)
            (section (programStart #x801) (startup #x80e)))
    (memory zeroPage (address (#x2 . #x7f)) (type ram) (qualifier zpage)
        (section (registers #x2)))
    (memory stackPage (address (#x100 . #x1ff)) (type ram))
    (memory VRAM (address (#x00000 . #x1ffff))
        (section zvram vram))
    ))

This describes memory system that uses the full BASIC memory area.

cx16-banked.scm

(define memories
  '((memory program
            (address (#x801 . #x9fff)) (type any)
            (section (programStart #x801) (startup #x80e)))
    (memory zeroPage (address (#x2 . #x7f)) (type ram) (qualifier zpage)
        (section (registers #x2)))
    (memory stackPage (address (#x100 . #x1ff)) (type ram))
    (memory VRAM (address (#x00000 . #x1ffff))
        (section zvram vram))
    (memory bankSlotRAM
        (address (#xa000 . #xbfff))
        (scatter-to RAM-banks)
        :generate-instances
        (section bankedcode))
    (memory bankedRAM (address (#x2000 . #x1fffff))
        (section RAM-banks))
    ))

This describes memory system that uses the full BASIC memory area and allows for banked code in the 0xa0000xbfff slot.

9.5. Linking

When linking for a system like the Commodore 64, MEGA65 or Commander X16 you will normally use a binary load format such as PRG, PGZ or RAW.

Such file is typically loaded from some storage media and doing this can initialize data sections by as part of the load process. This is enabled by either specifying the --target or the --hosted command-line option.

You may want to place the application in a ROM or flash memory so that it can be started either by turning on the computer or having it act like a resident application invoked by some call mechanism from the operating system. Use the --rom-code command-line option to get this bevaior. This creates a ROM section with initializers that are copied over to RAM as part of the initialization process before the main() function is called.

Note

Loading a program from media that is compiled with --hosted (or --target) and then restarting the program again will not re-initialize static variables that are non-zero. They will keep their values after the previous run. If you want to be able to restart a loaded program, consider linking with the --rom-code command-line option.

9.6. Banked linking

Banked memory can be set up using the scatter-to property of a memory. See Scatter for an overview.

To map in a memory bank in a slot in the 64K memory area the compiler translates the scatter-to (storage) address of the bank in a way that works with the bank system. This is done using a target dependent relocation operator. The low portion of the address are formed by combining the address of the slot and low portion of the address.

Somewhat simplified, once properly linked, the compiler runtime handles the bank system automatically.

Custom bank systems

Using scatter-to combined with manual manipulation of the bank mechanism also allows for making your own bank system. In such situations you probably need to control where functions are placed, which can be done using custom sections. see Description of pragma directives.

Clever management of section names allows for placing code together with data so that they appear in the same bank and are visible together when mapped into a block.

Note

For advanced custom bank system function inlining may cause problems. This is because functions may be inlined in other functions that belong in different sections. If data is being stored together, you may want to prevent such inlining from happening. You can use the --inline-on-matching-custom-text-section command-line option to prevent it, see Controlling inline expansion.