aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/casm.html70
-rw-r--r--src/parse.c29
-rw-r--r--src/spc700.c702
-rw-r--r--src/test/cpm.13
-rw-r--r--src/util.c21
-rw-r--r--src/util.h9
6 files changed, 767 insertions, 67 deletions
diff --git a/doc/casm.html b/doc/casm.html
index bbef8ea..2e95ccc 100644
--- a/doc/casm.html
+++ b/doc/casm.html
@@ -157,6 +157,10 @@ http://www.gnu.org/licenses/gpl-3.0.html)</a></p>
<p>
<a href="#65c816">65c816</a> - 65c816 processor support, as used in the SNES.
</p>
+<p>
+<a href="#spc700">SPC700</a> - SPC700 processor support, as used in the SNES
+sound co-processor.
+</p>
<h1 id="casm">CASM</h1>
@@ -1557,7 +1561,7 @@ Controls the assumptions made regarding Zero Page address. Defaults to
off
</td>
<td class="def">
-The default; all addresses are assumed to be not on the Zero Page, regardless
+All addresses are assumed to be not on the Zero Page, regardless
of the value used.
</td></tr>
@@ -1835,6 +1839,70 @@ section.
</table>
+<h1 id="spc700">SPC700 CPU</h1>
+
+<h2>Using the SPC700</h2>
+
+The SPC700 processor can be selected by passing <b>spc700</b> to the processor
+directive, i.e.
+
+<pre class="codeblock">
+ processor spc700
+</pre>
+
+<h2>Opcodes</h2>
+
+I could find no official documentation on The SPC700, so the assembler uses what
+seems to be the accepted opcode format.
+
+
+<h2>Options</h2>
+
+The SPC700 assembler has the following options.
+
+<table>
+
+<thead><tr><td class="head">SPC700 Option</td>
+<td class="head">Description</td></tr></thead>
+
+<tr><td class="cmd">
+option direct-page, &lt;on|off|auto&gt;
+</td>
+<td class="def">
+Controls the assumptions made regarding Direct Page address. Defaults to
+<i>auto</i>, and can be the following values:
+
+<table>
+<tr><td class="cmd">
+off
+</td>
+<td class="def">
+All addresses are assumed to be not on the Direct Page, regardless of the value
+used.
+</td></tr>
+
+<tr><td class="cmd">
+on
+</td>
+<td class="def">
+Assumes all addresses are in the Direct Page, raising an error if any address is
+not in the Direct Page.
+</td></tr>
+
+<tr><td class="cmd">
+auto
+</td>
+<td class="def">
+Treats addresses less than 256 as being in the Direct Page automatically. This
+mode also makes the assembler perform an extra pass to guard against the
+possibility of the calculation being fooled.
+</td></tr>
+</table>
+
+</td></tr>
+</table>
+
+
<!-- vim: ai sw=4 ts=8 expandtab spell
-->
</body>
diff --git a/src/parse.c b/src/parse.c
index fe9a989..8e83374 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -97,6 +97,17 @@ static void AddToken(const char *start, const char *end, Line *line, int quoted)
}
+static int IsClosure(const char *p, const char *sep)
+{
+ while(*p && isspace(*p))
+ {
+ p++;
+ }
+
+ return !*p || strchr(sep, *p);
+}
+
+
/* ---------------------------------------- INTERFACES
*/
@@ -210,9 +221,25 @@ int ParseLine(Line *line, const char *source)
{
if (quote)
{
+ /* When we find a closing quote check if the following
+ character is a seperator or end-of-line. If not
+ this wasn't really a quoted string.
+ */
if (*p == quote)
{
- state = CONSUME_WS;
+ if (IsClosure(p + 1, sep_chars[stage]))
+ {
+ state = CONSUME_WS;
+ }
+ else
+ {
+ /* Wasn't a real closue, so add the quote as
+ a character onto the string.
+ */
+ quote = 0;
+ open_quote = 0;
+ start--;
+ }
}
}
else if (strchr(sep_chars[stage], *p) || *p == ';')
diff --git a/src/spc700.c b/src/spc700.c
index b1a3914..f4541ef 100644
--- a/src/spc700.c
+++ b/src/spc700.c
@@ -39,32 +39,32 @@
*/
enum option_t
{
- OPT_ZP
+ OPT_DP
};
-enum zp_mode_t
+enum dp_mode_t
{
- ZP_OFF,
- ZP_ON,
- ZP_AUTO
+ DP_OFF,
+ DP_ON,
+ DP_AUTO
};
static const ValueTable options[] =
{
- {"zero-page", OPT_ZP},
+ {"direct-page", OPT_DP},
{NULL}
};
-static const ValueTable zp_table[] =
+static const ValueTable dp_table[] =
{
- YES_NO_ENTRIES(ZP_ON, ZP_OFF),
- {"auto", ZP_AUTO},
+ YES_NO_ENTRIES(DP_ON, DP_OFF),
+ {"auto", DP_AUTO},
{NULL}
};
static struct
{
- enum zp_mode_t zp_mode;
+ enum dp_mode_t dp_mode;
} option;
@@ -77,7 +77,8 @@ typedef enum
SP_REGISTER,
C_FLAG,
PSW_REGISTER,
- NOTTED_BIT,
+ BIT_ADDRESS,
+ NOTTED_BIT_ADDRESS,
INDIRECT_X,
INDIRECT_Y,
INDIRECT_X_INC,
@@ -104,7 +105,8 @@ static const char *address_mode_name[] =
"Stack Pointer",
"Carry flag",
"PSW register",
- "Notted (/) bit",
+ "Bit address",
+ "Notted (/) bit address",
"Indirect X",
"Indirect Y",
"Indirect X increment",
@@ -163,12 +165,12 @@ do \
} while(0)
-#define CMD_ZP_MODE(ZP_mode, non_ZP_mode) \
+#define CMD_DP_MODE(DP_mode, non_DP_mode) \
do \
{ \
- switch(option.zp_mode) \
+ switch(option.dp_mode) \
{ \
- case ZP_ON: \
+ case DP_ON: \
if (*address < 0 || *address > 255) \
{ \
snprintf(err, errsize, "value %d outside of " \
@@ -177,26 +179,37 @@ do \
return; \
} \
\
- *mode = ZP_mode; \
+ *mode = DP_mode; \
break; \
\
- case ZP_OFF: \
- *mode = non_ZP_mode; \
+ case DP_OFF: \
+ *mode = non_DP_mode; \
break; \
\
- case ZP_AUTO: \
+ case DP_AUTO: \
if (*address >= 0 && *address <= 255) \
{ \
- *mode = ZP_mode; \
+ *mode = DP_mode; \
} \
else \
{ \
- *mode = non_ZP_mode; \
+ *mode = non_DP_mode; \
} \
break; \
} \
} while (0)
+#define CHECK_RANGE(val, min, max) \
+do { \
+ if (val < min || val > max) \
+ { \
+ snprintf(err, errsize, "%s: value %d outside " \
+ "of valid range %d - %d", \
+ argv[0], val, min, max); \
+ return CMD_FAILED; \
+ } \
+} while(0)
+
/* ---------------------------------------- PRIVATE FUNCTIONS
*/
@@ -285,19 +298,75 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
return;
}
- /* 'Notted' bit
+ /* Bit addresses
*/
- if (arg[0] == '/')
+ if (strchr(arg, '.'))
{
- *mode = NOTTED_BIT;
+ char *copy;
+ char *end;
+ int a,b;
+
+ copy = DupStr(arg);
+ end = strrchr(copy, '.');
+ *end++ = 0;
+
+ if (arg[0] == '/')
+ {
+ *mode = NOTTED_BIT_ADDRESS;
+
+ if (IsFinalPass() && !ExprEval(copy + 1, &a))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ copy + 1, ExprError());
+ *mode = ADDR_MODE_ERROR;
+ free(copy);
+ return;
+ }
+ }
+ else
+ {
+ *mode = BIT_ADDRESS;
+
+ if (IsFinalPass() && !ExprEval(copy, &a))
+ {
+ snprintf(err, errsize, "%s: expression error: %s",
+ copy, ExprError());
+ *mode = ADDR_MODE_ERROR;
+ free(copy);
+ return;
+ }
+ }
- if (!ExprEval(arg + 1, address))
+ if (IsFinalPass() && !ExprEval(end, &b))
{
snprintf(err, errsize, "%s: expression error: %s",
- arg + 1, ExprError());
+ end, ExprError());
*mode = ADDR_MODE_ERROR;
+ free(copy);
+ return;
}
+ if (IsFinalPass() && (a < 0 || a > 0x1fff))
+ {
+ snprintf(err, errsize, "%s: address component of bit address "
+ "out of valid range 0x0 to 0x1fff", copy);
+ *mode = ADDR_MODE_ERROR;
+ free(copy);
+ return;
+ }
+
+ if (IsFinalPass() && (b < 0 || b > 7))
+ {
+ snprintf(err, errsize, "%s: address component of bit address "
+ "out of valid range 0 to 7", end);
+ *mode = ADDR_MODE_ERROR;
+ free(copy);
+ return;
+ }
+
+ *address = a | b << 13;
+
+ free(copy);
return;
}
@@ -307,7 +376,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
{
*mode = IMMEDIATE;
- if (!ExprEval(arg + 1, address))
+ if (IsFinalPass() && !ExprEval(arg + 1, address))
{
snprintf(err, errsize, "%s: expression error: %s",
arg + 1, ExprError());
@@ -332,7 +401,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
*/
if (quote == '(' && CompareString(end, "X"))
{
- if (!ExprEval(copy, address))
+ if (IsFinalPass() && !ExprEval(copy, address))
{
snprintf(err, errsize, "%s: expression error: %s",
copy, ExprError());
@@ -351,10 +420,15 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
*/
if (!quote && *copy == '(' && CompareString(end, "Y"))
{
- if (!ExprEval(copy + 1, address))
+ /* Remember that the expression parser doesn't allow
+ round braclets.
+ */
+ TrimChars(copy, "()");
+
+ if (IsFinalPass() && !ExprEval(copy, address))
{
snprintf(err, errsize, "%s: expression error: %s",
- copy + 1, ExprError());
+ copy, ExprError());
*mode = ADDR_MODE_ERROR;
}
else
@@ -370,7 +444,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
*/
if (!quote && CompareString(end, "X"))
{
- if (!ExprEval(copy, address))
+ if (IsFinalPass() && !ExprEval(copy, address))
{
snprintf(err, errsize, "%s: expression error: %s",
copy, ExprError());
@@ -378,7 +452,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
}
else
{
- CMD_ZP_MODE(DIRECT_PAGE_INDEX_X, ABSOLUTE_INDEX_X);
+ CMD_DP_MODE(DIRECT_PAGE_INDEX_X, ABSOLUTE_INDEX_X);
}
free(copy);
@@ -389,7 +463,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
*/
if (!quote && CompareString(end, "Y"))
{
- if (!ExprEval(copy, address))
+ if (IsFinalPass() && !ExprEval(copy, address))
{
snprintf(err, errsize, "%s: expression error: %s",
copy, ExprError());
@@ -397,7 +471,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
}
else
{
- CMD_ZP_MODE(DIRECT_PAGE_INDEX_Y, ABSOLUTE_INDEX_Y);
+ CMD_DP_MODE(DIRECT_PAGE_INDEX_Y, ABSOLUTE_INDEX_Y);
}
free(copy);
@@ -409,7 +483,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
/* If all else fails, Absolute
*/
- if (!ExprEval(arg, address))
+ if (IsFinalPass() && !ExprEval(arg, address))
{
snprintf(err, errsize, "%s: expression error: %s",
arg, ExprError());
@@ -417,7 +491,7 @@ static void CalcAddressMode(int argc, char *argv[], int quoted[], int index,
return;
}
- CMD_ZP_MODE(DIRECT_PAGE, ABSOLUTE);
+ CMD_DP_MODE(DIRECT_PAGE, ABSOLUTE);
}
@@ -471,6 +545,20 @@ static int WriteRegisterPairModes(const char *caller,
}
+static int MakeRelative(int *addr, char *cmd, char *err, size_t errsize)
+{
+ *addr = *addr - (PC() + 2);
+
+ if (IsFinalPass() && (*addr < -128 || *addr > 127))
+ {
+ snprintf(err, errsize, "%s: Branch offset (%d) too big",
+ cmd, *addr);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* ---------------------------------------- COMMAND HANDLERS
*/
@@ -486,6 +574,7 @@ static RegisterPairCodes codes[] = \
{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_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}}, \
@@ -525,6 +614,7 @@ static CommandStatus MOV(const char *label, int argc, char *argv[],
{ACCUMULATOR, DIRECT_PAGE_INDEX_X, {0xf4, WB_RHS}},
{ACCUMULATOR, ABSOLUTE, {0xe5, WW_RHS}},
{ACCUMULATOR, ABSOLUTE_INDEX_X, {0xf5, WW_RHS}},
+ {ACCUMULATOR, DIRECT_PAGE_INDEX_Y, {0xf6, 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}},
@@ -546,6 +636,7 @@ static CommandStatus MOV(const char *label, int argc, char *argv[],
{ABSOLUTE, ACCUMULATOR, {0xc5, WW_LHS}},
{ABSOLUTE_INDEX_X, ACCUMULATOR, {0xd5, WW_LHS}},
{ABSOLUTE_INDEX_Y, ACCUMULATOR, {0xd6, WW_LHS}},
+ {DIRECT_PAGE_INDEX_Y, ACCUMULATOR, {0xd6, WW_LHS}},
{DIRECT_PAGE_INDIRECT_X,ACCUMULATOR, {0xc7, WB_LHS}},
{DIRECT_PAGE_INDIRECT_Y,ACCUMULATOR, {0xd7, WB_LHS}},
@@ -561,7 +652,8 @@ static CommandStatus MOV(const char *label, int argc, char *argv[],
{ACCUMULATOR, Y_REGISTER, {0xdd}},
{X_REGISTER, ACCUMULATOR, {0x5d}},
{Y_REGISTER, ACCUMULATOR, {0xfd}},
- {X_REGISTER, SP_REGISTER, {0xbd}},
+ {X_REGISTER, SP_REGISTER, {0x9d}},
+ {SP_REGISTER, X_REGISTER, {0xbd}},
{DIRECT_PAGE, DIRECT_PAGE, {0xfa, WB_LHS, WB_RHS}},
{DIRECT_PAGE, IMMEDIATE, {0x8f, WB_LHS, WB_RHS}}
};
@@ -673,6 +765,7 @@ static CommandStatus CMP(const char *label, int argc, char *argv[],
{ACCUMULATOR, ABSOLUTE, {0x65, WW_RHS}},
{ACCUMULATOR, ABSOLUTE_INDEX_X, {0x75, WW_RHS}},
{ACCUMULATOR, ABSOLUTE_INDEX_Y, {0x76, WW_RHS}},
+ {ACCUMULATOR, DIRECT_PAGE_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}},
@@ -894,6 +987,7 @@ static CommandStatus JMP(const char *label, int argc, char *argv[],
case DIRECT_PAGE_INDEX_X:
case ABSOLUTE_INDEX_X:
+ case DIRECT_PAGE_INDIRECT_X:
PCWrite(0x1f);
PCWriteWord(address);
return CMD_OK;
@@ -938,6 +1032,7 @@ static CommandStatus PCALL(const char *label, int argc, char *argv[],
switch(mode)
{
+ case ABSOLUTE:
case DIRECT_PAGE:
PCWrite(0x4f);
PCWrite(address);
@@ -950,6 +1045,29 @@ static CommandStatus PCALL(const char *label, int argc, char *argv[],
}
}
+static CommandStatus TCALL(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:
+ CHECK_RANGE(address, 0, 15);
+ PCWrite(0x01 + 0x10 * 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)
{
@@ -1314,6 +1432,413 @@ static CommandStatus POP(const char *label, int argc, char *argv[],
}
}
+static CommandStatus BBCx(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+ int bit;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ bit = argv[0][strlen(argv[0]) - 1] - '0';
+
+ if (!MakeRelative(&addr2, argv[0], err, errsize))
+ {
+ return CMD_FAILED;
+ }
+
+ switch(mode1)
+ {
+ case ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0x13 + bit * 0x20);
+ PCWrite(addr1);
+ PCWrite(addr2);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode1]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus BBSx(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+ int bit;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ bit = argv[0][strlen(argv[0]) - 1] - '0';
+
+ if (!MakeRelative(&addr2, argv[0], err, errsize))
+ {
+ return CMD_FAILED;
+ }
+
+ switch(mode1)
+ {
+ case ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0x03 + bit * 0x20);
+ PCWrite(addr1);
+ PCWrite(addr2);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode1]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus CBNE(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ if (!MakeRelative(&addr2, argv[0], err, errsize))
+ {
+ return CMD_FAILED;
+ }
+
+ switch(mode1)
+ {
+ case ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0x2e);
+ PCWrite(addr1);
+ PCWrite(addr2);
+ return CMD_OK;
+
+ case DIRECT_PAGE_INDEX_X:
+ PCWrite(0xde);
+ PCWrite(addr1);
+ PCWrite(addr2);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode1]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus DBNZ(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ if (!MakeRelative(&addr2, argv[0], err, errsize))
+ {
+ return CMD_FAILED;
+ }
+
+ switch(mode1)
+ {
+ case ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0x6e);
+ PCWrite(addr1);
+ PCWrite(addr2);
+ return CMD_OK;
+
+ case Y_REGISTER:
+ PCWrite(0xfe);
+ PCWrite(addr2);
+ return CMD_OK;
+
+ default:
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode1]);
+ return CMD_FAILED;
+ }
+}
+
+static CommandStatus SETx(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int addr;
+ int bit;
+
+ CMD_ARGC_CHECK(2);
+
+ ADDRESS_MODE(mode, addr, 1);
+
+ bit = argv[0][strlen(argv[0]) - 1] - '0';
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0x12 + bit * 0x20);
+ 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 CLRx(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode;
+ int addr;
+ int bit;
+
+ CMD_ARGC_CHECK(2);
+
+ ADDRESS_MODE(mode, addr, 1);
+
+ bit = argv[0][strlen(argv[0]) - 1] - '0';
+
+ switch(mode)
+ {
+ case ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0x02 + bit * 0x20);
+ 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 TSET1(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:
+ case ABSOLUTE:
+ PCWrite(0x0e);
+ 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 TCLR1(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 ABSOLUTE:
+ case DIRECT_PAGE:
+ PCWrite(0xe4);
+ 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 AND1(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ if (mode1 == C_FLAG)
+ {
+ switch(mode2)
+ {
+ case BIT_ADDRESS:
+ PCWrite(0x4a);
+ PCWriteWord(addr2);
+ return CMD_OK;
+
+ case NOTTED_BIT_ADDRESS:
+ PCWrite(0x6a);
+ PCWriteWord(addr2);
+ return CMD_OK;
+
+ default:
+ break;
+ }
+ }
+
+ snprintf(err, errsize, "%s: unsupported addressing mode %s, %s",
+ argv[0], address_mode_name[mode1],
+ address_mode_name[mode2]);
+ return CMD_FAILED;
+}
+
+static CommandStatus OR1(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ if (mode1 == C_FLAG)
+ {
+ switch(mode2)
+ {
+ case BIT_ADDRESS:
+ PCWrite(0x0a);
+ PCWriteWord(addr2);
+ return CMD_OK;
+
+ case NOTTED_BIT_ADDRESS:
+ PCWrite(0x2a);
+ PCWriteWord(addr2);
+ return CMD_OK;
+
+ default:
+ break;
+ }
+ }
+
+ snprintf(err, errsize, "%s: unsupported addressing mode %s, %s",
+ argv[0], address_mode_name[mode1],
+ address_mode_name[mode2]);
+ return CMD_FAILED;
+}
+
+static CommandStatus EOR1(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ if (mode1 == C_FLAG)
+ {
+ switch(mode2)
+ {
+ case BIT_ADDRESS:
+ PCWrite(0x8a);
+ PCWriteWord(addr2);
+ return CMD_OK;
+
+ default:
+ break;
+ }
+ }
+
+ snprintf(err, errsize, "%s: unsupported addressing mode %s, %s",
+ argv[0], address_mode_name[mode1],
+ address_mode_name[mode2]);
+ return CMD_FAILED;
+}
+
+static CommandStatus NOT1(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);
+
+ if (mode == BIT_ADDRESS)
+ {
+ PCWrite(0xea);
+ PCWriteWord(addr);
+ return CMD_OK;
+ }
+
+ snprintf(err, errsize, "%s: unsupported addressing mode %s",
+ argv[0], address_mode_name[mode]);
+ return CMD_FAILED;
+}
+
+static CommandStatus MOV1(const char *label, int argc, char *argv[],
+ int quoted[], char *err, size_t errsize)
+{
+ address_mode_t mode1, mode2;
+ int addr1, addr2;
+
+ CMD_ARGC_CHECK(3);
+
+ ADDRESS_MODE(mode1, addr1, 1);
+ ADDRESS_MODE(mode2, addr2, 2);
+
+ if (mode1 == C_FLAG && mode2 == BIT_ADDRESS)
+ {
+ PCWrite(0xaa);
+ PCWriteWord(addr2);
+ return CMD_OK;
+ }
+
+ if (mode2 == C_FLAG && mode1 == BIT_ADDRESS)
+ {
+ PCWrite(0xca);
+ PCWriteWord(addr2);
+ return CMD_OK;
+ }
+
+ snprintf(err, errsize, "%s: unsupported addressing mode %s, %s",
+ argv[0], address_mode_name[mode1],
+ address_mode_name[mode2]);
+ return CMD_FAILED;
+}
+
/* ---------------------------------------- OPCODE TABLES
*/
typedef struct
@@ -1344,7 +1869,6 @@ static const OpcodeTable implied_opcodes[] =
{"BRK", 0x0f},
{"RET", 0x6f},
{"RETI", 0x7f},
- {"RET1", 0x7f},
{NULL}
};
@@ -1367,23 +1891,77 @@ static const OpcodeTable branch_opcodes[] =
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},
+ {"ADC", ADC},
+ {"ADDW", ADDW},
+ {"AND", AND},
+ {"AND1", AND1},
+ {"ASL", ASL},
+ {"BBC0", BBCx},
+ {"BBC1", BBCx},
+ {"BBC2", BBCx},
+ {"BBC3", BBCx},
+ {"BBC4", BBCx},
+ {"BBC5", BBCx},
+ {"BBC6", BBCx},
+ {"BBC7", BBCx},
+ {"BBS0", BBSx},
+ {"BBS1", BBSx},
+ {"BBS2", BBSx},
+ {"BBS3", BBSx},
+ {"BBS4", BBSx},
+ {"BBS5", BBSx},
+ {"BBS6", BBSx},
+ {"BBS7", BBSx},
+ {"CALL", CALL},
+ {"CBNE", CBNE},
+ {"CLR0", CLRx},
+ {"CLR1", CLRx},
+ {"CLR2", CLRx},
+ {"CLR3", CLRx},
+ {"CLR4", CLRx},
+ {"CLR5", CLRx},
+ {"CLR6", CLRx},
+ {"CLR7", CLRx},
+ {"CMP", CMP},
+ {"CMPW", CMPW},
+ {"DAA", DAA},
+ {"DAS", DAS},
+ {"DBNZ", DBNZ},
+ {"DEC", DEC},
+ {"DECW", DECW},
+ {"DIV", DIV},
+ {"EOR", EOR},
+ {"EOR1", EOR1},
+ {"INC", INC},
+ {"INCW", INCW},
+ {"JMP", JMP},
+ {"LSR", LSR},
+ {"MOV", MOV},
+ {"MOV1", MOV1},
+ {"MOVW", MOVW},
+ {"MUL", MUL},
+ {"NOT1", NOT1},
+ {"OR", OR},
+ {"OR1", OR1},
+ {"PCALL", PCALL},
+ {"POP", POP},
+ {"PUSH", PUSH},
+ {"ROL", ROL},
+ {"ROR", ROR},
+ {"SBC", SBC},
+ {"SET0", SETx},
+ {"SET1", SETx},
+ {"SET2", SETx},
+ {"SET3", SETx},
+ {"SET4", SETx},
+ {"SET5", SETx},
+ {"SET6", SETx},
+ {"SET7", SETx},
+ {"SUBW", SUBW},
+ {"TCALL", TCALL},
+ {"TCLR1", TCLR1},
+ {"TSET1", TSET1},
+ {"XCN", XCN},
{NULL}
};
@@ -1395,7 +1973,7 @@ static const HandlerTable handler_table[] =
void Init_SPC700(void)
{
- option.zp_mode = ZP_AUTO;
+ option.dp_mode = DP_AUTO;
SetNeededPasses(3);
}
@@ -1412,11 +1990,11 @@ CommandStatus SetOption_SPC700(int opt, int argc, char *argv[],
switch(opt)
{
- case OPT_ZP:
+ case OPT_DP:
CMD_ARGC_CHECK(1);
- CMD_TABLE(argv[0], zp_table, val);
+ CMD_TABLE(argv[0], dp_table, val);
- option.zp_mode = val->value;
+ option.dp_mode = val->value;
break;
default:
@@ -1454,12 +2032,8 @@ CommandStatus Handler_SPC700(const char *label, int argc, char *argv[],
CMD_EXPR(argv[1], offset);
- offset = offset - (PC() + 2);
-
- if (IsFinalPass() && (offset < -128 || offset > 127))
+ if (!MakeRelative(&offset, argv[0], err, errsize))
{
- snprintf(err, errsize, "%s: Branch offset (%d) too big",
- argv[1], offset);
return CMD_FAILED;
}
diff --git a/src/test/cpm.1 b/src/test/cpm.1
index 60ec8c2..7f46637 100644
--- a/src/test/cpm.1
+++ b/src/test/cpm.1
@@ -24,6 +24,7 @@ strout1:macro
jr z,end_str
call BDOS
inc de
+ inc de
jr loop
.str defb \*,0
@@ -37,7 +38,7 @@ strout1:macro
org $100
strout str
- strout1 "Bye world", 13, 10, '$'
+ strout1 "Bye world", 13, 10, '$$'
ret
diff --git a/src/util.c b/src/util.c
index d7ac2b9..fba0753 100644
--- a/src/util.c
+++ b/src/util.c
@@ -109,6 +109,27 @@ char *Trim(char *p)
}
+char *TrimChars(char *p, const char *chars)
+{
+ if (p)
+ {
+ size_t l = strlen(p);
+
+ while (l > 0 && strchr(chars, *p))
+ {
+ memmove(p, p + 1, l--);
+ }
+
+ while(l > 1 && strchr(chars, p[l-1]))
+ {
+ p[--l] = 0;
+ }
+ }
+
+ return p;
+}
+
+
char *CopyStr(char *dest, const char *src, size_t size)
{
strncpy(dest, src, size);
diff --git a/src/util.h b/src/util.h
index 6f70a8d..4faec6f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -54,10 +54,19 @@ char *RemoveNL(char *p);
/* Remove white space from the start and end of a string.
+ Characters from the front are removed by memmov()ing the string, so the
+ returned point is always the same as the passed 'p'.
*/
char *Trim(char *p);
+/* Remove passed characters from the start and end of a string.
+ Characters from the front are removed by memmov()ing the string, so the
+ returned point is always the same as the passed 'p'.
+*/
+char *TrimChars(char *p, const char *chars);
+
+
/* Compare a string, but case insensitive. Returns TRUE for match, otherwise
FALSE.
*/