| ... | ... |
@@ -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 |
} |