XXIIVV

The Uxntal Manual

This documentation includes hand gestures, and glyphs, which might serve a dual purpose; both enabling the usage of the Uxntal language outside of the computer, as well as to help students to familiarize themselves with hexadecimal finger-counting and bitwise operations.

Opcodes

000102030405060708090a0b0c0d0e0f
00BRKINCPOPNIPSWPROTDUPOVREQUNEQGTHLTHJMPJCNJSRSTH
10LDZSTZLDRSTRLDASTADEIDEOADDSUBMULDIVANDORAEORSFT
20-INC2POP2NIP2SWP2ROT2DUP2OVR2EQU2NEQ2GTH2LTH2JMP2JCN2JSR2STH2
30LDZ2STZ2LDR2STR2LDA2STA2DEI2DEO2ADD2SUB2MUL2DIV2AND2ORA2EOR2SFT2
40-INCrPOPrNIPrSWPrROTrDUPrOVRrEQUrNEQrGTHrLTHrJMPrJCNrJSRrSTHr
50LDZrSTZrLDRrSTRrLDArSTArDEIrDEOrADDrSUBrMULrDIVrANDrORArEORrSFTr
60-INC2rPOP2rNIP2rSWP2rROT2rDUP2rOVR2rEQU2rNEQ2rGTH2rLTH2rJMP2rJCN2rJSR2rSTH2r
70LDZ2rSTZ2rLDR2rSTR2rLDA2rSTA2rDEI2rDEO2rADD2rSUB2rMUL2rDIV2rAND2rORA2rEOR2rSFT2r
80LITINCkPOPkNIPkSWPkROTkDUPkOVRkEQUkNEQkGTHkLTHkJMPkJCNkJSRkSTHk
90LDZkSTZkLDRkSTRkLDAkSTAkDEIkDEOkADDkSUBkMULkDIVkANDkORAkEORkSFTk
a0LIT2INC2kPOP2kNIP2kSWP2kROT2kDUP2kOVR2kEQU2kNEQ2kGTH2kLTH2kJMP2kJCN2kJSR2kSTH2k
b0LDZ2kSTZ2kLDR2kSTR2kLDA2kSTA2kDEI2kDEO2kADD2kSUB2kMUL2kDIV2kAND2kORA2kEOR2kSFT2k
c0LITrINCkrPOPkrNIPkrSWPkrROTkrDUPkrOVRkrEQUkrNEQkrGTHkrLTHkrJMPkrJCNkrJSRkrSTHkr
d0LDZkrSTZkrLDRkrSTRkrLDAkrSTAkrDEIkrDEOkrADDkrSUBkrMULkrDIVkrANDkrORAkrEORkrSFTkr
e0LIT2rINC2krPOP2krNIP2krSWP2krROT2krDUP2krOVR2krEQU2krNEQ2krGTH2krLTH2krJMP2krJCN2krJSR2krSTH2kr
f0LDZ2krSTZ2krLDR2krSTR2krLDA2krSTA2krDEI2krDEO2krADD2krSUB2krMUL2krDIV2krAND2krORA2krEOR2krSFT2kr

The 0x20, 0x40 and 0x60 opcodes are unused, emulators can make use of these for debugging purposes. Notice how the 0x00 opcode, with the keep bit toggled, is the actual location of the LIT, LIT2, LITr and LIT2r opcodes. Boolean bytes are 00 for false, and 01 for true.

Break

BRK -- Ends the evalutation of the current vector, the BRK opcode has no modes.

Literal

LIT -- a Pushes the next bytes in memory, on the stack, the LIT opcode always has the keep mode active. To learn more, see literals.

LIT 12          ( 12 )
LIT2 abcd       ( ab cd )

Increment

INC a -- b Increments the value at the top of the stack, by 1.

#01 INC         ( 02 )
#0001 INC2      ( 00 02 )
#0001 INC2k     ( 00 01 00 02 )

Pop

POP a -- Removes the value at the top of the stack.

#1234 POP    ( 12 )
#1234 POP2   ( )
#1234 POP2k  ( 12 34 )

Nip

NIP a b -- b Removes the second value from the stack. This is practical to convert a small short into a byte.

#1234 NIP          ( 34 )
#1234 #5678 NIP2   ( 56 78 )
#1234 #5678 NIP2k  ( 12 34 56 78 56 78 )

Swap

SWP a b -- b a Exchanges the first and second values at the top of the stack.

#1234 SWP          ( 34 12 )
#1234 SWPk         ( 12 34 34 12 )
#1234 #5678 SWP2   ( 56 78 12 34 )
#1234 #5678 SWP2k  ( 12 34 56 78 56 78 12 34 )

Rotate

ROT a b c -- b c a Rotates three values at the top of the stack, to the left, wrapping around.

