<--  back   Last regenerated: 2022-04-20 17:31:36 kio

zasm - Z80 Assembler – Version 4.4

Including C Source Files

Short tutorial for using C files

zasm can include C source files in your project. These will be compiled using the C compiler sdcc.

In a 'normal' C project you typically start writing C sources and then at some point wonder what the file crt0.s may do and then how to modify it. With zasm you start with an assembler file which mostly does what the crt0.s file should do. zasm also resolves global symbols from the system libraries and links your project into one binary.

The main assembler file must define a Assembler directives: #target
Including C Source Files: #target
#target, some #code and #data segments, implement the restart vectors, an interrupt and the nmi handler, initialize the system hardware, initialize variables and define _putchar and _getchar, Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if required.

Find the C compiler

When it comes to compiling a C source, zasm looks for the C compiler. Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
If it is not in your $PATH then you must tell zasm where it is with the Differences from v3 to v4: Command line options
Command Line Options
Command Line Options: Command line options
command line option -c.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

$> zasm -c /usr/bin/sdcc foo.asm
Locate the system headers

Next the C compiler needs to know where the system headers are when a C source includes some of them. The C compiler will look at the default locations, but you may pass it the include/ directory from the zasm distribution, which can be done with Differences from v3 to v4: Command line options
Command Line Options
Command Line Options: Command line options
command line option -I.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

$> zasm -I /work/sdcc/include foo.asm
Required segments

The C compiler sdcc Run test code and test your expectations: .expect register
Run test code and test your expectations: .expect cc
expects some segments to be defined in your source.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

_ram_start Pseudo instructions: equ
Types of labels: Named values
Labels: EQU
equ 0x4000 ; wherever   #target rom ; define the code model   Assembler directives: #code
Including C Source Files: #code
#code _HOME,0 ; code that must not be put in a bank switched part of memory. Assembler directives: #code
Including C Source Files: #code
#code _GSINIT ; init code: the compiler adds some code here and there as required Assembler directives: #code
Including C Source Files: #code
#code _CODE ; most code and const data go here Assembler directives: #code
Including C Source Files: #code
#code _INITIALIZER ; initializer data (in rom) for initialized variables (in ram) Assembler directives: #code
Including C Source Files: #code
#code _CABS,*,0 ; referenced but never (?) actually used by sdcc Assembler directives: #code
Including C Source Files: #code
#code _GSFINAL,*,0 ; referenced but never (?) actually used by sdcc   Assembler directives: #data
Including C Source Files: #data
#data _DATA, _ram_start ; uninitialized variables Assembler directives: #data
Including C Source Files: #data
#data _INITIALIZED ; variables initialized from _INITIALIZER Assembler directives: #data
Including C Source Files: #data
#data _DABS,*,0 ; referenced but never (?) actually used by sdcc Assembler directives: #data
Including C Source Files: #data
#data _RSEG,*,0 ; referenced but never (?) actually used by kcc

In this #insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
example the _HOME segment starts at address 0 and therefore must start with the handlers for the restart vectors. As an #insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
example see Examples/template_rom_with_c_code.asm.

Hint: as one of the very last lines in your source add a ret statement or directly a call to main() in _GSINIT:

Assembler directives: #code
Including C Source Files: #code
#code _GSINIT ; switch to segment _GSINIT call _main ; final action in _GSINIT: call main() rst 0 ; Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if it returns (which it shouldn't)
How to include C source files

The major file of your project must be an assembler file.
This file can include other assembler files or c source files.
C source files must Pseudo instructions: end, .end
8080 pseudo instructions: END
end with the file name extension '.c'.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

Assembler directives: #include
Including C Source Files: #include
#include "#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
example.c"
How to resolve symbols from the system library

Compiled C source files frequently contain references to procedures or other global symbols in the system libraries. These can be resolved automatically Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if your assembler file includes the system library with the Assembler directives: #include
Including C Source Files: #include
#include assembler directive after the last included c source file or after the last reference to an undefined symbol from the system library for the first time.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

