197 lines
7.0 KiB
Groff
197 lines
7.0 KiB
Groff
.\" Manpage reference for uxntal.
|
|
.\" Contact d_m@plastic-idolatry.com to correct errors or typos.
|
|
.TH uxntal 1 "01 Aug 2024" "1.0" "Uxntal Reference Guide"
|
|
.SH NAME
|
|
uxntal \- assembly langauge for Varvara virtual machine
|
|
.SH DESCRIPTION
|
|
Uxntal is an 8-bit instruction set for programming the Varvara virtual machine.
|
|
It uses the lower 5-bits to specify an opcode, and the upper 3-bits to specify
|
|
optional modes.
|
|
|
|
ROMs consist of a 16-bit address space of bytes. Any byte can be interpreted as either data or an instruction. A 2-byte instruction pointer determines the address of the next instruction to decode and run.
|
|
|
|
Instructions manipulate data using two stacks: a working stack (\fBwst\fP) and a return stack (\fBrst\fP). Each stack consists of 256 bytes, and in the case of overflow or underflow the stack pointer will wrap (the stacks are circular).
|
|
|
|
.SH INSTRUCTION LAYOUT
|
|
|
|
0x01 -
|
|
0x02 \\
|
|
0x04 +- \fIopcode\fP
|
|
0x08 /
|
|
0x10 -
|
|
|
|
0x20 ---- 2: \fIshort\fP mode
|
|
0x40 ---- r: \fIreturn\fP mode
|
|
0x80 ---- k: \fIkeep\fP mode
|
|
|
|
.SH OPCODE LAYOUT
|
|
|
|
There are 32 base values for opcodes:
|
|
|
|
0x00 \fB***\fP 0x08 \fBEQU\fP 0x10 \fBLDZ\fP 0x18 \fBADD\fP
|
|
0x01 \fBINC\fP 0x09 \fBNEQ\fP 0x11 \fBSTZ\fP 0x19 \fBSUB\fP
|
|
0x02 \fBPOP\fP 0x0a \fBGTH\fP 0x12 \fBLDR\fP 0x1a \fBMUL\fP
|
|
0x03 \fBNIP\fP 0x0b \fBLTH\fP 0x13 \fBSTR\fP 0x1b \fBDIV\fP
|
|
0x04 \fBSWP\fP 0x0c \fBJMP\fP 0x14 \fBLDA\fP 0x1c \fBAND\fP
|
|
0x05 \fBROT\fP 0x0d \fBJCN\fP 0x15 \fBSTA\fP 0x1d \fBORA\fP
|
|
0x06 \fBDUP\fP 0x0e \fBJSR\fP 0x16 \fBDEI\fP 0x1e \fBEOR\fP
|
|
0x07 \fBOVR\fP 0x0f \fBSTH\fP 0x17 \fBDEO\fP 0x1f \fBSFT\fP
|
|
|
|
The "complete" opcode's value can be derived by combining the base value with its flags.
|
|
|
|
For example, \fBADD2k\fP is \fB(0x18 | 0x20 | 0x80)\fP = \fB0xb8\fP.
|
|
|
|
Unlike other opcodes, \fB0x00\fP is contextual. Its meaning depends on the \fImode\fP bits provided:
|
|
|
|
0x00 \fBBRK\fP 0x80 \fBLIT\fP
|
|
0x20 \fBJCI\fP 0xa0 \fBLIT2\fP
|
|
0x40 \fBJMI\fP 0xc0 \fBLITr\fP
|
|
0x60 \fBJSI\fP 0xe0 \fBLIT2r\fP
|
|
|
|
.SH REGULAR INSTRUCTIONS
|
|
|
|
Regular instructions have a single stack effect which is modified in a predictable way by any additional modes.
|
|
|
|
For example the generic effect for \fBADD\fP is ( x y -- x+y ). The eight combinations of modes have the following effects:
|
|
|
|
\fBADD\fP ( x^ y^ -- x+y^ ) sum two bytes using \fBwst\fP
|
|
\fBADDr\fP ( [x^ y^] -- [x+y^] ) sum two bytes using \fBrst\fP
|
|
\fBADD2\fP ( x* y* -- x+y* ) sum two shorts using \fBwst\fP
|
|
\fBADD2r\fP ( [x* y*] -- [x+y*] ) sum two shorts using \fBrst\fP
|
|
\fBADDk\fP ( x^ y^ -- x^ y^ x+y^ ) sum two bytes using \fBwst\fP, retain arguments
|
|
\fBADDkr\fP ( [x^ y^] -- [x^ y^ x+y^] ) sum two bytes using \fBrst\fP, retain arguments
|
|
\fBADD2k\fP ( x* y* -- x* y* x+y* ) sum two shorts using \fBwst\fP, retain arguments
|
|
\fBADD2kr\fP ( [x* y*] -- [x* y* x+y*] ) sum two shorts using \fBrst\fP, retain arguments
|
|
|
|
Thus for regular instructions writing a "generic" effect (leaving sigils off values whose size depends on \fIshort\fP mode) is sufficient to describe its behavior across all eight variations. Note that some instructions always read values of a fixed size. (For example the boolean condition read by \fBJCN\fP is always one byte, no matter what modes are used.)
|
|
|
|
.SS INC
|
|
( x -- x+1 )
|
|
|
|
.SS POP
|
|
( x -- )
|
|
|
|
.SS NIP
|
|
( x y -- y )
|
|
|
|
.SS SWP
|
|
( x y -- y x )
|
|
|
|
.SS ROT
|
|
( x y z -- y z x )
|
|
|
|
.SS DUP
|
|
( x -- x x )
|
|
|
|
.SS OVR
|
|
( x y -- x y x )
|
|
|
|
.SS EQU
|
|
( x y -- x==y^ )
|
|
|
|
.SS NEQ
|
|
( x y -- x!=y^ )
|
|
|
|
.SS GTH
|
|
( x y -- x>y^ )
|
|
|
|
.SS LTH
|
|
( x y -- x<y^ )
|
|
|
|
.SS JMP
|
|
( x -- ; pc <- x )
|
|
|
|
The program counter (\fIpc\fP) is unconditionally updated. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP).
|
|
|
|
.SS JCN
|
|
( x bool^ -- ; pc <- x if bool )
|
|
|
|
The program counter (\fIpc\fP) is updated when \fIbool\fP is non-zero. When \fIx\fP is a byte, it is treated as relative (\fBpc += x\fP) and when \fIx\fP is a short it is treated as absolute (\fBpc = x\fP).
|
|
|
|
.SS JSR
|
|
( x -- [pc+1*] )
|
|
|
|
Store the next address to execute before unconditionally updating the program counter (\fIpc\fP). This instruction is usually used to invoke subroutines, which use the \fBJMP2r\fP to return.
|
|
|
|
.SS STH
|
|
( x -- [x] )
|
|
|
|
.SS LDZ
|
|
( zp^ -- x )
|
|
|
|
Load data from a zero-page address (\fB0x0000 - 0x00ff\fP).
|
|
|
|
.SS STZ
|
|
( x zp^ -- )
|
|
|
|
Store data at a zero-page address (\fB0x0000 - 0x00ff\fP).
|
|
|
|
.SS LDR
|
|
( rel^ -- x )
|
|
|
|
Load data from a relative address (\fBpc + x\fP).
|
|
|
|
Note that unlike \fBLDZk\fP and \fBLDAk\fP the \fBLDRk\fP instruction is not very useful, since a relative address is usually only meaningful when run from a particular address (i.e. for a particular \fBpc\fP value).
|
|
|
|
|
|
.SS STR
|
|
( x rel^ -- )
|
|
|
|
Store data at a relative address (\fBpc + x\fP).
|
|
|
|
Note that unlike \fBSTZk\fP and \fBSTAk\fP the \fBSTRk\fP instruction is not very useful, since a relative address is usually only meaningful when run from a particular address (i.e. for a particular \fBpc\fP value).
|
|
|
|
.SS LDA
|
|
( abs* -- x )
|
|
|
|
Load data from an absolute address (\fB0x0000 - 0xffff\fP).
|
|
|
|
.SS STA
|
|
( x abs* -- )
|
|
|
|
Store data at an absolute address (\fB0x0000 - 0xffff\fP).
|
|
|
|
.SS DEI
|
|
( dev^ -- x )
|
|
|
|
Read data from a device port (\fB0x00 - 0xff\fP).
|
|
|
|
Reading from some ports may have an effect on the underlying VM; in other cases it will simply read values from device memory. See Varvara device documentation for more details.
|
|
|
|
.SS DEO
|
|
( x dev^ -- )
|
|
|
|
Write data to a device port (\fB0x00 - 0xff\fP).
|
|
|
|
Writing to some ports may have an effect on the underlying VM; in other cases it will simply write values to device memory. See Varvara device documentation for more details.
|
|
|
|
.SH SPECIAL INSTRUCTIONS
|
|
|
|
These instructions do not accept all mode flags (some do not accept any).
|
|
|
|
.SS BRK
|
|
|
|
The break instruction is used to end a vector call and return control to the virtual machine.
|
|
|
|
.SS JCI, JMI, and JSI
|
|
|
|
The "immediate jump" instructions are produced by the assembler. They interpret the next 2 bytes of the ROM as a relative address (\fIaddr\fP) and have the following effects:
|
|
|
|
\fBJMI\fP ( -- ) jump to \fIaddr\fP unconditionally
|
|
\fBJCI\fP ( bool^ -- ) jump to \fIaddr\fP if \fIbool\fP is non-zero
|
|
\fBJSI\fP ( -- [pc*] ) jump to \fIaddr\fP saving the current address (\fIpc\fP) on the return stack
|
|
|
|
(The instruction pointer will be moved forward 2 bytes, past the relative address.)
|
|
|
|
.SS LIT, LIT2, LITr, and LIT2r
|
|
|
|
The "literal" instructions are used to push new data onto the stacks. They interpret the next 1-2 bytes of the ROM (\fIwx\fP, \fIwxyz\fP) as data and push it onto the corresponding stack:
|
|
|
|
\fBLIT\fP ( -- wx^ ) push literal byte \fIwx\fP onto the \fBwst\fP
|
|
\fBLITr\fP ( -- [wx^] ) push literal byte \fIwx\fP onto the \fBrst\fP
|
|
\fBLIT2\fP ( -- wxyz* ) push literal short \fIwxyz\fP (2 bytes) onto the \fBwst\fP
|
|
\fBLIT2r\fP ( -- [wxyz*] ) push literal short \fIwxyz\fP (2 bytes) onto the \fBrst\fP
|
|
|
|
(The instruction pointer will be moved forward 1-2 bytes, past the literal data.)
|
|
|