#1234 #56 ROT            ( 34 56 12 )
#1234 #56 ROTk           ( 12 34 56 34 56 12 )
#1234 #5678 #9abc ROT2   ( 56 78 9a bc 12 34 )
#1234 #5678 #9abc ROT2k  ( 12 34 56 78 9a bc 56 78 9a bc 12 34 )

Duplicate

DUP a -- a a Duplicates the value at the top of the stack.

#1234 DUP   ( 12 34 34 )
#12 DUPk    ( 12 12 12 )
#1234 DUP2  ( 12 34 12 34 )

Over

OVR a b -- a b a Duplicates the second value at the top of the stack.

#1234 OVR          ( 12 34 12 )
#1234 OVRk         ( 12 34 12 34 12 )
#1234 #5678 OVR2   ( 12 34 56 78 12 34 )
#1234 #5678 OVR2k  ( 12 34 56 78 12 34 56 78 12 34 )

Equal

EQU a b -- bool8 Pushes 01 to the stack if the two values at the top of the stack are equal, 00 otherwise.

#1212 EQU          ( 01 )
#1234 EQUk         ( 12 34 00 )
#abcd #ef01 EQU2   ( 00 )
#abcd #abcd EQU2k  ( ab cd ab cd 01 )

Not Equal

NEQ a b -- bool8 Pushes 01 to the stack if the two values at the top of the stack are not equal, 00 otherwise.

#1212 NEQ          ( 00 )
#1234 NEQk         ( 12 34 01 )
#abcd #ef01 NEQ2   ( 01 )
#abcd #abcd NEQ2k  ( ab cd ab cd 00 )

Greater Than

GTH a b -- bool8 Pushes 01 to the stack if the second value at the top of the stack is greater than the value at the top of the stack, 00 otherwise.

#1234 GTH          ( 00 )
#3412 GTHk         ( 34 12 01 )
#3456 #1234 GTH2   ( 01 )
#1234 #3456 GTH2k  ( 12 34 34 56 00 )

Lesser Than

LTH a b -- bool8 Pushes 01 to the stack if the second value at the top of the stack is lesser than the value at the top of the stack, 00 otherwise.

#0101 LTH          ( 00 )
#0100 LTHk         ( 01 00 00 )
#0001 #0000 LTH2   ( 00 )
#0001 #0000 LTH2k  ( 00 01 00 00 00 )

Jump

JMP addr -- Moves the program counter by a signed value equal to the byte on the top of the stack, or an absolute address in short mode.

Jump Conditional

JCN cond8 addr -- If the byte preceeding the address is not 00, moves the program counter by a signed value equal to the byte on the top of the stack, or an absolute address in short mode.

Jump Stash Return

JSR addr -- Pushes the value of the program counter to the return-stack and moves the program counter by a signed value equal to the byte on the top of the stack, or an absolute address in short mode.

Stash

STH a -- Moves the value at the top of the stack, to the return stack.


Load Zero-Page

LDZ addr8 -- value Pushes the value at an address within the first 256 bytes of memory, to the top of the stack.

Store Zero-Page

STZ val addr8 -- Writes a value to an address within the first 256 bytes of memory.

Load Relative

LDR addr8 -- value Pushes the value at a relative address, to the top of the stack. The possible relative range is -128 to +127 bytes.

Store Relative

STR val addr8 -- Writes a value to a relative address. The possible relative range is -128 to +127 bytes.

Load Absolute

LDA addr16 -- value Pushes the value at a absolute address, to the top of the stack.

Store Absolute

STA val addr16 -- Writes a value to a absolute address.

Device Input

DEI device8 -- value Pushes a value from the device page, to the top of the stack. The target device might capture the reading to trigger an I/O event.

Device Output

DEO val device8 -- Writes a value to the device page. The target device might capture the writing to trigger an I/O event.


Add

ADD a b -- c Pushes the sum of the two values at the top of the stack.

Subtract

SUB a b -- c Pushes the difference of the first value minus the second, to the top of the stack.

Multiply

MUL a b -- c Pushes the product of the first and second values at the top of the stack.

Divide

DIV a b -- c Pushes the quotient of the first value over the second, to the top of the stack.


And

AND a b -- c Pushes the result of the bitwise operation AND, to the top of the stack.

Or

ORA a b -- c Pushes the result of the bitwise operation OR, to the top of the stack.

Exclusive Or

EOR a b -- c Pushes the result of the bitwise operation XOR, to the top of the stack.

Shift

SFT a shift8 -- c Shifts the bits of the second value of the stack to the left or right, depending on the control value at the top of the stack. The high nibble of the control value indicates how many bits to shift left, and the low nibble how many bits to shift right. The rightward shift is done first.

