aboutsummaryrefslogtreecommitdiff
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
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>
-rw-r--r--README.md40
-rw-r--r--crates/nasm/README.md174
2 files changed, 181 insertions, 33 deletions
diff --git a/README.md b/README.md
index 5dcd3a9..771f9a5 100644
--- a/README.md
+++ b/README.md
@@ -4,38 +4,8 @@ Tools I have created to help with NES/Famicom development.
## `nasm`
-`nasm` is an assembler specifically tailored for the NES/Famicom. Build it and
-run it with cargo, or you can install it somewhere in your `$PATH` and simply:
-
-```
-$ 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
-```
-
-By default it will assume the configuration for an `NROM` mapper, but this can
-be changed with the `-c/--configuration` flag, which accepts the following
-values: `empty`, `nrom`, `nrom65`, `unrom`, `uxrom` and `mmc1`. These values
-correspond to the configurations [already bundled](./lib/xixanta/src/mappings)
-on this application, which follow a simplified syntax from the
-[ld65](https://www.cc65.org/doc/ld65-5.html) one. Alternatively, you can also
-pass the path to a configuration file to this flag. This file can either follow
-the same [ld65](https://www.cc65.org/doc/ld65-5.html) syntax, or the simplified
-one.
+`nasm` is an assembler specifically tailored for the NES/Famicom. Read more
+about it in [./crates/nasm/README.md](./crates/nasm/README.md).
## `xa65`
@@ -44,7 +14,11 @@ results that it produces with a mature and stable assembler like
[cc65](https://github.com/cc65/cc65). The purpose of `xa65` is to provide a
bridge, and so it simply executes both `nasm` and `cc65` with the given
arguments. If the results from both assemblers are not the same, then it will
-display a warning and produce the binary as taken from `cc65`.
+display a warning and produce the binary as taken from `cc65`. Moreover, if you
+want this warning to be an error instead, then use the `--no-errors`.
+
+Last but not least, you can also pass flags to `xa65` like `--strict`, which
+will invoke `nasm` with more pedantic features like its address sanitizer.
## `readrom`
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.