diff options
-rw-r--r-- | src/65c816.c | 1572 | ||||
-rw-r--r-- | src/65c816.h | 43 | ||||
-rw-r--r-- | src/Makefile | 4 |
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 \ |