commit 5a41189

d_m  ·  2024-08-06 02:09:53 +0000 UTC
parent 7849662
Add uxntal manpage.

This change adds uxntal.7 [1].

It also updates the makefile to install the executables and man page
in ~/.local (~/.local/bin and ~/.local/share/man respectively). This
can easily be overridden by using PREFIX, for example:

  # install into home directory
  make PREFIX=$HOME install

  # install into /usr/local
  make PREFIX=/usr/local install

Finally, it updates the README to describe these things.

[1] Origin: https://git.phial.org/d6/nxu/raw/branch/main/uxntal.7
3 files changed,  +394, -2
+24, -0
 1@@ -4,6 +4,20 @@ An emulator for the [Uxn stack-machine](https://wiki.xxiivv.com/site/uxn.html),
 2 
 3 ## Building 
 4 
 5+### Makefile
 6+
 7+For your convenience a [Makefile](https://en.wikipedia.org/wiki/Make_(software)#Makefile) is provided. You can run `make install` to build and install the files.
 8+
 9+By default, files are installed into `~/.local` but this can be overridden using `PREFIX`:
10+
11+```sh
12+# installs files into ~/.local/bin and ~/.local/share
13+$ make install
14+
15+# installs files into /opt/uxn/bin and /opt/uxn/share
16+$ make PREFIX=/opt/uxn install
17+```
18+
19 ### Graphical
20 
21 All you need is X11.
22@@ -32,6 +46,16 @@ The first parameter is the rom file, the subsequent arguments will be accessible
23 bin/uxnemu bin/polycat.rom arg1 arg2
24 ```
25 
26+## Manual
27+
28+A manual page is provided documenting the Uxntal language:
29+
30+```sh
31+man ./doc/man/uxntal.7
32+```
33+
34+After running `make install` the man page should be found by `man uxntal`.
35+
36 ## Devices
37 
38 The file device is _sandboxed_, meaning that it should not be able to read or write outside of the working directory.
+363, -0
  1@@ -0,0 +1,363 @@
  2+.\" Manpage reference for uxntal.
  3+.\" by Eiríkr Åsheim
  4+.\" Contact d_m@plastic-idolatry.com to correct errors or typos.
  5+.TH uxntal 7 "05 Aug 2024" "1.0" "Uxntal Reference Guide"
  6+.SH NAME
  7+uxntal \- assembly langauge for Varvara virtual machine
  8+.SH DESCRIPTION
  9+Uxntal is an 8-bit instruction set for programming the Varvara virtual machine.
 10+It uses the lower 5-bits to specify an opcode, and the upper 3-bits to specify
 11+optional modes.
 12+
 13+ROMs 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.
 14+
 15+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).
 16+
 17+There are also 256 bytes of device memory, which are used to interact with the virtual machine and its devices.
 18+
 19+Instructions deal with unsigned 8-bit values (\fIbytes\fP) and unsigned 16-bit values (\fIshorts\fP). There are no other built-in data types.
 20+
 21+.SH INSTRUCTION LAYOUT
 22+
 23+ 0x01 ----
 24+ 0x02     \\
 25+ 0x04      +- \fIopcode\fP
 26+ 0x08     /
 27+ 0x10 ----
 28+ 0x20 ---- 2: \fIshort mode\fP
 29+ 0x40 ---- r: \fIreturn mode\fP
 30+ 0x80 ---- k: \fIkeep mode\fP
 31+
 32+.SH OPCODE LAYOUT
 33+
 34+There are 32 base values for opcodes:
 35+
 36+    0x00 \fBBRK*\fP   0x08 \fBEQU\fP    0x10 \fBLDZ\fP    0x18 \fBADD\fP
 37+    0x01 \fBINC\fP    0x09 \fBNEQ\fP    0x11 \fBSTZ\fP    0x19 \fBSUB\fP
 38+    0x02 \fBPOP\fP    0x0a \fBGTH\fP    0x12 \fBLDR\fP    0x1a \fBMUL\fP
 39+    0x03 \fBNIP\fP    0x0b \fBLTH\fP    0x13 \fBSTR\fP    0x1b \fBDIV\fP
 40+    0x04 \fBSWP\fP    0x0c \fBJMP\fP    0x14 \fBLDA\fP    0x1c \fBAND\fP
 41+    0x05 \fBROT\fP    0x0d \fBJCN\fP    0x15 \fBSTA\fP    0x1d \fBORA\fP
 42+    0x06 \fBDUP\fP    0x0e \fBJSR\fP    0x16 \fBDEI\fP    0x1e \fBEOR\fP
 43+    0x07 \fBOVR\fP    0x0f \fBSTH\fP    0x17 \fBDEO\fP    0x1f \fBSFT\fP
 44+
 45+The "complete" opcode's value can be derived by combining the base value with its flags.
 46+
 47+For example, \fBADD2k\fP is \fB(ADD | 2 | k)\fP = \fB(0x18 | 0x20 | 0x80)\fP = \fB0xb8\fP.
 48+
 49+Unlike other opcodes, \fB0x00\fP (\fBBRK*\fP) is contextual: its meaning depends on the \fImode\fP bits provided:
 50+
 51+    0x00 \fBBRK\fP    0x80 \fBLIT\fP
 52+    0x20 \fBJCI\fP    0xa0 \fBLIT2\fP
 53+    0x40 \fBJMI\fP    0xc0 \fBLITr\fP
 54+    0x60 \fBJSI\fP    0xe0 \fBLIT2r\fP
 55+
 56+.SH STACK EFFECTS
 57+
 58+.BR
 59+
 60+.SS NOTATION
 61+
 62+Given a stack effect \fB( a^ b^ c^ -- c^ a^ b^ )\fP here is what each symbol means:
 63+
 64+    \fB(\fP and \fB)\fP are comment delimiters
 65+    \fBa^\fP, \fBb^\fP, and \fBc^\fP are values on the stack
 66+    \fB^\fP indicates that each value is a \fIbyte\fP (\fB*\fP would indicate \fIshort\fP)
 67+    \fB--\fP separates the "before" and "after" of the stack effect
 68+
 69+The effect here is to move the top byte of the stack below the next two bytes, which could be achieved with \fBROT ROT\fP.
 70+
 71+By 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.
 72+
 73+.SS EFFECTS AND MODES
 74+
 75+Regular instructions have a single stack effect which is modified in a predictable way by any additional modes.
 76+
 77+For example the generic effect for \fBADD\fP is ( x y -- x+y ). The eight combinations of modes have the following effects:
 78+
 79+    \fBADD\fP    ( x^ y^   -- x+y^ )         sum two bytes using \fBwst\fP
 80+    \fBADDr\fP   ( [x^ y^] -- [x+y^] )       sum two bytes using \fBrst\fP
 81+    \fBADD2\fP   ( x* y*   -- x+y* )         sum two shorts using \fBwst\fP
 82+    \fBADD2r\fP  ( [x* y*] -- [x+y*] )       sum two shorts using \fBrst\fP
 83+    \fBADDk\fP   ( x^ y^   -- x^ y^ x+y^ )   sum two bytes using \fBwst\fP, retain arguments
 84+    \fBADDkr\fP  ( [x^ y^] -- [x^ y^ x+y^] ) sum two bytes using \fBrst\fP, retain arguments
 85+    \fBADD2k\fP  ( x* y*   -- x* y* x+y* )   sum two shorts using \fBwst\fP, retain arguments
 86+    \fBADD2kr\fP ( [x* y*] -- [x* y* x+y*] ) sum two shorts using \fBrst\fP, retain arguments
 87+
 88+Thus 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.
 89+
 90+In \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.
 91+
 92+In \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.
 93+
 94+.SS TERMINOLOGY
 95+
 96+We 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).
 97+
 98+.SH REGULAR INSTRUCTIONS
 99+
100+.BR
101+
102+.SS INC
103+( x -- x+1 )
104+
105+Increment the top value of the stack by 1.
106+
107+Overflow will be truncated, so \fB#ff INC\fP will evaluate to \fB0x00\fP.
108+
109+.SS POP
110+( x -- )
111+
112+Remove the top value of the stack.
113+
114+\fBPOPk\fP is guaranteed to have no effect (it will not change the stack).
115+
116+.SS NIP
117+( x y -- y )
118+
119+Remove the second value of the stack.
120+
121+\fBNIPk\fP is guaranteed to have no effect (it will not change the stack).
122+
123+.SS SWP
124+( x y -- y x )
125+
126+Swap the top two values of the stack.
127+
128+.SS ROT
129+( x y z -- y z x )
130+
131+Rotate 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
134+( x -- x x )
135+
136+Place a copy of the top value of the stack on top of the stack.
137+
138+.SS OVR
139+( x y -- x y x )
140+
141+Place a copy of the second value of the stack on top of the stack.
142+
143+.SS EQU
144+( x y -- x==y^ )
145+
146+Test whether the top two values of the stack are equal.
147+
148+Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
149+
150+.SS NEQ
151+( x y -- x!=y^ )
152+
153+Test whether the top two values of the stack are not equal.
154+
155+Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
156+
157+.SS GTH
158+( x y -- x>y^ )
159+
160+Test whether the second value of the stack is greater than the top.
161+
162+Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
163+
164+.SS LTH
165+( x y -- x<y^ )
166+
167+Test whether the second value of the stack is less than the top.
168+
169+Result is guaranteed to be boolean (\fB0x00\fP or \fB0x01\fP).
170+
171+.SS JMP
172+( x -- ; pc <- x )
173+
174+Jump to a location.
175+
176+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).
177+
178+It is common to \fBJMP\fP with boolean bytes (0-1) to handle simple conditionals. For example:
179+
180+    @max ( x^ y^ -- max^ ) GTHk JMP SWP POP JMP2r
181+
182+.SS JCN
183+( x bool^ -- ; pc <- x if bool )
184+
185+Jump to a location when a condition is true.
186+
187+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).
188+
189+.SS JSR
190+( x -- [pc+1*] )
191+
192+Jump to a location, saving a reference to return to.
193+
194+Stores 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).
195+
196+The saved address will always be a short regardless of \fIshort mode\fP.
197+
198+.SS STH
199+( x -- [x] )
200+
201+Move the top value of the stack to the return stack.
202+
203+.SS LDZ
204+( zp^ -- x )
205+
206+Load data from a zero-page address (\fB0x00 - 0xff\fP).
207+
208+.SS STZ
209+( x zp^ -- )
210+
211+Store data at a zero-page address (\fB0x00 - 0xff\fP).
212+
213+.SS LDR
214+( rel^ -- x )
215+
216+Load data from a relative address (\fBpc + x\fP).
217+
218+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 \fIpc\fP value).
219+
220+.SS STR
221+( x rel^ -- )
222+
223+Store data at a relative address (\fBpc + x\fP).
224+
225+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 \fIpc\fP value).
226+
227+.SS LDA
228+( abs* -- x )
229+
230+Load data from an absolute address (\fB0x0000 - 0xffff\fP).
231+
232+.SS STA
233+( x abs* -- )
234+
235+Store data at an absolute address (\fB0x0000 - 0xffff\fP).
236+
237+.SS DEI
238+( dev^ -- x )
239+
240+Read data from a device port (\fB0x00 - 0xff\fP).
241+
242+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.
243+
244+.SS DEO
245+( x dev^ -- )
246+
247+Write data to a device port (\fB0x00 - 0xff\fP).
248+
249+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.
250+
251+.SS ADD
252+( x y -- x+y )
253+
254+Add the top two values of the stack.
255+
256+Overflow will be truncated, so \fB#ff #03 ADD\fP will evaluate to \fB0x02\fP.
257+
258+.SS SUB
259+( x y -- x-y )
260+
261+Subtract the top of the stack from the second value of the stack.
262+
263+Underflow will be truncated, so \fB#01 #03 SUB\fP will evaluate to \fB0xfe\fP.
264+
265+.SS MUL
266+( x y -- xy )
267+
268+Multiply the top two values of the stack.
269+
270+Overflow will be truncated, so \fB#11 #11 MUL\fP will evaluate to \fB0x21\fP.
271+
272+.SS DIV
273+( x y -- x/y )
274+
275+Divide the second value of the stack by the top of the stack.
276+
277+\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.
278+
279+Division by zero will return zero (instead of signaling an error).
280+
281+Unlike \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).
282+
283+There is no \fIremainder\fP instruction, but the phrase \fBDIVk MUL SUB\fP can be used to compute the remainder.
284+
285+.SS AND
286+( x y -- x&y )
287+
288+Compute the bitwise union of the top two values of the stack.
289+
290+.SS ORA
291+( x y -- x|y )
292+
293+Compute the bitwise intersection of the top two values of the stack.
294+
295+.SS EOR
296+( x y -- x^y )
297+
298+Compute the bitwise exclusive-or (\fIxor\fP) of the top two values of the stack.
299+
300+.SS SFT
301+( x rl^ -- (x>>l)<<r )
302+
303+Compute a bit shift of the second value of the stack; the directions and distances are determined by the top value of the stack.
304+
305+Given 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.
306+
307+Right shifts are unsigned (they introduce zero bits). There are no signed shifts.
308+
309+For 16-bit (and 8-bit) values, one nibble (\fB0x0 - 0xf\fP) is sufficient to express all useful left or right shifts.
310+
311+  Right: \fB#ff #03 SFT\fP evaluates to \fB0x1f\fP
312+  Left:  \fB#ff #20 SFT\fP evaluates to \fB0xfc\fP
313+  Both:  \fB#ff #23 SFT\fP evaluates to \fB0x7c\fP
314+
315+.SH SPECIAL INSTRUCTIONS
316+
317+These instructions do not accept all mode flags (some do not accept any).
318+
319+.SS BRK
320+
321+The break instruction is used to end a vector call and return control to the virtual machine.
322+
323+.SS JCI, JMI, and JSI
324+
325+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:
326+
327+ \fBJMI\fP ( -- )       jump to \fIaddr\fP unconditionally
328+ \fBJCI\fP ( bool^ -- ) jump to \fIaddr\fP if \fIbool\fP is non-zero
329+ \fBJSI\fP ( -- [pc*] ) jump to \fIaddr\fP saving the current address (\fIpc\fP) on the return stack
330+
331+(The instruction pointer will be moved forward 2 bytes, past the relative address.)
332+
333+These instructions are created by the assembler from special syntax:
334+
335+    \fB!dest\fP produces \fBJMI wx yz\fP
336+    \fB?dest\fP produces \fBJCI wx yz\fP
337+    \fBdest\fP  produces \fBJSI wx yz\fP (assuming \fBdest\fP is not a macro or reserved)
338+
339+.SS LIT, LIT2, LITr, and LIT2r
340+
341+Push a literal value on the stack.
342+
343+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:
344+
345+    \fBLIT\fP   ( -- wx^ )     push literal byte \fIwx\fP onto the \fBwst\fP
346+    \fBLITr\fP  ( -- [wx^] )   push literal byte \fIwx\fP onto the \fBrst\fP
347+    \fBLIT2\fP  ( -- wxyz* )   push literal short \fIwxyz\fP (2 bytes) onto the \fBwst\fP
348+    \fBLIT2r\fP ( -- [wxyz*] ) push literal short \fIwxyz\fP (2 bytes) onto the \fBrst\fP
349+
350+(The instruction pointer will be moved forward 1-2 bytes, past the literal data.)
351+
352+Literal values can be updated dynamically using store instructions:
353+
354+    #abcd ;x STA2
355+    ( later on... )
356+    LIT2 [ @x $2 ]
357+
358+.SH SEE ALSO
359+
360+  https://wiki.xxiivv.com/site/uxntal_opcodes.html      \fIUxntal Opcodes\fP
361+  https://wiki.xxiivv.com/site/uxntal_syntax.html       \fIUxntal Syntax\fP
362+  https://wiki.xxiivv.com/site/uxntal_modes.html        \fIUxntal Modes\fP
363+  https://wiki.xxiivv.com/site/uxntal_immediate.html    \fIImmediate opcodes\fP
364+  https://wiki.xxiivv.com/site/varvara.html             \fIVarvara\fP
+7, -2
 1@@ -5,6 +5,8 @@ EMU_src=${CLI_src} src/devices/screen.c src/devices/controller.c src/devices/mou
 2 RELEASE_flags=-DNDEBUG -O2 -g0 -s
 3 DEBUG_flags=-std=c89 -D_POSIX_C_SOURCE=199309L -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined
 4 
 5+PREFIX=${HOME}/.local
 6+
 7 .PHONY: all debug dest run test install uninstall format clean grab archive
 8 
 9 all: dest bin/uxnasm bin/uxncli bin/uxn11
10@@ -12,7 +14,7 @@ all: dest bin/uxnasm bin/uxncli bin/uxn11
11 dest:
12 	@ mkdir -p bin
13 run: all bin/uxnasm bin/uxncli bin/uxn11
14-	@ bin/uxn11 
15+	@ bin/uxn11
16 debug: bin/uxnasm-debug bin/uxncli-debug bin/uxn11-debug
17 	@ bin/uxncli-debug bin/opctest.rom
18 test: all
19@@ -20,7 +22,10 @@ test: all
20 	@ bin/uxnasm etc/opctest.tal bin/opctest.rom
21 	@ bin/uxncli bin/opctest.rom
22 install: all
23-	@ cp bin/uxn11 bin/uxnasm bin/uxncli ~/bin/
24+	@ mkdir -p ${PREFIX}/bin
25+	@ cp bin/uxn11 bin/uxnasm bin/uxncli ${PREFIX}/bin
26+	@ mkdir -p ${PREFIX}/share/man/man7
27+	@ cp doc/man/uxntal.7 ${PREFIX}/share/man/man7
28 uninstall:
29 	@ rm -f ~/bin/uxn11 ~/bin/uxnasm ~/bin/uxncli
30 format: