XXIIVV

The Uxntal Manual

The LIT and BRK opcodes share the same opcode space, the BRK opcode is stored as 00, whereas the LIT and LIT2 opcodes are stored where LITk and LIT2k would be stored. The extra modes of the BRK/LIT opcode are unused.

Addressing

Labels

A position in a program can be defined with a label, a label is a permanent reference to that specific location in the program. Labels can have sublabels, which are automatically prefixed with their parent label. In the following example, print-str is a label, and code>print-str/while is a sublabel.

@print-str ( str* -- )

	&while
		LDAk #18 DEO
		INC2 LDAk ,&while JCN
	POP2

JMP2r

References

There are 4 ways to reference a label, a zero-page reference can only target a label located within the first 256 bytes of memory. A relative reference can only target a label located 127 bytes before, or 127 bytes after the current location, an absolute reference can target a label anywhere in the program.

Instructions

Modes

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. You can see the complete list of stack permutations.

#1234 #4567 ADD2k 12  34  45  67  57  9b  00  00
POPkaaSWPka ba b b a
DUPkaa a aOVRka ba b a b a
NIPka ba b bROTka b ca b c b c a

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 stash 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

Opcodes

Break

BRK -- Halts the program.

Literal

LIT -- a Pushes the next bytes in memory, on the stack.

LIT 12          ( 12 )
LIT2 abcd       ( ab cd )

Increment

INC a -- b Adds 1 to the value at the top of the stack.

#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 )

Logic

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 )

Control-Flow

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.

Memory

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.

Arithmetic

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.

Bitwise

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 )

Incoming: uxntal 2021