Each opcode has 3 possible modes, which can combined:
- The short mode 2 operates on shorts, instead of bytes.
- The keep mode k operates without consuming items.
- The return mode r operates on the return stack.
By default, operators consume bytes from the working stack, notice how in the following example only the last two bytes
#67 are added, even if there are two shorts on the stack.
#1234 #4567 ADD12 34 ac
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
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 decremented on
#1234 #4567 ADD2k 12 34 45 67 57 9b
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.
LITr 12 #34 STH ADDr STHr 46
To better understand how the opcode modes are used, here is a 22 bytes long implementation of the function to generate numbers in the Fibonacci sequence. Notice how only a single literal is created to perform the operation.
@fib ( num -- numfib* ) #0001 GTH2k ?&ok POP2 JMP2r &ok SUB2k fib STH2 INC2 SUB2 fib STH2r ADD2 JMP2r
Incoming: uxn devlog