mirror of
https://github.com/KarolS/millfork.git
synced 2025-04-13 05:39:54 +00:00
Add guides to documentation
This commit is contained in:
parent
d5367cc1fe
commit
c6c021cf85
@ -79,6 +79,14 @@
|
||||
* [Game Boy–only modules](stdlib/gb.md)
|
||||
|
||||
* [X16–only modules](stdlib/x16.md)
|
||||
|
||||
## Guides
|
||||
|
||||
* [Differences from C](various/cdiff.md)
|
||||
|
||||
* [Differences from other assemblers](various/asmdiff.md)
|
||||
|
||||
* [Optimization guide](various/optimization.md)
|
||||
|
||||
## Implementation details
|
||||
|
||||
|
@ -81,6 +81,14 @@
|
||||
* [Game Boy–only modules](stdlib/gb.md)
|
||||
|
||||
* [X16–only modules](stdlib/x16.md)
|
||||
|
||||
## Guides
|
||||
|
||||
* [Differences from C](various/cdiff.md)
|
||||
|
||||
* [Differences from other assemblers](various/asmdiff.md)
|
||||
|
||||
* [Optimization guide](various/optimization.md)
|
||||
|
||||
## Implementation details
|
||||
|
||||
|
34
docs/various/asmdiff.md
Normal file
34
docs/various/asmdiff.md
Normal file
@ -0,0 +1,34 @@
|
||||
[< back to index](../doc_index.md)
|
||||
|
||||
# Differences in assembly
|
||||
|
||||
## Syntax
|
||||
|
||||
* High and low bytes of an 16-bit value are acquired using the `hi` and `lo` functions, not the `>` and `<` operators.
|
||||
|
||||
* Anonymous labels and local labels are not supported.
|
||||
All labels defined in assembly are global.
|
||||
Colons are required in label declarations.
|
||||
|
||||
* Macros are inserted using the `+` operator.
|
||||
|
||||
* Raw bytes are inserted using the Millfork array syntax, not with any pseudoopcode (like `!byte`, `db` or `fcb`)
|
||||
|
||||
* Assembly blocks cannot contain definitions of constants or variables.
|
||||
|
||||
* 6502: To enforce zero-page addressing, wrap the argument in the `lo` function: `lo(arg)`
|
||||
|
||||
* 6502: To enforce absolute addressing, add a 16-bit zero to the argument: `0000 + arg`
|
||||
|
||||
* GameBoy: The $FF page loads/stores are written `LDH (C),A`, not `LD ($FF00+C),A`.
|
||||
|
||||
* GameBoy: The loads/stores that postincrement/postdecrement HL write the HL register as `HLI` or `HLD`, not `HL+` or `HL-`
|
||||
|
||||
* Z80: Indexing using the index register uses the `IX(1)` syntax, not `(IX+1)` or `1(IX)`.
|
||||
|
||||
* Z80: Most undocumented instructions are not supported. The only one supported is `SLL`.
|
||||
|
||||
* 6809: `0,X` is assembled the same as `,X`.
|
||||
|
||||
|
||||
|
78
docs/various/cdiff.md
Normal file
78
docs/various/cdiff.md
Normal file
@ -0,0 +1,78 @@
|
||||
[< back to index](../doc_index.md)
|
||||
|
||||
# Differences from C
|
||||
|
||||
## Syntax
|
||||
|
||||
* Block comments `/* */` are not supported, use line comments `//`.
|
||||
|
||||
* You cannot put multiple statements on one line.
|
||||
Semicolons are allowed at the end of the line, but no code can follow them.
|
||||
|
||||
* There are no `++` or `--` operators. Use `+= 1` and `-= 1`.
|
||||
|
||||
* Pointer types are declared using the `pointer.` prefix, not `*` suffix. To dereference them, use `p[0]` instead of `*p`.
|
||||
|
||||
* There is no unary `&` operator.
|
||||
Pointers to an object are acquired using the `.pointer` suffix.
|
||||
Raw addresses are acquired using the `.addr` suffix.
|
||||
The numeric values of the pointer and of the raw address may differ.
|
||||
|
||||
* Operator precedence works differently.
|
||||
Bitwise and bitshift operators have the same precedence as arithmetic operators,
|
||||
and mixing different operators with the same precedence is usually forbidden.
|
||||
This prevents most ambiguities in bit-twiddling code, but requires care when porting code from or to C.
|
||||
|
||||
* There is no `!` operator. The negation is expressed as the `not` function.
|
||||
|
||||
* The modulo operator is written `%%`. As with `/`, it's only defined for unsigned division.
|
||||
|
||||
* The `for` loops are range-based. Arbitrary, C-like `for` loops are not supported.
|
||||
|
||||
* Variable declaration and initialization have to be separate.
|
||||
|
||||
* Integer literals starting with zero and containing just digits are decimal, not octal.
|
||||
For octal literals, use the `0o` prefix.
|
||||
|
||||
* String literals are not null-terminated by default. Use the `z` suffix for null-terminated strings.
|
||||
|
||||
* In `if`, `do/while`, `while` and `for` statements, parentheses are not required, but braces are.
|
||||
The `else` branch also requires braces, unless the only statement in the `else` block is an `if` statement.
|
||||
|
||||
* There has to be a space between many operators and character literals,
|
||||
as the parser may treat the apostrophe as a part of the operator.
|
||||
|
||||
## Preprocessor
|
||||
|
||||
* The preprocessor cannot expand symbols to something more complex than an identifier or a literal.
|
||||
|
||||
* The preprocessor cannot define symbols for use in other files.
|
||||
|
||||
* The closest to C's `#define` is `#use`.
|
||||
Unlike `#define`, such definitions are not visible within the preprocessor.
|
||||
|
||||
* Directives like `#use` and `#pragma` affect the entire file, not just the code after the directive.
|
||||
|
||||
* The preprocessor cannot include files.
|
||||
|
||||
## Semantics
|
||||
|
||||
* There is no automatic integer promotion. An operation of two bytes will yield a byte. For example:
|
||||
|
||||
byte a
|
||||
byte b
|
||||
word w
|
||||
w = a * b
|
||||
|
||||
may yield unexpected results. To prevent this, cast at least one argument:
|
||||
|
||||
w = word(a) * b
|
||||
|
||||
This issue applies mostly to the `*` and `<<` operators.
|
||||
|
||||
* There is no padding in structs.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -83,6 +83,10 @@ or generate a static binary and link it manually using the `file` directive.
|
||||
|
||||
Since the compiler is a work-in-progress, some of the mentioned issues might be improved upon in the future.
|
||||
|
||||
### I have experience with C and/or assembly. What should I keep in mind?
|
||||
|
||||
See the [differences from C](./cdiff.md) and the [differences from assembly](./asmdiff.md).
|
||||
|
||||
### Why is it called Millfork?
|
||||
|
||||
It stands for **MI**ddle **L**evel **L**anguage **FOR** **K**ommodore computers.
|
||||
|
103
docs/various/optimization.md
Normal file
103
docs/various/optimization.md
Normal file
@ -0,0 +1,103 @@
|
||||
[< back to index](../doc_index.md)
|
||||
|
||||
# Optimization guidelines
|
||||
|
||||
## Command-line options
|
||||
|
||||
* The default options provide literally no optimizations.
|
||||
Consider using at least `-O1` for quick compilation and `-O4` for release builds.
|
||||
|
||||
* Inlining can drastically improve performance. Add `-finline` to the command line.
|
||||
|
||||
* If you're not using self-modifying code or code generation,
|
||||
enabling interprocedural optimizations (`-fipo`) and stdlib optimizations (`-foptimize-stdlib`) can also help.
|
||||
|
||||
* For convenience, all options useful for debug builds can be enabled with `-Xd`,
|
||||
and for release builds with `-Xr`.
|
||||
|
||||
* 6502 only: If you are sure the target will have a CPU that supports so-called illegal/undocumented 6502 instructions,
|
||||
consider adding the `-fillegals` option. Good examples of such targets are NES and C64.
|
||||
|
||||
## Alignment
|
||||
|
||||
* Consider adding `align(fast)` or even `align(256)` to arrays which you want to access quickly.
|
||||
|
||||
* 6502 only: Consider adding `align(fast)` to the hottest functions.
|
||||
|
||||
* If you have an array of structs, consider adding `align(X)` to the definition of the struct,
|
||||
where `X` is a power of two. Even if this makes the struct 12 bytes instead of 11, it can still improve performance.
|
||||
|
||||
## Variables
|
||||
|
||||
* Use the smallest type you need. Note that Millfork supports integers of any size from 1 to 16 bytes.
|
||||
|
||||
* Consider using multiple arrays instead of arrays of structs.
|
||||
|
||||
* Avoid reusing temporary variables.
|
||||
It makes it easier for the optimizer to eliminate the variable entirely.
|
||||
|
||||
## Functions
|
||||
|
||||
* Write many functions with no parameters and use `-finline`.
|
||||
This will simplify the job for the optimizer and increase the chances of certain powerful optimizations to apply.
|
||||
|
||||
* Avoid passing many parameters to functions.
|
||||
Try to minimize the number of bytes passed as parameters and returned as return values.
|
||||
|
||||
## Loops
|
||||
|
||||
* For `for` loops that use a byte-sized variable and whose body does not involve function calls or further loops,
|
||||
use a unique iteration variable. Such variable will have a bigger chance of being stored in a CPU register.
|
||||
For example:
|
||||
|
||||
byte i
|
||||
byte j
|
||||
for i,0,until,30 { .... }
|
||||
for j,0,until,40 { .... }
|
||||
|
||||
is usually better than:
|
||||
|
||||
byte i
|
||||
for i,0,until,30 { .... }
|
||||
for i,0,until,40 { .... }
|
||||
|
||||
* 8080/Z80 only: The previous tip applies also for loops using word-sized variables.
|
||||
|
||||
* When the iteration order is not important, use `paralleluntil` or `parallelto`.
|
||||
The compiler will try to choose the optimal iteration order.
|
||||
|
||||
* Since 0.3.18: When the iteration order is not important,
|
||||
use `for ix,ptr:array` to iterate over arrays of structs.
|
||||
|
||||
* 6502 only: When iterating over an array larger than 256 bytes, whose element count is a composite number,
|
||||
consider splitting it into less-than-256-byte sized slices and use them within the same iteration.
|
||||
For example, instead of:
|
||||
|
||||
word i
|
||||
for i,0,paralleluntil,1000 {
|
||||
screen[i] = ' 'scr
|
||||
}
|
||||
|
||||
consider:
|
||||
|
||||
byte i
|
||||
for i,0,paralleluntil,250 {
|
||||
screen[i+000] = ' 'scr
|
||||
screen[i+250] = ' 'scr
|
||||
screen[i+500] = ' 'scr
|
||||
screen[i+750] = ' 'scr
|
||||
}
|
||||
|
||||
Note that the compiler might do this optimization automatically
|
||||
for simpler loops with certain iteration ranges, but it is not guaranteed.
|
||||
|
||||
# Arithmetic
|
||||
|
||||
* Avoid 16-bit arithmetic. Try to keep calculations 8-bit for as long as you can.
|
||||
If you can calculate the upper and lower byte of a 16-bit value separately, it's usually better to do so.
|
||||
|
||||
* Avoid arithmetic larger than 16-bit.
|
||||
|
||||
* Use `nonet` if you are sure that the result of shifting will fit into 9 bits.
|
||||
Use `nonet` when doing byte addition that you want to promote to a word.
|
||||
|
Loading…
x
Reference in New Issue
Block a user