diff --git a/Source/Core/Common/Src/FileUtil.cpp b/Source/Core/Common/Src/FileUtil.cpp
index 11fd035ad9..bfc3188a67 100644
--- a/Source/Core/Common/Src/FileUtil.cpp
+++ b/Source/Core/Common/Src/FileUtil.cpp
@@ -579,8 +579,8 @@ std::string GetSysDirectory()
sysDir += DIR_SEP;
INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str());
return sysDir;
-
}
+
// Returns a pointer to a string with a Dolphin data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const char *GetUserDirectory()
diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj
index 1c524c77a8..f7a0fc90f6 100644
--- a/Source/Core/DSPCore/DSPCore.vcproj
+++ b/Source/Core/DSPCore/DSPCore.vcproj
@@ -522,6 +522,14 @@
RelativePath=".\Src\gdsp_registers.h"
>
+
+
+
+
diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp
index 9ddf2c9405..370e945a12 100644
--- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp
+++ b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp
@@ -71,7 +71,7 @@ bool Compare(const std::vector &code1, const std::vector &code2)
if (code1[i] == code2[i])
count_equal++;
else
- printf("!! %i : %04x vs %04x\n", i, code1[i], code2[i]);
+ printf("!! %04x : %04x vs %04x\n", i, code1[i], code2[i]);
}
printf("Equal instruction words: %i / %i\n", count_equal, min_size);
return code1.size() == code2.size() && code1.size() == count_equal;
@@ -86,11 +86,11 @@ void GenRandomCode(int size, std::vector *code)
}
}
-void CodeToHeader(std::vector *code, const char *name, std::string *header)
+void CodeToHeader(const std::vector &code, const char *name, std::string *header)
{
char buffer[1024];
header->clear();
- header->reserve(code->size() * 4);
+ header->reserve(code.size() * 4);
header->append("#ifndef _MSCVER\n");
sprintf(buffer, "const __declspec(align:64) unsigned short %s = {\n");
header->append(buffer);
@@ -98,7 +98,7 @@ void CodeToHeader(std::vector *code, const char *name, std::string *header)
sprintf(buffer, "const unsigned short %s __attribute__(aligned:64) = {\n");
header->append(buffer);
header->append("#endif\n\n ");
- for (int i = 0; i < code->size(); i++)
+ for (int i = 0; i < code.size(); i++)
{
if (((i + 1) & 15) == 0)
header->append("\n ");
diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.h b/Source/Core/DSPCore/Src/DSPCodeUtil.h
index 7701a3432c..02105dc52c 100644
--- a/Source/Core/DSPCore/Src/DSPCodeUtil.h
+++ b/Source/Core/DSPCore/Src/DSPCodeUtil.h
@@ -27,7 +27,7 @@ bool Assemble(const char *text, std::vector *code);
bool Disassemble(const std::vector &code, bool line_numbers, std::string *text);
bool Compare(const std::vector &code1, const std::vector &code2);
void GenRandomCode(int size, std::vector *code);
-void CodeToHeader(std::vector *code, const char *name, std::string *header);
+void CodeToHeader(const std::vector &code, const char *name, std::string *header);
// Big-endian, for writing straight to file using File::WriteStringToFile.
void CodeToBinaryStringBE(const std::vector &code, std::string *str);
diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.cpp b/Source/Core/DSPCore/Src/DSPInterpreter.cpp
index 9392d555f1..e801e4e1b9 100644
--- a/Source/Core/DSPCore/Src/DSPInterpreter.cpp
+++ b/Source/Core/DSPCore/Src/DSPInterpreter.cpp
@@ -1214,7 +1214,7 @@ void addis(const UDSPInstruction& opc)
{
u8 areg = (opc.hex >> 8) & 0x1;
- s64 Imm = (s8)opc.hex;
+ s64 Imm = (s8)(u8)opc.hex;
Imm <<= 16;
s64 acc = dsp_get_long_acc(areg);
acc += Imm;
diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp
index d3f015921d..e57c886fe2 100644
--- a/Source/Core/DSPCore/Src/DSPTables.cpp
+++ b/Source/Core/DSPCore/Src/DSPTables.cpp
@@ -66,7 +66,6 @@ void nop(const UDSPInstruction& opc)
// All AX games: a100
// Zelda Four Swords: 02ca
-
// TODO: Fill up the tables with the corresponding instructions
const DSPOPCTemplate opcodes[] =
{
@@ -90,17 +89,17 @@ const DSPOPCTemplate opcodes[] =
{"RET", 0x02df, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
{"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, nop, 1, 0, {}, NULL, NULL},
- {"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"IFNS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IFS", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
@@ -114,17 +113,17 @@ const DSPOPCTemplate opcodes[] =
{"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // Hermes doesn't list this
- {"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JRNS", 0x1700, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
@@ -205,11 +204,11 @@ const DSPOPCTemplate opcodes[] =
// LOOPS
{"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 2, 2, {{P_REG, 1, 0, 0, 0x00c0}, {P_REG04, 2, 1, 0, 0x0003}}, NULL, NULL},
+ {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, NULL, NULL},
// opcodes that can be extended
@@ -292,12 +291,12 @@ const DSPOPCTemplate opcodes[] =
{"ADDR", 0x4000, 0xf8ff, DSPInterpreter::addr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADDAX", 0x4800, 0xfcff, DSPInterpreter::addax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADDAXL", 0x7000, 0xfcff, DSPInterpreter::addaxl, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SUBR", 0x5000, 0xf8ff, DSPInterpreter::subr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SUBAX", 0x5800, 0xfcff, DSPInterpreter::subax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SUBP", 0x5e00, 0xfeff, DSPInterpreter::subp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MADD", 0xf200, 0xfeff, DSPInterpreter::madd, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h
index 4a5990a53e..8e0f66207c 100644
--- a/Source/Core/DSPCore/Src/DSPTables.h
+++ b/Source/Core/DSPCore/Src/DSPTables.h
@@ -22,7 +22,7 @@
#include "Common.h"
-// The ones that end with _D are the opposite one - if the bit specify
+// The non-ADDR ones that end with _D are the opposite one - if the bit specify
// ACC0, then ACC_D will be ACC1.
// The values of these are very important.
@@ -32,10 +32,12 @@
enum partype_t
{
P_NONE = 0x0000,
- P_VAL = 0x0001,
+ P_VAL = 0x0001,
P_IMM = 0x0002,
P_MEM = 0x0003,
P_STR = 0x0004,
+ P_ADDR_I = 0x0005,
+ P_ADDR_D = 0x0006,
P_REG = 0x8000,
P_REG04 = P_REG | 0x0400, // IX
P_REG08 = P_REG | 0x0800,
@@ -60,7 +62,6 @@ enum partype_t
// The following seem like junk:
// P_REG10 = P_REG | 0x1000,
// P_AX_D = P_REG | 0x2280,
-
};
#define P_EXT 0x80
diff --git a/Source/Core/DSPCore/Src/LabelMap.cpp b/Source/Core/DSPCore/Src/LabelMap.cpp
new file mode 100644
index 0000000000..836fef98f9
--- /dev/null
+++ b/Source/Core/DSPCore/Src/LabelMap.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2003-2009 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "LabelMap.h"
+#include "DSPTables.h"
+
+LabelMap::LabelMap()
+{
+
+}
+
+void LabelMap::RegisterDefaults()
+{
+ for (int i = 0; i < 0x24; i++)
+ {
+ RegisterLabel(regnames[i].name, regnames[i].addr);
+ }
+ for (int i = 0; i < (int)pdlabels_size; i++)
+ {
+ RegisterLabel(pdlabels[i].name, pdlabels[i].addr);
+ }
+}
+
+void LabelMap::RegisterLabel(const char *label, u16 lval, LabelType type)
+{
+ u16 old_value;
+ if (GetLabelValue(label, &old_value) && old_value != lval)
+ {
+ printf("WARNING: Redefined label %s to %04x - old value %04x\n",
+ label, lval, old_value);
+ DeleteLabel(label);
+ }
+ labels.push_back(label_t(label, lval, type));
+}
+
+void LabelMap::DeleteLabel(const char *label)
+{
+ for (std::vector::iterator iter = labels.begin();
+ iter != labels.end(); ++iter)
+ {
+ if (!strcmp(label, iter->name.c_str()))
+ {
+ labels.erase(iter);
+ return;
+ }
+ }
+}
+
+bool LabelMap::GetLabelValue(const char *label, u16 *value, LabelType type) const
+{
+ for (int i = 0; i < labels.size(); i++)
+ {
+ if (!strcmp(labels[i].name.c_str(), label))
+ {
+ if (type & labels[i].type) {
+ *value = labels[i].addr;
+ return true;
+ } else {
+ printf("WARNING: Wrong label type requested. %s\n", label);
+ }
+ }
+ }
+ return false;
+}
+
+void LabelMap::Clear()
+{
+ labels.clear();
+}
diff --git a/Source/Core/DSPCore/Src/LabelMap.h b/Source/Core/DSPCore/Src/LabelMap.h
new file mode 100644
index 0000000000..66d442e49c
--- /dev/null
+++ b/Source/Core/DSPCore/Src/LabelMap.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2003-2009 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _LABELMAP_H
+#define _LABELMAP_H
+
+#include
+#include
+
+#include "Common.h"
+
+enum LabelType
+{
+ LABEL_IADDR = 1, // Jump addresses, etc
+ LABEL_DADDR = 2, // Data addresses, etc
+ LABEL_VALUE = 4,
+ LABEL_ANY = 0xFF,
+};
+
+class LabelMap
+{
+ struct label_t
+ {
+ label_t(const char *lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {}
+ std::string name;
+ s32 addr;
+ LabelType type;
+ };
+ std::vector labels;
+
+public:
+ LabelMap();
+ void RegisterDefaults();
+ void RegisterLabel(const char *label, u16 lval, LabelType type = LABEL_VALUE);
+ void DeleteLabel(const char *label);
+ bool GetLabelValue(const char *label, u16 *value, LabelType type = LABEL_ANY) const;
+ void Clear();
+};
+
+#endif // _LABELMAP_H
diff --git a/Source/Core/DSPCore/Src/assemble.cpp b/Source/Core/DSPCore/Src/assemble.cpp
index 59ca640ee6..729578f5b7 100644
--- a/Source/Core/DSPCore/Src/assemble.cpp
+++ b/Source/Core/DSPCore/Src/assemble.cpp
@@ -115,12 +115,12 @@ bool DSPAssembler::Assemble(const char *text, std::vector *code, std::vecto
return true;
}
-void DSPAssembler::parse_error(err_t err_code, const char *extra_info)
+void DSPAssembler::ShowError(err_t err_code, const char *extra_info)
{
failed = true;
char error_buffer[1024];
char *buf_ptr = error_buffer;
- buf_ptr += sprintf(buf_ptr, "%i : %s\n", code_line, cur_line);
+ buf_ptr += sprintf(buf_ptr, "%i : %s", code_line, cur_line.c_str());
if (!extra_info)
extra_info = "-";
if (fsrc)
@@ -151,18 +151,8 @@ const char *skip_spaces(const char *ptr)
return ptr;
}
-void DSPAssembler::gd_ass_register_label(const char *label, u16 lval)
-{
- labels.push_back(label_t(label, lval));
-}
-
-void DSPAssembler::gd_ass_clear_labels()
-{
- labels.clear();
-}
-
// Parse a standalone value - it can be a number in one of several formats or a label.
-s32 DSPAssembler::strtoval(const char *str)
+s32 DSPAssembler::ParseValue(const char *str)
{
bool negative = false;
s32 val = 0;
@@ -188,7 +178,7 @@ s32 DSPAssembler::strtoval(const char *str)
if (ptr[i] >= '0' && ptr[i] <= '9')
val += ptr[i] - '0';
else
- parse_error(ERR_INCORRECT_DEC, str);
+ ShowError(ERR_INCORRECT_DEC, str);
}
}
else
@@ -206,7 +196,7 @@ s32 DSPAssembler::strtoval(const char *str)
else if (ptr[i] >= '0' && ptr[i] <= '9')
val += (ptr[i] - '0');
else
- parse_error(ERR_INCORRECT_HEX, str);
+ ShowError(ERR_INCORRECT_HEX, str);
}
break;
case '\'': // binary
@@ -216,7 +206,7 @@ s32 DSPAssembler::strtoval(const char *str)
if(ptr[i] >= '0' && ptr[i] <= '1')
val += ptr[i] - '0';
else
- parse_error(ERR_INCORRECT_BIN, str);
+ ShowError(ERR_INCORRECT_BIN, str);
}
break;
default:
@@ -237,19 +227,17 @@ s32 DSPAssembler::strtoval(const char *str)
if (ptr[i] >= '0' && ptr[i] <= '9')
val += ptr[i] - '0';
else
- parse_error(ERR_INCORRECT_DEC, str);
+ ShowError(ERR_INCORRECT_DEC, str);
}
}
else // Everything else is a label.
{
// Lookup label
- for (int i = 0; i < labels.size(); i++)
- {
- if (strcmp(labels[i].label.c_str(), ptr) == 0)
- return labels[i].addr;
- }
+ u16 value;
+ if (labels.GetLabelValue(ptr, &value))
+ return value;
if (cur_pass == 2)
- parse_error(ERR_UNKNOWN_LABEL, str);
+ ShowError(ERR_UNKNOWN_LABEL, str);
}
}
if (negative)
@@ -257,10 +245,9 @@ s32 DSPAssembler::strtoval(const char *str)
return val;
}
-
// Modifies both src and dst!
// What does it do, really??
-char *DSPAssembler::find_brackets(char *src, char *dst)
+char *DSPAssembler::FindBrackets(char *src, char *dst)
{
s32 len = (s32) strlen(src);
s32 first = -1;
@@ -302,12 +289,12 @@ char *DSPAssembler::find_brackets(char *src, char *dst)
}
}
if (count)
- parse_error(ERR_NO_MATCHING_BRACKETS);
+ ShowError(ERR_NO_MATCHING_BRACKETS);
return NULL;
}
// Bizarre in-place expression evaluator.
-u32 DSPAssembler::parse_exp(const char *ptr)
+u32 DSPAssembler::ParseExpression(const char *ptr)
{
char *pbuf;
s32 val = 0;
@@ -316,9 +303,9 @@ u32 DSPAssembler::parse_exp(const char *ptr)
char *s_buffer = (char *)malloc(1024);
strcpy(s_buffer, ptr);
- while ((pbuf = find_brackets(s_buffer, d_buffer)) != NULL)
+ while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL)
{
- val = parse_exp(d_buffer);
+ val = ParseExpression(d_buffer);
sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf);
strcpy(s_buffer, d_buffer);
}
@@ -351,17 +338,18 @@ u32 DSPAssembler::parse_exp(const char *ptr)
}
d_buffer[i] = c;
}
+
while ((pbuf = strstr(d_buffer, "+")) != NULL)
{
*pbuf = 0x0;
- val = parse_exp(d_buffer) + parse_exp(pbuf+1);
+ val = ParseExpression(d_buffer) + ParseExpression(pbuf+1);
sprintf(d_buffer, "%d", val);
}
while ((pbuf = strstr(d_buffer, "-")) != NULL)
{
*pbuf = 0x0;
- val = parse_exp(d_buffer) - parse_exp(pbuf+1);
+ val = ParseExpression(d_buffer) - ParseExpression(pbuf+1);
if (val < 0)
{
val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf
@@ -373,44 +361,39 @@ u32 DSPAssembler::parse_exp(const char *ptr)
while ((pbuf = strstr(d_buffer, "*")) != NULL)
{
*pbuf = 0x0;
- val = parse_exp(d_buffer) * parse_exp(pbuf+1);
+ val = ParseExpression(d_buffer) * ParseExpression(pbuf+1);
sprintf(d_buffer, "%d", val);
}
while ((pbuf = strstr(d_buffer, "/")) != NULL)
{
*pbuf = 0x0;
- val = parse_exp(d_buffer) / parse_exp(pbuf+1);
+ val = ParseExpression(d_buffer) / ParseExpression(pbuf+1);
sprintf(d_buffer, "%d", val);
}
while ((pbuf = strstr(d_buffer, "|")) != NULL)
{
*pbuf = 0x0;
- val = parse_exp(d_buffer) | parse_exp(pbuf+1);
+ val = ParseExpression(d_buffer) | ParseExpression(pbuf+1);
sprintf(d_buffer, "%d", val);
}
while ((pbuf = strstr(d_buffer, "&")) != NULL)
{
*pbuf = 0x0;
- val = parse_exp(d_buffer) & parse_exp(pbuf+1);
+ val = ParseExpression(d_buffer) & ParseExpression(pbuf+1);
sprintf(d_buffer, "%d", val);
}
- val = strtoval(d_buffer);
+ val = ParseValue(d_buffer);
free(d_buffer);
free(s_buffer);
return val;
}
-u32 DSPAssembler::parse_exp_f(const char *ptr)
-{
- return parse_exp(ptr);
-}
-
// Destroys parstr
-u32 DSPAssembler::get_params(char *parstr, param_t *par)
+u32 DSPAssembler::GetParams(char *parstr, param_t *par)
{
u32 count = 0;
char *tmpstr = skip_spaces(parstr);
@@ -435,27 +418,28 @@ u32 DSPAssembler::get_params(char *parstr, param_t *par)
par[i].type = P_STR;
break;
case '#':
- par[i].val = parse_exp_f(tmpstr + 1);
+ par[i].val = ParseExpression(tmpstr + 1);
par[i].type = P_IMM;
break;
case '@':
if (tmpstr[1] == '$')
{
- par[i].val = parse_exp_f(tmpstr + 2);
+ par[i].val = ParseExpression(tmpstr + 2);
par[i].type = P_PRG;
}
else
{
- par[i].val = parse_exp_f(tmpstr + 1);
+ par[i].val = ParseExpression(tmpstr + 1);
par[i].type = P_MEM;
}
break;
case '$':
- par[i].val = parse_exp_f(tmpstr + 1);
+ par[i].val = ParseExpression(tmpstr + 1);
par[i].type = P_REG;
break;
+
default:
- par[i].val = parse_exp_f(tmpstr);
+ par[i].val = ParseExpression(tmpstr);
par[i].type = P_VAL;
break;
}
@@ -464,7 +448,7 @@ u32 DSPAssembler::get_params(char *parstr, param_t *par)
return count;
}
-const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size)
+const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size)
{
if (opcode[0] == 'C' && opcode[1] == 'W')
return &cw;
@@ -479,16 +463,16 @@ const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const
{
if (par_count < opc->param_count)
{
- parse_error(ERR_NOT_ENOUGH_PARAMETERS);
+ ShowError(ERR_NOT_ENOUGH_PARAMETERS);
}
if (par_count > opc->param_count)
{
- parse_error(ERR_TOO_MANY_PARAMETERS);
+ ShowError(ERR_TOO_MANY_PARAMETERS);
}
return opc;
}
}
- parse_error(ERR_UNKNOWN_OPCODE);
+ ShowError(ERR_UNKNOWN_OPCODE);
return NULL;
}
@@ -500,13 +484,20 @@ u16 get_mask_shifted_down(u16 mask)
return mask;
}
-bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool ext)
+bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext)
{
for (int i = 0; i < count; i++)
{
const int current_param = i + 1; // just for display.
if (opc->params[i].type != par[i].type || (par[i].type & P_REG))
{
+ if (par[i].type == P_VAL &&
+ (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D))
+ {
+ // Data and instruction addresses are valid as VAL values.
+ continue;
+ }
+
if ((opc->params[i].type & P_REG) && (par[i].type & P_REG))
{
// Just a temp. Should be replaced with more purposeful vars.
@@ -524,7 +515,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
{
if (ext) fprintf(stderr, "(ext) ");
fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- parse_error(ERR_INVALID_REGISTER);
+ ShowError(ERR_INVALID_REGISTER);
}
break;
case P_PRG:
@@ -532,21 +523,24 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
{
if (ext) fprintf(stderr, "(ext) ");
fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- parse_error(ERR_INVALID_REGISTER);
+ ShowError(ERR_INVALID_REGISTER);
}
break;
case P_ACC:
if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21)
{
if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1e && par[i].val <= 0x1f)
+ if (par[i].val >= 0x1e && par[i].val <= 0x1f) {
+ fprintf(stderr, "%i : %s", code_line, cur_line.c_str());
fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d\n",
(par[i].val & 1), (par[i].val & 1), code_line, current_param, ext);
- else if (par[i].val >= 0x1c && par[i].val <= 0x1d)
+ }
+ else if (par[i].val >= 0x1c && par[i].val <= 0x1d) {
fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n",
(par[i].val & 1), (par[i].val & 1), code_line, current_param);
+ }
else
- parse_error(ERR_WRONG_PARAMETER_ACC);
+ ShowError(ERR_WRONG_PARAMETER_ACC);
}
break;
case P_ACCM:
@@ -560,7 +554,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n",
(par[i].val & 1), (par[i].val & 1), code_line, current_param);
else
- parse_error(ERR_WRONG_PARAMETER_ACC);
+ ShowError(ERR_WRONG_PARAMETER_ACC);
}
break;
@@ -580,39 +574,39 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
(par[i].val & 1), (par[i].val & 1), code_line, current_param);
}
else
- parse_error(ERR_WRONG_PARAMETER_ACC);
+ ShowError(ERR_WRONG_PARAMETER_ACC);
}
break;
/* case P_ACCM_D: //P_ACC_MID:
if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
{
- parse_error(ERR_WRONG_PARAMETER_MID_ACC);
+ ShowError(ERR_WRONG_PARAMETER_MID_ACC);
}
break;*/
}
continue;
}
- switch (par[i].type & (P_REG | P_VAL | P_MEM | P_IMM))
+ switch (par[i].type & (P_REG | 7))
{
case P_REG:
if (ext) fprintf(stderr, "(ext) ");
- parse_error(ERR_EXPECTED_PARAM_REG);
+ ShowError(ERR_EXPECTED_PARAM_REG);
break;
case P_MEM:
if (ext) fprintf(stderr, "(ext) ");
- parse_error(ERR_EXPECTED_PARAM_MEM);
+ ShowError(ERR_EXPECTED_PARAM_MEM);
break;
case P_VAL:
if (ext) fprintf(stderr, "(ext) ");
- parse_error(ERR_EXPECTED_PARAM_VAL);
+ ShowError(ERR_EXPECTED_PARAM_VAL);
break;
case P_IMM:
if (ext) fprintf(stderr, "(ext) ");
- parse_error(ERR_EXPECTED_PARAM_IMM);
+ ShowError(ERR_EXPECTED_PARAM_IMM);
break;
}
- parse_error(ERR_WRONG_PARAMETER);
+ ShowError(ERR_WRONG_PARAMETER);
break;
}
else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0)
@@ -625,7 +619,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
if (value == 7) // value 7 por sbclr/sbset
{
fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value);
- parse_error(ERR_OUT_RANGE_NUMBER);
+ ShowError(ERR_OUT_RANGE_NUMBER);
}
else if (opc->params[i].type == P_MEM)
{
@@ -634,7 +628,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
else
fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value);
- parse_error(ERR_OUT_RANGE_NUMBER);
+ ShowError(ERR_OUT_RANGE_NUMBER);
}
else if ((int)par[i].val < -((value >> 1) + 1))
{
@@ -645,7 +639,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n",
(value >> 1) + 1, value >> 1, value, par[i].val);
- parse_error(ERR_OUT_RANGE_NUMBER);
+ ShowError(ERR_OUT_RANGE_NUMBER);
}
}
else
@@ -655,7 +649,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
if (par[i].val > (unsigned)value)
{
fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val);
- parse_error(ERR_OUT_RANGE_NUMBER);
+ ShowError(ERR_OUT_RANGE_NUMBER);
}
}
else if (opc->params[i].type == P_MEM)
@@ -669,7 +663,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val);
else
fprintf(stderr,"Address value must be minor of 0x%x\n", value+1);
- parse_error(ERR_OUT_RANGE_NUMBER);
+ ShowError(ERR_OUT_RANGE_NUMBER);
}
}
else
@@ -682,7 +676,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val);
else
fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val);
- parse_error(ERR_OUT_RANGE_NUMBER);
+ ShowError(ERR_OUT_RANGE_NUMBER);
}
}
}
@@ -695,7 +689,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool
// Merge opcode with params.
-void DSPAssembler::build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
+void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
{
outbuf[cur_addr] |= opc->opcode;
for (u32 i = 0; i < par_count; i++)
@@ -721,15 +715,8 @@ void DSPAssembler::InitPass(int pass)
if (pass == 1)
{
// Reset label table. Pre-populate with hw addresses and registers.
- gd_ass_clear_labels();
- for (int i = 0; i < 0x24; i++)
- {
- gd_ass_register_label(regnames[i].name, regnames[i].addr);
- }
- for (int i = 0; i < (int)pdlabels_size; i++)
- {
- gd_ass_register_label(pdlabels[i].name, pdlabels[i].addr);
- }
+ labels.Clear();
+ labels.RegisterDefaults();
aliases.clear();
aliases["S15"] = "SET15";
aliases["S16"] = "SET16";
@@ -875,9 +862,9 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
}
if (paramstr)
- params_count = get_params(paramstr, params);
+ params_count = GetParams(paramstr, params);
if (paramstr_ext)
- params_count_ext = get_params(paramstr_ext, params_ext);
+ params_count_ext = GetParams(paramstr_ext, params_ext);
}
if (label)
@@ -893,7 +880,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
}
}
if (pass == 1)
- gd_ass_register_label(label, lval);
+ labels.RegisterLabel(label, lval);
}
if (opcode == NULL)
@@ -919,7 +906,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
free(tmpstr);
}
else
- parse_error(ERR_EXPECTED_PARAM_STR);
+ ShowError(ERR_EXPECTED_PARAM_STR);
continue;
}
@@ -928,7 +915,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
if (params[0].type == P_STR)
include_dir = params[0].str;
else
- parse_error(ERR_EXPECTED_PARAM_STR);
+ ShowError(ERR_EXPECTED_PARAM_STR);
continue;
}
@@ -937,7 +924,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
if (params[0].type == P_VAL)
cur_addr = params[0].val;
else
- parse_error(ERR_EXPECTED_PARAM_VAL);
+ ShowError(ERR_EXPECTED_PARAM_VAL);
continue;
}
@@ -953,17 +940,17 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
cur_addr = segment_addr[cur_segment];
}
else
- parse_error(ERR_EXPECTED_PARAM_STR);
+ ShowError(ERR_EXPECTED_PARAM_STR);
continue;
}
- const opc_t *opc = find_opcode(opcode, params_count, opcodes, opcodes_size);
+ const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
if (!opc)
opc = &cw;
opcode_size = opc->size & ~P_EXT;
- verify_params(opc, params, params_count);
+ VerifyParams(opc, params, params_count);
const opc_t *opc_ext = NULL;
// Check for opcode extensions.
@@ -971,27 +958,27 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
{
if (opcode_ext)
{
- opc_ext = find_opcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size);
- verify_params(opc_ext, params_ext, params_count_ext, true);
+ opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size);
+ VerifyParams(opc_ext, params_ext, params_count_ext, true);
}
else if (params_count_ext)
- parse_error(ERR_EXT_PAR_NOT_EXT);
+ ShowError(ERR_EXT_PAR_NOT_EXT);
}
else
{
if (opcode_ext)
- parse_error(ERR_EXT_CANT_EXTEND_OPCODE);
+ ShowError(ERR_EXT_CANT_EXTEND_OPCODE);
if (params_count_ext)
- parse_error(ERR_EXT_PAR_NOT_EXT);
+ ShowError(ERR_EXT_PAR_NOT_EXT);
}
if (pass == 2)
{
// generate binary
((u16 *)gdg_buffer)[cur_addr] = 0x0000;
- build_code(opc, params, params_count, (u16 *)gdg_buffer);
+ BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
if (opc_ext)
- build_code(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
+ BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
}
cur_addr += opcode_size;
diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h
index 3d3800d343..4b698e7e6e 100644
--- a/Source/Core/DSPCore/Src/assemble.h
+++ b/Source/Core/DSPCore/Src/assemble.h
@@ -31,6 +31,7 @@
#include "Common.h"
#include "disassemble.h"
#include "DSPTables.h"
+#include "LabelMap.h"
enum err_t
{
@@ -59,6 +60,7 @@ enum err_t
ERR_OUT_RANGE_NUMBER
};
+
// Unless you want labels to carry over between files, you probably
// want to create a new DSPAssembler for every file you assemble.
class DSPAssembler
@@ -77,13 +79,6 @@ public:
err_t GetError() const { return last_error; }
private:
- struct label_t
- {
- label_t(const char *lbl, s32 address) : label(lbl), addr(address) {}
- std::string label;
- s32 addr;
- };
-
struct param_t
{
u32 val;
@@ -99,30 +94,33 @@ private:
SEGMENT_MAX
};
+ // Utility functions
+ s32 ParseValue(const char *str);
+ u32 ParseExpression(const char *ptr);
+
+ u32 GetParams(char *parstr, param_t *par);
+
void InitPass(int pass);
bool AssembleFile(const char *fname, int pass);
+ void ShowError(err_t err_code, const char *extra_info = NULL);
+ // void ShowWarning(err_t err_code, const char *extra_info = NULL);
+
+ char *FindBrackets(char *src, char *dst);
+ const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size);
+ bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false);
+ void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
+
char *gdg_buffer;
int gdg_buffer_size;
- void parse_error(err_t err_code, const char *extra_info = NULL);
- void gd_ass_register_label(const char *label, u16 lval);
- void gd_ass_clear_labels();
- s32 strtoval(const char *str);
- char *find_brackets(char *src, char *dst);
- u32 parse_exp(const char *ptr);
- u32 parse_exp_f(const char *ptr);
- u32 get_params(char *parstr, param_t *par);
- const opc_t *find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size);
- bool verify_params(const opc_t *opc, param_t *par, int count, bool ext = false);
- void build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
-
std::string include_dir;
- std::vector labels;
std::string cur_line;
u32 cur_addr;
u8 cur_pass;
+
+ LabelMap labels;
FILE *fsrc;
u32 code_line;
diff --git a/Source/Core/DSPCore/Src/disassemble.cpp b/Source/Core/DSPCore/Src/disassemble.cpp
index 8accae2ecf..4840517fbb 100644
--- a/Source/Core/DSPCore/Src/disassemble.cpp
+++ b/Source/Core/DSPCore/Src/disassemble.cpp
@@ -82,15 +82,8 @@ bool DSPDisassembler::Disassemble(int start_pc, const std::vector &code, st
fwrite(&code[0], 1, code.size() * 2, f);
fclose(f);
- FILE* t = fopen(tmp2, "w");
- if (!t)
- return false;
-
- bool success = DisFile(tmp1, t);
- fclose(t);
-
- File::ReadFileToString(true, tmp2, text);
- return success;
+ // Run the two passes.
+ return DisFile(tmp1, 1, text) && DisFile(tmp1, 2, text);
}
char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char *strbuf)
@@ -101,31 +94,24 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
if (j > 0)
buf += sprintf(buf, ", ");
- u32 val;
- if (opc.params[j].loc >= 1)
- val = op2;
- else
- val = op1;
-
+ u32 val = (opc.params[j].loc >= 1) ? val = op2 : val = op1;
val &= opc.params[j].mask;
-
if (opc.params[j].lshift < 0)
val = val << (-opc.params[j].lshift);
else
val = val >> opc.params[j].lshift;
u32 type = opc.params[j].type;
-
if ((type & 0xff) == 0x10)
type &= 0xff00;
if (type & P_REG)
{
+ // Check for _D parameter - if so flip.
if (type == P_ACC_D) // Used to be P_ACCM_D TODO verify
val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8);
else
val |= (type & P_REGS_MASK) >> 8;
-
type &= ~P_REGS_MASK;
}
@@ -146,8 +132,12 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
break;
case P_VAL:
+ case P_ADDR_I:
+ case P_ADDR_D:
if (settings_.decode_names)
+ {
sprintf(buf, "%s", pdname(val));
+ }
else
sprintf(buf, "0x%04x", val);
break;
@@ -156,17 +146,19 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
if (opc.params[j].size != 2)
{
if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR
- sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val);
+ sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension
else
sprintf(buf, "#0x%02x", val);
}
else
+ {
sprintf(buf, "#0x%04x", val);
+ }
break;
case P_MEM:
if (opc.params[j].size != 2)
- val = (u16)(s8)val;
+ val = (u16)(s16)(s8)val;
if (settings_.decode_names)
sprintf(buf, "@%s", pdname(val));
@@ -185,12 +177,22 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
return strbuf;
}
-void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
+static void MakeLowerCase(char *ptr)
+{
+ int i = 0;
+ while (ptr[i])
+ {
+ ptr[i] = tolower(ptr[i]);
+ i++;
+ }
+}
+
+void DSPDisassembler::DisOpcode(const u16 *binbuf, int pass, u16 *pc, std::string *dest)
{
- u32 op2;
char buffer[256];
char *buf = buffer;
- // Start with a space.
+
+ // Start with 8 spaces, if there's no label.
buf[0] = ' ';
buf[1] = '\0';
buf++;
@@ -206,6 +208,7 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
const DSPOPCTemplate *opc = NULL;
const DSPOPCTemplate *opc_ext = NULL;
+
// find opcode
for (int j = 0; j < opcodes_size; j++)
{
@@ -222,13 +225,12 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
break;
}
}
-
const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
if (!opc)
opc = &fake_op;
bool extended;
- if (opc->size & P_EXT && op1 & 0x00ff)
+ if ((opc->size & P_EXT) && (op1 & 0x00ff))
extended = true;
else
extended = false;
@@ -250,52 +252,52 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
// printing
if (settings_.show_pc)
- sprintf(buf, "%04x ", *pc);
+ buf += sprintf(buf, "%04x ", *pc);
- buf += strlen(buf);
+ u32 op2;
+ // Size 2 - the op has a large immediate.
if ((opc->size & ~P_EXT) == 2)
{
op2 = binbuf[*pc + 1];
if (settings_.show_hex)
- sprintf(buf, "%04x %04x ", op1, op2);
+ buf += sprintf(buf, "%04x %04x ", op1, op2);
}
else
{
op2 = 0;
-
if (settings_.show_hex)
- sprintf(buf, "%04x ", op1);
+ buf += sprintf(buf, "%04x ", op1);
}
- buf += strlen(buf);
-
- char tmpbuf[20];
-
+ char opname[20];
+ strcpy(opname, opc->name);
+ if (settings_.lower_case_ops)
+ MakeLowerCase(opname);
+ char ext_buf[20];
if (extended)
- sprintf(tmpbuf, "%s%c%s", opc->name, settings_.ext_separator, opc_ext->name);
+ sprintf(ext_buf, "%s%c%s", opname, settings_.ext_separator, opc_ext->name);
else
- sprintf(tmpbuf, "%s", opc->name);
+ sprintf(ext_buf, "%s", opname);
+ if (settings_.lower_case_ops)
+ MakeLowerCase(ext_buf);
if (settings_.print_tabs)
- sprintf(buf, "%s\t", tmpbuf);
+ buf += sprintf(buf, "%s\t", ext_buf);
else
- sprintf(buf, "%-12s", tmpbuf);
-
- buf += strlen(buf);
+ buf += sprintf(buf, "%-12s", ext_buf);
if (opc->param_count > 0)
DisParams(*opc, op1, op2, buf);
buf += strlen(buf);
+ // Handle opcode extension.
if (extended)
{
if (opc->param_count > 0)
buf += sprintf(buf, " ");
-
buf += sprintf(buf, ": ");
-
if (opc_ext->param_count > 0)
DisParams(*opc_ext, op1, op2, buf);
@@ -314,40 +316,33 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
else
*pc += opc->size & ~P_EXT;
- dest->append(buffer);
+ if (pass == 2)
+ dest->append(buffer);
}
-bool DSPDisassembler::DisFile(const char* name, FILE* output)
+bool DSPDisassembler::DisFile(const char* name, int pass, std::string *output)
{
- FILE* in;
- u32 size;
-
- in = fopen(name, "rb");
- if (in == NULL) {
+ FILE* in = fopen(name, "rb");
+ if (in == NULL)
+ {
printf("gd_dis_file: No input\n");
return false;
}
fseek(in, 0, SEEK_END);
- size = (int)ftell(in) & ~1;
+ int size = (int)ftell(in) & ~1;
fseek(in, 0, SEEK_SET);
-
u16 *binbuf = new u16[size / 2];
fread(binbuf, 1, size, in);
+ fclose(in);
+ // Actually do the disassembly.
for (u16 pc = 0; pc < (size / 2);)
{
- std::string str;
- DisOpcode(binbuf, &pc, &str);
- fprintf(output, "%s\n", str.c_str());
+ DisOpcode(binbuf, pass, &pc, output);
+ if (pass == 2)
+ output->append("\n");
}
-
- fclose(in);
delete [] binbuf;
return true;
}
-
-const char *gd_get_reg_name(u16 reg)
-{
- return regnames[reg].name;
-}
diff --git a/Source/Core/DSPCore/Src/disassemble.h b/Source/Core/DSPCore/Src/disassemble.h
index 610755407a..e131450ef5 100644
--- a/Source/Core/DSPCore/Src/disassemble.h
+++ b/Source/Core/DSPCore/Src/disassemble.h
@@ -30,6 +30,7 @@
#include "Common.h"
#include "DSPTables.h"
+#include "LabelMap.h"
struct AssemblerSettings
{
@@ -40,6 +41,7 @@ struct AssemblerSettings
decode_names(true),
decode_registers(true),
ext_separator('\''),
+ lower_case_ops(true),
pc(0)
{
}
@@ -50,6 +52,7 @@ struct AssemblerSettings
bool decode_names;
bool decode_registers;
char ext_separator;
+ bool lower_case_ops;
u16 pc;
};
@@ -63,19 +66,20 @@ public:
bool Disassemble(int start_pc, const std::vector &code, std::string *text);
// Warning - this one is trickier to use right.
- void DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest);
+ // Use pass == 2 if you're just using it by itself.
+ void DisOpcode(const u16 *binbuf, int pass, u16 *pc, std::string *dest);
private:
// Moves PC forward and writes the result to dest.
- bool DisFile(const char* name, FILE *output);
+ bool DisFile(const char* name, int pass, std::string *output);
char* DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char* strbuf);
std::map unk_opcodes;
const AssemblerSettings settings_;
-};
-const char *gd_get_reg_name(u16 reg);
+ LabelMap labels;
+};
#endif // _DSP_DISASSEMBLE_H
diff --git a/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h b/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h
index 7bfdadd2b8..ee6b02d552 100644
--- a/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h
+++ b/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h
@@ -123,7 +123,9 @@ inline s64 dsp_get_long_prod()
return val;
}
-
+// For accurate emulation, this is wrong - it should take the two multiplicands
+// as input and set the two mid stages accordingly. most likely it's doing something
+// pretty simple.
inline void dsp_set_long_prod(s64 val)
{
#if PROFILE
diff --git a/Source/DSPTool/Src/main.cpp b/Source/DSPTool/Src/main.cpp
index 42bfc0774e..d355fc31d5 100644
--- a/Source/DSPTool/Src/main.cpp
+++ b/Source/DSPTool/Src/main.cpp
@@ -19,6 +19,8 @@
#include "FileUtil.h"
#include "DSPCodeUtil.h"
+#include "dsp_test.h"
+
// Stub out the dsplib host stuff, since this is just a simple cmdline tools.
u8 DSPHost_ReadHostMemory(u32 addr) { return 0; }
bool DSPHost_OnThread() { return false; }
@@ -41,7 +43,11 @@ bool RoundTrip(const std::vector &code1)
printf("RoundTrip: Assembly failed.\n");
return false;
}
- Compare(code1, code2);
+ if (!Compare(code1, code2))
+ {
+ Disassemble(code1, true, &text);
+ printf("%s", text.c_str());
+ }
return true;
}
@@ -64,8 +70,8 @@ bool SuperTrip(const char *asm_code)
}
else
{
- //printf("Disass:\n");
- //printf("%s", text.c_str());
+ printf("Disass:\n");
+ printf("%s", text.c_str());
}
if (!Assemble(text.c_str(), &code2))
{
@@ -119,8 +125,47 @@ void RunAsmTests()
//" ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n");
// Let's get brutal. We generate random code bytes and make sure that they can
// be roundtripped. We don't expect it to always succeed but it'll be sure to generate
- // interesting test cases.
+ // interesting test cases.
+ /*
+ std::vector hermes;
+ if (!LoadBinary("testdata/hermes.bin", &hermes))
+ PanicAlert("Failed to load hermes rom");
+ RoundTrip(hermes);
+ */
+ /*
+ std::vector code;
+ std::string text_orig;
+ File::ReadFileToString(false, "testdata/dsp_test.S", &text_orig);
+ if (!Assemble(text_orig.c_str(), &code))
+ {
+ printf("SuperTrip: First assembly failed\n");
+ return;
+ }*/
+
+ /*
+ code.clear();
+ for (int i = 0; i < sizeof(dsp_test)/4; i++)
+ {
+ code.push_back(dsp_test[i] >> 16);
+ code.push_back(dsp_test[i] & 0xFFFF);
+ }
+
+ SaveBinary(code, "dsp_test.bin");
+ RoundTrip(code);*/
+ //if (Compare(code, hermes))
+ // printf("Successs\n");
+/*
+ {
+ std::vector code;
+ std::string text;
+ LoadBinary("testdata/dsp_test.bin", &code);
+ Disassemble(code, true, &text);
+ Assemble(text.c_str(), &code);
+ Disassemble(code, true, &text);
+ printf("%s", text.c_str());
+ }*/
+ /*
puts("Insane Random Code Test\n");
std::vector rand_code;
GenRandomCode(30, &rand_code);
@@ -129,24 +174,102 @@ void RunAsmTests()
printf("%s", rand_code_text.c_str());
RoundTrip(rand_code);
- std::string dsp_test;
if (File::ReadFileToString(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test))
SuperTrip(dsp_test.c_str());
//.File::ReadFileToString(true, "C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test);
// This is CLOSE to working. Sorry about the local path btw. This is preliminary code.
-
+*/
+
+ std::string dsp_test;
+ if (File::ReadFileToString(true, "Testdata/dsp_test.s", &dsp_test))
+ fail = fail || !SuperTrip(dsp_test.c_str());
if (!fail)
printf("All passed!\n");
}
+
+// Usage:
+// Run internal tests:
+// dsptool test
+// Disassemble a file:
+// dsptool -d -o asdf.txt asdf.bin
+// Disassemble a file, output to standard output:
+// dsptool -d asdf.bin
+// Assemble a file:
+// dsptool -o asdf.bin asdf.txt
+// Assemble a file, output header:
+// dsptool -h asdf.h asdf.txt
+
// So far, all this binary can do is test partially that itself works correctly.
int main(int argc, const char *argv[])
{
if (argc == 2 && !strcmp(argv[1], "test"))
{
- RunAsmTests();
+ RunAsmTests();
+ return 0;
+ }
+
+ std::string input_name;
+ std::string output_header_name;
+ std::string output_name;
+
+ bool disassemble = false;
+ for (int i = 1; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-d"))
+ disassemble = true;
+ else if (!strcmp(argv[i], "-o"))
+ output_name = argv[++i];
+ else if (!strcmp(argv[i], "-h"))
+ output_header_name = argv[++i];
+ else
+ {
+ if (!input_name.empty())
+ {
+ printf("Can only take one input file.\n");
+ return 1;
+ }
+ input_name = argv[i];
+ }
+ }
+
+ if (disassemble)
+ {
+ if (input_name.empty())
+ {
+ printf("Must specify input.\n");
+ return 1;
+ }
+ std::string binary_code;
+ std::vector code;
+ File::ReadFileToString(false, input_name.c_str(), &binary_code);
+ BinaryStringBEToCode(binary_code, &code);
+ std::string text;
+ Disassemble(code, true, &text);
+ File::WriteStringToFile(true, text, output_name.c_str());
+ }
+ else
+ {
+ std::string source;
+ if (File::ReadFileToString(true, input_name.c_str(), &source))
+ {
+ std::vector code;
+ Assemble(source.c_str(), &code);
+ if (!output_name.empty())
+ {
+ std::string binary_code;
+ CodeToBinaryStringBE(code, &binary_code);
+ File::WriteStringToFile(false, binary_code, output_name.c_str());
+ }
+ if (!output_header_name.empty())
+ {
+ std::string header;
+ CodeToHeader(code, output_header_name.c_str(), &header);
+ File::WriteStringToFile(true, header, (output_header_name + ".h").c_str());
+ }
+ }
}
return 0;
}
\ No newline at end of file
diff --git a/Source/DSPTool/Testdata/dsp_test.S b/Source/DSPTool/Testdata/dsp_test.S
new file mode 100644
index 0000000000..11de8ff33e
--- /dev/null
+++ b/Source/DSPTool/Testdata/dsp_test.S
@@ -0,0 +1,639 @@
+
+DSCR: equ 0xffc9 ; DSP DMA Control Reg
+DSBL: equ 0xffcb ; DSP DMA Block Length
+DSPA: equ 0xffcd ; DSP DMA DMEM Address
+DSMAH: equ 0xffce ; DSP DMA Mem Address H
+DSMAL: equ 0xffcf ; DSP DMA Mem Address L
+
+ACSAH: equ 0xffd4
+ACSAL: equ 0xffd5
+ACEAH: equ 0xffd6
+ACEAL: equ 0xffd7
+ACCAH: equ 0xffd8
+ACCAL: equ 0xffd9
+AMDM: equ 0xffef ; ARAM DMA Request Mask
+
+DIRQ: equ 0xfffb ; DSP Irq Request
+DMBH: equ 0xfffc ; DSP Mailbox H
+DMBL: equ 0xfffd ; DSP Mailbox L
+CMBH: equ 0xfffe ; CPU Mailbox H
+CMBL: equ 0xffff ; CPU Mailbox L
+
+R00: equ 0x00
+R01: equ 0x01
+R02: equ 0x02
+R03: equ 0x03
+R04: equ 0x04
+R05: equ 0x05
+R06: equ 0x06
+R07: equ 0x07
+R08: equ 0x08
+R09: equ 0x09
+R0A: equ 0x0a
+R0B: equ 0x0b
+R0C: equ 0x0c
+R0D: equ 0x0d
+R0E: equ 0x0e
+R0F: equ 0x0f
+R10: equ 0x10
+R11: equ 0x11
+R12: equ 0x12
+R13: equ 0x13
+R14: equ 0x14
+R15: equ 0x15
+R16: equ 0x16
+R17: equ 0x17
+R18: equ 0x18
+R19: equ 0x19
+R1A: equ 0x1a
+R1B: equ 0x1b
+R1C: equ 0x1c
+R1D: equ 0x1d
+R1E: equ 0x1e
+R1F: equ 0x1f
+
+ACH0: equ 0x10
+ACH1: equ 0x11
+ACL0: equ 0x1e
+ACL1: equ 0x1f
+
+DSP_CR_IMEM: equ 2
+DSP_CR_TO_CPU: equ 1
+
+
+REGS_BASE: equ 0x0f80
+MEM_HI: equ 0x0f7E
+MEM_LO: equ 0x0f7F
+
+
+; Interrupt vectors 8 vectors, 2 opcodes each
+
+ jmp irq0
+ jmp irq1
+ jmp irq2
+ jmp irq3
+ jmp irq4
+ jmp irq5
+ jmp irq6
+ jmp irq7
+
+; Main code at 0x10
+ CW 0x1302
+ CW 0x1303
+ CW 0x1204
+ CW 0x1305
+ CW 0x1306
+
+ s40
+ lri $r12, #0x00ff
+
+main:
+
+ cw 0x8900
+ cw 0x8100
+
+; get address of memory dump and copy it
+
+ call wait_for_dsp_mbox
+ si @DMBH, #0x8888
+ si @DMBL, #0xdead
+ si @DIRQ, #0x0001
+
+ call wait_for_cpu_mbox
+ lrs $ACL0, @CMBL
+ andi $acl1, #0x7fff
+
+ sr @MEM_HI, $ACL1
+ sr @MEM_LO, $ACL0
+
+ lri $r18, #0
+ lri $r19, #0 ;(DSP_CR_IMEM | DSP_CR_TO_CPU)
+ lri $r1a, #0x2000
+ lr $r1c, @MEM_HI
+ lr $r1e, @MEM_LO
+ call do_dma
+
+
+; get address of registers and DMA them to memory
+
+ call wait_for_dsp_mbox
+ si @DMBH, #0x8888
+ si @DMBL, #0xbeef
+ si @DIRQ, #0x0001
+
+ call wait_for_cpu_mbox
+ lrs $ACL0, @CMBL
+ andi $acl1, #0x7fff
+
+ sr @MEM_HI, $ACL1
+ sr @MEM_LO, $ACL0
+
+ lri $r18, #REGS_BASE
+ lri $r19, #0 ;(DSP_CR_IMEM | DSP_CR_TO_CPU)
+ lri $r1a, #0x80
+ lr $r1c, @MEM_HI
+ lr $r1e, @MEM_LO
+ call do_dma
+
+
+
+ lri $r00, #REGS_BASE+1
+ lrri $r01, @$r00
+ lrri $r02, @$r00
+ lrri $r03, @$r00
+ lrri $r04, @$r00
+ lrri $r05, @$r00
+ lrri $r06, @$r00
+ lrri $r07, @$r00
+ lrri $r08, @$r00
+ lrri $r09, @$r00
+ lrri $r0a, @$r00
+ lrri $r0b, @$r00
+ lrri $r0c, @$r00
+ lrri $r0d, @$r00
+ lrri $r0e, @$r00
+ lrri $r0f, @$r00
+ lrri $r10, @$r00
+ lrri $r11, @$r00
+ lrri $r12, @$r00
+ lrri $r13, @$r00
+ lrri $r14, @$r00
+ lrri $r15, @$r00
+ lrri $r16, @$r00
+ lrri $r17, @$r00
+ lrri $r18, @$r00
+ lrri $r19, @$r00
+ lrri $r1a, @$r00
+ lrri $r1b, @$r00
+ lrri $r1c, @$r00
+ lrri $r1d, @$r00
+ lrri $r1e, @$r00
+ lrri $r1f, @$r00
+ lr $r00, @REGS_BASE
+
+ nop
+ nop
+ nop
+ nop
+
+
+
+
+ cw 0x8600
+
+ call send_back
+
+ JMP ende
+
+
+; call dump_memory
+; call send_back
+
+
+; 0x041e
+;
+
+ cw 0x00de
+ cw 0x03f1
+ call send_back
+
+ cw 0x0200
+ cw 0x0a60
+ call send_back
+
+ cw 0x1c7e
+ call send_back
+
+ cw 0x8100
+ call send_back
+
+ cw 0x8900
+ call send_back
+
+ cw 0x009f
+ cw 0x00a0
+ call send_back
+
+ cw 0x00de
+ cw 0x03f1
+ call send_back
+
+ cw 0x5d00
+ call send_back
+
+ cw 0x0e50
+ call send_back
+
+ cw 0x0750
+ call send_back
+
+ cw 0x0270
+ call send_back
+
+ cw 0x5d00
+ call send_back
+
+ cw 0x00da
+ cw 0x03f2
+ call send_back
+
+ cw 0x8600
+ call send_back
+
+ JNS g_0c4d
+; cw 0x0290
+; cw 0x0c4d
+; call send_back JX0
+
+ cw 0x00de
+ cw 0x03f3
+ call send_back
+
+ cw 0x5c00
+ call send_back
+
+ JLE g_0c38
+; cw 0x0293
+; cw 0x0c38 JX3
+; call send_back
+
+ JMP g_0c52
+
+; cw 0x029f
+; cw 0x0c52
+; call send_back
+
+g_0c38:
+ cw 0x00db
+ cw 0x03f7
+ call send_back
+
+ cw 0x009e
+ cw 0x8000
+ call send_back
+
+ cw 0x4600
+ call send_back
+
+ JMP g_0c44
+; cw 0x029f
+; cw 0x0c44
+; call send_back
+
+g_0c3f:
+ cw 0x00db
+ cw 0x03f7
+ call send_back
+
+ cw 0x009e
+ cw 0x8000
+ call send_back
+
+ cw 0x5600
+ call send_back
+
+g_0c44:
+ cw 0x00fe
+ cw 0x03f5
+ call send_back
+
+ cw 0x1fda
+ call send_back
+
+ cw 0x7c00
+ call send_back
+
+ cw 0x1f5e
+ call send_back
+
+ cw 0x00fe
+ cw 0x03f2
+ call send_back
+
+ JMP g_0c52
+; cw 0x029f
+; cw 0x0c52
+; call send_back
+
+g_0c4d:
+
+ cw 0x00de
+ cw 0x03f4
+ call send_back
+
+ cw 0x5d00
+ call send_back
+
+ JLE g_0c3f
+; cw 0x0293
+; cw 0x0c3f
+; call send_back
+
+g_0c52:
+ cw 0x8900
+ call send_back
+
+ cw 0x00dd
+ cw 0x03f5
+ call send_back
+
+ cw 0x1501
+ call send_back
+
+ cw 0x8100
+ call send_back
+
+ cw 0x00dc
+ cw 0x03f6
+ call send_back
+
+ cw 0x008b
+ cw 0x009f
+ call send_back
+
+ cw 0x0080
+ cw 0x0a00
+ call send_back
+
+ cw 0x0900
+ call send_back
+
+ BLOOPI #0x50, g_0c65
+; cw 0x1150
+; cw 0x0c65
+; call send_back
+
+
+ cw 0x1878
+ call send_back
+
+ cw 0x4c00
+ call send_back
+
+ cw 0x1cfe
+ call send_back
+
+ cw 0x001f
+ call send_back
+
+ cw 0x1fd9
+ call send_back
+g_0c65:
+ cw 0x1b18
+ call send_back
+
+ cw 0x009f
+ cw 0x0a60
+ call send_back
+
+ cw 0x1fc3
+ call send_back
+
+ cw 0x5c00
+ call send_back
+
+ cw 0x00fe
+ cw 0x03f1
+ call send_back
+
+ cw 0x00fc
+ cw 0x03f6
+ call send_back
+
+ cw 0x008b
+ cw 0xffff
+ call send_back
+
+
+
+ende:
+
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+
+
+dead_loop:
+ jmp dead_loop
+
+do_dma:
+ sr @DSMAH, $r1c
+ sr @DSMAL, $r1e
+ sr @DSPA, $r18
+ sr @DSCR, $r19
+ sr @DSBL, $r1a
+wait_dma:
+ LRS $ACL1, @DSCR
+ andf $acl1, #0x0004
+ JNZ wait_dma
+ RET
+
+
+wait_for_dsp_mbox:
+ lrs $ACL1, @DMBH
+ andf $acl1, #0x8000
+ jnz wait_for_dsp_mbox
+ ret
+
+wait_for_cpu_mbox:
+ lrs $ACL1, @cmbh
+ andcf $acl1, #0x8000
+ jlnz wait_for_cpu_mbox
+ ret
+
+irq0:
+ lri $acl0, #0x0000
+ jmp irq
+irq1:
+ lri $acl0, #0x0001
+ jmp irq
+irq2:
+ lri $acl0, #0x0002
+ jmp irq
+
+irq3:
+ lri $acl0, #0x0003
+ jmp irq
+irq4:
+ lri $acl0, #0x0004
+ jmp irq
+irq5:
+; jmp finale
+ s40
+ mrr $r0d, $r1c
+ mrr $r0d, $r1e
+ clr $acc0
+ mrr $r1e, $r0d
+ mrr $r1c, $r0d
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ rti
+
+ lri $acl0, #0x0005
+ jmp irq
+irq6:
+ lri $acl0, #0x0006
+ jmp irq
+irq7:
+ lri $acl0, #0x0007
+ jmp irq
+
+irq:
+ lrs $ACL1, @DMBH
+ andf $acl1, #0x8000
+ jnz irq
+ si @DMBH, #0x8BAD
+ sr @DMBL, $r0b
+;sr @DMBL, $acl0
+ si @DIRQ, #0x0001
+ halt
+
+
+
+
+send_back:
+
+ ; store registers to reg table
+ sr @REGS_BASE, $r00
+ lri $r00, #(REGS_BASE + 1)
+ srri @$r00, $r01
+ srri @$r00, $r02
+ srri @$r00, $r03
+ srri @$r00, $r04
+ srri @$r00, $r05
+ srri @$r00, $r06
+ srri @$r00, $r07
+ srri @$r00, $r08
+ srri @$r00, $r09
+ srri @$r00, $r0a
+ srri @$r00, $r0b
+ srri @$r00, $r0c
+ srri @$r00, $r0d
+ srri @$r00, $r0e
+ srri @$r00, $r0f
+ srri @$r00, $r10
+ srri @$r00, $r11
+ srri @$r00, $r12
+ srri @$r00, $r13
+ srri @$r00, $r14
+ srri @$r00, $r15
+ srri @$r00, $r16
+ srri @$r00, $r17
+ srri @$r00, $r18
+ srri @$r00, $r19
+ srri @$r00, $r1a
+ srri @$r00, $r1b
+ srri @$r00, $r1c
+ srri @$r00, $r1d
+ srri @$r00, $r1e
+ srri @$r00, $r1f
+
+
+ lri $r18, #0x0000
+ lri $r19, #1 ;(DSP_CR_IMEM | DSP_CR_TO_CPU)
+ lri $r1a, #0x200
+ lr $r1c, @MEM_HI
+ lr $r1e, @MEM_LO
+
+ lri $r01, #8+8
+
+ bloop $r01, dma_copy
+ call do_dma
+ addi $r1e, #0x200
+ mrr $r1f, $r18
+ addi $r1f, #0x100
+ mrr $r18, $r1f
+ nop
+dma_copy:
+ nop
+
+ call wait_for_dsp_mbox
+ si @DMBH, #0x8888
+ si @DMBL, #0xfeeb
+ si @DIRQ, #0x0001
+
+; wait for answer before we execute the next op
+ call wait_for_cpu_mbox
+ lrs $ACL0, @CMBL
+ andi $acl1, #0x7fff
+
+
+
+ lri $r00, #REGS_BASE+1
+ lrri $r01, @$r00
+ lrri $r02, @$r00
+ lrri $r03, @$r00
+ lrri $r04, @$r00
+ lrri $r05, @$r00
+ lrri $r06, @$r00
+ lrri $r07, @$r00
+ lrri $r08, @$r00
+ lrri $r09, @$r00
+ lrri $r0a, @$r00
+ lrri $r0b, @$r00
+ lrri $r0c, @$r00
+ lrri $r0d, @$r00
+ lrri $r0e, @$r00
+ lrri $r0f, @$r00
+ lrri $r10, @$r00
+ lrri $r11, @$r00
+ lrri $r12, @$r00
+ lrri $r13, @$r00
+ lrri $r14, @$r00
+ lrri $r15, @$r00
+ lrri $r16, @$r00
+ lrri $r17, @$r00
+ lrri $r18, @$r00
+ lrri $r19, @$r00
+ lrri $r1a, @$r00
+ lrri $r1b, @$r00
+ lrri $r1c, @$r00
+ lrri $r1d, @$r00
+ lrri $r1e, @$r00
+ lrri $r1f, @$r00
+ lr $r00, @REGS_BASE
+
+ ret
+
+send_back_16:
+
+ cw 0x8e00
+ call send_back
+ cw 0x8f00
+
+ ret
+
+
+dump_memory:
+
+ lri $r02, #0x0000
+ lri $acl0, #0x1000
+
+ lri $r01, #0x1000
+ bloop $r01, _fill_loop2
+
+ mrr $r03, $acl0
+ cw 0x80f0
+
+ mrr $r1f, $r00
+ mrr $r00, $r02
+ srri @$r00, $r1b
+ mrr $r02, $r00
+ mrr $r00, $r1f
+
+ addis $acc0, #0x1
+
+_fill_loop2:
+ nop
+
+
+ret
diff --git a/Source/DSPTool/Testdata/dsp_test.bin b/Source/DSPTool/Testdata/dsp_test.bin
new file mode 100644
index 0000000000..4726300d23
Binary files /dev/null and b/Source/DSPTool/Testdata/dsp_test.bin differ
diff --git a/Source/DSPTool/Testdata/hermes.bin b/Source/DSPTool/Testdata/hermes.bin
new file mode 100644
index 0000000000..0f6f9dd42a
Binary files /dev/null and b/Source/DSPTool/Testdata/hermes.bin differ
diff --git a/Source/DSPTool/Testdata/hermes.s b/Source/DSPTool/Testdata/hermes.s
new file mode 100644
index 0000000000..5bef82eb8c
--- /dev/null
+++ b/Source/DSPTool/Testdata/hermes.s
@@ -0,0 +1,1099 @@
+/* DSP_MIXER -> PCM VOICE SOFTWARE PROCESSOR (8-16 Bits Mono/Stereo Voices)
+
+// Thanks to Duddie for you hard work and documentation
+
+Copyright (c) 2008 Hermes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+- The names of the contributors may not be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+/********************************/
+/** REGISTER NAMES **/
+/********************************/
+
+AR0: equ 0x00 ; address registers
+AR1: equ 0x01
+AR2: equ 0x02
+AR3: equ 0x03 // used as jump function selector
+
+IX0: equ 0x04 // LEFT_VOLUME accel
+IX1: equ 0x05 // RIGHT_VOLUME accel
+IX2: equ 0x06 // ADDRH_SMP accel
+IX3: equ 0x07 // ADDRL_SMP accel
+
+R08: equ 0x08 // fixed to 48000 value
+R09: equ 0x09 // problems using this
+R0A: equ 0x0a // ADDREH_SMP accel
+R0B: equ 0x0b // ADDREL_SMP accel
+
+ST0: equ 0x0c
+ST1: equ 0x0d
+ST2: equ 0x0e
+ST3: equ 0x0f
+
+CONFIG: equ 0x12
+SR: equ 0x13
+
+PRODL: equ 0x14
+PRODM: equ 0x15
+PRODH: equ 0x16
+PRODM2: equ 0x17
+
+AXL0: equ 0x18
+AXL1: equ 0x19
+AXH0: equ 0x1A // SMP_R accel
+AXH1: equ 0x1b // SMP_L accel
+
+ACC0: equ 0x1c // accumulator (global)
+ACC1: equ 0x1d
+
+ACL0: equ 0x1c // Low accumulator
+ACL1: equ 0x1d
+ACM0: equ 0x1e // Mid accumulator
+ACM1: equ 0x1f
+ACH0: equ 0x10 // Sign extended 8 bit register 0
+ACH1: equ 0x11 // Sign extended 8 bit register 1
+
+/********************************/
+/** HARDWARE REGISTER ADDRESS **/
+/********************************/
+
+DSCR: equ 0xffc9 ; DSP DMA Control Reg
+DSBL: equ 0xffcb ; DSP DMA Block Length
+DSPA: equ 0xffcd ; DSP DMA DMEM Address
+DSMAH: equ 0xffce ; DSP DMA Mem Address H
+DSMAL: equ 0xffcf ; DSP DMA Mem Address L
+
+DIRQ: equ 0xfffb ; DSP Irq Request
+DMBH: equ 0xfffc ; DSP Mailbox H
+DMBL: equ 0xfffd ; DSP Mailbox L
+CMBH: equ 0xfffe ; CPU Mailbox H
+CMBL: equ 0xffff ; CPU Mailbox L
+
+DMA_TO_DSP: equ 0
+DMA_TO_CPU: equ 1
+
+/**************************************************************/
+/* NUM_SAMPLES SLICE */
+/**************************************************************/
+
+NUM_SAMPLES: equ 1024 ; 1024 stereo samples 16 bits
+
+
+/**************************************************************/
+/* SOUND CHANNEL REGS */
+/**************************************************************/
+
+MEM_REG2: equ 0x0
+MEM_VECTH: equ MEM_REG2
+MEM_VECTL: equ MEM_REG2+1
+RETURN: equ MEM_REG2+2
+
+/**************************************************************/
+/* CHANNEL DATAS */
+/**************************************************************/
+
+MEM_REG: equ MEM_REG2+0x10
+
+ADDRH_SND: equ MEM_REG // Output buffer
+ADDRL_SND: equ MEM_REG+1
+
+DELAYH_SND: equ MEM_REG+2 // Delay samples High word
+DELAYL_SND: equ MEM_REG+3 // Delay samples Low word
+
+CHAN_REGS: equ MEM_REG+4 // specific regs for the channel
+
+FLAGSH_SMP: equ CHAN_REGS+0 // countain number of bytes for step (1-> Mono 8 bits, 2-> Stereo 8 bits and Mono 16 bits, 4-> Stereo 16 bits)
+FLAGSL_SMP: equ CHAN_REGS+1 // 0->Mono 8 bits, 1->Stereo 8 bits, 2->Mono 16 bits 3 -> Stereo 16 bits
+
+ADDRH_SMP: equ CHAN_REGS+2 // start address
+ADDRL_SMP: equ CHAN_REGS+3
+
+ADDREH_SMP: equ CHAN_REGS+4 // end address
+ADDREL_SMP: equ CHAN_REGS+5
+
+FREQH_SMP: equ CHAN_REGS+6 // Freq in Hz to play
+FREQL_SMP: equ CHAN_REGS+7
+
+SMP_L: equ CHAN_REGS+8 // last sample for left (used to joint various buffers)
+SMP_R: equ CHAN_REGS+9 // last sample for right (used to joint various buffers)
+
+COUNTERH_SMP: equ CHAN_REGS+10 // pitch counter
+COUNTERL_SMP: equ CHAN_REGS+11
+
+LEFT_VOLUME: equ CHAN_REGS+12 // volume (0 to 255)
+RIGHT_VOLUME: equ CHAN_REGS+13
+
+ADDR2H_SMP: equ CHAN_REGS+14 // start address of buffer two (to joint)
+ADDR2L_SMP: equ CHAN_REGS+15
+
+ADDR2EH_SMP: equ CHAN_REGS+16 // end address of buffer two (to joint)
+ADDR2EL_SMP: equ CHAN_REGS+17
+
+LEFT_VOLUME2: equ CHAN_REGS+18 // volume (0 to 255) for buffer two
+RIGHT_VOLUME2: equ CHAN_REGS+19
+
+BACKUPH_SMP: equ CHAN_REGS+20 // start address backup
+BACKUPL_SMP: equ CHAN_REGS+21
+
+/**************************************************************/
+/* VOICE SAMPLE BUFFER DATAS */
+/**************************************************************/
+
+MEM_SAMP: equ CHAN_REGS+0x20
+
+
+data_end: equ MEM_SAMP+0x20
+
+/**************************************************************/
+/* SND OUTPUT DATAS */
+/**************************************************************/
+
+MEM_SND: equ data_end ; it need 2048 words (4096 bytes)
+
+
+
+/*** START CODE ***/
+
+/**************************************************************/
+/* EXCEPTION TABLE */
+/**************************************************************/
+
+ jmp exception0
+ jmp exception1
+ jmp exception2
+ jmp exception3
+ jmp exception4
+ jmp exception5
+ jmp exception6
+ jmp exception7
+
+ lri $CONFIG, #0xff
+ lri $SR,#0
+ s40
+ clr15
+ m0
+
+/**************************************************************/
+/* main */
+/**************************************************************/
+
+main:
+
+// send init token to CPU
+
+ si @DMBH, #0xdcd1
+ si @DMBL, #0x0000
+ si @DIRQ, #1
+
+recv_cmd:
+// check if previous mail is received from the CPU
+
+ call wait_for_dsp_mail
+
+// wait a mail from CPU
+
+ call wait_for_cpu_mail
+
+ si @DMBH, #0xdcd1
+
+ clr $ACC0
+ lri $ACM0,#0xcdd1
+ cmp
+ jz sys_command
+
+ clr $ACC1
+ lrs $ACM1, @CMBL
+
+ cmpi $ACM1, #0x111 // fill the internal sample buffer and process the voice internally
+ jz input_samples
+
+ cmpi $ACM1, #0x112 // get samples from the external buffer to the internal buffer and process the voice mixing the samples internally
+ jz input_samples2
+
+ cmpi $ACM1, #0x123 // get the address of the voice datas buffer (CHANNEL DATAS)
+ jz get_data_addr
+
+ cmpi $ACM1, #0x222 // process the voice mixing the samples internally
+ jz input_next_samples
+
+ cmpi $ACM1, #0x666 // send the samples for the internal buffer to the external buffer
+ jz send_samples
+
+ cmpi $ACM1, #0x777 // special: to dump the IROM Datas (remember disable others functions from the interrupt vector to use)
+ jz rom_dump_word // (CMBH+0x8000) countain the address of IROM
+
+ cmpi $ACM1, #0x888 // Used for test
+ jz polla_loca
+
+ cmpi $ACM1, #0x999
+ jz task_terminate
+
+ si @DMBL, #0x0004 // return 0 as ignore command
+ si @DIRQ, #0x1 // set the interrupt
+ jmp recv_cmd
+
+task_terminate:
+ si @DMBL, #0x0003
+ si @DIRQ, #0x1
+ jmp recv_cmd
+
+sys_command:
+ clr $ACC1
+ lrs $ACM1, @CMBL
+
+ cmpi $ACM1,#0x0001
+ jz run_nexttask
+
+ cmpi $ACM1,#0x0002
+ jz 0x8000
+
+ jmp recv_cmd
+
+run_nexttask:
+ s40
+ call wait_for_cpu_mail
+ lrs $29,@CMBL
+ call wait_for_cpu_mail
+ lrs $29,@CMBL
+ call wait_for_cpu_mail
+ lrs $29,@CMBL
+ call wait_for_cpu_mail
+ lr $5,@CMBL
+ andi $31,#0x0fff
+ mrr $4,$31
+ call wait_for_cpu_mail
+ lr $7,@CMBL
+ call wait_for_cpu_mail
+ lr $6,@CMBL
+ call wait_for_cpu_mail
+ lr $0,@CMBL
+ call wait_for_cpu_mail
+ lrs $24,@CMBL
+ andi $31,#0x0fff
+ mrr $26,$31
+ call wait_for_cpu_mail
+ lrs $25,@CMBL
+ call wait_for_cpu_mail
+ lrs $27,@CMBL
+ sbclr #0x05
+ sbclr #0x06
+ jmp 0x80b5
+ halt
+
+/**************************************************************************************************************************************/
+// send the samples for the internal buffer to the external buffer
+
+send_samples:
+
+ lri $AR0, #MEM_SND
+ lris $AXL1, #DMA_TO_CPU;
+ lri $AXL0, #NUM_SAMPLES*4 ; len
+ lr $ACM0, @ADDRH_SND
+ lr $ACL0, @ADDRL_SND
+
+ call do_dma
+ si @DMBL, #0x0004
+ si @DIRQ, #0x1 // set the interrupt
+ jmp recv_cmd
+
+/**************************************************************************************************************************************/
+// get the address of the voice datas buffer (CHANNEL DATAS)
+
+get_data_addr:
+ call wait_for_cpu_mail
+
+ lrs $ACM0, @CMBH
+ lr $ACL0, @CMBL
+
+ sr @MEM_VECTH, $ACM0
+ sr @MEM_VECTL, $ACL0
+
+ si @DIRQ, #0x0 // clear the interrupt
+ jmp recv_cmd
+
+/**************************************************************************************************************************************/
+// fill the internal sample buffer and process the voice internally
+
+input_samples:
+
+ clr $ACC0
+ lr $ACM0, @MEM_VECTH
+ lr $ACL0, @MEM_VECTL
+
+ lris $AXL0, #0x0004
+ sr @RETURN, $AXL0
+ si @DIRQ, #0x0000
+
+ // program DMA to get datas
+
+ lri $AR0, #MEM_REG
+ lris $AXL1, #DMA_TO_DSP
+ lris $AXL0, #64 ; len
+
+ call do_dma
+
+ lri $AR1, #MEM_SND
+ lri $ACL1, #0;
+
+ lri $AXL0, #NUM_SAMPLES
+ bloop $AXL0, loop_get1
+
+ srri @$AR1, $ACL1
+ srri @$AR1, $ACL1
+
+loop_get1:
+ nop
+
+ lr $ACM0, @ADDRH_SND
+ lr $ACL0, @ADDRL_SND
+ jmp start_main
+
+/**************************************************************************************************************************************/
+// get samples from the external buffer to the internal buffer and process the voice mixing the samples internally
+
+input_samples2:
+
+ clr $ACC0
+ lr $ACM0, @MEM_VECTH
+ lr $ACL0, @MEM_VECTL
+
+ lris $AXL0, #0x0004
+ sr @RETURN, $AXL0
+ si @DIRQ, #0x0000
+
+ // program DMA to get datas
+
+ lri $AR0, #MEM_REG
+ lri $AXL1, #DMA_TO_DSP
+ lris $AXL0, #64 ; len
+
+ call do_dma
+
+ lr $ACM0, @ADDRH_SND
+ lr $ACL0, @ADDRL_SND
+
+ lri $AR0, #MEM_SND
+ lris $AXL1, #DMA_TO_DSP;
+ lri $AXL0, #NUM_SAMPLES*4; len
+
+ call do_dma
+
+ jmp start_main
+
+/**************************************************************************************************************************************/
+// process the voice mixing the samples internally
+
+input_next_samples:
+
+ clr $ACC0
+ lr $ACM0, @MEM_VECTH
+ lr $ACL0, @MEM_VECTL
+
+ lris $AXL0, #0x0004
+ sr @RETURN, $AXL0
+ si @DIRQ, #0x0000
+
+ // program DMA to get datas
+
+ lri $AR0, #MEM_REG
+ lris $AXL1, #DMA_TO_DSP
+ lris $AXL0, #64 ; len
+
+ call do_dma
+
+/**************************************************************************************************************************************/
+// mixing and control pitch to create 1024 Stereo Samples at 16 bits from here
+
+start_main:
+
+ lri $R08, #48000
+
+ // load the previous samples used
+
+ lr $AXH0, @SMP_R
+ lr $AXH1, @SMP_L
+
+// optimize the jump function to get MONO/STEREO 8/16 bits samples
+
+ lr $ACM1, @FLAGSL_SMP
+ andi $ACM1, #0x3
+ addi $ACM1, #sample_selector
+ mrr $AR3, $ACM1
+ ilrr $ACM1, @$AR3
+ mrr $AR3, $ACM1 // AR3 countain the jump loaded from sample selector
+
+ clr $ACC0
+
+// test for channel paused
+
+ lr $ACM0, @FLAGSL_SMP
+ andcf $ACM0, #0x20
+ jlz end_main
+
+// load the sample address
+
+ lr $ACM0, @ADDRH_SMP
+ lr $ACL0, @ADDRL_SMP
+
+// test if ADDR_SMP & ADDR2H_SMP are zero
+
+ tst $ACC0
+ jnz do_not_change1
+
+// set return as "change of buffer"
+
+ lris $AXL0, #0x0004
+ sr @RETURN, $AXL0
+
+// change to buffer 2 if it is possible
+
+ call change_buffer
+
+// stops if again 0 address
+
+ tst $ACC0
+ jz save_datas_end
+
+do_not_change1:
+
+
+// backup the external sample address
+
+ mrr $IX2, $ACM0
+ mrr $IX3, $ACL0
+
+
+// load the counter pitch
+
+ //lr $r08, @COUNTERH_SMP
+ //lr $r09, @COUNTERL_SMP
+
+// load the end address of the samples
+
+ lr $r0a, @ADDREH_SMP
+ lr $r0b, @ADDREL_SMP
+
+// load AR1 with internal buffer address
+
+ lri $AR1, #MEM_SND
+
+/////////////////////////////////////
+// delay time section
+/////////////////////////////////////
+
+// load AXL0 with the samples to be processed
+
+ lri $AXL0, #NUM_SAMPLES
+
+// test if DELAY == 0 and skip or not
+
+ clr $ACC0
+ clr $ACC1
+ lr $ACH0, @DELAYH_SND
+ lr $ACM0, @DELAYL_SND
+ tst $ACC0
+ jz no_delay
+
+// samples left and right to 0
+
+ lris $AXH0, #0
+ lris $AXH1, #0
+
+// load the samples to be processed in ACM1
+
+ mrr $ACM1, $AXL0
+l_delay:
+ iar $AR1 // skip two samples
+ iar $AR1
+ decm $ACM1
+ jz exit_delay1 // exit1 if samples to be processed == 0
+
+ decm $ACM0
+ jz exit_delay2 // exit2 if delay time == 0
+ jmp l_delay
+
+// store the remanent delay and ends
+
+exit_delay1:
+ decm $ACM0
+
+ sr @DELAYH_SND, $ACH0
+ sr @DELAYL_SND, $ACM0
+
+ lris $AXL0,#0 ; exit from loop
+
+ jmp no_delay
+
+
+exit_delay2:
+
+ // store delay=0 and continue
+
+ sr @DELAYH_SND, $ACH0
+ sr @DELAYL_SND, $ACM0
+ mrr $AXL0, $ACL1 // load remanent samples to be processed in AXL0
+
+no_delay:
+
+/////////////////////////////////////
+// end of delay time section
+/////////////////////////////////////
+
+/* bucle de generacion de samples */
+
+
+// load the sample buffer with address aligned to 32 bytes blocks (first time)
+
+ si @DSCR, #DMA_TO_DSP // very important!: load_smp_addr_align and jump_load_smp_addr need fix this DMA Register (I gain some cycles so)
+
+// load_smp_addr_align input: $IX2:$IX3
+
+ call load_smp_addr_align
+
+// load the volume registers
+
+ lr $IX0, @LEFT_VOLUME
+ lr $IX1, @RIGHT_VOLUME
+
+// test the freq value
+
+ clr $ACL0
+ lr $ACH0, @FREQH_SMP
+ lr $ACM0, @FREQL_SMP
+
+ clr $ACC1
+ ;lri $ACM1,#48000
+ mrr $ACM1, $R08
+ cmp
+
+// select the output of the routine to process stereo-mono 8/16bits samples
+
+ lri $AR0, #get_sample // fast method <=48000
+
+// if number is greater freq>48000 fix different routine
+
+ ifg
+ lri $AR0, #get_sample2 // slow method >48000
+
+// loops for samples to be processed
+
+ bloop $AXL0, loop_end
+
+ //srri @$AR1, $AXH0 // put sample R
+ //srri @$AR1, $AXH1 // put sample L
+
+// Mix right sample section
+
+ lrr $ACL0, @$AR1 // load in ACL0 the right sample from the internal buffer
+ movax $ACC1, $AXL1 // big trick :) load the current sample <<16 and sign extended
+
+ asl $ACC0,#24 // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0)
+ asr $ACC0,#-8
+
+ add $ACC0,$ACC1 // current_sample+buffer sample
+
+ cmpi $ACM0,#32767 // limit to 32767
+ jle right_skip
+
+ lri $ACM0, #32767
+ jmp right_skip2
+
+right_skip:
+
+ cmpi $ACM0,#-32768 // limit to -32768
+ ifle
+ lri $ACM0, #-32768
+
+right_skip2:
+
+ srri @$AR1, $ACM0 // store the right sample mixed to the internal buffer and increment AR1
+
+// Mix left sample section
+
+ lrr $ACL0, @$AR1 // load in ACL0 the left sample from the internal buffer
+
+ movax $ACC1, $AXL0 // big trick :) load the current sample <<16 and sign extended
+
+ asl $ACC0, #24 // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0)
+ asr $ACC0, #-8
+
+ add $ACC0, $ACC1 // current_sample+buffer sample
+
+ cmpi $ACM0,#32767 // limit to 32767
+ jle left_skip
+
+ lri $ACM0, #32767
+ jmp left_skip2
+
+left_skip:
+
+ cmpi $ACM0,#-32768 // limit to -32768
+ ifle
+ lri $ACM0, #-32768
+
+left_skip2:
+
+ srri @$AR1, $ACM0 // store the left sample mixed to the internal buffer and increment AR1
+
+// adds the counter with the voice frequency and test if it >=48000 to get the next sample
+
+ clr $ACL1
+ lr $ACH1, @COUNTERH_SMP
+ lr $ACM1, @COUNTERL_SMP
+ clr $ACL0
+ lr $ACH0, @FREQH_SMP
+ lr $ACM0, @FREQL_SMP
+
+ add $ACC1,$ACC0
+ clr $ACC0
+ //lri $ACM0,#48000
+ mrr $ACM0, $R08
+
+ cmp
+
+ jrl $AR0 //get_sample or get_sample2 method
+
+ sr @COUNTERH_SMP, $ACH1
+ sr @COUNTERL_SMP, $ACM1
+
+ jmp loop_end
+
+// get a new sample for freq > 48000 Hz
+
+get_sample2: // slow method
+
+ sub $ACC1,$ACC0 // restore the counter
+
+// restore the external sample buffer address
+
+ clr $ACC0
+ mrr $ACM0, $IX2 // load ADDRH_SMP
+ mrr $ACL0, $IX3 // load ADDRL_SMP
+
+ lr $AXL1, @FLAGSH_SMP // add the step to get the next samples
+ addaxl $ACC0, $AXL1
+
+ mrr $IX2, $ACM0 // store ADDRH_SMP
+ mrr $IX3, $ACL0 // store ADDRL_SMP
+
+ mrr $ACM0, $ACL0
+ andf $ACM0, #0x1f
+
+// load_smp_addr_align input: $IX2:$IX3 call if (ACM0 & 0x1f)==0
+
+ calllz load_smp_addr_align
+
+ clr $ACC0
+ //lri $ACM0,#48000
+ mrr $ACM0, $R08
+
+ cmp
+
+ jle get_sample2
+
+ sr @COUNTERH_SMP, $ACH1
+ sr @COUNTERL_SMP, $ACM1
+
+ mrr $ACM0, $IX2 // load ADDRH_SMP
+ mrr $ACL0, $IX3 // load ADDRL_SMP
+
+ clr $ACC1
+ mrr $ACM1, $r0a // load ADDREH_SMP
+ mrr $ACL1, $r0b // load ADDREL_SMP
+
+// compares if the current address is >= end address to change the buffer or stops
+
+ cmp
+
+// if addr>addr end get a new buffer (if you uses double buffer)
+
+ jge get_new_buffer
+
+// load samples from dma, return $ar2 with the addr to get the samples and return using $ar0 to the routine to process 8-16bits Mono/Stereo
+
+ jmp jump_load_smp_addr
+
+// get a new sample for freq <= 48000 Hz
+
+get_sample: // fast method
+
+ sub $ACC1,$ACC0 // restore the counter
+ sr @COUNTERH_SMP, $ACH1
+ sr @COUNTERL_SMP, $ACM1
+
+// restore the external sample buffer address
+
+ clr $ACC0
+ mrr $ACM0, $IX2 // load ADDRH_SMP
+ mrr $ACL0, $IX3 // load ADDRL_SMP
+
+ lr $AXL1, @FLAGSH_SMP // add the step to get the next samples
+ addaxl $ACC0, $AXL1
+
+ clr $ACC1
+ mrr $ACM1, $r0a // load ADDREH_SMP
+ mrr $ACL1, $r0b // load ADDREL_SMP
+
+// compares if the current address is >= end address to change the buffer or stops
+
+ cmp
+ jge get_new_buffer
+
+// load the new sample from the buffer
+
+ mrr $IX2, $ACM0 // store ADDRH_SMP
+ mrr $IX3, $ACL0 // store ADDRL_SMP
+
+// load samples from dma, return $ar2 with the addr and return using $ar0 to the routine to process 8-16bits Mono/Stereo or addr_get_sample_again
+
+ jmp jump_load_smp_addr
+
+sample_selector:
+ cw mono_8bits
+ cw mono_16bits
+ cw stereo_8bits
+ cw stereo_16bits
+
+get_new_buffer:
+
+// set return as "change of buffer": it need to change the sample address
+
+ lris $AXL0, #0x0004
+ sr @RETURN, $AXL0
+
+ call change_buffer // load add from addr2
+
+// addr is 0 ? go to zero_samples and exit
+
+ tst $acc0
+ jz zero_samples
+
+// load_smp_addr_align input: $IX2:$IX3
+
+ call load_smp_addr_align // force the load the samples cached (address aligned)
+
+// jump_load_smp_addr: $IX2:$IX3
+// load samples from dma, return $ar2 with the addr to get the samples and return using $ar0 to the routine to process 8-16bits Mono/Stereo
+
+ jmp jump_load_smp_addr
+
+// set to 0 the current samples
+
+zero_samples:
+
+ lris $AXH0, #0
+ lris $AXH1, #0
+ jmp out_samp
+
+mono_8bits:
+
+// 8 bits mono
+ mrr $ACM1, $IX3
+ lrri $ACL0, @$AR2
+ andf $ACM1, #0x1
+
+ iflz // obtain sample0-sample1 from 8bits packet
+ asr $ACL0, #-8
+ asl $ACL0, #8
+
+ mrr $AXH1,$ACL0
+ mrr $AXH0,$ACL0
+ jmp out_samp
+
+stereo_8bits:
+
+// 8 bits stereo
+
+ lrri $ACL0, @$AR2
+ mrr $ACM0, $ACL0
+ andi $ACM0, #0xff00
+ mrr $AXH1, $ACM0
+ lsl $ACL0, #8
+ mrr $AXH0, $ACL0
+
+ jmp out_samp
+
+mono_16bits:
+
+// 16 bits mono
+
+ lrri $AXH1, @$AR2
+ mrr $AXH0,$AXH1
+ jmp out_samp
+
+stereo_16bits:
+
+// 16 bits stereo
+
+ lrri $AXH1, @$AR2
+ lrri $AXH0, @$AR2
+
+out_samp:
+
+// multiply sample x volume
+
+ // LEFT_VOLUME
+ mrr $AXL0,$IX0
+ mul $AXL0,$AXH0
+ movp $ACL0
+ asr $ACL0,#-8
+ mrr $AXH0, $ACL0
+
+ // RIGHT VOLUME
+ mrr $AXL1,$IX1
+ mul $AXL1,$AXH1
+ movp $ACL0
+ asr $ACL0,#-8
+ mrr $AXH1, $ACL0
+
+loop_end:
+ nop
+
+end_process:
+
+ // load the sample address
+
+ clr $ACC0
+ mrr $ACM0, $IX2
+ mrr $ACL0, $IX3
+
+ tst $ACC0
+ jnz save_datas_end
+
+// set return as "change of buffer"
+
+ lris $AXL0, #0x0004
+ sr @RETURN, $AXL0
+
+// change to buffer 2 if it is possible
+
+ call change_buffer
+
+save_datas_end:
+
+ sr @ADDRH_SMP, $IX2
+ sr @ADDRL_SMP, $IX3
+ sr @SMP_R, $AXH0
+ sr @SMP_L, $AXH1
+
+end_main:
+
+// program DMA to send the CHANNEL DATAS changed
+
+ clr $ACC0
+ lr $ACM0, @MEM_VECTH
+ lr $ACL0, @MEM_VECTL
+
+ lri $AR0, #MEM_REG
+ lris $AXL1, #DMA_TO_CPU
+ lris $AXL0, #64 ; len
+
+ call do_dma
+
+ si @DMBH, #0xdcd1
+ lr $ACL0, @RETURN
+
+ sr @DMBL, $ACL0
+ si @DIRQ, #0x1 // set the interrupt
+
+ jmp recv_cmd
+
+change_buffer:
+
+ clr $ACC0
+ lr $ACM0, @LEFT_VOLUME2
+ lr $ACL0, @RIGHT_VOLUME2
+ sr @LEFT_VOLUME, $ACM0
+ sr @RIGHT_VOLUME, $ACL0
+ mrr $IX0, $ACM0
+ mrr $IX1, $ACL0
+
+ lr $ACM0, @ADDR2EH_SMP
+ lr $ACL0, @ADDR2EL_SMP
+ sr @ADDREH_SMP, $ACM0
+ sr @ADDREL_SMP, $ACL0
+ mrr $r0a, $ACM0
+ mrr $r0b, $ACL0
+
+ lr $ACM0, @ADDR2H_SMP
+ lr $ACL0, @ADDR2L_SMP
+ sr @ADDRH_SMP, $ACM0
+ sr @ADDRL_SMP, $ACL0
+ sr @BACKUPH_SMP, $ACM0
+ sr @BACKUPL_SMP, $ACL0
+ mrr $IX2, $ACM0
+ mrr $IX3, $ACL0
+
+ lr $ACM1, @FLAGSL_SMP
+ andcf $ACM1, #0x4
+ retlz
+
+ sr @ADDR2H_SMP, $ACH0
+ sr @ADDR2L_SMP, $ACH0
+ sr @ADDR2EH_SMP, $ACH0
+ sr @ADDR2EL_SMP, $ACH0
+ ret
+
+/**************************************************************/
+/* DMA ROUTINE */
+/**************************************************************/
+
+do_dma:
+
+ sr @DSMAH, $ACM0
+ sr @DSMAL, $ACL0
+ sr @DSPA, $AR0
+ sr @DSCR, $AXL1
+ sr @DSBL, $AXL0
+
+wait_dma:
+
+ lrs $ACM1, @DSCR
+ andcf $ACM1, #0x4
+ jlz wait_dma
+ ret
+
+
+wait_for_dsp_mail:
+
+ lrs $ACM1, @DMBH
+ andf $ACM1, #0x8000
+ jnz wait_for_dsp_mail
+ ret
+
+wait_for_cpu_mail:
+
+ lrs $ACM1, @cmbh
+ andcf $ACM1, #0x8000
+ jlnz wait_for_cpu_mail
+ ret
+
+load_smp_addr_align:
+
+ mrr $ACL0, $IX3 // load ADDRL_SMP
+
+ lsr $ACC0, #-5
+ lsl $ACC0, #5
+ sr @DSMAH, $IX2
+ sr @DSMAL, $ACL0
+ si @DSPA, #MEM_SAMP
+ ;si @DSCR, #DMA_TO_DSP
+ si @DSBL, #0x20
+
+wait_dma1:
+ lrs $ACM0, @DSCR
+ andcf $ACM0, #0x4
+ jlz wait_dma1
+
+ lri $AR2, #MEM_SAMP
+ ret
+
+
+//////////////////////////////////////////
+
+jump_load_smp_addr:
+
+ mrr $ACM0, $IX3 // load ADDRL_SMP
+ asr $ACC0, #-1
+ andi $ACM0, #0xf
+ jz jump_load_smp_dma
+
+ addi $ACM0, #MEM_SAMP
+ mrr $AR2, $ACM0
+ jmpr $AR3
+
+jump_load_smp_dma:
+
+ sr @DSMAH, $IX2
+ sr @DSMAL, $IX3
+ si @DSPA, #MEM_SAMP
+ ;si @DSCR, #DMA_TO_DSP // to gain some cycles
+ si @DSBL, #0x20
+
+wait_dma2:
+ lrs $ACM0, @DSCR
+ andcf $ACM0, #0x4
+ jlz wait_dma2
+
+ lri $AR2, #MEM_SAMP
+ jmpr $AR3
+
+// exception table
+
+exception0: // RESET
+ rti
+
+exception1: // STACK OVERFLOW
+ rti
+
+exception2:
+ rti
+
+exception3:
+ rti
+
+exception4:
+ rti
+
+exception5: // ACCELERATOR ADDRESS OVERFLOW
+ rti
+
+exception6:
+ rti
+
+exception7:
+ rti
+
+// routine to read a word of the IROM space
+
+rom_dump_word:
+
+ clr $ACC0
+
+ lr $ACM0, @CMBH
+ ori $ACM0, #0x8000
+ mrr $AR0, $ACM0
+ clr $ACC0
+ ilrr $ACM0, @$AR0
+ sr @DMBH, $ACL0
+ sr @DMBL, $ACM0
+ ;si @DIRQ, #0x1 // set the interrupt
+ clr $ACC0
+ jmp recv_cmd
+
+polla_loca:
+
+ clr $ACC0
+ lri $acm0, #0x0
+ andf $acm0,#0x1
+
+ sr @DMBH, $sr
+ sr @DMBL, $acm0
+ ;si @DIRQ, #0x1 // set the interrupt
+ clr $ACC0
+ jmp recv_cmd
+
+
diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp
index 711ba5cfe3..6fef8b8937 100644
--- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp
+++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp
@@ -25,7 +25,7 @@ wxString CRegTable::GetValue(int row, int col)
{
switch (col)
{
- case 0: return wxString::FromAscii(gd_get_reg_name(row));
+ case 0: return wxString::FromAscii(pdregname(row));
case 1: return wxString::Format(wxT("0x%04x"), g_dsp.r[row]);
default: return wxString::FromAscii("");
}
diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp
index c036f15db4..79b72288f5 100644
--- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp
+++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp
@@ -221,7 +221,7 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
AssemblerSettings settings;
DSPDisassembler disasm(settings);
std::string op_str;
- disasm.DisOpcode(binbuf, &settings.pc, &op_str);
+ disasm.DisOpcode(binbuf, 2, &settings.pc, &op_str);
const char* pParameter = NULL;
const char* pExtension = NULL;
diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp
index 0d1cb2ea2a..a60a25b195 100644
--- a/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp
+++ b/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp
@@ -53,7 +53,7 @@ bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc)
AssemblerSettings settings;
settings.show_hex = true;
settings.show_pc = true;
- settings.ext_separator = '\t';
+ settings.ext_separator = '\'';
settings.decode_names = true;
settings.decode_registers = true;