4 * Init6502 initialization
5 * d_6502 handle ".6502" directive
6 * m6502cg generate code for a 6502 mnemonic
7 * d_org handle 6502 section's ".org" directive
8 * m6502obj generate 6502 object file
16 #define UPSEG_SIZE 0x10010L /* size of 6502 code buffer, 64K+16bytes */
22 extern TOKEN *tok; /* -> current token */
23 extern int debug; /* >0, in debug mode (-x) */
24 extern int m6502; /* 1, in 6502 mode */
25 extern TOKEN exprbuf[]; /* "universal" postfix expression buffer */
26 extern LONG lsloc; /* `sloc' at start of line */
27 extern unsigned orgactive; // RISC/6502 org directive active
28 extern unsigned orgaddr; // Org'd address
29 extern char * string[];
31 extern char extra_stuff[]; /* needed-eol error message */
32 extern char *range_error; /* value-out-of-range error message */
38 char in_6502mode[] = "directive illegal in .6502 section";
39 static uint16_t orgmap[1024][2]; /* mark all 6502 org changes */
40 uint16_t *currentorg = (uint16_t *)orgmap; /* current org range */
43 * 6502 addressing modes;
44 * do not change these values.
62 #define NMACHOPS 56 /* number of machine ops */
63 #define NMODES 14 /* number of addressing modes */
64 #define NOP 0xea /* 6502 NOP instruction */
65 #define ILLEGAL 0xff /* 'illegal instr' marker */
66 #define END65 0xff /* end-of-an-instr-list */
68 static char imodes[] =
70 A65_IMMED, 0x69, A65_ABS, 0x6d, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71,
71 A65_ZPX, 0x75, A65_ABSX, 0x7d, A65_ABSY, 0x79, END65,
72 A65_IMMED, 0x29, A65_ABS, 0x2d, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31,
73 A65_ZPX, 0x35, A65_ABSX, 0x3d, A65_ABSY, 0x39, END65,
74 A65_ABS, 0x0e, A65_ZP, 0x06, A65_IMPL, 0x0a, A65_ZPX, 0x16, A65_ABSX,
84 A65_ABS, 0x2c, A65_ZP, 0x24, END65,
85 A65_IMPL, 0x00, END65,
86 A65_IMPL, 0x18, END65,
87 A65_IMPL, 0xd8, END65,
88 A65_IMPL, 0x58, END65,
89 A65_IMPL, 0xb8, END65,
90 A65_IMMED, 0xc9, A65_ABS, 0xcd, A65_ZP, 0xc5, A65_INDX, 0xc1, A65_INDY, 0xd1,
91 A65_ZPX, 0xd5, A65_ABSX, 0xdd, A65_ABSY, 0xd9, END65,
92 A65_IMMED, 0xe0, A65_ABS, 0xec, A65_ZP, 0xe4, END65,
93 A65_IMMED, 0xc0, A65_ABS, 0xcc, A65_ZP, 0xc4, END65,
94 A65_ABS, 0xce, A65_ZP, 0xc6, A65_ZPX, 0xd6, A65_ABSX, 0xde, END65,
95 A65_IMPL, 0xca, END65,
96 A65_IMPL, 0x88, END65,
97 A65_IMMED, 0x49, A65_ABS, 0x4d, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51,
98 A65_ZPX, 0x55, A65_ABSX, 0x5d, A65_ABSY, 0x59, END65,
99 A65_ABS, 0xee, A65_ZP, 0xe6, A65_ZPX, 0xf6, A65_ABSX, 0xfe, END65,
100 A65_IMPL, 0xe8, END65,
101 A65_IMPL, 0xc8, END65,
102 A65_ABS, 0x4c, A65_IND, 0x6c, END65,
103 A65_ABS, 0x20, END65,
104 A65_IMMED, 0xa9, A65_ABS, 0xad, A65_ZP, 0xa5, A65_INDX, 0xa1, A65_INDY, 0xb1,
105 A65_ZPX, 0xb5, A65_ABSX, 0xbd, A65_ABSY, 0xb9, A65_IMMEDH, 0xa9, A65_IMMEDL, 0xa9, END65,
106 A65_IMMED, 0xa2, A65_ABS, 0xae, A65_ZP, 0xa6, A65_ABSY, 0xbe,
107 A65_ZPY, 0xb6, A65_IMMEDH, 0xa2, A65_IMMEDL, 0xa2, END65,
108 A65_IMMED, 0xa0, A65_ABS, 0xac, A65_ZP, 0xa4, A65_ZPX, 0xb4,
109 A65_ABSX, 0xbc, A65_IMMEDH, 0xa0, A65_IMMEDL, 0xa0, END65,
110 A65_ABS, 0x4e, A65_ZP, 0x46, A65_IMPL, 0x4a, A65_ZPX, 0x56,
111 A65_ABSX, 0x5e, END65,
112 A65_IMPL, 0xea, END65,
113 A65_IMMED, 0x09, A65_ABS, 0x0d, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11,
114 A65_ZPX, 0x15, A65_ABSX, 0x1d, A65_ABSY, 0x19, END65,
115 A65_IMPL, 0x48, END65,
116 A65_IMPL, 0x08, END65,
117 A65_IMPL, 0x68, END65,
118 A65_IMPL, 0x28, END65,
119 A65_ABS, 0x2e, A65_ZP, 0x26, A65_IMPL, 0x2a, A65_ZPX, 0x36,
120 A65_ABSX, 0x3e, END65,
121 A65_ABS, 0x6e, A65_ZP, 0x66, A65_IMPL, 0x6a, A65_ZPX, 0x76,
122 A65_ABSX, 0x7e, END65,
123 A65_IMPL, 0x40, END65,
124 A65_IMPL, 0x60, END65,
125 A65_IMMED, 0xe9, A65_ABS, 0xed, A65_ZP, 0xe5, A65_INDX, 0xe1, A65_INDY, 0xf1,
126 A65_ZPX, 0xf5, A65_ABSX, 0xfd, A65_ABSY, 0xf9, END65,
127 A65_IMPL, 0x38, END65,
128 A65_IMPL, 0xf8, END65,
129 A65_IMPL, 0x78, END65,
130 A65_ABS, 0x8d, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95,
131 A65_ABSX, 0x9d, A65_ABSY, 0x99, END65,
132 A65_ABS, 0x8e, A65_ZP, 0x86, A65_ZPY, 0x96, END65,
133 A65_ABS, 0x8c, A65_ZP, 0x84, A65_ZPX, 0x94, END65,
134 A65_IMPL, 0xaa, END65,
135 A65_IMPL, 0xa8, END65,
136 A65_IMPL, 0xba, END65,
137 A65_IMPL, 0x8a, END65,
138 A65_IMPL, 0x9a, END65,
139 A65_IMPL, 0x98, END65
142 static char ops[NMACHOPS][NMODES]; /* opcodes */
143 static unsigned char inf[NMACHOPS][NMODES]; /* construction info */
145 static int abs2zp[] =
146 { /* absolute-to-zeropage trans table */
163 * initialize 6502 assembler
174 /* set all instruction slots to illegal */
175 for (i = 0; i < NMACHOPS; ++i)
176 for (j = 0; j < NMODES; ++j)
179 /* uncompress legal instructions into their slots */
180 for (i = 0; i < NMACHOPS; ++i)
187 /* hack A65_REL mode */
190 inf[i][A65_ABS] = A65_REL;
191 ops[i][A65_ABS] = s[1];
192 inf[i][A65_ZP] = A65_REL;
193 ops[i][A65_ZP] = s[1];
195 } while(*(s += 2) != (char)END65);
199 /* set up first org section (set to zero) */
205 * .6502 --- enter 6502 mode
210 SaveSection(); /* save curent section */
211 SwitchSection(M6502); /* switch to 6502 section */
214 * Allocate and clear 64K of space for the 6502 section
217 memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE);
224 * Do 6502 code generation
229 register int amode; /* (parsed) addressing mode */
231 VALUE eval; /* expression value */
232 WORD eattr; /* expression attributes */
233 int zpreq; /* 1, optimize instr to zero-page form */
234 register char *p; /* (temp) string usage */
237 ch_size = 0; /* reset chunk size on every instruction */
240 * Parse 6502 addressing mode
255 if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
259 else if (*tok == '<')
262 if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
266 if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
272 if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
275 { /* (foo) or (foo),y */
280 if (*tok != SYMBOL ||
282 (*p | 0x20) != 'y') /* sleazo tolower() */
287 else amode = A65_IND;
289 else if (*tok == ',')
293 if (*tok != SYMBOL ||
295 (*p | 0x20) != 'x') /* sleazo tolower() */
307 if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
313 if (*tok != SYMBOL ||
319 i = (*p | 0x20); /* sleazo tolower */
325 tok += 3; /* past SYMBOL <string> ')' EOL */
326 zpreq = 1; /* request zeropage optimization */
328 else if (*tok == EOL)
341 if (*tok == SYMBOL &&
345 tok += 3; /* past: SYMBOL <string> ',' */
352 else goto not_coinop;
354 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
364 if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
369 else if (*tok == ',')
373 if (*tok != SYMBOL ||
379 * Check for X or Y index register;
380 * the OR with 0x20 is a sleazo conversion
381 * to lower-case that actually works.
383 i = *p | 0x20; /* oooh, this is slimey (but fast!) */
394 error("bad 6502 addressing mode");
399 * Optimize ABS modes to zero-page when possible
400 * o ZPX or ZPY is illegal, or
401 * o expr is zeropage && zeropageRequest && expression is defined
403 if (inf[op][amode] == ILLEGAL || /* if current op is illegal, or */
404 (eval < 0x100 && /* expr must be zero-page */
405 zpreq != 0 && /* amode must request zero-page opt. */
406 (eattr & DEFINED))) /* and the expression must be defined */
408 i = abs2zp[amode]; /* i = zero-page translation of amode */
410 DEBUG printf(" OPT: op=%d amode=%d i=%d inf[op][i]=%d\n",
411 op, amode, i, inf[op][i]);
414 (inf[op][i] & 0xff) != ILLEGAL) /* use it if it's legal */
419 DEBUG printf("6502: op=%d amode=%d ", op, amode);
420 DEBUG printf("inf[op][amode]=%d\n", (int)inf[op][amode]);
423 switch (inf[op][amode])
425 case A65_IMPL: /* just leave the instruction */
426 D_byte(ops[op][amode]);
430 D_byte(ops[op][amode]);
431 if (!(eattr & DEFINED))
433 AddFixup(FU_BYTEH, sloc, exprbuf);
436 eval = (eval >> 8) & 0xff; /* bring high byte to low */
437 D_byte(eval); /* deposit byte following instr */
441 D_byte(ops[op][amode]);
442 if (!(eattr & DEFINED))
444 AddFixup(FU_BYTEL, sloc, exprbuf);
447 eval = eval & 0xff; /* mask high byte */
448 D_byte(eval); /* deposit byte following instr */
457 D_byte(ops[op][amode]);
458 if (!(eattr & DEFINED))
460 AddFixup(FU_BYTE, sloc, exprbuf);
463 else if (eval + 0x100 >= 0x200)
468 D_byte(eval); /* deposit byte following instr */
472 D_byte(ops[op][amode]);
476 if (eval + 0x80 >= 0x100)
485 AddFixup(FU_6BRA, sloc, exprbuf);
494 D_byte(ops[op][amode]);
495 if (!(eattr & DEFINED))
497 AddFixup(FU_WORD, sloc, exprbuf);
504 * Deposit 3 NOPs for illegal things
508 for (i = 0; i < 3; ++i) {
511 error("illegal 6502 addressing mode");
515 * Check for overflow of code region
517 if (sloc > 0x10000L) fatal("6502 code pointer > 64K");
518 if (*tok != EOL) error(extra_stuff);
523 * Generate 6502 object output file.
526 // ggn: converted into a com/exe/xex output format
527 // Notes: 1. The $ffff is only mandatory for the first segment, but let's dump it everywhere for now
528 // 2. It's still dumping pages instead of more fine grained stuff. Should look into this - a8 people don't like waste so much ;)
534 uint16_t exeheader[3];
537 uint16_t *headpoint = (uint16_t *)exeheader;
540 * If no 6502 code was generated, forget it
542 if ((ch = sect[M6502].scode) == NULL ||
546 exeheader[0] = 0xffff; // mandatory for first segment
549 for (l = (uint16_t *)orgmap;l < currentorg;l+=2)
552 exeheader[2] = l[1]-1;
553 write(ofd, headpoint, headsize); // Write header
554 write(ofd, p + l[0], l[1] - l[0]);
555 headpoint = &exeheader[1]; // skip the $ffff after first segment, it's not mandatory