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

# zasm - Z80 Assembler – Version 4.4

# Including C Source Files

[<prev] [next>]

| ### 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: EQUequ 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, endifif 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.
    Assembler directives: #data
    Including C Source Files: #data#data _HEAP                 ; heap:
    __sdcc_heap_start:          ; --> sdcc _malloc.c
        Pseudo instructions: defs, ds, .ds, .block, .blkb and data
    8080 pseudo instructions: DSds  _min_heap_size      ; minimum required size
        Pseudo instructions: defs, ds, .ds, .block, .blkb and data
    8080 pseudo instructions: DSds  _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: DSds  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: SETset 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, endifif not done at the Pseudo instructions: end, .end
    8080 pseudo instructions: ENDend of _GSINIT itself)
        rst  0                  ; Assembler directives: #if, #elif, #else, #endif
    Pseudo instructions: if, endifif 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 |

[<prev] [top] [next>]