//
-// RMAC - Reboot's Macro Assembler for all Atari computers
+// RMAC - Renamed Macro Assembler for all Atari computers
// 6502.C - 6502 Assembler
-// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
#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
#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
};
void m6502cg(int op)
{
register int amode; // (Parsed) addressing mode
- register int i;
- uint32_t 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 '(':
{
// (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
break;
+ // I'm guessing that the form of this is @<expr>(X) or @<expr>(Y), which
+ // I've *never* seen before. :-/
case '@':
tok++;
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 <string> ')' EOL
+ tok += 2;
zpreq = 1; // Request zeropage optimization
}
else if (*tok == EOL)
break;
default:
- //
- // Short-circuit
- // x,foo
- // y,foo
- //
- p = string[tok[1]];
- // ggn: the following code is effectively disabled as it would make
- // single letter labels not work correctly (would not identify the
- // label properly). And from what I understand it's something to
- // keep compatibility with the coinop assembler which is probably
- // something we don't care about much :D
-#if 0
- if (*tok == SYMBOL && p[1] == EOS && tok[2] == ',')
- {
- tok += 3; // Past: SYMBOL <string> ','
- 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:
-#endif
+ // <expr>
+ // <expr>,x
+ // <expr>,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;
// 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;
}
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");
}
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
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<currentorg; l+=2)
{
- exeheader[1] = l[0];
- exeheader[2] = l[1] - 1;
+ SETLE16(header, 0, l[0]);
+ SETLE16(header, 2, l[1] - 1);
- // Write header
- size_t unused = write(ofd, headpoint, headsize);
+ // Write header for segment
+ unused = write(ofd, header, 4);
+ // Write the segment data
unused = write(ofd, p + l[0], l[1] - l[0]);
-
- // Skip the $FFFF after first segment, it's not mandatory
- headpoint = &exeheader[1];
- headsize = 4;
}
}