Assembly Language - z88dk/z88dk GitHub Wiki

The entire library is accessible from assembly language. The assembly entry points for functions are prefixed with asm_ and the register interface for each function is documented in the source code rooted in {z88dk}/libsrc/_DEVELOPMENT. Here is a brief example that makes use of stdlib's dtoa() function to convert a double to ascii text:

; assumes math48 is the math library linked

SECTION code_user

EXTERN asm_dtoa

exx
ld bc,$490F      ; AC' = pi
ld de,$DAA2      ; math48 uses BCDEHL to hold a double
ld hl,$2182
exx

ld c,0           ; no flags
ld de,-1         ; max precision
ld hl,buffer     ; destination buffer

call asm_dtoa    ; write double in ddd.ddd format to buffer

...

SECTION bss_user

buffer:   defs 32

asm_dtoa is located in {z88dk}/libsrc/_DEVELOPMENT/stdlib/z80. The comments detail input parameters, output parameters and registers modified. The C documentation can also be consulted for more details.

Vararg functions such as printf expect their parameters to be pushed onto the stack. In these sorts of cases, the asm caller must use standard C linkage to call the function. Here is a brief example that uses printf:

; assumes sccz80 is the compiler
; L->R parameter order, varargs require A to be loaded with num words pushed onto stack

SECTION code_user

EXTERN asm_printf

ld hl,fmt       ; format string
push hl
ld hl,100       ; 100 dollars (16-bit integer)
push hl
ld a,2          ; sccz80 only, number of words pushed
call asm_printf
pop af
pop af          ; clear stack

...

SECTION rodata_user

fmt:  defm "You win %d dollars.\n"
      defb 0

The equivalent C is:

printf("You win %d dollars.\n", 100);

If this is a project compiled with sccz80 or if this is an assembly language project linked against the sccz80 library, then printf is expecting its parameters to be pushed in left-to-right order and the A register must be loaded with the number of 16-bit words pushed.

On the other hand if the project is compiled with sdcc or if this is an assembly language project linked against the sdcc library, then printf is expecting its parameters to be pushed in right-to-left order and nothing needs to be loaded into A.

More details can be found in the front#mixing_c_and_assembly_language topic. Most library functions are not vararg and asm parameters will be passed via register rather than stack.

You must also be aware that the new c library employs sections. Sections are destination containers that hold code and/or data and can have an ORG address associated with them. All assembly language written should be assigned to a section so that the linker can know where to place it in memory.

The crts previously discussed create three basic sections: CODE, DATA and BSS. These large sections hold many small ones, including some sections designated for user code:

  • code_user assign executable code to this section
  • rodata_user assign read-only data to this section
  • smc_user assign self-modifying code to this section
  • data_user assign non-zero initial data to this section
  • bss_user assign zero initial data to this section

By assigning your assembly code to the correct sections, the linker will be able to create ROMable software with your code.

You can also create your own sections. There's no magic incantation, simply start using it and assign a name as in:

SECTION my_section

start:

    ld hl,2
    ....
    ret

Since this section is not in the crts' memory map, all data or code assigned to it will be output as a separate binary when the project is assembled. The name of the binary will be outputname_my_section.bin. If no ORG is assigned to the section anywhere in your project, it is assigned an ORG of 0. (Note that un-ORGed sections may be appended to previously defined sections in the same source file; this is how memory maps are built with z80asm).

These details are best described in the front#mixing_c_and_assembly_language topic.