#include: #include library
#include: #include library
#include standard library

This will resolve all symbols from the system library known as required at that point in your source.

As a prerequisite zasm must know where to find the system library directory. It is recommended to use the supplied directory from the distribution and then you have to tell zasm where it is. This can be done with the Differences from v3 to v4: Command line options
Command Line Options
Command Line Options: Command line options
command line option -L.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

$> zasm -L /work/sdcc/lib foo.asm

Alternatively you can give a path in the '#include: #include library
#include: #include library
#include library' directive itself:

#include: #include library
#include: #include library
#include library "/work/sdcc/lib"
Using a heap

Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
If you use malloc() etc. then you also need a heap. The actual requirements depend on the implementation of malloc() and free() and this is how it currently should work: (else refer to the implementations of lib/_malloc and lib/_mfree…)

Define data segment _HEAP as the last data segment Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if you want it to occupy all unused ram up to ram Pseudo instructions: end, .end
8080 pseudo instructions: END
end.

#data _HEAP                 ; heap:
__sdcc_heap_start:          ; --> sdcc _malloc.c
    Pseudo instructions: defs, ds, .ds, .block, .blkb and data
8080 pseudo instructions: DS
ds _min_heap_size ; minimum required size Pseudo instructions: defs, ds, .ds, .block, .blkb and data
8080 pseudo instructions: DS
ds _ram_end-$-1 ; add all unused memory to the heap __sdcc_heap_end: ; --> sdcc _malloc.c Pseudo instructions: defs, ds, .ds, .block, .blkb and data
8080 pseudo instructions: DS
ds 1
Initialization code

System initialization must be done in assembler as far as it cannot be done in C. An important step in system initialization is the initialization of initialized variables. After that main() must be called which should not return.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example:

_init:                      ; jump here from reset entry at 0x0000
    di
    ld  sp,_ram_end         ; Pseudo instructions: defl, set and '='
Labels: SET
set stack pointer ld bc,_initializer_len ; length of segment _INITIALIZER (must be calculated) ld de,_INITIALIZED ; start of segment _INITIALIZED ld hl,_INITIALIZER ; start of segment _INITIALIZER ld a,b or c jr z,$+4 ldir ; copy initializer data into initialized variables call _GSINIT ; Initialize global variables (whatever the c compiler has put in here) call _main ; call main() (Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if not done at the Pseudo instructions: end, .end
8080 pseudo instructions: END
end of _GSINIT itself) rst 0 ; Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if it returns
How to implement _putchar() and _getchar()

C will call the symbols _putchar and _getchar Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if your source includes any print or read function call. These cannot be provided by the standard system library because they are highly specific to your target system. Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
If C sources link against these symbols then you must provide appropriate definitions.

Eventually you can implement _putchar and _getchar in C, but Assembler directives: #if, #elif, #else, #endif
Pseudo instructions: if, endif
if you need to implement them in assembler, then you need to know how the C compiler passes the arguments.

Argument passing to and from functions may vary with compiler options, so i recommend that you first include dummy definitions for _putchar() and _getchar() in your project and inspect the list file generated by the assembler to see what the compiler does.

#insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
Example: in a C file define:

char inchar,outchar;
char getchar(void) { return inchar; }
void putchar(char c) { outchar = c; }

assemble your project and you may see the following assember source for _putchar and _getchar:

;char getchar(void) { return inchar; }
_getchar:
    ld  hl,#_inchar
    ld  l,(hl)
    ret

;void putchar(char c) { outchar = c; }
_putchar:
    push ix
    ld   ix,#0
    add  ix,sp
    ld   a, 4 (ix)
    ld   (#_outchar),a
    pop  ix
    ret

Use this as a template for your own implementation. For an #insert: Examples:
#assert: Example:
incbin: Examples:
#assert: Example:
example see Examples/zx_spectrum_io_rom.s

Valid HTML   Valid CSS