Crates.io | trion |
lib.rs | trion |
version | 0.7.2 |
source | src |
created_at | 2024-05-02 16:48:47.938085 |
updated_at | 2024-05-16 20:05:00.535061 |
description | Trion is an assembler designed to be used with the Raspberry Pico (RP2040) microcontroller. |
homepage | |
repository | https://github.com/KosmosPrime/trion |
max_upload_size | |
id | 1227895 |
size | 320,562 |
Trion is an assembler (with some disassembling capabilities) designed to be used with the Raspberry Pico (RP2040) microcontroller.
You can run the executables in this package in one of 2 ways:
cargo install trion
(see also the --bin <name>
option in the cargo docs) and later run the installed version with just trias <args>
or tridas <args>
.cargo run --bin <name>
where trias
is the assembler and tridas
the disassembler.If you opt for the latter option, keep in mind that this documentation uses the former method for brevity. Installing also doesn't require the command to be run from within the package folder, but on the other hand requires you to manually reinstall after every version change and is thus unsuitable for development.
The package can also be used as a library (as used by the samples repo) and therefore does not have a default executable (you must specify one). When used as such, the main code which handles file reading, assembling and writing the output will be absent but the functionality responsible for assembly (including the parser, instructions and output format helper) are available to be used in different contexts.
Trion's assembly syntax is mostly similar to that of other assemblers, with slight modifications to simplify the parsing step.
An assembly file (typically but not necessarily *.asm
) consists of a number of statements, which can be any of the following:
"." <name> [<argument> {"," <argument>}] ";"
<name> ":"
<name>["." <flags>] [<argument> {"," <argument>}] ";"
The number and types of arguments accepted depend on the directive or instruction used, but parsing may continue if they are wrong.
Directives and instructions often take arguments that control their behavior. Atomic arguments are:
"0b"
, "0o"
and "0x"
respectively."A"
to "Z"
(case-insensitive) and "_"
, after the first "$"
, "."
, "@"
or "0"
to "9"
are also valid.Further, trion supports a number of numeric operations (in order of highest precedence first):
"-" <arg>
, Bitwise not "!" <arg>
<lhs> "*" <rhs>
, Division <lhs> "/" <rhs>
, Modulo <lhs> "%" <rhs>
<lhs> "+" <rhs>
, Subtraction <lhs> "-" <rhs>
<lhs> "<<" <rhs>
, Right shift (logical) <lhs> ">>" <rhs>
<lhs> & <rhs>
<lhs> ^ <rhs>
<lhs> | <rhs>
Finally, there are a number of special operators:
"[" <arg> "]"
): Indicates that the processor should access the memory location instead of the numeric value."{" [<argument> {, <argument>}] "}"
): A generic collection of arguments, typically a register set.<name> "(" [<argument> {"," <argument>}] ")"
): A general-purpose to perform computations on values of any type.As with regular mathematics, it is always valid to wrap any argument in parentheses to affect evaluation order. For numeric operations, though, all arguments must evaluate to a register or numeric value to be valid. In addition, it is an error for the result of a mathematical operation to overflow the constant's integer limit (64-bit signed).
Trion utilizes compile-time constants to enable simplification and source code reuse.
Constants must not have the same name as any register in the current instruction set.
Constants are signed 64-bit integers to comfortably encompass the RP2040's 32-bit address and register size.
Labels are themselves constants, with a value equivalent to their location, thus arbitrary numeric arguments can be used as branch/load targets.
Use of constants is dictated by scope: with the exception of importing/exporting, all directives and instructions use local constants.
It is possible to declare a constant after it is used (especially labels) but search won't escape to parent scope unless the constant is deferred.
Usage: trias <input_file.asm> [<ouput_file.uf2>]
The assembler is used to turn human-readable assembly source code into a UF2 container recognized by the RP2040's startup routine.
As such, it is possible for the assembler to directly upload code onto the device via USB by choosing an output path within the device's drive.
The output file argument is optional however, if omitted the assembler will proceed as normal but will not save the final output.
This is intended for syntax validation or testing purposes.
".addr" <addr> ";"
: Changes the current output address to addr
(where data and instructions are written to).".align" <alignment> ";"
: Aligns the current address to alignment
bytes.
The empty space (if any) is filled with 0xBE
(the opcode for the BKPT
instruction)".const" <name> "," <value> ";"
: Creates a local constant with the given name (identifier) and value.
value
must evaluate to a numeric value containing no deferred constants.".du8" <value> ";"
, ".du16" <value> ";"
, ".du32" <value> ";"
: Outputs an unsigned integer value, which must be in the specified range.".dhex" <value> ";"
: Decodes a hexadecimal string and outputs the resulting bytes.".dstr" <value> ";"
: Outputs a string as-is (without padding, length prefix or terminal character).".dfile" <path> ";"
: Outputs the named file as-is, the path
must be a string relative to the path of the current file.".global" <name> ";"
: Declares a deferred constant name
which is exported at the end of the local scope.
It is valid for the constant to already exist locally, including if deferred. In the former case, it is exported immediately.".import" <name> ";"
: Imports the (possibly deferred) constant name
from the parent scope to the local scope.".export" <name> ";"
: Exports the existing, non-deferred constant name
from the local scope to the parent scope.".include" <path> ";"
: Assembles the file at the relative path
(must be a string) and outputs the result at the current address.
The file is assembled with its own local scope, but it can import/export constants from/to the current file's local scope.Directives (and instructions) which can write data can only be used after an .addr
has been set.
The assembler does not require proper alignment, but the RP2040 will not be able to access data or execute instructions which aren't aligned.
Trion currently supports only the ARMv6-M instruction set (which is used by the RP2040).
Instructions have the same names but, unlike ARM's UAL, require a terminal semicolon.
Flags are only supported (and in fact required) for the UDF
instruction (which has narrow and wide representations).
Usage: tridas <input_file.bin>
The disassembler is not the exact inverse of the assembler. For example, it requires as input a binary file containing only the opcodes, not a UF2 container.
Therefore, and because assembling strips label names, the disassembler will assume the binary is mounted at addess 0x2000000
(the start of SRAM on the
RP2040) and generate hexadecimal label names based on these addresses.
It currently only follows labels to other code, and won't generate any directives for relevant data items (such as with an immediate LDR
).