1.\" Manpage reference for uxntal.
2.\" by Eiríkr Åsheim
3.\" Contact d_m@plastic-idolatry.com to correct errors or typos.
4.TH uxntal 7 "05 Aug 2024" "1.0" "Uxntal Reference Guide"
5.SH NAME
6uxntal \- assembly language for Varvara virtual machine
7.SH DESCRIPTION
8Uxntal is an 8-bit instruction set for programming the Varvara virtual machine.
9It uses the lower 5-bits to specify an opcode, and the upper 3-bits to specify
10optional modes.
11
12ROMs consist of a 16-bit address space of bytes. Any byte can be interpreted as either data or an instruction. A 2-byte program counter (\fIpc\fP) determines the address of the next instruction to decode and run.
13
14Instructions 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).
15
16There are also 256 bytes of device memory, which are used to interact with the virtual machine and its devices.
17
18Instructions deal with unsigned 8-bit values (\fIbytes\fP) and unsigned 16-bit values (\fIshorts\fP). There are no other built-in data types. Occasionally values are treated as signed, such as when loading, storing, or jumping with a relative address.
19
20Short values are stored on the stack in big-endian byte order: the least significant byte will be on the top of the stack. This makes \fB#abcd\fB is equivalent to \fB#ab #cd\fB.
21
22.SH INSTRUCTION LAYOUT
23
24 0x01 ----
25 0x02 \\
26 0x04 +- \fIopcode\fP
27 0x08 /
28 0x10 ----
29 0x20 ---- 2: \fIshort mode\fP
30 0x40 ---- r: \fIreturn mode\fP
31 0x80 ---- k: \fIkeep mode\fP
32
33.SH OPCODE LAYOUT
34
35There are 32 base values for opcodes:
36
37 0x00 \fBBRK*\fP 0x08 \fBEQU\fP 0x10 \fBLDZ\fP 0x18 \fBADD\fP
38 0x01 \fBINC\fP 0x09 \fBNEQ\fP 0x11 \fBSTZ\fP 0x19 \fBSUB\fP
39 0x02 \fBPOP\fP 0x0a \fBGTH\fP 0x12 \fBLDR\fP 0x1a \fBMUL\fP
40 0x03 \fBNIP\fP 0x0b \fBLTH\fP 0x13 \fBSTR\fP 0x1b \fBDIV\fP
41 0x04 \fBSWP\fP 0x0c \fBJMP\fP 0x14 \fBLDA\fP 0x1c \fBAND\fP
42 0x05 \fBROT\fP 0x0d \fBJCN\fP 0x15 \fBSTA\fP 0x1d \fBORA\fP
43 0x06 \fBDUP\fP 0x0e \fBJSR\fP 0x16 \fBDEI\fP 0x1e \fBEOR\fP
44 0x07 \fBOVR\fP 0x0f \fBSTH\fP 0x17 \fBDEO\fP 0x1f \fBSFT\fP
45
46The "complete" opcode's value can be derived by combining the base value with its flags.
47
48For example, \fBADD2k\fP is \fB(ADD | 2 | k)\fP = \fB(0x18 | 0x20 | 0x80)\fP = \fB0xb8\fP.
49
50Unlike other opcodes, \fB0x00\fP (\fBBRK*\fP) is contextual: its meaning depends on the \fImode\fP bits provided:
51
52 0x00 \fBBRK\fP 0x80 \fBLIT\fP
53 0x20 \fBJCI\fP 0xa0 \fBLIT2\fP
54 0x40 \fBJMI\fP 0xc0 \fBLITr\fP
55 0x60 \fBJSI\fP 0xe0 \fBLIT2r\fP
56
57.SH STACK EFFECTS
58
59.BR
60
61.SS NOTATION
62
63Given a stack effect \fB( a^ b^ c^ -- c^ a^ b^ )\fP here is what each symbol means:
64
65 \fB(\fP and \fB)\fP are comment delimiters
66 \fBa^\fP, \fBb^\fP, and \fBc^\fP are values on the stack
67 \fB^\fP indicates that each value is a \fIbyte\fP (\fB*\fP would indicate \fIshort\fP)
68 \fB--\fP separates the "before" and "after" of the stack effect
69
70The effect here is to move the top byte of the stack below the next two bytes, which could be achieved with \fBROT ROT\fP.
71
72By default stack effects describe the effect on \fBwst\fP. When \fBrst\fP is involved we use \fB[]\fP to differentiate the stacks. For example \fB( a* [b*] -- a+1* [b+1*] )\fP will increment the top short of both \fBwst\fP and \fBrst\fP.
73
74.SS EFFECTS AND MODES
75
76Regular instructions have a single stack effect which is modified in a predictable way by any additional modes.
77
78For example the generic effect for \fBADD\fP is ( x y -- x+y ). The eight combinations of modes have the following effects:
79
80.nf
81
82 \fBADD\fP ( x^ y^ -- x+y^ ) sum bytes from \fBwst\fP
83 \fBADDr\fP ( [x^ y^] -- [x+y^] ) sum bytes from \fBrst\fP
84 \fBADD2\fP ( x* y* -- x+y* ) sum shorts from \fBwst\fP
85 \fBADD2r\fP ( [x* y*] -- [x+y*] ) sum shorts from \fBrst\fP
86 \fBADDk\fP ( x^ y^ -- x^ y^ x+y^ ) sum and keep bytes from \fBwst\fP
87 \fBADDkr\fP ( [x^ y^] -- [x^ y^ x+y^] ) sum and keep bytes from \fBrst\fP
88 \fBADD2k\fP ( x* y* -- x* y* x+y* ) sum and keep shorts from \fBwst\fP
89 \fBADD2kr\fP ( [x* y*] -- [x* y* x+y*] ) sum and keep shorts from \fBrst\fP
90
91.fi
92
93Thus for regular instructions writing a "generic" effect (leaving sigils off values whose size depends on \fIshort mode\fP) 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.
94
95In \fIreturn mode\fP the stacks are reversed. Effects on \fBwst\fP will instead affect \fBrst\fP, and effects on \fBrst\fP will instead affect \fBwst\fP. For example, \fBSTH\fP reads a byte from \fBwst\fP and writes it to \fBrst\fP, but \fBSTHr\fP reads a byte from \fBrst\fP and writes it to \fBwst\fP.
96
97In \fIkeep mode\fP all the values on the left-hand side of the stack effect will also appear on the right-hand side before the outputs. For example, \fBSWP\fP is \fB(x y -- y x)\fP but \fBSWPk\fP is \fB(x y -- x y y x)\fP.
98
99.SS TERMINOLOGY
100
101We consider the top of the stack to be the first value of the stack, and count back from there. For example, given the stack effect \fB( a b c -- )\fP we would say that \fBc\fP is the top of the stack, \fBb\fP is the second value (second from the top), and \fBa\fP is the third value (third from the top).
102
103.SH REGULAR INSTRUCTIONS
104
105.BR
106
107.SS INC ( x -- x+1 )
108
109Increment the top value of the stack by 1.
110
111Overflow will be truncated, so \fB#ff INC\fP will evaluate to \fB0x00\fP.
112
113.SS POP ( x -- )
114
115Remove the top value of the stack.
116
117\fBPOPk\fP is guaranteed to have no effect (it will not change the stack).
118
119.SS NIP ( x y -- y )
120
121Remove the second value of the stack.
122
123\fBNIPk\fP is guaranteed to have no effect (it will not change the stack).
124
125.SS SWP ( x y -- y x )
126
127Swap the top two values of the stack.
128
129.SS ROT ( x y z -- y z x )
130
131Rotate the top three values of the stack. The lowest becomes the top and the others are each shifted down one place.
132
133.SS DUP ( x -- x x )
134
135Place a copy of the top value of the stack on top of the stack.
136
137.SS OVR ( x y -- x y x )
138
139Place a copy of the second value of the stack on top of the stack.
140
141.SS EQU ( x y -- x==y^ )
142
143Test whether the top two values of the stack are equal.
144
145Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
146
147.SS NEQ ( x y -- x!=y^ )
148
149Test whether the top two values of the stack are not equal.
150
151Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
152
153.SS GTH ( x y -- x>y^ )
154
155Test whether the second value of the stack is greater than the top.
156
157Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
158
159.SS LTH ( x y -- x<y^ )
160
161Test whether the second value of the stack is less than the top.
162
163Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
164
165.SS JMP ( x -- ; pc <- x )
166
167Jump to a location.
168
169The 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).
170
171It is common to \fBJMP\fP with boolean bytes (0-1) to handle simple conditionals. For example:
172
173 @max ( x^ y^ -- max^ ) GTHk JMP SWP POP JMP2r
174
175.SS JCN ( bool^ x -- ; pc <- x if bool )
176
177Jump to a location when a condition is true.
178
179The 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).
180
181.SS JSR ( x -- [pc+1*] )
182
183Jump to a location, saving a reference to return to.
184
185Stores 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. 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).
186
187The saved address will always be a short regardless of \fIshort mode\fP.
188
189.SS STH ( x -- [x] )
190
191Move the top value of the stack to the return stack.
192
193.SS LDZ ( zp^ -- x )
194
195Load data from a zero-page address (\fB0x00 - 0xff\fP).
196
197.SS STZ ( x zp^ -- )
198
199Store data at a zero-page address (\fB0x00 - 0xff\fP).
200
201.SS LDR ( rel^ -- x )
202
203Load data from a relative address (\fBpc + x\fP).
204
205Note 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 \fIpc\fP value).
206
207.SS STR ( x rel^ -- )
208
209Store data at a relative address (\fBpc + x\fP).
210
211Note 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 \fIpc\fP value).
212
213.SS LDA ( abs* -- x )
214
215Load data from an absolute address (\fB0x0000 - 0xffff\fP).
216
217.SS STA ( x abs* -- )
218
219Store data at an absolute address (\fB0x0000 - 0xffff\fP).
220
221.SS DEI ( dev^ -- x )
222
223Read data from a device port (\fB0x00 - 0xff\fP).
224
225Reading 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.
226
227.SS DEO ( x dev^ -- )
228
229Write data to a device port (\fB0x00 - 0xff\fP).
230
231Writing 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.
232
233.SS ADD ( x y -- x+y )
234
235Add the top two values of the stack.
236
237Overflow will be truncated, so \fB#ff #03 ADD\fP will evaluate to \fB0x02\fP.
238
239.SS SUB ( x y -- x-y )
240
241Subtract the top of the stack from the second value of the stack.
242
243Underflow will be truncated, so \fB#01 #03 SUB\fP will evaluate to \fB0xfe\fP.
244
245.SS MUL ( x y -- xy )
246
247Multiply the top two values of the stack.
248
249Overflow will be truncated, so \fB#11 #11 MUL\fP will evaluate to \fB0x21\fP.
250
251.SS DIV ( x y -- x/y )
252
253Divide the second value of the stack by the top of the stack.
254
255\fBDIV\fP implements \fIEuclidean division\fP, which is also known as \fIinteger division\fP. It returns whole numbers, so \fB#08 #09 DIV\fP evaluates to \fB0x00\fP.
256
257Division by zero will return zero (instead of signaling an error).
258
259Unlike \fBADD\fP, \fBSUB\fP, and \fBMUL\fP, \fBDIV\fP does not behave correctly for numbers which should be treated as signed. For example, the signed byte representation of \fB-2\fP is \fB0xfe\fP, but \fB#06 #fe DIV\fP evaluates to \fB0x00\fP (\fB6 / 254 = 0\fP). For signed values the correct result should instead be \fB0xfd\fP (\fB6 / -2 = -3\fP).
260
261There is no \fIremainder\fP instruction, but the phrase \fBDIVk MUL SUB\fP can be used to compute the remainder.
262
263.SS AND ( x y -- x&y )
264
265Compute the bitwise union of the top two values of the stack.
266
267.SS ORA ( x y -- x|y )
268
269Compute the bitwise intersection of the top two values of the stack.
270
271.SS EOR ( x y -- x^y )
272
273Compute the bitwise exclusive-or (\fIxor\fP) of the top two values of the stack.
274
275.SS SFT ( x rl^ -- (x>>l)<<r )
276
277Compute a bit shift of the second value of the stack; the directions and distances are determined by the top value of the stack.
278
279Given a byte \fIrl\fP consisting of a low nibble (\fIl\fP) and a high nibble (\fIr\fP), this instruction shifts \fIx\fP left by \fIl\fP and then right by \fIr\fP.
280
281Right shifts are unsigned (they introduce zero bits). There are no signed shifts.
282
283For 16-bit (and 8-bit) values, one nibble (\fB0x0 - 0xf\fP) is sufficient to express all useful left or right shifts.
284
285 Right: \fB#ff #03 SFT\fP evaluates to \fB0x1f\fP
286 Left: \fB#ff #20 SFT\fP evaluates to \fB0xfc\fP
287 Both: \fB#ff #23 SFT\fP evaluates to \fB0x7c\fP
288
289.SH SPECIAL INSTRUCTIONS
290
291These instructions do not accept all mode flags (some do not accept any).
292
293.SS BRK
294
295The break instruction is used to end a vector call and return control to the virtual machine.
296
297.SS JCI, JMI, and JSI
298
299The "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:
300
301 \fBJMI\fP ( -- ) jump to \fIaddr\fP unconditionally
302 \fBJCI\fP ( bool^ -- ) jump to \fIaddr\fP if \fIbool\fP is non-zero
303 \fBJSI\fP ( -- [pc*] ) jump to \fIaddr\fP saving the current address (\fIpc\fP) on \fIrst\fP
304
305(The instruction pointer will be moved forward 2 bytes, past the relative address.)
306
307These instructions are created by the assembler from special syntax:
308
309 \fB!dest\fP produces \fBJMI wx yz\fP
310 \fB?dest\fP produces \fBJCI wx yz\fP
311 \fBdest\fP produces \fBJSI wx yz\fP (assuming \fBdest\fP is not a macro or reserved)
312
313.SS LIT, LIT2, LITr, and LIT2r
314
315Push a literal value on the stack.
316
317The "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:
318
319 \fBLIT\fP ( -- wx^ ) push literal byte \fIwx\fP onto the \fBwst\fP
320 \fBLITr\fP ( -- [wx^] ) push literal byte \fIwx\fP onto the \fBrst\fP
321 \fBLIT2\fP ( -- wxyz* ) push literal short \fIwxyz\fP (2 bytes) onto the \fBwst\fP
322 \fBLIT2r\fP ( -- [wxyz*] ) push literal short \fIwxyz\fP (2 bytes) onto the \fBrst\fP
323
324(The instruction pointer will be moved forward 1-2 bytes, past the literal data.)
325
326Literal values can be updated dynamically using store instructions:
327
328 #abcd ;x STA2
329 ( later on... )
330 LIT2 [ @x $2 ]
331
332.SH SEE ALSO
333
334 https://wiki.xxiivv.com/site/uxntal_opcodes.html \fIUxntal Opcodes\fP
335 https://wiki.xxiivv.com/site/uxntal_syntax.html \fIUxntal Syntax\fP
336 https://wiki.xxiivv.com/site/uxntal_modes.html \fIUxntal Modes\fP
337 https://wiki.xxiivv.com/site/uxntal_immediate.html \fIImmediate opcodes\fP
338 https://wiki.xxiivv.com/site/varvara.html \fIVarvara\fP