That documentation is a little bit old but it will work (the scoping directives XLIB,XDEF,XREF are deprecated in favour of PUBLIC,EXTERN,GLOBAL). As mentioned, the preference now is to put the asm implementation into a separate asm file and the C interface to the asm implementation, the code that gathers params from stack, in its own asm file as well.
You should replace "#asm" and "#endasm" with "__asm" and "__endasm;" (note the semicolon) as the latter is acceptable to both compilers.
There is a little more on this topic here:
https://www.z88dk.org/wiki/doku.php?id= ... y_language
I looked at some of the examples from: libsrc/_DEVELOPMENT/string/z80/*.asm
But I'm still lost...
I'll give one example here using strcat:
The asm implementation for strcat was written first and called "asm_strcat.asm". Convention has "asm_" at the front of the name.
https://github.com/z88dk/z88dk/blob/mas ... strcat.asm
Because there are two arguments the best function call linkage is callee where the compiler/caller pushes the arguments onto the stack and the asm implementation pops them off so that the caller doesn't have to fix the stack after the call.
The header file reflects the linkage (taken from the classic library):
https://github.com/z88dk/z88dk/blob/mas ... e/string.h
Code: Select all
extern char __LIB__ *strcat(char *dst,const char *src) __smallc;
extern char __LIB__ *strcat_callee(char *dst,const char *src) __smallc __z88dk_callee;
#define strcat(a,b) strcat_callee(a,b)
There is a bit of magic here but a typical call will be to strcat_callee. There is a second c interface to a related function strcat that uses standard c linkage instead of callee. This is because the compilers must use standard linkage for function pointers. So function pointers will be assigned strcat rather than strcat_callee and this decision is made by the pre-processor.
Then the c interface for strcat_callee using callee linkage is:
https://github.com/z88dk/z88dk/blob/mas ... callee.asm
and the c interface for strcat using standard linkage is:
https://github.com/z88dk/z88dk/blob/mas ... strcat.asm
We're trying to get maximum performance and that's why it's a little more complicated than a straightforward implementation.
Can a C only solution be done somehow with some inline assembly? I just need one example BDOS call!
Yes you can, from the example you quoted above:
Code: Select all
int myfunc(char b, unsigned char *p) __smallc __naked
{
__asm
ld hl,2
add hl,sp ; skip over return address on stack
ld e,(hl)
inc hl
ld d,(hl) ; de = p
inc hl
ld a,(hl) ; a = b, "char b" occupies 16 bits on stack
; but only the LSB is relevant
...
ld hl,1 ; hl is the return parameter
ret
__endasm
}
The C wrapper is going to tell the C compiler how to call. The "__smallc" will ensure the compilers push parameters in left to right order. zsdcc will do right to left otherwise. The "__naked" ensures zsdcc will not put function prologue and epilogue around your asm code (and now a "ret" us required at the end).
Another point to consider: zsdcc pushes char types as one byte on the stack but sccz80 pushes two bytes for char. So either add some conditional assembly to distinguish the two ("IF __SDCC ... ELSE ... ENDIF") or avoid char parameters.
Any return value goes in a subset of DEHL. sccz80 expects 16-bits for char but zsdcc only 8. Float and 64-bit longlong (zsdcc only) are returned differently.
sccz80 allows any registers to be modified by asm but zsdcc requires ix to be preserved. If you have a call to bios in there you must save ix around the call for zsdcc.