From 5e6a1c3434b96ea16485b160c25732df3b00b2b8 Mon Sep 17 00:00:00 2001 From: Ian C Date: Thu, 12 May 2016 15:28:32 +0100 Subject: Started on SPC700 Also: * Added offset to import command. Realised fairly useless, but may as well keep it. * Added setting of address space size to state for PC. --- doc/casm.html | 6 +- src/Makefile | 8 +- src/casm.c | 34 +- src/label.c | 4 +- src/label.h | 5 +- src/libout.c | 6 +- src/libout.h | 2 +- src/spc700.c | 1492 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/spc700.h | 43 ++ src/state.c | 17 + src/state.h | 5 + src/test/link | 4 +- 12 files changed, 1598 insertions(+), 28 deletions(-) create mode 100644 src/spc700.c create mode 100644 src/spc700.h diff --git a/doc/casm.html b/doc/casm.html index e0f0299..bbef8ea 100644 --- a/doc/casm.html +++ b/doc/casm.html @@ -346,11 +346,13 @@ the skipped bytes unless the optional fill is supplied. -import filename[, labels] +import filename[, labels|all[, offset]] Includes a simple library file as generated by casm. See the section on simple library files for more details. If the optional second -argument is set to labels then only the label values are imported. +argument is set to labels then only the label values are imported, otherwise +both memory and labels are imported. If the optional offset is given +then that offset is added onto the load address and defined labels. diff --git a/src/Makefile b/src/Makefile index ea8c7a9..fe9fc6d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -40,6 +40,7 @@ SOURCE = casm.c \ 6502.c \ 65c816.c \ z80.c \ + spc700.c \ gbcpu.c \ rawout.c \ specout.c \ @@ -65,6 +66,7 @@ OBJECTS = casm.o \ 6502.o \ 65c816.o \ z80.o \ + spc700.o \ gbcpu.o \ rawout.o \ specout.o \ @@ -88,7 +90,7 @@ 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 \ specout.h t64out.h zx81out.h gbout.h snesout.h libout.h z80.h 6502.h \ - gbcpu.h 65c816.h + gbcpu.h 65c816.h spc700.h codepage.o: codepage.c global.h basetype.h util.h state.h codepage.h \ parse.h cmd.h expr.o: expr.c global.h basetype.h util.h state.h expr.h label.h @@ -99,7 +101,7 @@ gbout.o: gbout.c global.h basetype.h util.h state.h expr.h codepage.h \ label.o: label.c global.h basetype.h util.h state.h codepage.h parse.h \ cmd.h stack.h label.h libout.o: libout.c global.h basetype.h util.h state.h libout.h parse.h \ - cmd.h + cmd.h label.h listing.o: listing.c global.h basetype.h util.h state.h label.h macro.h \ cmd.h parse.h expr.h varchar.h listing.h macro.o: macro.c global.h basetype.h util.h state.h codepage.h parse.h \ @@ -112,6 +114,8 @@ rawout.o: rawout.c global.h basetype.h util.h state.h rawout.h parse.h \ cmd.h snesout.o: snesout.c global.h basetype.h util.h state.h expr.h codepage.h \ parse.h cmd.h snesout.h +spc700.o: spc700.c global.h basetype.h util.h state.h expr.h label.h \ + parse.h cmd.h codepage.h spc700.h specout.o: specout.c global.h basetype.h util.h state.h specout.h parse.h \ cmd.h stack.o: stack.c global.h basetype.h util.h state.h stack.h diff --git a/src/casm.c b/src/casm.c index 9e5c68e..1fa6d03 100644 --- a/src/casm.c +++ b/src/casm.c @@ -48,6 +48,7 @@ #include "6502.h" #include "gbcpu.h" #include "65c816.h" +#include "spc700.h" /* ---------------------------------------- MACROS @@ -76,7 +77,7 @@ static const char *casm_usage = typedef struct { const char *name; - int mem_size; + int address_space; WordMode word_mode; void (*init)(void); const ValueTable *(*options)(void); @@ -124,6 +125,12 @@ static const CPU cpu_table[]= LSB_Word, Init_65c816, Options_65c816, SetOption_65c816, Handler_65c816 }, + { + "spc700", + 0x10000, + LSB_Word, + Init_SPC700, Options_SPC700, SetOption_SPC700, Handler_SPC700 + }, {NULL} }; @@ -416,6 +423,7 @@ static CommandStatus ARCH(const char *label, int argc, char *argv[], { cpu = cpu_table + f; SetWordMode(cpu->word_mode); + SetAddressSpace(cpu->address_space); return CMD_OK; } } @@ -509,25 +517,22 @@ static CommandStatus NULLCMD(const char *label, int argc, char *argv[], static CommandStatus IMPORT(const char *label, int argc, char *argv[], int quoted[], char *err, size_t errsize) { + LibLoadOption opt = LibLoadAll; + int offset = 0; + CMD_ARGC_CHECK(2); - if (argc == 3) + if (argc >= 3 && CompareString(argv[2], "labels")) { - if (CompareString(argv[2], "labels")) - { - return LibLoad(argv[1], LibLoadLabels, err, errsize) ? - CMD_OK : CMD_FAILED; - } - else - { - snprintf(err, errsize, "%s: unknown argument %s", argv[0], argv[2]); - return CMD_FAILED; - } + opt = LibLoadLabels; } - else + + if (argc >= 4) { - return LibLoad(argv[1], LibLoadAll, err, errsize) ? CMD_OK : CMD_FAILED; + CMD_EXPR(argv[3], offset); } + + return LibLoad(argv[1], opt, offset, err, errsize) ? CMD_OK : CMD_FAILED; } @@ -711,6 +716,7 @@ static void InitProcessors(void) } SetWordMode(cpu->word_mode); + SetAddressSpace(cpu->address_space); } diff --git a/src/label.c b/src/label.c index 78a4793..449f4d0 100644 --- a/src/label.c +++ b/src/label.c @@ -550,7 +550,7 @@ void LabelWriteBlob(FILE *fp) } -void LabelReadBlob(FILE *fp) +void LabelReadBlob(FILE *fp, int offset) { int count; int f; @@ -565,7 +565,7 @@ void LabelReadBlob(FILE *fp) ReadName(fp, name); value = ReadNumber(fp); - LabelSet(name, value, GLOBAL_LABEL); + LabelSet(name, value + offset, GLOBAL_LABEL); } } diff --git a/src/label.h b/src/label.h index a190154..a7cb720 100644 --- a/src/label.h +++ b/src/label.h @@ -121,9 +121,10 @@ void LabelDump(FILE *fp, int dump_private); void LabelWriteBlob(FILE *fp); -/* Read a binary blob of information containing all the labels +/* Read a binary blob of information containing all the labels, adjusting values + by the passed offset. */ -void LabelReadBlob(FILE *fp); +void LabelReadBlob(FILE *fp, int offset); #endif diff --git a/src/libout.c b/src/libout.c index f9ca74f..000b7a9 100644 --- a/src/libout.c +++ b/src/libout.c @@ -117,7 +117,7 @@ int LibOutput(const char *filename, const char *filename_bank, } -int LibLoad(const char *filename, LibLoadOption opt, +int LibLoad(const char *filename, LibLoadOption opt, int offset, char *error, size_t error_size) { char magic[CASM_LIBRARY_MAGIC_LEN + 1] = {0}; @@ -163,7 +163,7 @@ int LibLoad(const char *filename, LibLoadOption opt, fread(buff, 1, len, fp); - SetPC(min); + SetPC((min + offset)); p = buff; if (opt != LibLoadLabels) @@ -180,7 +180,7 @@ int LibLoad(const char *filename, LibLoadOption opt, if (opt != LibLoadMemory) { - LabelReadBlob(fp); + LabelReadBlob(fp, offset); } fclose(fp); diff --git a/src/libout.h b/src/libout.h index 40cfc87..7175d27 100644 --- a/src/libout.h +++ b/src/libout.h @@ -58,7 +58,7 @@ int LibOutput(const char *filename, const char *filename_bank, /* Load a libray. Returns TRUE if OK, FALSE for failure and updates error. */ -int LibLoad(const char *filename, LibLoadOption opt, +int LibLoad(const char *filename, LibLoadOption opt, int offset, char *error, size_t error_size); #endif diff --git a/src/spc700.c b/src/spc700.c new file mode 100644 index 0000000..b1a3914 --- /dev/null +++ b/src/spc700.c @@ -0,0 +1,1492 @@ +/* + + casm - Simple, portable assembler + + Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.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 . + + ------------------------------------------------------------------------- + + SPC700 Assembler + +*/ +#include +#include + +#include "global.h" +#include "expr.h" +#include "label.h" +#include "parse.h" +#include "cmd.h" +#include "codepage.h" + +#include "spc700.h" + + +/* ---------------------------------------- TYPES AND GLOBALS +*/ +enum option_t +{ + OPT_ZP +}; + +enum zp_mode_t +{ + ZP_OFF, + ZP_ON, + ZP_AUTO +}; + +static const ValueTable options[] = +{ + {"zero-page", OPT_ZP}, + {NULL} +}; + +static const ValueTable zp_table[] = +{ + YES_NO_ENTRIES(ZP_ON, ZP_OFF), + {"auto", ZP_AUTO}, + {NULL} +}; + +static struct +{ + enum zp_mode_t zp_mode; +} option; + + +typedef enum +{ + ACCUMULATOR, + X_REGISTER, + Y_REGISTER, + YA_REGISTER, + SP_REGISTER, + C_FLAG, + PSW_REGISTER, + NOTTED_BIT, + INDIRECT_X, + INDIRECT_Y, + INDIRECT_X_INC, + IMPLIED, + IMMEDIATE, + ABSOLUTE, + DIRECT_PAGE, + ABSOLUTE_INDEX_X, + ABSOLUTE_INDEX_Y, + DIRECT_PAGE_INDEX_X, + DIRECT_PAGE_INDEX_Y, + DIRECT_PAGE_INDIRECT_X, + DIRECT_PAGE_INDIRECT_Y, + ADDR_MODE_ERROR, + ADDR_MODE_UNKNOWN +} address_mode_t; + +static const char *address_mode_name[] = +{ + "Accumulator", + "X register", + "Y register", + "YA register", + "Stack Pointer", + "Carry flag", + "PSW register", + "Notted (/) bit", + "Indirect X", + "Indirect Y", + "Indirect X increment", + "Implied", + "Immediate", + "Absolute", + "Direct Page", + "Absolute, index X", + "Absolute, index Y", + "Direct Page, index X", + "Direct Page, index Y", + "Direct Page, indirect X", + "Direct Page, indirect Y", + "Address Mode Error", + "Address Mode Unknown" +}; + + +typedef enum +{ + WB_LHS = -1, + WW_LHS = -2, + WB_RHS = -3, + WW_RHS = -4 +} StreamCodes; + + +typedef struct +{ + address_mode_t lhs; + address_mode_t rhs; + int code[10]; +} RegisterPairCodes; + +#define NUM_REGISTER_CODES(a) ((sizeof a)/(sizeof a[1])) + + + +/* ---------------------------------------- MACROS +*/ + +#define ADDRESS_MODE(mode, address, idx) \ +do \ +{ \ + CalcAddressMode(argc, argv, quoted, idx, 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_ZP_MODE(ZP_mode, non_ZP_mode) \ +do \ +{ \ + switch(option.zp_mode) \ + { \ + case ZP_ON: \ + if (*address < 0 || *address > 255) \ + { \ + snprintf(err, errsize, "value %d outside of " \ + "zero page", *address); \ + *mode = ADDR_MODE_ERROR; \ + return; \ + } \ + \ + *mode = ZP_mode; \ + break; \ + \ + case ZP_OFF: \ + *mode = non_ZP_mode; \ + break; \ + \ + case ZP_AUTO: \ + if (*address >= 0 && *address <= 255) \ + { \ + *mode = ZP_mode; \ + } \ + else \ + { \ + *mode = non_ZP_mode; \ + } \ + break; \ + } \ +} while (0) + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void CalcAddressMode(int argc, char *argv[], int quoted[], int index, + char *err, size_t errsize, + address_mode_t *mode, int *address) +{ + char *arg; + int quote; + + *mode = ADDR_MODE_UNKNOWN; + *address = 0; + + /* Implied + */ + if (argc == 1) + { + *mode = IMPLIED; + return; + } + + arg = argv[index]; + quote = quoted[index]; + + /* Accumulator and other simple fixed string register modes + */ + if (CompareString(arg, "A")) + { + *mode = ACCUMULATOR; + return; + } + + if (CompareString(arg, "C")) + { + *mode = C_FLAG; + return; + } + + if (CompareString(arg, "PSW")) + { + *mode = PSW_REGISTER; + return; + } + + if (CompareString(arg, "X")) + { + if (quote == '(') + { + *mode = INDIRECT_X; + } + else + { + *mode = X_REGISTER; + } + return; + } + + if (CompareString(arg, "Y")) + { + if (quote == '(') + { + *mode = INDIRECT_Y; + } + else + { + *mode = Y_REGISTER; + } + return; + } + + if (CompareString(arg, "YA")) + { + *mode = YA_REGISTER; + return; + } + + if (CompareString(arg, "SP")) + { + *mode = SP_REGISTER; + return; + } + + if (CompareString(arg, "(X)+")) + { + *mode = INDIRECT_X_INC; + return; + } + + /* 'Notted' bit + */ + if (arg[0] == '/') + { + *mode = NOTTED_BIT; + + if (!ExprEval(arg + 1, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + arg + 1, ExprError()); + *mode = ADDR_MODE_ERROR; + } + + return; + } + + /* Immediate + */ + if (arg[0] == '#') + { + *mode = IMMEDIATE; + + if (!ExprEval(arg + 1, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + arg + 1, ExprError()); + *mode = ADDR_MODE_ERROR; + } + + return; + } + + /* Address modes involving '+' character + */ + if (strchr(arg, '+')) + { + char *copy; + char *end; + + copy = DupStr(arg); + end = strrchr(copy, '+'); + *end++ = 0; + + /* Direct page indirect X + */ + if (quote == '(' && CompareString(end, "X")) + { + if (!ExprEval(copy, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + copy, ExprError()); + *mode = ADDR_MODE_ERROR; + } + else + { + *mode = DIRECT_PAGE_INDIRECT_X; + } + + free(copy); + return; + } + + /* Direct page indirect Y + */ + if (!quote && *copy == '(' && CompareString(end, "Y")) + { + if (!ExprEval(copy + 1, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + copy + 1, ExprError()); + *mode = ADDR_MODE_ERROR; + } + else + { + *mode = DIRECT_PAGE_INDIRECT_Y; + } + + free(copy); + return; + } + + /* Direct page or absolute index X + */ + if (!quote && CompareString(end, "X")) + { + if (!ExprEval(copy, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + copy, ExprError()); + *mode = ADDR_MODE_ERROR; + } + else + { + CMD_ZP_MODE(DIRECT_PAGE_INDEX_X, ABSOLUTE_INDEX_X); + } + + free(copy); + return; + } + + /* Direct page or absolute index Y + */ + if (!quote && CompareString(end, "Y")) + { + if (!ExprEval(copy, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + copy, ExprError()); + *mode = ADDR_MODE_ERROR; + } + else + { + CMD_ZP_MODE(DIRECT_PAGE_INDEX_Y, ABSOLUTE_INDEX_Y); + } + + free(copy); + return; + } + + free(copy); + } + + /* If all else fails, Absolute + */ + if (!ExprEval(arg, address)) + { + snprintf(err, errsize, "%s: expression error: %s", + arg, ExprError()); + *mode = ADDR_MODE_ERROR; + return; + } + + CMD_ZP_MODE(DIRECT_PAGE, ABSOLUTE); +} + + +static int WriteRegisterPairModes(const char *caller, + const RegisterPairCodes *codes, size_t count, + address_mode_t lhs, address_mode_t rhs, + int val_lhs, int val_rhs, + char *err, size_t errsize) +{ + size_t f; + + for(f = 0; f < count; f++) + { + if (codes[f].lhs == lhs && codes[f].rhs == rhs) + { + int r; + + for(r = 0; codes[f].code[r]; r++) + { + switch(codes[f].code[r]) + { + case WB_LHS: + PCWrite(val_lhs); + break; + + case WW_LHS: + PCWriteWord(val_lhs); + break; + + case WB_RHS: + PCWrite(val_rhs); + break; + + case WW_RHS: + PCWriteWord(val_rhs); + break; + + default: + PCWrite(codes[f].code[r]); + break; + } + } + return TRUE; + } + } + + snprintf(err, errsize, "%s: no code generation for register pair %s/%s", + caller, address_mode_name[lhs], address_mode_name[rhs]); + + return FALSE; +} + + + +/* ---------------------------------------- COMMAND HANDLERS +*/ + +#define COMMON_ALU(base) \ +do { \ +static RegisterPairCodes codes[] = \ +{ \ + {ACCUMULATOR, IMMEDIATE, {base + 0x08, WB_RHS}}, \ + {ACCUMULATOR, INDIRECT_X, {base + 0x06}}, \ + {ACCUMULATOR, DIRECT_PAGE, {base + 0x04, WB_RHS}}, \ + {ACCUMULATOR, DIRECT_PAGE_INDEX_X, {base + 0x14, WB_RHS}}, \ + {ACCUMULATOR, ABSOLUTE, {base + 0x05, WW_RHS}}, \ + {ACCUMULATOR, ABSOLUTE_INDEX_X, {base + 0x15, WW_RHS}}, \ + {ACCUMULATOR, ABSOLUTE_INDEX_Y, {base + 0x16, WW_RHS}}, \ + {ACCUMULATOR, DIRECT_PAGE_INDIRECT_X, {base + 0x07, WB_RHS}}, \ + {ACCUMULATOR, DIRECT_PAGE_INDIRECT_Y, {base + 0x17, WB_RHS}}, \ + {INDIRECT_X, INDIRECT_Y, {base + 0x19}}, \ + {DIRECT_PAGE, DIRECT_PAGE, {base + 0x09, \ + WB_LHS, WB_RHS}}, \ + {DIRECT_PAGE, IMMEDIATE, {base + 0x18, \ + WB_LHS, WB_RHS}} \ +}; \ + \ +address_mode_t mode1, mode2; \ +int addr1, addr2; \ + \ +CMD_ARGC_CHECK(3); \ + \ +ADDRESS_MODE(mode1, addr1, 1); \ +ADDRESS_MODE(mode2, addr2, 2); \ + \ +if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), \ + mode1, mode2, addr1, addr2, err, errsize)) \ +{ \ + return CMD_FAILED; \ +} \ + \ +return CMD_OK; \ +} while(0) + + +static CommandStatus MOV(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + static RegisterPairCodes codes[] = + { + {ACCUMULATOR, IMMEDIATE, {0xe8, WB_RHS}}, + {ACCUMULATOR, INDIRECT_X, {0xe6}}, + {ACCUMULATOR, INDIRECT_X_INC, {0xbf}}, + {ACCUMULATOR, DIRECT_PAGE, {0xe4, WB_RHS}}, + {ACCUMULATOR, DIRECT_PAGE_INDEX_X, {0xf4, WB_RHS}}, + {ACCUMULATOR, ABSOLUTE, {0xe5, WW_RHS}}, + {ACCUMULATOR, ABSOLUTE_INDEX_X, {0xf5, WW_RHS}}, + {ACCUMULATOR, ABSOLUTE_INDEX_Y, {0xf6, WW_RHS}}, + {ACCUMULATOR, DIRECT_PAGE_INDIRECT_X, {0xe7, WB_RHS}}, + {ACCUMULATOR, DIRECT_PAGE_INDIRECT_Y, {0xf7, WB_RHS}}, + + {X_REGISTER, IMMEDIATE, {0xcd, WB_RHS}}, + {X_REGISTER, DIRECT_PAGE, {0xf8, WB_RHS}}, + {X_REGISTER, DIRECT_PAGE_INDEX_Y, {0xf9, WB_RHS}}, + {X_REGISTER, ABSOLUTE, {0xe9, WW_RHS}}, + + {Y_REGISTER, IMMEDIATE, {0x8d, WB_RHS}}, + {Y_REGISTER, DIRECT_PAGE, {0xeb, WB_RHS}}, + {Y_REGISTER, DIRECT_PAGE_INDEX_X, {0xfb, WB_RHS}}, + {Y_REGISTER, ABSOLUTE, {0xec, WW_RHS}}, + + {INDIRECT_X, ACCUMULATOR, {0xc6}}, + {INDIRECT_X_INC, ACCUMULATOR, {0xaf}}, + {DIRECT_PAGE, ACCUMULATOR, {0xc4, WB_LHS}}, + {DIRECT_PAGE_INDEX_X, ACCUMULATOR, {0xd4, WB_LHS}}, + {ABSOLUTE, ACCUMULATOR, {0xc5, WW_LHS}}, + {ABSOLUTE_INDEX_X, ACCUMULATOR, {0xd5, WW_LHS}}, + {ABSOLUTE_INDEX_Y, ACCUMULATOR, {0xd6, WW_LHS}}, + {DIRECT_PAGE_INDIRECT_X,ACCUMULATOR, {0xc7, WB_LHS}}, + {DIRECT_PAGE_INDIRECT_Y,ACCUMULATOR, {0xd7, WB_LHS}}, + + {DIRECT_PAGE, X_REGISTER, {0xd8, WB_LHS}}, + {DIRECT_PAGE_INDEX_Y, X_REGISTER, {0xd9, WB_LHS}}, + {ABSOLUTE, X_REGISTER, {0xc9, WW_LHS}}, + + {DIRECT_PAGE, Y_REGISTER, {0xcb, WB_LHS}}, + {DIRECT_PAGE_INDEX_X, Y_REGISTER, {0xdb, WB_LHS}}, + {ABSOLUTE, Y_REGISTER, {0x0c, WW_LHS}}, + + {ACCUMULATOR, X_REGISTER, {0x7d}}, + {ACCUMULATOR, Y_REGISTER, {0xdd}}, + {X_REGISTER, ACCUMULATOR, {0x5d}}, + {Y_REGISTER, ACCUMULATOR, {0xfd}}, + {X_REGISTER, SP_REGISTER, {0xbd}}, + {DIRECT_PAGE, DIRECT_PAGE, {0xfa, WB_LHS, WB_RHS}}, + {DIRECT_PAGE, IMMEDIATE, {0x8f, WB_LHS, WB_RHS}} + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + + + +static CommandStatus ADC(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + COMMON_ALU(0x80); +} + +static CommandStatus ADDW(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + static RegisterPairCodes codes[] = + { + {YA_REGISTER, DIRECT_PAGE, {0x7a, WB_RHS}}, + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + + +static CommandStatus AND(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + COMMON_ALU(0x20); +} + +static CommandStatus ASL(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x1c); + return CMD_OK; + + case DIRECT_PAGE: + PCWrite(0x0b); + PCWrite(addr); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + PCWrite(0x1b); + PCWrite(addr); + return CMD_OK; + + case ABSOLUTE: + PCWrite(0xcc); + PCWriteWord(addr); + 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) +{ + static RegisterPairCodes codes[] = + { + {ACCUMULATOR, IMMEDIATE, {0x68, WB_RHS}}, + {ACCUMULATOR, INDIRECT_X, {0x66}}, + {ACCUMULATOR, DIRECT_PAGE, {0x64, WB_RHS}}, + {ACCUMULATOR, DIRECT_PAGE_INDEX_X, {0x74, WB_RHS}}, + {ACCUMULATOR, ABSOLUTE, {0x65, WW_RHS}}, + {ACCUMULATOR, ABSOLUTE_INDEX_X, {0x75, WW_RHS}}, + {ACCUMULATOR, ABSOLUTE_INDEX_Y, {0x76, WW_RHS}}, + {ACCUMULATOR, DIRECT_PAGE_INDIRECT_X, {0x67, WB_RHS}}, + {ACCUMULATOR, DIRECT_PAGE_INDIRECT_Y, {0x77, WB_RHS}}, + {INDIRECT_X, INDIRECT_Y, {0x79}}, + {DIRECT_PAGE, DIRECT_PAGE, {0x69, WB_LHS, WB_RHS}}, + {DIRECT_PAGE, IMMEDIATE, {0x78, WB_LHS, WB_RHS}}, + + {X_REGISTER, IMMEDIATE, {0xc8, WB_RHS}}, + {X_REGISTER, DIRECT_PAGE, {0x3e, WB_RHS}}, + {X_REGISTER, ABSOLUTE, {0x1e, WW_RHS}}, + + {Y_REGISTER, IMMEDIATE, {0xad, WB_RHS}}, + {Y_REGISTER, DIRECT_PAGE, {0x7e, WB_RHS}}, + {Y_REGISTER, ABSOLUTE, {0x5e, WW_RHS}}, + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + +static CommandStatus CMPW(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + static RegisterPairCodes codes[] = + { + {YA_REGISTER, DIRECT_PAGE, {0x5a, WB_RHS}}, + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + +static CommandStatus DEC(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x9c); + return CMD_OK; + + case DIRECT_PAGE: + PCWrite(0x8b); + PCWrite(addr); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + PCWrite(0x9b); + PCWrite(addr); + return CMD_OK; + + case ABSOLUTE: + PCWrite(0x8c); + PCWriteWord(addr); + return CMD_OK; + + case X_REGISTER: + PCWrite(0x1d); + return CMD_OK; + + case Y_REGISTER: + PCWrite(0xdc); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus DECW(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case DIRECT_PAGE: + PCWrite(0x1a); + PCWrite(addr); + 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) +{ + COMMON_ALU(0x40); +} + +static CommandStatus INC(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0xbc); + return CMD_OK; + + case DIRECT_PAGE: + PCWrite(0xab); + PCWrite(addr); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + PCWrite(0xbb); + PCWrite(addr); + return CMD_OK; + + case ABSOLUTE: + PCWrite(0xac); + PCWriteWord(addr); + return CMD_OK; + + case X_REGISTER: + PCWrite(0x3d); + return CMD_OK; + + case Y_REGISTER: + PCWrite(0xfc); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus INCW(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case DIRECT_PAGE: + PCWrite(0x3a); + PCWrite(addr); + 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; + + ADDRESS_MODE(mode, address, 1); + + switch(mode) + { + case ABSOLUTE: + case DIRECT_PAGE: + PCWrite(0x5f); + PCWriteWord(address); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + case ABSOLUTE_INDEX_X: + PCWrite(0x1f); + 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 CALL(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int address; + + ADDRESS_MODE(mode, address, 1); + + switch(mode) + { + case ABSOLUTE: + case DIRECT_PAGE: + PCWrite(0x3f); + 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 PCALL(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int address; + + ADDRESS_MODE(mode, address, 1); + + switch(mode) + { + case DIRECT_PAGE: + PCWrite(0x4f); + 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 addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x5c); + return CMD_OK; + + case DIRECT_PAGE: + PCWrite(0x4b); + PCWrite(addr); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + PCWrite(0x5b); + PCWrite(addr); + return CMD_OK; + + case ABSOLUTE: + PCWrite(0x4c); + PCWriteWord(addr); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus OR(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + COMMON_ALU(0x00); +} + +static CommandStatus ROL(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x3c); + return CMD_OK; + + case DIRECT_PAGE: + PCWrite(0x2b); + PCWrite(addr); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + PCWrite(0x3b); + PCWrite(addr); + return CMD_OK; + + case ABSOLUTE: + PCWrite(0x2c); + PCWriteWord(addr); + 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 addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x7c); + return CMD_OK; + + case DIRECT_PAGE: + PCWrite(0x6b); + PCWrite(addr); + return CMD_OK; + + case DIRECT_PAGE_INDEX_X: + PCWrite(0x7b); + PCWrite(addr); + return CMD_OK; + + case ABSOLUTE: + PCWrite(0x6c); + PCWriteWord(addr); + 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) +{ + COMMON_ALU(0xa0); +} + +static CommandStatus SUBW(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + static RegisterPairCodes codes[] = + { + {YA_REGISTER, DIRECT_PAGE, {0x9a, WB_RHS}}, + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + +static CommandStatus XCN(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x9f); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus MOVW(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + static RegisterPairCodes codes[] = + { + {YA_REGISTER, DIRECT_PAGE, {0xba}}, + {DIRECT_PAGE, YA_REGISTER, {0xda}} + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + +static CommandStatus MUL(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case YA_REGISTER: + PCWrite(0xcf); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus DIV(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + static RegisterPairCodes codes[] = + { + {YA_REGISTER, X_REGISTER, {0x9e}} + }; + + address_mode_t mode1, mode2; + int addr1, addr2; + + CMD_ARGC_CHECK(3); + + ADDRESS_MODE(mode1, addr1, 1); + ADDRESS_MODE(mode2, addr2, 2); + + if (!WriteRegisterPairModes(argv[0], codes, NUM_REGISTER_CODES(codes), + mode1, mode2, addr1, addr2, err, errsize)) + { + return CMD_FAILED; + } + + return CMD_OK; +} + +static CommandStatus DAA(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0xdf); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus DAS(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0xbe); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus PUSH(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0x2d); + return CMD_OK; + + case X_REGISTER: + PCWrite(0x4d); + return CMD_OK; + + case Y_REGISTER: + PCWrite(0x6d); + return CMD_OK; + + case PSW_REGISTER: + PCWrite(0x0d); + return CMD_OK; + + default: + snprintf(err, errsize, "%s: unsupported addressing mode %s", + argv[0], address_mode_name[mode]); + return CMD_FAILED; + } +} + +static CommandStatus POP(const char *label, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + address_mode_t mode; + int addr; + + CMD_ARGC_CHECK(2); + + ADDRESS_MODE(mode, addr, 1); + + switch(mode) + { + case ACCUMULATOR: + PCWrite(0xae); + return CMD_OK; + + case X_REGISTER: + PCWrite(0xce); + return CMD_OK; + + case Y_REGISTER: + PCWrite(0xee); + return CMD_OK; + + case PSW_REGISTER: + PCWrite(0x8e); + 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", 0x00}, + {"SLEEP", 0xef}, + {"STOP", 0xff}, + {"CLRC", 0x60}, + {"SETC", 0x80}, + {"NOTC", 0xed}, + {"CLRV", 0xe0}, + {"CLRP", 0x20}, + {"SETP", 0x40}, + {"EI", 0xa0}, + {"DI", 0xc0}, + {"BRK", 0x0f}, + {"RET", 0x6f}, + {"RETI", 0x7f}, + {"RET1", 0x7f}, + {NULL} +}; + + +static const OpcodeTable branch_opcodes[] = +{ + {"BRA", 0x2f}, + {"BEQ", 0xF0}, + {"BNE", 0xD0}, + {"BCS", 0xB0}, + {"BVC", 0x50}, + {"BCC", 0x90}, + {"BVS", 0x70}, + {"BVC", 0x50}, + {"BMI", 0x30}, + {"BPL", 0x10}, + {NULL} +}; + + +static const HandlerTable handler_table[] = +{ + {"ADC", ADC}, + {"AND", AND}, + {"ASL", ASL}, + {"CMP", CMP}, + {"DEC", DEC}, + {"EOR", EOR}, + {"INC", INC}, + {"JMP", JMP}, + {"CALL", CALL}, + {"PCALL", PCALL}, + {"LSR", LSR}, + {"OR", OR}, + {"ROL", ROL}, + {"ROR", ROR}, + {"SBC", SBC}, + {"MOV", MOV}, + {"MOVW", MOVW}, + {NULL} +}; + + + + +/* ---------------------------------------- PUBLIC FUNCTIONS +*/ + +void Init_SPC700(void) +{ + option.zp_mode = ZP_AUTO; + SetNeededPasses(3); +} + + +const ValueTable *Options_SPC700(void) +{ + return options; +} + +CommandStatus SetOption_SPC700(int opt, int argc, char *argv[], + int quoted[], char *err, size_t errsize) +{ + const ValueTable *val; + + switch(opt) + { + case OPT_ZP: + CMD_ARGC_CHECK(1); + CMD_TABLE(argv[0], zp_table, val); + + option.zp_mode = val->value; + break; + + default: + break; + } + + return CMD_OK; +} + +CommandStatus Handler_SPC700(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/spc700.h b/src/spc700.h new file mode 100644 index 0000000..a73b40f --- /dev/null +++ b/src/spc700.h @@ -0,0 +1,43 @@ +/* + + casm - Simple, portable assembler + + Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.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 . + + ------------------------------------------------------------------------- + + SPC700 Assembler + +*/ + +#ifndef CASM_SPC700_H +#define CASM_SPC700_H + +void Init_SPC700(void); + +const ValueTable *Options_SPC700(void); + +CommandStatus SetOption_SPC700(int opt, int argc, char *argv[], int quoted[], + char *error, size_t error_size); + +CommandStatus Handler_SPC700(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/state.c b/src/state.c index 8a8d227..d9a9d01 100644 --- a/src/state.c +++ b/src/state.c @@ -40,6 +40,7 @@ static int pass = 1; static int maxpass = 2; static int pc = 0; static int num_banks = 0; +static int address_space = 0; static unsigned currbank = 0; static WordMode wmode = LSB_Word; @@ -200,9 +201,25 @@ void SetWordMode(WordMode mode) } +void SetAddressSpace(int size) +{ + address_space = size; +} + + void SetPC(int i) { pc = i; + + if (address_space > 0) + { + while (pc < 0) + { + pc += address_space; + } + + pc = pc % address_space; + } } diff --git a/src/state.h b/src/state.h index 137670e..4cff0f2 100644 --- a/src/state.h +++ b/src/state.h @@ -107,6 +107,11 @@ void SetPC(int i); void SetWordMode(WordMode mode); +/* Set the size of address space +*/ +void SetAddressSpace(int size); + + /* Get the current PC */ int PC(void); diff --git a/src/test/link b/src/test/link index b30036e..41d11f1 100644 --- a/src/test/link +++ b/src/test/link @@ -2,5 +2,5 @@ option +list option list-labels,all - import "lib2.lib" - import "lib1.lib",labels + import "lib2.lib",all,-$1000 + import "lib1.lib",all,$1000 -- cgit v1.2.3