diff --git a/.gitignore b/.gitignore index 3248adc..e476763 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # Build artifacts build/ *.nds +*.1 # Developer conveniences testdir/ diff --git a/README.md b/README.md index a26446e..eee02d8 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,27 @@ Developers and early-adopters can build the project from source: ./build/nitrorom ``` +Optionally, distributable manual-pages can be generated from the plain-text +files in `docs/`: + +```sh +ninja -C build docs +``` + +This requires setting up the project with the `manuals` option set to `true`, +which must be specified when configuring the build: + +```sh +meson setup -Dmanuals=true build +``` + +The generation targets use [`asciidoctor`][repology-asciidoctor] to convert the +`.adoc` files into manual pages. + [getting-meson]: https://mesonbuild.com/Getting-meson.html [repology-meson]: https://repology.org/project/meson/versions [repology-libpng]: https://repology.org/project/libpng/versions +[repology-asciidoctor]: https://repology.org/project/asciidoctor/versions ## Usage diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 0000000..b217fde --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,25 @@ +man_1_adoc_files = [ + 'nitrorom.adoc', + 'nitrorom-list.adoc', + 'nitrorom-pack.adoc', +] + +asciidoctor_exe = find_program('asciidoctor') + +man_1 = [] +foreach man_1_adoc : man_1_adoc_files + man_1_out = man_1_adoc.replace('.adoc', '.1') + man_1 += custom_target( + input: files(man_1_adoc), + output: man_1_out, + command: [ + asciidoctor_exe, + '-b', 'manpage', + '-a', 'manversion=' + meson.project_version(), + '-o', '@OUTPUT@', + '@INPUT@', + ], + ) +endforeach + +alias_target('docs', man_1) diff --git a/docs/nitrorom-list.adoc b/docs/nitrorom-list.adoc new file mode 100644 index 0000000..d2d33a1 --- /dev/null +++ b/docs/nitrorom-list.adoc @@ -0,0 +1,40 @@ +nitrorom-list (1) +================= + +:doctype: manpage +:manmanual: NitroROM Manual +:mansource: NitroROM {manversion} +:man-linkstyle: pass:[blue R < >] + +NAME +---- + +nitrorom-list - List the components of a Nintendo DS ROM + +SYNOPSIS +-------- + +[verse] +'nitrorom list' + +DESCRIPTION +----------- + +Generate a listing of the constituent members of an input ROM file. The listing +will be emitted to the standard-output stream in a comma-separated format. Each +record in the output adheres to the following `printf`-style format: + +------ + + ROM Start,ROM End,Size,Padding,Component + + ROM Start - 0x%08X + ROM End - 0x%08X + Size - 0x%08X + Padding - 0x%04X + Component - %s + +------ + +No program-options are available for this command. No validation is performed on +the input ROM-file, and it is treated as-is. diff --git a/docs/nitrorom-pack.adoc b/docs/nitrorom-pack.adoc new file mode 100644 index 0000000..c4d4d36 --- /dev/null +++ b/docs/nitrorom-pack.adoc @@ -0,0 +1,371 @@ +nitrorom-pack (1) +================= + +:doctype: manpage +:manmanual: NitroROM Manual +:mansource: NitroROM {manversion} +:man-linkstyle: pass:[blue R < >] + +NAME +---- + +nitrorom-pack - Produce a Nintendo DS ROM from sources + +SYNOPSIS +-------- + +[verse] +'nitrorom pack' [OPTION]... + +DESCRIPTION +----------- + +Construct a Nintendo DS ROM-file from the contents of the input specification +files. The output ROM-file will be packaged using a strategy similar to that +used by the tooling which shipped with the original proprietary SDK. Thus, given +a set of binary-identical input files and an identical ordering of those input +files, this program should produce a binary-identical ROM-file to an existing +retail copy. + +For details on the expected content of input specification files, refer to +<> and <>. + +OPTIONS +------- + +`-D `:: +`--define=`:: + Define a key-value pair to be used while parsing program configuration. Keys + identified during the parse-run will be substituted in-place for matching + values from these definitions, if any such match exists. If no match exists, + then the program will exit with an appropriate error message. Keys specified + must be unique. + +`-C `:: +`--directory=`:: + Change to directory __ before loading any constituent file-data. This + will not affect the loading of input specification files, which will be + opened according to the working directory in which the program is run. + +`-o `:: +`--output=`:: + Write a packaged output ROM to __. Defaults to `rom.nds`. + +`--dry-run`:: + Do not create an output ROM; instead, emit intermediate artifacts computed + during packing which would be built into the ROM. For details on the files + generated by this option, refer to <>. + +`--verbose`:: + Emit verbose program logs during execution. These logs are written to the + standard-error stream to separate them from any other logging statements + which may be written to the standard-output stream. + +EXAMPLES +-------- + +`nitrorom pack -C build config.ini filesys.csv`:: + Reads the contents of _./config.ini_ and _./filesys.csv_ to build an output + ROM. Filepaths referenced in _./config.ini_ and _./filesys.csv_ will be + implicitly prefixed with _./build/_. An output ROM _./rom.nds_ will be created. + +`nitrorom pack -C build --output myrom.nds config.ini filesys.csv`:: + Identical to the above, but the output ROM will be created as _./myrom.nds_. + +`nitrorom pack -DARM7_STATIC=myarm7.sbin -C build config.ini filesys.csv`:: + Replace the variable-substitution token _${ARM7_STATIC}_ with _myarm7.sbin_ + while processing configuration. + +`nitrorom pack -C build --dry-run config.ini filesys.csv`:: + Do not generate an output ROM, but instead emit dry-run artifacts to the + directory _./build_. + +`nitrorom pack -C build --dry-run --verbose config.ini filesys.csv`:: + Emit verbose logs detailing the packing strategy while reading configuration + files. These verbose logs are prefixed with a colon-delimited string which + details the stage of the packing process; e.g., _rompacker:configuration:banner:_ + will precede a message emitted while parsing the _banner_ section of _./config.ini_. + +[[CONFIG.INI]] +CONFIG.INI +---------- + +This file details important meta-properties for the output ROM's structure and +critical files to be used by the system's coprocessors. + +Syntax Overview +~~~~~~~~~~~~~~~ + +The contents of this file are parsed as a flavour of _.ini_: + +- Comments are permitted on standalone lines and recognized by a leading hash + (‘#’) or semicolon (‘;’). Comments are _not_ permitted in-line. +- The file consists of sections and key-value pairs. A section begins with the + name of the section in square brackets (‘[’ and ‘]’) and continues until the + beginning of the next section. +- All key-value pairs belong to a section. +- A key-value pair is separated into a key and a value around an equals sign + (‘=’). +- The keys recognized by each section are strictly-defined. +- Values of the form `${VARIABLE}` will be replaced with corresponding values + from the variable-store specified by command-line arguments. +- White-space which leads or trails either the key or value is ignored. +- White-space _within_ values is permitted, provided that it follows a character + which is _not_ white-space and is not a new-line (which would terminate the + key-value pair). +- Blank lines (those which contain only white-space) are ignored. + +Value Types +~~~~~~~~~~~ + +Values read from the input file are strongly-typed. + +`boolean`:: + A simple flag value. The literal values “true”, “yes”, and “on” will be read + as a “truthy” value; “false”, “no”, and “off” will be read as a “falsy” + value. Any other specified value is invalid. + +`number`:: + A literal number, either in base-10 or base-16. If the number must be given + as base-16, then it must be prefixed with “0x” or “0X”. Both lowercase and + uppercase alphabetic digits are accepted for base-16 numbers. Digit + separators of any kind (‘\_’, ‘,’, ‘.’, etc.) are _not_ permitted. + +`string`:: + A literal string. No additional validation is performed inherently, though + individual keys are free to enforce their own specific value-validation. + +`header` Section +~~~~~~~~~~~~~~~~ + +This section is described by the name “header”. Keys in this section generally +specify metadata which is only relevant to the header of the output ROM-file. + +`template` -> `string`, filepath:: + Specify the path to a file which should be loaded as an initial state for + the output ROM-file's header. This may be useful if you have a pre-computed + header that should not be changed or modified, or if you have identified + byte-data within a retail ROM's header that must be maintained to produce an + output which satisfies which satisfies binary-matching (e.g., for a + decompilation project) or which is not configurable via other means within + this file. + +`title` -> `string`, max length: 12:: + The 12-character ASCII title string as stored in the output ROM header. Note + that this does _not_ specify the title which is displayed on the system + boot-menu. Some emulators, however, may show this title string in their + window decorations. + +`serial` -> `string`, max length: 4:: + The 4-character ASCII serial code associated with the output ROM. This value + uniquely identifies the game's ROM software and release language. + Functionally, this value serves no purpose and is purely informational. + +`maker` -> `string`, max length: 2:: + The 2-character ASCII maker code associated with the output ROM. + Historically, the value given here was assigned to a developer as part of + their publication-agreement with Nintendo. Functionally, this value serves + no purpose and is purely informational. + +`revision` -> `number`, base-10, max value: 255:: + The revision number of the ROM-file. Historically, some retail releases + produced further revisions which may have corrected issues identified after + the first edition was submitted for publication. + +`secure-crc` -> `number`, base-16, max value: 0xFFFF:: + An override value to be specified as the CRC-16 checksum of the output ROM's + secure area. The secure area consists largely of system-critical code for, + e.g., reading data from the inserted game card. + +`rom` Section +~~~~~~~~~~~~~ + +This section is described by the name “rom”. Keys in this section define +attributes about the output ROM-file's structure or control interactions between +the ROM-file and the hardware. + +`storage-type` -> `string`, allowed values: “MROM”, “PROM”:: + Either “MROM” (for Masked Read-Only Memory) or “PROM” (for Programmable + Read-Only Memory). The specified storage-type has a number of implications + which will not be summarized here; in practice, this value controls various + clock-timings for card-access by the hardware and the functional size-limit + for an output ROM-file: “MROM” ROM-files are limited to 64MB of capacity, + whereas “PROM” ROM-files are limited to 2GB of total ROM space. + Generally, the storage-type used by a retail ROM-file can be identified + by interpreting offset `0x006E..0x006F` of the file as a 16-bit integer in + little-endian order: a value of `0x051E` represents “MROM”, while a value of + `0x0D7E` represents “PROM”. + +`fill-tail` -> `boolean`:: + If set to a truthy-value, then the output ROM-file should be filled to its + maximum capacity with the configured padding value (see “fill-with”). The + maximum capacity is computed according to the consumed storage space of the + output ROM-file, rounded up to the next power-of-2. + +`fill-with` -> `number`, base-16, max value: 0xFF:: + This value will be used to align member-files and ROM sections to offset- + boundaries divisible by `0x200`. If “fill-tail” is set to a truthy-value, + then this value will also be used to fill any remaining space in the output + ROM-file up to its determined maximum capacity. + +`banner` Section +~~~~~~~~~~~~~~~~ + +This section is described by the name “banner”. Keys in this section define data +usable by the system for display to an end-user via the boot menu. + +`version` -> `number`, allowed values: 1, 2, 3:: + Specify the version of the banner-encoding to be used. This value controls + the languages in which the title-string is provided, and all versions are + backwards-compatible with previous versions. All banners will provide a + title-string for the Japanese, English, French, German, Italian, and Spanish + languages; version 2 banners will additionally provide a title-string for + the Chinese language, and version 3 banners will further provide a title- + string for the Korean language. + +`icon` -> `string`, filepath:: + Specify the path to an indexed, 16-color PNG to be used for displaying an + icon on the system boot menu. This key acts as a wrapper around `icon4bpp` + and `iconpal` for end-users that do not wish to pre-compute the requisite + files for those keys as part of their packaging workflow. + +`icon4bpp` -> `string`, filepath:: + Specify the path to a pre-computed 4-bit-per-pixel tileset to be used by an + icon on the system boot menu. Individual tiles should be computed from the + indexed-PNG format by consuming 4 pixel-pairs from the row-origin, then + iterating to the next column and repeating 8 total times. The output + pixel-pairs must have their ordering inverted -- that is, the right-most + pixel of the pair will comprise the most-significant nybble, and the + left-most pixel will comprise the least-significant nybble. + +`iconpal` -> `string`, filepath:: + Specify the path to a pre-computed 15-bit-color RGB palette to be used by an + icon on the system boot menu. Each color-value in the palette must be + formatted with 5-bit values for each of the Red, Green, and Blue channels. + The Red channel will comprise bits 0 through 4, the Green channel will + comprise bits 5 through 9, the Blue channel will comprise bits 10 through + 14, and bit 15 will be discarded. + +`title` -> `string`, UTF-8 encoded, Basic Multilingual Plane:: +`subtitle` -> `string`, UTF-8 encoded, Basic Multilingual Plane:: +`developer` -> `string`, UTF-8 encoded, Basic Multilingual Plane:: + Specify title-string components for the output ROM-file. These components + are copied for use by all languages in the output, and they must be + specified in the order “title” -> “subtitle” -> “developer”. The “subtitle” + component is considered optional. Individual components accept the same set + of characters from plane 0 of the Unicode standard (the “Basic Multilingual + Plane”), which defines encodings for characters in most major world + languages. + +`arm9` and `arm7` Sections +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These two sections, despite their differing names, are sisters which support an +identical set of keys. These sections are kept separate from one another to +denote to which coprocessor each key-value pair belongs: the ARM946E-S (commonly +called the “main” coprocessor) or the ARM7TDMI (commonly called the “sub” +coprocessor). + +`static-binary` -> `string`, filepath:: + Specify the path to a file which will be loaded and treated by the hardware + as code for the corresponding coprocessor that should always be present + within RAM at runtime. + +`definitions` -> `string`, filepath:: + Specify the path to a file which will be interpreted by this program as a + set of “definitions” relevant to the coprocessor. The terminology used here + and the collection of values therein are both loosely defined, and this file + should be produced by some aspect of your build system. This program expects + this file to have the following structure: + +-------- + + struct definitions_t { + uint32_t load_addr; // RAM address for the static code-binary. + uint32_t entry; // RAM address for the coprocessor's entry-point. + uint32_t load_size; // Size of the static code-binary. + uint32_t load_cb; // RAM address of an on-load callback routine. + char *overlays[]; // Null-terminated filepaths for overlay binaries. + }; + +-------- + +`overlay-table` -> `string`, filepath:: + Specify the path to a file which will be loaded and treated by the hardware + as a list of data-values for use by the coprocessor when loading overlays. + This file should be produced by some aspect of your build system, whether + when unpacking an existing ROM-file or by a program-linker. Individual + records within this table must adhere to the following structure: + +-------- + + struct overlay_t { + uint32_t id; + uint32_t load_addr; + uint32_t load_size; + uint32_t bss_size; + uint32_t static_init_head_addr; + uint32_t static_init_tail_addr; + uint32_t filesys_id; + uint32_t _padding; + }; + +-------- + +[[FILESYS.CSV]] +FILESYS.CSV +----------- + +The structure of the output ROM's filesystem is computed from this input file, +which contains newline-delimited records of comma-delimited fields (a typical +CSV table-file). This program expects that this input file: + +1. contains a header record, which acts only as an informant to a human reader + and is otherwise ignored by the program; +2. specifies one record for each filesystem member in the output ROM, ordered + according to order in which they appear in a forward linear scan of the ROM; +3. specifies two fields for each record: the first is a path to a local file + which contains the filesystem member's data (the “source path”), and the + second is a path to the member in the output ROM's filesystem (the “target + path”); +4. specifies a source path to a local file that is accessible to the program; +5. specifies a Unix-like absolute target path. + +To illustrate, consider the following record from a hypothetical input file: + +-------- + + filesys/data/UTF16.txt,/data/UTF16.txt + +-------- + +This record declares the following to the program: + +1. there is a file on-disk at the path “filesys/data/UTF16.txt”; +2. the contents of this file at this path must be packed into the ROM; and +3. the contents of this file shall be accessible in the output ROM-file from the + virtual filesystem path “/data/UTF16.txt”. + +[[DRY-RUN_MODE]] +DRY-RUN MODE +------------ + +Running the program in this mode will suppress the final output of a ROM-file. +It can be used, thus, to act as a validator for the input files above. However, +during program execution, some virtual files are generated for packaging into +the output ROM-file; in dry-run mode, these virtual files will be dumped to real +files on-disk in the working directory (potentially modified by the `-C` option) +for inspection / debugging: + +1. `header.sbin` - The computed ROM header, which contains critical information + for executing software on the hardware. This header file contains offsets at + which important sections can be found, e.g., the location of static binaries, + coprocessor overlay tables, and the filesystem structure. +2. `banner.sbin` - A collection of data relevant to the system's boot menu which + should be displayed to an end-user: the ROM's software title, any sub-title, + the developer, and a small graphics-set defining a 32x32 icon. +3. `fntb.sbin` - A binary structure which defines the ROM's internal filesystem + layout. +4. `fatb.sbin` - A table of ROM offsets to the head and tail of each member-file + present in the output ROM. This table includes offsets both for coprocessor + overlays and filesystem entries. diff --git a/docs/nitrorom.adoc b/docs/nitrorom.adoc new file mode 100644 index 0000000..d6bb77e --- /dev/null +++ b/docs/nitrorom.adoc @@ -0,0 +1,65 @@ +nitrorom (1) +============ + +:doctype: manpage +:manmanual: NitroROM Manual +:mansource: NitroROM {manversion} +:man-linkstyle: pass:[blue R < >] + +NAME +---- + +nitrorom - Interface with Nintendo DS ROM images + +SYNOPSIS +-------- + +[verse] +'nitrorom' [OPTION]... [COMMAND] [ARGUMENT]... + +DESCRIPTION +----------- + +NitroROM is a program for interfacing with Nintendo DS ROM-files in a variety of +ways. Its primary aims are to provide a reusable tool-suite for developers, +modders, hackers, and reverse-engineering researchers. This tool-suite is +sub-divided into a set of commands which act as programs unto themselves; the +top-level executable acts merely as an access-director to these programs. + +For details on each of the commands listed below, refer to their distinct manual +page. + +OPTIONS +------- + +`-h`:: +`--help`:: + View the help-text for the access-director, which provides a summary for + basic usage. + +`-v`:: +`--version`:: + Display the NitroROM suite-version and exit. + +COMMANDS +-------- + +`list`:: + Generate a listing of the constituent members of an input ROM-file. The + output listing will be emitted to standard-output in comma-separated format. + +`pack`:: + Construct a Nintendo DS ROM-file from the contents of the input specification + files. + +REPORTING BUGS +-------------- + +Report bugs to the project's issue page . You will +need a GitHub account to create a new issue. + +NOTES +----- + +1. lhearachel/nitrorom.git + https://github.com/lhearachel/nitrorom diff --git a/meson.build b/meson.build index dc4f843..223709b 100644 --- a/meson.build +++ b/meson.build @@ -70,6 +70,9 @@ nitrorom_exe = executable( if not meson.is_subproject() subdir('tests') + if get_option('manuals') + subdir('docs') + endif else meson.override_find_program('nitrorom', nitrorom_exe) endif diff --git a/meson.options b/meson.options index 3c6f038..576791b 100644 --- a/meson.options +++ b/meson.options @@ -4,3 +4,10 @@ option( value: true, description: 'Force native compilation, even in a cross-compilation setup', ) + +option( + 'manuals', + type: 'boolean', + value: false, + description: 'Generate manual pages from documentation using Asciidoctor. Ignored by subprojects.', +)