aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/65c816.c1572
-rw-r--r--src/65c816.h43
-rw-r--r--src/Makefile4
3 files changed, 1619 insertions, 0 deletions
diff --git a/src/65c816.c b/src/65c816.c
new file mode 100644
index 0000000..0fbf8bc
--- /dev/null
+++ b/src/65c816.c
@@ -0,0 +1,1572 @@
+/*
+
+ casm - Simple, portable assembler
+
+ Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ -------------------------------------------------------------------------
+
+ 65c816 Assembler
+
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "global.h"
+#include "expr.h"
+#include "label.h"
+#include "parse.h"
+#include "cmd.h"
+#include "codepage.h"
+
+#include "65c816.h"
+
+
+/* ---------------------------------------- TYPES AND GLOBALS
+*/
+
+/* Note some addressing modes are indistinguable and will never be returned,
+ for example STACK_IMMEDIATE or STACK_PC_LONG. They are kept here as a
+ memory aid.
+*/
+typedef enum
+{
+ ACCUMULATOR, /* A */
+ IMPLIED, /* none */
+ IMMEDIATE, /* #$nn */
+ ABSOLUTE, /* $nnnn */
+ ABSOLUTE_INDEX_X_INDIRECT, /* ($nnnn,X) */
+ ABSOLUTE_INDEX_X, /* $nnnn,X */
+ ABSOLUTE_INDEX_Y, /* $nnnn,Y */
+ ABSOLUTE_INDIRECT, /* ($nnnn) */
+ ABSOLUTE_INDIRECT_LONG, /* [$nnnn] */
+ ABSOLUTE_LONG, /* $nnnnnn */
+ ABSOLUTE_LONG_INDEX_X, /* $nnnnnn,X */
+ DIRECT_PAGE, /* $nn */
+ DIRECT_PAGE_INDEX_X, /* $nn,X */
+ DIRECT_PAGE_INDEX_Y, /* $nn,Y */
+ DIRECT_PAGE_INDIRECT, /* ($nn) */
+ DIRECT_PAGE_INDIRECT_LONG, /* [$nn] */
+ DIRECT_PAGE_INDEX_X_INDIRECT, /* ($nn,X) */
+ DIRECT_PAGE_INDEX_Y_INDIRECT, /* ($nn),Y */
+ DIRECT_PAGE_INDEX_Y_INDIRECT_LONG, /* [$nn],Y */
+ RELATIVE, /* rr */
+ RELATIVE_LONG, /* rrrr */
+ STACK_RELATIVE_INDIRECT_INDEX_Y, /* (sr,S),Y */
+ STACK_RELATIVE, /* sr,S */
+ STACK_IMMEDIATE /* #$nnnn */
+ STACK_DIRECT_PAGE_INDIRECT, /* ($nn) */
+ STACK_PC_LONG, /* #$nnnn */
+ ADDR_MODE_ERROR,
+ ADDR_MODE_UNKNOWN
+} address_mode_t;
+
+static const char *address_mode_name[ADDR_MODE_UNKNOWN+1] =
+{
+ "Accumulator",
+ "Implied",
+ "Immediate",
+ "Absolute",
+ "Absolute Index X, Indirect",
+ "Absolute, Index X",
+ "Absolute, Index Y",
+ "Absolute Indirect",
+ "Absolute Indirect Long",
+ "Absolute Long",
+ "Absolute Long, Index X",
+ "Direct Page",
+ "Direct Page, Index X",
+ "Direct Page, Index Y",
+ "Direct Page Indirect",
+ "Direct Page Indirect Long",
+ "Direct Page Index X, Indirect",
+ "Direct Page, Indirect, Index Y",
+ "Direct Page, Indirect, Index Y Long",
+ "Relative",
+ "Relative Long",
+ "Stack Relative Indirect Index Y",
+ "Stack Relative",
+ "Stack Immediate",
+ "Stack Direct Page Indirect",
+ "Stack Program Counter Relative Long:,
+ "Address Mode Error",
+ "Address Mode Unknown"
+};
+
+
+/* ---------------------------------------- MACROS
+*/
+#define CMD_ADDRESS_MODE(mode, address) \
+do \
+{ \
+ CalcAddressMode(argc, argv, quoted, err, errsize, &mode, &address); \
+ \
+ if (mode == ADDR_MODE_UNKNOWN) \
+ { \
+ snprintf(err, errsize, "%s: couldn't work out " \
+ "addressing mode", argv[0]); \
+ return CMD_FAILED; \
+ } \
+ \
+ if (mode == ADDR_MODE_ERROR) return CMD_FAILED; \
+} while(0)
+
+
+#define CMD_RANGE_ADDR_MODE(mode, dp_mode, norm_mode, long_mode, value) \
+do \
+{ \
+ if (value >= 0 && value <= 0xff) \
+ { \
+ *mode = dp_mode; \
+ } \
+ else if (value > 0xffff) \
+ { \
+ *mode = long_mode; \
+ } \
+ else \
+ { \
+ *mode = norm_mode; \
+ } \
+} while (0)
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void CalcAddressMode(int argc, char *argv[], int quoted[],
+ char *err, size_t errsize,
+ address_mode_t *mode, int *address)
+{
+ *mode = ADDR_MODE_UNKNOWN;
+ *address = 0;
+
+ /* Implied
+ */
+ if (argc == 1)
+ {
+ *mode = IMPLIED;
+ return;
+ }
+
+ /* Accumulator
+ */
+ if (argc == 2 && CompareString(argv[1], "A"))
+ {
+ *mode = ACCUMULATOR;
+ return;
+ }
+
+ /* Immediate
+ */
+ if (argc == 2 && argv[1][0] == '#')
+ {
+ *mode = IMMEDIATE;
+
+ if (!ExprEval(argv[1] + 1, address))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ argv[1], ExprError());
+ *mode = ADDR_MODE_ERROR;
+ }
+
+ return;
+ }
+
+
+ /* Absolute
+ */
+ if (argc == 2 && !quoted[1])
+ {
+ if (!ExprEval(argv[1], address))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ argv[1], ExprError());
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ CMD_RANGE_ADDR_MODE(mode,
+ DIRECT_PAGE,
+ ABSOLUTE,
+ ABSOLUTE_LONG,
+ address);
+
+ return;
+ }
+
+
+ /* Absolute,[XY]
+ */
+ if (argc == 3 && !quoted[1])
+ {
+ if (!ExprEval(argv[1], address))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ argv[1], ExprError());
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ if (CompareString(argv[2], "X"))
+ {
+ CMD_RANGE_ADDR_MODE(mode,
+ DIRECT_PAGE_INDEX_X,
+ ABSOLUTE_INDEX_X,
+ ABSOLUTE_LONG_INDEX_X,
+ address);
+ }
+ else if (CompareString(argv[2], "Y"))
+ {
+ CMD_RANGE_ADDR_MODE(mode,
+ DIRECT_PAGE_INDEX_X,
+ ABSOLUTE_INDEX_X,
+ ABSOLUTE_LONG_INDEX_X,
+ address);
+ }
+ else
+ {
+ snprintf(err, errsize, "unknown index register '%s'", argv[2]);
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ return;
+ }
+
+
+ /* (zp,x) or (ind)
+ */
+ if (argc == 2 && quoted[1] == '(')
+ {
+ char *addr;
+
+ if (!CompareEnd(argv[1], ",x"))
+ {
+ if (!ExprEval(argv[1], address))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ argv[1], ExprError());
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ *mode = INDIRECT;
+ return;
+ }
+
+ *mode = ZERO_PAGE_INDIRECT_X;
+
+ addr = DupStr(argv[1]);
+ *strchr(addr, ',') = 0;
+
+ if (!ExprEval(addr, address))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ addr, ExprError());
+ *mode = ADDR_MODE_ERROR;
+ free(addr);
+ return;
+ }
+
+ free(addr);
+
+ if (*address < 0 || *address > 255)
+ {
+ snprintf(err, errsize, "value %d outside of zero page", *address);
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ return;
+ }
+
+
+ /* (zp),y
+ */
+ if (argc == 3 && quoted[1] == '(')
+ {
+ *mode = ZERO_PAGE_INDIRECT_Y;
+
+ if (!CompareString(argv[2], "y"))
+ {
+ snprintf(err, errsize, "illegal index register '%s' used for "
+ "zero-page indirect", argv[2]);
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ if (!ExprEval(argv[1], address))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ argv[1], ExprError());
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ if (*address < 0 || *address > 255)
+ {
+ snprintf(err, errsize, "value %d outside of zero page", *address);
+ *mode = ADDR_MODE_ERROR;
+ return;
+ }
+
+ return;
+ }
+}
+
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+
+static CommandStatus DUMMY(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ACCUMULATOR:
+ return CMD_OK;
+
+ case IMPLIED:
+ return CMD_OK;
+
+ case IMMEDIATE:
+ return CMD_OK;
+
+ case ABSOLUTE:
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_Y:
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus ADC(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0x69);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x6d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x65);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x7d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0x79);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x75);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0x61);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0x71);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus AND(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0x29);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x2d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x25);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x3d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0x39);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x35);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0x21);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0x31);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus ASL(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMPLIED:
+ case ACCUMULATOR:
+ PCWrite(0x0a);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x0e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x06);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x1e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x16);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus BIT(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ PCWrite(0x2c);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x24);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus CMP(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xc9);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xcd);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xc5);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0xdd);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0xd9);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0xd5);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0xc1);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0xd1);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus CPX(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xe0);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xec);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xe4);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus CPY(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xc0);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xcc);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xc4);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus DEC(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ PCWrite(0xce);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xc6);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0xde);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0xd6);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus EOR(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0x49);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x4d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x45);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x5d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0x59);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x55);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0x41);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0x51);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus INC(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ PCWrite(0xee);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xe6);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0xfe);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0xf6);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus JMP(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ case ZERO_PAGE:
+ PCWrite(0x4c);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case INDIRECT:
+ PCWrite(0x6c);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus JSR(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ case ZERO_PAGE:
+ PCWrite(0x20);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus LDA(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xa9);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xad);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xa5);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0xbd);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0xb9);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0xb5);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0xa1);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0xb1);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus LDX(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xa2);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xae);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xa6);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ PCWrite(0xbe);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0xb6);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus LDY(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xa0);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xac);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xa4);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0xbc);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0xb4);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus LSR(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMPLIED:
+ case ACCUMULATOR:
+ PCWrite(0x4a);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x4e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x46);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x5e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x56);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus ORA(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0x09);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x0d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x05);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x1d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0x19);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x15);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0x01);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0x11);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus ROL(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMPLIED:
+ case ACCUMULATOR:
+ PCWrite(0x2a);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x2e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x26);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x3e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x36);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus ROR(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMPLIED:
+ case ACCUMULATOR:
+ PCWrite(0x6a);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0x6e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x66);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x7e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x76);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus SBC(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case IMMEDIATE:
+ PCWrite(0xe9);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE:
+ PCWrite(0xed);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0xe5);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0xfd);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0xf9);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0xf5);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0xe1);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0xf1);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus STA(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ PCWrite(0x8d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x85);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ PCWrite(0x9d);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0x99);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x95);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_X:
+ PCWrite(0x81);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDIRECT_Y:
+ PCWrite(0x91);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus STX(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ PCWrite(0x8e);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x86);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_Y:
+ if (address < 0 || address > 255)
+ {
+ snprintf(err, errsize, "%s: value %d outside of zero page",
+ argv[0], address);
+ return CMD_FAILED;
+ }
+
+ PCWrite(0x96);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_Y:
+ PCWrite(0x96);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus STY(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int address;
+
+ CMD_ADDRESS_MODE(mode, address);
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ PCWrite(0x8c);
+ PCWriteWord(address);
+ return CMD_OK;
+
+ case ZERO_PAGE:
+ PCWrite(0x84);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ABSOLUTE_INDEX_X:
+ if (address < 0 || address > 255)
+ {
+ snprintf(err, errsize, "%s: value %d outside of zero page",
+ argv[0], address);
+ return CMD_FAILED;
+ }
+
+ PCWrite(0x94);
+ PCWrite(address);
+ return CMD_OK;
+
+ case ZERO_PAGE_INDEX_X:
+ PCWrite(0x94);
+ PCWrite(address);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+ }
+}
+
+/* ---------------------------------------- OPCODE TABLES
+*/
+typedef struct
+{
+ const char *op;
+ int code;
+} OpcodeTable;
+
+typedef struct
+{
+ const char *op;
+ Command cmd;
+} HandlerTable;
+
+static const OpcodeTable implied_opcodes[] =
+{
+ {"NOP", 0xea},
+ {"TXS", 0x9a},
+ {"TSX", 0xba},
+ {"PHA", 0x48},
+ {"PLA", 0x68},
+ {"PHP", 0x08},
+ {"PLP", 0x28},
+ {"CLC", 0x18},
+ {"SEC", 0x38},
+ {"CLI", 0x58},
+ {"SEI", 0x78},
+ {"CLV", 0xb8},
+ {"CLD", 0xd8},
+ {"SED", 0xf8},
+ {"BRK", 0x00},
+ {"TAX", 0xaa},
+ {"TXA", 0x8a},
+ {"DEX", 0xca},
+ {"INX", 0xe8},
+ {"TAY", 0xa8},
+ {"TYA", 0x98},
+ {"DEY", 0x88},
+ {"INY", 0xc8},
+ {"RTI", 0x40},
+ {"RTS", 0x60},
+ {NULL}
+};
+
+
+static const OpcodeTable branch_opcodes[] =
+{
+ {"BPL", 0x10},
+ {"BMI", 0x30},
+ {"BVC", 0x50},
+ {"BVS", 0x70},
+ {"BCC", 0x90},
+ {"BCS", 0xB0},
+ {"BNE", 0xD0},
+ {"BEQ", 0xF0},
+ {NULL}
+};
+
+
+static const HandlerTable handler_table[] =
+{
+ {"ADC", ADC},
+ {"AND", AND},
+ {"ASL", ASL},
+ {"BIT", BIT},
+ {"CMP", CMP},
+ {"CPX", CPX},
+ {"CPY", CPY},
+ {"DEC", DEC},
+ {"EOR", EOR},
+ {"INC", INC},
+ {"JMP", JMP},
+ {"JSR", JSR},
+ {"LDA", LDA},
+ {"LDX", LDX},
+ {"LDY", LDY},
+ {"LSR", LSR},
+ {"ORA", ORA},
+ {"ROL", ROL},
+ {"ROR", ROR},
+ {"SBC", SBC},
+ {"STA", STA},
+ {"STX", STX},
+ {"STY", STY},
+ {NULL}
+};
+
+
+
+
+/* ---------------------------------------- PUBLIC FUNCTIONS
+*/
+
+void Init_65c816(void)
+{
+ SetNeededPasses(3);
+}
+
+
+const ValueTable *Options_65c816(void)
+{
+ return NULL;
+}
+
+CommandStatus SetOption_65c816(int opt, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ return CMD_OK;
+}
+
+CommandStatus Handler_65c816(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ int f;
+
+ /* Check for simple (implied addressing) opcodes
+ */
+ for(f = 0; implied_opcodes[f].op; f++)
+ {
+ if (CompareString(argv[0], implied_opcodes[f].op))
+ {
+ PCWrite(implied_opcodes[f].code);
+ return CMD_OK;
+ }
+ }
+
+ /* Check for branch opcodes
+ */
+ for(f = 0; branch_opcodes[f].op; f++)
+ {
+ if (CompareString(argv[0], branch_opcodes[f].op))
+ {
+ int offset;
+
+ CMD_ARGC_CHECK(2);
+
+ CMD_EXPR(argv[1], offset);
+
+ offset = offset - (PC() + 2);
+
+ if (IsFinalPass() && (offset < -128 || offset > 127))
+ {
+ snprintf(err, errsize, "%s: Branch offset (%d) too big",
+ argv[1], offset);
+ return CMD_FAILED;
+ }
+
+ PCWrite(branch_opcodes[f].code);
+ PCWrite(offset);
+
+ return CMD_OK;
+ }
+ }
+
+
+ /* Check for other opcodes
+ */
+ for(f = 0; handler_table[f].op; f++)
+ {
+ if (CompareString(argv[0], handler_table[f].op))
+ {
+ return handler_table[f].cmd(label, argc, argv,
+ quoted, err, errsize);;
+ }
+ }
+
+
+ return CMD_NOT_KNOWN;
+}
+
+
+/*
+vim: ai sw=4 ts=8 expandtab
+*/
diff --git a/src/65c816.h b/src/65c816.h
new file mode 100644
index 0000000..be972ec
--- /dev/null
+++ b/src/65c816.h
@@ -0,0 +1,43 @@
+/*
+
+ casm - Simple, portable assembler
+
+ Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ -------------------------------------------------------------------------
+
+ 65c816 Assembler
+
+*/
+
+#ifndef CASM_65c816_H
+#define CASM_65c816_H
+
+void Init_65c816(void);
+
+const ValueTable *Options_65c816(void);
+
+CommandStatus SetOption_65c816(int opt, int argc, char *argv[], int quoted[],
+ char *error, size_t error_size);
+
+CommandStatus Handler_65c816(const char *label, int argc, char *argv[],
+ int quoted[], char *error, size_t error_size);
+
+#endif
+
+/*
+vim: ai sw=4 ts=8 expandtab
+*/
diff --git a/src/Makefile b/src/Makefile
index baadcb4..4f7ec33 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -38,6 +38,7 @@ SOURCE = casm.c \
listing.c \
alias.c \
6502.c \
+ 65c816.c \
z80.c \
gbcpu.c \
rawout.c \
@@ -60,6 +61,7 @@ OBJECTS = casm.o \
listing.o \
alias.o \
6502.o \
+ 65c816.o \
z80.o \
gbcpu.o \
rawout.o \
@@ -76,6 +78,8 @@ clean:
6502.o: 6502.c global.h basetype.h util.h state.h expr.h label.h parse.h \
cmd.h codepage.h 6502.h
+65c816.o: 65c816.c global.h basetype.h util.h state.h expr.h label.h \
+ parse.h cmd.h codepage.h 65c816.h
alias.o: alias.c global.h basetype.h util.h state.h alias.h
casm.o: casm.c global.h basetype.h util.h state.h expr.h label.h macro.h \
cmd.h parse.h codepage.h stack.h listing.h alias.h output.h rawout.h \