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.

POPa bDiscard top item.
NIPa cDiscard second item.
SWPa c bMove second item to top.
ROTb c aMove third item to top.
DUPa b c cCopy top item.
OVRa b c bCopy 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.

BRK/LIT Literala b c M[PC+1] LDZ Load Zeropagea b M[c8]
INC Incrementa b c+1 STZ Save Zeropagea {M[c8]=b}
POP Popa b LDR Load Rela b M[PC+c8]
NIP Nipa c STR Save Rela {M[PC+c8]=b}
SWP Swapa c b LDA Load Absa b M[c16]
ROT Rotateb c a STA Save Absa {M[c16]=b}
DUP Duplicatea b c c DEI Device Ina b D[c8]
OVR Overa b c b DEO Device Outa {D[c8]=b}
EQU Equala b?c ADD Adda b+c
NEQ NotEquala b!c SUB Subtracta b-c
GTH Greatera b>c MUL Multiplya b*c
LTH Lessera b<c DIV Dividea b/c
JMP Jumpa b {PC+=c} AND Anda b&c
JCN JumpConda {(b8)PC+=c} ORA Ora b|c
JSR JumpStasha b {rs.PC PC+=c} EOR ExclusiveOra b^c
STH Stasha b {rs.c} SFT Shifta 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.


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


		( send ) LDAk EMIT
		( loop ) INC2 LDAk ,&while JCN



@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.

|absolute$relative#literal hex
@parent&child"raw word'raw char
,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.

Incoming: dexe left noodle gly format ufx format bifurcan catclock yufo proquints primes brainfuck uxn uxntal alphabet drifblim bicycle about 2021 computer oscean arvelie