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,
167 // Initialize 6502 assembler
174 register char * s = imodes;
176 // Set all instruction slots to illegal
177 for(i=0; i<NMACHOPS; i++)
178 for(j=0; j<NMODES; j++)
181 // Uncompress legal instructions into their slots
182 for(i=0; i<NMACHOPS; i++)
190 /* hack A65_REL mode */
193 inf[i][A65_ABS] = A65_REL;
194 ops[i][A65_ABS] = s[1];
195 inf[i][A65_ZP] = A65_REL;
196 ops[i][A65_ZP] = s[1];
199 while (*(s += 2) != (char)END65);
204 // Set up first org section (set to zero)
207 SwitchSection(M6502); // Switch to 6502 section
209 // Initialise string conversion table(s)
210 char * p = a8internal;
211 memset(strtoa8, 31, 128); // 31=fallback value ("?")
213 for(; p<a8internal+sizeof(a8internal); p+=2)
214 strtoa8[p[0]] = p[1];
218 // Allocate and clear 64K of space for the 6502 section
220 memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE);
223 SwitchSection(TEXT); // Go back to TEXT
228 // .6502 --- enter 6502 mode
232 SaveSection(); // Save curent section
233 SwitchSection(M6502); // Switch to 6502 section
240 // Do 6502 code generation
244 register int amode; // (Parsed) addressing mode
246 VALUE eval; // Expression value
247 WORD eattr; // Expression attributes
248 int zpreq; // 1, optimize instr to zero-page form
249 register char * p; // (Temp) string usage
250 ch_size = 0; // Reset chunk size on every instruction
253 // Parse 6502 addressing mode
269 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
275 else if (*tok == '<')
278 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
285 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
294 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
306 if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'y') // Sleazo tolower()
315 else if (*tok == ',')
321 if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'x') // Sleazo tolower()
339 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
347 if (*tok != SYMBOL || p[1] != EOS || tok[2] != ')' || tok[3] != EOL)
350 i = (*p | 0x20); // Sleazo tolower()
359 tok += 3; // Past SYMBOL <string> ')' EOL
360 zpreq = 1; // Request zeropage optimization
362 else if (*tok == EOL)
376 // ggn: the following code is effectively disabled as it would make
377 // single letter labels not work correctly (would not identify the
378 // label properly). And from what I understand it's something to
379 // keep compatibility with the coinop assembler which is probably
380 // something we don't care about much :D
382 if (*tok == SYMBOL && p[1] == EOS && tok[2] == ',')
384 tok += 3; // Past: SYMBOL <string> ','
394 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
406 if (expr(exprbuf, &eval, &eattr, NULL) < 0)
413 else if (*tok == ',')
418 if (*tok != SYMBOL || p[1] != EOS)
424 // Check for X or Y index register;
425 // the OR with 0x20 is a sleazo conversion
426 // to lower-case that actually works.
428 i = *p | 0x20; // Oooh, this is slimey (but fast!)
443 error("bad 6502 addressing mode");
448 // Optimize ABS modes to zero-page when possible
449 // o ZPX or ZPY is illegal, or
450 // o expr is zeropage && zeropageRequest && expression is defined
452 if (inf[op][amode] == ILLEGAL // If current op is illegal,
453 || (eval < 0x100 // or expr must be zero-page
454 && zpreq != 0 // amode must request zero-page opt.
455 && (eattr & DEFINED))) // and the expression must be defined
457 i = abs2zp[amode]; // i = zero-page translation of amode
459 DEBUG printf(" OPT: op=%d amode=%d i=%d inf[op][i]=%d\n",
460 op, amode, i, inf[op][i]);
462 if (i >= 0 && (inf[op][i] & 0xFF) != ILLEGAL) // Use it if it's legal
467 DEBUG printf("6502: op=%d amode=%d ", op, amode);
468 DEBUG printf("inf[op][amode]=%d\n", (int)inf[op][amode]);
471 switch (inf[op][amode])
473 case A65_IMPL: // Just leave the instruction
474 D_byte(ops[op][amode]);
478 D_byte(ops[op][amode]);
480 if (!(eattr & DEFINED))
482 AddFixup(FU_BYTEH, sloc, exprbuf);
486 eval = (eval >> 8) & 0xFF; // Bring high byte to low
487 D_byte(eval); // Deposit byte following instr
491 D_byte(ops[op][amode]);
493 if (!(eattr & DEFINED))
495 AddFixup(FU_BYTEL, sloc, exprbuf);
499 eval = eval & 0xFF; // Mask high byte
500 D_byte(eval); // Deposit byte following instr
509 D_byte(ops[op][amode]);
511 if (!(eattr & DEFINED))
513 AddFixup(FU_BYTE, sloc, exprbuf);
516 else if (eval + 0x100 >= 0x200)
522 D_byte(eval); // Deposit byte following instr
526 D_byte(ops[op][amode]);
532 if (eval + 0x80 >= 0x100)
542 AddFixup(FU_6BRA, sloc, exprbuf);
552 D_byte(ops[op][amode]);
554 if (!(eattr & DEFINED))
556 AddFixup(FU_WORD, sloc, exprbuf);
564 // Deposit 3 NOPs for illegal things
571 error("illegal 6502 addressing mode");
574 // Check for overflow of code region
576 fatal("6502 code pointer > 64K");
584 // Generate 6502 object output file.
586 // ggn: converted into a com/exe/xex output format
587 void m6502obj(int ofd)
589 uint16_t exeheader[3];
591 uint16_t * headpoint = exeheader;
593 CHUNK * ch = sect[M6502].scode;
595 // If no 6502 code was generated, forget it
596 if ((ch == NULL) || (ch->challoc == 0))
599 exeheader[0] = 0xFFFF; // Mandatory for first segment
600 register uint8_t * p = ch->chptr;
602 for(uint16_t * l=&orgmap[0][0]; l<currentorg; l+=2)
605 exeheader[2] = l[1] - 1;
608 size_t unused = write(ofd, headpoint, headsize);
609 unused = write(ofd, p + l[0], l[1] - l[0]);
611 // Skip the $FFFF after first segment, it's not mandatory
612 headpoint = &exeheader[1];