X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=6502.c;h=4397b0748bf446531317d3413908c4c6afb9bae5;hp=0e203f098b5dadc6c0647b065a791fb933d5f244;hb=d62ea9ab9323ed83b9feb96bd1d7df21c1bf6a63;hpb=ff2052bcaa1428a33a202822a81a6f9b8e567ef4 diff --git a/6502.c b/6502.c index 0e203f0..4397b07 100644 --- a/6502.c +++ b/6502.c @@ -1,5 +1,9 @@ // -// 6502 Assembler +// RMAC - Reboot's Macro Assembler for all Atari computers +// 6502.C - 6502 Assembler +// Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends +// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 +// Source utilised with the kind permission of Landon Dyer // // Init6502 initialization // d_6502 handle ".6502" directive @@ -17,14 +21,18 @@ #include "sect.h" #include "token.h" +#define DEF_KW +#include "kwtab.h" + #define UPSEG_SIZE 0x10010L // size of 6502 code buffer, 64K+16bytes -// +// Internal vars +static uint16_t orgmap[1024][2]; // Mark all 6502 org changes + // Exported vars -// const char in_6502mode[] = "directive illegal in .6502 section"; -static uint16_t orgmap[1024][2]; // Mark all 6502 org changes uint16_t * currentorg = &orgmap[0][0]; // Current org range +char strtoa8[128]; // ASCII to Atari 800 internal conversion table // // 6502 addressing modes; @@ -45,83 +53,83 @@ uint16_t * currentorg = &orgmap[0][0]; // Current org range #define A65_IMMEDH 12 #define A65_IMMEDL 13 -#define NMACHOPS 56 // Number of machine ops -#define NMODES 14 // Number of addressing modes -#define NOP 0xEA // 6502 NOP instruction -#define ILLEGAL 0xFF // 'Illegal instr' marker -#define END65 0xFF // End-of-an-instr-list +#define NMACHOPS 56 // Number of machine ops +#define NMODES 14 // Number of addressing modes +#define NOP 0xEA // 6502 NOP instruction +#define ILLEGAL 0xFF // 'Illegal instr' marker +#define END65 0xFF // End-of-an-instr-list static char imodes[] = { - A65_IMMED, 0x69, A65_ABS, 0x6d, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71, - A65_ZPX, 0x75, A65_ABSX, 0x7d, A65_ABSY, 0x79, END65, - A65_IMMED, 0x29, A65_ABS, 0x2d, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31, - A65_ZPX, 0x35, A65_ABSX, 0x3d, A65_ABSY, 0x39, END65, - A65_ABS, 0x0e, A65_ZP, 0x06, A65_IMPL, 0x0a, A65_ZPX, 0x16, A65_ABSX, - 0x1e, END65, + A65_IMMED, 0x69, A65_ABS, 0x6D, A65_ZP, 0x65, A65_INDX, 0x61, A65_INDY, 0x71, + A65_ZPX, 0x75, A65_ABSX, 0x7D, A65_ABSY, 0x79, END65, + A65_IMMED, 0x29, A65_ABS, 0x2D, A65_ZP, 0x25, A65_INDX, 0x21, A65_INDY, 0x31, + A65_ZPX, 0x35, A65_ABSX, 0x3D, A65_ABSY, 0x39, END65, + A65_ABS, 0x0E, A65_ZP, 0x06, A65_IMPL, 0x0A, A65_ZPX, 0x16, A65_ABSX, + 0x1E, END65, A65_REL, 0x90, END65, - A65_REL, 0xb0, END65, - A65_REL, 0xf0, END65, - A65_REL, 0xd0, END65, + A65_REL, 0xB0, END65, + A65_REL, 0xF0, END65, + A65_REL, 0xD0, END65, A65_REL, 0x30, END65, A65_REL, 0x10, END65, A65_REL, 0x50, END65, A65_REL, 0x70, END65, - A65_ABS, 0x2c, A65_ZP, 0x24, END65, + A65_ABS, 0x2C, A65_ZP, 0x24, END65, A65_IMPL, 0x00, END65, A65_IMPL, 0x18, END65, - A65_IMPL, 0xd8, END65, + A65_IMPL, 0xD8, END65, A65_IMPL, 0x58, END65, - A65_IMPL, 0xb8, END65, - A65_IMMED, 0xc9, A65_ABS, 0xcd, A65_ZP, 0xc5, A65_INDX, 0xc1, A65_INDY, 0xd1, - A65_ZPX, 0xd5, A65_ABSX, 0xdd, A65_ABSY, 0xd9, END65, - A65_IMMED, 0xe0, A65_ABS, 0xec, A65_ZP, 0xe4, END65, - A65_IMMED, 0xc0, A65_ABS, 0xcc, A65_ZP, 0xc4, END65, - A65_ABS, 0xce, A65_ZP, 0xc6, A65_ZPX, 0xd6, A65_ABSX, 0xde, END65, - A65_IMPL, 0xca, END65, + A65_IMPL, 0xB8, END65, + A65_IMMED, 0xC9, A65_ABS, 0xCD, A65_ZP, 0xC5, A65_INDX, 0xC1, A65_INDY, 0xD1, + A65_ZPX, 0xD5, A65_ABSX, 0xDD, A65_ABSY, 0xD9, END65, + A65_IMMED, 0xE0, A65_ABS, 0xEC, A65_ZP, 0xE4, END65, + A65_IMMED, 0xC0, A65_ABS, 0xCC, A65_ZP, 0xC4, END65, + A65_ABS, 0xCE, A65_ZP, 0xC6, A65_ZPX, 0xD6, A65_ABSX, 0xDE, END65, + A65_IMPL, 0xCA, END65, A65_IMPL, 0x88, END65, - A65_IMMED, 0x49, A65_ABS, 0x4d, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51, - A65_ZPX, 0x55, A65_ABSX, 0x5d, A65_ABSY, 0x59, END65, - A65_ABS, 0xee, A65_ZP, 0xe6, A65_ZPX, 0xf6, A65_ABSX, 0xfe, END65, - A65_IMPL, 0xe8, END65, - A65_IMPL, 0xc8, END65, - A65_ABS, 0x4c, A65_IND, 0x6c, END65, + A65_IMMED, 0x49, A65_ABS, 0x4D, A65_ZP, 0x45, A65_INDX, 0x41, A65_INDY, 0x51, + A65_ZPX, 0x55, A65_ABSX, 0x5D, A65_ABSY, 0x59, END65, + A65_ABS, 0xEE, A65_ZP, 0xE6, A65_ZPX, 0xF6, A65_ABSX, 0xFE, END65, + A65_IMPL, 0xE8, END65, + A65_IMPL, 0xC8, END65, + A65_ABS, 0x4C, A65_IND, 0x6C, END65, A65_ABS, 0x20, END65, - A65_IMMED, 0xa9, A65_ABS, 0xad, A65_ZP, 0xa5, A65_INDX, 0xa1, A65_INDY, 0xb1, - A65_ZPX, 0xb5, A65_ABSX, 0xbd, A65_ABSY, 0xb9, A65_IMMEDH, 0xa9, A65_IMMEDL, 0xa9, END65, - A65_IMMED, 0xa2, A65_ABS, 0xae, A65_ZP, 0xa6, A65_ABSY, 0xbe, - A65_ZPY, 0xb6, A65_IMMEDH, 0xa2, A65_IMMEDL, 0xa2, END65, - A65_IMMED, 0xa0, A65_ABS, 0xac, A65_ZP, 0xa4, A65_ZPX, 0xb4, - A65_ABSX, 0xbc, A65_IMMEDH, 0xa0, A65_IMMEDL, 0xa0, END65, - A65_ABS, 0x4e, A65_ZP, 0x46, A65_IMPL, 0x4a, A65_ZPX, 0x56, - A65_ABSX, 0x5e, END65, - A65_IMPL, 0xea, END65, - A65_IMMED, 0x09, A65_ABS, 0x0d, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11, - A65_ZPX, 0x15, A65_ABSX, 0x1d, A65_ABSY, 0x19, END65, + A65_IMMED, 0xA9, A65_ABS, 0xAD, A65_ZP, 0xA5, A65_INDX, 0xA1, A65_INDY, 0xB1, + A65_ZPX, 0xB5, A65_ABSX, 0xBD, A65_ABSY, 0xB9, A65_IMMEDH, 0xA9, A65_IMMEDL, 0xA9, END65, + A65_IMMED, 0xA2, A65_ABS, 0xAE, A65_ZP, 0xA6, A65_ABSY, 0xBE, + A65_ZPY, 0xB6, A65_IMMEDH, 0xA2, A65_IMMEDL, 0xA2, END65, + A65_IMMED, 0xA0, A65_ABS, 0xAC, A65_ZP, 0xA4, A65_ZPX, 0xB4, + A65_ABSX, 0xBC, A65_IMMEDH, 0xA0, A65_IMMEDL, 0xA0, END65, + A65_ABS, 0x4E, A65_ZP, 0x46, A65_IMPL, 0x4A, A65_ZPX, 0x56, + A65_ABSX, 0x5E, END65, + A65_IMPL, 0xEA, END65, + A65_IMMED, 0x09, A65_ABS, 0x0D, A65_ZP, 0x05, A65_INDX, 0x01, A65_INDY, 0x11, + A65_ZPX, 0x15, A65_ABSX, 0x1D, A65_ABSY, 0x19, END65, A65_IMPL, 0x48, END65, A65_IMPL, 0x08, END65, A65_IMPL, 0x68, END65, A65_IMPL, 0x28, END65, - A65_ABS, 0x2e, A65_ZP, 0x26, A65_IMPL, 0x2a, A65_ZPX, 0x36, - A65_ABSX, 0x3e, END65, - A65_ABS, 0x6e, A65_ZP, 0x66, A65_IMPL, 0x6a, A65_ZPX, 0x76, - A65_ABSX, 0x7e, END65, + A65_ABS, 0x2E, A65_ZP, 0x26, A65_IMPL, 0x2A, A65_ZPX, 0x36, + A65_ABSX, 0x3E, END65, + A65_ABS, 0x6E, A65_ZP, 0x66, A65_IMPL, 0x6A, A65_ZPX, 0x76, + A65_ABSX, 0x7E, END65, A65_IMPL, 0x40, END65, A65_IMPL, 0x60, END65, - A65_IMMED, 0xe9, A65_ABS, 0xed, A65_ZP, 0xe5, A65_INDX, 0xe1, A65_INDY, 0xf1, - A65_ZPX, 0xf5, A65_ABSX, 0xfd, A65_ABSY, 0xf9, END65, + A65_IMMED, 0xE9, A65_ABS, 0xED, A65_ZP, 0xE5, A65_INDX, 0xE1, A65_INDY, 0xF1, + A65_ZPX, 0xF5, A65_ABSX, 0xFD, A65_ABSY, 0xF9, END65, A65_IMPL, 0x38, END65, - A65_IMPL, 0xf8, END65, + A65_IMPL, 0xF8, END65, A65_IMPL, 0x78, END65, - A65_ABS, 0x8d, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95, - A65_ABSX, 0x9d, A65_ABSY, 0x99, END65, - A65_ABS, 0x8e, A65_ZP, 0x86, A65_ZPY, 0x96, END65, - A65_ABS, 0x8c, A65_ZP, 0x84, A65_ZPX, 0x94, END65, - A65_IMPL, 0xaa, END65, - A65_IMPL, 0xa8, END65, - A65_IMPL, 0xba, END65, - A65_IMPL, 0x8a, END65, - A65_IMPL, 0x9a, END65, + A65_ABS, 0x8D, A65_ZP, 0x85, A65_INDX, 0x81, A65_INDY, 0x91, A65_ZPX, 0x95, + A65_ABSX, 0x9D, A65_ABSY, 0x99, END65, + A65_ABS, 0x8E, A65_ZP, 0x86, A65_ZPY, 0x96, END65, + A65_ABS, 0x8C, A65_ZP, 0x84, A65_ZPX, 0x94, END65, + A65_IMPL, 0xAA, END65, + A65_IMPL, 0xA8, END65, + A65_IMPL, 0xBA, END65, + A65_IMPL, 0x8A, END65, + A65_IMPL, 0x9A, END65, A65_IMPL, 0x98, END65 }; @@ -145,6 +153,22 @@ static int abs2zp[] = -1 // ZPY }; +static char a8internal[] = +{ + ' ', 0, '!', 1, '"', 2, '#', 3, '$', 4, '%', 5, '&', 6, '\'', 7, + '(', 8, ')', 9, '*', 10, '+', 11, ',', 12, '-', 13, '.', 14, '/', 15, + '0', 16, '1', 17, '2', 18, '3', 19, '4', 20, '5', 21, '6', 22, '7', 23, + '8', 24, '9', 25, ':', 26, ';', 27, '<', 28, '=', 29, '>', 30, '?', 31, + '@', 32, 'A', 33, 'B', 34, 'C', 35, 'D', 36, 'E', 37, 'F', 38, 'G', 39, + 'H', 40, 'I', 41, 'J', 42, 'K', 43, 'L', 44, 'M', 45, 'N', 46, 'O', 47, + 'P', 48, 'Q', 49, 'R', 50, 'S', 51, 'T', 52, 'U', 53, 'V', 54, 'W', 55, + 'X', 56, 'Y', 57, 'Z', 58, '[', 59, '\\', 60, ']', 61, '^', 62, '_', 63, + 'a', 97, 'b', 98, 'c', 99, 'd', 100, 'e', 101, 'f', 102, 'g', 103, 'h', 104, + 'i', 105, 'j', 106, 'k', 107, 'l', 108, 'm', 109, 'n', 110, 'o', 111, 'p', 112, + 'q', 113, 'r', 114, 's', 115, 't', 116, 'u', 117, 'v', 118, 'w', 119, 'x', 120, + 'y', 121, 'z', 122 +}; + // // Initialize 6502 assembler @@ -186,6 +210,24 @@ void Init6502() // Set up first org section (set to zero) orgmap[0][0] = 0; + + SwitchSection(M6502); // Switch to 6502 section + + // Initialise string conversion table(s) + char * p = a8internal; + memset(strtoa8, 31, 128); // 31=fallback value ("?") + + for(; pchptr, 0, UPSEG_SIZE); + } + + SwitchSection(TEXT); // Go back to TEXT } @@ -197,13 +239,6 @@ int d_6502() SaveSection(); // Save curent section SwitchSection(M6502); // Switch to 6502 section - if (challoc == 0) - { - // Allocate and clear 64K of space for the 6502 section - chcheck(UPSEG_SIZE); - memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE); - } - return 0; } @@ -214,50 +249,47 @@ int d_6502() void m6502cg(int op) { register int amode; // (Parsed) addressing mode - register int i; - VALUE eval; // Expression value - WORD eattr; // Expression attributes - int zpreq; // 1, optimize instr to zero-page form - register char * p; // (Temp) string usage + uint64_t eval = -1; // Expression value + WORD eattr = 0; // Expression attributes + int zpreq = 0; // 1 = optimize instr to zero-page form ch_size = 0; // Reset chunk size on every instruction // // Parse 6502 addressing mode // - zpreq = 0; - - switch ((int)*tok) + switch (tok[0]) { case EOL: amode = A65_IMPL; break; + case KW_A: + if (tok[1] != EOL) + goto badmode; + + tok++; + amode = A65_IMPL; + break; + case '#': tok++; if (*tok == '>') { tok++; - if (expr(exprbuf, &eval, &eattr, NULL) < 0) - return; - amode = A65_IMMEDH; - break; } else if (*tok == '<') { tok++; - if (expr(exprbuf, &eval, &eattr, NULL) < 0) - return; - amode = A65_IMMEDL; - break; } + else + amode = A65_IMMED; if (expr(exprbuf, &eval, &eattr, NULL) < 0) return; - amode = A65_IMMED; break; case '(': @@ -273,31 +305,20 @@ void m6502cg(int op) { // (foo),y tok++; - p = string[tok[1]]; + amode = A65_INDY; - if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'y') // Sleazo tolower() + if (tok[0] != KW_Y) goto badmode; - tok += 2; - amode = A65_INDY; + tok++; } else amode = A65_IND; } - else if (*tok == ',') + else if ((tok[0] == ',') && (tok[1] == KW_X) && (tok[2] == ')')) { // (foo,x) - tok++; - p = string[tok[1]]; - - if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'x') // Sleazo tolower() - goto badmode; - - tok += 2; - - if (*tok++ != ')') - goto badmode; - + tok += 3; amode = A65_INDX; } else @@ -305,6 +326,8 @@ void m6502cg(int op) break; + // I'm guessing that the form of this is @(X) or @(Y), which + // I've *never* seen before. :-/ case '@': tok++; @@ -314,21 +337,18 @@ void m6502cg(int op) if (*tok == '(') { tok++; - p = string[tok[1]]; - if (*tok != SYMBOL || p[1] != EOS || tok[2] != ')' || tok[3] != EOL) + if ((tok[1] != ')') || (tok[2] != EOL)) goto badmode; - i = (*p | 0x20); // Sleazo tolower() - - if (i == 'x') + if (tok[0] == KW_X) amode = A65_INDX; - else if (i == 'y') + else if (tok[0] == KW_Y) amode = A65_INDY; else goto badmode; - tok += 3; // Past SYMBOL ')' EOL + tok += 2; zpreq = 1; // Request zeropage optimization } else if (*tok == EOL) @@ -339,66 +359,30 @@ void m6502cg(int op) break; default: - // - // Short-circuit - // x,foo - // y,foo - // - p = string[tok[1]]; - - if (*tok == SYMBOL && p[1] == EOS && tok[2] == ',') - { - tok += 3; // Past: SYMBOL ',' - i = (*p | 0x20); - - if (i == 'x') - amode = A65_ABSX; - else if (i == 'y') - amode = A65_ABSY; - else - goto not_coinop; - - if (expr(exprbuf, &eval, &eattr, NULL) < 0) - return; - - if (*tok != EOL) - goto badmode; - - zpreq = 1; - break; - } - -not_coinop: + // + // ,x + // ,y if (expr(exprbuf, &eval, &eattr, NULL) < 0) return; - zpreq = 1; + zpreq = 1; // Request zeropage optimization - if (*tok == EOL) + if (tok[0] == EOL) amode = A65_ABS; - else if (*tok == ',') + else if (tok[0] == ',') { tok++; - p = string[tok[1]]; - - if (*tok != SYMBOL || p[1] != EOS) - goto badmode; - tok += 2; - - // - // Check for X or Y index register; - // the OR with 0x20 is a sleazo conversion - // to lower-case that actually works. - // - i = *p | 0x20; // Oooh, this is slimey (but fast!) - - if (i == 'x') + if (tok[0] == KW_X) + { + tok++; amode = A65_ABSX; - else if (i == 'y') + } + else if (tok[0] == KW_Y) + { + tok++; amode = A65_ABSY; - else - goto badmode; + } } else goto badmode; @@ -415,17 +399,17 @@ badmode: // o ZPX or ZPY is illegal, or // o expr is zeropage && zeropageRequest && expression is defined // - if (inf[op][amode] == ILLEGAL // If current op is illegal, - || (eval < 0x100 // or expr must be zero-page - && zpreq != 0 // amode must request zero-page opt. - && (eattr & DEFINED))) // and the expression must be defined + if ((inf[op][amode] == ILLEGAL) // If current op is illegal OR + || (zpreq // amode requested a zero-page optimize + && (eval < 0x100) // and expr is zero-page + && (eattr & DEFINED))) // and the expression is defined { - i = abs2zp[amode]; // i = zero-page translation of amode + int i = abs2zp[amode]; // Get zero-page translation of amode #ifdef DO_DEBUG DEBUG printf(" OPT: op=%d amode=%d i=%d inf[op][i]=%d\n", op, amode, i, inf[op][i]); #endif - if (i >= 0 && (inf[op][i] & 0xFF) != ILLEGAL) // Use it if it's legal + if (i >= 0 && (inf[op][i] & 0xFF) != ILLEGAL) // & use it if it's legal amode = i; } @@ -526,13 +510,14 @@ badmode: D_rword(eval); break; - // - // Deposit 3 NOPs for illegal things - // + // + // Deposit 3 NOPs for illegal things (why 3? why not 30? or zero?) + // default: case ILLEGAL: - for(i=0; i<3; i++) - D_byte(NOP); + D_byte(NOP); + D_byte(NOP); + D_byte(NOP); error("illegal 6502 addressing mode"); } @@ -541,40 +526,39 @@ badmode: if (sloc > 0x10000L) fatal("6502 code pointer > 64K"); - if (*tok != EOL) - error(extra_stuff); + ErrorIfNotAtEOL(); } // // Generate 6502 object output file. +// ggn: Converted to COM/EXE/XEX output format // -// ggn: converted into a com/exe/xex output format -// Notes: 1. The $FFFF is only mandatory for the first segment, but let's dump it everywhere for now -// 2. It's still dumping pages instead of more fine grained stuff. Should look into this - a8 people don't like waste so much ;) void m6502obj(int ofd) { - uint16_t exeheader[3]; - int headsize = 6; - uint16_t * headpoint = exeheader; + uint8_t header[4]; CHUNK * ch = sect[M6502].scode; - // If no 6502 code was generated, forget it + // If no 6502 code was generated, bail out if ((ch == NULL) || (ch->challoc == 0)) return; - exeheader[0] = 0xFFFF; // Mandatory for first segment register uint8_t * p = ch->chptr; + // Write out mandatory $FFFF header + header[0] = header[1] = 0xFF; + uint32_t unused = write(ofd, header, 2); + for(uint16_t * l=&orgmap[0][0]; l