-/*
- * 6502 Assembler
- *
- * Init6502 initialization
- * d_6502 handle ".6502" directive
- * m6502cg generate code for a 6502 mnemonic
- * d_org handle 6502 section's ".org" directive
- * m6502obj generate 6502 object file
- *
- */
-#include "rmac.h"
-#include "sect.h"
+//
+// 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
+// m6502cg generate code for a 6502 mnemonic
+// d_org handle 6502 section's ".org" directive
+// m6502obj generate 6502 object file
+//
+#include "direct.h"
#include "expr.h"
#include "error.h"
+#include "mach.h"
+#include "procln.h"
+#include "riscasm.h"
+#include "rmac.h"
+#include "sect.h"
+#include "token.h"
+
+#define DEF_KW
+#include "kwtab.h"
-#define UPSEG_SIZE 0x10010L /* size of 6502 code buffer, 64K+16bytes */
-
-
-/*
- * Imports
- */
-extern TOKEN *tok; /* -> current token */
-extern int debug; /* >0, in debug mode (-x) */
-extern int m6502; /* 1, in 6502 mode */
-extern TOKEN exprbuf[]; /* "universal" postfix expression buffer */
-extern LONG lsloc; /* `sloc' at start of line */
-extern unsigned orgactive; // RISC/6502 org directive active
-extern unsigned orgaddr; // Org'd address
-extern char * string[];
-
-extern char extra_stuff[]; /* needed-eol error message */
-extern char *range_error; /* value-out-of-range error message */
-
-
-/*
- * Exports
- */
-char in_6502mode[] = "directive illegal in .6502 section";
-static uint16_t orgmap[1024][2]; /* mark all 6502 org changes */
-uint16_t *currentorg = (uint16_t *)orgmap; /* current org range */
-
-/*
- * 6502 addressing modes;
- * do not change these values.
- *
- */
+#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";
+uint16_t * currentorg = &orgmap[0][0]; // Current org range
+char strtoa8[128]; // ASCII to Atari 800 internal conversion table
+
+//
+// 6502 addressing modes;
+// DO NOT CHANGE THESE VALUES.
+//
#define A65_ABS 0
#define A65_ABSX 1
#define A65_ABSY 2
#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
};
-static char ops[NMACHOPS][NMODES]; /* opcodes */
-static unsigned char inf[NMACHOPS][NMODES]; /* construction info */
+static char ops[NMACHOPS][NMODES]; // Opcodes
+static unsigned char inf[NMACHOPS][NMODES]; // Construction info
+// Absolute-to-zeropage translation table
static int abs2zp[] =
-{ /* absolute-to-zeropage trans table */
- A65_ZP, /* ABS */
- A65_ZPX, /* ABSX */
- A65_ZPY, /* ABSY */
- -1, /* IMPL */
- -1, /* IMMED */
- -1, /* INDX */
- -1, /* INDY */
- -1, /* IND */
- -1, /* REL */
- -1, /* ZP */
- -1, /* ZPX */
- -1 /* ZPY */
+{
+ A65_ZP, // ABS
+ A65_ZPX, // ABSX
+ A65_ZPY, // ABSY
+ -1, // IMPL
+ -1, // IMMED
+ -1, // INDX
+ -1, // INDY
+ -1, // IND
+ -1, // REL
+ -1, // ZP
+ -1, // ZPX
+ -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
- *
- */
+
+//
+// Initialize 6502 assembler
+//
void Init6502()
{
register int i;
register int j;
- register char *s;
- s = imodes;
+ register char * s = imodes;
- /* set all instruction slots to illegal */
- for (i = 0; i < NMACHOPS; ++i)
- for (j = 0; j < NMODES; ++j)
+ // Set all instruction slots to illegal
+ for(i=0; i<NMACHOPS; i++)
+ for(j=0; j<NMODES; j++)
inf[i][j] = ILLEGAL;
- /* uncompress legal instructions into their slots */
- for (i = 0; i < NMACHOPS; ++i)
+ // Uncompress legal instructions into their slots
+ for(i=0; i<NMACHOPS; i++)
{
- do {
- j = *s & 0xff;
+ do
+ {
+ j = *s & 0xFF;
inf[i][j] = *s;
ops[i][j] = s[1];
inf[i][A65_ZP] = A65_REL;
ops[i][A65_ZP] = s[1];
}
- } while(*(s += 2) != (char)END65);
- ++s;
+ }
+ while (*(s += 2) != (char)END65);
+
+ s++;
+ }
+
+ // 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(; p<a8internal+sizeof(a8internal); p+=2)
+ strtoa8[p[0]] = p[1];
+
+ if (challoc == 0)
+ {
+ // Allocate and clear 64K of space for the 6502 section
+ chcheck(UPSEG_SIZE);
+ memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE);
}
- /* set up first org section (set to zero) */
- orgmap[0][0] = 0;
+ SwitchSection(TEXT); // Go back to TEXT
}
-/*
- * .6502 --- enter 6502 mode
- *
- */
+//
+// .6502 --- enter 6502 mode
+//
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;
+ SaveSection(); // Save curent section
+ SwitchSection(M6502); // Switch to 6502 section
+
+ return 0;
}
-/*
- * Do 6502 code generation
- *
- */
-VOID m6502cg(int op)
+//
+// Do 6502 code generation
+//
+void m6502cg(int op)
{
- register int amode; /* (parsed) addressing mode */
+ 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; // Expression value
+ WORD eattr; // Expression attributes
+ int zpreq; // 1, optimize instr to zero-page form
+ register char * p; // (Temp) string usage
+ ch_size = 0; // Reset chunk size on every instruction
+
+ //
+ // Parse 6502 addressing mode
+ //
+ zpreq = 0;
+ switch (tok[0])
+ {
+ case EOL:
+ amode = A65_IMPL;
+ break;
- ch_size = 0; /* reset chunk size on every instruction */
+ case KW_A:
+ if (tok[1] != EOL)
+ goto badmode;
- /*
- * Parse 6502 addressing mode
- *
- */
- zpreq = 0;
- switch ((int)*tok)
- {
- case EOL:
- amode = A65_IMPL;
- break;
+ amode = A65_IMPL;
+ tok++;
+ 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;
- }
- if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
- amode = A65_IMMED;
+ case '#':
+ tok++;
+
+ if (*tok == '>')
+ {
+ tok++;
+
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return;
+
+ amode = A65_IMMEDH;
break;
+ }
+ else if (*tok == '<')
+ {
+ tok++;
- case '(':
- ++tok;
- if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
-
- if (*tok == ')')
- { /* (foo) or (foo),y */
- if (*++tok == ',')
- { /* (foo),y */
- ++tok;
- p = string[tok[1]];
- if (*tok != SYMBOL ||
- p[1] != EOS ||
- (*p | 0x20) != 'y') /* sleazo tolower() */
- goto badmode;
- tok += 2;
- amode = A65_INDY;
- }
- else amode = A65_IND;
- }
- else if (*tok == ',')
- { /* (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;
- amode = A65_INDX;
- }
- else goto badmode;
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return;
+
+ amode = A65_IMMEDL;
break;
+ }
- case '@':
- ++tok;
- if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return;
- if (*tok == '(')
+ amode = A65_IMMED;
+ break;
+
+ case '(':
+ tok++;
+
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return;
+
+ if (*tok == ')')
+ {
+ // (foo) or (foo),y
+ if (*++tok == ',')
{
- ++tok;
+ // (foo),y
+ tok++;
+#if 0
p = string[tok[1]];
- if (*tok != SYMBOL ||
- p[1] != EOS ||
- tok[2] != ')' ||
- tok[3] != EOL)
+
+ // Sleazo tolower() -----------------vvvvvvvvvvv
+ if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'y')
goto badmode;
- i = (*p | 0x20); /* sleazo tolower */
- if (i == 'x')
- amode = A65_INDX;
- else if (i == 'y')
+ tok += 2;
+ amode = A65_INDY;
+#else
+ if (tok[0] == KW_Y)
amode = A65_INDY;
- else goto badmode;
- tok += 3; /* past SYMBOL <string> ')' EOL */
- zpreq = 1; /* request zeropage optimization */
+
+ if (tok[1] != EOL)
+ goto badmode;
+
+ tok++;
+#endif
}
- else if (*tok == EOL)
+ else
amode = A65_IND;
- else goto badmode;
- break;
+ }
+ else if (*tok == ',')
+ {
+ // (foo,x)
+ tok++;
+#if 0
+ p = string[tok[1]];
- default:
- /*
- * Short-circuit
- * x,foo
- * y,foo
- *
- */
+ // Sleazo tolower() -----------------vvvvvvvvvvv
+ if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'x')
+ goto badmode;
+
+ tok += 2;
+ if (*tok++ != ')')
+ goto badmode;
+
+ amode = A65_INDX;
+#else
+ if (tok[0] == KW_X)
+ amode = A65_INDX;
+
+ if ((tok[1] != ')') || (tok[2] != EOL))
+ goto badmode;
+
+ tok += 2;
+#endif
+ }
+ else
+ goto badmode;
+
+ break;
+
+ // I'm guessing that the form of this is @<expr>(X) or @<expr>(Y), which
+ // I've *never* seen before. :-/
+ case '@':
+ tok++;
+
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return;
+
+ if (*tok == '(')
+ {
+ tok++;
+#if 0
p = string[tok[1]];
- 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;
- }
+ if (*tok != SYMBOL || p[1] != EOS || tok[2] != ')' || tok[3] != EOL)
+ goto badmode;
+
+ i = (*p | 0x20); // Sleazo tolower()
+
+ if (i == 'x')
+ amode = A65_INDX;
+ else if (i == 'y')
+ amode = A65_INDY;
+ else
+ goto badmode;
+
+ tok += 3; // Past SYMBOL <string> ')' EOL
+#else
+ if ((tok[1] != ')') || (tok[2] != EOL))
+ goto badmode;
+
+ if (tok[0] == KW_X)
+ amode = A65_INDX;
+ else if (tok[0] == KW_Y)
+ amode = A65_INDY;
+ else
+ goto badmode;
+
+ tok += 2;
+#endif
+ zpreq = 1; // Request zeropage optimization
+ }
+ else if (*tok == EOL)
+ amode = A65_IND;
+ else
+ goto badmode;
+
+ 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;
-not_coinop:
- if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
zpreq = 1;
+ break;
+ }
- if (*tok == EOL)
- amode = A65_ABS;
- else if (*tok == ',')
- {
- ++tok;
- p = string[tok[1]];
- if (*tok != SYMBOL ||
- p[1] != EOS)
- goto badmode;
- tok += 2;
+not_coinop:
+#endif
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return;
+
+ zpreq = 1;
+
+ if (*tok == EOL)
+ amode = A65_ABS;
+ else if (*tok == ',')
+ {
+ tok++;
+#if 0
+ p = string[tok[1]];
+
+ if (*tok != SYMBOL || p[1] != EOS)
+ goto badmode;
- /*
- * 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')
- amode = A65_ABSX;
- else if (i == 'y')
- amode = A65_ABSY;
- else 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')
+ amode = A65_ABSX;
+ else if (i == 'y')
+ amode = A65_ABSY;
+ else
+ goto badmode;
+#else
+ if (tok[0] == KW_X)
+ {
+ amode = A65_ABSX;
+ tok++;
}
- else goto badmode;
- break;
+ else if (tok[0] == KW_Y)
+ {
+ amode = A65_ABSY;
+ tok++;
+ }
+
+ if (tok[0] != EOL)
+ goto badmode;
+#endif
+ }
+ else
+ goto badmode;
+
+ break;
badmode:
- error("bad 6502 addressing mode");
- return;
+ error("bad 6502 addressing mode");
+ return;
}
- /*
- * Optimize ABS modes to zero-page when possible
- * 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, or */
- (eval < 0x100 && /* expr must be zero-page */
- zpreq != 0 && /* amode must request zero-page opt. */
- (eattr & DEFINED))) /* and the expression must be defined */
+ //
+ // Optimize ABS modes to zero-page when possible
+ // 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
{
- i = abs2zp[amode]; /* i = zero-page translation of amode */
+ i = abs2zp[amode]; // i = 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;
}
switch (inf[op][amode])
{
- case A65_IMPL: /* just leave the instruction */
+ case A65_IMPL: // Just leave the instruction
D_byte(ops[op][amode]);
break;
- case A65_IMMEDH:
- D_byte(ops[op][amode]);
- if (!(eattr & DEFINED))
- {
- AddFixup(FU_BYTEH, sloc, exprbuf);
- eval = 0;
- }
- eval = (eval >> 8) & 0xff; /* bring high byte to low */
- D_byte(eval); /* deposit byte following instr */
- break;
-
- case A65_IMMEDL:
- D_byte(ops[op][amode]);
- if (!(eattr & DEFINED))
- {
- AddFixup(FU_BYTEL, sloc, exprbuf);
- eval = 0;
- }
- eval = eval & 0xff; /* mask high byte */
- D_byte(eval); /* deposit byte following instr */
- break;
+ case A65_IMMEDH:
+ D_byte(ops[op][amode]);
+
+ if (!(eattr & DEFINED))
+ {
+ AddFixup(FU_BYTEH, sloc, exprbuf);
+ eval = 0;
+ }
+
+ eval = (eval >> 8) & 0xFF; // Bring high byte to low
+ D_byte(eval); // Deposit byte following instr
+ break;
+
+ case A65_IMMEDL:
+ D_byte(ops[op][amode]);
+
+ if (!(eattr & DEFINED))
+ {
+ AddFixup(FU_BYTEL, sloc, exprbuf);
+ eval = 0;
+ }
+
+ eval = eval & 0xFF; // Mask high byte
+ D_byte(eval); // Deposit byte following instr
+ break;
case A65_IMMED:
case A65_INDX:
case A65_ZPX:
case A65_ZPY:
D_byte(ops[op][amode]);
+
if (!(eattr & DEFINED))
{
AddFixup(FU_BYTE, sloc, exprbuf);
error(range_error);
eval = 0;
}
- D_byte(eval); /* deposit byte following instr */
+
+ D_byte(eval); // Deposit byte following instr
break;
case A65_REL:
D_byte(ops[op][amode]);
+
if (eattr & DEFINED)
{
eval -= (sloc + 1);
+
if (eval + 0x80 >= 0x100)
{
error(range_error);
eval = 0;
}
+
D_byte(eval);
}
else
AddFixup(FU_6BRA, sloc, exprbuf);
D_byte(0);
}
+
break;
case A65_ABS:
case A65_ABSY:
case A65_IND:
D_byte(ops[op][amode]);
+
if (!(eattr & DEFINED))
{
AddFixup(FU_WORD, sloc, exprbuf);
eval = 0;
}
+
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) {
+ for(i=0; i<3; i++)
D_byte(NOP);
- }
+
error("illegal 6502 addressing mode");
}
- /*
- * Check for overflow of code region
- */
- if (sloc > 0x10000L) fatal("6502 code pointer > 64K");
- if (*tok != EOL) error(extra_stuff);
+ // Check for overflow of code region
+ if (sloc > 0x10000L)
+ fatal("6502 code pointer > 64K");
+
+ ErrorIfNotAtEOL();
}
-/*
- * Generate 6502 object output file.
- *
- */
-// 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(ofd)
-int ofd;
+//
+// Generate 6502 object output file.
+// ggn: Converted to COM/EXE/XEX output format
+//
+void m6502obj(int ofd)
{
- register CHUNK *ch;
- register char *p;
- uint16_t exeheader[3];
- uint16_t *l;
- int headsize = 6;
- uint16_t *headpoint = (uint16_t *)exeheader;
-
- /*
- * If no 6502 code was generated, forget it
- */
- if ((ch = sect[M6502].scode) == NULL ||
- ch->challoc == 0)
+ uint8_t header[4];
+
+ CHUNK * ch = sect[M6502].scode;
+
+ // If no 6502 code was generated, bail out
+ if ((ch == NULL) || (ch->challoc == 0))
return;
- exeheader[0] = 0xffff; // mandatory for first segment
- p = ch->chptr;
+ register uint8_t * p = ch->chptr;
- for (l = (uint16_t *)orgmap;l < currentorg;l+=2)
- {
- exeheader[1] = l[0];
- exeheader[2] = l[1]-1;
- write(ofd, headpoint, headsize); // Write header
- write(ofd, p + l[0], l[1] - l[0]);
- headpoint = &exeheader[1]; // skip the $ffff after first segment, it's not mandatory
- headsize = 4;
- }
+ // 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)
+ {
+ SETLE16(header, 0, l[0]);
+ SETLE16(header, 2, l[1] - 1);
+
+ // Write header for segment
+ unused = write(ofd, header, 4);
+ // Write the segment data
+ unused = write(ofd, p + l[0], l[1] - l[0]);
+ }
}
+