aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2016-05-12 15:28:32 +0100
committerIan C <ianc@noddybox.co.uk>2016-05-12 15:28:32 +0100
commit5e6a1c3434b96ea16485b160c25732df3b00b2b8 (patch)
treec86331cb1c74fbff18a8b7ef0ebd5989a0a1f182
parente60cc5a36c148ef5ea0e38bcc848cf32f2b54a18 (diff)
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.
-rw-r--r--doc/casm.html6
-rw-r--r--src/Makefile8
-rw-r--r--src/casm.c34
-rw-r--r--src/label.c4
-rw-r--r--src/label.h5
-rw-r--r--src/libout.c6
-rw-r--r--src/libout.h2
-rw-r--r--src/spc700.c1492
-rw-r--r--src/spc700.h43
-rw-r--r--src/state.c17
-rw-r--r--src/state.h5
-rw-r--r--src/test/link4
12 files changed, 1598 insertions, 28 deletions
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 <i>fill</i> is supplied.
</td></tr>
<tr><td class="cmd">
-import <i>filename</i>[, labels]</code>
+import <i>filename</i>[, labels|all[, offset]]</code>
</td>
<td class="def">
Includes a simple library file as generated by casm. See the <a href="#libout">section on simple library files</a> 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 <i>offset</i> is given
+then that offset is added onto the load address and defined labels.
</td></tr>
<tr><td class="cmd">
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 <http://www.gnu.org/licenses/>.
+
+ -------------------------------------------------------------------------
+
+ SPC700 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 "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 <http://www.gnu.org/licenses/>.
+
+ -------------------------------------------------------------------------
+
+ 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