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.
A
asm.doc
+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+
M
uxn.doc
+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> )
M
uxnasm.c
+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] == '&')