--- /dev/null
+/*
+ * 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"
+#include "expr.h"
+#include "error.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 A65_ABS 0
+#define A65_ABSX 1
+#define A65_ABSY 2
+#define A65_IMPL 3
+#define A65_IMMED 4
+#define A65_INDX 5
+#define A65_INDY 6
+#define A65_IND 7
+#define A65_REL 8
+#define A65_ZP 9
+#define A65_ZPX 10
+#define A65_ZPY 11
+#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 */
+
+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_REL, 0x90, 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_IMPL, 0x00, END65,
+ A65_IMPL, 0x18, 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, 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_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_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_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_IMPL, 0x38, 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_IMPL, 0x98, END65
+};
+
+static char ops[NMACHOPS][NMODES]; /* opcodes */
+static unsigned char inf[NMACHOPS][NMODES]; /* construction info */
+
+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 */
+};
+
+
+/*
+ * initialize 6502 assembler
+ *
+ */
+void Init6502()
+{
+ register int i;
+ register int j;
+ register char *s;
+
+ s = imodes;
+
+ /* 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)
+ {
+ do {
+ j = *s & 0xff;
+ inf[i][j] = *s;
+ ops[i][j] = s[1];
+
+ /* hack A65_REL mode */
+ if (*s == A65_REL)
+ {
+ inf[i][A65_ABS] = A65_REL;
+ ops[i][A65_ABS] = s[1];
+ inf[i][A65_ZP] = A65_REL;
+ ops[i][A65_ZP] = s[1];
+ }
+ } while(*(s += 2) != (char)END65);
+ ++s;
+ }
+
+ /* set up first org section (set to zero) */
+ orgmap[0][0] = 0;
+}
+
+
+/*
+ * .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;
+}
+
+
+/*
+ * Do 6502 code generation
+ *
+ */
+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 */
+
+
+ ch_size = 0; /* reset chunk size on every instruction */
+
+ /*
+ * Parse 6502 addressing mode
+ *
+ */
+ zpreq = 0;
+ switch ((int)*tok)
+ {
+ case EOL:
+ 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;
+ }
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
+ amode = A65_IMMED;
+ break;
+
+ 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;
+ break;
+
+ case '@':
+ ++tok;
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
+
+ if (*tok == '(')
+ {
+ ++tok;
+ p = string[tok[1]];
+ 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 */
+ 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]];
+ 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:
+ if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
+ zpreq = 1;
+
+ if (*tok == EOL)
+ amode = A65_ABS;
+ else if (*tok == ',')
+ {
+ ++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')
+ amode = A65_ABSX;
+ else if (i == 'y')
+ amode = A65_ABSY;
+ else goto badmode;
+ }
+ else goto badmode;
+ break;
+
+badmode:
+ 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 */
+ {
+ 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 */
+ amode = i;
+ }
+
+#ifdef DO_DEBUG
+ DEBUG printf("6502: op=%d amode=%d ", op, amode);
+ DEBUG printf("inf[op][amode]=%d\n", (int)inf[op][amode]);
+#endif
+
+ switch (inf[op][amode])
+ {
+ 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_IMMED:
+ case A65_INDX:
+ case A65_INDY:
+ case A65_ZP:
+ case A65_ZPX:
+ case A65_ZPY:
+ D_byte(ops[op][amode]);
+ if (!(eattr & DEFINED))
+ {
+ AddFixup(FU_BYTE, sloc, exprbuf);
+ eval = 0;
+ }
+ else if (eval + 0x100 >= 0x200)
+ {
+ error(range_error);
+ eval = 0;
+ }
+ 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_ABSX:
+ 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
+ */
+ default:
+ case ILLEGAL:
+ 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);
+}
+
+
+/*
+ * 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;
+{
+ 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)
+ return;
+
+ exeheader[0] = 0xffff; // mandatory for first segment
+ 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;
+ }
+
+}
--- /dev/null
+#
+# 6502 mnemonics
+#
+adc 2000
+and 2001
+asl 2002
+bcc 2003
+bcs 2004
+beq 2005
+bne 2006
+bmi 2007
+bpl 2008
+bvc 2009
+bvs 2010
+bit 2011
+brk 2012
+clc 2013
+cld 2014
+cli 2015
+clv 2016
+cmp 2017
+cpx 2018
+cpy 2019
+dec 2020
+dex 2021
+dey 2022
+eor 2023
+inc 2024
+inx 2025
+iny 2026
+jmp 2027
+jsr 2028
+lda 2029
+ldx 2030
+ldy 2031
+lsr 2032
+nop 2033
+ora 2034
+pha 2035
+php 2036
+pla 2037
+plp 2038
+rol 2039
+ror 2040
+rti 2041
+rts 2042
+sbc 2043
+sec 2044
+sed 2045
+sei 2046
+sta 2047
+stx 2048
+sty 2049
+tax 2050
+tay 2051
+tsx 2052
+txa 2053
+txs 2054
+tya 2055
#define DEF_KW
#include "kwtab.h"
-
TOKEN exprbuf[128]; // Expression buffer
SYM * symbolPtr[1000000]; // Symbol pointers table
static long unused; // For supressing 'write' warnings
int (*dirtab[])() = {
d_org, // 0 org
d_even, // 1 even
- d_unimpl, // 2 .6502
+ d_6502, // 2 .6502
d_68000, // 3 .68000
d_bss, // 4 bss
d_data, // 5 data
//
int d_org(void)
{
- VALUE address;
-
- if (!rgpu && !rdsp)
- return error(".org permitted only in gpu/dsp section");
-
- orgaddr = 0;
-
- if (abs_expr(&address) == ERROR)
- {
- error("cannot determine org'd address");
- return ERROR;
- }
-
- orgaddr = address;
- orgactive = 1;
-//printf("ORG: address = $%08X...\n", orgaddr);
-
- return 0;
+ VALUE address;
+
+ if (!rgpu && !rdsp && !m6502)
+ return error(".org permitted only in gpu/dsp and 6502 sections");
+
+ if (rgpu | rdsp)
+ {
+ orgaddr = 0;
+
+ if (abs_expr(&address) == ERROR)
+ {
+ error("cannot determine org'd address");
+ return ERROR;
+ }
+
+ orgaddr = address;
+ orgactive = 1;
+ //printf("ORG: address = $%08X...\n", orgaddr);
+
+ return 0;
+ }
+ else
+ {
+ // 6502
+ // We also kludge `lsloc' so the listing generator doesn't
+ // try to spew out megabytes.
+ VALUE eval;
+
+ //if (m6502 == 0) return error(".org permitted only in .6502 section");
+ if (abs_expr(&eval) < 0) return 0;
+ if (eval >= 0x10000L) return error(range_error);
+
+ if (sloc != currentorg[0])
+ {
+ currentorg[1] = sloc;
+ currentorg += 2;
+ }
+
+ currentorg[0] = eval;
+ ch_size = 0;
+ lsloc = sloc = eval;
+ chptr = scode->chptr + eval;
+ orgactive = 1;
+ orgaddr = eval;
+ at_eol();
+ return 0;
+ }
}
//
int d_even(void)
{
+ if (m6502)
+ return error(in_6502mode);
+
unsigned skip = (rgpu || rdsp ? orgaddr : sloc) & 0x01;
if (skip)
//
void auto_even(void)
{
+ if (cursect != M6502)
+ {
if (scattr & SBSS)
sloc++; // Bump BSS section
else
if (lab_sym != NULL) // Bump label if we have to
lab_sym->svalue++;
+ }
}
int d_globl(void)
{
+ if (m6502)
+ return error(in_6502mode);
+
symlist(globl1);
return 0;
}
{
VALUE eval;
+ if (m6502)
+ return error(in_6502mode);
+
SaveSection();
if (*tok == EOL)
{
if (rgpu || rdsp)
return error("directive forbidden in gpu/dsp mode");
+ if (m6502)
+ return error(in_6502mode);
if (cursect != TEXT)
{
{
if (rgpu || rdsp)
return error("directive forbidden in gpu/dsp mode");
+ if (m6502)
+ return error(in_6502mode);
if (cursect != DATA)
{
{
if (rgpu || rdsp)
return error("directive forbidden in gpu/dsp mode");
+ if (m6502)
+ return error(in_6502mode);
if (cursect != BSS)
{
VALUE eval;
- if ((siz != SIZB) && (sloc & 1)) // Automatic .even
- auto_even();
+ if (cursect != M6502)
+ {
+ if ((siz != SIZB) && (sloc & 1)) // Automatic .even
+ auto_even();
+ }
if (abs_expr(&eval) != OK)
return 0;
// In non-TDB section (BSS, ABS and M6502) just advance the location
// counter appropriately. In TDB sections, deposit (possibly large) chunks
// of zeroed memory....
- if (scattr & SBSS)
+ if ((scattr & SBSS) || cursect == M6502)
{
listvalue(eval);
eval *= siz;
sloc += eval;
+ if (cursect == M6502) chptr += eval;
just_bss = 1; // No data deposited (8-bit CPU mode)
}
else
return error("illegal initialization of section");
// Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
- if ((siz != SIZB) && (sloc & 1))
+ if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
auto_even();
// Check to see if we're trying to set LONGS on a non 32-bit aligned
MarkRelocatable(cursect, sloc, tdb, MWORD, NULL);
// Deposit 68000 or 6502 (byte-reversed) word
- D_word(eval);
+ if (cursect != M6502)
+ {
+ D_word(eval);
+ }
+ else
+ {
+ D_rword(eval);
+ }
+
}
break;
case SIZL:
+ if (m6502)
+ return error(in_6502mode);
+
if (!defined)
{
if (movei)
if (expr(exprbuf, &eval, &eattr, NULL) < 0)
return 0;
- if ((siz != SIZB) && (sloc & 1))
+ if (cursect != M6502 && (siz != SIZB) && (sloc & 1))
auto_even();
dep_block(evalc, siz, eval, eattr, exprbuf);
return error(range_error);
// Deposit 68000 or 6502 (byte-reversed) word
- D_word(eval);
+ if (cursect != M6502)
+ {
+ D_word(eval);
+ }
+ else
+ {
+ D_rword(eval);
+ }
+
}
break;
case SIZL:
+ if (m6502)
+ return error(in_6502mode);
+
if (!defined)
{
AddFixup(FU_LONG, sloc, exprbuf);
char * p;
VALUE eval;
+ if (m6502)
+ return error(in_6502mode);
+
if (*tok != SYMBOL)
return error("missing symbol");
extern TOKEN exprbuf[];
extern SYM * symbolPtr[];
extern int (* dirtab[])();
+extern int as68_flag; /* 1, AS68 kludge mode for Alcyon back-end */
+extern int m6502; /* 1, assembler in 6502 mode */
+extern char in_6502mode[];
+extern uint16_t *currentorg;
// Prototypes
int d_even(void);
disclaims liability for changes, errors or omissions.*
-*Copyright © 2011-2015, Reboot*
+*Copyright © 2011-2017, Reboot*
*All rights reserved.*
AS68 user, before you leap into the unknown please read the section on Notes for
AS68 Users.
-This manual was typeset with TEX and the Computer Modern fonts, and it
-was printed on the Atari SLM-804 laser printer with a MEGA ST. Except for 200
-lines of assembly language, the assembler is written entirely in C.
-
.. [1] It processes 30,000 lines a minute on a lightly loaded VAX 11/780; maybe 40,000 on a 520-ST with an SH-204 hard disk. Yet it could be sped up even more with some effort and without resorting to assembly language; C doesn't have to be slow!
`Getting Started`_
INTIE: ds.l 1
PTSIN: ds.l 1
+ Another interesting example worth mentioning is the emulation of "C"'s "union" keyword
+ using *.abs*. For example, the following "C" code:
+
+ ::
+
+ struct spritesheet
+ {
+ short spf_w;
+ short spf_h;
+ short spf_xo;
+ short spf_yo;
+ union { int spf_em_colour; int spf_emx_colour; };
+ union { int spf_em_psmask[16]; int spf_emx_colouropt; };
+ }
+
+ can be expressed as:
+
+ ::
+
+ .abs
+ *-------------------------------------------------------*
+ spf_w: ds.w 1 ;<- common
+ spf_h: ds.w 1
+ spf_xo: ds.w 1
+ spf_yo: ds.w 1
+ spf_data: ds.l 0
+ *-------------------------------------------------------*
+ ; .union set
+ spf_em_colour: ds.l 1 ;<- union #1
+ spf_em_psmask: ds.l 16
+ *-------------------------------------------------------*
+ .68000
+ .abs spf_em_colour
+ ; .union reset
+ spf_emx_colour: ds.l 1 ;<- union #2
+ spf_emx_colouropt: ds.l 1
+ spf_emx_psmask: ds.l 16
+ spf_emx_psmaskopt: ds.l 16
+
+ .68000
+ ;*-------------------------------------------------------*
+
+ move #spf_em_colour,d0
+ move #spf_emx_colour,d0
+
+ In this example, *spf_em_colour* and *spf_emx_colour* will have the same value.
+
**.comm** *symbol*, *expression*
Specifies a label and the size of a common region. The label is made global,
thus confined symbols cannot be made common. The linker groups all common
*empty* implied or accumulator (e.g. tsx or ror)
*expr* absolute or zeropage
#\ *expr* immediate
+#<\ *expr* immediate low byte of a word
+#>\ *expr* immediate high byte of a word
(*expr*,x) indirect X
(*expr*),y indirect Y
(*expr*) indirect
y,\ *expr* indexed Y
============== ========================================
-While RMAC lacks "high" and "low" operators, high bytes of words may
-be extracted with the shift (``>>``) or divide (``/``) operators, and low bytes may be
-extracted with the bitwise AND (``&``) operator.
-
`6502 Directives`_
''''''''''''''''''
**.6502**
`6502 Object Code Format`_
''''''''''''''''''''''''''
-This is a little bit of a kludge. An object file consists of a page map, followed by
-one or more page images, followed by a normal Alcyon 68000 object file. If the page
-map is all zero, it is not written.
+Traditionally Madmac had a very kludgy way of storing object files. This has been
+replaced with a more standard *.exe* (or *.com* or *.xex* if you prefer). Briefly,
+the *.exe* format consists of chunks of this format (one after the other):
-The page map contains a byte for each of the 256 256-byte pages in the 6502's
-64K address space. The byte is zero (``$00``) if the page contained only zero bytes, or
-one (``$01``) if the page contained any non-zero bytes. If a page is flagged with a one,
-then it is written (in order) following the page map.
-
-The following code:
-
- ::
-
- .6502
- .org $8000
- .dc.b 1
- .org $8100
- .dc.b 1
- .org $8300
- .dc.b 1
- .end
-
-will generate a page map that looks (to a programmer) something like:
-
- ::
+ ::
- <80 bytes of zero>
- 01 01 00 01
- <$7c more bytes of zero, for $100 total>
- <image of page $80>
- <image of page $81>
- <image of page $83>
-
-Following the last page image is an Alcyon-format object file, starting with
-the magic number ``$601a``. It may contain 68000 code (although that is probably
-useless), but the symbol table is valid and available for debugging purposes. 6502
-symbols will be absolute (not in text, data or bss).
+ Offset Description
+ 00-01 $FFFF - Indicates a binary load file. Mandatory for first segment, optional for any other segment
+ 02-03 Start Address. The segment will load at this address
+ 04-05 End Address. The last byte to load for this segment
+ 06-.. The actual segment data to load (End Address-Start Address + 1 bytes)
`Error Messages`_
=================
{
ch = sect[lcursect].sfcode;
+ if (lcursect != M6502)
+ {
for(; ch!=NULL; ch=ch->chnext)
{
if (lsloc >= ch->chloc && lsloc < (ch->chloc + ch->ch_size))
break;
}
+ }
// Fatal: Can't find chunk holding code
if (ch == NULL)
strncpy(lnimage + LOC_COL, buf, 8);
}
- if (lsloc >= (ch->chloc + ch->ch_size))
+ if (lcursect != M6502 &&
+ lsloc >= (ch->chloc + ch->ch_size))
{
if ((ch = ch->chnext) == NULL)
goto nochunk;
CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2
-SRCS = amode.c debug.c direct.c eagen.c error.c expr.c listing.c mach.c macro.c mark.c object.c procln.c riscasm.c rmac.c sect.c symbol.c token.c
+SRCS = amode.c debug.c direct.c eagen.c error.c expr.c listing.c mach.c macro.c mark.c object.c procln.c riscasm.c rmac.c sect.c symbol.c token.c 6502.c
-OBJS = amode.o debug.o direct.o eagen.o error.o expr.o listing.o mach.o macro.o mark.o object.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
+OBJS = amode.o debug.o direct.o eagen.o error.o expr.o listing.o mach.o macro.o mark.o object.o procln.o riscasm.o rmac.o sect.o symbol.o token.o 6502.o
#
# Build everything
#
-all : mntab.h 68ktab.h kwtab.h risckw.h rmac
+all : mntab.h 68ktab.h kwtab.h risckw.h 6502.h rmac
@echo
@echo "Don't forget to bump the version number before commiting!"
@echo
kwtab.h : kwtab kwgen
./kwgen kw <kwtab >kwtab.h
+6502.h : 6502.tbl kwgen
+ ./kwgen mp <6502.tbl >6502.h
+
risckw.h : kwtab kwgen
./kwgen mr <risctab >risckw.h
symbol.o : symbol.c
$(CC) $(CFLAGS) -c symbol.c
+6502.o : 6502.c
+ $(CC) $(CFLAGS) -c 6502.c
+
token.o : token.c
$(CC) $(CFLAGS) -c token.c
#include "riscasm.h"
#include "sect.h"
#include "symbol.h"
-
+extern void m6502obj(int ofd);
//#define DEBUG_ELF
free(strtable);
}
}
+ else if (obj_format == XEX)
+ {
+ // Just write the object file
+ m6502obj(fd);
+ }
return 0;
}
#ifndef __OBJECT_H__
#define __OBJECT_H__
-#include <rmac.h>
+#include "rmac.h"
#define BSDHDRSIZE 0x20 // Size of BSD header
#define HDRSIZE 0x1C // Size of Alcyon header
#define DECL_MR
#include "risckw.h"
+#define DEF_MP /* include 6502 keyword definitions */
+#define DECL_MP /* include 6502 keyword state machine tables */
+#include "6502.h"
+extern int m6502; /* 1, assembler in .6502 mode */
+extern VOID m6502cg(); /* 6502 code generator */
+extern VOID m6502obj(int ofd);
IFENT * ifent; // Current ifent
static IFENT ifent0; // Root ifent
if (state == -3)
goto loop;
+ /*
+ * If we're in 6502 mode and are still in need
+ * of a mnemonic, then search for valid 6502 mnemonic.
+ */
+ if (m6502 &&
+ (state < 0 || state >= 1000))
+ {
+#ifdef ST
+ state = kmatch(opname, mpbase, mpcheck, mptab, mpaccept);
+#else
+ for (state = 0, p = opname; state >= 0;)
+ {
+ j = mpbase[state] + tolowertab[*p];
+ if (mpcheck[j] != state) /* reject, character doesn't match */
+ {
+ state = -1; /* no match */
+ break;
+ }
+
+ if (!*++p)
+ { /* must accept or reject at EOS */
+ state = mpaccept[j]; /* (-1 on no terminal match) */
+ break;
+ }
+ state = mptab[j];
+ }
+#endif
+
+ /*
+ * Call 6502 code generator if we found a mnemonic
+ */
+ if (state >= 2000)
+ {
+ m6502cg(state - 2000);
+ goto loop;
+ }
+ }
+
// If we are in GPU or DSP mode and still in need of a mnemonic then search
// for one
if ((rgpu || rdsp) && (state < 0 || state >= 1000))
extern VALUE pcloc;
extern SYM * lab_sym;
extern LONG amsktab[];
+extern char in_6502mode[];
// Prototypes
void InitLineProcessor(void);
unsigned altbankok = 0; // Ok to use alternate register bank
-unsigned orgactive = 0; // RISC org directive active
+unsigned orgactive = 0; // RISC/6502 org directive active
unsigned orgaddr = 0; // Org'd address
unsigned orgwarning = 0; // Has an ORG warning been issued
int lastOpcode = -1; // Last RISC opcode assembled
int perm_verb_flag; // Permanently verbose, interactive mode
int list_flag; // "-l" listing flag on command line
int verb_flag; // Be verbose about what's going on
+int m6502; // 1, assembling 6502 code
int as68_flag; // as68 kludge mode
int glob_flag; // Assume undefined symbols are global
int lsym_flag; // Include local symbols in object file
" a: ALCYON (use this for ST)\n"
" b: BSD (use this for Jaguar)\n"
" e: ELF\n"
+ " x: com/exe/xex (Atari 800)\n"
" -i[path] Directory to search for include files\n"
" -l[filename] Create an output listing file\n"
" -n Don't do things behind your back in RISC assembler\n"
orgactive = 0; // Not in RISC org section
orgwarning = 0; // No ORG warning issued
segpadsize = 2; // Initialise segment padding size
+ m6502 = 0; // 6502 mode off by default
// Initialise modules
InitSymbolTable(); // Symbol table
InitMark(); // Mark tape-recorder
InitMacro(); // Macro processor
InitListing(); // Listing generator
+ Init6502(); // 6502 assembler
// Process command line arguments and assemble source files
for(argno=0; argno<argc; ++argno)
case 'E':
obj_format = ELF;
break;
+ case 'x': // -fx = COM/EXE/XEX
+ case 'X':
+ obj_format = XEX;
+ break;
default:
printf("-f: unknown object format specified\n");
errcnt++;
// o save current section (no more code generation)
// o do auto-even of all sections (or boundary alignment as requested
// through '-r')
+ // o save the last pc value for 6502 (if we used 6502 at all) and
+ // detemine if the last section contains anything
// o determine name of object file:
// - "foo.o" for linkable output;
// - "foo.prg" for GEMDOS executable (-p flag).
SaveSection();
}
+ SwitchSection(M6502);
+ if (sloc != currentorg[0])
+ {
+ currentorg[1] = sloc;
+ currentorg += 2;
+ }
+
if (objfname == NULL)
{
if (firstfname == NULL)
#define MWC 1 // Mark Williams object format
#define BSD 2 // BSD object format
#define ELF 3 // ELF object format
+#define XEX 4 // COM/EXE/XEX/whatever a8 object format
// Pointer type that can point to (almost) anything
#define PTR union _ptr
#define TEXT 0x0001 // Relative to text
#define DATA 0x0002 // Relative to data
#define BSS 0x0004 // Relative to BSS
-//#define M6502 0x0008 // 6502/microprocessor (absolute)
+#define M6502 0x0008 // 6502/microprocessor (absolute)
#define TDB (TEXT|DATA|BSS) // Mask for text+data+bss
// Sizes
extern char * firstfname;
extern int list_fd;
extern int as68_flag;
+extern int m6502;
extern int list_flag;
extern int glob_flag;
extern int lsym_flag;
extern int prg_flag; // 1 = write ".PRG" relocatable executable
extern LONG PRGFLAGS;
extern int optim_flags[OPT_COUNT];
+extern void Init6502();
// Exported functions
char * fext(char *, char *, int);
#include "riscasm.h"
#include "symbol.h"
#include "token.h"
+extern int m6502; /* 1, assembler in .6502 mode */
// Function prototypes
MakeSection(TEXT, SUSED | TEXT ); // TEXT
MakeSection(DATA, SUSED | DATA ); // DATA
MakeSection(BSS, SUSED | BSS | SBSS); // BSS
-// MakeSection(M6502, SUSED | TEXT ); // 6502 code section
+ MakeSection(M6502, SUSED | TEXT ); // 6502 code section
// Switch to TEXT for starters
SwitchSection(TEXT);
cursect = sno;
SECT * p = §[sno];
+ m6502 = (sno == M6502); /* set 6502-mode */
+
// Copy section vars
scattr = p->scattr;
sloc = p->sloc;
if (cch == NULL)
return 0;
+ /*
+ * Wire the 6502 segment's size to its allocated size (64K)
+ */
+ if (sno == M6502)
+ cch->ch_size = cch->challoc;
+
do
{
fup.cp = ch->chptr; // fup -> start of chunk
*locp = (uint8_t)eval;
break;
+ // Fixup high/low byte off word for 6502
+ case FU_BYTEH:
+ if (!(eattr & DEFINED))
+ {
+ error("external byte reference");
+ continue;
+ }
+
+ *locp = (uint8_t)((eval >> 8) & 0xff);
+ break;
+ case FU_BYTEL:
+ if (!(eattr & DEFINED))
+ {
+ error("external byte reference");
+ continue;
+ }
+
+ *locp = (uint8_t)(eval & 0xff);
+ break;
// Fixup WORD forward references;
// the word could be unaligned in the section buffer, so we have to
// be careful.
}
}
- SETBE16(locp, 0, eval);
+ if (sno != M6502)
+ {
+ *locp++ = (char)(eval >> 8);
+ *locp = (char)eval;
+ }
+ else
+ {
+ SETBE16(locp, 0, eval);
+ }
break;
// Fixup LONG forward references;
// the long could be unaligned in the section buffer, so be careful
ResolveFixups(TEXT);
DEBUG printf("Resolving DATA sections...\n");
ResolveFixups(DATA);
+ DEBUG printf("Resolving 6502 sections...\n");
+ ResolveFixups(M6502); /* fixup 6502 section (if any) */
return 0;
}
*chptr++=(uint8_t)((lw)>>8); \
*chptr++=(uint8_t)(lw); \
sloc += 4; ch_size += 4; if(orgactive) orgaddr += 4;}
-//#define D_rword(w) {*chptr++=(uint8_t)w; *chptr++=(uint8_t)(w>>8); \
-// sloc+=2; ch_size+=2;if(orgactive) orgaddr += 2;}
+#define D_rword(w) {*chptr++=(uint8_t)w; *chptr++=(uint8_t)(w>>8); \
+ sloc+=2; ch_size+=2;if(orgactive) orgaddr += 2;}
//#define D_rlong(lw) {*chptr++=(uint8_t)(lw>>16);*chptr++=(uint8_t)(lw>>24);\
// *chptr++=(uint8_t)lw;*chptr++=(uint8_t)(lw>>8); \
// sloc+=4; ch_size += 4;if(orgactive) orgaddr += 4;}
#define FU_LONG 004 // Fixup long
#define FU_BBRA 005 // Fixup byte branch
#define FU_6BRA 007 // Fixup 6502-format branch offset
+#define FU_BYTEH 050 // Fixup 6502 high byte of immediate word
+#define FU_BYTEL 051 // Fixup 6502 low byte of immediate word
#define FU_SEXT 010 // Ok to sign extend
#define FU_PCREL 020 // Subtract PC first
#define FU_EXPR 040 // Expression (not symbol) follows
--- /dev/null
+; Compile me using "rmac -l6502tester.lst 6502tester.s" and open
+; 6502tester.lst to see and compare the output opcodes
+
+ .6502
+
+label:
+
+;ADC (ADd with Carry)
+
+; SYNTAX HEX LEN MODE
+ ADC #$44 ;$69 2 Immediate
+ ADC $44 ;$65 2 Zero Page
+ ADC $44,X ;$75 2 Zero Page,X
+ ADC $4400 ;$6D 3 Absolute
+ ADC $4400,X ;$7D 3 Absolute,X
+ ADC $4400,Y ;$79 3 Absolute,Y
+ ADC ($44,X) ;$61 2 Indirect,X
+ ADC ($44),Y ;$71 2 Indirect,Y
+
+;AND (bitwise AND with accumulator)
+
+; SYNTAX HEX LEN MODE
+ AND #$44 ;$29 2 Immediate
+ AND $44 ;$25 2 Zero Page
+ AND $44,X ;$35 2 Zero Page,X
+ AND $4400 ;$2D 3 Absolute
+ AND $4400,X ;$3D 3 Absolute,X
+ AND $4400,Y ;$39 3 Absolute,Y
+ AND ($44,X) ;$21 2 Indirect,X
+ AND ($44),Y ;$31 2 Indirect,Y
+
+;ASL (Arithmetic Shift Left)
+
+; SYNTAX HEX LEN MODE
+ ASL ;$0A 1 Accumulator (Implied)
+ ASL $44 ;$06 2 Zero Page
+ ASL $44,X ;$16 2 Zero Page,X
+ ASL $4400 ;$0E 3 Absolute
+ ASL $4400,X ;$1E 3 Absolute,X
+
+;BIT (test BITs)
+
+; SYNTAX HEX LEN MODE
+ BIT $44 ;$24 2 Zero Page
+ BIT $4400 ;$2C 3 Absolute
+
+;Branch Instructions
+
+;MNEMONIC HEX
+BPL label ;$10 (Branch on PLus)
+BMI label ;$30 (Branch on MInus)
+BVC label ;$50 (Branch on oVerflow Clear)
+BVS label ;$70 (Branch on oVerflow Set)
+BCC label ;$90 (Branch on Carry Clear)
+BCS label ;$B0 (Branch on Carry Set)
+BNE label ;$D0 (Branch on Not Equal)
+BEQ label ;$F0 (Branch on EQual)
+
+;BRK (BReaK)
+; SYNTAX HEX LEN ;MODE
+ BRK ;$00 1 ;Implied
+
+;CMP (CoMPare accumulator)
+
+; SYNTAX HEX LEN MODE
+ CMP #$44 ;$C9 2 Immediate
+ CMP $44 ;$C5 2 Zero Page
+ CMP $44,X ;$D5 2 Zero Page,X
+ CMP $4400 ;$CD 3 Absolute
+ CMP $4400,X ;$DD 3 Absolute,X
+ CMP $4400,Y ;$D9 3 Absolute,Y
+ CMP ($44,X) ;$C1 2 Indirect,X
+ CMP ($44),Y ;$D1 2 Indirect,Y
+
+;CPX (ComPare X register)
+
+; SYNTAX HEX LEN MODE
+ CPX #$44 ;$E0 2 Immediate
+ CPX $44 ;$E4 2 Zero Page
+ CPX $4400 ;$EC 3 Absolute
+
+;CPY (ComPare Y register)
+
+; SYNTAX HEX LEN MODE
+ CPY #$44 ;$C0 2 Immediate
+ CPY $44 ;$C4 2 Zero Page
+ CPY $4400 ;$CC 3 Absolute
+
+;DEC (DECrement memory)
+
+; SYNTAX HEX LEN MODE
+ DEC $44 ;$C6 2 Zero Page
+ DEC $44,X ;$D6 2 Zero Page,X
+ DEC $4400 ;$CE 3 Absolute
+ DEC $4400,X ;$DE 3 Absolute,X
+
+;EOR (bitwise Exclusive OR)
+
+; SYNTAX HEX LEN MODE
+ EOR #$44 ;$49 2 Immediate
+ EOR $44 ;$45 2 Zero Page
+ EOR $44,X ;$55 2 Zero Page,X
+ EOR $4400 ;$4D 3 Absolute
+ EOR $4400,X ;$5D 3 Absolute,X
+ EOR $4400,Y ;$59 3 Absolute,Y
+ EOR ($44,X) ;$41 2 Indirect,X
+ EOR ($44),Y ;$51 2 Indirect,Y
+
+;Flag (Processor Status) Instructions
+
+;MNEMONIC HEX
+CLC ;(CLear Carry) $18
+SEC ;(SEt Carry) $38
+CLI ;(CLear Interrupt) $58
+SEI ;(SEt Interrupt) $78
+CLV ;(CLear oVerflow) $B8
+CLD ;(CLear Decimal) $D8
+SED ;(SEt Decimal) $F8
+
+;INC (INCrement memory)
+
+; SYNTAX HEX LEN MODE
+ INC $44 ;$E6 2 ;Zero Page
+ INC $44,X ;$F6 2 ;Zero Page,X
+ INC $4400 ;$EE 3 ;Absolute
+ INC $4400,X ;$FE 3 ;Absolute,X
+
+;JMP (JuMP)
+
+; SYNTAX HEX LEN MODE
+ JMP $5597 ;$4C 3 Absolute
+ JMP ($5597) ;$6C 3 Indirect
+
+;JSR (Jump to SubRoutine)
+
+; SYNTAX HEX LEN MODE
+ JSR $5597 ;$20 3 Absolute
+
+;LDA (LoaD Accumulator)
+
+; SYNTAX HEX LEN MODE
+ LDA #$44 ;$A9 2 Immediate
+ LDA $44 ;$A5 2 Zero Page
+ LDA $44,X ;$B5 2 Zero Page,X
+ LDA $4400 ;$AD 3 Absolute
+ LDA $4400,X ;$BD 3 Absolute,X
+ LDA $4400,Y ;$B9 3 Absolute,Y
+ LDA ($44,X) ;$A1 2 Indirect,X
+ LDA ($44),Y ;$B1 2 Indirect,Y
+
+;LDX (LoaD X register)
+
+; SYNTAX HEX LEN MODE
+ LDX #$44 ;$A2 2 Immediate
+ LDX $44 ;$A6 2 Zero Page
+ LDX $44,Y ;$B6 2 Zero Page,Y
+ LDX $4400 ;$AE 3 Absolute
+ LDX $4400,Y ;$BE 3 Absolute,Y
+
+;LDY (LoaD Y register)
+
+; SYNTAX HEX LEN MODE
+ LDY #$44 ;$A0 2 Immediate
+ LDY $44 ;$A4 2 Zero Page
+ LDY $44,X ;$B4 2 Zero Page,X
+ LDY $4400 ;$AC 3 Absolute
+ LDY $4400,X ;$BC 3 Absolute,X
+
+;LSR (Logical Shift Right)
+
+; SYNTAX HEX LEN MODE
+ LSR ;$4A 1 Accumulator (Implied)
+ LSR $44 ;$46 2 Zero Page
+ LSR $44,X ;$56 2 Zero Page,X
+ LSR $4400 ;$4E 3 Absolute
+ LSR $4400,X ;$5E 3 Absolute,X
+
+;NOP (No OPeration)
+
+; SYNTAX HEX LEN MODE
+ NOP ;$EA 1 Implied
+
+;ORA (bitwise OR with Accumulator)
+
+; SYNTAX HEX LEN MODE
+ ORA #$44 ;$09 2 Immediate
+ ORA $44 ;$05 2 Zero Page
+ ORA $44,X ;$15 2 Zero Page,X
+ ORA $4400 ;$0D 3 Absolute
+ ORA $4400,X ;$1D 3 Absolute,X
+ ORA $4400,Y ;$19 3 Absolute,Y
+ ORA ($44,X) ;$01 2 Indirect,X
+ ORA ($44),Y ;$11 2 Indirect,Y
+
+;Register Instructions
+
+;MNEMONIC HEX
+TAX ;(Transfer A to X) $AA
+TXA ;(Transfer X to A) $8A
+DEX ;(DEcrement X) $CA
+INX ;(INcrement X) $E8
+TAY ;(Transfer A to Y) $A8
+TYA ;(Transfer Y to A) $98
+DEY ;(DEcrement Y) $88
+INY ;(INcrement Y) $C8
+
+;ROL (ROtate Left)
+
+; SYNTAX HEX LEN MODE
+ ROL ;$2A 1 Accumulator (Implied)
+ ROL $44 ;$26 2 Zero Page
+ ROL $44,X ;$36 2 Zero Page,X
+ ROL $4400 ;$2E 3 Absolute
+ ROL $4400,X ;$3E 3 Absolute,X
+
+;ROR (ROtate Right)
+
+; SYNTAX HEX LEN MODE
+ ROR ;$6A 1 Accumulator (Implied)
+ ROR $44 ;$66 2 Zero Page
+ ROR $44,X ;$76 2 Zero Page,X
+ ROR $4400 ;$6E 3 Absolute
+ ROR $4400,X ;$7E 3 Absolute,X
+
+;RTI (ReTurn from Interrupt)
+
+; SYNTAX HEX LEN MODE
+ RTI ;$40 1 Implied
+
+;RTS (ReTurn from Subroutine)
+
+; SYNTAX HEX LEN MODE
+ RTS ;$60 1 Implied
+
+;SBC (SuBtract with Carry)
+
+; SYNTAX HEX LEN MODE
+ SBC #$44 ;$E9 2 Immediate
+ SBC $44 ;$E5 2 Zero Page
+ SBC $44,X ;$F5 2 Zero Page,X
+ SBC $4400 ;$ED 3 Absolute
+ SBC $4400,X ;$FD 3 Absolute,X
+ SBC $4400,Y ;$F9 3 Absolute,Y
+ SBC ($44,X) ;$E1 2 Indirect,X
+ SBC ($44),Y ;$F1 2 Indirect,Y
+
+;STA (STore Accumulator)
+
+; SYNTAX HEX LEN MODE
+ STA $44 ;$85 2 Zero Page
+ STA $44,X ;$95 2 Zero Page,X
+ STA $4400 ;$8D 3 Absolute
+ STA $4400,X ;$9D 3 Absolute,X
+ STA $4400,Y ;$99 3 Absolute,Y
+ STA ($44,X) ;$81 2 Indirect,X
+ STA ($44),Y ;$91 2 Indirect,Y
+
+;Stack Instructions
+;MNEMONIC HEX
+TXS ;(Transfer X to Stack ptr) $9A
+TSX ;(Transfer Stack ptr to X) $BA
+PHA ;(PusH Accumulator) $48
+PLA ;(PuLl Accumulator) $68
+PHP ;(PusH Processor status) $08
+PLP ;(PuLl Processor status) $28
+
+;STX (STore X register)
+
+; SYNTAX HEX LEN MODE
+ STX $44 ;$86 2 ;Zero Page
+ STX $44,Y ;$96 2 ;Zero Page,Y
+ STX $4400 ;$8E 3 ;Absolute
+
+;STY (STore Y register)
+
+; SYNTAX HEX LEN MODE
+ STY $44 ;$84 2 ;Zero Page
+ STY $44,X ;$94 2 ;Zero Page,X
+ STY $4400 ;$8C 3 ;Absolute