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