... | ... |
@@ -10,6 +10,10 @@ cc uxn.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o uxn |
10 | 10 |
|
11 | 11 |
## Assembly Syntax |
12 | 12 |
|
13 |
+- `:label`, a named offset |
|
14 |
+- `+literal`, a numeric value |
|
15 |
+- `.pointer`, pointer to a label |
|
16 |
+ |
|
13 | 17 |
``` |
14 | 18 |
< comment > |
15 | 19 |
|
... | ... |
@@ -30,31 +34,16 @@ $01 < pointer8 > |
30 | 34 |
:label ADD RTS |
31 | 35 |
``` |
32 | 36 |
|
33 |
-## Design |
|
34 |
- |
|
35 |
-### CPU |
|
36 |
- |
|
37 |
-- Build stack with pointer |
|
38 |
-- Print stack |
|
39 |
-- Build memory |
|
40 |
- |
|
41 |
-### PPU |
|
42 |
- |
|
43 |
-### Assembly |
|
44 |
- |
|
45 |
-#### Addressing |
|
46 |
- |
|
47 |
-- `label`, a named offset[TODO] |
|
48 |
-- `literal`, a numeric value |
|
49 |
-- `pointer`, pointer to an address[TODO] |
|
50 |
- |
|
51 |
-### Assembler |
|
52 |
- |
|
53 |
- |
|
54 |
-### Emulator |
|
55 |
- |
|
56 |
-- SDL Layer |
|
37 |
+## TODOs |
|
57 | 38 |
|
39 |
+- Implement addressing |
|
40 |
+- Implement 16 bits operations |
|
41 |
+- Jumps should be relative |
|
42 |
+- Catch overflow/underflow |
|
43 |
+- Implement literals like `[2]`, and `[ 2 3 ]`. |
|
44 |
+- Audo-detect literals length. |
|
45 |
+- SDL Layer Emulator |
|
46 |
+- Build PPU |
|
58 | 47 |
|
59 | 48 |
## Refs |
60 | 49 |
|
... | ... |
@@ -1,5 +1,18 @@ |
1 | 1 |
< comment > |
2 | 2 |
|
3 |
-[3 1 2 3 ] pop dup swp ovr rot |
|
3 |
+.deep JSR [4 6 7 8 9 ] BRK |
|
4 | 4 |
|
5 |
-brk |
|
5 |
+:deep |
|
6 |
+ [2 1 2 ] |
|
7 |
+ .deeper JSR |
|
8 |
+ RTS |
|
9 |
+ |
|
10 |
+:deeper |
|
11 |
+ [3 3 4 5 ] |
|
12 |
+ .deeperyet JSR |
|
13 |
+ RTS |
|
14 |
+ |
|
15 |
+:deeperyet |
|
16 |
+ [2 aa bb ] |
|
17 |
+ RTS |
|
18 |
+ |
|
6 | 19 |
\ No newline at end of file |
... | ... |
@@ -24,8 +24,9 @@ typedef struct { |
24 | 24 |
Uint8 literal; |
25 | 25 |
Uint8 status, counter; |
26 | 26 |
Uint8 memory[STACK_DEPTH]; |
27 |
- Uint8 mptr, sptr; |
|
27 |
+ Uint8 mptr, sptr, rsptr; |
|
28 | 28 |
Uint8 stack[STACK_DEPTH]; |
29 |
+ Uint8 rstack[STACK_DEPTH]; |
|
29 | 30 |
Uint8 address[STACK_DEPTH]; |
30 | 31 |
} Computer; |
31 | 32 |
|
... | ... |
@@ -61,20 +62,66 @@ echo(Uint8 *s, Uint8 len, char *name) |
61 | 62 |
printf("\n\n"); |
62 | 63 |
} |
63 | 64 |
|
64 |
-#pragma mark - Operations |
|
65 |
+void |
|
66 |
+spush(Uint8 v) |
|
67 |
+{ |
|
68 |
+ cpu.stack[cpu.sptr++] = v; |
|
69 |
+} |
|
70 |
+ |
|
71 |
+Uint8 |
|
72 |
+spop(void) |
|
73 |
+{ |
|
74 |
+ return cpu.stack[--cpu.sptr]; |
|
75 |
+} |
|
65 | 76 |
|
66 | 77 |
void |
67 |
-op_push(Uint8 *s, Uint8 *ptr, Uint8 v) |
|
78 |
+rspush(Uint8 v) |
|
68 | 79 |
{ |
69 |
- s[(*ptr)++] = v; |
|
80 |
+ cpu.rstack[cpu.rsptr++] = v; |
|
70 | 81 |
} |
71 | 82 |
|
72 | 83 |
Uint8 |
73 |
-op_pop(Uint8 *s, Uint8 *ptr) |
|
84 |
+rspop(void) |
|
74 | 85 |
{ |
75 |
- return s[--*ptr]; |
|
86 |
+ return cpu.rstack[--cpu.rsptr]; |
|
76 | 87 |
} |
77 | 88 |
|
89 |
+#pragma mark - Operations |
|
90 |
+ |
|
91 |
+/* clang-format off */ |
|
92 |
+ |
|
93 |
+void op_brk() { setflag(FLAG_HALT, 1); } |
|
94 |
+void op_lit() { cpu.literal += cpu.memory[cpu.mptr++]; } |
|
95 |
+void op_nop() { } |
|
96 |
+void op_drp() { spop(); } |
|
97 |
+void op_dup() { spush(cpu.stack[cpu.sptr - 1]); } |
|
98 |
+void op_swp() { Uint8 b = spop(), a = spop(); spush(b); spush(a); } |
|
99 |
+void op_ovr() { spush(cpu.stack[cpu.sptr - 2]); } |
|
100 |
+void op_rot() { Uint8 c = spop(),b = spop(),a = spop(); spush(b); spush(c); spush(a); } |
|
101 |
+void op_jmp() { cpu.mptr = spop(); } |
|
102 |
+void op_jsr() { rspush(cpu.mptr); cpu.mptr = spop(); } |
|
103 |
+void op_jeq() { if(getflag(FLAG_ZERO)) cpu.mptr = spop(); } |
|
104 |
+void op_rts() { cpu.mptr = rspop(); } |
|
105 |
+void op_equ() { setflag(FLAG_ZERO, spop() == spop()); } |
|
106 |
+void op_neq() { setflag(FLAG_ZERO, spop() != spop()); } |
|
107 |
+void op_lth() { setflag(FLAG_ZERO, spop() < spop()); } |
|
108 |
+void op_gth() { setflag(FLAG_ZERO, spop() > spop()); } |
|
109 |
+void op_and() { spush(spop() & spop()); } |
|
110 |
+void op_ora() { spush(spop() | spop()); } |
|
111 |
+void op_rol() { spush(spop() << 1); } |
|
112 |
+void op_ror() { spush(spop() >> 1); } |
|
113 |
+void op_add() { spush(spop() + spop()); } |
|
114 |
+void op_sub() { spush(spop() - spop()); } |
|
115 |
+void op_mul() { spush(spop() * spop()); } |
|
116 |
+void op_div() { spush(spop() / spop()); } |
|
117 |
+ |
|
118 |
+void (*ops[])(void) = { |
|
119 |
+ op_brk, op_lit, op_nop, op_drp, op_dup, op_swp, op_ovr, op_rot, |
|
120 |
+ op_jmp, op_jsr, op_jeq, op_rts, op_equ, op_neq, op_gth, op_lth, |
|
121 |
+ op_and, op_ora, op_rol, op_ror, op_add, op_sub, op_mul, op_div}; |
|
122 |
+ |
|
123 |
+/* clang-format on */ |
|
124 |
+ |
|
78 | 125 |
void |
79 | 126 |
reset(void) |
80 | 127 |
{ |
... | ... |
@@ -105,42 +152,13 @@ void |
105 | 152 |
eval() |
106 | 153 |
{ |
107 | 154 |
Uint8 instr = cpu.memory[cpu.mptr++]; |
108 |
- Uint8 a, b, c; |
|
109 | 155 |
if(cpu.literal > 0) { |
110 |
- printf("push: %02x[%d](%d)\n", instr, cpu.literal, cpu.sptr); |
|
111 |
- op_push(cpu.stack, &cpu.sptr, instr); |
|
156 |
+ spush(instr); |
|
112 | 157 |
cpu.literal--; |
113 | 158 |
return; |
114 | 159 |
} |
115 |
- switch(instr) { |
|
116 |
- case 0x0: setflag(FLAG_HALT, 1); break; |
|
117 |
- case 0x1: cpu.literal += cpu.memory[cpu.mptr++]; break; |
|
118 |
- case 0x2: printf("??\n"); break; |
|
119 |
- case 0x3: /* pop */ |
|
120 |
- op_pop(cpu.stack, &cpu.sptr); |
|
121 |
- break; |
|
122 |
- case 0x4: /* dup */ |
|
123 |
- op_push(cpu.stack, &cpu.sptr, cpu.stack[cpu.sptr - 1]); |
|
124 |
- break; |
|
125 |
- case 0x5: /* swp */ |
|
126 |
- b = op_pop(cpu.stack, &cpu.sptr); |
|
127 |
- a = op_pop(cpu.stack, &cpu.sptr); |
|
128 |
- op_push(cpu.stack, &cpu.sptr, b); |
|
129 |
- op_push(cpu.stack, &cpu.sptr, a); |
|
130 |
- break; |
|
131 |
- case 0x6: /* ovr */ |
|
132 |
- op_push(cpu.stack, &cpu.sptr, cpu.stack[cpu.sptr - 2]); |
|
133 |
- break; |
|
134 |
- case 0x7: /* rot */ |
|
135 |
- c = op_pop(cpu.stack, &cpu.sptr); |
|
136 |
- b = op_pop(cpu.stack, &cpu.sptr); |
|
137 |
- a = op_pop(cpu.stack, &cpu.sptr); |
|
138 |
- op_push(cpu.stack, &cpu.sptr, b); |
|
139 |
- op_push(cpu.stack, &cpu.sptr, c); |
|
140 |
- op_push(cpu.stack, &cpu.sptr, a); |
|
141 |
- break; |
|
142 |
- default: printf("Unknown instruction: #%02x\n", instr); |
|
143 |
- } |
|
160 |
+ if(instr < 24) |
|
161 |
+ (*ops[instr])(); |
|
144 | 162 |
} |
145 | 163 |
|
146 | 164 |
void |
... | ... |
@@ -12,6 +12,7 @@ WITH REGARD TO THIS SOFTWARE. |
12 | 12 |
*/ |
13 | 13 |
|
14 | 14 |
#define PRGLEN 256 |
15 |
+#define LABELIDLEN 32 |
|
15 | 16 |
|
16 | 17 |
typedef unsigned char Uint8; |
17 | 18 |
|
... | ... |
@@ -20,7 +21,13 @@ typedef struct { |
20 | 21 |
Uint8 data[PRGLEN]; |
21 | 22 |
} Program; |
22 | 23 |
|
23 |
-char labels[256][16]; |
|
24 |
+typedef struct { |
|
25 |
+ Uint8 addr; |
|
26 |
+ char name[LABELIDLEN]; |
|
27 |
+} Label; |
|
28 |
+ |
|
29 |
+int labelslen; |
|
30 |
+Label labels[256]; |
|
24 | 31 |
|
25 | 32 |
char opcodes[][4] = { |
26 | 33 |
"BRK", |
... | ... |
@@ -40,6 +47,14 @@ char opcodes[][4] = { |
40 | 47 |
"NEQ", |
41 | 48 |
"LTH", |
42 | 49 |
"GTH", |
50 |
+ "---", |
|
51 |
+ "---", |
|
52 |
+ "---", |
|
53 |
+ "---", |
|
54 |
+ "ADD", |
|
55 |
+ "SUB", |
|
56 |
+ "MUL", |
|
57 |
+ "DIV" |
|
43 | 58 |
/* */}; |
44 | 59 |
|
45 | 60 |
Program p; |
... | ... |
@@ -56,6 +71,16 @@ scmp(char *a, char *b) /* string compare */ |
56 | 71 |
return 0; |
57 | 72 |
} |
58 | 73 |
|
74 |
+char * |
|
75 |
+scpy(char *src, char *dst, int len) /* string copy */ |
|
76 |
+{ |
|
77 |
+ int i = 0; |
|
78 |
+ while((dst[i] = src[i]) && i < len - 2) |
|
79 |
+ i++; |
|
80 |
+ dst[i + 1] = '\0'; |
|
81 |
+ return dst; |
|
82 |
+} |
|
83 |
+ |
|
59 | 84 |
char * |
60 | 85 |
suca(char *s) /* string to uppercase */ |
61 | 86 |
{ |
... | ... |
@@ -72,7 +97,7 @@ sihx(char *s) |
72 | 97 |
int i = 0; |
73 | 98 |
char c; |
74 | 99 |
while((c = s[i++])) |
75 |
- if(!(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'F')) |
|
100 |
+ if(!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) |
|
76 | 101 |
return 0; |
77 | 102 |
return 1; |
78 | 103 |
} |
... | ... |
@@ -87,6 +112,8 @@ shex(char *s) /* string to num */ |
87 | 112 |
n = n * 16 + (c - '0'); |
88 | 113 |
else if(c >= 'A' && c <= 'F') |
89 | 114 |
n = n * 16 + 10 + (c - 'A'); |
115 |
+ else if(c >= 'a' && c <= 'f') |
|
116 |
+ n = n * 16 + 10 + (c - 'f'); |
|
90 | 117 |
return n; |
91 | 118 |
} |
92 | 119 |
|
... | ... |
@@ -101,7 +128,10 @@ addprg(Uint8 hex) |
101 | 128 |
void |
102 | 129 |
addlabel(char *id, Uint8 addr) |
103 | 130 |
{ |
104 |
- printf("new label: %s=%02x\n", id, addr); |
|
131 |
+ Label *l = &labels[labelslen++]; |
|
132 |
+ scpy(suca(id), l->name, LABELIDLEN); |
|
133 |
+ l->addr = addr; |
|
134 |
+ printf("new label: %s=%02x\n", l->name, l->addr); |
|
105 | 135 |
} |
106 | 136 |
|
107 | 137 |
void |
... | ... |
@@ -110,16 +140,39 @@ addconst(char *id, Uint8 value) |
110 | 140 |
printf("new const: %s=%02x\n", id, value); |
111 | 141 |
} |
112 | 142 |
|
143 |
+Label * |
|
144 |
+findlabel(char *s) |
|
145 |
+{ |
|
146 |
+ int i; |
|
147 |
+ for(i = 0; i < labelslen; ++i) |
|
148 |
+ if(scmp(labels[i].name, s)) |
|
149 |
+ return &labels[i]; |
|
150 |
+ return NULL; |
|
151 |
+} |
|
152 |
+ |
|
113 | 153 |
Uint8 |
114 | 154 |
findop(char *s) |
115 | 155 |
{ |
116 | 156 |
int i; |
117 |
- for(i = 0; i < 16; ++i) |
|
157 |
+ for(i = 0; i < 24; ++i) |
|
118 | 158 |
if(scmp(opcodes[i], s)) |
119 | 159 |
return i; |
120 | 160 |
return 0; |
121 | 161 |
} |
122 | 162 |
|
163 |
+int |
|
164 |
+getlength(char *w) |
|
165 |
+{ |
|
166 |
+ if(findop(w) || scmp(w, "BRK")) return 1; |
|
167 |
+ if(w[0] == '.') return 3; |
|
168 |
+ if(w[0] == ':') return 0; |
|
169 |
+ if(w[0] == '[') return 2; |
|
170 |
+ if(sihx(w)) return 1; |
|
171 |
+ if(w[0] == ']') return 0; |
|
172 |
+ printf("Unknown length %s\n", w); |
|
173 |
+ return 0; |
|
174 |
+} |
|
175 |
+ |
|
123 | 176 |
int |
124 | 177 |
comment(char *w, int *skip) |
125 | 178 |
{ |
... | ... |
@@ -136,10 +189,12 @@ void |
136 | 189 |
pass1(FILE *f) |
137 | 190 |
{ |
138 | 191 |
int skip = 0; |
192 |
+ int addr = 0; |
|
139 | 193 |
char word[64]; |
140 | 194 |
while(fscanf(f, "%s", word) == 1) { |
141 |
- if(comment(word, &skip)) |
|
142 |
- continue; |
|
195 |
+ if(comment(word, &skip)) continue; |
|
196 |
+ if(word[0] == ':') addlabel(word + 1, addr); |
|
197 |
+ addr += getlength(word); |
|
143 | 198 |
} |
144 | 199 |
rewind(f); |
145 | 200 |
} |
... | ... |
@@ -151,6 +206,8 @@ pass2(FILE *f) |
151 | 206 |
char word[64]; |
152 | 207 |
while(fscanf(f, "%s", word) == 1) { |
153 | 208 |
Uint8 op; |
209 |
+ Label *l; |
|
210 |
+ if(word[0] == ':') continue; |
|
154 | 211 |
suca(word); |
155 | 212 |
if(comment(word, &skip)) continue; |
156 | 213 |
if(word[0] == ']') continue; |
... | ... |
@@ -167,7 +224,11 @@ pass2(FILE *f) |
167 | 224 |
addprg(shex(word)); |
168 | 225 |
else if(scmp(word, "BRK")) |
169 | 226 |
addprg(0x00); |
170 |
- else |
|
227 |
+ else if((l = findlabel(word + 1))) { |
|
228 |
+ addprg(0x01); |
|
229 |
+ addprg(1); |
|
230 |
+ addprg(l->addr); |
|
231 |
+ } else |
|
171 | 232 |
printf("unknown: %s\n", word); |
172 | 233 |
} |
173 | 234 |
} |