SIRTX VM
Information on the SIRTX VM
The SIRTX VM is a part of SIRTX that is used to run code that not part of the image nor interpreted command line (see line command interpreter).
Information on the SIRTX VM
The SIRTX VM is a part of SIRTX that is used to run code that not part of the image nor interpreted command line (see line command interpreter).
The SIRTX VM supports code in its own optimised format. This special format natively supports the SIRTX API and therefor can be used to compile to a small binary size. The following outlines the syntax for the reference assembler.
The syntax follows many standard assembler patterns. However, opcodes may be different from other architecturs.
Each line of the file may contain comments. A comment starts with ;
, //
, or #
and extends the rest of the line. If the line contains any directive there must be at least one space in between.
Every line may start with any number of whitespaces, end with them. Those are ignored. Between values there must be at least one whitespace or a comma or both.
Each directive may have zero or more values. A value can be of different types, depending on the directive. The first one is normally the destination, output, or target, and the second one the source or input.
It is possible to mark each opcode with a bang (!
) to select autodie mode. This will set the autodie flag of the opcode (if any) or insert a autodie directive right after the opcode (if it has no autodie on its own).
BOOL
: Booleantrue
or false
.INT
: Integer123
for decimal, 0xabc
for hex, 0123
for octal, or 0b0101
for binary. Also, each value can be prefixed with a +
or -
to make it relative. What it is relative to depends on the opcode.STRING
: String"..."
or U+1234
(single character Unicode string). If in double quotes, backslashes are used to escape. \\
escapes single backslash, \0
escapes single 0-byte, \n
escapes LF/new line (U+000A), \t
escapes HT/horizontal tab (U+0009), \e
escapes ESC/escape (U+001B). Also, the form \xAB
can be used to escape any byte, note that in most cases those most form correct UTF-8 strings. For example U+00FC is correctly escaped \xC3\xBC
, not \xFC
.LREG
: Logical registerrN
with N being 0 to 7.PREG
: Physical registersuser7
or program_text
.REG
: General register syntaxID
: Identifiersni
, e.g. sni:80
. Only numerical values are currently supported. Some values from the raes
space are however automatically converted to raen
.VAR
: Variable$
, author defined ones start with it.Below is a list of directives and opcodes. Note that directives and opcodes may generate a variable amount of actual code depending on their parameters and context.
.align INT
Aligns the current location to at least INT bytes
.align 8
.align INT [, INT [, INT [, ...]]]
Outputs the given bytes.
.bytes 0x56, 0x4D
.cat STRING [, STRING [, STRING [, ...]]]
Includes files as-is into the output. No translation is performed when including file files. This is mostly useful to include large binary objects (blobs).
.cat "help.txt"
.cold PREG [, PREG [, PREG [, ...]]]
Mark a given physical register as cold. Cold registers are unlikely to be used/referenced. This allows the assembler to optimise better.
.cold arg
.endsection
Ends a section started with .section
.endsection
.hot PREG [, PREG [, PREG [, ...]]]
Marks a given physical register as hot. Hot registers are likely to be used frequently. This allows the assembler to optimise better.
.hot user3, out
.include STRING [, STRING [, STRING [, ...]]]
Includes source files and translates them. The .include directive does not create a new context of any kind. The files are included as if their content were in the main file.
.include "lib.vmv0-asm"
.lukewarm PREG [, PREG [, PREG [, ...]]]
Marks physical registers as lukewarm. This tells the assmeber that they are not specically hot nor cold. This is the default temperature for registers.
.lukewarm user2, error
.map LREG, PREG
Marks a logical register to be mapped to a physical register in the assembler's internal state without actually emitting an opcode. This is useful to set a correct state e.g. after a jump when the assembler can no longer know the actual mapping. To actually emit an opcode use map.
.map r0 user0
.mine REG [, REG [, REG [, ...]]]
This marks registers as owned by the author. If a register is owned by the authour the assembler will not try to use it for automatic code generation (such as auto mapping). This is the default for registers.
.mine r0, r1, r2, out
.org INT
Seeks the output to the given position. If the value is relative moves relative to the current position
.org 0x100
.popname VAR [, VAR [, VAR [, ...]]]
Pops a name of the name stack. See .pushname for details.
.popname $x, $y
.pushname VAR = VALUE [, VAR = VALUE [, VAR = VALUE [, ...]]]
Pushes name-value-pairs onto the name stack. Each name must start with a single $
. The value can be any value (register, constant, ...) but another name. This mechanism can be used to assign more memorable names to registers or other constants. Those names can be used at any point. Names are pushed onto the stack, meaning if a name becomes pushed again it shadows the old content. The old content will be come visible again after .popname.
.pushname $x = 5, $y = user7
.quit
Quits the assembler, the rest of the file is ignored.
.quit
.regmap_auto BOOL
Enables or disables automatic register mapping by the assembler. In order to work as expected some logical registers must be declared .yours. The number of registers that should be declared .yours depend on the code. A general starting point would be three or four.
.regmap_auto true
.section SECTIONTYPE
Starts a section of the given type. If another section is already open it first needs to be ended with .endsection.
.section header
.theirs REG [, REG [, REG [, ...]]]
Marks a register as owned not by the author nor the assambler. This can be useful if it is for example owned by a library or other module.
.theirs deep, user4
.utf8 STRING [, STRING, [, ...]]]
Writes the given strings as-is to the output. No final null-byte is inserted. However it can be manually added using \0
. Any escaped characters within must be valid UTF-8.
Note that the source file must be in UTF-8 (it always must). If it is not, strange things might happen.
.utf8 "Hello World\n", "Good afternoon!\0", U+1F981
.yours REG [, REG [, REG [, ...]]]
Marks a register as owned by the assembler. The assembler is free to use it however it sees fit. The author should avoid using those registers after being declared yours.
.yours r4, r5, r6, r7
autodie
Dies with the error in error
if error
is not undef and not RoarAudio error code 0
(none).
autodie
byte_transfer! REG, REG, INT byte_transfer REG, REG, INT
Transfers the given number of bytes from the source to the destination register. Optionally dies if the number of bytes actually transferred is less than the number of bytes requested. The transferred length is stored in out
.
byte_transfer! r0, r2, 15
control REG, REG control REG, REG, REG control REG, sni:NNN control REG, sni:NNN, REG control REG, sni:NNN, sni:MMM control REG, sni:NNN, INT
Performs a control call on the target register. The second argument is the command, the third is in if any. arg is taken from the arg register. And out is always the out register.
control! user0, sni:31, user1
die REG
Dies with the error in the given register. The value is stored in the error
register.
die r0
exit REG
Exits the program (not just returns the function). Stores the value from the given register in out
exit r0
jump REG
Jumps to the given position.
jump r0
magic
Writes a format specific magic. Normally this is used as the very first opcode for format detection. If it is encountered anywhere in the code it is equivalent to a noop.
magic
map LREG, PREG
Maps a logical register to a physical register.
map r0 user0
move REG, REG
Moves a value from one register to another. The source register becomes undef
by the move. To copy a value (like many assembler langauges do with mov
) use replace.
move r0, r1
noop
Does nothing (no operation).
noop
open REG, INT open REG, ID
Opens a handle and stores the value in the given register
open r0, 7
open user3, sni:80
replace REG, REG
Replaces a value in a register with the value of another register. The source register is unchanged.
replace r0, r2
return return REG
return
return user4
rewind REG
Rewinds (seeks to the beginning) the handle in the given register.
rewind r0
seek REG, REG
Seeks the value in the left register to the positon in the right register.
seek r0, r1
substr REG, REG, INT, INT
Opens a substring of the input register in the output register. The offset and end is given. If the end is given as a relative integer it is understood as the length.
substr rodata, program_text, 0x100, +13
tell REG, REG
Stores the current position of the input register in the output register.
tell r0, r3
transfer REG, REG
Transfers the subject/object from the source register to the target register.
transfer r0, r2
undef REG
Undefines the given register.
undef r3