This document does not include command-line usage! All information you need for command-line usage is available on tachyon --help
.
- Environment Variables
- Project Folder Structure
- Project Configuration (project.yaml)
- Modules (ModulesDir/*.yaml)
- Patches & Hooks
- Symbol Maps (syms/main.map, syms/*.x)
- Address Offsets Maps (conv/*.offs)
- Linker Directives (linker/*.ld)
- Compilation Caches
- Console Compilation
Note: All environment variables are optional and have less priority than their equivalent flags.
GHS_ROOT
: Instead of passing the--ghs
option to thecompile
command every time, Tachyon supports this environment variable to permanently store the path to GHS.CEMU_ROOT
: Instead of passing the--cemu
option to thelaunch
command every time, Tachyon supports this environment variable to permanently store the path to Cemu.TACHYON_DEFAULT_GAME_ROOT
: Instead of passing the--game
option to thelaunch
command every time, Tachyon supports this environment variable to permanently store the path to a default game folder.
All Tachyon-based projects must use the following minimal folder structure:
{IncludeDir}/
# your C++ header (.h) & Assembly (.S) files
{SourceDir}/
# your C++ source (.cpp) & Assembly (.S) files
{ModulesDir}/
# your Tachyon Modules YAML (.yaml) files
{RpxDir}/
# your base vanilla RPX (.rpx) files
[MetadataDir]/
conv/
# your Tachyon Address Offsets (.offs) files
syms/
main.map # your primary symbol map file
project.yaml # the main project configuration file
The folder all of the above are inside will be referred to as the root.
The folder names as {Example}
are customizable through the field Example
in project.yaml
. They can be placed anywhere within the root, even nested inside other folders, except for each other, with the exception of the MetadataDir, which can be referred to with the +
symbol on the paths.
The folder names as [Example]
are customizable through certain command-line options when calling the compile
command, they are as follows:
- MetadataDir: Customizable through the
--meta
/-m
option.- NOTE: This folder can only be renamed, it cannot be moved outside of the root nor nested inside other folders.
The folder and file names not using either of the syntaxes above are hardcoded and cannot be customized.
All of the above folder customization options are not required, and all customizable folders have default values as follows:
- IncludeDir =
include
- SourceDir =
src
- ModulesDir =
modules
- RpxDir =
rpxs
- MetadataDir =
project
All relative to the root folder. The resulting default folder structure looks like this:
include/
# your C++ header (.h) & Assembly (.S) files
source/
# your C++ source (.cpp) & Assembly (.S) files
modules/
# your Tachyon Modules YAML (.yaml) files
rpxs/
# your base vanilla RPX (.rpx) files
project/
conv/
# your Tachyon Address Offsets (.offs) files
syms/
main.map # your primary symbol map file
project.yaml # the main project configuration file
Project configuration is done through the main configuration file, [MetadataDir]/project.yaml
, containing the following structure:
---
Name: # project name (REQUIRED)
ModulesDir: # path to modules folder (default: modules)
IncludeDir: # path to headers folder (default: include)
SourceDir: # path to sources folder (default: src)
RpxDir: # path to rpxs files folder (default: rpxs)
Modules:
- # list of names of global modules to compile (REQUIRED)
- # ...
Defines:
- # list of global C++ defines to set on compilation (default: empty list)
- # ...
Targets: # key/value pairs of indefinite target configurations
TargetName: # a single target configuration (At least 1 required)
Extends: # name of a template target to inherit settings from (default: none)
AddrMap: # name of conv/*.offs file to use with this target (default: TargetName)
BaseRpx: # name of {RpxDir}/*.rpx file to use with this target (default: TargetName)
Modules:
- # list of names of additional modules to compile with this target (default: empty list)
- # ...
Defines:
- # list of additional C++ defines to set with this target (default: empty list)
- # ...
Remove/Modules:
- # list of names of global modules to remove from compilation with this target (default: empty list)
- # ...
Remove/Defines:
- # list of global C++ defines to remove from this target (default: empty list)
- # ...
Template/TemplateName: # a target configuration template, identified by the "Template/" prefix (optional)
# other non-template targets can inherit the settings defined here with the Extends setting
# templates cannot be nested, so the Extends setting is not allowed on them.
# aside from Extends, all target settings are also valid here.
#
# AddrMap and BaseRpx will default to TemplateName instead of TargetName here
# if AddrMap/BaseRpx are set on both template and an extending target, the extending target has priority.
#
# all the list settings are merged together if set on both template and extending target.
To create an "empty" target using all default settings, give it ~
as the value.
In the value for ModulesDir, IncludeDir, SourceDir and RpxDir, the special prefix +/
can be used to reference the MetadataDir given its name can be changed per run (similar to ~/
to reference the home folder on Linux)
Tachyon projects are structured in "modules", enabled/disabled by the project.yaml
, which are defined by YAML files located inside {ModulesDir}
, which in turn declare source files (.cpp
/ .S
) to compile and assemble aswell as binary patches/hooks to apply directly to the base RPX file.
Each module file is structured as follows:
---
Files:
- # list of .cpp and .S files to compile/assemble when this module is enabled (REQUIRED, but can be empty list with [] as value)
- # ...
Hooks:
- # list of patches/hooks to apply when this module is enabled (REQUIRED, but can be empty list with [] as value)
# example patch/hook structure
- type: # the type of the patch/hook, see the Patches & Hooks section of the docs for details
addr: # a stringified hex number with 0x prefix, indicating the where to apply the patch
????: # other hook-type specific fields exist, see the Patches & Hooks section of the docs for details
This section documents the different types of structures you can write on the Hooks
list of a module. The current valid types, and their extra fields besides the base type
and addr
common to all hook types, are as follows:
patch
- The most basic and versatile hook, simply inserts
data
ataddr
- Additional field:
data
- A value to be encoded according to
datatype
and inserted at theaddr
- A value to be encoded according to
- Optional field:
datatype
(Default:raw
)- A string representing a C++ data type to interpret the value of
data
as, the supported types are:raw
: A sequence of hex bytes, value ofdata
should be a string.f32
/f64
/float
/double
: A 32/64 bit floating point number, value ofdata
should be a numeric literal.u16
/u32
/u64
/ushort
/uint
/ulonglong
: A 16/32/64 bit unsigned integer, value ofdata
should be a positive numeric literal.s16
/s32
/s64
/short
/int
/longlong
: A 16/32/64 bit signed integer, value ofdata
should be a numeric literal.char
: A single char patch is not supported and will result in misaligned data. This is also whyu8
/s8
don't exist. Refer to array types below.string
: A null-terminated C string. Due to alignment, must be an odd length. Null terminator is automatically added. Value ofdata
should be a string.#[]
: Where#
is any of the types above, you may suffix a type with[]
to make an array of it. Value ofdata
will be an array of values of the respective type.- The difference between
char[]
andstring
is achar[]
doesn't automatically null-terminate and uses ASCII encoding, whilestring
uses UTF8. - To write a null character on a
char[]
, write downnull
as a literal. - Multidimensional arrays such as
int[][]
are not supported.
- The difference between
- A string representing a C++ data type to interpret the value of
- The most basic and versatile hook, simply inserts
nop
- A shorthand for a
patch
hook with60000000
(nop
) asdata
- A shorthand for a
multinop
- A shorthand for multiple
nop
hooks in a sequence - Additional field:
count
- A decimal integer number, specifying how many
nop
's to apply starting fromaddr
- A decimal integer number, specifying how many
- A shorthand for multiple
returnvalue
- This hook type is currently volatile and should be avoided.
return
- A shortcut for a
patch
hook with4E800020
(blr
) asdata
- A shortcut for a
branch
- Inserts the respective branch instruction
instr
ataddr
jumping to the address of the symbolfunc
- Additional field:
instr
- The branch instruction to use:
b
orbl
- The branch instruction to use:
- Additional field:
func
- The symbol whose address the branch instruction should jump to
- Inserts the respective branch instruction
funcptr
- Inserts the address of the symbol
func
ataddr
- Additional field:
func
- The symbol whose address to write at
addr
- The symbol whose address to write at
- Inserts the address of the symbol
All hook fields are required unless explicitly marked as optional.
The primary symbol map for a project is located at [MetadataDir]/syms/main.map
and has a very basic syntax similar to any other symbol map file.
- Indentation and whitespace are free-form
#
is used for comments- Both full line and end-of-line comments are supported
- There is no multi-line comment support
- Line-separated list of key value pairs in the format:
SYMBOL = ADDRESS;
- Where
SYMBOL
is the symbol's text - Where
ADDRESS
is the symbol's address as a hex or decimal number- Alternatively
ADDRESS
can also a previously definedSYMBOL
which instructs the parser to re-use thatSYMBOL
's address for the current one.
- Alternatively
- Where
- Anything not fitting the above syntax rules is a syntax error
The primary symbol map is not the one actually given to the compiler, as it must be converted to different regions according to the build targets through the conv/*.offs
files. The resulting converted symbol maps of a compilation are placed in syms/
aswell next to the main.map
, with {Target}.x
as name. Those are temporary and can be safely deleted after compilation if desired.
The *.offs
files inside the [MetadataDir]/conv
folder are used for converting the addresses of the primary symbol map (syms/main.map
) to different regions and versions of the game/app being modified.
The addresses in main.map
can be of any region/version of your choosing, but must be consistent throughout the main.map
. For build targets of the same region/version as your main.map
addresses, where no conversion is necessary, a matching *.offs
file is still required, even if empty or with a comment such as // main
. This empty file requirement may be dropped in the future.
The offset files support both #
and //
comments at both start and end of lines, but no multi-line comments.
Address conversion offsets are arranged in a line-separated list of the following indentation and whitespace agnostic format:
RANGE_START - RANGE_END: SIGN OFFSET
- Where
RANGE_START
is an unprefixed (no0x
) hex number (inclusive) - Where
RANGE_END
is an unprefixed (no0x
) hex number (exclusive) - Where
SIGN
is either+
or-
. Anything else is a syntax error- This is REQUIRED even for positive offsets!
- Where
OFFSET
is a hex (0x
prefix) or decimal (no prefix) number
- Where
Besides address conversion offsets, the *.offs
files also store the offsets pointing to the end address of the text, data and syms section groups of the base RPX file. For targets targetting emulators (Cemu), these are not required and should be omitted to be autocalculated, but for targets targetting real Wii U hardware, they must be provided as they cannot be autocalculated due to real hardware shifting the addresses on load.
TextAddr = ADDRESS
DataAddr = ADDRESS
SymsAddr = ADDRESS
Where ADDRESS
is a hex (0x
prefix) or decimal (no prefix) positive number. If these values are not provided for a console-targetting build it will cause build errors.
The {Target}.ld
files inside the [MetadataDir]/linker
folder are temporary files produced during a compilation run, they should never be edited and can be safely deleted after each run, including the folder itself. (They will both always be re-created every compilation run)
In combination with the compiler caching C++ files, Tachyon also caches Assembly files to avoid needlessly reassembling unmodified files between runs. This cache is currently stored at <PROJECT_DIR>/objs/.asm.cache
, to clear/invalidate ONLY the Assembly cache, simply delete said file. To clear BOTH the C++ and the Assembly cache, run the compile
command with --no-cache
.
Support for compilation to real Wii U hardware is not finished and currently unavailable. This will be handled soon at a later update.