====== C calling convention ======
A C compiler typically defines a //calling convention// - a set of rules used for mapping C function arguments and return values to the CPU's registers and stack, allowing
the //caller// (the function making the call) and the //callee// (the function being called) to put and retrieve data from the same locations.
If you're writing both the callee and caller in assembly, you are free to define your own calling convention. However, if you're interfacing with C code, you will need
to follow the C compiler's expectations for where this data is to be placed.
Wonderful currently uses the ''20180813'' version of the ''regparmcall'' calling convention as defined by the gcc-ia16 compiler.
===== Function arguments =====
For typical functions, the first three arguments or words, whichever comes first, are passed via the registers
''AX'', ''DX'' and ''CX'', in this order. Bytes are passed via ''AL'', ''DL'' and ''CL''. The remaining arguments are pushed
onto the stack.
Individual arguments are not split between registers and stack. A far pointer, or 32-bit integer, will be passed via ''DX:AX'', ''CX:DX'', or entirely on the stack.
For functions which contain //variable arguments//, all arguments are pushed onto the stack. It is the callee's responsibility to remove arguments off the stack.
For example, the following function signature:
void outportw(uint8_t port, uint16_t value);
results in the argument ''port'' being passed in the register ''AL'', and ''value'' - in the register ''DX''.
The following function signature:
void __far* memcpy(void __far* s1, const void __far* s2, size_t n);
results in the following calling convention:
* ''DX:AX'' = ''s1'',
* stack (4 bytes allocated) = ''s2'',
* stack (2 bytes allocated) = ''n'',
* the return value is placed in ''DX:AX''.
===== Caller and callee responsibilities =====
The registers ''AX'', ''BX'', ''CX'', ''DX'' can be modified by the callee freely. This means that the caller //cannot// expect their value to stay the same before and after calling the function.
Conversely, the remaining registers - ''SI'', ''DI'', ''BP'', ''DS'', ''ES'' and ''SS'' must be //saved// by the callee. This allows the caller to expect their value to stay unchanged at the expense of the callee, who
is now the party needing to ensure that this is the case - that is, that their values are the same at the beginning and end of the function.