aboutsummaryrefslogtreecommitdiff
path: root/crates/nasm
diff options
context:
space:
mode:
Diffstat (limited to 'crates/nasm')
-rw-r--r--crates/nasm/README.md138
1 files changed, 138 insertions, 0 deletions
diff --git a/crates/nasm/README.md b/crates/nasm/README.md
index bc58232..6283f72 100644
--- a/crates/nasm/README.md
+++ b/crates/nasm/README.md
@@ -54,6 +54,144 @@ important. Hence, the following code is valid in `nasm`, but not in `ca65`:
Variable = $00
```
+### Interfaces specific to `nasm`
+
+In contrast to `ca65`, there are some nasm-specific features. First of all,
+`nasm` defines the `__NASM__` variable by default, with an integer value of
+`1`. This way, if you plan on using something nasm-specific, you can always do
+something like:
+
+```asm
+.ifdef __NASM__
+ ;; whatever
+.endif
+```
+
+The main design of this assembler from the interface's perspective was to be as
+close to `ca65` as possible. Thus, using `__NASM__` shouldn't happen, as it's
+expected from code written targetting `ca65` to "just work" on `nasm`. That
+being said, if you use `nasm` there might be some specific features which are
+missing in `ca65`. In this case, `nasm` has the `--prelude` flag, which will
+print some code that can fill the gaps when running `ca65` with some
+nasm-specific code. See below.
+
+#### The `__fallthrough__` pseudo-instruction
+
+It's a [well-known
+optimizaion](https://www.nesdev.org/wiki/6502_assembly_optimisations) to avoid
+`jsr` + `rts` chains, and that's why programmers usually change `jsr` with `jmp`
+in cases such as this:
+
+```asm
+.proc foo
+ ;; code
+ jmp bar
+
+ ;; instead of:
+ ;; jsr bar
+ ;; rts
+.endproc
+
+;; comments, documentation, blank lines, whatever
+
+.proc bar
+ ;; code
+ rts
+.endproc
+```
+
+But if you try to assemble this code by using `nasm` you will get the following
+warning:
+
+```asm
+warning: unconditional jump that points to the next instruction (bad_fallthrough.s: line 11)
+```
+
+This is because `foo` and `bar` happen to be contiguous and `nasm` is telling
+you that a further optimization can be done by removing the `jmp` instruction
+altogether. This is "falling through" the code as it's done in high-level
+programming languages such as C. Hence:
+
+```asm
+.proc foo
+ ;; code
+ ;; fall through 'bar'
+.endproc
+
+;; comments, documentation, blank lines, whatever
+
+.proc bar
+ ;; code
+ rts
+.endproc
+```
+
+In these cases, when reading the code, a programmer might not be totally sure on
+whether the code is missing an `rts` or a `jmp` instruction, or whether this
+falling through was done on purpose. Hence, as it's done above, one idea is to
+leave a comment for future reference.
+
+But `nasm` also provides the `__fallthrough__` pseudo-instruction, which allows
+developers to explicitly specify that the code flow is expected to fall through
+to the next instruction, even if the code layout might not make this obvious, or
+it might seem an accident. Hence, the above could have been written like so:
+
+```asm
+.proc foo
+ ;; code
+ __fallthrough__
+.endproc
+
+;; comments, documentation, blank lines, whatever
+
+.proc bar
+ ;; code
+ rts
+.endproc
+```
+
+This is not that much different than writing a comment. But this
+pseudo-instruction also accepts an argument, which is the label that you expect
+the code to fall through. Hence, the previous code can be better written like
+this:
+
+```asm
+.proc foo
+ ;; code
+ __fallthrough__ bar
+.endproc
+
+;; comments, documentation, blank lines, whatever
+
+.proc bar
+ ;; code
+ rts
+.endproc
+```
+
+This is semantically similar, but we are also stating that we expect to fall to
+the first instruction of `bar`. That is, if now the programmer moves `bar`
+somewhere else, or puts some code in between both functions, then the assembler
+will issue the following error:
+
+```
+error: statement expects to progress on 'bar' ($8004), but the next address is $8002 (bad_fallthrough.s: line 11)
+```
+
+This way, programmers can perform this optimization while also making sure that
+the assembler will catch the error whenever code moves around.
+
+Last but not least, the `--prelude` flag provides a default implementation so
+`ca65` doesn't break on an otherwise unknown `__fallthrough__` identifier. The
+implementation looks like this:
+
+```asm
+.ifndef __NASM__
+ .macro __fallthrough__ arg
+ .endmacro
+.endif
+```
+
## Mappers
By default `nasm` will assume the configuration for an `NROM` mapper, but this