Tal is the programming language for the Uxn virtual machine.
Uxn programs are written in a unique flavor of assembly designed especially for this virtual machine. TAL files are human-readable source files, ROM files are uxn-compatible binary program files; the application that transforms a program into an application is called the Assembler.
The Stack

In stack-machine programming, parentheses are unnecessary as there are no precedence rules, the user merely performs calculations in the sequence that is presented. The order in which elements come off a stack is known as last in, first out. In the stack items a b c
, the c
item was the last to be added, and will be the first to be removed.
POP | a b | Discard top item. |
---|---|---|
NIP | a c | Discard second item. |
SWP | a c b | Move second item to top. |
ROT | b c a | Move third item to top. |
DUP | a b c c | Copy top item. |
OVR | a b c b | Copy second item to top. |
For example, the expression 3 + 4
in conventional notation would be written as 3 4 +
in postfix notation. The expression (5 + 10) * 3
in would be written 10 5 + 3 *
.
The Opcode
Uxn can perform 32 different operations, each operation has 3 possible modes. The items in the following table include the Program Counter(PC), Memory(M), Devices(D) and Return Stack(rs). For a more detailed view of the opcodes, see the Uxntal Reference.
Stack | Memory | ||
---|---|---|---|
BRK/LIT Literal | a b c M[PC+1] | LDZ Load Zeropage | a b M[c8] |
INC Increment | a b c+1 | STZ Save Zeropage | a {M[c8]=b} |
POP Pop | a b | LDR Load Rel | a b M[PC+c8] |
NIP Nip | a c | STR Save Rel | a {M[PC+c8]=b} |
SWP Swap | a c b | LDA Load Abs | a b M[c16] |
ROT Rotate | b c a | STA Save Abs | a {M[c16]=b} |
DUP Duplicate | a b c c | DEI Device In | a b D[c8] |
OVR Over | a b c b | DEO Device Out | a {D[c8]=b} |
Logic | Arithmetic | ||
EQU Equal | a b?c | ADD Add | a b+c |
NEQ NotEqual | a b!c | SUB Subtract | a b-c |
GTH Greater | a b>c | MUL Multiply | a b*c |
LTH Lesser | a b<c | DIV Divide | a b/c |
JMP Jump | a b {PC+=c} | AND And | a b&c |
JCN JumpCond | a {(b8)PC+=c} | ORA Or | a b|c |
JSR JumpStash | a b {rs.PC PC+=c} | EOR ExclusiveOr | a b^c |
STH Stash | a b {rs.c} | SFT Shift | a b>>c8l<<c8h |
The modes are indicated by appending extra characters at the end of an opcode, for example, the short mode for the ADD
opcode is ADD2
, modes can also be combined, for example: ADD2kr
.
- The short mode operates on shorts instead of bytes.
- The return mode operate on the return stack.
- The keep mode operates without consuming items.
Programming
Uppercased opcodes are reserved words, hexadecimal values are always lowercase, values and labels begin with a special character. Comments are within parentheses, curlies are used in the definition of macros, and the square brackets are ignored.

In the following example program, we begins by creating the EMIT
macro, which contains #18
the byte referencing the Console/write port, followed by the device output DEO
opcode. From that point onward, using EMIT
will send a byte from the stack, to the Console/write port. Each device has 16 ports, each port handles a specific I/O message.
%EMIT { #18 DEO } %HALT { #010f DEO } ( init ) |0100 @program ;hello-word &while ( send ) LDAk EMIT ( loop ) INC2 LDAk ,&while JCN POP2 HALT BRK @hello-word "Hello 20 "World! 00
Assembled(32 bytes):
a001 1294 8018 1721 9480 f70d 22a0 010f 1700 4865 6c6c 6f20 576f 726c 6421 0a00
Next, we pad to |0100
, which is where the first page of memory ends, and where all Uxn programs begin. Our program begins by pushing the absolute address of the label @hello-world
to the stack, which is defined later, and points to a series ofASCII characters. This absolute address is made of two bytes.
We create the child label &while
to this position of the program so we can return to it later. Both &while
and @while
are ways to define labels, but using &while
will automatically prefix a new &label
with the name of the last @label
, in this example program/while
.
Padding | Literals | ||||||
---|---|---|---|---|---|---|---|
| | absolute | $ | relative | # | literal hex | ||
Labels | Ascii | ||||||
@ | parent | & | child | " | raw word | ' | raw char |
Addressing | Pre-processor | ||||||
, | literal relative | . | literal zero-page | % | macro-define | ~ | include |
: | raw absolute | ; | literal absolute |
Next, the LDAk
opcode takes two bytes at the top of the stack to form an absolute address, and puts the value in memory found at that address to the top of the stack, in this case, the ASCII value of the letter H. That value is sent to Console/write(port #18) which prints that character to the terminal.
We increment the absolute address found on top of the stack with INC2
, because the address is made of two bytes. We load the incremented value, the JCN
opcode will jump to the position of label &while
for as long as the item on the stack not zero. We complete the program with POP2
to remove the address on the stack, to keep the stack clean at the end of the program.
That's it! To learn more, see the Cheatsheet.
- Introduction to Uxntal, online book
- Uxntal Assembler, self-hosted
- Uxntal Linter, self-hosted
- HTML5 Interpreter, works in browser
Incoming: dexe left noodle gly format ufx format bifurcan catclock yufo proquints primes brainfuck uxn uxntal alphabet drifblim bicycle about 2021 computer oscean arvelie