# UXN Reformatted from [the reference document](https://wiki.xxiivv.com/site/uxntal_reference.html) UXN is a deterministic, non-interrupting, 8-bit instruction set and word stack machine with a 16bi address space. It interacts with the outside world via port mapped I/O devices, of which 16 are supported. ## Memory model UXN presents a linear uniform main memory with a 16bi address space. Programs may do I/O across the entire address space using the `LDR2` and `STR2` instructions. The UXN address space is divided into chunks called pages, each with 8bi of addressing. The 0 page (`0x00[00-FF]`) is special and, for convenience, can be accessed using the `LDZ` and `STRZ` instructions. The UXN stack machine, in keeping with [the forth tradition](http://www.forth.org/svfig/Len/softstak.htm) has two stacks. These are referred to as `DATA` (stack 0) and `RETURN` (stack 1) by convention. Instructions may choose to transpose the stacks, allowing for computation on either stack. See below for more on the `return` flag. The `LDR` and `STR` instructions are stack relative and allow for computed loads and stores. ## Instruction set UXN instructions are 8-bit values. | k | r | 2 | opcode | |------|--------|-------|-----------| | keep | return | short | 0 0 0 0 0 | The three most significant bits of the instructions are mode flags of which we will say more. The least significant five bits select an instruction. Effects are written using forth-style notation `inputs -- outputs` | Opcode | Memonic | Long name | Data stack effect | Control stack effect | PC effect | Memory effect | |--------|---------|--------------------------|---------------------------------------------|----------------------|---------------------|-------------------| | 0x00 | BRK | Break | -- | -- | | | | 0x01 | INC | Increment | a -- a+1 | | | | | 0x02 | POP | Pop | a -- | | | | | 0x03 | NIP | Nip | b a -- a | | | | | 0x04 | SWP | Swap | b a -- a b | | | | | 0x05 | ROT | Rotate | a b c -- b c a | | | | | 0x06 | DUP | Duplicate | a -- a a | | | | | 0x07 | OVR | Over | a b -- a b a | | | | | 0x08 | EQU | Equal | b a -- (a == b) | | | | | 0x09 | NEQ | Not equal | b a -- (a != b) | | | | | 0x0A | GTH | Greater than | b a -- (b > a) | | | | | 0x0B | LTH | Less than | b a -- (b < a) | | | | | 0x0C | JMP | Jump | a -- | | PC+=a | | | 0x0D | JCN | Conditional jump | b a -- | | PC+=(a if b else 1) | | | 0x0E | JSR | Jump stash return (call) | a -- | -- pc | PC+=a | | | 0x0F | STH | Stash | a -- | -- a | | | | 0x10 | LDZ | Load zero page | a: u8 -- MEM[a] | | | | | 0x11 | STZ | Store zero page | b a: u8 -- | | | MEM[a] = b | | 0x12 | LDR | Load | a: i8 -- MEM[DATA + a] | | | | | 0x13 | STR | Store | b a: i8 -- | | | MEM[DATA + a] = b | | 0x14 | LDA | Load absolute | a: i16 -- MEM[a] | | | | | 0x15 | STA | Store absolute | b a: i16 -- | | | MEM[a] = b | | 0x16 | DEI | Device input | a: u8 -- DEV[a] | | | | | 0x17 | DEO | Device output | b a: u8 -- | | | DEV[a] = b | | 0x18 | ADD | Add | b a -- a + b | | | | | 0x19 | SUB | Subtract | b a -- a - b | | | | | 0x1A | MUL | Multiply | b a -- a * b | | | | | 0x1B | DIV | Divide | b a -- a / b | | | | | 0x1C | AND | And | b a -- a && b | | | | | 0x1D | ORA | Or | b a -- a\|b | | | | | 0x1E | EOR | Exclusive or (xor) | b a -- a^b | | | | | 0x1F | SFT | Shift | b a -- b >> (a & 0x0f) << ((a & 0xf0) >> 4) | | | | ### Mode bits Note that all these instructions are listed with `keep=0,return=0,short=0`. The UXN documentation refers to `ADD` with `keep=1` as `ADDk`. `ADD` with `short=1` is `ADD2`, and with `keep=1` would be `ADD2k`. `POP` with `return=1` is `POPr`. Conventionally these suffixes are formatted `%/2?k?r?/` as required. #### Short mode In When the `short` bit is set, the opcode will pop two 8bi quantities from the stack where it would only consume one in `byte` mode. Each `b a` pair so popped is considered to be the unsigned 16bi quantity `a + b<<8` For instance `ADDs` would be `a b c d –- (a<<8 + b) + (c<<8+d)`. **Exceptions:** - The load/store operations move two 8bi values not one. `STR` becomes `c b a -- MEM[DATA + a] = ` Relative address computation is unaffected. - The jump opcodes become absolute rather than computed relative jumps. #### Keep mode When the `keep` bit is set, no values are popped from the stack. For instance `ADD2k` would be `a b c d -- a b c d e f`. #### Return mode "return mode" flips the stacks. If `STH` pops from data and pushes to return, `STHr` pops from return and pushes to data. Likewise if `ADD` pops from data and pushes to data, `ADDr` would pop from data and push to data. `JMP2` would load `b a` from the data stack and branch absolutely, `JMP2r` would do the same from the control stack. `DUP2r` would `a b -- a b a b` the return stack. The bytecode sequence `LIT 0x01 STH JSRr BRK` would load `0x1` to the data stack, pop and stash it to the return stack, perform a relative jump by `+1` while pushing `PC` to the data stack and halt.