From: ggn Date: Wed, 19 Apr 2017 16:42:26 +0000 (+0300) Subject: 6502 support added back from original Madmac sources! X-Git-Tag: v2.1.0~139 X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=commitdiff_plain;h=052be802baa4836564801c780b1d432cfe17c576 6502 support added back from original Madmac sources! - Source fixed to work with current rmac implementation - Removed ultra kludgy output mode and replaced it with .com/.exe./.xex output module (activated using -fx) - Added #< and #> to give low and high bytes off an immediate word - Included tester in "tests" folder. - Updated docs. --- diff --git a/6502.c b/6502.c new file mode 100644 index 0000000..823263a --- /dev/null +++ b/6502.c @@ -0,0 +1,559 @@ +/* + * 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 ')' 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 ',' */ + 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; + } + +} diff --git a/6502.tbl b/6502.tbl new file mode 100644 index 0000000..52cfdca --- /dev/null +++ b/6502.tbl @@ -0,0 +1,59 @@ +# +# 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 diff --git a/direct.c b/direct.c index e9eb8ac..15ce236 100644 --- a/direct.c +++ b/direct.c @@ -21,7 +21,6 @@ #define DEF_KW #include "kwtab.h" - TOKEN exprbuf[128]; // Expression buffer SYM * symbolPtr[1000000]; // Symbol pointers table static long unused; // For supressing 'write' warnings @@ -32,7 +31,7 @@ char buffer[256]; // Scratch buffer for messages 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 @@ -139,24 +138,53 @@ int d_warn(char *str) // 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; + } } @@ -467,6 +495,9 @@ static inline void SkipBytes(unsigned bytesToSkip) // int d_even(void) { + if (m6502) + return error(in_6502mode); + unsigned skip = (rgpu || rdsp ? orgaddr : sloc) & 0x01; if (skip) @@ -562,6 +593,8 @@ int d_qphrase(void) // void auto_even(void) { + if (cursect != M6502) + { if (scattr & SBSS) sloc++; // Bump BSS section else @@ -569,6 +602,7 @@ void auto_even(void) if (lab_sym != NULL) // Bump label if we have to lab_sym->svalue++; + } } @@ -737,6 +771,9 @@ int globl1(char * p) int d_globl(void) { + if (m6502) + return error(in_6502mode); + symlist(globl1); return 0; } @@ -770,6 +807,9 @@ int d_abs(void) { VALUE eval; + if (m6502) + return error(in_6502mode); + SaveSection(); if (*tok == EOL) @@ -790,6 +830,8 @@ int d_text(void) { if (rgpu || rdsp) return error("directive forbidden in gpu/dsp mode"); + if (m6502) + return error(in_6502mode); if (cursect != TEXT) { @@ -805,6 +847,8 @@ int d_data(void) { if (rgpu || rdsp) return error("directive forbidden in gpu/dsp mode"); + if (m6502) + return error(in_6502mode); if (cursect != DATA) { @@ -820,6 +864,8 @@ int d_bss(void) { if (rgpu || rdsp) return error("directive forbidden in gpu/dsp mode"); + if (m6502) + return error(in_6502mode); if (cursect != BSS) { @@ -840,8 +886,11 @@ int d_ds(WORD siz) 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; @@ -854,11 +903,12 @@ int d_ds(WORD siz) // 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 @@ -884,7 +934,7 @@ int d_dc(WORD siz) 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 @@ -971,11 +1021,22 @@ int d_dc(WORD siz) 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) @@ -1030,7 +1091,7 @@ int d_dcb(WORD siz) 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); @@ -1160,11 +1221,22 @@ int dep_block(VALUE count, WORD siz, VALUE eval, WORD eattr, TOKEN * 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); @@ -1195,6 +1267,9 @@ int d_comm(void) char * p; VALUE eval; + if (m6502) + return error(in_6502mode); + if (*tok != SYMBOL) return error("missing symbol"); diff --git a/direct.h b/direct.h index 6ce7d45..57cdd63 100644 --- a/direct.h +++ b/direct.h @@ -15,6 +15,10 @@ 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); diff --git a/docs/rmac.rst b/docs/rmac.rst index 91571d9..f6f445e 100644 --- a/docs/rmac.rst +++ b/docs/rmac.rst @@ -15,7 +15,7 @@ the accuracy of printed or duplicated material after the date of publication and disclaims liability for changes, errors or omissions.* -*Copyright © 2011-2015, Reboot* +*Copyright © 2011-2017, Reboot* *All rights reserved.* @@ -52,10 +52,6 @@ with an editor should allow you to assemble your current source files. If you ar 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`_ @@ -968,6 +964,53 @@ described in the chapter on `6502 Support`_. 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 @@ -1588,6 +1631,8 @@ the Atari Coinop assembler. *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 @@ -1600,10 +1645,6 @@ x,\ *expr* indexed X 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** @@ -1643,43 +1684,17 @@ extracted with the bitwise AND (``&``) operator. `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> - - - - -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`_ ================= diff --git a/listing.c b/listing.c index 3d63256..68d6c6f 100644 --- a/listing.c +++ b/listing.c @@ -301,11 +301,14 @@ void listeol(void) { 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) @@ -331,7 +334,8 @@ nochunk: 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; diff --git a/makefile b/makefile index c9260ff..99325d6 100644 --- a/makefile +++ b/makefile @@ -26,15 +26,15 @@ HOSTCC = gcc 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 @@ -53,6 +53,9 @@ mntab.h : mntab 68kmn kwgen kwtab.h : kwtab kwgen ./kwgen kw kwtab.h +6502.h : 6502.tbl kwgen + ./kwgen mp <6502.tbl >6502.h + risckw.h : kwtab kwgen ./kwgen mr risckw.h @@ -124,6 +127,9 @@ sect.o : sect.c 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 diff --git a/object.c b/object.c index cbedaab..3cae547 100644 --- a/object.c +++ b/object.c @@ -12,7 +12,7 @@ #include "riscasm.h" #include "sect.h" #include "symbol.h" - +extern void m6502obj(int ofd); //#define DEBUG_ELF @@ -752,6 +752,11 @@ for(int j=0; j +#include "rmac.h" #define BSDHDRSIZE 0x20 // Size of BSD header #define HDRSIZE 0x1C // Size of Alcyon header diff --git a/procln.c b/procln.c index dd89806..4afd538 100644 --- a/procln.c +++ b/procln.c @@ -29,6 +29,12 @@ #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 @@ -566,6 +572,44 @@ When checking to see if it's already been equated, issue a warning. 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)) diff --git a/procln.h b/procln.h index c645722..4acf856 100644 --- a/procln.h +++ b/procln.h @@ -22,6 +22,7 @@ extern int just_bss; extern VALUE pcloc; extern SYM * lab_sym; extern LONG amsktab[]; +extern char in_6502mode[]; // Prototypes void InitLineProcessor(void); diff --git a/riscasm.c b/riscasm.c index 2c291ff..fb29b5a 100644 --- a/riscasm.c +++ b/riscasm.c @@ -23,7 +23,7 @@ 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 diff --git a/rmac.c b/rmac.c index 084f898..6bf5a50 100644 --- a/rmac.c +++ b/rmac.c @@ -25,6 +25,7 @@ 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 @@ -129,6 +130,7 @@ void DisplayHelp(void) " 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" @@ -250,6 +252,7 @@ int Process(int argc, char ** argv) 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 @@ -260,6 +263,7 @@ int Process(int argc, char ** argv) InitMark(); // Mark tape-recorder InitMacro(); // Macro processor InitListing(); // Listing generator + Init6502(); // 6502 assembler // Process command line arguments and assemble source files for(argno=0; argnoscattr; sloc = p->sloc; @@ -409,6 +412,12 @@ int ResolveFixups(int sno) 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 @@ -583,6 +592,25 @@ int ResolveFixups(int sno) *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. @@ -713,7 +741,15 @@ int ResolveFixups(int sno) } } - 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 @@ -793,6 +829,8 @@ int ResolveAllFixups(void) 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; } diff --git a/sect.h b/sect.h index b4c3733..d34dec2 100644 --- a/sect.h +++ b/sect.h @@ -24,8 +24,8 @@ *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;} @@ -67,6 +67,8 @@ #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 diff --git a/tests/6502tester.s b/tests/6502tester.s new file mode 100644 index 0000000..852b4fb --- /dev/null +++ b/tests/6502tester.s @@ -0,0 +1,279 @@ +; 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