#34 #10 SFT        ( 68 )
#34 #01 SFT        ( 1a )
#34 #33 SFTk       ( 34 33 30 )
#1248 #34 SFTk2    ( 12 48 34 09 20 )

Modes

There are 32 opcodes, each opcode occupies 5 bits of a byte, the remaining 3 bits are used for the modes of that opcode.

modes kr2opcode BRK
keepreturnshort00000

By default, operators operate on bytes, notice how in the following example only the last two bytes #45 and #67 are added, even if there are two shorts on the stack.

#1234 #4567 ADD  12  34  ac  00  00  00  00  00

The short mode consumes two bytes from the stack. In the case of jump opcodes, the short-mode operation jumps to an absolute address in memory. For the memory accessing opcodes, the short mode operation indicates the size of the data to read and write.

#1234 #4567 ADD2 57  9b  00  00  00  00  00  00

The keep mode does not consume items from the stack, and pushes the result on top. The following example adds the two shorts together, but does not consume them. Under the hood, the keep mode keeps a temporary stack pointer that is decrement on POP.

#1234 #4567 ADD2k 12  34  45  67  57  9b  00  00

The return mode makes it possible for any opcode to operate on the return-stack directly. For that reason, there is no dedicated return opcode. For example, the JSR opcode pushes the program's address onto the return stack before jumping, to return to that address, the JMP2r opcode is used, where instead of using the address on the working-stack, it takes its address from the return-stack.

#1234 #4567 STH ROT STH ADDr STHr 34  45  79  00  00  00  00  00

Literals

A literal is a byte or short value to be pushed on the stacks, it is prefixed with the LIT opcode. A plain value will be interpreted as an opcode.

ByteCharZeroPageRelativeShort*Absolute*
Literal#ab.label,label#abcd;label
Plainab'Qabcd:label

Stacks

Stacks are made of 256 bytes, or a page, of memory. The second to last byte of the page stores an error code, the last byte of a stack stores the stack pointer which holds the position of the next item on the stack. For example, if the stack is empty, the pointer has the value 0, if an item is added the stack pointer has a value of 1.

There is a total of 254 bytes of memory that can be stored in a stack before it overflows.

Memory

There are 64kb of addressable memory. Roms are loaded at 0x0100. Once in memory, a Uxn program can write over itself, store values among its running code, it is not uncommon for a uxntal program to directly modify the value of a literal in memory, or to change an opcode for another instead of branching.

The zero-page is the memory located between 0x0000 and 0x0100, its purpose is to store variables that will be accessed often. It is sligthly faster to read and write from the zero-page using the LDZ and STZ opcodes as they use only a single byte instead of a short. This memory space cannot be pre-filled in the rom prior to assembly.

Vectors

Uxn is non-interruptible, vectors are locations in programs that are evaluated when certain events occur. A vector is evaluated until a BRK opcode is encountered, no new events will be triggered while a vector is evaluated. Only one vector is executed at a time. The content of the stacks are preserved between vectors.

In other words, the Mouse/vector port holds an address to a part of the program that will be evaluated when the cursor is moved, or a button state has changed.

Errors

Errors occur when a program behaves badly. Errors are normally handled by the emulator, but programs can set a system vector to evaluate when errors occurs. There are four known error types, and each one has an error code:

The Uxntal Alphabet is a series of glyph representing uxntal numbers and opcodes.

This purpose of the alphabet is to enable the usage of the Uxntal operators outside of the computer, as well as to help students to familiarize themselves with hexadecimal finger-counting and bitwise operations.

Opcodes

brk inc pop nip swp rot dup ovr
equ neq gth lth jmp jcn jsr sth
ldz stz ldr str lda sta dei deo
add sub mul div and ora eor sft

Modes

The Short Mode is indicated by 2 vertical strokes above the glyph, the Keep Mode is indicated by a forward diagonal stroke under the glyph, the Stash Mode is indicated by a small circle drawn above the glyph.

The Min2 routine written with the Uxntal alphabet.

Numbers

The numerical system was designed by Bruce Martin.

The Uxntal Sign Language is a series of hand gestures representing uxntal numbers and opcodes.

The signs are meant to augment the student's current sign dialect, and disambiguate from commonly used signs, and decimal numbers that might be found in the names of labels.

Opcodes

brk inc pop nip
swp rot dup ovr
equ neq gth lth
jmp jcn jsr sth
add sub mul div
and ora eor sft

Numbers

To sign numbers, such as the number two, which would be hard to do by sheer positioning of the finger, open your palm, and use your left index finger to push the ring finger out of your right palm. Don't try to extend the ring finger out on its own.

0 1 2 3
4 5 6 7
8 9 a b
c d e f

Incoming: uxntal