commit e8a5ebb

zzo38  ·  2022-11-06 18:52:35 +0000 UTC
parent 19db03d
Add documentation for the assembler. Also change some of the limits in the assembler into macros.
3 files changed,  +184, -9
+170, -0
  1@@ -0,0 +1,170 @@
  2+This document describes the Uxn assembler, including the nonstandard
  3+extensions of the implementation included in this repository.
  4+
  5+Specify two or three command-line arguments:
  6+
  7+* Input file name (you can specify /dev/stdin to read from stdin).
  8+
  9+* Output file name (you can specify /dev/stdout to write to stdout, or you
 10+can specify /dev/null to discard the output).
 11+
 12+* Name output file name (you can specify /dev/stdout to write to stdout).
 13+This is optional, and if specified, then it will write a list of labels
 14+(including unused labels too) and their addresses to this file. (This is a
 15+nonstandard feature.)
 16+
 17+
 18+=== Tokens ===
 19+
 20+A token consists of a sequence of one or more non-whitespace characters
 21+(you can have whitespace characters to separate them). The maximum length
 22+of each token is sixty-three characters.
 23+
 24+All numbers must be lowercase hexadecimal, and normally must be either two
 25+or four hex digits.
 26+
 27+The following standard tokens are available:
 28+
 29+ ( which begins a block comment; all further tokens up to ) are ignored.
 30+ Comments can be nested.
 31+
 32+ [ or ] has no meaning. Anything inside this block is still assembled as
 33+ though the [ and ] commands are not present.
 34+
 35+ ~ and a file name will include that file as a source file.
 36+
 37+ % and a macro name will define a macro; you will need tokens { and }
 38+ around the definition of the macro.
 39+
 40+ The name of a previously defined macro without % in front will call that
 41+ macro, as though its definition is substituted in its place.
 42+
 43+ | and a number will set the current address to that number. Any address
 44+ is possible, but you cannot assemble anything in the zero page nor can
 45+ anything be assembled out of order, although you can skip any space.
 46+
 47+ $ and a number will advance the address by that number. (The padding will
 48+ be all zeros if not filled in.)
 49+
 50+ @ and a name will make a label with that name.
 51+
 52+ & and a name will make a label whose name is the same as the most recent
 53+ @ command and then / and then the name specified by the & command.
 54+
 55+ # and a number will make a LIT or LIT2 opcode with the specified number
 56+ (the number of hex digits determines which opcode).
 57+
 58+ A number without # is similar but the opcode is omitted, so raw data is
 59+ emitted instead.
 60+
 61+ . and a name will make a LIT opcode whose value is the low 8-bits of the
 62+ address of the specified name.
 63+
 64+ , and a name will make a LIT opcode whose value is a signed 8-bit value
 65+ which is a relative offset of the address of the specified name; this
 66+ should be used immediately preceding a JMP, JSR, or JCN instruction.
 67+
 68+ ; and a name will make a LIT2 opcode whose value is the address of the
 69+ specified name.
 70+
 71+ : and a name will write the 16-bit address of the specified name directly,
 72+ without any opcode.
 73+
 74+ " and any characters (other than whitespaces) will emit that sequence of
 75+ characters without any opcodes or delimiters. (If you need spaces, then
 76+ you must use separate tokens such as 20 for spaces.)
 77+
 78+ An instruction opcode consists of three uppercase letters, optionally
 79+ followed by any combination of instruction flags which can be "2" for
 80+ 16-bit operands, "r" to work with the other stack, and/or "k" to keep
 81+ the input operands in the stack.
 82+
 83+The following nonstandard tokens are available:
 84+
 85+ \\ begins a line comment, which ends at the next line break.
 86+
 87+ \~ and a file name will include the contents of the binary file.
 88+
 89+ \ and a number pushes the number to the special stack (which is a stack
 90+ which exists only at compile-time).
 91+
 92+ \: and a name will push the address of the name to the special stack.
 93+
 94+ \@ and a name will pop an address from the special stack and define a
 95+ label whose address is the address which has been popped in this way.
 96+
 97+ \_ and further text is a special calculation; see the below section
 98+ about special calculations. These are executed immediately at compile
 99+ time, before the compiled program is written to the output file.
