aboutsummaryrefslogtreecommitdiff
path: root/crates/nasm
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2025-09-04 07:56:44 +0200
committerMiquel Sabaté Solà <mikisabate@gmail.com>2025-09-04 07:56:44 +0200
commit14c8f64f38b601398a144d507c0183016d27b87c (patch)
tree9646b2094cbae3022418a8183f454f8436f566dd /crates/nasm
parent2e99bdfed0d4f0cd78f03886155ff175e115bb77 (diff)
downloadtools.nes-14c8f64f38b601398a144d507c0183016d27b87c.tar.gz
tools.nes-14c8f64f38b601398a144d507c0183016d27b87c.zip
Move and expand the README on nasm
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'crates/nasm')
-rw-r--r--crates/nasm/README.md174
1 files changed, 174 insertions, 0 deletions
diff --git a/crates/nasm/README.md b/crates/nasm/README.md
new file mode 100644
index 0000000..5e2fa69
--- /dev/null
+++ b/crates/nasm/README.md
@@ -0,0 +1,174 @@
+## Usage
+
+The most basic way to use this assembler is by running:
+
+```
+$ nasm awesome.s
+```
+
+This will produce an `out.nes` file placed under the same working directory. You
+can change the name of the file with the `-o/--output` flag. Hence, you can call
+it like so:
+
+```
+$ nasm -o awesome.nes awesome.s
+```
+
+Moreover, you can actually tell `nasm` to redirect the output to stdout instead
+with the `--stdout` flag. This is useful when debugging the binary format with
+another CLI tool. For example:
+
+```
+$ nasm --stdout awesome.s | hexdump -C
+```
+
+The syntax for this assembler is virtually the same as the one for
+[ca65](https://cc65.github.io/doc/ca65.html), even if some functions might be
+missing. One difference that you will find in contrast with `ca65` is that
+`nasm` is a bit more pedantic. Let's consider the following example:
+
+```asm
+.scope Scope
+ .macro MACRO
+ lda #0
+ .endmacro
+.endscope
+```
+
+Here `ca65` will place `MACRO` on the global scope. `nasm` will do the same but
+it will also print a warning telling the programmer about this, as this might be
+unexpected at first. Hence, as a general rule `nasm` will be more noisy than
+`ca65`, in the hope that the programmer is more aware about the end result.
+
+## Mappers
+
+By default `nasm` will assume the configuration for an `NROM` mapper, but this
+can be changed with the `-c/--configuration` flag, with which you can pass the
+path for the linker configuration file you'd like to use. This file can either
+follow the same [ld65 syntax](https://www.cc65.org/doc/ld65-5.html), or a
+simplified one (check out some samples for the "simplified" syntax
+[here](../../lib/xixanta/src/mappings)).
+
+All of that being said, and out of convenience, this flag also accepts this set
+of **values**: `empty`, `nrom`, `nrom65`, `unrom`, `uxrom` and `mmc1`. These
+values correspond to the configurations [already
+bundled](../../lib/xixanta/src/mappings) on this application.
+
+## Defining global values from the command line
+
+You can define global values with the `-D` flag which follows a `NAME=VALUE`
+syntax. Note that the value is expected to be in decimal format and it has to
+fit in a byte. Hence, you could have a code like follows:
+
+```asm
+.ifdef PAL
+ lda #1
+.else
+ lda #0
+.endif
+```
+
+If you compile the code with `-D PAL=1`, then the first branch will be taken
+instead of the second one.
+
+## Address sanitizer
+
+This assembler comes with a set of tools that builds up an "address
+sanitizer". Some of its functionality is already included, while some other is
+opt-in via a special command line option.
+
+### Reserved memory
+
+This assembler can detect the memory regions being used and make decisions out
+of it. This comes with a few gotchas that the programmer has to be aware in
+order for the assembler to be useful. Because of this, the tooling around this
+detection is behind the `-a/--asan` flag.
+
+The address sanitizer will blindly follow the naming conventions from
+[style.nes](https://github.com/mssola/style.nes), and assume at first that each
+variable takes 1 byte exactly. Hence, in order to reserve one byte, you can
+simply:
+
+```asm
+zp_variable = $20
+```
+
+Then the address sanitizer will assume that you are reserving a byte at address
+`$20` which will be used throughout the code. If you want to reserve more than a
+byte, then:
+
+```asm
+zp_buffer = $20 ; asan:reserve $0F
+```
+
+Then the address sanitizer will assume that `zp_buffer = $20..$2F
+(included)`. Any access to this reserved range will be considered a
+conflict. For example:
+
+```asm
+zp_buffer = $20 ; asan:reserve $0F
+zp_bad = $22 ; NOTE: The address sanitizer will mark it as a *conflict*.
+```
+
+If you want to ignore this (e.g. you are using a variable that shadows other
+ones), then you can explicitely tell the address sanitizer to ignore a given
+assignment:
+
+```asm
+zp_buffer = $20 ; asan:reserve $0F
+zp_good = $22 ; asan:ignore
+```
+
+TODO: NOTE asan:ignore also takes care of lda $200 ; asan:ignore
+
+
+
+In order for the address sanitizer to be successful, it will warn programmers
+whenever an access to memory is being done without using variables. This allows
+for the address sanitizer to be more thorough, even if there is never the
+guarantee that memory accesses will be safe. For example:
+
+```asm
+zp_variable = $20
+
+ldx #20
+lda zp_variable, x
+```
+
+This will access memory far beyond to `zp_variable` which was only reserving a
+single byte. This is beyond the scope of this tool and other tools should be
+used instead (e.g. an emulator with breakpoints on accesses to unexpected memory
+regions, or `vnf` from this project).
+
+On another note, the address sanitizer is also able to do some basic bound
+checks. For example:
+
+```asm
+zp_variable = $20 ; asan:reserve $02
+
+lda zp_variable ; good
+lda zp_variable + 1 ; good: arithmetics within the reserved limits.
+lda zp_variable + 2 ; bad: arithmetics that would point to out of bounds.
+lda zp_variable - 1 ; bad: same as before but wrapping around.
+```
+
+With all of this, `nasm` will be able to tell how much memory you've been using
+so far, and if you add the `--write-info` option, you will also know how this
+memory is laid out by reading the `.nasm/memory.txt` file. Couple that with the
+`--stats` option, and for a given project you will be able to know:
+
+1. How much do you have left in memory and in your ROM segments.
+2. You have no conflicting variables or variables that shadow others in
+ unexpected ways.
+3. Where exactly you are reserving RAM and ROM space.
+4. Basic arithmetics don't make you fall out of bounds.
+
+### Working RAM
+
+In NES/Famicom programs you have to advertise on the header whether Working RAM
+is being used or not (see [byte 6 on the iNES
+format](https://www.nesdev.org/wiki/INES)). The programmer is expected to set
+this flag on if PRG RAM is available. If there are memory accesses to PRG RAM
+but the programmer did not advertise that on the header flag, then the `nasm`
+will error out as it cannot assume that these accesses are valid. This check
+will happen regardless of the `-a/--asan` flag.