2019-07-15 12:21:50 +00:00
|
|
|
|
[< back to index](../doc_index.md)
|
2018-04-02 22:21:26 +00:00
|
|
|
|
|
2018-01-04 00:15:04 +00:00
|
|
|
|
# Function definitions
|
|
|
|
|
|
2018-01-18 21:35:25 +00:00
|
|
|
|
Syntax:
|
|
|
|
|
|
2018-10-04 19:33:10 +00:00
|
|
|
|
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [@ <address>] { <body> }`
|
2018-01-18 21:35:25 +00:00
|
|
|
|
|
2019-04-15 17:56:14 +00:00
|
|
|
|
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [@ <address>] = <expression>`
|
|
|
|
|
|
2018-03-15 22:09:19 +00:00
|
|
|
|
`[segment (<segment>)] asm <return_type> <name> ( <params> ) @ <address> extern`
|
|
|
|
|
|
2019-08-05 12:07:33 +00:00
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
|
|
void do_nothing() { }
|
|
|
|
|
inline byte two() = 2
|
|
|
|
|
extern asm void chkout(byte a) @ $FFD2
|
|
|
|
|
segment(prgrom0) void main_loop(word w, byte x) align(fast) { // body omitted
|
|
|
|
|
|
|
|
|
|
|
2018-08-03 15:26:26 +00:00
|
|
|
|
* `<segment>`: segment name; if absent, then defaults to `default_code_segment` as defined for the platform (usually `default`)
|
2018-01-18 21:35:25 +00:00
|
|
|
|
|
|
|
|
|
* `<modifiers>`: zero or more of the following:
|
|
|
|
|
|
2018-03-05 11:05:37 +00:00
|
|
|
|
* `asm` – the function is written in assembly, not in Millfork (obligatory for `extern` functions),
|
2018-08-03 15:26:26 +00:00
|
|
|
|
see [Using 6502 assembly within Millfork programs#Assembly functions](./assembly.md#assembly-functions)
|
2019-05-31 15:03:35 +00:00
|
|
|
|
or [Using 8080/LR35902/Z80 assembly within Millfork programs#Assembly functions](./assemblyz80.md#assembly-functions);
|
|
|
|
|
for 8086, see the [8086 support disclaimer](./x86disclaimer.md).
|
2018-01-18 21:35:25 +00:00
|
|
|
|
|
2018-02-01 21:39:38 +00:00
|
|
|
|
* `macro` – the function is a macro,
|
|
|
|
|
see [Macros_and inlining#Macros](../abi/inlining.md#macros)
|
|
|
|
|
|
2018-03-05 11:05:37 +00:00
|
|
|
|
* `inline` – the function should preferably be inlined
|
2018-07-30 22:58:43 +00:00
|
|
|
|
see [Macros_and inlining#Inlining](../abi/inlining.md#automatic-inlining)
|
2018-01-18 21:35:25 +00:00
|
|
|
|
|
2018-03-05 11:05:37 +00:00
|
|
|
|
* `noinline` – the function should never be inlined
|
|
|
|
|
|
|
|
|
|
* `interrupt` – the function is a hardware interrupt handler.
|
|
|
|
|
You are not allowed to call such functions directly.
|
2018-06-04 14:24:18 +00:00
|
|
|
|
The function cannot have parameters and the return type should be `void`.
|
2018-03-05 11:05:37 +00:00
|
|
|
|
|
|
|
|
|
* `kernal_interrupt` – the function is an interrupt handler called from a generic vendor-provider hardware interrupt handler.
|
|
|
|
|
The hardware instruction handler is assumed to have preserved the CPU registers,
|
|
|
|
|
so this function only has to preserve the zeropage pseudoregisters.
|
|
|
|
|
An example is the Commodore 64 interrupt handler that calls the function at an address read from $314/$315.
|
2019-06-05 16:34:32 +00:00
|
|
|
|
Unlike hardware handlers with `interrupt`, you can treat functions with `kernal_interrupt` like normal functions.
|
|
|
|
|
On non-6502-based targets, functions marked as `kernal_interrupt` don't differ from normal functions.
|
2018-01-18 21:35:25 +00:00
|
|
|
|
|
|
|
|
|
* `<return_type>` is a valid return type, see [Types](./types.md)
|
|
|
|
|
|
|
|
|
|
* `<params>` is a comma-separated list of parameters, in form `type name`. Allowed types are the same as for local variables.
|
2019-07-09 20:40:14 +00:00
|
|
|
|
For assembly functions, certain parameter names are interpreted as CPU registers.
|
2018-01-18 21:35:25 +00:00
|
|
|
|
|
2018-10-04 19:33:10 +00:00
|
|
|
|
* `<alignment>` is either a numeric literal that is a power of 2, or keyword `fast`.
|
|
|
|
|
The function will be allocated at the address divisible by alignment.
|
|
|
|
|
`fast` means different things depending on the target platform:
|
|
|
|
|
|
2019-06-05 16:34:32 +00:00
|
|
|
|
* on 6502, it means that the function will not cross a page boundary if possible
|
2018-10-04 19:33:10 +00:00
|
|
|
|
* on Z80, it is ignored
|
|
|
|
|
|
2018-01-18 21:35:25 +00:00
|
|
|
|
* `<address>` is a constant expression that defines where in the memory the function is or will be located.
|
|
|
|
|
|
|
|
|
|
* `extern` is a keyword than marks functions that are not defined in the current program,
|
|
|
|
|
but are likely to be available at certain address in memory.
|
|
|
|
|
Such functions should be marked as written in assembly and should have their parameters passed through registers.
|
|
|
|
|
|
|
|
|
|
* `<body>` is a newline-separated list of either Millfork or assembly statements
|
|
|
|
|
|
2019-04-15 17:56:14 +00:00
|
|
|
|
* `<expression>` is an expression. It is equivalent to a function body of form `{ return <expression> }`.
|
|
|
|
|
|
2019-07-30 20:49:32 +00:00
|
|
|
|
The address of an non-macro function `f` is a constant `f.addr`.
|
|
|
|
|
|
|
|
|
|
Non-macro, non-interrupt functions which have max one parameter of size max 2 bytes
|
|
|
|
|
and return `void` or a value of size max 2 bytes,
|
|
|
|
|
can be accessed via a pointer.
|
|
|
|
|
|
|
|
|
|
void f() {}
|
|
|
|
|
|
|
|
|
|
function.void.to.void p = f.pointer
|
|
|
|
|
|
|
|
|
|
call(p)
|
|
|
|
|
|
|
|
|
|
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.
|