diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-09-04 07:56:44 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-09-04 07:56:44 +0200 |
| commit | 14c8f64f38b601398a144d507c0183016d27b87c (patch) | |
| tree | 9646b2094cbae3022418a8183f454f8436f566dd | |
| parent | 2e99bdfed0d4f0cd78f03886155ff175e115bb77 (diff) | |
| download | tools.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.md | 40 | ||||
| -rw-r--r-- | crates/nasm/README.md | 174 |
2 files changed, 181 insertions, 33 deletions
@@ -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. |
