Closed feilipu closed 7 years ago
IIRC with the parameter passing a single byte is still using a whole word space, so you should increment sp twice, this is quite a common approach with many recent and historical compilers. You may know the FASTCALL trick for the single parameter passing, where a simple assignment to hl substitutes the heavy sp load/unload, usually provided by the compiler itself. The CALLEE option is a clever, slightly more complex option used to reduce the stack dependency when multiple parameters are needed.. as said it is a medium complexity topic, you can look at the already implemented functions and at their correspondent header definitions (a little redundant, look for the redefinitions,too).
Yes, I'm using __z88dk_fastcall
where I can. But the issue is most painful for the pdrv
bytes in disk_read
and disk_write
.
extern DSTATUS disk_initialize (BYTE pdrv) __z88dk_fastcall;
extern DSTATUS disk_status (BYTE pdrv) __z88dk_fastcall;
extern DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) __z88dk_callee;
extern DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) __z88dk_callee;
extern DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) __z88dk_callee;
I'll have to change my disk_ioctl
implementation, now I know that a char
uses one whole 16 bit stack push. Glad to know that now, rather than later. I'll dig into some further reading. Thanks :+1:
It is different for zsdcc and sccz80. zsdcc pushes one byte but sccz80 pushes two.
For every function, the library provides two entry points :- one with standard linkage (push, call, pop) and the other with fastcall or callee. The standard linkage is required for calls through a function pointer so if you don't care about that, you can skip it.
For fastcall, of course, the parameters are in registers so you don't need to worry about the stack and one byte pushes.
For callee, you do :)
Ok. So the short code segment in the question is the right way to do it then? I can't see a better way at the moment.
Ok. So the short code segment in the question is the right way to do it then? I can't see a better way at the moment.
ld a, (sp)
inc sp
The z180 doesn't have that instruction does it? I have to switch gears for the z180 but I think it's just mlt and the io instructions that have been added.
The best way to access single chars depends on the argument list.
If there are two chars in a row as in foo(unsigned char a, unsigned char b)
for zsdcc you can just pop into a register pair:
_foo:
pop hl ;; return address
ex (sp),hl ;; l = a, h = b
jp asm_foo
Sometimes it's less convenient as when a char is isolated amongst words. as in foo(unsigned char a, void *b)
:
_foo:
pop hl ;; return address
dec sp
pop bc ;; b = a
ex (sp),hl ;; hl = void *b
jp asm_foo
If the parameters are in reverse order foo(void *b, unsigned char a)
:
_foo:
pop af ;; return address
pop hl ;; hl = void *b
dec sp
pop bc ;; b = a
push af
jp asm_foo
These are all callee linkage where the parameters are removed from the stack by the called function. I'm also careful to separate the c interface from the asm implementation, mainly because I don't want to supply c overhead to people calling the asm implementation only, and I'm prepared to accommodate both C compilers as well as standard linkage for function pointers.
When the argument list gets longer, it can get hairy. There are examples in the c lib.
ld a, (sp)
inc sp
The z180 doesn't have that instruction does it? I have to switch gears for the z180 but I think it's just mlt and the io instructions that have been added.
🤦♂️ Of course, you're right. Which makes life substantially more complex, as you've described. Thanks for the code hints. Very useful.
I'm also careful to separate the c interface from the asm implementation,...
I'll follow that principal too. Generates a lot of files to manage, and lots of jump instructions, but sensible given the flexibility needed for multiple compilers and calling mechanisms.
If I've a C function definition that passes one or multiple
uint8_t
to an asm function, how is it (are they) represented on the stack? Is a single byte pushed onto the stack for eachchar
?Is the best way (or only way) to retrieve a
char
from the stack something like this?