100+
101+For the . ,  : ; commands, the name can optionally start with & to mean
102+that it is interpreted the same as for a & command.
103+
104+
105+=== Special calculations ===
106+
107+Each instruction is a single character.
108+
109+Numbers 0 to 9 push that number to the special stack.
110+
111+_  ( -- )  Set loop point (currently not used for anything).
112+
113+!  ( x -- )  Set current address.
114+
115+@  ( -- x )  Get current address.
116+
117+#  ( x -- )  Set current length. (This length includes the zero page,
118+even though the zero page is not written to the output file.)
119+
120+$  ( -- x )  Get current length.
121+
122++  ( x y -- z )  Addition x+y.
123+
124+-  ( x y -- z )  Subtraction x-y.
125+
126+*  ( x y -- z )  Multiplication x*y.
127+
128+/  ( x y -- z )  Division x/y.
129+
130+%  ( x y -- z )  Modulo x&y.
131+
132+&  ( x y -- z )  Bitwise AND.
133+
134+|  ( x y -- z )  Bitwise OR.
135+
136+^  ( x y -- z )  Bitwise XOR.
137+
138+:  ( x -- x x )  Duplicate.
139+
140+,  ( x y -- y x )  Swap.
141+
142+.  ( x -- )  Discard.
143+
144+g  ( address -- value )  Read 8-bits from memory.
145+
146+G  ( address -- value )  Read 16-bits from memory.
147+
148+p  ( value address -- )  Write 8-bits to memory. You can write anywhere
149+including the zero page and can also overwrite memory that has already
150+been written. Anything written to the zero page can be read back by other
151+special calculations but will not be written to the output file; anything
152+written outside of the zero page is written to the output file too.
153+
154+P  ( value address -- )  Write 16-bits to memory.
155+
156+w  ( value -- )  Write 8-bits at the current address and advance. You
157+cannot write in the zero page or overwrite what is already written.
158+
159+W  ( value -- )  Write 16-bits at the current address and advance. You
160+cannot write in the zero page or overwrite what is already written.
161+
162+
163+=== Name output format ===
164+
165+The name output format has each record on a line by itself, and each
166+record will be like:   |xxxx @yyyy
167+
168+xxxx is four lowercase hex digits being the address of that label.
169+
170+yyyy is the name of that label.
171+
+1, -1
1@@ -71,7 +71,7 @@ but if 8-bits then it is a signed relative address.
2   Unconditional jump.
3 0D JCN ( cond8 addr! -- )
4   Jump if the condition is nonzero.
5-0E JSR ( addr -- <old_addr> )
6+0E JSR ( addr! -- <old_addr> )
7   Unconditional jump, but the address of the next instruction if it
8   would not jump is saved in the other stack.
9 0F STH ( a -- <a> )
+13, -8
 1@@ -16,6 +16,11 @@ version, although the person who modified it is not the person who is
 2 named in the above copyright notice.]
 3 */
 4 
 5+#define MAXLABELS 0x400
 6+#define MAXMACROS 0x100
 7+#define MAXREFS 0x800
 8+#define MAXITEMS 0x40
 9+
10 #define TRIM 0x0100
11 #define LENGTH 0x10000
12 
13@@ -24,7 +29,7 @@ typedef signed char Sint8;
14 typedef unsigned short Uint16;
15 
16 typedef struct {
17-	char name[0x40], items[0x40][0x40];
18+	char name[0x40], items[MAXITEMS][0x40];
19 	Uint8 len;
20 } Macro;
21 
22@@ -42,9 +47,9 @@ typedef struct {
23 	Uint8 data[LENGTH];
24 	unsigned int ptr, length;
25 	Uint16 llen, mlen, rlen;
26-	Label labels[0x400];
27-	Macro macros[0x100];
28-	Reference refs[0x800];
29+	Label labels[MAXLABELS];
30+	Macro macros[MAXMACROS];
31+	Reference refs[MAXREFS];
32 	char scope[0x40];
33 } Program;
34 
35@@ -143,7 +148,7 @@ makemacro(char *name, FILE *f)
36 		return error("Macro name is hex number", name);
37 	if(findopcode(name) || scmp(name, "BRK", 4) || !slen(name))
38 		return error("Macro name is invalid", name);
39-	if(p.mlen == 0x100)
40+	if(p.mlen == MAXMACROS)
41 		return error("Macros limit exceeded", name);
42 	m = &p.macros[p.mlen++];
43 	scpy(name, m->name, 0x40);
44@@ -152,7 +157,7 @@ makemacro(char *name, FILE *f)
45 		if(word[0] == '}') break;
46 		if(word[0] == '%' || line_comment)
47 			return error("Macro error", name);
48-		if(m->len >= 0x40)
49+		if(m->len >= MAXITEMS)
50 			return error("Macro size exceeded", name);
51 		scpy(word, m->items[m->len++], 0x40);
52 	}
53@@ -169,7 +174,7 @@ makelabel(char *name)
54 		return error("Label name is hex number", name);
55 	if(findopcode(name) || scmp(name, "BRK", 4) || !slen(name))
56 		return error("Label name is invalid", name);
57-	if(p.llen == 0x400)
58+	if(p.llen == MAXLABELS)
59 		return error("Labels limit exceeded", name);
60 	l = &p.labels[p.llen++];
61 	l->addr = p.ptr;
62@@ -183,7 +188,7 @@ makereference(char *scope, char *label, Uint16 addr)
63 {
64 	char subw[0x40], parent[0x40];
65 	Reference *r;
66-	if(p.rlen == 0x800)
67+	if(p.rlen == MAXREFS)
68 		return error("References limit exceeded", label);
69 	r = &p.refs[p.rlen++];
70 	if(label[1] == '&')