diff options
| -rw-r--r-- | crates/nasm/README.md | 138 |
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 |
