blob: 61ad6bd49ff2dacdcad30ebbdb8be37f3309e30a [file] [log] [blame]
swissChili97b5d8b2020-08-15 20:00:54 -07001#include "as.h"
2#include "../cpu.h"
3#include "../instructions.h"
4#include "../mnemonics.h"
5
6#include <collect/map.h>
7#include <collect/vector.h>
8#include <string.h>
9#include <ctype.h>
10#include <stdbool.h>
11
12enum
13{
14 ARG_16, /* Absolute 16 bit argument */
15 ARG_8, /* Absolute 8 bit argument */
16 ARG_8REL, /* Relative 8 bit argument */
17 ARG_REL, /* Relative label */
18 ARG_ABS, /* Absolute label */
19 ARG_IMP, /* Implied argument */
20};
21
22typedef struct
23{
24 uint8_t opcode;
25 uint8_t arg_type;
26 union
27 {
28 char label[32];
29 uint16_t long_arg;
30 uint8_t byte_arg;
31 int8_t rel_arg;
32 };
33} inst_t;
34
35void print_inst(inst_t *arg)
36{
37 char *arg_types =
38 "16 8 8RELREL ABS IMP ";
39
40 printf("\033[33mInst: %.4s $%x ", arg_types + arg->arg_type * 4, arg->opcode);
41
42 switch (arg->arg_type)
43 {
44 case ARG_16:
45 printf("%x", arg->long_arg);
46 break;
47 case ARG_8:
48 printf("%x", arg->byte_arg);
49 break;
50 case ARG_8REL:
51 printf("%d", arg->rel_arg);
52 break;
53 case ARG_REL:
54 case ARG_ABS:
55 printf("%s", arg->label);
56 break;
57 }
58
59 printf("\033[0m\n");
60}
61
62bool is_ident(char c)
63{
64 return c && (isalpha(c) || isdigit(c));
65}
66
67uint32_t skip_ws(char **code)
68{
69 uint32_t len = 0;
70
71 for (; isspace(**code); (*code)++, len++)
72 {}
73
74 return len;
75}
76
77uint32_t skip_to_eol(char **code)
78{
79 uint32_t len = 0;
80
81 for (; **code && **code != '\n'; (*code)++, len++)
82 {}
83
84 if (**code)
85 (*code)++;
86
87 return len;
88}
89
90char *parse_label_name(char **code)
91{
92 char *start = *code;
93 for (; is_ident(**code); (*code)++)
94 {}
95
96 if (start == *code)
97 return false;
98
99 **code = 0;
100 return start;
101}
102
103char *parse_label(char **code)
104{
105 char *start = *code;
106
107 for (; is_ident(**code); (*code)++)
108 {}
109
110 skip_ws(code);
111
112 if (**code == ':')
113 {
114 **code = 0;
115 (*code)++;
116 return start;
117 }
118
119 *code = start;
120
121 return NULL;
122}
123
124char *parse_inst(char **code)
125{
126 char *start = *code;
127
128 for (; isalpha(**code); (*code)++)
129 {}
130
131 **code = 0;
132
133 if (start == *code)
134 return NULL;
135
136 (*code)++;
137 return start;
138}
139
140bool is_eol(char c)
141{
142 return c == ';' ||
143 c == '\n' ||
144 c == '\r' ||
145 c == '\0';
146}
147
148bool skip(char **code, const char *p)
149{
150 for (; *p && *p == **code; p++, (*code)++)
151 {}
152
153 if (!*p)
154 return true;
155 return false;
156}
157
158bool parse_num(char **code, uint64_t *num)
159{
160 char *start = *code;
161 int base = 10;
162 if (**code == '$')
163 {
164 base = 16;
165 (*code)++;
166 }
167
168 skip_ws(code);
169
170 char *endptr = *code;
171 int64_t val = strtol(*code, &endptr, base);
172
173 if (*code == endptr)
174 {
175 *code = start;
176 return false;
177 }
178 *num = val;
179 *code = endptr;
180 return true;
181}
182
183bool parse_num_max(char **code, uint64_t *num, uint64_t max)
184{
185 uint64_t n;
186 if (parse_num(code, &n))
187 {
188 if (n > max)
189 return false;
190
191 *num = n;
192 return true;
193 }
194 else return false;
195}
196
197bool parse_u8(char **code, uint8_t *num)
198{
199 uint64_t n;
200 if (!parse_num_max(code, &n, 0xFF))
201 return false;
202
203 *num = n & 0xFF;
204 return true;
205}
206
207bool parse_u16(char **code, uint16_t *num)
208{
209 uint64_t n;
210 if (!parse_num_max(code, &n, 0xFFFF))
211 return false;
212
213 *num = n & 0xFFFF;
214 return true;
215}
216
217bool ws_end(char **code)
218{
219 skip_ws(code);
220 return is_eol(**code);
221}
222
223bool parse_arg(char *code, int am, inst_t *inst)
224{
225 skip_ws(&code);
226
227 uint16_t num;
228 uint8_t num8;
229 char *lbl;
230
231 switch (am)
232 {
233 case AM_ACC:
234 case AM_IMP:
235 printf("Trying AM_IMP on '%.8s'\n", code);
236 skip_ws(&code);
237 if (is_eol(*code))
238 {
239 inst->arg_type = ARG_IMP;
240 return ws_end(&code);
241 }
242 break;
243
244 case AM_IMM:
245 printf("Trying AM_IMM on '%.8s'\n", code);
246 if (!skip(&code, "#"))
247 return false;
248 skip_ws(&code);
249 case AM_ZP:
250 if (parse_u8(&code, &num8))
251 {
252 inst->arg_type = ARG_8;
253 inst->byte_arg = num8;
254
255 return ws_end(&code);
256 }
257 break;
258
259 case AM_ABS:
260 if (parse_u16(&code, &num))
261 {
262 inst->arg_type = ARG_16;
263 inst->long_arg = num;
264 return true;
265 }
266 else if ((lbl = parse_label_name(&code)))
267 {
268 inst->arg_type = ARG_ABS;
269 strncpy(inst->label, lbl, 32);
270 return true;
271 }
272 break;
273
274 case AM_REL:
275 if (parse_u8(&code, &num8))
276 {
277 inst->arg_type = ARG_8REL;
278 inst->rel_arg = num;
279 return ws_end(&code);
280 }
281 else if ((lbl = parse_label_name(&code)))
282 {
283 inst->arg_type = ARG_REL;
284 strncpy(inst->label, lbl, 32);
285 return ws_end(&code);
286 }
287 break;
288
289 case AM_IND:
290 if (!skip(&code,"("))
291 return false;
292
293 if (!parse_u16(&code, &num))
294 return false;
295
296 if (!skip(&code, ")"))
297 return false;
298
299 inst->arg_type = ARG_16;
300 inst->long_arg = num;
301 return true;
302
303 case AM_AX:
304 case AM_ZPX:
305 case AM_AY:
306 case AM_ZPY:
307 if (am == AM_AX || am == AM_AY)
308 {
309 if (!parse_u16(&code, &num))
310 return false;
311 inst->arg_type = ARG_16;
312 inst->long_arg = num;
313 }
314 else
315 {
316 if (!parse_u8(&code, &num8))
317 return false;
318 inst->arg_type = ARG_8;
319 inst->byte_arg = num8;
320 }
321 if (!skip(&code, ","))
322 return false;
323
324 skip_ws(&code);
325
326 if (tolower(*code) != (am == AM_AY || am == AM_ZPY ? 'y' : 'x'))
327 return false;
328
329 return ws_end(&code);
330
331 case AM_ZIX:
332 if (!skip(&code, "("))
333 break;
334 skip_ws(&code);
335 if (!parse_u8(&code, &num8))
336 break;
337 skip_ws(&code);
338 if (!skip(&code, ","))
339 break;
340 skip_ws(&code);
341 if (tolower(*code) != 'x')
342 return false;
343 skip_ws(&code);
344
345 if (!skip(&code, ")"))
346 break;
347
348 inst->arg_type = ARG_8;
349 inst->byte_arg = num8;
350 return ws_end(&code);
351
352 case AM_ZIY:
353 if (!skip(&code, "("))
354 break;
355 skip_ws(&code);
356 if (!parse_u8(&code, &num8))
357 break;
358 skip_ws(&code);
359 if (!skip(&code, ")"))
360 break;
361 skip_ws(&code);
362 if (!skip(&code, ","))
363 break;
364 skip_ws(&code);
365 if (tolower(*code) != 'x')
366 break;
367
368 inst->arg_type = ARG_8;
369 inst->byte_arg = num8;
370 return ws_end(&code);
371 }
372 return false;
373}
374
375uint32_t assemble(char *code, FILE *out)
376{
377 uintptr_t num_insts = 0;
378 uint32_t line_no = 1;
379 map *labels = new_map();
380 vector *insts = new_vector();
381 char *line;
382
383 printf("Assembling File\n");
384 printf("%s\n", code);
385
386 line = strtok(code, "\r\n");
387
388 while (line)
389 {
390 skip_ws(&line);
391
392 printf("\033[36m%.9s\033[0m\n", line);
393
394 char *label = parse_label(&line),
395 *mn = parse_inst(&line);
396 int32_t mnemonic = -1;
397
398 if (label)
399 {
400 map_set(labels, label, (void *)num_insts);
401 printf("Set label %s at %lu\n", label, num_insts);
402 }
403
404 if (mn)
405 {
406#define MN(a) if (!strcasecmp(mn, #a)) \
407 mnemonic = a; \
408 else
409
410 MNEMONICS;
411#undef MN
412
413 printf("Got instruction %s %d\n", mn, mnemonic);
414
415 inst_t arg;
416 // printf("Parsing '%s'\n", line);
417#define INST(_mn, am, op, len) \
418 if (mnemonic == _mn && parse_arg(line, am, &arg)) \
419 { \
420 arg.opcode = op; \
421 print_inst(&arg); \
422 } \
423 else
424
425 INSTRUCTIONS
426 {
427 printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
428 }
429#undef INST
430 }
431
432 num_insts++;
433 line = strtok(NULL, "\r\n");
434 }
435
436 free_map(labels);
437
438 return num_insts;
439}