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
20 #define UPSEG_SIZE 0x10010L // size of 6502 code buffer, 64K+16bytes
23 static uint16_t orgmap[1024][2]; // Mark all 6502 org changes
26 const char in_6502mode[] = "directive illegal in .6502 section";
27 uint16_t * currentorg = &orgmap[0][0]; // Current org range
28 char strtoa8[128]; // ASCII to Atari 800 internal conversion table
31 // 6502 addressing modes;
32 // DO NOT CHANGE THESE VALUES.
49 #define NMACHOPS 56 // Number of machine ops
50 #define NMODES 14 // Number of addressing modes
51 #define NOP 0xEA // 6502 NOP instruction
52 #define ILLEGAL 0xFF // 'Illegal instr' marker
53 #define END65 0xFF // End-of-an-instr-list
55 static char imodes[] =
57 A65_IMMED, 0x69, A65_ABS, 0x6d, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71,
58 A65_ZPX, 0x75, A65_ABSX, 0x7d, A65_ABSY, 0x79, END65,
59 A65_IMMED, 0x29, A65_ABS, 0x2d, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31,
60 A65_ZPX, 0x35, A65_ABSX, 0x3d, A65_ABSY, 0x39, END65,
61 A65_ABS, 0x0e, A65_ZP, 0x06, A65_IMPL, 0x0a, A65_ZPX, 0x16, A65_ABSX,
71 A65_ABS, 0x2c, A65_ZP, 0x24, END65,
72 A65_IMPL, 0x00, END65,
73 A65_IMPL, 0x18, END65,
74 A65_IMPL, 0xd8, END65,
75 A65_IMPL, 0x58, END65,
76 A65_IMPL, 0xb8, END65,
77 A65_IMMED, 0xc9, A65_ABS, 0xcd, A65_ZP, 0xc5, A65_INDX, 0xc1, A65_INDY, 0xd1,
78 A65_ZPX, 0xd5, A65_ABSX, 0xdd, A65_ABSY, 0xd9, END65,
79 A65_IMMED, 0xe0, A65_ABS, 0xec, A65_ZP, 0xe4, END65,
80 A65_IMMED, 0xc0, A65_ABS, 0xcc, A65_ZP, 0xc4, END65,
81 A65_ABS, 0xce, A65_ZP, 0xc6, A65_ZPX, 0xd6, A65_ABSX, 0xde, END65,
82 A65_IMPL, 0xca, END65,
83 A65_IMPL, 0x88, END65,
84 A65_IMMED, 0x49, A65_ABS, 0x4d, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51,
85 A65_ZPX, 0x55, A65_ABSX, 0x5d, A65_ABSY, 0x59, END65,
86 A65_ABS, 0xee, A65_ZP, 0xe6, A65_ZPX, 0xf6, A65_ABSX, 0xfe, END65,
87 A65_IMPL, 0xe8, END65,
88 A65_IMPL, 0xc8, END65,
89 A65_ABS, 0x4c, A65_IND, 0x6c, END65,
91 A65_IMMED, 0xa9, A65_ABS, 0xad, A65_ZP, 0xa5, A65_INDX, 0xa1, A65_INDY, 0xb1,
92 A65_ZPX, 0xb5, A65_ABSX, 0xbd, A65_ABSY, 0xb9, A65_IMMEDH, 0xa9, A65_IMMEDL, 0xa9, END65,
93 A65_IMMED, 0xa2, A65_ABS, 0xae, A65_ZP, 0xa6, A65_ABSY, 0xbe,
94 A65_ZPY, 0xb6, A65_IMMEDH, 0xa2, A65_IMMEDL, 0xa2, END65,
95 A65_IMMED, 0xa0, A65_ABS, 0xac, A65_ZP, 0xa4, A65_ZPX, 0xb4,
96 A65_ABSX, 0xbc, A65_IMMEDH, 0xa0, A65_IMMEDL, 0xa0, END65,
97 A65_ABS, 0x4e, A65_ZP, 0x46, A65_IMPL, 0x4a, A65_ZPX, 0x56,
98 A65_ABSX, 0x5e, END65,
99 A65_IMPL, 0xea, END65,
100 A65_IMMED, 0x09, A65_ABS, 0x0d, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11,
101 A65_ZPX, 0x15, A65_ABSX, 0x1d, A65_ABSY, 0x19, END65,
102 A65_IMPL, 0x48, END65,
103 A65_IMPL, 0x08, END65,
104 A65_IMPL, 0x68, END65,
105 A65_IMPL, 0x28, END65,
106 A65_ABS, 0x2e, A65_ZP, 0x26, A65_IMPL, 0x2a, A65_ZPX, 0x36,
107 A65_ABSX, 0x3e, END65,
108 A65_ABS, 0x6e, A65_ZP, 0x66, A65_IMPL, 0x6a, A65_ZPX, 0x76,
109 A65_ABSX, 0x7e, END65,
110 A65_IMPL, 0x40, END65,
111 A65_IMPL, 0x60, END65,
112 A65_IMMED, 0xe9, A65_ABS, 0xed, A65_ZP, 0xe5, A65_INDX, 0xe1, A65_INDY, 0xf1,
113 A65_ZPX, 0xf5, A65_ABSX, 0xfd, A65_ABSY, 0xf9, END65,
114 A65_IMPL, 0x38, END65,
115 A65_IMPL, 0xf8, END65,
116 A65_IMPL, 0x78, END65,
117 A65_ABS, 0x8d, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95,
118 A65_ABSX, 0x9d, A65_ABSY, 0x99, END65,
119 A65_ABS, 0x8e, A65_ZP, 0x86, A65_ZPY, 0x96, END65,
120 A65_ABS, 0x8c, A65_ZP, 0x84, A65_ZPX, 0x94, END65,
121 A65_IMPL, 0xaa, END65,
122 A65_IMPL, 0xa8, END65,
123 A65_IMPL, 0xba, END65,
124 A65_IMPL, 0x8a, END65,
125 A65_IMPL, 0x9a, END65,
126 A65_IMPL, 0x98, END65
129 static char ops[NMACHOPS][NMODES]; // Opcodes
130 static unsigned char inf[NMACHOPS][NMODES]; // Construction info
132 // Absolute-to-zeropage translation table
133 static int abs2zp[] =
149 static char a8internal[] =
151 ' ', 0, '!', 1, '"', 2, '#', 3, '$', 4, '%', 5, '&', 6, '\'', 7,
152 '(', 8, ')', 9, '*', 10, '+', 11, ',', 12, '-', 13, '.', 14, '/', 15,
153 '0', 16, '1', 17, '2', 18, '3', 19, '4', 20, '5', 21, '6', 22, '7', 23,
154 '8', 24, '9', 25, ':', 26, ';', 27, '<', 28, '=', 29, '>', 30, '?', 31,
155 '@', 32, 'A', 33, 'B', 34, 'C', 35, 'D', 36, 'E', 37, 'F', 38, 'G', 39,
156 'H', 40, 'I', 41, 'J', 42, 'K', 43, 'L', 44, 'M', 45, 'N', 46, 'O', 47,
157 'P', 48, 'Q', 49, 'R', 50, 'S', 51, 'T', 52, 'U', 53, 'V', 54, 'W', 55,
158 'X', 56, 'Y', 57, 'Z', 58, '[', 59, '\\', 60, ']', 61, '^', 62, '_', 63,
159 'a', 97, 'b', 98, 'c', 99, 'd', 100, 'e', 101, 'f', 102, 'g', 103, 'h', 104,
160 'i', 105, 'j', 106, 'k', 107, 'l', 108, 'm', 109, 'n', 110, 'o', 111, 'p', 112,
161 'q', 113, 'r', 114, 's', 115, 't', 116, 'u', 117, 'v', 118, 'w', 119, 'x', 120,
166 // initialize 6502 assembler
173 register char * s = imodes;
175 // Set all instruction slots to illegal
176 for(i=0; i<NMACHOPS; i++)
177 for(j=0; j<NMODES; j++)
180 // Uncompress legal instructions into their slots
181 for(i=0; i<NMACHOPS; i++)
189 /* hack A65_REL mode */
192 inf[i][A65_ABS] = A65_REL;
193 ops[i][A65_ABS] = s[1];
194 inf[i][A65_ZP] = A65_REL;
195 ops[i][A65_ZP] = s[1];
198 while (*(s += 2) != (char)END65);
203 // Set up first org section (set to zero)
206 SwitchSection(M6502); // Switch to 6502 section
208 // Initialise string conversion table(s)
211 char *p = a8internal;
212 memset(strtoa8, 31, 128); // 31=fallback value ("?")
213 for (; p < a8internal + sizeof(a8internal); p += 2)
215 strtoa8[p[0]] = p[1];
219 // Allocate and clear 64K of space for the 6502 section
221 memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE);
223 SwitchSection(TEXT); // Go back to TEXT
227 // .6502 --- enter 6502 mode
231 SaveSection(); // Save curent section
232 SwitchSection(M6502); // Switch to 6502 section
239 // Do 6502 code generation
243 register int amode; // (Parsed) addressing mode
245 VALUE eval; // Expression value
246 WORD eattr; // Expression attributes
247 int zpreq; // 1, optimize instr to zero-page form
248 register char * p; // (Temp) string usage
249 ch_size = 0; // Reset chunk size on every instruction
252 // Parse 6502 addressing mode
268 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
274 else if (*tok == '<')
277 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
284 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
293 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
305 if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'y') // Sleazo tolower()
314 else if (*tok == ',')
320 if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'x') // Sleazo tolower()
338 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
346 if (*tok != SYMBOL || p[1] != EOS || tok[2] != ')' || tok[3] != EOL)
349 i = (*p | 0x20); // Sleazo tolower()
358 tok += 3; // Past SYMBOL <string> ')' EOL
359 zpreq = 1; // Request zeropage optimization
361 else if (*tok == EOL)
375 // ggn: the following code is effectively disabled as it would make
376 // single letter labels not work correctly (would not identify the
377 // label properly). And from what I understand it's something to
378 // keep compatibility with the coinop assembler which is probably
379 // something we don't care about much :D
381 if (*tok == SYMBOL && p[1] == EOS && tok[2] == ',')
383 tok += 3; // Past: SYMBOL <string> ','
393 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
405 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
412 else if (*tok == ',')
417 if (*tok != SYMBOL || p[1] != EOS)
423 // Check for X or Y index register;
424 // the OR with 0x20 is a sleazo conversion
425 // to lower-case that actually works.
427 i = *p | 0x20; // Oooh, this is slimey (but fast!)
442 error("bad 6502 addressing mode");
447 // Optimize ABS modes to zero-page when possible
448 // o ZPX or ZPY is illegal, or
449 // o expr is zeropage && zeropageRequest && expression is defined
451 if (inf[op][amode] == ILLEGAL // If current op is illegal,
452 || (eval < 0x100 // or expr must be zero-page
453 && zpreq != 0 // amode must request zero-page opt.
454 && (eattr & DEFINED))) // and the expression must be defined
456 i = abs2zp[amode]; // i = zero-page translation of amode
458 DEBUG printf(" OPT: op=%d amode=%d i=%d inf[op][i]=%d\n",
459 op, amode, i, inf[op][i]);
461 if (i >= 0 && (inf[op][i] & 0xFF) != ILLEGAL) // Use it if it's legal
466 DEBUG printf("6502: op=%d amode=%d ", op, amode);
467 DEBUG printf("inf[op][amode]=%d\n", (int)inf[op][amode]);
470 switch (inf[op][amode])
472 case A65_IMPL: // Just leave the instruction
473 D_byte(ops[op][amode]);
477 D_byte(ops[op][amode]);
479 if (!(eattr & DEFINED))
481 AddFixup(FU_BYTEH, sloc, exprbuf);
485 eval = (eval >> 8) & 0xFF; // Bring high byte to low
486 D_byte(eval); // Deposit byte following instr
490 D_byte(ops[op][amode]);
492 if (!(eattr & DEFINED))
494 AddFixup(FU_BYTEL, sloc, exprbuf);
498 eval = eval & 0xFF; // Mask high byte
499 D_byte(eval); // Deposit byte following instr
508 D_byte(ops[op][amode]);
510 if (!(eattr & DEFINED))
512 AddFixup(FU_BYTE, sloc, exprbuf);
515 else if (eval + 0x100 >= 0x200)
521 D_byte(eval); // Deposit byte following instr
525 D_byte(ops[op][amode]);
531 if (eval + 0x80 >= 0x100)
541 AddFixup(FU_6BRA, sloc, exprbuf);
551 D_byte(ops[op][amode]);
553 if (!(eattr & DEFINED))
555 AddFixup(FU_WORD, sloc, exprbuf);
563 // Deposit 3 NOPs for illegal things
570 error("illegal 6502 addressing mode");
573 // Check for overflow of code region
575 fatal("6502 code pointer > 64K");
583 // Generate 6502 object output file.
585 // ggn: converted into a com/exe/xex output format
586 void m6502obj(int ofd)
588 uint16_t exeheader[3];
590 uint16_t * headpoint = exeheader;
592 CHUNK * ch = sect[M6502].scode;
594 // If no 6502 code was generated, forget it
595 if ((ch == NULL) || (ch->challoc == 0))
598 exeheader[0] = 0xFFFF; // Mandatory for first segment
599 register uint8_t * p = ch->chptr;
601 for(uint16_t * l=&orgmap[0][0]; l<currentorg; l+=2)
604 exeheader[2] = l[1] - 1;
607 size_t unused = write(ofd, headpoint, headsize);
608 unused = write(ofd, p + l[0], l[1] - l[0]);
610 // Skip the $FFFF after first segment, it's not mandatory
611 headpoint = &exeheader[1];