summaryrefslogtreecommitdiff
path: root/Source/Core/DSPCore
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/DSPCore')
-rw-r--r--Source/Core/DSPCore/Src/DSPAnalyzer.cpp266
-rw-r--r--Source/Core/DSPCore/Src/DSPAnalyzer.h98
-rw-r--r--Source/Core/DSPCore/Src/DSPBreakpoints.cpp38
-rw-r--r--Source/Core/DSPCore/Src/DSPBreakpoints.h126
-rw-r--r--Source/Core/DSPCore/Src/DSPCodeUtil.cpp470
-rw-r--r--Source/Core/DSPCore/Src/DSPCodeUtil.h86
-rw-r--r--Source/Core/DSPCore/Src/DSPCore.cpp512
-rw-r--r--Source/Core/DSPCore/Src/DSPCore.h480
-rw-r--r--Source/Core/DSPCore/Src/DSPHost.h70
-rw-r--r--Source/Core/DSPCore/Src/DSPIntCCUtil.cpp280
-rw-r--r--Source/Core/DSPCore/Src/DSPIntCCUtil.h78
-rw-r--r--Source/Core/DSPCore/Src/DSPInterpreter.h342
-rw-r--r--Source/Core/DSPCore/Src/DSPJit.cpp44
-rw-r--r--Source/Core/DSPCore/Src/DSPJit.h56
-rw-r--r--Source/Core/DSPCore/Src/DSPTables.cpp1166
-rw-r--r--Source/Core/DSPCore/Src/DSPTables.h336
-rw-r--r--Source/Core/DSPCore/Src/DspIntArithmetic.cpp1468
-rw-r--r--Source/Core/DSPCore/Src/DspIntBranch.cpp498
-rw-r--r--Source/Core/DSPCore/Src/DspIntLoadStore.cpp532
-rw-r--r--Source/Core/DSPCore/Src/DspIntMisc.cpp404
-rw-r--r--Source/Core/DSPCore/Src/DspIntMultiplier.cpp1004
-rw-r--r--Source/Core/DSPCore/Src/LabelMap.cpp170
-rw-r--r--Source/Core/DSPCore/Src/LabelMap.h110
-rw-r--r--Source/Core/DSPCore/Src/assemble.cpp2032
-rw-r--r--Source/Core/DSPCore/Src/assemble.h278
25 files changed, 5472 insertions, 5472 deletions
diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp
index db08157299..e851d44ba0 100644
--- a/Source/Core/DSPCore/Src/DSPAnalyzer.cpp
+++ b/Source/Core/DSPCore/Src/DSPAnalyzer.cpp
@@ -1,133 +1,133 @@
-// 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 "DSPAnalyzer.h"
-#include "DSPInterpreter.h"
-#include "DSPTables.h"
-#include "DSPMemoryMap.h"
-
-namespace DSPAnalyzer {
-
-// Holds data about all instructions in RAM.
-u8 code_flags[ISPACE];
-
-// Good candidates for idle skipping is mail wait loops. If we're time slicing
-// between the main CPU and the DSP, if the DSP runs into one of these, it might
-// as well give up its time slice immediately, after executing once.
-
-// Max signature length is 6. A 0 in a signature is ignored.
-#define NUM_IDLE_SIGS 5
-#define MAX_IDLE_SIG_SIZE 6
-
-// 0xFFFF means ignore.
-const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
-{
- // From AX:
- { 0x26fc, // LRS $30, @DMBH
- 0x02c0, 0x8000, // ANDCF $30, #0x8000
- 0x029d, 0xFFFF, // JLZ 0x027a
- 0, 0 }, // RET
- { 0x27fc, // LRS $31, @DMBH
- 0x03c0, 0x8000, // ANDCF $31, #0x8000
- 0x029d, 0xFFFF, // JLZ 0x027a
- 0, 0 }, // RET
- { 0x26fe, // LRS $30, @CMBH
- 0x02c0, 0x8000, // ANDCF $30, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x0280
- 0, 0 }, // RET
- { 0x27fe, // LRS $31, @CMBH
- 0x03c0, 0x8000, // ANDCF $31, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x0280
- 0, 0 }, // RET
-
- // From Zelda:
- { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH
- 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000
- 0x029c, 0xFFFF, // JLNZ 0x05cf
- 0 }
-};
-
-void Reset()
-{
- memset(code_flags, 0, sizeof(code_flags));
-}
-
-void AnalyzeRange(int start_addr, int end_addr)
-{
- // First we run an extremely simplified version of a disassembler to find
- // where all instructions start.
-
- // This may not be 100% accurate in case of jump tables!
- // It could get desynced, which would be bad. We'll see if that's an issue.
- int addr = start_addr;
- while (addr < end_addr)
- {
- UDSPInstruction inst = dsp_imem_read(addr);
- const DSPOPCTemplate *opcode = GetOpTemplate(inst);
- if (!opcode)
- {
- addr++;
- continue;
- }
- code_flags[addr] |= CODE_START_OF_INST;
- addr += opcode->size;
-
- // Look for loops.
- if ((inst.hex & 0xffe0) == 0x0060 || (inst.hex & 0xff00) == 0x1100) {
- // BLOOP, BLOOPI
- u16 loop_end = dsp_imem_read(addr + 1);
- code_flags[loop_end] |= CODE_LOOP_END;
- } else if ((inst.hex & 0xffe0) == 0x0040 || (inst.hex & 0xff00) == 0x1000) {
- // LOOP, LOOPI
- code_flags[addr + 1] |= CODE_LOOP_END;
- }
- }
-
- // Next, we'll scan for potential idle skips.
- for (int s = 0; s < NUM_IDLE_SIGS; s++)
- {
- for (int addr = start_addr; addr < end_addr; addr++)
- {
- bool found = false;
- for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++)
- {
- if (idle_skip_sigs[s][i] == 0)
- found = true;
- if (idle_skip_sigs[s][i] == 0xFFFF)
- continue;
- if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i))
- break;
- }
- if (found)
- {
- NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr);
- code_flags[addr] |= CODE_IDLE_SKIP;
- // TODO: actually use this flag somewhere.
- }
- }
- }
- NOTICE_LOG(DSPLLE, "Finished analysis.");
-}
-
-void Analyze()
-{
- Reset();
- AnalyzeRange(0x0000, 0x1000); // IRAM
- AnalyzeRange(0x8000, 0x9000); // IROM
-}
-
-} // namespace
+// 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 "DSPAnalyzer.h"
+#include "DSPInterpreter.h"
+#include "DSPTables.h"
+#include "DSPMemoryMap.h"
+
+namespace DSPAnalyzer {
+
+// Holds data about all instructions in RAM.
+u8 code_flags[ISPACE];
+
+// Good candidates for idle skipping is mail wait loops. If we're time slicing
+// between the main CPU and the DSP, if the DSP runs into one of these, it might
+// as well give up its time slice immediately, after executing once.
+
+// Max signature length is 6. A 0 in a signature is ignored.
+#define NUM_IDLE_SIGS 5
+#define MAX_IDLE_SIG_SIZE 6
+
+// 0xFFFF means ignore.
+const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
+{
+ // From AX:
+ { 0x26fc, // LRS $30, @DMBH
+ 0x02c0, 0x8000, // ANDCF $30, #0x8000
+ 0x029d, 0xFFFF, // JLZ 0x027a
+ 0, 0 }, // RET
+ { 0x27fc, // LRS $31, @DMBH
+ 0x03c0, 0x8000, // ANDCF $31, #0x8000
+ 0x029d, 0xFFFF, // JLZ 0x027a
+ 0, 0 }, // RET
+ { 0x26fe, // LRS $30, @CMBH
+ 0x02c0, 0x8000, // ANDCF $30, #0x8000
+ 0x029c, 0xFFFF, // JLNZ 0x0280
+ 0, 0 }, // RET
+ { 0x27fe, // LRS $31, @CMBH
+ 0x03c0, 0x8000, // ANDCF $31, #0x8000
+ 0x029c, 0xFFFF, // JLNZ 0x0280
+ 0, 0 }, // RET
+
+ // From Zelda:
+ { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH
+ 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000
+ 0x029c, 0xFFFF, // JLNZ 0x05cf
+ 0 }
+};
+
+void Reset()
+{
+ memset(code_flags, 0, sizeof(code_flags));
+}
+
+void AnalyzeRange(int start_addr, int end_addr)
+{
+ // First we run an extremely simplified version of a disassembler to find
+ // where all instructions start.
+
+ // This may not be 100% accurate in case of jump tables!
+ // It could get desynced, which would be bad. We'll see if that's an issue.
+ int addr = start_addr;
+ while (addr < end_addr)
+ {
+ UDSPInstruction inst = dsp_imem_read(addr);
+ const DSPOPCTemplate *opcode = GetOpTemplate(inst);
+ if (!opcode)
+ {
+ addr++;
+ continue;
+ }
+ code_flags[addr] |= CODE_START_OF_INST;
+ addr += opcode->size;
+
+ // Look for loops.
+ if ((inst.hex & 0xffe0) == 0x0060 || (inst.hex & 0xff00) == 0x1100) {
+ // BLOOP, BLOOPI
+ u16 loop_end = dsp_imem_read(addr + 1);
+ code_flags[loop_end] |= CODE_LOOP_END;
+ } else if ((inst.hex & 0xffe0) == 0x0040 || (inst.hex & 0xff00) == 0x1000) {
+ // LOOP, LOOPI
+ code_flags[addr + 1] |= CODE_LOOP_END;
+ }
+ }
+
+ // Next, we'll scan for potential idle skips.
+ for (int s = 0; s < NUM_IDLE_SIGS; s++)
+ {
+ for (int addr = start_addr; addr < end_addr; addr++)
+ {
+ bool found = false;
+ for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++)
+ {
+ if (idle_skip_sigs[s][i] == 0)
+ found = true;
+ if (idle_skip_sigs[s][i] == 0xFFFF)
+ continue;
+ if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i))
+ break;
+ }
+ if (found)
+ {
+ NOTICE_LOG(DSPLLE, "Idle skip location found at %02x", addr);
+ code_flags[addr] |= CODE_IDLE_SKIP;
+ // TODO: actually use this flag somewhere.
+ }
+ }
+ }
+ NOTICE_LOG(DSPLLE, "Finished analysis.");
+}
+
+void Analyze()
+{
+ Reset();
+ AnalyzeRange(0x0000, 0x1000); // IRAM
+ AnalyzeRange(0x8000, 0x9000); // IROM
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h
index 1b29ede4af..65b83a205b 100644
--- a/Source/Core/DSPCore/Src/DSPAnalyzer.h
+++ b/Source/Core/DSPCore/Src/DSPAnalyzer.h
@@ -1,49 +1,49 @@
-// 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/
-
-// Basic code analysis.
-
-#include "DSPInterpreter.h"
-
-namespace DSPAnalyzer {
-
-#define ISPACE 65536
-
-// Useful things to detect:
-// * Loop endpoints - so that we can avoid checking for loops every cycle.
-
-enum
-{
- CODE_START_OF_INST = 1,
- CODE_IDLE_SKIP = 2,
- CODE_LOOP_END = 4,
-};
-
-// Easy to query array covering the whole of instruction memory.
-// Just index by address.
-// This one will be helpful for debuggers and jits.
-extern u8 code_flags[ISPACE];
-
-// This one should be called every time IRAM changes - which is basically
-// every time that a new ucode gets uploaded, and never else. At that point,
-// we can do as much static analysis as we want - but we should always throw
-// all old analysis away. Luckily the entire address space is only 64K code
-// words and the actual code space 8K instructions in total, so we can do
-// some pretty expensive analysis if necessary.
-void Analyze();
-
-} // namespace
+// 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/
+
+// Basic code analysis.
+
+#include "DSPInterpreter.h"
+
+namespace DSPAnalyzer {
+
+#define ISPACE 65536
+
+// Useful things to detect:
+// * Loop endpoints - so that we can avoid checking for loops every cycle.
+
+enum
+{
+ CODE_START_OF_INST = 1,
+ CODE_IDLE_SKIP = 2,
+ CODE_LOOP_END = 4,
+};
+
+// Easy to query array covering the whole of instruction memory.
+// Just index by address.
+// This one will be helpful for debuggers and jits.
+extern u8 code_flags[ISPACE];
+
+// This one should be called every time IRAM changes - which is basically
+// every time that a new ucode gets uploaded, and never else. At that point,
+// we can do as much static analysis as we want - but we should always throw
+// all old analysis away. Luckily the entire address space is only 64K code
+// words and the actual code space 8K instructions in total, so we can do
+// some pretty expensive analysis if necessary.
+void Analyze();
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.cpp b/Source/Core/DSPCore/Src/DSPBreakpoints.cpp
index ec48a249fc..0d1537ed1d 100644
--- a/Source/Core/DSPCore/Src/DSPBreakpoints.cpp
+++ b/Source/Core/DSPCore/Src/DSPBreakpoints.cpp
@@ -1,19 +1,19 @@
-// 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 "DSPBreakpoints.h"
-
+// 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 "DSPBreakpoints.h"
+
diff --git a/Source/Core/DSPCore/Src/DSPBreakpoints.h b/Source/Core/DSPCore/Src/DSPBreakpoints.h
index 98ff5f609d..752c1f9080 100644
--- a/Source/Core/DSPCore/Src/DSPBreakpoints.h
+++ b/Source/Core/DSPCore/Src/DSPBreakpoints.h
@@ -1,63 +1,63 @@
-// 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 _DSP_BREAKPOINTS
-#define _DSP_BREAKPOINTS
-
-#include "Common.h"
-
-// super fast breakpoints for a limited range.
-// To be used interchangably with the BreakPoints class.
-class DSPBreakpoints
-{
-public:
- DSPBreakpoints() {Clear();}
- // is address breakpoint
- bool IsAddressBreakPoint(u32 addr) {
- return b[addr] != 0;
- }
-
- // AddBreakPoint
- bool Add(u32 addr, bool temp=false) {
- bool was_one = b[addr] != 0;
- if (!was_one) {
- b[addr] = temp ? 2 : 1;
- return true;
- } else {
- return false;
- }
- }
- // Remove Breakpoint
- bool Remove(u32 addr) {
- bool was_one = b[addr] != 0;
- b[addr] = 0;
- return was_one;
- }
- void Clear() {
- for (int i = 0; i < 65536; i++)
- b[i] = 0;
- }
-
- void DeleteByAddress(u32 addr) {
- b[addr] = 0;
- }
-
-private:
- u8 b[65536];
-};
-
-#endif
+// 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 _DSP_BREAKPOINTS
+#define _DSP_BREAKPOINTS
+
+#include "Common.h"
+
+// super fast breakpoints for a limited range.
+// To be used interchangably with the BreakPoints class.
+class DSPBreakpoints
+{
+public:
+ DSPBreakpoints() {Clear();}
+ // is address breakpoint
+ bool IsAddressBreakPoint(u32 addr) {
+ return b[addr] != 0;
+ }
+
+ // AddBreakPoint
+ bool Add(u32 addr, bool temp=false) {
+ bool was_one = b[addr] != 0;
+ if (!was_one) {
+ b[addr] = temp ? 2 : 1;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // Remove Breakpoint
+ bool Remove(u32 addr) {
+ bool was_one = b[addr] != 0;
+ b[addr] = 0;
+ return was_one;
+ }
+ void Clear() {
+ for (int i = 0; i < 65536; i++)
+ b[i] = 0;
+ }
+
+ void DeleteByAddress(u32 addr) {
+ b[addr] = 0;
+ }
+
+private:
+ u8 b[65536];
+};
+
+#endif
diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp
index 3f81b67e04..d0dd510949 100644
--- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp
+++ b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp
@@ -1,235 +1,235 @@
-// 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 <iostream>
-#include <vector>
-
-#include "Common.h"
-#include "FileUtil.h"
-#include "StringUtil.h"
-#include "DSPCodeUtil.h"
-#include "assemble.h"
-#include "disassemble.h"
-
-
-bool Assemble(const char *text, std::vector<u16> &code)
-{
- AssemblerSettings settings;
- settings.pc = 0;
- // settings.decode_registers = false;
- // settings.decode_names = false;
- settings.print_tabs = false;
- settings.ext_separator = '\'';
-
- // TODO: fix the terrible api of the assembler.
- DSPAssembler assembler(settings);
- if (!assembler.Assemble(text, code)) {
- std::cerr << assembler.GetErrorString() << std::endl;
- return false;
- }
-
- return true;
-}
-
-bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text)
-{
- if (code.empty())
- return false;
-
- AssemblerSettings settings;
-
- // These two prevent roundtripping.
- settings.show_hex = false;
- settings.show_pc = line_numbers;
- settings.ext_separator = '\'';
- settings.decode_names = false;
- settings.decode_registers = true;
-
- DSPDisassembler disasm(settings);
- bool success = disasm.Disassemble(0, code, 0x0000, text);
- return success;
-}
-
-bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
-{
- if (code1.size() != code2.size())
- printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
- u32 count_equal = 0;
- const int min_size = (int)std::min(code1.size(), code2.size());
-
- AssemblerSettings settings;
- DSPDisassembler disassembler(settings);
- for (int i = 0; i < min_size; i++)
- {
- if (code1[i] == code2[i])
- count_equal++;
- else
- {
- std::string line1, line2;
- u16 pc = i;
- disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1);
- pc = i;
- disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2);
- printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str());
- }
- }
- if (code2.size() != code1.size())
- {
- printf("Extra code words:\n");
- const std::vector<u16> &longest = code1.size() > code2.size() ? code1 : code2;
- for (int i = min_size; i < (int)longest.size(); i++)
- {
- u16 pc = i;
- std::string line;
- disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line);
- printf("!! %s\n", line.c_str());
- }
- }
- printf("Equal instruction words: %i / %i\n", count_equal, min_size);
- return code1.size() == code2.size() && code1.size() == count_equal;
-}
-
-void GenRandomCode(int size, std::vector<u16> &code)
-{
- code.resize(size);
- for (int i = 0; i < size; i++)
- {
- code[i] = rand() ^ (rand() << 8);
- }
-}
-
-void CodeToHeader(const std::vector<u16> &code, std::string _filename,
- const char *name, std::string &header)
-{
- std::vector<u16> code_copy = code;
- // Add some nops at the end to align the size a bit.
- while (code_copy.size() & 7)
- code_copy.push_back(0);
- char buffer[1024];
- header.clear();
- header.reserve(code.size() * 4);
- header.append("#define NUM_UCODES 1\n\n");
- std::string filename;
- SplitPath(_filename, NULL, &filename, NULL);
- header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str()));
- header.append("#ifndef _MSCVER\n");
- header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n");
- header.append("#else\n");
- header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
- header.append("#endif\n\n");
-
- header.append("\t{\n\t\t");
- for (u32 j = 0; j < code.size(); j++)
- {
- if (j && ((j & 15) == 0))
- header.append("\n\t\t");
- sprintf(buffer, "0x%04x, ", code[j]);
- header.append(buffer);
- }
- header.append("\n\t},\n");
-
- header.append("};\n");
-}
-
-void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames,
- int numCodes, const char *name, std::string &header)
-{
- char buffer[1024];
- int reserveSize = 0;
- for(int i = 0; i < numCodes; i++)
- reserveSize += (int)codes[i].size();
-
-
- header.clear();
- header.reserve(reserveSize * 4);
- sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes);
- header.append(buffer);
- header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n");
- for (int i = 0; i < numCodes; i++)
- {
- std::string filename;
- if (! SplitPath(filenames->at(i), NULL, &filename, NULL))
- filename = filenames->at(i);
- sprintf(buffer, "\t\"%s\",\n", filename.c_str());
- header.append(buffer);
- }
- header.append("};\n\n");
- header.append("#ifndef _MSCVER\n");
- header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] = {\n");
- header.append("#else\n");
- header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
- header.append("#endif\n\n");
-
- for(int i = 0; i < numCodes; i++) {
- if(codes[i].size() == 0)
- continue;
-
- std::vector<u16> code_copy = codes[i];
- // Add some nops at the end to align the size a bit.
- while (code_copy.size() & 7)
- code_copy.push_back(0);
-
- header.append("\t{\n\t\t");
- for (u32 j = 0; j < codes[i].size(); j++)
- {
- if (j && ((j & 15) == 0))
- header.append("\n\t\t");
- sprintf(buffer, "0x%04x, ", codes[i][j]);
- header.append(buffer);
- }
- header.append("\n\t},\n");
- }
- header.append("};\n");
-}
-
-void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
-{
- str.resize(code.size() * 2);
- for (int i = 0; i < (int)code.size(); i++)
- {
- str[i * 2 + 0] = code[i] >> 8;
- str[i * 2 + 1] = code[i] & 0xff;
- }
-}
-
-void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
-{
- code.resize(str.size() / 2);
- for (int i = 0; i < (int)code.size(); i++)
- {
- code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]);
- }
-}
-
-bool LoadBinary(const char *filename, std::vector<u16> &code)
-{
- std::string buffer;
- if (!File::ReadFileToString(false, filename, buffer))
- return false;
-
- BinaryStringBEToCode(buffer, code);
- return true;
-}
-
-bool SaveBinary(const std::vector<u16> &code, const char *filename)
-{
- std::string buffer;
- CodeToBinaryStringBE(code, buffer);
- if (!File::WriteStringToFile(false, buffer, filename))
- return false;
- return true;
-}
+// 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 <iostream>
+#include <vector>
+
+#include "Common.h"
+#include "FileUtil.h"
+#include "StringUtil.h"
+#include "DSPCodeUtil.h"
+#include "assemble.h"
+#include "disassemble.h"
+
+
+bool Assemble(const char *text, std::vector<u16> &code)
+{
+ AssemblerSettings settings;
+ settings.pc = 0;
+ // settings.decode_registers = false;
+ // settings.decode_names = false;
+ settings.print_tabs = false;
+ settings.ext_separator = '\'';
+
+ // TODO: fix the terrible api of the assembler.
+ DSPAssembler assembler(settings);
+ if (!assembler.Assemble(text, code)) {
+ std::cerr << assembler.GetErrorString() << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text)
+{
+ if (code.empty())
+ return false;
+
+ AssemblerSettings settings;
+
+ // These two prevent roundtripping.
+ settings.show_hex = false;
+ settings.show_pc = line_numbers;
+ settings.ext_separator = '\'';
+ settings.decode_names = false;
+ settings.decode_registers = true;
+
+ DSPDisassembler disasm(settings);
+ bool success = disasm.Disassemble(0, code, 0x0000, text);
+ return success;
+}
+
+bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
+{
+ if (code1.size() != code2.size())
+ printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
+ u32 count_equal = 0;
+ const int min_size = (int)std::min(code1.size(), code2.size());
+
+ AssemblerSettings settings;
+ DSPDisassembler disassembler(settings);
+ for (int i = 0; i < min_size; i++)
+ {
+ if (code1[i] == code2[i])
+ count_equal++;
+ else
+ {
+ std::string line1, line2;
+ u16 pc = i;
+ disassembler.DisOpcode(&code1[0], 0x0000, 2, &pc, line1);
+ pc = i;
+ disassembler.DisOpcode(&code2[0], 0x0000, 2, &pc, line2);
+ printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str());
+ }
+ }
+ if (code2.size() != code1.size())
+ {
+ printf("Extra code words:\n");
+ const std::vector<u16> &longest = code1.size() > code2.size() ? code1 : code2;
+ for (int i = min_size; i < (int)longest.size(); i++)
+ {
+ u16 pc = i;
+ std::string line;
+ disassembler.DisOpcode(&longest[0], 0x0000, 2, &pc, line);
+ printf("!! %s\n", line.c_str());
+ }
+ }
+ printf("Equal instruction words: %i / %i\n", count_equal, min_size);
+ return code1.size() == code2.size() && code1.size() == count_equal;
+}
+
+void GenRandomCode(int size, std::vector<u16> &code)
+{
+ code.resize(size);
+ for (int i = 0; i < size; i++)
+ {
+ code[i] = rand() ^ (rand() << 8);
+ }
+}
+
+void CodeToHeader(const std::vector<u16> &code, std::string _filename,
+ const char *name, std::string &header)
+{
+ std::vector<u16> code_copy = code;
+ // Add some nops at the end to align the size a bit.
+ while (code_copy.size() & 7)
+ code_copy.push_back(0);
+ char buffer[1024];
+ header.clear();
+ header.reserve(code.size() * 4);
+ header.append("#define NUM_UCODES 1\n\n");
+ std::string filename;
+ SplitPath(_filename, NULL, &filename, NULL);
+ header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str()));
+ header.append("#ifndef _MSCVER\n");
+ header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n");
+ header.append("#else\n");
+ header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
+ header.append("#endif\n\n");
+
+ header.append("\t{\n\t\t");
+ for (u32 j = 0; j < code.size(); j++)
+ {
+ if (j && ((j & 15) == 0))
+ header.append("\n\t\t");
+ sprintf(buffer, "0x%04x, ", code[j]);
+ header.append(buffer);
+ }
+ header.append("\n\t},\n");
+
+ header.append("};\n");
+}
+
+void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string>* filenames,
+ int numCodes, const char *name, std::string &header)
+{
+ char buffer[1024];
+ int reserveSize = 0;
+ for(int i = 0; i < numCodes; i++)
+ reserveSize += (int)codes[i].size();
+
+
+ header.clear();
+ header.reserve(reserveSize * 4);
+ sprintf(buffer, "#define NUM_UCODES %d\n\n", numCodes);
+ header.append(buffer);
+ header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n");
+ for (int i = 0; i < numCodes; i++)
+ {
+ std::string filename;
+ if (! SplitPath(filenames->at(i), NULL, &filename, NULL))
+ filename = filenames->at(i);
+ sprintf(buffer, "\t\"%s\",\n", filename.c_str());
+ header.append(buffer);
+ }
+ header.append("};\n\n");
+ header.append("#ifndef _MSCVER\n");
+ header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] = {\n");
+ header.append("#else\n");
+ header.append("const unsigned short dsp_ucode[NUM_UCODES][0x1000] __attribute__ ((aligned (64))) = {\n");
+ header.append("#endif\n\n");
+
+ for(int i = 0; i < numCodes; i++) {
+ if(codes[i].size() == 0)
+ continue;
+
+ std::vector<u16> code_copy = codes[i];
+ // Add some nops at the end to align the size a bit.
+ while (code_copy.size() & 7)
+ code_copy.push_back(0);
+
+ header.append("\t{\n\t\t");
+ for (u32 j = 0; j < codes[i].size(); j++)
+ {
+ if (j && ((j & 15) == 0))
+ header.append("\n\t\t");
+ sprintf(buffer, "0x%04x, ", codes[i][j]);
+ header.append(buffer);
+ }
+ header.append("\n\t},\n");
+ }
+ header.append("};\n");
+}
+
+void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str)
+{
+ str.resize(code.size() * 2);
+ for (int i = 0; i < (int)code.size(); i++)
+ {
+ str[i * 2 + 0] = code[i] >> 8;
+ str[i * 2 + 1] = code[i] & 0xff;
+ }
+}
+
+void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code)
+{
+ code.resize(str.size() / 2);
+ for (int i = 0; i < (int)code.size(); i++)
+ {
+ code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]);
+ }
+}
+
+bool LoadBinary(const char *filename, std::vector<u16> &code)
+{
+ std::string buffer;
+ if (!File::ReadFileToString(false, filename, buffer))
+ return false;
+
+ BinaryStringBEToCode(buffer, code);
+ return true;
+}
+
+bool SaveBinary(const std::vector<u16> &code, const char *filename)
+{
+ std::string buffer;
+ CodeToBinaryStringBE(code, buffer);
+ if (!File::WriteStringToFile(false, buffer, filename))
+ return false;
+ return true;
+}
diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.h b/Source/Core/DSPCore/Src/DSPCodeUtil.h
index 3d204e359e..bcf4a78048 100644
--- a/Source/Core/DSPCore/Src/DSPCodeUtil.h
+++ b/Source/Core/DSPCore/Src/DSPCodeUtil.h
@@ -1,43 +1,43 @@
-// 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 _DSPCODEUTIL_H
-#define _DSPCODEUTIL_H
-
-#include <string>
-#include <vector>
-
-#include "Common.h"
-
-bool Assemble(const char *text, std::vector<u16> &code);
-bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text);
-bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
-void GenRandomCode(int size, std::vector<u16> &code);
-void CodeToHeader(const std::vector<u16> &code, std::string _filename,
- const char *name, std::string &header);
-void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames,
- int numCodes, const char *name, std::string &header);
-
-// Big-endian, for writing straight to file using File::WriteStringToFile.
-void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str);
-void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code);
-
-// Load code (big endian binary).
-bool LoadBinary(const char *filename, std::vector<u16> &code);
-bool SaveBinary(const std::vector<u16> &code, const char *filename);
-
-#endif // _DSPCODEUTIL_H
+// 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 _DSPCODEUTIL_H
+#define _DSPCODEUTIL_H
+
+#include <string>
+#include <vector>
+
+#include "Common.h"
+
+bool Assemble(const char *text, std::vector<u16> &code);
+bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string &text);
+bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
+void GenRandomCode(int size, std::vector<u16> &code);
+void CodeToHeader(const std::vector<u16> &code, std::string _filename,
+ const char *name, std::string &header);
+void CodesToHeader(const std::vector<u16> *codes, const std::vector<std::string> *filenames,
+ int numCodes, const char *name, std::string &header);
+
+// Big-endian, for writing straight to file using File::WriteStringToFile.
+void CodeToBinaryStringBE(const std::vector<u16> &code, std::string &str);
+void BinaryStringBEToCode(const std::string &str, std::vector<u16> &code);
+
+// Load code (big endian binary).
+bool LoadBinary(const char *filename, std::vector<u16> &code);
+bool SaveBinary(const std::vector<u16> &code, const char *filename);
+
+#endif // _DSPCODEUTIL_H
diff --git a/Source/Core/DSPCore/Src/DSPCore.cpp b/Source/Core/DSPCore/Src/DSPCore.cpp
index c143852251..0dafd25259 100644
--- a/Source/Core/DSPCore/Src/DSPCore.cpp
+++ b/Source/Core/DSPCore/Src/DSPCore.cpp
@@ -1,256 +1,256 @@
-/*====================================================================
-
- filename: gdsp_interpreter.cpp
- project: GCemu
- created: 2004-6-18
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie & Tratax
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- ====================================================================*/
-
-#include "Common.h"
-#include "Thread.h"
-#include "DSPCore.h"
-#include "DSPHost.h"
-#include "DSPAnalyzer.h"
-#include "MemoryUtil.h"
-
-#include "DSPHWInterface.h"
-#include "DSPIntUtil.h"
-
-SDSP g_dsp;
-DSPBreakpoints dsp_breakpoints;
-DSPCoreState core_state = DSPCORE_RUNNING;
-Common::Event step_event;
-
-static bool LoadRom(const char *fname, int size_in_words, u16 *rom)
-{
- FILE *pFile = fopen(fname, "rb");
- const size_t size_in_bytes = size_in_words * sizeof(u16);
- if (pFile)
- {
- size_t read_bytes = fread(rom, 1, size_in_bytes, pFile);
- if (read_bytes != size_in_bytes)
- {
- PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes);
- fclose(pFile);
- return false;
- }
- fclose(pFile);
-
- // Byteswap the rom.
- for (int i = 0; i < DSP_IROM_SIZE; i++)
- rom[i] = Common::swap16(rom[i]);
-
- return true;
- }
- // Always keep ROMs write protected.
- WriteProtectMemory(g_dsp.irom, size_in_bytes, false);
- return false;
-}
-
-bool DSPCore_Init(const char *irom_filename, const char *coef_filename)
-{
- g_dsp.step_counter = 0;
-
- g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
- g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE);
- g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE);
- g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE);
-
- // Fill roms with zeros.
- memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE);
- memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE);
-
- // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP.
- LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom);
- LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef);
-
- for (int i = 0; i < 32; i++)
- {
- g_dsp.r[i] = 0;
- }
-
- for (int i = 0; i < 4; i++)
- {
- g_dsp.reg_stack_ptr[i] = 0;
- for (int j = 0; j < DSP_STACK_DEPTH; j++)
- {
- g_dsp.reg_stack[i][j] = 0;
- }
- }
-
- // Fill IRAM with HALT opcodes.
- for (int i = 0; i < DSP_IRAM_SIZE; i++)
- {
- g_dsp.iram[i] = 0x0021; // HALT opcode
- }
-
- // Just zero out DRAM.
- for (int i = 0; i < DSP_DRAM_SIZE; i++)
- {
- g_dsp.dram[i] = 0;
- }
-
- // Copied from a real console after the custom UCode has been loaded.
- // These are the indexing wrapping registers.
- g_dsp.r[DSP_REG_WR0] = 0xffff;
- g_dsp.r[DSP_REG_WR1] = 0xffff;
- g_dsp.r[DSP_REG_WR2] = 0xffff;
- g_dsp.r[DSP_REG_WR3] = 0xffff;
-
- g_dsp.cr = 0x804;
- gdsp_ifx_init();
-
- // Mostly keep IRAM write protected. We unprotect only when DMA-ing
- // in new ucodes.
- WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
- DSPAnalyzer::Analyze();
-
- step_event.Init();
- return true;
-}
-
-void DSPCore_Shutdown()
-{
- step_event.Shutdown();
- FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
- FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE);
-}
-
-void DSPCore_Reset()
-{
- _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception");
- g_dsp.pc = DSP_RESET_VECTOR;
- g_dsp.exception_in_progress_hack = false;
-
- g_dsp.r[DSP_REG_WR0] = 0xffff;
- g_dsp.r[DSP_REG_WR1] = 0xffff;
- g_dsp.r[DSP_REG_WR2] = 0xffff;
- g_dsp.r[DSP_REG_WR3] = 0xffff;
-
-}
-
-void DSPCore_SetException(u8 level)
-{
- g_dsp.exceptions |= 1 << level;
-}
-
-void DSPCore_CheckExternalInterrupt()
-{
- // check if there is an external interrupt
- if (g_dsp.cr & CR_EXTERNAL_INT && !g_dsp.exception_in_progress_hack)
- {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "trying External interupt fired");
-#endif
- if (dsp_SR_is_flag_set(SR_EXT_INT_ENABLE))
- {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "External interupt fired");
-#endif
- // level 7 is the interrupt exception
- DSPCore_SetException(EXP_INT);
-
- g_dsp.cr &= ~CR_EXTERNAL_INT;
- }
- }
-}
-
-void DSPCore_CheckExceptions()
-{
- if (g_dsp.exceptions != 0 && !g_dsp.exception_in_progress_hack) {
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "trying exception %d fired", g_dsp.exceptions);
-#endif
- // check exceptions
- for (int i = 0; i < 8; i++) {
- // Seems 7 must pass or zelda dies
- if (dsp_SR_is_flag_set(SR_INT_ENABLE) || i == EXP_INT) {
- if (g_dsp.exceptions & (1 << i)) {
- _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
-
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]);
-
- g_dsp.pc = i * 2;
- g_dsp.exceptions &= ~(1 << i);
-#ifdef DEBUG_EXP
- NOTICE_LOG(DSPLLE, "exception %d fired");
-#endif
- g_dsp.exception_in_progress_hack = true;
- break;
- }
- }
- }
- }
-}
-
-// Delegate to JIT (when it is written) or interpreter as appropriate.
-// Handle state changes and stepping.
-int DSPCore_RunCycles(int cycles)
-{
- while (cycles > 0) {
- reswitch:
- switch (core_state)
- {
- case DSPCORE_RUNNING:
-#if 1 // Set to 0 to disable breakpoints, for a speed boost.
- cycles = DSPInterpreter::RunCyclesDebug(cycles);
-#else
- cycles = DSPInterpreter::RunCycles(cycles);
-#endif
- break;
-
- case DSPCORE_STEPPING:
- step_event.Wait();
- if (core_state != DSPCORE_STEPPING)
- goto reswitch;
-
- DSPInterpreter::Step();
- cycles--;
-
- DSPHost_UpdateDebugger();
- break;
- }
- }
- return cycles;
-}
-
-void DSPCore_SetState(DSPCoreState new_state)
-{
- core_state = new_state;
- // kick the event, in case we are waiting
- if (new_state == DSPCORE_RUNNING)
- step_event.Set();
- // Sleep(10);
- DSPHost_UpdateDebugger();
-}
-
-DSPCoreState DSPCore_GetState()
-{
- return core_state;
-}
-
-void DSPCore_Step()
-{
- if (core_state == DSPCORE_STEPPING)
- step_event.Set();
-}
+/*====================================================================
+
+ filename: gdsp_interpreter.cpp
+ project: GCemu
+ created: 2004-6-18
+ mail: duddie@walla.com
+
+ Copyright (c) 2005 Duddie & Tratax
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ ====================================================================*/
+
+#include "Common.h"
+#include "Thread.h"
+#include "DSPCore.h"
+#include "DSPHost.h"
+#include "DSPAnalyzer.h"
+#include "MemoryUtil.h"
+
+#include "DSPHWInterface.h"
+#include "DSPIntUtil.h"
+
+SDSP g_dsp;
+DSPBreakpoints dsp_breakpoints;
+DSPCoreState core_state = DSPCORE_RUNNING;
+Common::Event step_event;
+
+static bool LoadRom(const char *fname, int size_in_words, u16 *rom)
+{
+ FILE *pFile = fopen(fname, "rb");
+ const size_t size_in_bytes = size_in_words * sizeof(u16);
+ if (pFile)
+ {
+ size_t read_bytes = fread(rom, 1, size_in_bytes, pFile);
+ if (read_bytes != size_in_bytes)
+ {
+ PanicAlert("ROM %s too short : %i/%i", fname, (int)read_bytes, (int)size_in_bytes);
+ fclose(pFile);
+ return false;
+ }
+ fclose(pFile);
+
+ // Byteswap the rom.
+ for (int i = 0; i < DSP_IROM_SIZE; i++)
+ rom[i] = Common::swap16(rom[i]);
+
+ return true;
+ }
+ // Always keep ROMs write protected.
+ WriteProtectMemory(g_dsp.irom, size_in_bytes, false);
+ return false;
+}
+
+bool DSPCore_Init(const char *irom_filename, const char *coef_filename)
+{
+ g_dsp.step_counter = 0;
+
+ g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
+ g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE);
+ g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE);
+ g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE);
+
+ // Fill roms with zeros.
+ memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE);
+ memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE);
+
+ // Try to load real ROM contents. Failing this, only homebrew will work correctly with the DSP.
+ LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom);
+ LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef);
+
+ for (int i = 0; i < 32; i++)
+ {
+ g_dsp.r[i] = 0;
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ g_dsp.reg_stack_ptr[i] = 0;
+ for (int j = 0; j < DSP_STACK_DEPTH; j++)
+ {
+ g_dsp.reg_stack[i][j] = 0;
+ }
+ }
+
+ // Fill IRAM with HALT opcodes.
+ for (int i = 0; i < DSP_IRAM_SIZE; i++)
+ {
+ g_dsp.iram[i] = 0x0021; // HALT opcode
+ }
+
+ // Just zero out DRAM.
+ for (int i = 0; i < DSP_DRAM_SIZE; i++)
+ {
+ g_dsp.dram[i] = 0;
+ }
+
+ // Copied from a real console after the custom UCode has been loaded.
+ // These are the indexing wrapping registers.
+ g_dsp.r[DSP_REG_WR0] = 0xffff;
+ g_dsp.r[DSP_REG_WR1] = 0xffff;
+ g_dsp.r[DSP_REG_WR2] = 0xffff;
+ g_dsp.r[DSP_REG_WR3] = 0xffff;
+
+ g_dsp.cr = 0x804;
+ gdsp_ifx_init();
+
+ // Mostly keep IRAM write protected. We unprotect only when DMA-ing
+ // in new ucodes.
+ WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
+ DSPAnalyzer::Analyze();
+
+ step_event.Init();
+ return true;
+}
+
+void DSPCore_Shutdown()
+{
+ step_event.Shutdown();
+ FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE);
+ FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
+ FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
+ FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE);
+}
+
+void DSPCore_Reset()
+{
+ _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception");
+ g_dsp.pc = DSP_RESET_VECTOR;
+ g_dsp.exception_in_progress_hack = false;
+
+ g_dsp.r[DSP_REG_WR0] = 0xffff;
+ g_dsp.r[DSP_REG_WR1] = 0xffff;
+ g_dsp.r[DSP_REG_WR2] = 0xffff;
+ g_dsp.r[DSP_REG_WR3] = 0xffff;
+
+}
+
+void DSPCore_SetException(u8 level)
+{
+ g_dsp.exceptions |= 1 << level;
+}
+
+void DSPCore_CheckExternalInterrupt()
+{
+ // check if there is an external interrupt
+ if (g_dsp.cr & CR_EXTERNAL_INT && !g_dsp.exception_in_progress_hack)
+ {
+#ifdef DEBUG_EXP
+ NOTICE_LOG(DSPLLE, "trying External interupt fired");
+#endif
+ if (dsp_SR_is_flag_set(SR_EXT_INT_ENABLE))
+ {
+#ifdef DEBUG_EXP
+ NOTICE_LOG(DSPLLE, "External interupt fired");
+#endif
+ // level 7 is the interrupt exception
+ DSPCore_SetException(EXP_INT);
+
+ g_dsp.cr &= ~CR_EXTERNAL_INT;
+ }
+ }
+}
+
+void DSPCore_CheckExceptions()
+{
+ if (g_dsp.exceptions != 0 && !g_dsp.exception_in_progress_hack) {
+#ifdef DEBUG_EXP
+ NOTICE_LOG(DSPLLE, "trying exception %d fired", g_dsp.exceptions);
+#endif
+ // check exceptions
+ for (int i = 0; i < 8; i++) {
+ // Seems 7 must pass or zelda dies
+ if (dsp_SR_is_flag_set(SR_INT_ENABLE) || i == EXP_INT) {
+ if (g_dsp.exceptions & (1 << i)) {
+ _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
+
+ dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
+ dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[DSP_REG_SR]);
+
+ g_dsp.pc = i * 2;
+ g_dsp.exceptions &= ~(1 << i);
+#ifdef DEBUG_EXP
+ NOTICE_LOG(DSPLLE, "exception %d fired");
+#endif
+ g_dsp.exception_in_progress_hack = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+// Delegate to JIT (when it is written) or interpreter as appropriate.
+// Handle state changes and stepping.
+int DSPCore_RunCycles(int cycles)
+{
+ while (cycles > 0) {
+ reswitch:
+ switch (core_state)
+ {
+ case DSPCORE_RUNNING:
+#if 1 // Set to 0 to disable breakpoints, for a speed boost.
+ cycles = DSPInterpreter::RunCyclesDebug(cycles);
+#else
+ cycles = DSPInterpreter::RunCycles(cycles);
+#endif
+ break;
+
+ case DSPCORE_STEPPING:
+ step_event.Wait();
+ if (core_state != DSPCORE_STEPPING)
+ goto reswitch;
+
+ DSPInterpreter::Step();
+ cycles--;
+
+ DSPHost_UpdateDebugger();
+ break;
+ }
+ }
+ return cycles;
+}
+
+void DSPCore_SetState(DSPCoreState new_state)
+{
+ core_state = new_state;
+ // kick the event, in case we are waiting
+ if (new_state == DSPCORE_RUNNING)
+ step_event.Set();
+ // Sleep(10);
+ DSPHost_UpdateDebugger();
+}
+
+DSPCoreState DSPCore_GetState()
+{
+ return core_state;
+}
+
+void DSPCore_Step()
+{
+ if (core_state == DSPCORE_STEPPING)
+ step_event.Set();
+}
diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h
index 24d31eed48..b1293e70f6 100644
--- a/Source/Core/DSPCore/Src/DSPCore.h
+++ b/Source/Core/DSPCore/Src/DSPCore.h
@@ -1,240 +1,240 @@
-/*====================================================================
-
- filename: DSPCore.h
- project: GCemu
- created: 2004-6-18
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie & Tratax
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- ====================================================================*/
-
-#ifndef _DSPCORE_H
-#define _DSPCORE_H
-
-#include "DSPBreakpoints.h"
-
-#define DSP_IRAM_BYTE_SIZE 0x2000
-#define DSP_IRAM_SIZE 0x1000
-#define DSP_IRAM_MASK 0x0fff
-
-#define DSP_IROM_BYTE_SIZE 0x2000
-#define DSP_IROM_SIZE 0x1000
-#define DSP_IROM_MASK 0x0fff
-
-#define DSP_DRAM_BYTE_SIZE 0x2000
-#define DSP_DRAM_SIZE 0x1000
-#define DSP_DRAM_MASK 0x0fff
-
-#define DSP_COEF_BYTE_SIZE 0x2000
-#define DSP_COEF_SIZE 0x1000
-#define DSP_COEF_MASK 0x0fff
-
-#define DSP_RESET_VECTOR 0x8000
-
-#define DSP_STACK_DEPTH 0x20
-#define DSP_STACK_MASK 0x1f
-
-#define DSP_CR_IMEM 2
-#define DSP_CR_DMEM 0
-#define DSP_CR_TO_CPU 1
-#define DSP_CR_FROM_CPU 0
-
-
-// Register table taken from libasnd
-#define DSP_REG_AR0 0x00 // address registers
-#define DSP_REG_AR1 0x01
-#define DSP_REG_AR2 0x02
-#define DSP_REG_AR3 0x03
-
-#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments)
-#define DSP_REG_IX1 0x05
-#define DSP_REG_IX2 0x06
-#define DSP_REG_IX3 0x07
-
-#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used.
-#define DSP_REG_WR1 0x09
-#define DSP_REG_WR2 0x0a
-#define DSP_REG_WR3 0x0b
-
-#define DSP_REG_ST0 0x0c // stacks.
-#define DSP_REG_ST1 0x0d
-#define DSP_REG_ST2 0x0e
-#define DSP_REG_ST3 0x0f
-
-#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS.
-#define DSP_REG_SR 0x13
-
-#define DSP_REG_PRODL 0x14 // product.
-#define DSP_REG_PRODM 0x15
-#define DSP_REG_PRODH 0x16
-#define DSP_REG_PRODM2 0x17
-
-#define DSP_REG_AXL0 0x18
-#define DSP_REG_AXL1 0x19
-#define DSP_REG_AXH0 0x1a
-#define DSP_REG_AXH1 0x1b
-
-#define DSP_REG_ACC0 0x1c // accumulator (global)
-#define DSP_REG_ACC1 0x1d
-
-#define DSP_REG_ACL0 0x1c // Low accumulator
-#define DSP_REG_ACL1 0x1d
-#define DSP_REG_ACM0 0x1e // Mid accumulator
-#define DSP_REG_ACM1 0x1f
-#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0
-#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1
-
-// Hardware registers address
-
-#define DSP_COEF_A1_0 0xa0
-
-#define DSP_DSMAH 0xce
-#define DSP_DSMAL 0xcf
-#define DSP_DSCR 0xc9 // DSP DMA Control Reg
-#define DSP_DSPA 0xcd // DSP DMA Block Length
-#define DSP_DSBL 0xcb // DSP DMA DMEM Address
-#define DSP_DSMAH 0xce // DSP DMA Mem Address H
-#define DSP_DSMAL 0xcf // DSP DMA Mem Address L
-
-#define DSP_FORMAT 0xd1
-#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes
-#define DSP_ACSAH 0xd4
-#define DSP_ACSAL 0xd5
-#define DSP_ACEAH 0xd6
-#define DSP_ACEAL 0xd7
-#define DSP_ACCAH 0xd8
-#define DSP_ACCAL 0xd9
-#define DSP_PRED_SCALE 0xda
-#define DSP_YN1 0xdb
-#define DSP_YN2 0xdc
-#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX.
-#define DSP_GAIN 0xde
-
-#define DSP_DIRQ 0xfb // DSP Irq Rest
-#define DSP_DMBH 0xfc // DSP Mailbox H
-#define DSP_DMBL 0xfd // DSP Mailbox L
-#define DSP_CMBH 0xfe // CPU Mailbox H
-#define DSP_CMBL 0xff // CPU Mailbox L
-
-#define DMA_TO_DSP 0
-#define DMA_TO_CPU 1
-
-// Stacks
-#define DSP_STACK_C 0
-#define DSP_STACK_D 1
-
-// cr (Not g_dsp.r[CR]) bits
-// See HW/DSP.cpp.
-#define CR_HALT 0x0004
-#define CR_EXTERNAL_INT 0x0002
-
-
-// SR bits
-#define SR_CARRY 0x0001
-#define SR_2 0x0002 // overflow???
-#define SR_ARITH_ZERO 0x0004
-#define SR_SIGN 0x0008
-#define SR_10 0x0010 // seem to be set by tst
-#define SR_TOP2BITS 0x0020 // this is an odd one. (set by tst)
-#define SR_LOGIC_ZERO 0x0040
-#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so.
-#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts
-#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2)
-#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums.
-#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far.
-
-// This should be the bits affected by CMP. Does not include logic zero.
-#define SR_CMP_MASK 0x3f
-
-// exceptions vector
-#define EXP_RESET 0 // 0x0000
-#define EXP_STOVF 1 // 0x0002 stack under/over flow
-#define EXP_4 2 // 0x0004
-#define EXP_6 3 // 0x0006
-#define EXP_8 4 // 0x0008
-#define EXP_ACCOV 5 // 0x000a accelerator address overflow
-#define EXP_c 6 // 0x000c
-#define EXP_INT 7 // 0x000e external int? (mail?)
-
-struct SDSP
-{
- u16 r[32];
- u16 pc;
-#if PROFILE
- u16 err_pc;
-#endif
-
- // This is NOT the same cr as r[DSP_REG_CR].
- // This register is shared with the main emulation, see DSP.cpp
- // The plugin has control over 0x0C07 of this reg.
- // Bits are defined in a struct in DSP.cpp.
- u16 cr;
-
- u8 reg_stack_ptr[4];
- u8 exceptions; // pending exceptions?
- bool exception_in_progress_hack; // is this the same as "exception enabled"?
-
- // Let's make stack depth 32 for now. The real DSP has different depths
- // for the different stacks, but it would be strange if any ucode relied on stack
- // overflows since on the DSP, when the stack overflows, you're screwed.
- u16 reg_stack[4][DSP_STACK_DEPTH];
-
- // For debugging.
- u32 iram_crc;
- u64 step_counter;
-
- // When state saving, all of the above can just be memcpy'd into the save state.
- // The below needs special handling.
- u16 *iram;
- u16 *dram;
- u16 *irom;
- u16 *coef;
-
- // This one doesn't really belong here.
- u8 *cpu_ram;
-};
-
-extern SDSP g_dsp;
-extern DSPBreakpoints dsp_breakpoints;
-
-bool DSPCore_Init(const char *irom_filename, const char *coef_filename);
-
-void DSPCore_Reset();
-void DSPCore_Shutdown(); // Frees all allocated memory.
-
-void DSPCore_CheckExternalInterrupt();
-void DSPCore_CheckExceptions();
-
-// sets a flag in the pending exception register.
-void DSPCore_SetException(u8 level);
-
-enum DSPCoreState
-{
- DSPCORE_RUNNING = 0,
- DSPCORE_STEPPING = 1,
-};
-
-int DSPCore_RunCycles(int cycles);
-
-// These are meant to be called from the UI thread.
-void DSPCore_SetState(DSPCoreState new_state);
-DSPCoreState DSPCore_GetState();
-
-void DSPCore_Step();
-
-#endif // _DSPCORE_H
+/*====================================================================
+
+ filename: DSPCore.h
+ project: GCemu
+ created: 2004-6-18
+ mail: duddie@walla.com
+
+ Copyright (c) 2005 Duddie & Tratax
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ ====================================================================*/
+
+#ifndef _DSPCORE_H
+#define _DSPCORE_H
+
+#include "DSPBreakpoints.h"
+
+#define DSP_IRAM_BYTE_SIZE 0x2000
+#define DSP_IRAM_SIZE 0x1000
+#define DSP_IRAM_MASK 0x0fff
+
+#define DSP_IROM_BYTE_SIZE 0x2000
+#define DSP_IROM_SIZE 0x1000
+#define DSP_IROM_MASK 0x0fff
+
+#define DSP_DRAM_BYTE_SIZE 0x2000
+#define DSP_DRAM_SIZE 0x1000
+#define DSP_DRAM_MASK 0x0fff
+
+#define DSP_COEF_BYTE_SIZE 0x2000
+#define DSP_COEF_SIZE 0x1000
+#define DSP_COEF_MASK 0x0fff
+
+#define DSP_RESET_VECTOR 0x8000
+
+#define DSP_STACK_DEPTH 0x20
+#define DSP_STACK_MASK 0x1f
+
+#define DSP_CR_IMEM 2
+#define DSP_CR_DMEM 0
+#define DSP_CR_TO_CPU 1
+#define DSP_CR_FROM_CPU 0
+
+
+// Register table taken from libasnd
+#define DSP_REG_AR0 0x00 // address registers
+#define DSP_REG_AR1 0x01
+#define DSP_REG_AR2 0x02
+#define DSP_REG_AR3 0x03
+
+#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments)
+#define DSP_REG_IX1 0x05
+#define DSP_REG_IX2 0x06
+#define DSP_REG_IX3 0x07
+
+#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used.
+#define DSP_REG_WR1 0x09
+#define DSP_REG_WR2 0x0a
+#define DSP_REG_WR3 0x0b
+
+#define DSP_REG_ST0 0x0c // stacks.
+#define DSP_REG_ST1 0x0d
+#define DSP_REG_ST2 0x0e
+#define DSP_REG_ST3 0x0f
+
+#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS.
+#define DSP_REG_SR 0x13
+
+#define DSP_REG_PRODL 0x14 // product.
+#define DSP_REG_PRODM 0x15
+#define DSP_REG_PRODH 0x16
+#define DSP_REG_PRODM2 0x17
+
+#define DSP_REG_AXL0 0x18
+#define DSP_REG_AXL1 0x19
+#define DSP_REG_AXH0 0x1a
+#define DSP_REG_AXH1 0x1b
+
+#define DSP_REG_ACC0 0x1c // accumulator (global)
+#define DSP_REG_ACC1 0x1d
+
+#define DSP_REG_ACL0 0x1c // Low accumulator
+#define DSP_REG_ACL1 0x1d
+#define DSP_REG_ACM0 0x1e // Mid accumulator
+#define DSP_REG_ACM1 0x1f
+#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0
+#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1
+
+// Hardware registers address
+
+#define DSP_COEF_A1_0 0xa0
+
+#define DSP_DSMAH 0xce
+#define DSP_DSMAL 0xcf
+#define DSP_DSCR 0xc9 // DSP DMA Control Reg
+#define DSP_DSPA 0xcd // DSP DMA Block Length
+#define DSP_DSBL 0xcb // DSP DMA DMEM Address
+#define DSP_DSMAH 0xce // DSP DMA Mem Address H
+#define DSP_DSMAL 0xcf // DSP DMA Mem Address L
+
+#define DSP_FORMAT 0xd1
+#define DSP_ACDATA1 0xd3 // used only by Zelda ucodes
+#define DSP_ACSAH 0xd4
+#define DSP_ACSAL 0xd5
+#define DSP_ACEAH 0xd6
+#define DSP_ACEAL 0xd7
+#define DSP_ACCAH 0xd8
+#define DSP_ACCAL 0xd9
+#define DSP_PRED_SCALE 0xda
+#define DSP_YN1 0xdb
+#define DSP_YN2 0xdc
+#define DSP_ACCELERATOR 0xdd // ADPCM accelerator read. Used by AX.
+#define DSP_GAIN 0xde
+
+#define DSP_DIRQ 0xfb // DSP Irq Rest
+#define DSP_DMBH 0xfc // DSP Mailbox H
+#define DSP_DMBL 0xfd // DSP Mailbox L
+#define DSP_CMBH 0xfe // CPU Mailbox H
+#define DSP_CMBL 0xff // CPU Mailbox L
+
+#define DMA_TO_DSP 0
+#define DMA_TO_CPU 1
+
+// Stacks
+#define DSP_STACK_C 0
+#define DSP_STACK_D 1
+
+// cr (Not g_dsp.r[CR]) bits
+// See HW/DSP.cpp.
+#define CR_HALT 0x0004
+#define CR_EXTERNAL_INT 0x0002
+
+
+// SR bits
+#define SR_CARRY 0x0001
+#define SR_2 0x0002 // overflow???
+#define SR_ARITH_ZERO 0x0004
+#define SR_SIGN 0x0008
+#define SR_10 0x0010 // seem to be set by tst
+#define SR_TOP2BITS 0x0020 // this is an odd one. (set by tst)
+#define SR_LOGIC_ZERO 0x0040
+#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so.
+#define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts
+#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2)
+#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums.
+#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far.
+
+// This should be the bits affected by CMP. Does not include logic zero.
+#define SR_CMP_MASK 0x3f
+
+// exceptions vector
+#define EXP_RESET 0 // 0x0000
+#define EXP_STOVF 1 // 0x0002 stack under/over flow
+#define EXP_4 2 // 0x0004
+#define EXP_6 3 // 0x0006
+#define EXP_8 4 // 0x0008
+#define EXP_ACCOV 5 // 0x000a accelerator address overflow
+#define EXP_c 6 // 0x000c
+#define EXP_INT 7 // 0x000e external int? (mail?)
+
+struct SDSP
+{
+ u16 r[32];
+ u16 pc;
+#if PROFILE
+ u16 err_pc;
+#endif
+
+ // This is NOT the same cr as r[DSP_REG_CR].
+ // This register is shared with the main emulation, see DSP.cpp
+ // The plugin has control over 0x0C07 of this reg.
+ // Bits are defined in a struct in DSP.cpp.
+ u16 cr;
+
+ u8 reg_stack_ptr[4];
+ u8 exceptions; // pending exceptions?
+ bool exception_in_progress_hack; // is this the same as "exception enabled"?
+
+ // Let's make stack depth 32 for now. The real DSP has different depths
+ // for the different stacks, but it would be strange if any ucode relied on stack
+ // overflows since on the DSP, when the stack overflows, you're screwed.
+ u16 reg_stack[4][DSP_STACK_DEPTH];
+
+ // For debugging.
+ u32 iram_crc;
+ u64 step_counter;
+
+ // When state saving, all of the above can just be memcpy'd into the save state.
+ // The below needs special handling.
+ u16 *iram;
+ u16 *dram;
+ u16 *irom;
+ u16 *coef;
+
+ // This one doesn't really belong here.
+ u8 *cpu_ram;
+};
+
+extern SDSP g_dsp;
+extern DSPBreakpoints dsp_breakpoints;
+
+bool DSPCore_Init(const char *irom_filename, const char *coef_filename);
+
+void DSPCore_Reset();
+void DSPCore_Shutdown(); // Frees all allocated memory.
+
+void DSPCore_CheckExternalInterrupt();
+void DSPCore_CheckExceptions();
+
+// sets a flag in the pending exception register.
+void DSPCore_SetException(u8 level);
+
+enum DSPCoreState
+{
+ DSPCORE_RUNNING = 0,
+ DSPCORE_STEPPING = 1,
+};
+
+int DSPCore_RunCycles(int cycles);
+
+// These are meant to be called from the UI thread.
+void DSPCore_SetState(DSPCoreState new_state);
+DSPCoreState DSPCore_GetState();
+
+void DSPCore_Step();
+
+#endif // _DSPCORE_H
diff --git a/Source/Core/DSPCore/Src/DSPHost.h b/Source/Core/DSPCore/Src/DSPHost.h
index 60791deeb1..0abddd85f3 100644
--- a/Source/Core/DSPCore/Src/DSPHost.h
+++ b/Source/Core/DSPCore/Src/DSPHost.h
@@ -1,35 +1,35 @@
-// 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 _DSPHOST_H
-#define _DSPHOST_H
-
-// The user of the DSPCore library must supply a few functions so that the
-// emulation core can access the environment it runs in. If the emulation
-// core isn't used, for example in an asm/disasm tool, then most of these
-// can be stubbed out.
-#define DEBUG_EXP 1
-
-u8 DSPHost_ReadHostMemory(u32 addr);
-void DSPHost_WriteHostMemory(u8 value, u32 addr);
-bool DSPHost_OnThread();
-bool DSPHost_Running();
-void DSPHost_InterruptRequest();
-u32 DSPHost_CodeLoaded(const u8 *ptr, int size);
-void DSPHost_UpdateDebugger();
-
-#endif
+// 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 _DSPHOST_H
+#define _DSPHOST_H
+
+// The user of the DSPCore library must supply a few functions so that the
+// emulation core can access the environment it runs in. If the emulation
+// core isn't used, for example in an asm/disasm tool, then most of these
+// can be stubbed out.
+#define DEBUG_EXP 1
+
+u8 DSPHost_ReadHostMemory(u32 addr);
+void DSPHost_WriteHostMemory(u8 value, u32 addr);
+bool DSPHost_OnThread();
+bool DSPHost_Running();
+void DSPHost_InterruptRequest();
+u32 DSPHost_CodeLoaded(const u8 *ptr, int size);
+void DSPHost_UpdateDebugger();
+
+#endif
diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp
index bb391a4a91..171a783331 100644
--- a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp
+++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp
@@ -1,140 +1,140 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-// HELPER FUNCTIONS
-
-#include "DSPIntCCUtil.h"
-#include "DSPCore.h"
-#include "DSPInterpreter.h"
-
-namespace DSPInterpreter {
-
-void Update_SR_Register64(s64 _Value)
-{
- g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
-
- if (_Value < 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_SIGN;
- }
-
- if (_Value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
- }
-
- // weird
- if ((_Value >> 62) == 0)
- {
- g_dsp.r[DSP_REG_SR] |= 0x20;
- }
-}
-
-void Update_SR_Register16(s16 _Value)
-{
- g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
-
- if (_Value < 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_SIGN;
- }
-
- if (_Value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
- }
-
- // weird
- if ((_Value >> 14) == 0)
- {
- g_dsp.r[DSP_REG_SR] |= 0x20;
- }
-}
-
-void Update_SR_LZ(s64 value) {
-
- if (value == 0)
- {
- g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO;
- }
- else
- {
- g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO;
- }
-
-}
-
-int GetMultiplyModifier()
-{
- if (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)
- return 1;
- else
- return 2;
-}
-
-inline bool isCarry() {
- return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false;
-}
-inline bool isSign() {
- return ((g_dsp.r[DSP_REG_SR] & SR_2) != (g_dsp.r[DSP_REG_SR] & SR_SIGN));
-}
-inline bool isZero() {
- return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false;
-}
-
-//see gdsp_registers.h for flags
-bool CheckCondition(u8 _Condition)
-{
- switch (_Condition & 0xf)
- {
- case 0x0: //NS - NOT SIGN
- return !isSign();
- case 0x1: // S - SIGN
- return isSign();
- case 0x2: // G - GREATER
- return !isSign() && !isZero();
- case 0x3: // LE - LESS EQUAL
- return isSign() || isZero();
- case 0x4: // NZ - NOT ZERO
- return !isZero();
- case 0x5: // Z - ZERO
- return isZero();
- case 0x6: // L - LESS
- // Should be that once we set 0x01
- return !isCarry();
- // if (isSign())
- case 0x7: // GE - GREATER EQUAL
- // Should be that once we set 0x01
- return isCarry();
- // if (! isSign() || isZero())
- case 0xc: // LNZ - LOGIC NOT ZERO
- return !(g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO);
- case 0xd: // LZ - LOGIC ZERO
- return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) != 0;
-
- case 0xf: // Empty - always true.
- return true;
- default:
- ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf);
- return false;
- }
-}
-
-} // namespace
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+
+// HELPER FUNCTIONS
+
+#include "DSPIntCCUtil.h"
+#include "DSPCore.h"
+#include "DSPInterpreter.h"
+
+namespace DSPInterpreter {
+
+void Update_SR_Register64(s64 _Value)
+{
+ g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
+
+ if (_Value < 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= SR_SIGN;
+ }
+
+ if (_Value == 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
+ }
+
+ // weird
+ if ((_Value >> 62) == 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= 0x20;
+ }
+}
+
+void Update_SR_Register16(s16 _Value)
+{
+ g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
+
+ if (_Value < 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= SR_SIGN;
+ }
+
+ if (_Value == 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
+ }
+
+ // weird
+ if ((_Value >> 14) == 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= 0x20;
+ }
+}
+
+void Update_SR_LZ(s64 value) {
+
+ if (value == 0)
+ {
+ g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO;
+ }
+ else
+ {
+ g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO;
+ }
+
+}
+
+int GetMultiplyModifier()
+{
+ if (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)
+ return 1;
+ else
+ return 2;
+}
+
+inline bool isCarry() {
+ return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false;
+}
+inline bool isSign() {
+ return ((g_dsp.r[DSP_REG_SR] & SR_2) != (g_dsp.r[DSP_REG_SR] & SR_SIGN));
+}
+inline bool isZero() {
+ return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false;
+}
+
+//see gdsp_registers.h for flags
+bool CheckCondition(u8 _Condition)
+{
+ switch (_Condition & 0xf)
+ {
+ case 0x0: //NS - NOT SIGN
+ return !isSign();
+ case 0x1: // S - SIGN
+ return isSign();
+ case 0x2: // G - GREATER
+ return !isSign() && !isZero();
+ case 0x3: // LE - LESS EQUAL
+ return isSign() || isZero();
+ case 0x4: // NZ - NOT ZERO
+ return !isZero();
+ case 0x5: // Z - ZERO
+ return isZero();
+ case 0x6: // L - LESS
+ // Should be that once we set 0x01
+ return !isCarry();
+ // if (isSign())
+ case 0x7: // GE - GREATER EQUAL
+ // Should be that once we set 0x01
+ return isCarry();
+ // if (! isSign() || isZero())
+ case 0xc: // LNZ - LOGIC NOT ZERO
+ return !(g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO);
+ case 0xd: // LZ - LOGIC ZERO
+ return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) != 0;
+
+ case 0xf: // Empty - always true.
+ return true;
+ default:
+ ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf);
+ return false;
+ }
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.h b/Source/Core/DSPCore/Src/DSPIntCCUtil.h
index def95e0b97..135e861062 100644
--- a/Source/Core/DSPCore/Src/DSPIntCCUtil.h
+++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.h
@@ -1,39 +1,39 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#ifndef _GDSP_CONDITION_CODES_H
-#define _GDSP_CONDITION_CODES_H
-
-// Anything to do with SR and conditions goes here.
-
-#include "Common.h"
-
-namespace DSPInterpreter {
-
-bool CheckCondition(u8 _Condition);
-
-int GetMultiplyModifier();
-
-void Update_SR_Register16(s16 _Value);
-void Update_SR_Register64(s64 _Value);
-void Update_SR_LZ(s64 value);
-
-} // namespace
-
-#endif // _GDSP_CONDITION_CODES_H
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+#ifndef _GDSP_CONDITION_CODES_H
+#define _GDSP_CONDITION_CODES_H
+
+// Anything to do with SR and conditions goes here.
+
+#include "Common.h"
+
+namespace DSPInterpreter {
+
+bool CheckCondition(u8 _Condition);
+
+int GetMultiplyModifier();
+
+void Update_SR_Register16(s16 _Value);
+void Update_SR_Register64(s64 _Value);
+void Update_SR_LZ(s64 value);
+
+} // namespace
+
+#endif // _GDSP_CONDITION_CODES_H
diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.h b/Source/Core/DSPCore/Src/DSPInterpreter.h
index d8f4d84f58..fe5f1afcc9 100644
--- a/Source/Core/DSPCore/Src/DSPInterpreter.h
+++ b/Source/Core/DSPCore/Src/DSPInterpreter.h
@@ -1,171 +1,171 @@
-// 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 _DSPINTERPRETER_H
-#define _DSPINTERPRETER_H
-
-#include "DSPTables.h"
-
-#define DSP_REG_MASK 0x1f
-
-namespace DSPInterpreter {
-
-void Step();
-void Run();
-
-// If these simply return the same number of cycles as was passed into them,
-// chances are that the DSP is halted.
-// The difference between them is that the debug one obeys breakpoints.
-int RunCycles(int cycles);
-int RunCyclesDebug(int cycles);
-
-void Stop();
-
-void WriteCR(u16 val);
-u16 ReadCR();
-
-
-typedef void (*DSPInterpreterFunc)(const UDSPInstruction& opc);
-
-// All the opcode functions.
-void unknown(const UDSPInstruction& opc);
-void call(const UDSPInstruction& opc);
-void callr(const UDSPInstruction& opc);
-void ifcc(const UDSPInstruction& opc);
-void jcc(const UDSPInstruction& opc);
-void jmprcc(const UDSPInstruction& opc);
-void ret(const UDSPInstruction& opc);
-void halt(const UDSPInstruction& opc);
-void loop(const UDSPInstruction& opc);
-void loopi(const UDSPInstruction& opc);
-void bloop(const UDSPInstruction& opc);
-void bloopi(const UDSPInstruction& opc);
-void mrr(const UDSPInstruction& opc);
-void lrr(const UDSPInstruction& opc);
-void lrrd(const UDSPInstruction& opc);
-void lrri(const UDSPInstruction& opc);
-void lrrn(const UDSPInstruction& opc);
-void srr(const UDSPInstruction& opc);
-void srrd(const UDSPInstruction& opc);
-void srri(const UDSPInstruction& opc);
-void srrn(const UDSPInstruction& opc);
-void lri(const UDSPInstruction& opc);
-void lris(const UDSPInstruction& opc);
-void lr(const UDSPInstruction& opc);
-void sr(const UDSPInstruction& opc);
-void si(const UDSPInstruction& opc);
-void tstaxh(const UDSPInstruction& opc);
-void clr(const UDSPInstruction& opc);
-void clrl(const UDSPInstruction& opc);
-void clrp(const UDSPInstruction& opc);
-void mulc(const UDSPInstruction& opc);
-void cmpar(const UDSPInstruction& opc);
-void cmp(const UDSPInstruction& opc);
-void tst(const UDSPInstruction& opc);
-void addaxl(const UDSPInstruction& opc);
-void addarn(const UDSPInstruction& opc);
-void mulcac(const UDSPInstruction& opc);
-void movr(const UDSPInstruction& opc);
-void movax(const UDSPInstruction& opc);
-void xorr(const UDSPInstruction& opc);
-void andr(const UDSPInstruction& opc);
-void andc(const UDSPInstruction& opc);
-void orr(const UDSPInstruction& opc);
-void orc(const UDSPInstruction& opc);
-void orf(const UDSPInstruction& opc);
-void add(const UDSPInstruction& opc);
-void addp(const UDSPInstruction& opc);
-void cmpis(const UDSPInstruction& opc);
-void addpaxz(const UDSPInstruction& opc);
-void movpz(const UDSPInstruction& opc);
-void decm(const UDSPInstruction& opc);
-void dec(const UDSPInstruction& opc);
-void inc(const UDSPInstruction& opc);
-void incm(const UDSPInstruction& opc);
-void neg(const UDSPInstruction& opc);
-void addax(const UDSPInstruction& opc);
-void addr(const UDSPInstruction& opc);
-void subr(const UDSPInstruction& opc);
-void subp(const UDSPInstruction& opc);
-void subax(const UDSPInstruction& opc);
-void addis(const UDSPInstruction& opc);
-void addi(const UDSPInstruction& opc);
-void lsl16(const UDSPInstruction& opc);
-void madd(const UDSPInstruction& opc);
-void msub(const UDSPInstruction& opc);
-void lsr16(const UDSPInstruction& opc);
-void asr16(const UDSPInstruction& opc);
-void lsl(const UDSPInstruction& opc);
-void lsr(const UDSPInstruction& opc);
-void asl(const UDSPInstruction& opc);
-void asr(const UDSPInstruction& opc);
-void lsrn(const UDSPInstruction& opc);
-void asrn(const UDSPInstruction& opc);
-void dar(const UDSPInstruction& opc);
-void iar(const UDSPInstruction& opc);
-void sbclr(const UDSPInstruction& opc);
-void sbset(const UDSPInstruction& opc);
-void mov(const UDSPInstruction& opc);
-void movp(const UDSPInstruction& opc);
-void mul(const UDSPInstruction& opc);
-void mulac(const UDSPInstruction& opc);
-void mulmv(const UDSPInstruction& opc);
-void mulmvz(const UDSPInstruction& opc);
-void mulx(const UDSPInstruction& opc);
-void mulxac(const UDSPInstruction& opc);
-void mulxmv(const UDSPInstruction& opc);
-void mulxmvz(const UDSPInstruction& opc);
-void mulcmvz(const UDSPInstruction& opc);
-void mulcmv(const UDSPInstruction& opc);
-void movnp(const UDSPInstruction& opc);
-void sub(const UDSPInstruction& opc);
-void maddx(const UDSPInstruction& opc);
-void msubx(const UDSPInstruction& opc);
-void maddc(const UDSPInstruction& opc);
-void msubc(const UDSPInstruction& opc);
-void srs(const UDSPInstruction& opc);
-void lrs(const UDSPInstruction& opc);
-void nx(const UDSPInstruction& opc);
-void cmpi(const UDSPInstruction& opc);
-void rti(const UDSPInstruction& opc);
-void ilrr(const UDSPInstruction& opc);
-void ilrrd(const UDSPInstruction& opc);
-void ilrri(const UDSPInstruction& opc);
-void ilrrn(const UDSPInstruction& opc);
-void andcf(const UDSPInstruction& opc);
-void andf(const UDSPInstruction& opc);
-void xori(const UDSPInstruction& opc);
-void andi(const UDSPInstruction& opc);
-void ori(const UDSPInstruction& opc);
-
-// FIXME inside
-void srbith(const UDSPInstruction& opc);
-
-// END OF FIXMEs
-
-// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED
-void tstaxl(const UDSPInstruction& opc);
-// The mysterious a100
-
-// END OF UNIMPLEMENTED
-
-// Helpers
-inline void tsta(int reg);
-
-} // namespace
-
-#endif // _DSPINTERPRETER_H
+// 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 _DSPINTERPRETER_H
+#define _DSPINTERPRETER_H
+
+#include "DSPTables.h"
+
+#define DSP_REG_MASK 0x1f
+
+namespace DSPInterpreter {
+
+void Step();
+void Run();
+
+// If these simply return the same number of cycles as was passed into them,
+// chances are that the DSP is halted.
+// The difference between them is that the debug one obeys breakpoints.
+int RunCycles(int cycles);
+int RunCyclesDebug(int cycles);
+
+void Stop();
+
+void WriteCR(u16 val);
+u16 ReadCR();
+
+
+typedef void (*DSPInterpreterFunc)(const UDSPInstruction& opc);
+
+// All the opcode functions.
+void unknown(const UDSPInstruction& opc);
+void call(const UDSPInstruction& opc);
+void callr(const UDSPInstruction& opc);
+void ifcc(const UDSPInstruction& opc);
+void jcc(const UDSPInstruction& opc);
+void jmprcc(const UDSPInstruction& opc);
+void ret(const UDSPInstruction& opc);
+void halt(const UDSPInstruction& opc);
+void loop(const UDSPInstruction& opc);
+void loopi(const UDSPInstruction& opc);
+void bloop(const UDSPInstruction& opc);
+void bloopi(const UDSPInstruction& opc);
+void mrr(const UDSPInstruction& opc);
+void lrr(const UDSPInstruction& opc);
+void lrrd(const UDSPInstruction& opc);
+void lrri(const UDSPInstruction& opc);
+void lrrn(const UDSPInstruction& opc);
+void srr(const UDSPInstruction& opc);
+void srrd(const UDSPInstruction& opc);
+void srri(const UDSPInstruction& opc);
+void srrn(const UDSPInstruction& opc);
+void lri(const UDSPInstruction& opc);
+void lris(const UDSPInstruction& opc);
+void lr(const UDSPInstruction& opc);
+void sr(const UDSPInstruction& opc);
+void si(const UDSPInstruction& opc);
+void tstaxh(const UDSPInstruction& opc);
+void clr(const UDSPInstruction& opc);
+void clrl(const UDSPInstruction& opc);
+void clrp(const UDSPInstruction& opc);
+void mulc(const UDSPInstruction& opc);
+void cmpar(const UDSPInstruction& opc);
+void cmp(const UDSPInstruction& opc);
+void tst(const UDSPInstruction& opc);
+void addaxl(const UDSPInstruction& opc);
+void addarn(const UDSPInstruction& opc);
+void mulcac(const UDSPInstruction& opc);
+void movr(const UDSPInstruction& opc);
+void movax(const UDSPInstruction& opc);
+void xorr(const UDSPInstruction& opc);
+void andr(const UDSPInstruction& opc);
+void andc(const UDSPInstruction& opc);
+void orr(const UDSPInstruction& opc);
+void orc(const UDSPInstruction& opc);
+void orf(const UDSPInstruction& opc);
+void add(const UDSPInstruction& opc);
+void addp(const UDSPInstruction& opc);
+void cmpis(const UDSPInstruction& opc);
+void addpaxz(const UDSPInstruction& opc);
+void movpz(const UDSPInstruction& opc);
+void decm(const UDSPInstruction& opc);
+void dec(const UDSPInstruction& opc);
+void inc(const UDSPInstruction& opc);
+void incm(const UDSPInstruction& opc);
+void neg(const UDSPInstruction& opc);
+void addax(const UDSPInstruction& opc);
+void addr(const UDSPInstruction& opc);
+void subr(const UDSPInstruction& opc);
+void subp(const UDSPInstruction& opc);
+void subax(const UDSPInstruction& opc);
+void addis(const UDSPInstruction& opc);
+void addi(const UDSPInstruction& opc);
+void lsl16(const UDSPInstruction& opc);
+void madd(const UDSPInstruction& opc);
+void msub(const UDSPInstruction& opc);
+void lsr16(const UDSPInstruction& opc);
+void asr16(const UDSPInstruction& opc);
+void lsl(const UDSPInstruction& opc);
+void lsr(const UDSPInstruction& opc);
+void asl(const UDSPInstruction& opc);
+void asr(const UDSPInstruction& opc);
+void lsrn(const UDSPInstruction& opc);
+void asrn(const UDSPInstruction& opc);
+void dar(const UDSPInstruction& opc);
+void iar(const UDSPInstruction& opc);
+void sbclr(const UDSPInstruction& opc);
+void sbset(const UDSPInstruction& opc);
+void mov(const UDSPInstruction& opc);
+void movp(const UDSPInstruction& opc);
+void mul(const UDSPInstruction& opc);
+void mulac(const UDSPInstruction& opc);
+void mulmv(const UDSPInstruction& opc);
+void mulmvz(const UDSPInstruction& opc);
+void mulx(const UDSPInstruction& opc);
+void mulxac(const UDSPInstruction& opc);
+void mulxmv(const UDSPInstruction& opc);
+void mulxmvz(const UDSPInstruction& opc);
+void mulcmvz(const UDSPInstruction& opc);
+void mulcmv(const UDSPInstruction& opc);
+void movnp(const UDSPInstruction& opc);
+void sub(const UDSPInstruction& opc);
+void maddx(const UDSPInstruction& opc);
+void msubx(const UDSPInstruction& opc);
+void maddc(const UDSPInstruction& opc);
+void msubc(const UDSPInstruction& opc);
+void srs(const UDSPInstruction& opc);
+void lrs(const UDSPInstruction& opc);
+void nx(const UDSPInstruction& opc);
+void cmpi(const UDSPInstruction& opc);
+void rti(const UDSPInstruction& opc);
+void ilrr(const UDSPInstruction& opc);
+void ilrrd(const UDSPInstruction& opc);
+void ilrri(const UDSPInstruction& opc);
+void ilrrn(const UDSPInstruction& opc);
+void andcf(const UDSPInstruction& opc);
+void andf(const UDSPInstruction& opc);
+void xori(const UDSPInstruction& opc);
+void andi(const UDSPInstruction& opc);
+void ori(const UDSPInstruction& opc);
+
+// FIXME inside
+void srbith(const UDSPInstruction& opc);
+
+// END OF FIXMEs
+
+// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED
+void tstaxl(const UDSPInstruction& opc);
+// The mysterious a100
+
+// END OF UNIMPLEMENTED
+
+// Helpers
+inline void tsta(int reg);
+
+} // namespace
+
+#endif // _DSPINTERPRETER_H
diff --git a/Source/Core/DSPCore/Src/DSPJit.cpp b/Source/Core/DSPCore/Src/DSPJit.cpp
index cbf7d1ebeb..540380f6de 100644
--- a/Source/Core/DSPCore/Src/DSPJit.cpp
+++ b/Source/Core/DSPCore/Src/DSPJit.cpp
@@ -1,22 +1,22 @@
-// 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 "DSPJit.h"
-
-namespace DSPJit {
-
-};
+// 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 "DSPJit.h"
+
+namespace DSPJit {
+
+};
diff --git a/Source/Core/DSPCore/Src/DSPJit.h b/Source/Core/DSPCore/Src/DSPJit.h
index 32e34672e2..9f05faedf1 100644
--- a/Source/Core/DSPCore/Src/DSPJit.h
+++ b/Source/Core/DSPCore/Src/DSPJit.h
@@ -1,28 +1,28 @@
-// 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 _DSPJIT_H
-#define _DSPJIT_H
-
-namespace DSPJit {
-
-// TODO(XK): Fill
-
-
-} // namespace
-
-#endif // _DSPJIT_H
+// 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 _DSPJIT_H
+#define _DSPJIT_H
+
+namespace DSPJit {
+
+// TODO(XK): Fill
+
+
+} // namespace
+
+#endif // _DSPJIT_H
diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp
index 4913e0cc60..b9162de01a 100644
--- a/Source/Core/DSPCore/Src/DSPTables.cpp
+++ b/Source/Core/DSPCore/Src/DSPTables.cpp
@@ -1,583 +1,583 @@
-// 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/
-
-// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
-
-/* NOTES BY HERMES:
-
-LZ flag: original opcodes andf and andcf are swaped. Also "jzr" and "jnz" are swaped but now named 'jlz' and 'jlnz'
-As you can see it obtain the same result but now LZ=1 correctly
-
-Added conditional instructions:
-
-conditional names:
-
-NZ -> NOT ZERO
-Z -> ZERO
-
-NS -> NOT SIGN
-S -> SIGN
-
-LZ -> LOGIC ZERO (only used with andcf-andf instructions?)
-LNZ -> LOGIC NOT ZERO
-
-G -> GREATER
-LE-> LESS EQUAL
-
-GE-> GREATER EQUAL
-L -> LESS
-
-Examples:
-
-jnz, ifs, retlnz
-
-*/
-
-
-#include "Common.h"
-#include "DSPTables.h"
-
-#include "DSPInterpreter.h"
-#include "DSPJit.h"
-#include "DSPIntExtOps.h"
-
-void nop(const UDSPInstruction& opc)
-{
- // The real nop is 0. Anything else is bad.
- if (opc.hex)
- DSPInterpreter::unknown(opc);
-}
-
-// Unknown Ops
-// All AX games: a100
-// Zelda Four Swords: 02ca
-
-// TODO: Fill up the tables with the corresponding instructions
-const DSPOPCTemplate opcodes[] =
-{
- {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL},
-
- {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
-
- {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL},
-
- {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETL", 0x02d6, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETGE", 0x02d7, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
- {"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_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},
- {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFL", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFGE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
- {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // This is just nop
-
- {"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},
- {"JRS", 0x1701, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRL", 0x1706, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRGE", 0x1707, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
-
- {"CALLRNS", 0x1710, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRS", 0x1711, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRL", 0x1716, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRGE", 0x1717, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
- {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
-
- {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
- {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
-
- // actually, given the masks these should probably be 0x3f. need investigation.
- {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
- {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
-
- // discovered by ector!
- {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, nop, 1, 0, {}, NULL, NULL},
- {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, nop, 1, 0, {}, NULL, NULL},
-
- {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, nop, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, nop, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- {"SI", 0x1600, 0xff00, DSPInterpreter::si, nop, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, nop, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, NULL, NULL},
-
- {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
-
- {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
- {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
- {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
-
- {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, nop, 2, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
- {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // Hermes: ??? (has it commented out)
-
- {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // F|RES: missing S64
- {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
-
- {"ILRR", 0x0210, 0xfedc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"ILRRD", 0x0214, 0xfedc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, // Hermes doesn't list this
- {"ILRRI", 0x0218, 0xfedc, DSPInterpreter::ilrri, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
- {"ILRRN", 0x0222, 0xfedc, DSPInterpreter::ilrrn, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
-
- // load and store value pointed by indexing reg and increment; LRR/SRR variants
- {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
- {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
-
- {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
- {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
-
- // 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_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_ADDR_I, 2, 1, 0, 0xffff}}, 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
- // extended opcodes, note size of opcode will be set to 0
-
- {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"SET16", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"SET40", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
-
- {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
-
- {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- // Definitely not TSTAXL, it affects one of the accumulators. (a100 or a900, same op, one parameter).
- {"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- // This op does NOT exist, at least not under this name, in duddie's docs!
- {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0
- {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0
- {"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, },
-
- {"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, 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},
- {"MOVAX", 0x6800, 0xfcff, DSPInterpreter::movax, 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},
- {"MOVR", 0x6000, 0xf8ff, DSPInterpreter::movr, 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},
- {"MOVP", 0x6e00, 0xfeff, DSPInterpreter::movp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MOVPZ", 0xfe00, 0xfeff, DSPInterpreter::movpz, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"ADDPAXZ", 0xf800, 0xfcff, DSPInterpreter::addpaxz, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, //Think the args are wrong
- {"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"LSL16", 0xf000, 0xfeff, DSPInterpreter::lsl16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"LSR16", 0xf400, 0xfeff, DSPInterpreter::lsr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ASR16", 0x9100, 0xf7ff, DSPInterpreter::asr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"XORR", 0x3000, 0xfcff, DSPInterpreter::xorr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ANDR", 0x3400, 0xfcff, DSPInterpreter::andr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ORR", 0x3800, 0xfcff, DSPInterpreter::orr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"ANDC", 0x3C00, 0xfeff, DSPInterpreter::andc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
- {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
-
- {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-
- {"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_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_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},
- {"MSUB", 0xf600, 0xfeff, DSPInterpreter::msub , 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},
- {"MADDX", 0xe000, 0xfcff, DSPInterpreter::maddx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUBX", 0xe400, 0xfcff, DSPInterpreter::msubx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MADDC", 0xe800, 0xfcff, DSPInterpreter::maddc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
- {"MSUBC", 0xec00, 0xfcff, DSPInterpreter::msubc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
-};
-
-const DSPOPCTemplate cw =
- {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
-
-
-const DSPOPCTemplate opcodes_ext[] =
-{
- // FIXME: guessing this is cr need checking
- {"DR", 0x0004, 0x00fc, nop, /*DSPInterpreter::Ext::dr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"IR", 0x0008, 0x00fc, nop, /*DSPInterpreter::Ext::ir*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"NR", 0x000c, 0x00fc, nop, /*DSPInterpreter::Ext::nr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"MV", 0x0010, 0x00f0, nop, /*DSPInterpreter::Ext::mv*/ nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"S", 0x0020, 0x00e4, nop, /*DSPInterpreter::Ext::s*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
- {"SN", 0x0024, 0x00e4, nop, /*DSPInterpreter::Ext::sn*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
-
- {"L", 0x0040, 0x00c4, nop, /*DSPInterpreter::Ext::l*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LN", 0x0044, 0x00c4, nop, /*DSPInterpreter::Ext::ln*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"LS", 0x0080, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SL", 0x0082, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
- {"LSNM", 0x008c, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
- {"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
-
- /* FIXME: what are the LDX functions for? they have the same opcode as LD ones but different mask
- {"LDX", 0x00c0, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXN", 0x00c4, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXM", 0x00c8, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
- {"LDXNM", 0x00cc, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},*/
-
- {"LD", 0x00c0, 0x00cc, nop, /*DSPInterpreter::Ext::ld*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDN", 0x00c4, 0x00cc, nop, /*DSPInterpreter::Ext::ldn*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDM", 0x00c8, 0x00cc, nop, /*DSPInterpreter::Ext::ldm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
- {"LDNM", 0x00cc, 0x00cc, nop, /*DSPInterpreter::Ext::ldnm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
-
- {"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
-};
-
-const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
-const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
-
-const pdlabel_t pdlabels[] =
-{
- {0xffa0, "COEF_A1_0", "COEF_A1_0",},
- {0xffa1, "COEF_A2_0", "COEF_A2_0",},
- {0xffa2, "COEF_A1_1", "COEF_A1_1",},
- {0xffa3, "COEF_A2_1", "COEF_A2_1",},
- {0xffa4, "COEF_A1_2", "COEF_A1_2",},
- {0xffa5, "COEF_A2_2", "COEF_A2_2",},
- {0xffa6, "COEF_A1_3", "COEF_A1_3",},
- {0xffa7, "COEF_A2_3", "COEF_A2_3",},
- {0xffa8, "COEF_A1_4", "COEF_A1_4",},
- {0xffa9, "COEF_A2_4", "COEF_A2_4",},
- {0xffaa, "COEF_A1_5", "COEF_A1_5",},
- {0xffab, "COEF_A2_5", "COEF_A2_5",},
- {0xffac, "COEF_A1_6", "COEF_A1_6",},
- {0xffad, "COEF_A2_6", "COEF_A2_6",},
- {0xffae, "COEF_A1_7", "COEF_A1_7",},
- {0xffaf, "COEF_A2_7", "COEF_A2_7",},
-
- {0xffb0, "0xffb0", 0,},
- {0xffb1, "0xffb1", 0,},
- {0xffb2, "0xffb2", 0,},
- {0xffb3, "0xffb3", 0,},
- {0xffb4, "0xffb4", 0,},
- {0xffb5, "0xffb5", 0,},
- {0xffb6, "0xffb6", 0,},
- {0xffb7, "0xffb7", 0,},
- {0xffb8, "0xffb8", 0,},
- {0xffb9, "0xffb9", 0,},
- {0xffba, "0xffba", 0,},
- {0xffbb, "0xffbb", 0,},
- {0xffbc, "0xffbc", 0,},
- {0xffbd, "0xffbd", 0,},
- {0xffbe, "0xffbe", 0,},
- {0xffbf, "0xffbf", 0,},
-
- {0xffc0, "0xffc0", 0,},
- {0xffc1, "0xffc1", 0,},
- {0xffc2, "0xffc2", 0,},
- {0xffc3, "0xffc3", 0,},
- {0xffc4, "0xffc4", 0,},
- {0xffc5, "0xffc5", 0,},
- {0xffc6, "0xffc6", 0,},
- {0xffc7, "0xffc7", 0,},
- {0xffc8, "0xffc8", 0,},
- {0xffc9, "DSCR", "DSP DMA Control Reg",},
- {0xffca, "0xffca", 0,},
- {0xffcb, "DSBL", "DSP DMA Block Length",},
- {0xffcc, "0xffcc", 0,},
- {0xffcd, "DSPA", "DSP DMA DMEM Address",},
- {0xffce, "DSMAH", "DSP DMA Mem Address H",},
- {0xffcf, "DSMAL", "DSP DMA Mem Address L",},
-
- {0xffd0, "0xffd0",0,},
- {0xffd1, "SampleFormat", "SampleFormat",},
- {0xffd2, "0xffd2",0,},
- {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",},
- {0xffd4, "ACSAH", "Accelerator start address H",},
- {0xffd5, "ACSAL", "Accelerator start address L",},
- {0xffd6, "ACEAH", "Accelerator end address H",},
- {0xffd7, "ACEAL", "Accelerator end address L",},
- {0xffd8, "ACCAH", "Accelerator current address H",},
- {0xffd9, "ACCAL", "Accelerator current address L",},
- {0xffda, "pred_scale", "pred_scale",},
- {0xffdb, "yn1", "yn1",},
- {0xffdc, "yn2", "yn2",},
- {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",},
- {0xffde, "GAIN", "Gain",},
- {0xffdf, "0xffdf", 0,},
-
- {0xffe0, "0xffe0",0,},
- {0xffe1, "0xffe1",0,},
- {0xffe2, "0xffe2",0,},
- {0xffe3, "0xffe3",0,},
- {0xffe4, "0xffe4",0,},
- {0xffe5, "0xffe5",0,},
- {0xffe6, "0xffe6",0,},
- {0xffe7, "0xffe7",0,},
- {0xffe8, "0xffe8",0,},
- {0xffe9, "0xffe9",0,},
- {0xffea, "0xffea",0,},
- {0xffeb, "0xffeb",0,},
- {0xffec, "0xffec",0,},
- {0xffed, "0xffed",0,},
- {0xffee, "0xffee",0,},
- {0xffef, "AMDM", "ARAM DMA Request Mask",},
-
- {0xfff0, "0xfff0",0,},
- {0xfff1, "0xfff1",0,},
- {0xfff2, "0xfff2",0,},
- {0xfff3, "0xfff3",0,},
- {0xfff4, "0xfff4",0,},
- {0xfff5, "0xfff5",0,},
- {0xfff6, "0xfff6",0,},
- {0xfff7, "0xfff7",0,},
- {0xfff8, "0xfff8",0,},
- {0xfff9, "0xfff9",0,},
- {0xfffa, "0xfffa",0,},
- {0xfffb, "DIRQ", "DSP IRQ Request",},
- {0xfffc, "DMBH", "DSP Mailbox H",},
- {0xfffd, "DMBL", "DSP Mailbox L",},
- {0xfffe, "CMBH", "CPU Mailbox H",},
- {0xffff, "CMBL", "CPU Mailbox L",},
-};
-
-const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t);
-
-const pdlabel_t regnames[] =
-{
- {0x00, "AR0", "Addr Reg 00",},
- {0x01, "AR1", "Addr Reg 01",},
- {0x02, "AR2", "Addr Reg 02",},
- {0x03, "AR3", "Addr Reg 03",},
- {0x04, "IX0", "Index Reg 0",},
- {0x05, "IX1", "Index Reg 1",},
- {0x06, "IX2", "Index Reg 2",},
- {0x07, "IX3", "Index Reg 3",},
- {0x08, "WR0", "Wrapping Register 0",},
- {0x09, "WR1", "Wrapping Register 1",},
- {0x0a, "WR2", "Wrapping Register 2",},
- {0x0b, "WR3", "Wrapping Register 3",},
- {0x0c, "ST0", "Call stack",},
- {0x0d, "ST1", "Data stack",},
- {0x0e, "ST2", "Loop addr stack",},
- {0x0f, "ST3", "Loop counter",},
- {0x10, "AC0.H", "Accu High 0",},
- {0x11, "AC1.H", "Accu High 1",},
- {0x12, "CR", "Config Register",},
- {0x13, "SR", "Special Register",},
- {0x14, "PROD.L", "Prod L",},
- {0x15, "PROD.M1", "Prod M1",},
- {0x16, "PROD.H", "Prod H",},
- {0x17, "PROD.M2", "Prod M2",},
- {0x18, "AX0.L", "Extra Accu L 0",},
- {0x19, "AX1.L", "Extra Accu L 1",},
- {0x1a, "AX0.H", "Extra Accu H 0",},
- {0x1b, "AX1.H", "Extra Accu H 1",},
- {0x1c, "AC0.L", "Accu Low 0",},
- {0x1d, "AC1.L", "Accu Low 1",},
- {0x1e, "AC0.M", "Accu Mid 0",},
- {0x1f, "AC1.M", "Accu Mid 1",},
-
- // To resolve combined register names.
- {0x20, "ACC0", "Accu Full 0",},
- {0x21, "ACC1", "Accu Full 1",},
- {0x22, "AX0", "Extra Accu 0",},
- {0x23, "AX1", "Extra Accu 1",},
-};
-
-u8 opSize[OPTABLE_SIZE];
-dspInstFunc opTable[OPTABLE_SIZE];
-dspInstFunc prologueTable[OPTABLE_SIZE];
-dspInstFunc epilogueTable[OPTABLE_SIZE];
-
-const char* pdname(u16 val)
-{
- static char tmpstr[12]; // nasty
-
- for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++)
- {
- if (pdlabels[i].addr == val)
- return pdlabels[i].name;
- }
-
- sprintf(tmpstr, "0x%04x", val);
- return tmpstr;
-}
-
-const char *pdregname(int val)
-{
- return regnames[val].name;
-}
-
-const char *pdregnamelong(int val)
-{
- return regnames[val].description;
-}
-
-const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
-{
- for (int i = 0; i < opcodes_size; i++)
- {
- u16 mask = opcodes[i].opcode_mask;
- if (opcodes[i].size & P_EXT) {
- // Ignore extension bits.
- mask &= 0xFF00;
- }
- if ((mask & inst.hex) == opcodes[i].opcode)
- return &opcodes[i];
- }
- return NULL;
-}
-
-
-// This function could use the above GetOpTemplate, but then we'd lose the
-// nice property that it catches colliding op masks.
-void InitInstructionTable()
-{
- for (int i = 0; i < OPTABLE_SIZE; i++)
- {
- opTable[i] = DSPInterpreter::unknown;
- prologueTable[i] = NULL;
- epilogueTable[i] = NULL;
- opSize[i] = 0;
- }
-
- for (int i = 0; i < OPTABLE_SIZE; i++)
- {
- for (int j = 0; j < opcodes_size; j++)
- {
- u16 mask = opcodes[j].opcode_mask;
- if (opcodes[j].size & P_EXT) {
- // Ignore extension bits.
- mask &= 0xFF00;
- }
- if ((mask & i) == opcodes[j].opcode)
- {
- if (opTable[i] == DSPInterpreter::unknown)
- {
- opTable[i] = opcodes[j].interpFunc;
- opSize[i] = opcodes[j].size & 3;
- prologueTable[i] = opcodes[j].prologue;
- epilogueTable[i] = opcodes[j].epilogue;
- }
- else
- {
- ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name);
- }
- }
- }
- }
-}
+// 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/
+
+// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
+
+/* NOTES BY HERMES:
+
+LZ flag: original opcodes andf and andcf are swaped. Also "jzr" and "jnz" are swaped but now named 'jlz' and 'jlnz'
+As you can see it obtain the same result but now LZ=1 correctly
+
+Added conditional instructions:
+
+conditional names:
+
+NZ -> NOT ZERO
+Z -> ZERO
+
+NS -> NOT SIGN
+S -> SIGN
+
+LZ -> LOGIC ZERO (only used with andcf-andf instructions?)
+LNZ -> LOGIC NOT ZERO
+
+G -> GREATER
+LE-> LESS EQUAL
+
+GE-> GREATER EQUAL
+L -> LESS
+
+Examples:
+
+jnz, ifs, retlnz
+
+*/
+
+
+#include "Common.h"
+#include "DSPTables.h"
+
+#include "DSPInterpreter.h"
+#include "DSPJit.h"
+#include "DSPIntExtOps.h"
+
+void nop(const UDSPInstruction& opc)
+{
+ // The real nop is 0. Anything else is bad.
+ if (opc.hex)
+ DSPInterpreter::unknown(opc);
+}
+
+// Unknown Ops
+// All AX games: a100
+// Zelda Four Swords: 02ca
+
+// TODO: Fill up the tables with the corresponding instructions
+const DSPOPCTemplate opcodes[] =
+{
+ {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, NULL, NULL},
+
+ {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
+ {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL},
+
+ {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, NULL, NULL},
+
+ {"RETNS", 0x02d0, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETS", 0x02d1, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETL", 0x02d6, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETGE", 0x02d7, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
+ {"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_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},
+ {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFL", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFGE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
+ {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // This is just nop
+
+ {"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},
+ {"JRS", 0x1701, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRL", 0x1706, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRGE", 0x1707, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+
+ {"CALLRNS", 0x1710, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRS", 0x1711, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRL", 0x1716, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRGE", 0x1717, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRLNZ",0x171c, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+ {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
+
+ {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
+ {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
+
+ // actually, given the masks these should probably be 0x3f. need investigation.
+ {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
+ {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
+ {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
+ {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
+
+ // discovered by ector!
+ {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, nop, 1, 0, {}, NULL, NULL},
+ {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, nop, 1, 0, {}, NULL, NULL},
+
+ {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, nop, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
+
+ {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, nop, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
+
+ {"SI", 0x1600, 0xff00, DSPInterpreter::si, nop, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
+
+ {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, NULL, NULL},
+ {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, nop, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, NULL, NULL},
+
+ {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, nop, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
+
+ {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
+ {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
+ {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
+ {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
+
+ {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, nop, 2, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
+
+ {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
+ {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // Hermes: ??? (has it commented out)
+
+ {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL}, // F|RES: missing S64
+ {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
+
+ {"ILRR", 0x0210, 0xfedc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
+ {"ILRRD", 0x0214, 0xfedc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL}, // Hermes doesn't list this
+ {"ILRRI", 0x0218, 0xfedc, DSPInterpreter::ilrri, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
+ {"ILRRN", 0x0222, 0xfedc, DSPInterpreter::ilrrn, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL},
+
+ // load and store value pointed by indexing reg and increment; LRR/SRR variants
+ {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
+ {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
+ {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
+ {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, NULL, NULL},
+
+ {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
+ {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
+ {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
+ {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, nop, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
+
+ // 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_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_ADDR_I, 2, 1, 0, 0xffff}}, 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
+ // extended opcodes, note size of opcode will be set to 0
+
+ {"NX", 0x8000, 0xf700, DSPInterpreter::nx, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"M2", 0x8a00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"M0", 0x8b00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"CLR15", 0x8c00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"SET15", 0x8d00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"SET16", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"SET40", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+
+ {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+
+ {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ // Definitely not TSTAXL, it affects one of the accumulators. (a100 or a900, same op, one parameter).
+ {"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"TSTAXH", 0x8600, 0xfeff, DSPInterpreter::tstaxh, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ // This op does NOT exist, at least not under this name, in duddie's docs!
+ {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0
+ {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0
+ {"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, },
+
+ {"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, 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},
+ {"MOVAX", 0x6800, 0xfcff, DSPInterpreter::movax, 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},
+ {"MOVR", 0x6000, 0xf8ff, DSPInterpreter::movr, 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},
+ {"MOVP", 0x6e00, 0xfeff, DSPInterpreter::movp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MOVPZ", 0xfe00, 0xfeff, DSPInterpreter::movpz, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"ADDPAXZ", 0xf800, 0xfcff, DSPInterpreter::addpaxz, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, //Think the args are wrong
+ {"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"LSL16", 0xf000, 0xfeff, DSPInterpreter::lsl16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"LSR16", 0xf400, 0xfeff, DSPInterpreter::lsr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"ASR16", 0x9100, 0xf7ff, DSPInterpreter::asr16, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"XORR", 0x3000, 0xfcff, DSPInterpreter::xorr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"ANDR", 0x3400, 0xfcff, DSPInterpreter::andr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"ORR", 0x3800, 0xfcff, DSPInterpreter::orr, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"ANDC", 0x3C00, 0xfeff, DSPInterpreter::andc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
+ {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
+
+ {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+
+ {"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_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_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},
+ {"MSUB", 0xf600, 0xfeff, DSPInterpreter::msub , 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},
+ {"MADDX", 0xe000, 0xfcff, DSPInterpreter::maddx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MSUBX", 0xe400, 0xfcff, DSPInterpreter::msubx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MADDC", 0xe800, 0xfcff, DSPInterpreter::maddc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+ {"MSUBC", 0xec00, 0xfcff, DSPInterpreter::msubc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+};
+
+const DSPOPCTemplate cw =
+ {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
+
+
+const DSPOPCTemplate opcodes_ext[] =
+{
+ // FIXME: guessing this is cr need checking
+ {"DR", 0x0004, 0x00fc, nop, /*DSPInterpreter::Ext::dr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"IR", 0x0008, 0x00fc, nop, /*DSPInterpreter::Ext::ir*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"NR", 0x000c, 0x00fc, nop, /*DSPInterpreter::Ext::nr*/ nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"MV", 0x0010, 0x00f0, nop, /*DSPInterpreter::Ext::mv*/ nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,},
+
+ {"S", 0x0020, 0x00e4, nop, /*DSPInterpreter::Ext::s*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
+ {"SN", 0x0024, 0x00e4, nop, /*DSPInterpreter::Ext::sn*/ nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
+
+ {"L", 0x0040, 0x00c4, nop, /*DSPInterpreter::Ext::l*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"LN", 0x0044, 0x00c4, nop, /*DSPInterpreter::Ext::ln*/ nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+
+ {"LS", 0x0080, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
+ {"SL", 0x0082, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
+ {"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
+ {"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
+ {"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
+ {"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
+ {"LSNM", 0x008c, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
+ {"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
+
+ /* FIXME: what are the LDX functions for? they have the same opcode as LD ones but different mask
+ {"LDX", 0x00c0, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
+ {"LDXN", 0x00c4, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
+ {"LDXM", 0x00c8, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},
+ {"LDXNM", 0x00cc, 0x00cf, nop, nop, 1, 3, {{P_REG18, 1, 0, 4, 0x0010}, {P_REG1A, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, NULL, NULL,},*/
+
+ {"LD", 0x00c0, 0x00cc, nop, /*DSPInterpreter::Ext::ld*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"LDN", 0x00c4, 0x00cc, nop, /*DSPInterpreter::Ext::ldn*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"LDM", 0x00c8, 0x00cc, nop, /*DSPInterpreter::Ext::ldm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+ {"LDNM", 0x00cc, 0x00cc, nop, /*DSPInterpreter::Ext::ldnm*/ nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
+
+ {"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
+};
+
+const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
+const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
+
+const pdlabel_t pdlabels[] =
+{
+ {0xffa0, "COEF_A1_0", "COEF_A1_0",},
+ {0xffa1, "COEF_A2_0", "COEF_A2_0",},
+ {0xffa2, "COEF_A1_1", "COEF_A1_1",},
+ {0xffa3, "COEF_A2_1", "COEF_A2_1",},
+ {0xffa4, "COEF_A1_2", "COEF_A1_2",},
+ {0xffa5, "COEF_A2_2", "COEF_A2_2",},
+ {0xffa6, "COEF_A1_3", "COEF_A1_3",},
+ {0xffa7, "COEF_A2_3", "COEF_A2_3",},
+ {0xffa8, "COEF_A1_4", "COEF_A1_4",},
+ {0xffa9, "COEF_A2_4", "COEF_A2_4",},
+ {0xffaa, "COEF_A1_5", "COEF_A1_5",},
+ {0xffab, "COEF_A2_5", "COEF_A2_5",},
+ {0xffac, "COEF_A1_6", "COEF_A1_6",},
+ {0xffad, "COEF_A2_6", "COEF_A2_6",},
+ {0xffae, "COEF_A1_7", "COEF_A1_7",},
+ {0xffaf, "COEF_A2_7", "COEF_A2_7",},
+
+ {0xffb0, "0xffb0", 0,},
+ {0xffb1, "0xffb1", 0,},
+ {0xffb2, "0xffb2", 0,},
+ {0xffb3, "0xffb3", 0,},
+ {0xffb4, "0xffb4", 0,},
+ {0xffb5, "0xffb5", 0,},
+ {0xffb6, "0xffb6", 0,},
+ {0xffb7, "0xffb7", 0,},
+ {0xffb8, "0xffb8", 0,},
+ {0xffb9, "0xffb9", 0,},
+ {0xffba, "0xffba", 0,},
+ {0xffbb, "0xffbb", 0,},
+ {0xffbc, "0xffbc", 0,},
+ {0xffbd, "0xffbd", 0,},
+ {0xffbe, "0xffbe", 0,},
+ {0xffbf, "0xffbf", 0,},
+
+ {0xffc0, "0xffc0", 0,},
+ {0xffc1, "0xffc1", 0,},
+ {0xffc2, "0xffc2", 0,},
+ {0xffc3, "0xffc3", 0,},
+ {0xffc4, "0xffc4", 0,},
+ {0xffc5, "0xffc5", 0,},
+ {0xffc6, "0xffc6", 0,},
+ {0xffc7, "0xffc7", 0,},
+ {0xffc8, "0xffc8", 0,},
+ {0xffc9, "DSCR", "DSP DMA Control Reg",},
+ {0xffca, "0xffca", 0,},
+ {0xffcb, "DSBL", "DSP DMA Block Length",},
+ {0xffcc, "0xffcc", 0,},
+ {0xffcd, "DSPA", "DSP DMA DMEM Address",},
+ {0xffce, "DSMAH", "DSP DMA Mem Address H",},
+ {0xffcf, "DSMAL", "DSP DMA Mem Address L",},
+
+ {0xffd0, "0xffd0",0,},
+ {0xffd1, "SampleFormat", "SampleFormat",},
+ {0xffd2, "0xffd2",0,},
+ {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",},
+ {0xffd4, "ACSAH", "Accelerator start address H",},
+ {0xffd5, "ACSAL", "Accelerator start address L",},
+ {0xffd6, "ACEAH", "Accelerator end address H",},
+ {0xffd7, "ACEAL", "Accelerator end address L",},
+ {0xffd8, "ACCAH", "Accelerator current address H",},
+ {0xffd9, "ACCAL", "Accelerator current address L",},
+ {0xffda, "pred_scale", "pred_scale",},
+ {0xffdb, "yn1", "yn1",},
+ {0xffdc, "yn2", "yn2",},
+ {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",},
+ {0xffde, "GAIN", "Gain",},
+ {0xffdf, "0xffdf", 0,},
+
+ {0xffe0, "0xffe0",0,},
+ {0xffe1, "0xffe1",0,},
+ {0xffe2, "0xffe2",0,},
+ {0xffe3, "0xffe3",0,},
+ {0xffe4, "0xffe4",0,},
+ {0xffe5, "0xffe5",0,},
+ {0xffe6, "0xffe6",0,},
+ {0xffe7, "0xffe7",0,},
+ {0xffe8, "0xffe8",0,},
+ {0xffe9, "0xffe9",0,},
+ {0xffea, "0xffea",0,},
+ {0xffeb, "0xffeb",0,},
+ {0xffec, "0xffec",0,},
+ {0xffed, "0xffed",0,},
+ {0xffee, "0xffee",0,},
+ {0xffef, "AMDM", "ARAM DMA Request Mask",},
+
+ {0xfff0, "0xfff0",0,},
+ {0xfff1, "0xfff1",0,},
+ {0xfff2, "0xfff2",0,},
+ {0xfff3, "0xfff3",0,},
+ {0xfff4, "0xfff4",0,},
+ {0xfff5, "0xfff5",0,},
+ {0xfff6, "0xfff6",0,},
+ {0xfff7, "0xfff7",0,},
+ {0xfff8, "0xfff8",0,},
+ {0xfff9, "0xfff9",0,},
+ {0xfffa, "0xfffa",0,},
+ {0xfffb, "DIRQ", "DSP IRQ Request",},
+ {0xfffc, "DMBH", "DSP Mailbox H",},
+ {0xfffd, "DMBL", "DSP Mailbox L",},
+ {0xfffe, "CMBH", "CPU Mailbox H",},
+ {0xffff, "CMBL", "CPU Mailbox L",},
+};
+
+const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t);
+
+const pdlabel_t regnames[] =
+{
+ {0x00, "AR0", "Addr Reg 00",},
+ {0x01, "AR1", "Addr Reg 01",},
+ {0x02, "AR2", "Addr Reg 02",},
+ {0x03, "AR3", "Addr Reg 03",},
+ {0x04, "IX0", "Index Reg 0",},
+ {0x05, "IX1", "Index Reg 1",},
+ {0x06, "IX2", "Index Reg 2",},
+ {0x07, "IX3", "Index Reg 3",},
+ {0x08, "WR0", "Wrapping Register 0",},
+ {0x09, "WR1", "Wrapping Register 1",},
+ {0x0a, "WR2", "Wrapping Register 2",},
+ {0x0b, "WR3", "Wrapping Register 3",},
+ {0x0c, "ST0", "Call stack",},
+ {0x0d, "ST1", "Data stack",},
+ {0x0e, "ST2", "Loop addr stack",},
+ {0x0f, "ST3", "Loop counter",},
+ {0x10, "AC0.H", "Accu High 0",},
+ {0x11, "AC1.H", "Accu High 1",},
+ {0x12, "CR", "Config Register",},
+ {0x13, "SR", "Special Register",},
+ {0x14, "PROD.L", "Prod L",},
+ {0x15, "PROD.M1", "Prod M1",},
+ {0x16, "PROD.H", "Prod H",},
+ {0x17, "PROD.M2", "Prod M2",},
+ {0x18, "AX0.L", "Extra Accu L 0",},
+ {0x19, "AX1.L", "Extra Accu L 1",},
+ {0x1a, "AX0.H", "Extra Accu H 0",},
+ {0x1b, "AX1.H", "Extra Accu H 1",},
+ {0x1c, "AC0.L", "Accu Low 0",},
+ {0x1d, "AC1.L", "Accu Low 1",},
+ {0x1e, "AC0.M", "Accu Mid 0",},
+ {0x1f, "AC1.M", "Accu Mid 1",},
+
+ // To resolve combined register names.
+ {0x20, "ACC0", "Accu Full 0",},
+ {0x21, "ACC1", "Accu Full 1",},
+ {0x22, "AX0", "Extra Accu 0",},
+ {0x23, "AX1", "Extra Accu 1",},
+};
+
+u8 opSize[OPTABLE_SIZE];
+dspInstFunc opTable[OPTABLE_SIZE];
+dspInstFunc prologueTable[OPTABLE_SIZE];
+dspInstFunc epilogueTable[OPTABLE_SIZE];
+
+const char* pdname(u16 val)
+{
+ static char tmpstr[12]; // nasty
+
+ for (int i = 0; i < (int)(sizeof(pdlabels) / sizeof(pdlabel_t)); i++)
+ {
+ if (pdlabels[i].addr == val)
+ return pdlabels[i].name;
+ }
+
+ sprintf(tmpstr, "0x%04x", val);
+ return tmpstr;
+}
+
+const char *pdregname(int val)
+{
+ return regnames[val].name;
+}
+
+const char *pdregnamelong(int val)
+{
+ return regnames[val].description;
+}
+
+const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
+{
+ for (int i = 0; i < opcodes_size; i++)
+ {
+ u16 mask = opcodes[i].opcode_mask;
+ if (opcodes[i].size & P_EXT) {
+ // Ignore extension bits.
+ mask &= 0xFF00;
+ }
+ if ((mask & inst.hex) == opcodes[i].opcode)
+ return &opcodes[i];
+ }
+ return NULL;
+}
+
+
+// This function could use the above GetOpTemplate, but then we'd lose the
+// nice property that it catches colliding op masks.
+void InitInstructionTable()
+{
+ for (int i = 0; i < OPTABLE_SIZE; i++)
+ {
+ opTable[i] = DSPInterpreter::unknown;
+ prologueTable[i] = NULL;
+ epilogueTable[i] = NULL;
+ opSize[i] = 0;
+ }
+
+ for (int i = 0; i < OPTABLE_SIZE; i++)
+ {
+ for (int j = 0; j < opcodes_size; j++)
+ {
+ u16 mask = opcodes[j].opcode_mask;
+ if (opcodes[j].size & P_EXT) {
+ // Ignore extension bits.
+ mask &= 0xFF00;
+ }
+ if ((mask & i) == opcodes[j].opcode)
+ {
+ if (opTable[i] == DSPInterpreter::unknown)
+ {
+ opTable[i] = opcodes[j].interpFunc;
+ opSize[i] = opcodes[j].size & 3;
+ prologueTable[i] = opcodes[j].prologue;
+ epilogueTable[i] = opcodes[j].epilogue;
+ }
+ else
+ {
+ ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcodes[j].name);
+ }
+ }
+ }
+ }
+}
diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h
index 8e0f66207c..a56a112b72 100644
--- a/Source/Core/DSPCore/Src/DSPTables.h
+++ b/Source/Core/DSPCore/Src/DSPTables.h
@@ -1,168 +1,168 @@
-// 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/
-
-// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
-
-#ifndef _DSPTABLES_H
-#define _DSPTABLES_H
-
-#include "Common.h"
-
-// 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.
-// For the reg ones, the value >> 8 is the base register.
-// & 0x80 means it's a "D".
-
-enum partype_t
-{
- P_NONE = 0x0000,
- 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,
- P_REG18 = P_REG | 0x1800,
- P_REGM18 = P_REG | 0x1810, // used in multiply instructions
- P_REG19 = P_REG | 0x1900,
- P_REGM19 = P_REG | 0x1910, // used in multiply instructions
- P_REG1A = P_REG | 0x1a80,
- P_REG1C = P_REG | 0x1c00,
-// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value)
- P_ACC_D = P_REG | 0x1c80,
- P_ACCL = P_REG | 0x1c00, // used for low part of accum
- P_ACCM = P_REG | 0x1e00, // used for mid part of accum
- // The following are not in gcdsptool
- P_ACCM_D = P_REG | 0x1e80,
- P_ACC = P_REG | 0x2000, // used for full accum.
- P_AX = P_REG | 0x2200,
- P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
- P_REF = P_REG | 0x4000,
- P_PRG = P_REF | P_REG,
-
- // The following seem like junk:
- // P_REG10 = P_REG | 0x1000,
- // P_AX_D = P_REG | 0x2280,
-};
-
-#define P_EXT 0x80
-
-#define OPTABLE_SIZE 65536
-
-union UDSPInstruction
-{
- u16 hex;
-
- UDSPInstruction(u16 _hex) { hex = _hex; }
- UDSPInstruction() { hex = 0; }
-
- struct
- {
- signed shift : 6;
- unsigned negating : 1;
- unsigned arithmetic : 1;
- unsigned areg : 1;
- unsigned op : 7;
- };
- struct
- {
- unsigned ushift : 6;
- };
-
- // TODO: Figure out more instruction structures (add structs here)
-};
-
-typedef void (*dspInstFunc)(const UDSPInstruction&);
-
-struct param2_t
-{
- partype_t type;
- u8 size;
- u8 loc;
- s8 lshift;
- u16 mask;
-};
-
-typedef struct
-{
- const char *name;
- u16 opcode;
- u16 opcode_mask;
-
- dspInstFunc interpFunc;
- dspInstFunc jitFunc;
-
- u8 size;
- u8 param_count;
- param2_t params[8];
- dspInstFunc prologue;
- dspInstFunc epilogue;
-} DSPOPCTemplate;
-
-typedef DSPOPCTemplate opc_t;
-
-// Opcodes
-extern const DSPOPCTemplate opcodes[];
-extern const int opcodes_size;
-extern const DSPOPCTemplate opcodes_ext[];
-extern const int opcodes_ext_size;
-extern u8 opSize[OPTABLE_SIZE];
-extern const DSPOPCTemplate cw;
-
-extern dspInstFunc opTable[];
-extern dspInstFunc prologueTable[OPTABLE_SIZE];
-extern dspInstFunc epilogueTable[OPTABLE_SIZE];
-
-// Predefined labels
-struct pdlabel_t
-{
- u16 addr;
- const char* name;
- const char* description;
-};
-
-extern const pdlabel_t regnames[];
-extern const pdlabel_t pdlabels[];
-extern const u32 pdlabels_size;
-
-const char *pdname(u16 val);
-const char *pdregname(int val);
-const char *pdregnamelong(int val);
-
-void InitInstructionTable();
-
-inline void ExecuteInstruction(const UDSPInstruction& inst)
-{
- // TODO: Move the prologuetable calls into the relevant instructions themselves.
- // Better not do things like this until things work correctly though.
- if (prologueTable[inst.hex])
- prologueTable[inst.hex](inst);
- opTable[inst.hex](inst);
- if (epilogueTable[inst.hex])
- epilogueTable[inst.hex](inst);
-}
-
-// This one's pretty slow, try to use it only at init or seldomly.
-// returns NULL if no matching instruction.
-const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst);
-
-#endif // _DSPTABLES_H
+// 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/
+
+// Additional copyrights go to Duddie (c) 2005 (duddie@walla.com)
+
+#ifndef _DSPTABLES_H
+#define _DSPTABLES_H
+
+#include "Common.h"
+
+// 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.
+// For the reg ones, the value >> 8 is the base register.
+// & 0x80 means it's a "D".
+
+enum partype_t
+{
+ P_NONE = 0x0000,
+ 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,
+ P_REG18 = P_REG | 0x1800,
+ P_REGM18 = P_REG | 0x1810, // used in multiply instructions
+ P_REG19 = P_REG | 0x1900,
+ P_REGM19 = P_REG | 0x1910, // used in multiply instructions
+ P_REG1A = P_REG | 0x1a80,
+ P_REG1C = P_REG | 0x1c00,
+// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value)
+ P_ACC_D = P_REG | 0x1c80,
+ P_ACCL = P_REG | 0x1c00, // used for low part of accum
+ P_ACCM = P_REG | 0x1e00, // used for mid part of accum
+ // The following are not in gcdsptool
+ P_ACCM_D = P_REG | 0x1e80,
+ P_ACC = P_REG | 0x2000, // used for full accum.
+ P_AX = P_REG | 0x2200,
+ P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
+ P_REF = P_REG | 0x4000,
+ P_PRG = P_REF | P_REG,
+
+ // The following seem like junk:
+ // P_REG10 = P_REG | 0x1000,
+ // P_AX_D = P_REG | 0x2280,
+};
+
+#define P_EXT 0x80
+
+#define OPTABLE_SIZE 65536
+
+union UDSPInstruction
+{
+ u16 hex;
+
+ UDSPInstruction(u16 _hex) { hex = _hex; }
+ UDSPInstruction() { hex = 0; }
+
+ struct
+ {
+ signed shift : 6;
+ unsigned negating : 1;
+ unsigned arithmetic : 1;
+ unsigned areg : 1;
+ unsigned op : 7;
+ };
+ struct
+ {
+ unsigned ushift : 6;
+ };
+
+ // TODO: Figure out more instruction structures (add structs here)
+};
+
+typedef void (*dspInstFunc)(const UDSPInstruction&);
+
+struct param2_t
+{
+ partype_t type;
+ u8 size;
+ u8 loc;
+ s8 lshift;
+ u16 mask;
+};
+
+typedef struct
+{
+ const char *name;
+ u16 opcode;
+ u16 opcode_mask;
+
+ dspInstFunc interpFunc;
+ dspInstFunc jitFunc;
+
+ u8 size;
+ u8 param_count;
+ param2_t params[8];
+ dspInstFunc prologue;
+ dspInstFunc epilogue;
+} DSPOPCTemplate;
+
+typedef DSPOPCTemplate opc_t;
+
+// Opcodes
+extern const DSPOPCTemplate opcodes[];
+extern const int opcodes_size;
+extern const DSPOPCTemplate opcodes_ext[];
+extern const int opcodes_ext_size;
+extern u8 opSize[OPTABLE_SIZE];
+extern const DSPOPCTemplate cw;
+
+extern dspInstFunc opTable[];
+extern dspInstFunc prologueTable[OPTABLE_SIZE];
+extern dspInstFunc epilogueTable[OPTABLE_SIZE];
+
+// Predefined labels
+struct pdlabel_t
+{
+ u16 addr;
+ const char* name;
+ const char* description;
+};
+
+extern const pdlabel_t regnames[];
+extern const pdlabel_t pdlabels[];
+extern const u32 pdlabels_size;
+
+const char *pdname(u16 val);
+const char *pdregname(int val);
+const char *pdregnamelong(int val);
+
+void InitInstructionTable();
+
+inline void ExecuteInstruction(const UDSPInstruction& inst)
+{
+ // TODO: Move the prologuetable calls into the relevant instructions themselves.
+ // Better not do things like this until things work correctly though.
+ if (prologueTable[inst.hex])
+ prologueTable[inst.hex](inst);
+ opTable[inst.hex](inst);
+ if (epilogueTable[inst.hex])
+ epilogueTable[inst.hex](inst);
+}
+
+// This one's pretty slow, try to use it only at init or seldomly.
+// returns NULL if no matching instruction.
+const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst);
+
+#endif // _DSPTABLES_H
diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp
index 83b7791516..45b16ddf16 100644
--- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp
+++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp
@@ -1,734 +1,734 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-// Arithmetic and accumulator control.
-
-namespace DSPInterpreter {
-
-// CLR $acR
-// 1000 r001 xxxx xxxx
-// Clears accumulator $acR
-void clr(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 11) & 0x1;
-
- dsp_set_long_acc(reg, 0);
-
- Update_SR_Register64((s64)0); // really?
-}
-
-// CLRL $acR.l
-// 1111 110r xxxx xxxx
-// Clears $acR.l - low 16 bits of accumulator $acR.
-void clrl(const UDSPInstruction& opc)
-{
- u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1);
- g_dsp.r[reg] = 0;
-
- // Should this be 64bit?
- // nakee: it says the whole reg in duddie's doc sounds weird
- Update_SR_Register64((s64)reg);
-}
-
-
-// ADDAXL $acD, $axS.l
-// 0111 00sd xxxx xxxx
-// Adds secondary accumulator $axS.l to accumulator register $acD.
-void addaxl(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(dreg);
- s64 acx = dsp_get_ax_l(sreg);
-
- acc += acx;
-
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// TSTAXH $axR.h
-// 1000 011r xxxx xxxx
-// Test high part of secondary accumulator $axR.h.
-void tstaxh(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 8) & 0x1;
- s16 val = dsp_get_ax_h(reg);
-
- Update_SR_Register16(val);
-}
-
-// SUB $acD, $ac(1-D)
-// 0101 110d xxxx xxxx
-// Subtracts accumulator $ac(1-D) from accumulator register $acD.
-void sub(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
- s64 acc1 = dsp_get_long_acc(D);
- s64 acc2 = dsp_get_long_acc(1 - D);
-
- acc1 -= acc2;
-
- dsp_set_long_acc(D, acc1);
-
- Update_SR_Register64(acc1);
-}
-
-// MOVR $acD, $axS.R
-// 0110 0srd xxxx xxxx
-// Moves register $axS.R (sign extended) to middle accumulator $acD.hm.
-// Sets $acD.l to 0.
-// TODO: Check what happens to acD.h.
-void movr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 acc = (s16)g_dsp.r[sreg];
- acc <<= 16;
- acc &= ~0xffff;
-
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOVAX $acD, $axS
-// 0110 10sd xxxx xxxx
-// Moves secondary accumulator $axS to accumulator $axD.
-void movax(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 acx = dsp_get_long_acx(sreg);
- dsp_set_long_acc(dreg, acx);
-
- Update_SR_Register64(acx);
-}
-
-// XORR $acD.m, $axS.h
-// 0011 00sd xxxx xxxx
-// Logic XOR (exclusive or) middle part of accumulator $acD.m with
-// high part of secondary accumulator $axS.h.
-void xorr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
- Update_SR_Register64(acc);
-}
-
-// ANDR $acD.m, $axS.h
-// 0011 01sd xxxx xxxx
-// Logic AND middle part of accumulator $acD.m with high part of
-// secondary accumulator $axS.h.
-void andr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
-
- Update_SR_Register64(acc);
-}
-
-// ORR $acD.m, $axS.h
-// 0011 10sd xxxx xxxx
-// Logic OR middle part of accumulator $acD.m with high part of
-// secondary accumulator $axS.h.
-void orr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg];
-
- s64 acc = dsp_get_long_acc(dreg);
-
- Update_SR_Register64(acc);
-}
-
-// ANDC $acD.m, $ac(1-D).m
-// 0011 110d xxxx xxxx
-// Logic AND middle part of accumulator $acD.m with middle part of
-// accumulator $ax(1-D).m.s
-void andc(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
-
- u16 ac1 = dsp_get_acc_m(D);
- u16 ac2 = dsp_get_acc_m(1 - D);
-
- dsp_set_long_acc(D, ac1 & ac2);
-
- Update_SR_Register64(dsp_get_long_acc(D));
-}
-
-// ORC $acD.m, $ac(1-D).m
-// 0011 111d xxxx xxxx
-// Logic OR middle part of accumulator $acD.m with middle part of
-// accumulator $ax(1-D).m.
-void orc(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
-
- u16 ac1 = dsp_get_acc_m(D);
- u16 ac2 = dsp_get_acc_m(1 - D);
-
- dsp_set_long_acc(D, ac1 | ac2);
-
- Update_SR_Register64(dsp_get_long_acc(D));
-}
-
-void orf(const UDSPInstruction& opc)
-{
- ERROR_LOG(DSPLLE, "orf not implemented");
-}
-
-// Hermes switched andf and andcf, so check to make sure they are still correct
-// ANDCF $acD.m, #I
-// 0000 001r 1100 0000
-// iiii iiii iiii iiii
-// Set logic zero (LZ) flag in status register $sr if result of logic AND of
-// accumulator mid part $acD.m with immediate value I is equal I.
-void andcf(const UDSPInstruction& opc)
-{
- u8 reg = (opc.hex >> 8) & 0x1;
- u16 imm = dsp_fetch_code();
- u16 val = dsp_get_acc_m(reg);
-
- Update_SR_LZ(((val & imm) == imm) ? 0 : 1);
-}
-
-// Hermes switched andf and andcf, so check to make sure they are still correct
-
-// ANDF $acD.m, #I
-// 0000 001r 1010 0000
-// iiii iiii iiii iiii
-// Set logic zero (LZ) flag in status register $sr if result of logical AND
-// operation of accumulator mid part $acD.m with immediate value I is equal
-// immediate value 0.
-void andf(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- u16 val = g_dsp.r[reg];
-
- Update_SR_LZ(((val & imm) == 0) ? 0 : 1);
-}
-
-// CMPI $amD, #I
-// 0000 001r 1000 0000
-// iiii iiii iiii iiii
-// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I.
-// Although flags are being set regarding whole accumulator register.
-void cmpi(const UDSPInstruction& opc)
-{
- int reg = (opc.hex >> 8) & 0x1;
-
- // Immediate is considered to be at M level in the 40-bit accumulator.
- s64 imm = (s64)(s16)dsp_fetch_code() << 16;
- s64 val = dsp_get_long_acc(reg);
- Update_SR_Register64(val - imm);
-}
-
-// XORI $acD.m, #I
-// 0000 001r 0010 0000
-// iiii iiii iiii iiii
-// Logic exclusive or (XOR) of accumulator mid part $acD.m with
-// immediate value I.
-void xori(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] ^= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-// ANDI $acD.m, #I
-// 0000 001r 0100 0000
-// iiii iiii iiii iiii
-// Logic AND of accumulator mid part $acD.m with immediate value I.
-void andi(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] &= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-
-// F|RES: i am not sure if this shouldnt be the whole ACC
-// ORI $acD.m, #I
-// 0000 001r 0110 0000
-// iiii iiii iiii iiii
-// Logic OR of accumulator mid part $acD.m with immediate value I.
-void ori(const UDSPInstruction& opc)
-{
- u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
- u16 imm = dsp_fetch_code();
- g_dsp.r[reg] |= imm;
-
- Update_SR_Register16((s16)g_dsp.r[reg]);
-}
-
-//-------------------------------------------------------------
-
-
-// ADD $acD, $ac(1-D)
-// 0100 110d xxxx xxxx
-// Adds accumulator $ac(1-D) to accumulator register $acD.
-void add(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- s64 acc0 = dsp_get_long_acc(0);
- s64 acc1 = dsp_get_long_acc(1);
-
- s64 res = acc0 + acc1;
-
- dsp_set_long_acc(areg, res);
-
- Update_SR_Register64(res);
-}
-
-// ADDP $acD
-// 0100 111d xxxx xxxx
-// Adds product register to accumulator register.
-void addp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- s64 acc = dsp_get_long_acc(dreg);
- acc += dsp_get_long_prod();
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBP $acD
-// 0101 111d xxxx xxxx
-// Subtracts product register from accumulator register.
-void subp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- s64 acc = dsp_get_long_acc(dreg);
- acc -= dsp_get_long_prod();
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// CMPIS $acD, #I
-// 0000 011d iiii iiii
-// Compares accumulator with short immediate. Comaprison is executed
-// by subtracting short immediate (8bit sign extended) from mid accumulator
-// $acD.hm and computing flags based on whole accumulator $acD.
-void cmpis(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- s64 val = (s8)opc.hex;
- val <<= 16;
-
- s64 res = acc - val;
-
- Update_SR_Register64(res);
-}
-
-
-// DECM $acsD
-// 0111 100d xxxx xxxx
-// Decrement 24-bit mid-accumulator $acsD.
-void decm(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- s64 sub = 0x10000;
- s64 acc = dsp_get_long_acc(dreg);
- acc -= sub;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// DEC $acD
-// 0111 101d xxxx xxxx
-// Decrement accumulator $acD.
-void dec(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- s64 acc = dsp_get_long_acc(dreg) - 1;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// INCM $acsD
-// 0111 010d xxxx xxxx
-// Increment 24-bit mid-accumulator $acsD.
-void incm(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 sub = 0x10000;
- s64 acc = dsp_get_long_acc(dreg);
- acc += sub;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// INC $acD
-// 0111 011d xxxx xxxx
-// Increment accumulator $acD.
-void inc(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(dreg) + 1;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// NEG $acD
-// 0111 110d xxxx xxxx
-// Negate accumulator $acD.
-void neg(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- acc = 0 - acc;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOV $acD, $ac(1-D)
-// 0110 110d xxxx xxxx
-// Moves accumulator $ax(1-D) to accumulator $axD.
-void mov(const UDSPInstruction& opc)
-{
- u8 D = (opc.hex >> 8) & 0x1;
- u64 acc = dsp_get_long_acc(1 - D);
- dsp_set_long_acc(D, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDAX $acD, $axS
-// 0100 10sd xxxx xxxx
-// Adds secondary accumulator $axS to accumulator register $acD.
-void addax(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 ax = dsp_get_long_acx(sreg);
- s64 acc = dsp_get_long_acc(areg);
- acc += ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDR $acD, $(DSP_REG_AXL0+S)
-// 0100 0ssd xxxx xxxx
-// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register.
-void addr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 ax = (s16)g_dsp.r[sreg];
- ax <<= 16;
-
- s64 acc = dsp_get_long_acc(areg);
- acc += ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBR $acD, $(DSP_REG_AXL0+S)
-// 0101 0ssd xxxx xxxx
-// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register.
-void subr(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
-
- s64 ax = (s16)g_dsp.r[sreg];
- ax <<= 16;
-
- s64 acc = dsp_get_long_acc(areg);
- acc -= ax;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// SUBAX $acD, $axS
-// 0101 10sd xxxx xxxx
-// Subtracts secondary accumulator $axS from accumulator register $acD.
-void subax(const UDSPInstruction& opc)
-{
- int regD = (opc.hex >> 8) & 0x1;
- int regS = (opc.hex >> 9) & 0x1;
-
- s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS);
-
- dsp_set_long_acc(regD, acc);
- Update_SR_Register64(acc);
-}
-
-// ADDIS $acD, #I
-// 0000 010d iiii iiii
-// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm.
-void addis(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 Imm = (s8)(u8)opc.hex;
- Imm <<= 16;
- s64 acc = dsp_get_long_acc(areg);
- acc += Imm;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDI $amR, #I
-// 0000 001r 0000 0000
-// iiii iiii iiii iiii
-// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
-void addi(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 sub = (s16)dsp_fetch_code();
- sub <<= 16;
- s64 acc = dsp_get_long_acc(areg);
- acc += sub;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// LSL16 $acR
-// 1111 000r xxxx xxxx
-// Logically shifts left accumulator $acR by 16.
-void lsl16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
- acc <<= 16;
- dsp_set_long_acc(areg, acc);
- Update_SR_Register64(acc);
-}
-
-// LSR16 $acR
-// 1111 010r xxxx xxxx
-// Logically shifts right accumulator $acR by 16.
-void lsr16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 8) & 0x1;
-
- u64 acc = dsp_get_long_acc(areg);
-
- acc >>= 16;
- dsp_set_long_acc(areg, acc);
- Update_SR_Register64(acc);
-}
-
-// ASR16 $acR
-// 1001 r001 xxxx xxxx
-// Arithmetically shifts right accumulator $acR by 16.
-void asr16(const UDSPInstruction& opc)
-{
- u8 areg = (opc.hex >> 11) & 0x1;
-
- s64 acc = dsp_get_long_acc(areg);
-
- acc >>= 16;
- dsp_set_long_acc(areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// LSL $acR, #I
-// 0001 010r 00ii iiii
-// Logically shifts left accumulator $acR by number specified by value I.
-void lsl(const UDSPInstruction& opc)
-{
- u16 shift = opc.ushift;
- u64 acc = dsp_get_long_acc(opc.areg);
-
- acc <<= shift;
- dsp_set_long_acc(opc.areg, acc);
- Update_SR_Register64(acc);
-}
-
-// LSR $acR, #I
-// 0001 010r 01ii iiii
-// Logically shifts left accumulator $acR by number specified by value
-// calculated by negating sign extended bits 0-6.
-void lsr(const UDSPInstruction& opc)
-{
- u16 shift = -opc.ushift;
- u64 acc = dsp_get_long_acc(opc.areg);
- // Lop off the extraneous sign extension our 64-bit fake accum causes
- acc &= 0x000000FFFFFFFFFFULL;
- acc >>= shift;
- dsp_set_long_acc(opc.areg, (s64)acc);
- Update_SR_Register64(acc);
-}
-
-// ASL $acR, #I
-// 0001 010r 10ii iiii
-// Logically shifts left accumulator $acR by number specified by value I.
-void asl(const UDSPInstruction& opc)
-{
- u16 shift = opc.ushift;
-
- // arithmetic shift
- u64 acc = dsp_get_long_acc(opc.areg);
- acc <<= shift;
-
- dsp_set_long_acc(opc.areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ASR $acR, #I
-// 0001 010r 11ii iiii
-// Arithmetically shifts right accumulator $acR by number specified by
-// value calculated by negating sign extended bits 0-6.
-void asr(const UDSPInstruction& opc)
-{
- u16 shift = -opc.ushift;
-
- // arithmetic shift
- s64 acc = dsp_get_long_acc(opc.areg);
- acc >>= shift;
-
- dsp_set_long_acc(opc.areg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// (NEW)
-// LSRN (fixed parameters)
-// 0000 0010 1100 1010
-// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
-// (if value negative, becomes left shift).
-void lsrn(const UDSPInstruction& opc)
-{
- s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
- u64 acc = dsp_get_long_acc(0);
- // Lop off the extraneous sign extension our 64-bit fake accum causes
- acc &= 0x000000FFFFFFFFFFULL;
- if (shift > 0) {
- acc >>= shift;
- } else if (shift < 0) {
- acc <<= -shift;
- }
- dsp_set_long_acc(0, (s64)acc);
- Update_SR_Register64(acc);
-}
-
-// (NEW)
-// ASRN (fixed parameters)
-// 0000 0010 1100 1011
-// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
-// (if value negative, becomes left shift).
-void asrn(const UDSPInstruction& opc)
-{
- s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
- s64 acc = dsp_get_long_acc(0);
- if (shift > 0) {
- acc >>= shift;
- } else if (shift < 0) {
- acc <<= -shift;
- }
- dsp_set_long_acc(0, acc);
- Update_SR_Register64(acc);
-}
-
-
-// CMPAR $acS axR.h
-// 1100 0001 xxxx xxxx
-// Compares accumulator $acS with accumulator axR.h.
-// Not described by Duddie's doc - at least not as a separate instruction.
-void cmpar(const UDSPInstruction& opc)
-{
- u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0;
- u8 sreg = (opc.hex >> 11) & 0x1;
-
- // we compare
- s64 rr = (s16)g_dsp.r[rreg];
- rr <<= 16;
-
- s64 sr = dsp_get_long_acc(sreg);
-
- Update_SR_Register64(sr - rr);
-}
-
-// CMP
-// 1000 0010 xxxx xxxx
-// Compares accumulator $ac0 with accumulator $ac1.
-void cmp(const UDSPInstruction& opc)
-{
- s64 acc0 = dsp_get_long_acc(0);
- s64 acc1 = dsp_get_long_acc(1);
-
- Update_SR_Register64(acc0 - acc1);
-}
-
-// TST
-// 1011 r001 xxxx xxxx
-// Test accumulator %acR.
-void tst(const UDSPInstruction& opc)
-{
- s8 reg = (opc.hex >> 11) & 0x1;
- s64 acc = dsp_get_long_acc(reg);
-
- Update_SR_Register64(acc);
-}
-
-} // namespace
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+#include "DSPInterpreter.h"
+#include "DSPIntCCUtil.h"
+#include "DSPIntUtil.h"
+
+// Arithmetic and accumulator control.
+
+namespace DSPInterpreter {
+
+// CLR $acR
+// 1000 r001 xxxx xxxx
+// Clears accumulator $acR
+void clr(const UDSPInstruction& opc)
+{
+ u8 reg = (opc.hex >> 11) & 0x1;
+
+ dsp_set_long_acc(reg, 0);
+
+ Update_SR_Register64((s64)0); // really?
+}
+
+// CLRL $acR.l
+// 1111 110r xxxx xxxx
+// Clears $acR.l - low 16 bits of accumulator $acR.
+void clrl(const UDSPInstruction& opc)
+{
+ u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1);
+ g_dsp.r[reg] = 0;
+
+ // Should this be 64bit?
+ // nakee: it says the whole reg in duddie's doc sounds weird
+ Update_SR_Register64((s64)reg);
+}
+
+
+// ADDAXL $acD, $axS.l
+// 0111 00sd xxxx xxxx
+// Adds secondary accumulator $axS.l to accumulator register $acD.
+void addaxl(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 9) & 0x1;
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ s64 acc = dsp_get_long_acc(dreg);
+ s64 acx = dsp_get_ax_l(sreg);
+
+ acc += acx;
+
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// TSTAXH $axR.h
+// 1000 011r xxxx xxxx
+// Test high part of secondary accumulator $axR.h.
+void tstaxh(const UDSPInstruction& opc)
+{
+ u8 reg = (opc.hex >> 8) & 0x1;
+ s16 val = dsp_get_ax_h(reg);
+
+ Update_SR_Register16(val);
+}
+
+// SUB $acD, $ac(1-D)
+// 0101 110d xxxx xxxx
+// Subtracts accumulator $ac(1-D) from accumulator register $acD.
+void sub(const UDSPInstruction& opc)
+{
+ u8 D = (opc.hex >> 8) & 0x1;
+ s64 acc1 = dsp_get_long_acc(D);
+ s64 acc2 = dsp_get_long_acc(1 - D);
+
+ acc1 -= acc2;
+
+ dsp_set_long_acc(D, acc1);
+
+ Update_SR_Register64(acc1);
+}
+
+// MOVR $acD, $axS.R
+// 0110 0srd xxxx xxxx
+// Moves register $axS.R (sign extended) to middle accumulator $acD.hm.
+// Sets $acD.l to 0.
+// TODO: Check what happens to acD.h.
+void movr(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+ u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
+
+ s64 acc = (s16)g_dsp.r[sreg];
+ acc <<= 16;
+ acc &= ~0xffff;
+
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// MOVAX $acD, $axS
+// 0110 10sd xxxx xxxx
+// Moves secondary accumulator $axS to accumulator $axD.
+void movax(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+ u8 sreg = (opc.hex >> 9) & 0x1;
+
+ s64 acx = dsp_get_long_acx(sreg);
+ dsp_set_long_acc(dreg, acx);
+
+ Update_SR_Register64(acx);
+}
+
+// XORR $acD.m, $axS.h
+// 0011 00sd xxxx xxxx
+// Logic XOR (exclusive or) middle part of accumulator $acD.m with
+// high part of secondary accumulator $axS.h.
+void xorr(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 9) & 0x1;
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg];
+
+ s64 acc = dsp_get_long_acc(dreg);
+ Update_SR_Register64(acc);
+}
+
+// ANDR $acD.m, $axS.h
+// 0011 01sd xxxx xxxx
+// Logic AND middle part of accumulator $acD.m with high part of
+// secondary accumulator $axS.h.
+void andr(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 9) & 0x1;
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg];
+
+ s64 acc = dsp_get_long_acc(dreg);
+
+ Update_SR_Register64(acc);
+}
+
+// ORR $acD.m, $axS.h
+// 0011 10sd xxxx xxxx
+// Logic OR middle part of accumulator $acD.m with high part of
+// secondary accumulator $axS.h.
+void orr(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 9) & 0x1;
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg];
+
+ s64 acc = dsp_get_long_acc(dreg);
+
+ Update_SR_Register64(acc);
+}
+
+// ANDC $acD.m, $ac(1-D).m
+// 0011 110d xxxx xxxx
+// Logic AND middle part of accumulator $acD.m with middle part of
+// accumulator $ax(1-D).m.s
+void andc(const UDSPInstruction& opc)
+{
+ u8 D = (opc.hex >> 8) & 0x1;
+
+ u16 ac1 = dsp_get_acc_m(D);
+ u16 ac2 = dsp_get_acc_m(1 - D);
+
+ dsp_set_long_acc(D, ac1 & ac2);
+
+ Update_SR_Register64(dsp_get_long_acc(D));
+}
+
+// ORC $acD.m, $ac(1-D).m
+// 0011 111d xxxx xxxx
+// Logic OR middle part of accumulator $acD.m with middle part of
+// accumulator $ax(1-D).m.
+void orc(const UDSPInstruction& opc)
+{
+ u8 D = (opc.hex >> 8) & 0x1;
+
+ u16 ac1 = dsp_get_acc_m(D);
+ u16 ac2 = dsp_get_acc_m(1 - D);
+
+ dsp_set_long_acc(D, ac1 | ac2);
+
+ Update_SR_Register64(dsp_get_long_acc(D));
+}
+
+void orf(const UDSPInstruction& opc)
+{
+ ERROR_LOG(DSPLLE, "orf not implemented");
+}
+
+// Hermes switched andf and andcf, so check to make sure they are still correct
+// ANDCF $acD.m, #I
+// 0000 001r 1100 0000
+// iiii iiii iiii iiii
+// Set logic zero (LZ) flag in status register $sr if result of logic AND of
+// accumulator mid part $acD.m with immediate value I is equal I.
+void andcf(const UDSPInstruction& opc)
+{
+ u8 reg = (opc.hex >> 8) & 0x1;
+ u16 imm = dsp_fetch_code();
+ u16 val = dsp_get_acc_m(reg);
+
+ Update_SR_LZ(((val & imm) == imm) ? 0 : 1);
+}
+
+// Hermes switched andf and andcf, so check to make sure they are still correct
+
+// ANDF $acD.m, #I
+// 0000 001r 1010 0000
+// iiii iiii iiii iiii
+// Set logic zero (LZ) flag in status register $sr if result of logical AND
+// operation of accumulator mid part $acD.m with immediate value I is equal
+// immediate value 0.
+void andf(const UDSPInstruction& opc)
+{
+ u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
+ u16 imm = dsp_fetch_code();
+ u16 val = g_dsp.r[reg];
+
+ Update_SR_LZ(((val & imm) == 0) ? 0 : 1);
+}
+
+// CMPI $amD, #I
+// 0000 001r 1000 0000
+// iiii iiii iiii iiii
+// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I.
+// Although flags are being set regarding whole accumulator register.
+void cmpi(const UDSPInstruction& opc)
+{
+ int reg = (opc.hex >> 8) & 0x1;
+
+ // Immediate is considered to be at M level in the 40-bit accumulator.
+ s64 imm = (s64)(s16)dsp_fetch_code() << 16;
+ s64 val = dsp_get_long_acc(reg);
+ Update_SR_Register64(val - imm);
+}
+
+// XORI $acD.m, #I
+// 0000 001r 0010 0000
+// iiii iiii iiii iiii
+// Logic exclusive or (XOR) of accumulator mid part $acD.m with
+// immediate value I.
+void xori(const UDSPInstruction& opc)
+{
+ u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
+ u16 imm = dsp_fetch_code();
+ g_dsp.r[reg] ^= imm;
+
+ Update_SR_Register16((s16)g_dsp.r[reg]);
+}
+
+// ANDI $acD.m, #I
+// 0000 001r 0100 0000
+// iiii iiii iiii iiii
+// Logic AND of accumulator mid part $acD.m with immediate value I.
+void andi(const UDSPInstruction& opc)
+{
+ u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
+ u16 imm = dsp_fetch_code();
+ g_dsp.r[reg] &= imm;
+
+ Update_SR_Register16((s16)g_dsp.r[reg]);
+}
+
+
+// F|RES: i am not sure if this shouldnt be the whole ACC
+// ORI $acD.m, #I
+// 0000 001r 0110 0000
+// iiii iiii iiii iiii
+// Logic OR of accumulator mid part $acD.m with immediate value I.
+void ori(const UDSPInstruction& opc)
+{
+ u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1);
+ u16 imm = dsp_fetch_code();
+ g_dsp.r[reg] |= imm;
+
+ Update_SR_Register16((s16)g_dsp.r[reg]);
+}
+
+//-------------------------------------------------------------
+
+
+// ADD $acD, $ac(1-D)
+// 0100 110d xxxx xxxx
+// Adds accumulator $ac(1-D) to accumulator register $acD.
+void add(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+ s64 acc0 = dsp_get_long_acc(0);
+ s64 acc1 = dsp_get_long_acc(1);
+
+ s64 res = acc0 + acc1;
+
+ dsp_set_long_acc(areg, res);
+
+ Update_SR_Register64(res);
+}
+
+// ADDP $acD
+// 0100 111d xxxx xxxx
+// Adds product register to accumulator register.
+void addp(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+ s64 acc = dsp_get_long_acc(dreg);
+ acc += dsp_get_long_prod();
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// SUBP $acD
+// 0101 111d xxxx xxxx
+// Subtracts product register from accumulator register.
+void subp(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+ s64 acc = dsp_get_long_acc(dreg);
+ acc -= dsp_get_long_prod();
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+
+// CMPIS $acD, #I
+// 0000 011d iiii iiii
+// Compares accumulator with short immediate. Comaprison is executed
+// by subtracting short immediate (8bit sign extended) from mid accumulator
+// $acD.hm and computing flags based on whole accumulator $acD.
+void cmpis(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+
+ s64 acc = dsp_get_long_acc(areg);
+ s64 val = (s8)opc.hex;
+ val <<= 16;
+
+ s64 res = acc - val;
+
+ Update_SR_Register64(res);
+}
+
+
+// DECM $acsD
+// 0111 100d xxxx xxxx
+// Decrement 24-bit mid-accumulator $acsD.
+void decm(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x01;
+
+ s64 sub = 0x10000;
+ s64 acc = dsp_get_long_acc(dreg);
+ acc -= sub;
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// DEC $acD
+// 0111 101d xxxx xxxx
+// Decrement accumulator $acD.
+void dec(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x01;
+
+ s64 acc = dsp_get_long_acc(dreg) - 1;
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// INCM $acsD
+// 0111 010d xxxx xxxx
+// Increment 24-bit mid-accumulator $acsD.
+void incm(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ s64 sub = 0x10000;
+ s64 acc = dsp_get_long_acc(dreg);
+ acc += sub;
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// INC $acD
+// 0111 011d xxxx xxxx
+// Increment accumulator $acD.
+void inc(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ s64 acc = dsp_get_long_acc(dreg) + 1;
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// NEG $acD
+// 0111 110d xxxx xxxx
+// Negate accumulator $acD.
+void neg(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+
+ s64 acc = dsp_get_long_acc(areg);
+ acc = 0 - acc;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// MOV $acD, $ac(1-D)
+// 0110 110d xxxx xxxx
+// Moves accumulator $ax(1-D) to accumulator $axD.
+void mov(const UDSPInstruction& opc)
+{
+ u8 D = (opc.hex >> 8) & 0x1;
+ u64 acc = dsp_get_long_acc(1 - D);
+ dsp_set_long_acc(D, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// ADDAX $acD, $axS
+// 0100 10sd xxxx xxxx
+// Adds secondary accumulator $axS to accumulator register $acD.
+void addax(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+ u8 sreg = (opc.hex >> 9) & 0x1;
+
+ s64 ax = dsp_get_long_acx(sreg);
+ s64 acc = dsp_get_long_acc(areg);
+ acc += ax;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// ADDR $acD, $(DSP_REG_AXL0+S)
+// 0100 0ssd xxxx xxxx
+// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register.
+void addr(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+ u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
+
+ s64 ax = (s16)g_dsp.r[sreg];
+ ax <<= 16;
+
+ s64 acc = dsp_get_long_acc(areg);
+ acc += ax;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// SUBR $acD, $(DSP_REG_AXL0+S)
+// 0101 0ssd xxxx xxxx
+// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register.
+void subr(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+ u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0;
+
+ s64 ax = (s16)g_dsp.r[sreg];
+ ax <<= 16;
+
+ s64 acc = dsp_get_long_acc(areg);
+ acc -= ax;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// SUBAX $acD, $axS
+// 0101 10sd xxxx xxxx
+// Subtracts secondary accumulator $axS from accumulator register $acD.
+void subax(const UDSPInstruction& opc)
+{
+ int regD = (opc.hex >> 8) & 0x1;
+ int regS = (opc.hex >> 9) & 0x1;
+
+ s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS);
+
+ dsp_set_long_acc(regD, acc);
+ Update_SR_Register64(acc);
+}
+
+// ADDIS $acD, #I
+// 0000 010d iiii iiii
+// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm.
+void addis(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+
+ s64 Imm = (s8)(u8)opc.hex;
+ Imm <<= 16;
+ s64 acc = dsp_get_long_acc(areg);
+ acc += Imm;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// ADDI $amR, #I
+// 0000 001r 0000 0000
+// iiii iiii iiii iiii
+// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm.
+void addi(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+
+ s64 sub = (s16)dsp_fetch_code();
+ sub <<= 16;
+ s64 acc = dsp_get_long_acc(areg);
+ acc += sub;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// LSL16 $acR
+// 1111 000r xxxx xxxx
+// Logically shifts left accumulator $acR by 16.
+void lsl16(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+
+ s64 acc = dsp_get_long_acc(areg);
+ acc <<= 16;
+ dsp_set_long_acc(areg, acc);
+ Update_SR_Register64(acc);
+}
+
+// LSR16 $acR
+// 1111 010r xxxx xxxx
+// Logically shifts right accumulator $acR by 16.
+void lsr16(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 8) & 0x1;
+
+ u64 acc = dsp_get_long_acc(areg);
+
+ acc >>= 16;
+ dsp_set_long_acc(areg, acc);
+ Update_SR_Register64(acc);
+}
+
+// ASR16 $acR
+// 1001 r001 xxxx xxxx
+// Arithmetically shifts right accumulator $acR by 16.
+void asr16(const UDSPInstruction& opc)
+{
+ u8 areg = (opc.hex >> 11) & 0x1;
+
+ s64 acc = dsp_get_long_acc(areg);
+
+ acc >>= 16;
+ dsp_set_long_acc(areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// LSL $acR, #I
+// 0001 010r 00ii iiii
+// Logically shifts left accumulator $acR by number specified by value I.
+void lsl(const UDSPInstruction& opc)
+{
+ u16 shift = opc.ushift;
+ u64 acc = dsp_get_long_acc(opc.areg);
+
+ acc <<= shift;
+ dsp_set_long_acc(opc.areg, acc);
+ Update_SR_Register64(acc);
+}
+
+// LSR $acR, #I
+// 0001 010r 01ii iiii
+// Logically shifts left accumulator $acR by number specified by value
+// calculated by negating sign extended bits 0-6.
+void lsr(const UDSPInstruction& opc)
+{
+ u16 shift = -opc.ushift;
+ u64 acc = dsp_get_long_acc(opc.areg);
+ // Lop off the extraneous sign extension our 64-bit fake accum causes
+ acc &= 0x000000FFFFFFFFFFULL;
+ acc >>= shift;
+ dsp_set_long_acc(opc.areg, (s64)acc);
+ Update_SR_Register64(acc);
+}
+
+// ASL $acR, #I
+// 0001 010r 10ii iiii
+// Logically shifts left accumulator $acR by number specified by value I.
+void asl(const UDSPInstruction& opc)
+{
+ u16 shift = opc.ushift;
+
+ // arithmetic shift
+ u64 acc = dsp_get_long_acc(opc.areg);
+ acc <<= shift;
+
+ dsp_set_long_acc(opc.areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// ASR $acR, #I
+// 0001 010r 11ii iiii
+// Arithmetically shifts right accumulator $acR by number specified by
+// value calculated by negating sign extended bits 0-6.
+void asr(const UDSPInstruction& opc)
+{
+ u16 shift = -opc.ushift;
+
+ // arithmetic shift
+ s64 acc = dsp_get_long_acc(opc.areg);
+ acc >>= shift;
+
+ dsp_set_long_acc(opc.areg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+
+// (NEW)
+// LSRN (fixed parameters)
+// 0000 0010 1100 1010
+// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
+// (if value negative, becomes left shift).
+void lsrn(const UDSPInstruction& opc)
+{
+ s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
+ u64 acc = dsp_get_long_acc(0);
+ // Lop off the extraneous sign extension our 64-bit fake accum causes
+ acc &= 0x000000FFFFFFFFFFULL;
+ if (shift > 0) {
+ acc >>= shift;
+ } else if (shift < 0) {
+ acc <<= -shift;
+ }
+ dsp_set_long_acc(0, (s64)acc);
+ Update_SR_Register64(acc);
+}
+
+// (NEW)
+// ASRN (fixed parameters)
+// 0000 0010 1100 1011
+// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M
+// (if value negative, becomes left shift).
+void asrn(const UDSPInstruction& opc)
+{
+ s16 shift = (s16)g_dsp.r[DSP_REG_ACM1];
+ s64 acc = dsp_get_long_acc(0);
+ if (shift > 0) {
+ acc >>= shift;
+ } else if (shift < 0) {
+ acc <<= -shift;
+ }
+ dsp_set_long_acc(0, acc);
+ Update_SR_Register64(acc);
+}
+
+
+// CMPAR $acS axR.h
+// 1100 0001 xxxx xxxx
+// Compares accumulator $acS with accumulator axR.h.
+// Not described by Duddie's doc - at least not as a separate instruction.
+void cmpar(const UDSPInstruction& opc)
+{
+ u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0;
+ u8 sreg = (opc.hex >> 11) & 0x1;
+
+ // we compare
+ s64 rr = (s16)g_dsp.r[rreg];
+ rr <<= 16;
+
+ s64 sr = dsp_get_long_acc(sreg);
+
+ Update_SR_Register64(sr - rr);
+}
+
+// CMP
+// 1000 0010 xxxx xxxx
+// Compares accumulator $ac0 with accumulator $ac1.
+void cmp(const UDSPInstruction& opc)
+{
+ s64 acc0 = dsp_get_long_acc(0);
+ s64 acc1 = dsp_get_long_acc(1);
+
+ Update_SR_Register64(acc0 - acc1);
+}
+
+// TST
+// 1011 r001 xxxx xxxx
+// Test accumulator %acR.
+void tst(const UDSPInstruction& opc)
+{
+ s8 reg = (opc.hex >> 11) & 0x1;
+ s64 acc = dsp_get_long_acc(reg);
+
+ Update_SR_Register64(acc);
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DspIntBranch.cpp b/Source/Core/DSPCore/Src/DspIntBranch.cpp
index f37cc71ba0..721428d8f0 100644
--- a/Source/Core/DSPCore/Src/DspIntBranch.cpp
+++ b/Source/Core/DSPCore/Src/DspIntBranch.cpp
@@ -1,249 +1,249 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-#include "DSPCore.h"
-#include "DSPMemoryMap.h"
-#include "DSPStacks.h"
-
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// Generic call implementation
-// CALLcc addressA
-// 0000 0010 1011 cccc
-// aaaa aaaa aaaa aaaa
-// Call function if condition cc has been met. Push program counter of
-// instruction following "call" to $st0. Set program counter to address
-// represented by value that follows this "call" instruction.
-void call(const UDSPInstruction& opc)
-{
- // must be outside the if.
- u16 dest = dsp_fetch_code();
- if (CheckCondition(opc.hex & 0xf))
- {
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- g_dsp.pc = dest;
- }
-}
-
-// Generic callr implementation
-// CALLRcc $R
-// 0001 0111 rrr1 cccc
-// Call function if condition cc has been met. Push program counter of
-// instruction following "call" to call stack $st0. Set program counter to
-// register $R.
-void callr(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- u8 reg = (opc.hex >> 5) & 0x7;
- u16 addr = dsp_op_read_reg(reg);
- dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
- g_dsp.pc = addr;
- }
-}
-
-// Generic if implementation
-// IFcc
-// 0000 0010 0111 cccc
-// Execute following opcode if the condition has been met.
-void ifcc(const UDSPInstruction& opc)
-{
- if (!CheckCondition(opc.hex & 0xf))
- {
- // skip the next opcode - we have to lookup its size.
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-// Generic jmp implementation
-// Jcc addressA
-// 0000 0010 1001 cccc
-// aaaa aaaa aaaa aaaa
-// Jump to addressA if condition cc has been met. Set program counter to
-// address represented by value that follows this "jmp" instruction.
-void jcc(const UDSPInstruction& opc)
-{
- u16 dest = dsp_fetch_code();
- if (CheckCondition(opc.hex & 0xf))
- {
- g_dsp.pc = dest;
- }
-}
-
-// Generic jmpr implementation
-// JMPcc $R
-// 0001 0111 rrr0 cccc
-// Jump to address; set program counter to a value from register $R.
-void jmprcc(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- u8 reg = (opc.hex >> 5) & 0x7;
- g_dsp.pc = dsp_op_read_reg(reg);
- }
-}
-
-// Generic ret implementation
-// RETcc
-// 0000 0010 1101 cccc
-// Return from subroutine if condition cc has been met. Pops stored PC
-// from call stack $st0 and sets $pc to this location.
-void ret(const UDSPInstruction& opc)
-{
- if (CheckCondition(opc.hex & 0xf))
- {
- g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
- }
-}
-
-// RTI
-// 0000 0010 1111 1111
-// Return from exception. Pops stored status register $sr from data stack
-// $st1 and program counter PC from call stack $st0 and sets $pc to this
-// location.
-void rti(const UDSPInstruction& opc)
-{
- g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D);
- g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
-
- g_dsp.exception_in_progress_hack = false;
-}
-
-// HALT
-// 0000 0000 0020 0001
-// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
-void halt(const UDSPInstruction& opc)
-{
- g_dsp.cr |= 0x4;
- g_dsp.pc--;
-}
-
-
-// LOOP handling: Loop stack is used to control execution of repeated blocks of
-// instructions. Whenever there is value on stack $st2 and current PC is equal
-// value at $st2, then value at stack $st3 is decremented. If value is not zero
-// then PC is modified with calue from call stack $st0. Otherwise values from
-// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution
-// continues at next opcode.
-
-
-// LOOP $R
-// 0000 0000 010r rrrr
-// Repeatedly execute following opcode until counter specified by value
-// from register $R reaches zero. Each execution decrement counter. Register
-// $R remains unchanged. If register $R is set to zero at the beginning of loop
-// then looped instruction will not get executed.
-// Actually, this instruction simply prepares the loop stacks for the above.
-// The looping hardware takes care of the rest.
-void loop(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x1f;
- u16 cnt = g_dsp.r[reg];
- u16 loop_pc = g_dsp.pc;
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
-}
-
-// LOOPI #I
-// 0001 0000 iiii iiii
-// Repeatedly execute following opcode until counter specified by
-// immediate value I reaches zero. Each execution decrement counter. If
-// immediate value I is set to zero at the beginning of loop then looped
-// instruction will not get executed.
-// Actually, this instruction simply prepares the loop stacks for the above.
-// The looping hardware takes care of the rest.
-void loopi(const UDSPInstruction& opc)
-{
- u16 cnt = opc.hex & 0xff;
- u16 loop_pc = g_dsp.pc;
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
-}
-
-
-// BLOOP $R, addrA
-// 0000 0000 011r rrrr
-// aaaa aaaa aaaa aaaa
-// Repeatedly execute block of code starting at following opcode until
-// counter specified by value from register $R reaches zero. Block ends at
-// specified address addrA inclusive, ie. opcode at addrA is the last opcode
-// included in loop. Counter is pushed on loop stack $st3, end of block address
-// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
-// Up to 4 nested loops is allowed.
-void bloop(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x1f;
- u16 cnt = g_dsp.r[reg];
- u16 loop_pc = dsp_fetch_code();
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
- else
- {
- g_dsp.pc = loop_pc;
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-// BLOOPI #I, addrA
-// 0001 0001 iiii iiii
-// aaaa aaaa aaaa aaaa
-// Repeatedly execute block of code starting at following opcode until
-// counter specified by immediate value I reaches zero. Block ends at specified
-// address addrA inclusive, ie. opcode at addrA is the last opcode included in
-// loop. Counter is pushed on loop stack $st3, end of block address is pushed
-// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
-// nested loops is allowed.
-void bloopi(const UDSPInstruction& opc)
-{
- u16 cnt = opc.hex & 0xff;
- u16 loop_pc = dsp_fetch_code();
-
- if (cnt)
- {
- dsp_reg_store_stack(0, g_dsp.pc);
- dsp_reg_store_stack(2, loop_pc);
- dsp_reg_store_stack(3, cnt);
- }
- else
- {
- g_dsp.pc = loop_pc;
- g_dsp.pc += opSize[dsp_peek_code()];
- }
-}
-
-} // namespace
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+#include "DSPInterpreter.h"
+#include "DSPCore.h"
+#include "DSPMemoryMap.h"
+#include "DSPStacks.h"
+
+#include "DSPIntCCUtil.h"
+#include "DSPIntUtil.h"
+
+namespace DSPInterpreter {
+
+// Generic call implementation
+// CALLcc addressA
+// 0000 0010 1011 cccc
+// aaaa aaaa aaaa aaaa
+// Call function if condition cc has been met. Push program counter of
+// instruction following "call" to $st0. Set program counter to address
+// represented by value that follows this "call" instruction.
+void call(const UDSPInstruction& opc)
+{
+ // must be outside the if.
+ u16 dest = dsp_fetch_code();
+ if (CheckCondition(opc.hex & 0xf))
+ {
+ dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
+ g_dsp.pc = dest;
+ }
+}
+
+// Generic callr implementation
+// CALLRcc $R
+// 0001 0111 rrr1 cccc
+// Call function if condition cc has been met. Push program counter of
+// instruction following "call" to call stack $st0. Set program counter to
+// register $R.
+void callr(const UDSPInstruction& opc)
+{
+ if (CheckCondition(opc.hex & 0xf))
+ {
+ u8 reg = (opc.hex >> 5) & 0x7;
+ u16 addr = dsp_op_read_reg(reg);
+ dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc);
+ g_dsp.pc = addr;
+ }
+}
+
+// Generic if implementation
+// IFcc
+// 0000 0010 0111 cccc
+// Execute following opcode if the condition has been met.
+void ifcc(const UDSPInstruction& opc)
+{
+ if (!CheckCondition(opc.hex & 0xf))
+ {
+ // skip the next opcode - we have to lookup its size.
+ g_dsp.pc += opSize[dsp_peek_code()];
+ }
+}
+
+// Generic jmp implementation
+// Jcc addressA
+// 0000 0010 1001 cccc
+// aaaa aaaa aaaa aaaa
+// Jump to addressA if condition cc has been met. Set program counter to
+// address represented by value that follows this "jmp" instruction.
+void jcc(const UDSPInstruction& opc)
+{
+ u16 dest = dsp_fetch_code();
+ if (CheckCondition(opc.hex & 0xf))
+ {
+ g_dsp.pc = dest;
+ }
+}
+
+// Generic jmpr implementation
+// JMPcc $R
+// 0001 0111 rrr0 cccc
+// Jump to address; set program counter to a value from register $R.
+void jmprcc(const UDSPInstruction& opc)
+{
+ if (CheckCondition(opc.hex & 0xf))
+ {
+ u8 reg = (opc.hex >> 5) & 0x7;
+ g_dsp.pc = dsp_op_read_reg(reg);
+ }
+}
+
+// Generic ret implementation
+// RETcc
+// 0000 0010 1101 cccc
+// Return from subroutine if condition cc has been met. Pops stored PC
+// from call stack $st0 and sets $pc to this location.
+void ret(const UDSPInstruction& opc)
+{
+ if (CheckCondition(opc.hex & 0xf))
+ {
+ g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
+ }
+}
+
+// RTI
+// 0000 0010 1111 1111
+// Return from exception. Pops stored status register $sr from data stack
+// $st1 and program counter PC from call stack $st0 and sets $pc to this
+// location.
+void rti(const UDSPInstruction& opc)
+{
+ g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D);
+ g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C);
+
+ g_dsp.exception_in_progress_hack = false;
+}
+
+// HALT
+// 0000 0000 0020 0001
+// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
+void halt(const UDSPInstruction& opc)
+{
+ g_dsp.cr |= 0x4;
+ g_dsp.pc--;
+}
+
+
+// LOOP handling: Loop stack is used to control execution of repeated blocks of
+// instructions. Whenever there is value on stack $st2 and current PC is equal
+// value at $st2, then value at stack $st3 is decremented. If value is not zero
+// then PC is modified with calue from call stack $st0. Otherwise values from
+// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution
+// continues at next opcode.
+
+
+// LOOP $R
+// 0000 0000 010r rrrr
+// Repeatedly execute following opcode until counter specified by value
+// from register $R reaches zero. Each execution decrement counter. Register
+// $R remains unchanged. If register $R is set to zero at the beginning of loop
+// then looped instruction will not get executed.
+// Actually, this instruction simply prepares the loop stacks for the above.
+// The looping hardware takes care of the rest.
+void loop(const UDSPInstruction& opc)
+{
+ u16 reg = opc.hex & 0x1f;
+ u16 cnt = g_dsp.r[reg];
+ u16 loop_pc = g_dsp.pc;
+
+ if (cnt)
+ {
+ dsp_reg_store_stack(0, g_dsp.pc);
+ dsp_reg_store_stack(2, loop_pc);
+ dsp_reg_store_stack(3, cnt);
+ }
+}
+
+// LOOPI #I
+// 0001 0000 iiii iiii
+// Repeatedly execute following opcode until counter specified by
+// immediate value I reaches zero. Each execution decrement counter. If
+// immediate value I is set to zero at the beginning of loop then looped
+// instruction will not get executed.
+// Actually, this instruction simply prepares the loop stacks for the above.
+// The looping hardware takes care of the rest.
+void loopi(const UDSPInstruction& opc)
+{
+ u16 cnt = opc.hex & 0xff;
+ u16 loop_pc = g_dsp.pc;
+
+ if (cnt)
+ {
+ dsp_reg_store_stack(0, g_dsp.pc);
+ dsp_reg_store_stack(2, loop_pc);
+ dsp_reg_store_stack(3, cnt);
+ }
+}
+
+
+// BLOOP $R, addrA
+// 0000 0000 011r rrrr
+// aaaa aaaa aaaa aaaa
+// Repeatedly execute block of code starting at following opcode until
+// counter specified by value from register $R reaches zero. Block ends at
+// specified address addrA inclusive, ie. opcode at addrA is the last opcode
+// included in loop. Counter is pushed on loop stack $st3, end of block address
+// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
+// Up to 4 nested loops is allowed.
+void bloop(const UDSPInstruction& opc)
+{
+ u16 reg = opc.hex & 0x1f;
+ u16 cnt = g_dsp.r[reg];
+ u16 loop_pc = dsp_fetch_code();
+
+ if (cnt)
+ {
+ dsp_reg_store_stack(0, g_dsp.pc);
+ dsp_reg_store_stack(2, loop_pc);
+ dsp_reg_store_stack(3, cnt);
+ }
+ else
+ {
+ g_dsp.pc = loop_pc;
+ g_dsp.pc += opSize[dsp_peek_code()];
+ }
+}
+
+// BLOOPI #I, addrA
+// 0001 0001 iiii iiii
+// aaaa aaaa aaaa aaaa
+// Repeatedly execute block of code starting at following opcode until
+// counter specified by immediate value I reaches zero. Block ends at specified
+// address addrA inclusive, ie. opcode at addrA is the last opcode included in
+// loop. Counter is pushed on loop stack $st3, end of block address is pushed
+// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
+// nested loops is allowed.
+void bloopi(const UDSPInstruction& opc)
+{
+ u16 cnt = opc.hex & 0xff;
+ u16 loop_pc = dsp_fetch_code();
+
+ if (cnt)
+ {
+ dsp_reg_store_stack(0, g_dsp.pc);
+ dsp_reg_store_stack(2, loop_pc);
+ dsp_reg_store_stack(3, cnt);
+ }
+ else
+ {
+ g_dsp.pc = loop_pc;
+ g_dsp.pc += opSize[dsp_peek_code()];
+ }
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp
index 5346a4ed41..b2603f6c54 100644
--- a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp
+++ b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp
@@ -1,266 +1,266 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-#include "DSPInterpreter.h"
-
-#include "DSPMemoryMap.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// SRS @M, $(0x18+S)
-// 0010 1sss mmmm mmmm
-// Move value from register $(0x18+D) to data memory pointed by address CR[0-7] | M.
-// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
-// lower 8 bits are from the 8-bit immediate.
-// Note: pc+=2 in duddie's doc seems wrong
-void srs(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
- u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
- dsp_dmem_write(addr, g_dsp.r[reg]);
-}
-
-// LRS $(0x18+D), @M
-// 0010 0ddd mmmm mmmm
-// Move value from data memory pointed by address CR[0-7] | M to register $(0x18+D).
-// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
-// lower 8 bits are from the 8-bit immediate.
-void lrs(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
- u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
- g_dsp.r[reg] = dsp_dmem_read(addr);
-}
-
-// LR $D, @M
-// 0000 0000 110d dddd
-// mmmm mmmm mmmm mmmm
-// Move value from data memory pointed by address M to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void lr(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 addr = dsp_fetch_code();
- u16 val = dsp_dmem_read(addr);
- dsp_op_write_reg(reg, val);
- dsp_conditional_extend_accum(reg);
-}
-
-// SR @M, $S
-// 0000 0000 111s ssss
-// mmmm mmmm mmmm mmmm
-// Store value from register $S to a memory pointed by address M.
-// FIXME: Perform additional operation depending on destination register.
-void sr(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 addr = dsp_fetch_code();
- u16 val = dsp_op_read_reg(reg);
- dsp_dmem_write(addr, val);
-}
-
-// SI @M, #I
-// 0001 0110 mmmm mmmm
-// iiii iiii iiii iiii
-// Store 16-bit immediate value I to a memory location pointed by address
-// M (M is 8-bit value sign extended).
-void si(const UDSPInstruction& opc)
-{
- u16 addr = (s8)opc.hex;
- u16 imm = dsp_fetch_code();
- dsp_dmem_write(addr, imm);
-}
-
-// LRR $D, @$S
-// 0001 1000 0ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void lrr(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
-}
-
-// LRRD $D, @$S
-// 0001 1000 1ssd dddd
-// Move value from data memory pointed by addressing register $S toregister $D.
-// Decrement register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrrd(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- dsp_decrement_addr_reg(sreg);
-}
-
-// LRRI $D, @$S
-// 0001 1001 0ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// Increment register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrri(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- dsp_increment_addr_reg(sreg);
-}
-
-// LRRN $D, @$S
-// 0001 1001 1ssd dddd
-// Move value from data memory pointed by addressing register $S to register $D.
-// Add indexing register $(0x4+S) to register $S.
-// FIXME: Perform additional operation depending on destination register.
-void lrrn(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 5) & 0x3;
- u8 dreg = opc.hex & 0x1f;
-
- u16 val = dsp_dmem_read(g_dsp.r[sreg]);
- dsp_op_write_reg(dreg, val);
- // g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg];
- dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
-}
-
-// SRR @$D, $S
-// 0001 1010 0dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D.
-// FIXME: Perform additional operation depending on source register.
-void srr(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
-}
-
-// SRRD @$D, $S
-// 0001 1010 1dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Decrement register $D.
-// FIXME: Perform additional operation depending on source register.
-void srrd(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- dsp_decrement_addr_reg(dreg);
-}
-
-// SRRI @$D, $S
-// 0001 1011 0dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Increment register $D.
-// FIXME: Perform additional operation depending on source register.
-void srri(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- dsp_increment_addr_reg(dreg);
-}
-
-// SRRN @$D, $S
-// 0001 1011 1dds ssss
-// Store value from source register $S to a memory location pointed by
-// addressing register $D. Add DSP_REG_IX0 register to register $D.
-// FIXME: Perform additional operation depending on source register.
-void srrn(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 5) & 0x3;
- u8 sreg = opc.hex & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_dmem_write(g_dsp.r[dreg], val);
- // g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg];
- dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]);
-}
-
-// ILRR $acD.m, @$arS
-// 0000 001d 0001 00ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m.
-void ilrr(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-}
-
-// ILRRD $acD.m, @$arS
-// 0000 001d 0001 01ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
-void ilrrd(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- dsp_decrement_addr_reg(reg);
-}
-
-// ILRRI $acD.m, @$S
-// 0000 001d 0001 10ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
-void ilrri(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- dsp_increment_addr_reg(reg);
-}
-
-// ILRRN $acD.m, @$arS
-// 0000 001d 0001 11ss
-// Move value from instruction memory pointed by addressing register
-// $arS to mid accumulator register $acD.m. Add corresponding indexing
-// register $ixS to addressing register $arS.
-void ilrrn(const UDSPInstruction& opc)
-{
- u16 reg = opc.hex & 0x3;
- u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
-
- g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
-
- // g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg];
- dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg]);
-}
-
-} // namespace
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+#include "DSPInterpreter.h"
+
+#include "DSPMemoryMap.h"
+#include "DSPIntUtil.h"
+
+namespace DSPInterpreter {
+
+// SRS @M, $(0x18+S)
+// 0010 1sss mmmm mmmm
+// Move value from register $(0x18+D) to data memory pointed by address CR[0-7] | M.
+// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
+// lower 8 bits are from the 8-bit immediate.
+// Note: pc+=2 in duddie's doc seems wrong
+void srs(const UDSPInstruction& opc)
+{
+ u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
+ u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
+ dsp_dmem_write(addr, g_dsp.r[reg]);
+}
+
+// LRS $(0x18+D), @M
+// 0010 0ddd mmmm mmmm
+// Move value from data memory pointed by address CR[0-7] | M to register $(0x18+D).
+// That is, the upper 8 bits of the address are the bottom 8 bits from CR, and the
+// lower 8 bits are from the 8-bit immediate.
+void lrs(const UDSPInstruction& opc)
+{
+ u8 reg = ((opc.hex >> 8) & 0x7) + 0x18;
+ u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc.hex & 0xFF);
+ g_dsp.r[reg] = dsp_dmem_read(addr);
+}
+
+// LR $D, @M
+// 0000 0000 110d dddd
+// mmmm mmmm mmmm mmmm
+// Move value from data memory pointed by address M to register $D.
+// FIXME: Perform additional operation depending on destination register.
+void lr(const UDSPInstruction& opc)
+{
+ u8 reg = opc.hex & DSP_REG_MASK;
+ u16 addr = dsp_fetch_code();
+ u16 val = dsp_dmem_read(addr);
+ dsp_op_write_reg(reg, val);
+ dsp_conditional_extend_accum(reg);
+}
+
+// SR @M, $S
+// 0000 0000 111s ssss
+// mmmm mmmm mmmm mmmm
+// Store value from register $S to a memory pointed by address M.
+// FIXME: Perform additional operation depending on destination register.
+void sr(const UDSPInstruction& opc)
+{
+ u8 reg = opc.hex & DSP_REG_MASK;
+ u16 addr = dsp_fetch_code();
+ u16 val = dsp_op_read_reg(reg);
+ dsp_dmem_write(addr, val);
+}
+
+// SI @M, #I
+// 0001 0110 mmmm mmmm
+// iiii iiii iiii iiii
+// Store 16-bit immediate value I to a memory location pointed by address
+// M (M is 8-bit value sign extended).
+void si(const UDSPInstruction& opc)
+{
+ u16 addr = (s8)opc.hex;
+ u16 imm = dsp_fetch_code();
+ dsp_dmem_write(addr, imm);
+}
+
+// LRR $D, @$S
+// 0001 1000 0ssd dddd
+// Move value from data memory pointed by addressing register $S to register $D.
+// FIXME: Perform additional operation depending on destination register.
+void lrr(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 5) & 0x3;
+ u8 dreg = opc.hex & 0x1f;
+
+ u16 val = dsp_dmem_read(g_dsp.r[sreg]);
+ dsp_op_write_reg(dreg, val);
+}
+
+// LRRD $D, @$S
+// 0001 1000 1ssd dddd
+// Move value from data memory pointed by addressing register $S toregister $D.
+// Decrement register $S.
+// FIXME: Perform additional operation depending on destination register.
+void lrrd(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 5) & 0x3;
+ u8 dreg = opc.hex & 0x1f;
+
+ u16 val = dsp_dmem_read(g_dsp.r[sreg]);
+ dsp_op_write_reg(dreg, val);
+ dsp_decrement_addr_reg(sreg);
+}
+
+// LRRI $D, @$S
+// 0001 1001 0ssd dddd
+// Move value from data memory pointed by addressing register $S to register $D.
+// Increment register $S.
+// FIXME: Perform additional operation depending on destination register.
+void lrri(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 5) & 0x3;
+ u8 dreg = opc.hex & 0x1f;
+
+ u16 val = dsp_dmem_read(g_dsp.r[sreg]);
+ dsp_op_write_reg(dreg, val);
+ dsp_increment_addr_reg(sreg);
+}
+
+// LRRN $D, @$S
+// 0001 1001 1ssd dddd
+// Move value from data memory pointed by addressing register $S to register $D.
+// Add indexing register $(0x4+S) to register $S.
+// FIXME: Perform additional operation depending on destination register.
+void lrrn(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 5) & 0x3;
+ u8 dreg = opc.hex & 0x1f;
+
+ u16 val = dsp_dmem_read(g_dsp.r[sreg]);
+ dsp_op_write_reg(dreg, val);
+ // g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg];
+ dsp_increase_addr_reg(sreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
+}
+
+// SRR @$D, $S
+// 0001 1010 0dds ssss
+// Store value from source register $S to a memory location pointed by
+// addressing register $D.
+// FIXME: Perform additional operation depending on source register.
+void srr(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 5) & 0x3;
+ u8 sreg = opc.hex & 0x1f;
+
+ u16 val = dsp_op_read_reg(sreg);
+ dsp_dmem_write(g_dsp.r[dreg], val);
+}
+
+// SRRD @$D, $S
+// 0001 1010 1dds ssss
+// Store value from source register $S to a memory location pointed by
+// addressing register $D. Decrement register $D.
+// FIXME: Perform additional operation depending on source register.
+void srrd(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 5) & 0x3;
+ u8 sreg = opc.hex & 0x1f;
+
+ u16 val = dsp_op_read_reg(sreg);
+ dsp_dmem_write(g_dsp.r[dreg], val);
+ dsp_decrement_addr_reg(dreg);
+}
+
+// SRRI @$D, $S
+// 0001 1011 0dds ssss
+// Store value from source register $S to a memory location pointed by
+// addressing register $D. Increment register $D.
+// FIXME: Perform additional operation depending on source register.
+void srri(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 5) & 0x3;
+ u8 sreg = opc.hex & 0x1f;
+
+ u16 val = dsp_op_read_reg(sreg);
+ dsp_dmem_write(g_dsp.r[dreg], val);
+ dsp_increment_addr_reg(dreg);
+}
+
+// SRRN @$D, $S
+// 0001 1011 1dds ssss
+// Store value from source register $S to a memory location pointed by
+// addressing register $D. Add DSP_REG_IX0 register to register $D.
+// FIXME: Perform additional operation depending on source register.
+void srrn(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 5) & 0x3;
+ u8 sreg = opc.hex & 0x1f;
+
+ u16 val = dsp_op_read_reg(sreg);
+ dsp_dmem_write(g_dsp.r[dreg], val);
+ // g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg];
+ dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]);
+}
+
+// ILRR $acD.m, @$arS
+// 0000 001d 0001 00ss
+// Move value from instruction memory pointed by addressing register
+// $arS to mid accumulator register $acD.m.
+void ilrr(const UDSPInstruction& opc)
+{
+ u16 reg = opc.hex & 0x3;
+ u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
+
+ g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
+}
+
+// ILRRD $acD.m, @$arS
+// 0000 001d 0001 01ss
+// Move value from instruction memory pointed by addressing register
+// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
+void ilrrd(const UDSPInstruction& opc)
+{
+ u16 reg = opc.hex & 0x3;
+ u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
+
+ g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
+
+ dsp_decrement_addr_reg(reg);
+}
+
+// ILRRI $acD.m, @$S
+// 0000 001d 0001 10ss
+// Move value from instruction memory pointed by addressing register
+// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
+void ilrri(const UDSPInstruction& opc)
+{
+ u16 reg = opc.hex & 0x3;
+ u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
+
+ g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
+
+ dsp_increment_addr_reg(reg);
+}
+
+// ILRRN $acD.m, @$arS
+// 0000 001d 0001 11ss
+// Move value from instruction memory pointed by addressing register
+// $arS to mid accumulator register $acD.m. Add corresponding indexing
+// register $ixS to addressing register $arS.
+void ilrrn(const UDSPInstruction& opc)
+{
+ u16 reg = opc.hex & 0x3;
+ u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1);
+
+ g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]);
+
+ // g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg];
+ dsp_increase_addr_reg(reg, (s16)g_dsp.r[DSP_REG_IX0 + reg]);
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DspIntMisc.cpp b/Source/Core/DSPCore/Src/DspIntMisc.cpp
index df60210d98..3b9deee559 100644
--- a/Source/Core/DSPCore/Src/DspIntMisc.cpp
+++ b/Source/Core/DSPCore/Src/DspIntMisc.cpp
@@ -1,202 +1,202 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-#include "DSPInterpreter.h"
-
-#include "DSPCore.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-void unknown(const UDSPInstruction& opc)
-{
- //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
- ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc);
-}
-
-// MRR $D, $S
-// 0001 11dd ddds ssss
-// Move value from register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
-void mrr(const UDSPInstruction& opc)
-{
- u8 sreg = opc.hex & 0x1f;
- u8 dreg = (opc.hex >> 5) & 0x1f;
-
- u16 val = dsp_op_read_reg(sreg);
- dsp_op_write_reg(dreg, val);
-}
-
-// LRI $D, #I
-// 0000 0000 100d dddd
-// iiii iiii iiii iiii
-// Load immediate value I to register $D.
-// FIXME: Perform additional operation depending on destination register.
-
-// DSPSpy discovery: This, and possibly other instructions that load a register,
-// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended
-// to the whole accumulator! This does not happen in S16 mode.
-void lri(const UDSPInstruction& opc)
-{
- u8 reg = opc.hex & DSP_REG_MASK;
- u16 imm = dsp_fetch_code();
- dsp_op_write_reg(reg, imm);
- dsp_conditional_extend_accum(reg);
-}
-
-// LRIS $(0x18+D), #I
-// 0000 1ddd iiii iiii
-// Load immediate value I (8-bit sign extended) to accumulator register.
-// FIXME: Perform additional operation depending on destination register.
-void lris(const UDSPInstruction& opc)
-{
- u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0;
- u16 imm = (s8)opc.hex;
- dsp_op_write_reg(reg, imm);
- dsp_conditional_extend_accum(reg);
-}
-
-
-// TSTAXL $acR
-// 1000 r001 xxxx xxxx
-// r specifies one of the main accumulators.
-// Definitely not a test instruction - it changes the accums.
-// Not affected by m0/m2. Not affected by s16/s40.
-void tstaxl(const UDSPInstruction& opc)
-{
- // This is probably all wrong.
- //u8 reg = (opc.hex >> 8) & 0x1;
- //s16 val = dsp_get_ax_l(reg);
- //Update_SR_Register16(val);
-}
-
-// ADDARN $arD, $ixS
-// 0000 0000 0001 ssdd
-// Adds indexing register $ixS to an addressing register $arD.
-void addarn(const UDSPInstruction& opc)
-{
- u8 dreg = opc.hex & 0x3;
- u8 sreg = (opc.hex >> 2) & 0x3;
-
- // g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg];
-
- dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
-
- // It is critical for the Zelda ucode that this one wraps correctly.
-}
-
-// NX
-// 1000 -000 xxxx xxxx
-// No operation, but can be extended with extended opcode.
-void nx(const UDSPInstruction& opc)
-{
- // This opcode is supposed to do nothing - it's used if you want to use
- // an opcode extension but not do anything. At least according to duddie.
-}
-
-//-------------------------------------------------------------
-// DAR $arD ?
-// 0000 0000 0000 01dd
-// Decrement address register $arD.
-void dar(const UDSPInstruction& opc)
-{
- dsp_decrement_addr_reg(opc.hex & 0x3);
-}
-
-// IAR $arD ?
-// 0000 0000 0000 10dd
-// Increment address register $arD.
-void iar(const UDSPInstruction& opc)
-{
- dsp_increment_addr_reg(opc.hex & 0x3);
-}
-
-// SBCLR #I
-// 0001 0011 0000 0iii
-// bit of status register $sr. Bit number is calculated by adding 6 to
-// immediate value I.
-void sbclr(const UDSPInstruction& opc)
-{
- u8 bit = (opc.hex & 0xff) + 6;
- g_dsp.r[DSP_REG_SR] &= ~(1 << bit);
-}
-
-// SBSET #I
-// 0001 0010 0000 0iii
-// Set bit of status register $sr. Bit number is calculated by adding 6 to
-// immediate value I.
-void sbset(const UDSPInstruction& opc)
-{
- u8 bit = (opc.hex & 0xff) + 6;
- g_dsp.r[DSP_REG_SR] |= (1 << bit);
-}
-
-
-// FIXME inside
-// This is a bunch of flag setters, flipping bits in SR. So far so good,
-// but it's harder to know exactly what effect they have.
-// M0/M2 change the multiplier mode (it can multiply by 2 for free).
-//
-// SET16 changes something very important: see the LRI instruction above.
-// Hermes' demo sets the following defaults:
-// SET40
-// CLR15
-// M0
-void srbith(const UDSPInstruction& opc)
-{
- switch ((opc.hex >> 8) & 0xf)
- {
- // M0 seems to be the default. M2 is used in functions in Zelda
- // and then reset with M0 at the end. Like the other bits here, it's
- // done around loops with lots of multiplications.
- // I've confirmed with DSPSpy that they flip this bit.
- case 0xa: // M2
- g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY;
- break;
- case 0xb: // M0
- g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY;
- break;
-
- // If set, treat multiplicands as unsigned.
- // If clear, treat them as signed.
- case 0xc: // CLR15
- g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED;
- break;
- case 0xd: // SET15
- g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED;
- break;
-
- // Automatic 40-bit sign extension when loading ACx.M.
- // 40 seems to be the default.
- // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting.
- case 0xe: // SET16 (really, clear SR's 0x4000)
- g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT;
- break;
-
- case 0xf: // SET40 (really, set SR's 0x4000)
- g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT;
- break;
-
- default:
- break;
- }
-}
-
-} // namespace
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+
+#include "DSPInterpreter.h"
+
+#include "DSPCore.h"
+#include "DSPIntUtil.h"
+
+namespace DSPInterpreter {
+
+void unknown(const UDSPInstruction& opc)
+{
+ //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception");
+ ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc);
+}
+
+// MRR $D, $S
+// 0001 11dd ddds ssss
+// Move value from register $S to register $D.
+// FIXME: Perform additional operation depending on destination register.
+void mrr(const UDSPInstruction& opc)
+{
+ u8 sreg = opc.hex & 0x1f;
+ u8 dreg = (opc.hex >> 5) & 0x1f;
+
+ u16 val = dsp_op_read_reg(sreg);
+ dsp_op_write_reg(dreg, val);
+}
+
+// LRI $D, #I
+// 0000 0000 100d dddd
+// iiii iiii iiii iiii
+// Load immediate value I to register $D.
+// FIXME: Perform additional operation depending on destination register.
+
+// DSPSpy discovery: This, and possibly other instructions that load a register,
+// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended
+// to the whole accumulator! This does not happen in S16 mode.
+void lri(const UDSPInstruction& opc)
+{
+ u8 reg = opc.hex & DSP_REG_MASK;
+ u16 imm = dsp_fetch_code();
+ dsp_op_write_reg(reg, imm);
+ dsp_conditional_extend_accum(reg);
+}
+
+// LRIS $(0x18+D), #I
+// 0000 1ddd iiii iiii
+// Load immediate value I (8-bit sign extended) to accumulator register.
+// FIXME: Perform additional operation depending on destination register.
+void lris(const UDSPInstruction& opc)
+{
+ u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0;
+ u16 imm = (s8)opc.hex;
+ dsp_op_write_reg(reg, imm);
+ dsp_conditional_extend_accum(reg);
+}
+
+
+// TSTAXL $acR
+// 1000 r001 xxxx xxxx
+// r specifies one of the main accumulators.
+// Definitely not a test instruction - it changes the accums.
+// Not affected by m0/m2. Not affected by s16/s40.
+void tstaxl(const UDSPInstruction& opc)
+{
+ // This is probably all wrong.
+ //u8 reg = (opc.hex >> 8) & 0x1;
+ //s16 val = dsp_get_ax_l(reg);
+ //Update_SR_Register16(val);
+}
+
+// ADDARN $arD, $ixS
+// 0000 0000 0001 ssdd
+// Adds indexing register $ixS to an addressing register $arD.
+void addarn(const UDSPInstruction& opc)
+{
+ u8 dreg = opc.hex & 0x3;
+ u8 sreg = (opc.hex >> 2) & 0x3;
+
+ // g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg];
+
+ dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
+
+ // It is critical for the Zelda ucode that this one wraps correctly.
+}
+
+// NX
+// 1000 -000 xxxx xxxx
+// No operation, but can be extended with extended opcode.
+void nx(const UDSPInstruction& opc)
+{
+ // This opcode is supposed to do nothing - it's used if you want to use
+ // an opcode extension but not do anything. At least according to duddie.
+}
+
+//-------------------------------------------------------------
+// DAR $arD ?
+// 0000 0000 0000 01dd
+// Decrement address register $arD.
+void dar(const UDSPInstruction& opc)
+{
+ dsp_decrement_addr_reg(opc.hex & 0x3);
+}
+
+// IAR $arD ?
+// 0000 0000 0000 10dd
+// Increment address register $arD.
+void iar(const UDSPInstruction& opc)
+{
+ dsp_increment_addr_reg(opc.hex & 0x3);
+}
+
+// SBCLR #I
+// 0001 0011 0000 0iii
+// bit of status register $sr. Bit number is calculated by adding 6 to
+// immediate value I.
+void sbclr(const UDSPInstruction& opc)
+{
+ u8 bit = (opc.hex & 0xff) + 6;
+ g_dsp.r[DSP_REG_SR] &= ~(1 << bit);
+}
+
+// SBSET #I
+// 0001 0010 0000 0iii
+// Set bit of status register $sr. Bit number is calculated by adding 6 to
+// immediate value I.
+void sbset(const UDSPInstruction& opc)
+{
+ u8 bit = (opc.hex & 0xff) + 6;
+ g_dsp.r[DSP_REG_SR] |= (1 << bit);
+}
+
+
+// FIXME inside
+// This is a bunch of flag setters, flipping bits in SR. So far so good,
+// but it's harder to know exactly what effect they have.
+// M0/M2 change the multiplier mode (it can multiply by 2 for free).
+//
+// SET16 changes something very important: see the LRI instruction above.
+// Hermes' demo sets the following defaults:
+// SET40
+// CLR15
+// M0
+void srbith(const UDSPInstruction& opc)
+{
+ switch ((opc.hex >> 8) & 0xf)
+ {
+ // M0 seems to be the default. M2 is used in functions in Zelda
+ // and then reset with M0 at the end. Like the other bits here, it's
+ // done around loops with lots of multiplications.
+ // I've confirmed with DSPSpy that they flip this bit.
+ case 0xa: // M2
+ g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY;
+ break;
+ case 0xb: // M0
+ g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY;
+ break;
+
+ // If set, treat multiplicands as unsigned.
+ // If clear, treat them as signed.
+ case 0xc: // CLR15
+ g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED;
+ break;
+ case 0xd: // SET15
+ g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED;
+ break;
+
+ // Automatic 40-bit sign extension when loading ACx.M.
+ // 40 seems to be the default.
+ // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting.
+ case 0xe: // SET16 (really, clear SR's 0x4000)
+ g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT;
+ break;
+
+ case 0xf: // SET40 (really, set SR's 0x4000)
+ g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT;
+ break;
+
+ default:
+ break;
+ }
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp
index bf2e29fd62..13167e6fae 100644
--- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp
+++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp
@@ -1,502 +1,502 @@
-// 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/
-
-// Additional copyrights go to Duddie and Tratax (c) 2004
-
-
-// Multiplier and product register control
-
-#include "DSPInterpreter.h"
-
-#include "DSPIntCCUtil.h"
-#include "DSPIntUtil.h"
-
-namespace DSPInterpreter {
-
-// Sets prod as a side effect.
-// Only MULX family instructions have unsigned support.
-s64 dsp_multiply_conditional_unsigned(u16 a, u16 b)
-{
- s64 prod;
-#if 0 // Makes games sound horrible. TODO: activate and figure out why - it's been verified through DSPSpy :/
- if (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)
- prod = (u64)a * (u64)b; // won't overflow 32-bits
- else
-#endif
- prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-// Sets prod as a side effect.
-s64 dsp_multiply(u16 a, u16 b)
-{
- s64 prod;
- prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-s64 dsp_multiply_add(u16 a, u16 b)
-{
- s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Add the original prod value.
- prod += dsp_get_long_prod();
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-s64 dsp_multiply_sub(u16 a, u16 b)
-{
- s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
-
- // Conditionally multiply by 2.
- if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
- prod <<= 1;
-
- // Subtract from the original prod value.
- prod = dsp_get_long_prod() - prod;
-
- // Store the product, and return it, in case the caller wants to read it.
- dsp_set_long_prod(prod);
- return prod;
-}
-
-
-
-// CLRP
-// 1000 0100 xxxx xxxx
-// Clears product register $prod.
-void clrp(const UDSPInstruction& opc)
-{
- // Magic numbers taken from duddie's doc
- // These are probably a bad idea to put here.
- g_dsp.r[0x14] = 0x0000;
- g_dsp.r[0x15] = 0xfff0;
- g_dsp.r[0x16] = 0x00ff;
- g_dsp.r[0x17] = 0x0010;
-}
-
-// MOVP $acD
-// 0110 111d xxxx xxxx
-// Moves multiply product from $prod register to accumulator $acD register.
-void movp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_get_long_prod();
- dsp_set_long_acc(dreg, prod);
-
- Update_SR_Register64(prod);
-}
-
-// MOVNP $acD
-// 0111 111d xxxx xxxx
-// Moves negative of multiply product from $prod register to accumulator
-// $acD register.
-void movnp(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_get_long_prod();
- s64 acc = -prod;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// ADDPAXZ $acD, $axS
-// 1111 10sd xxxx xxxx
-// Adds secondary accumulator $axS to product register and stores result
-// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0.
-void addpaxz(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x1;
- u8 sreg = (opc.hex >> 9) & 0x1;
-
- s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here?
- s64 ax = dsp_get_long_acx(sreg);
- s64 acc = (prod + ax) & ~0xffff;
-
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MOVPZ $acD
-// 1111 111d xxxx xxxx
-// Moves multiply product from $prod register to accumulator $acD
-// register and sets $acD.l to 0
-void movpz(const UDSPInstruction& opc)
-{
- u8 dreg = (opc.hex >> 8) & 0x01;
-
- // overwrite acc and clear low part
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(dreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// MULC $acS.m, $axT.h
-// 110s t000 xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axS.h of
-// secondary accumulator $axS (treat them both as signed).
-void mulc(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- u8 treg = (opc.hex >> 12) & 0x1;
- s64 prod = dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MULCMVZ $acS.m, $axT.h, $acR
-// 110s t01r xxxx xxxx
-// (fixed possible bug in duddie's description, s->t)
-// Multiply mid part of accumulator register $acS.m by high part $axT.h of
-// secondary accumulator $axT (treat them both as signed). Move product
-// register before multiplication to accumulator $acR, set low part of
-// accumulator $acR.l to zero.
-void mulcmvz(const UDSPInstruction& opc)
-{
- s64 TempProd = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acc = TempProd & ~0xffff; // clear lower 4 bytes
- dsp_set_long_acc(rreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-// MULCMV $acS.m, $axT.h, $acR
-// 110s t11r xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axT.h of
-// secondary accumulator $axT (treat them both as signed). Move product
-// register before multiplication to accumulator $acR.
-// possible mistake in duddie's doc axT.h rather than axS.h
-void mulcmv(const UDSPInstruction& opc)
-{
- s64 old_prod = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- dsp_set_long_acc(rreg, old_prod);
-
- Update_SR_Register64(old_prod);
-}
-
-// MULCAC $acS.m, $axT.h, $acR
-// 110s t10r xxxx xxxx
-// Multiply mid part of accumulator register $acS.m by high part $axS.h of
-// secondary accumulator $axS (treat them both as signed). Add product
-// register before multiplication to accumulator $acR.
-void mulcac(const UDSPInstruction& opc)
-{
- s64 old_prod = dsp_get_long_prod();
-
- // update prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
- dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
-
- // update acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acc = old_prod + dsp_get_long_acc(rreg);
- dsp_set_long_acc(rreg, acc);
-
- Update_SR_Register64(acc);
-}
-
-
-// MUL $axS.l, $axS.h
-// 1001 s000 xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed).
-void mul(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- s64 prod = dsp_multiply(dsp_get_ax_h(sreg), dsp_get_ax_l(sreg));
- // FIXME: no update in duddie's docs
- Update_SR_Register64(prod);
-}
-
-// MULAC $axS.l, $axS.h, $acR
-// 1001 s10r xxxx xxxx
-// Add product register to accumulator register $acR. Multiply low part
-// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
-// accumulator $axS (treat them both as signed).
-void mulac(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // calculate new prod
- u8 sreg = (opc.hex >> 11) & 0x1;
- s64 prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
-
- // FIXME: no update in duddie's docs
- Update_SR_Register64(prod);
-}
-
-// MULMV $axS.l, $axS.h, $acR
-// 1001 s11r xxxx xxxx
-// Move product register to accumulator register $acR. Multiply low part
-// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
-// accumulator $axS (treat them both as signed).
-void mulmv(const UDSPInstruction& opc)
-{
- u8 rreg = (opc.hex >> 8) & 0x1;
- u8 sreg = ((opc.hex >> 11) & 0x1);
- s64 prod = dsp_get_long_prod();
- s64 acc = prod;
- dsp_set_long_acc(rreg, acc);
-
- prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MULMVZ $axS.l, $axS.h, $acR
-// 1001 s01r xxxx xxxx
-// Move product register to accumulator register $acR and clear low part
-// of accumulator register $acR.l. Multiply low part $axS.l of secondary
-// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat
-// them both as signed).
-void mulmvz(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 11) & 0x1;
- u8 rreg = (opc.hex >> 8) & 0x1;
-
- // overwrite acc and clear low part
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(rreg, acc);
-
- // math prod
- prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MULX $ax0.S, $ax1.T
-// 101s t000 xxxx xxxx
-// Multiply one part $ax0 by one part $ax1 (treat them both as signed).
-// Part is selected by S and T bits. Zero selects low part, one selects high part.
-void mulx(const UDSPInstruction& opc)
-{
- u8 sreg = ((opc.hex >> 12) & 0x1);
- u8 treg = ((opc.hex >> 11) & 0x1);
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXAC $ax0.S, $ax1.T, $acR
-// 101s t01r xxxx xxxx
-// Add product register to accumulator register $acR. Multiply one part
-// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
-// T bits. Zero selects low part, one selects high part.
-void mulxac(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // math new prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXMV $ax0.S, $ax1.T, $acR
-// 101s t11r xxxx xxxx
-// Move product register to accumulator register $acR. Multiply one part
-// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
-// T bits. Zero selects low part, one selects high part.
-void mulxmv(const UDSPInstruction& opc)
-{
- // add old prod to acc
- u8 rreg = ((opc.hex >> 8) & 0x1);
- s64 acR = dsp_get_long_prod();
- dsp_set_long_acc(rreg, acR);
-
- // math new prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MULXMV $ax0.S, $ax1.T, $acR
-// 101s t01r xxxx xxxx
-// Move product register to accumulator register $acR and clear low part
-// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat
-// them both as signed). Part is selected by S and T bits. Zero selects low part,
-// one selects high part.
-void mulxmvz(const UDSPInstruction& opc)
-{
- // overwrite acc and clear low part
- u8 rreg = (opc.hex >> 8) & 0x1;
- s64 prod = dsp_get_long_prod();
- s64 acc = prod & ~0xffff;
- dsp_set_long_acc(rreg, acc);
-
- // math prod
- u8 sreg = (opc.hex >> 12) & 0x1;
- u8 treg = (opc.hex >> 11) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- prod = dsp_multiply_conditional_unsigned(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MADDX ax0.S ax1.T
-// 1110 00st xxxx xxxx
-// Multiply one part of secondary accumulator $ax0 (selected by S) by
-// one part of secondary accumulator $ax1 (selected by T) (treat them both as
-// signed) and add result to product register.
-void maddx(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 treg = (opc.hex >> 8) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_add(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MSUBX $(0x18+S*2), $(0x19+T*2)
-// 1110 01st xxxx xxxx
-// Multiply one part of secondary accumulator $ax0 (selected by S) by
-// one part of secondary accumulator $ax1 (selected by T) (treat them both as
-// signed) and subtract result from product register.
-void msubx(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 9) & 0x1;
- u8 treg = (opc.hex >> 8) & 0x1;
-
- u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
- u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
-
- s64 prod = dsp_multiply_sub(val1, val2);
- Update_SR_Register64(prod);
-}
-
-// MADDC $acS.m, $axT.h
-// 1110 10st xxxx xxxx
-// Multiply middle part of accumulator $acS.m by high part of secondary
-// accumulator $axT.h (treat them both as signed) and add result to product
-// register.
-void maddc(const UDSPInstruction& opc)
-{
- u32 sreg = (opc.hex >> 9) & 0x1;
- u32 treg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_add(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MSUBC $acS.m, $axT.h
-// 1110 11st xxxx xxxx
-// Multiply middle part of accumulator $acS.m by high part of secondary
-// accumulator $axT.h (treat them both as signed) and subtract result from
-// product register.
-void msubc(const UDSPInstruction& opc)
-{
- u32 sreg = (opc.hex >> 9) & 0x1;
- u32 treg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_sub(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
- Update_SR_Register64(prod);
-}
-
-// MADD $axS.l, $axS.h
-// 1111 001s xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed) and add
-// result to product register.
-void madd(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_add(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-// MSUB $axS.l, $axS.h
-// 1111 011s xxxx xxxx
-// Multiply low part $axS.l of secondary accumulator $axS by high part
-// $axS.h of secondary accumulator $axS (treat them both as signed) and
-// subtract result from product register.
-void msub(const UDSPInstruction& opc)
-{
- u8 sreg = (opc.hex >> 8) & 0x1;
-
- s64 prod = dsp_multiply_sub(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
- Update_SR_Register64(prod);
-}
-
-} // namespace
+// 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/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+
+// Multiplier and product register control
+
+#include "DSPInterpreter.h"
+
+#include "DSPIntCCUtil.h"
+#include "DSPIntUtil.h"
+
+namespace DSPInterpreter {
+
+// Sets prod as a side effect.
+// Only MULX family instructions have unsigned support.
+s64 dsp_multiply_conditional_unsigned(u16 a, u16 b)
+{
+ s64 prod;
+#if 0 // Makes games sound horrible. TODO: activate and figure out why - it's been verified through DSPSpy :/
+ if (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)
+ prod = (u64)a * (u64)b; // won't overflow 32-bits
+ else
+#endif
+ prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
+
+ // Conditionally multiply by 2.
+ if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
+ prod <<= 1;
+
+ // Store the product, and return it, in case the caller wants to read it.
+ dsp_set_long_prod(prod);
+ return prod;
+}
+
+// Sets prod as a side effect.
+s64 dsp_multiply(u16 a, u16 b)
+{
+ s64 prod;
+ prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
+
+ // Conditionally multiply by 2.
+ if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
+ prod <<= 1;
+
+ // Store the product, and return it, in case the caller wants to read it.
+ dsp_set_long_prod(prod);
+ return prod;
+}
+
+s64 dsp_multiply_add(u16 a, u16 b)
+{
+ s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
+
+ // Conditionally multiply by 2.
+ if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
+ prod <<= 1;
+
+ // Add the original prod value.
+ prod += dsp_get_long_prod();
+
+ // Store the product, and return it, in case the caller wants to read it.
+ dsp_set_long_prod(prod);
+ return prod;
+}
+
+s64 dsp_multiply_sub(u16 a, u16 b)
+{
+ s64 prod = (s32)(s16)a * (s32)(s16)b; // won't overflow 32-bits
+
+ // Conditionally multiply by 2.
+ if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
+ prod <<= 1;
+
+ // Subtract from the original prod value.
+ prod = dsp_get_long_prod() - prod;
+
+ // Store the product, and return it, in case the caller wants to read it.
+ dsp_set_long_prod(prod);
+ return prod;
+}
+
+
+
+// CLRP
+// 1000 0100 xxxx xxxx
+// Clears product register $prod.
+void clrp(const UDSPInstruction& opc)
+{
+ // Magic numbers taken from duddie's doc
+ // These are probably a bad idea to put here.
+ g_dsp.r[0x14] = 0x0000;
+ g_dsp.r[0x15] = 0xfff0;
+ g_dsp.r[0x16] = 0x00ff;
+ g_dsp.r[0x17] = 0x0010;
+}
+
+// MOVP $acD
+// 0110 111d xxxx xxxx
+// Moves multiply product from $prod register to accumulator $acD register.
+void movp(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ s64 prod = dsp_get_long_prod();
+ dsp_set_long_acc(dreg, prod);
+
+ Update_SR_Register64(prod);
+}
+
+// MOVNP $acD
+// 0111 111d xxxx xxxx
+// Moves negative of multiply product from $prod register to accumulator
+// $acD register.
+void movnp(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+
+ s64 prod = dsp_get_long_prod();
+ s64 acc = -prod;
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// ADDPAXZ $acD, $axS
+// 1111 10sd xxxx xxxx
+// Adds secondary accumulator $axS to product register and stores result
+// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0.
+void addpaxz(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x1;
+ u8 sreg = (opc.hex >> 9) & 0x1;
+
+ s64 prod = dsp_get_long_prod() & ~0xffff; // hm, should we really mask here?
+ s64 ax = dsp_get_long_acx(sreg);
+ s64 acc = (prod + ax) & ~0xffff;
+
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// MOVPZ $acD
+// 1111 111d xxxx xxxx
+// Moves multiply product from $prod register to accumulator $acD
+// register and sets $acD.l to 0
+void movpz(const UDSPInstruction& opc)
+{
+ u8 dreg = (opc.hex >> 8) & 0x01;
+
+ // overwrite acc and clear low part
+ s64 prod = dsp_get_long_prod();
+ s64 acc = prod & ~0xffff;
+ dsp_set_long_acc(dreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+
+// MULC $acS.m, $axT.h
+// 110s t000 xxxx xxxx
+// Multiply mid part of accumulator register $acS.m by high part $axS.h of
+// secondary accumulator $axS (treat them both as signed).
+void mulc(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 11) & 0x1;
+ u8 treg = (opc.hex >> 12) & 0x1;
+ s64 prod = dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
+ Update_SR_Register64(prod);
+}
+
+// MULCMVZ $acS.m, $axT.h, $acR
+// 110s t01r xxxx xxxx
+// (fixed possible bug in duddie's description, s->t)
+// Multiply mid part of accumulator register $acS.m by high part $axT.h of
+// secondary accumulator $axT (treat them both as signed). Move product
+// register before multiplication to accumulator $acR, set low part of
+// accumulator $acR.l to zero.
+void mulcmvz(const UDSPInstruction& opc)
+{
+ s64 TempProd = dsp_get_long_prod();
+
+ // update prod
+ u8 sreg = (opc.hex >> 12) & 0x1;
+ u8 treg = (opc.hex >> 11) & 0x1;
+ dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
+
+ // update acc
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ s64 acc = TempProd & ~0xffff; // clear lower 4 bytes
+ dsp_set_long_acc(rreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+// MULCMV $acS.m, $axT.h, $acR
+// 110s t11r xxxx xxxx
+// Multiply mid part of accumulator register $acS.m by high part $axT.h of
+// secondary accumulator $axT (treat them both as signed). Move product
+// register before multiplication to accumulator $acR.
+// possible mistake in duddie's doc axT.h rather than axS.h
+void mulcmv(const UDSPInstruction& opc)
+{
+ s64 old_prod = dsp_get_long_prod();
+
+ // update prod
+ u8 sreg = (opc.hex >> 12) & 0x1;
+ u8 treg = (opc.hex >> 11) & 0x1;
+ dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
+
+ // update acc
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ dsp_set_long_acc(rreg, old_prod);
+
+ Update_SR_Register64(old_prod);
+}
+
+// MULCAC $acS.m, $axT.h, $acR
+// 110s t10r xxxx xxxx
+// Multiply mid part of accumulator register $acS.m by high part $axS.h of
+// secondary accumulator $axS (treat them both as signed). Add product
+// register before multiplication to accumulator $acR.
+void mulcac(const UDSPInstruction& opc)
+{
+ s64 old_prod = dsp_get_long_prod();
+
+ // update prod
+ u8 sreg = (opc.hex >> 12) & 0x1;
+ u8 treg = (opc.hex >> 11) & 0x1;
+ dsp_multiply(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
+
+ // update acc
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ s64 acc = old_prod + dsp_get_long_acc(rreg);
+ dsp_set_long_acc(rreg, acc);
+
+ Update_SR_Register64(acc);
+}
+
+
+// MUL $axS.l, $axS.h
+// 1001 s000 xxxx xxxx
+// Multiply low part $axS.l of secondary accumulator $axS by high part
+// $axS.h of secondary accumulator $axS (treat them both as signed).
+void mul(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 11) & 0x1;
+ s64 prod = dsp_multiply(dsp_get_ax_h(sreg), dsp_get_ax_l(sreg));
+ // FIXME: no update in duddie's docs
+ Update_SR_Register64(prod);
+}
+
+// MULAC $axS.l, $axS.h, $acR
+// 1001 s10r xxxx xxxx
+// Add product register to accumulator register $acR. Multiply low part
+// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
+// accumulator $axS (treat them both as signed).
+void mulac(const UDSPInstruction& opc)
+{
+ // add old prod to acc
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
+ dsp_set_long_acc(rreg, acR);
+
+ // calculate new prod
+ u8 sreg = (opc.hex >> 11) & 0x1;
+ s64 prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
+
+ // FIXME: no update in duddie's docs
+ Update_SR_Register64(prod);
+}
+
+// MULMV $axS.l, $axS.h, $acR
+// 1001 s11r xxxx xxxx
+// Move product register to accumulator register $acR. Multiply low part
+// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
+// accumulator $axS (treat them both as signed).
+void mulmv(const UDSPInstruction& opc)
+{
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ u8 sreg = ((opc.hex >> 11) & 0x1);
+ s64 prod = dsp_get_long_prod();
+ s64 acc = prod;
+ dsp_set_long_acc(rreg, acc);
+
+ prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
+ Update_SR_Register64(prod);
+}
+
+// MULMVZ $axS.l, $axS.h, $acR
+// 1001 s01r xxxx xxxx
+// Move product register to accumulator register $acR and clear low part
+// of accumulator register $acR.l. Multiply low part $axS.l of secondary
+// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat
+// them both as signed).
+void mulmvz(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 11) & 0x1;
+ u8 rreg = (opc.hex >> 8) & 0x1;
+
+ // overwrite acc and clear low part
+ s64 prod = dsp_get_long_prod();
+ s64 acc = prod & ~0xffff;
+ dsp_set_long_acc(rreg, acc);
+
+ // math prod
+ prod = dsp_multiply(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
+ Update_SR_Register64(prod);
+}
+
+// MULX $ax0.S, $ax1.T
+// 101s t000 xxxx xxxx
+// Multiply one part $ax0 by one part $ax1 (treat them both as signed).
+// Part is selected by S and T bits. Zero selects low part, one selects high part.
+void mulx(const UDSPInstruction& opc)
+{
+ u8 sreg = ((opc.hex >> 12) & 0x1);
+ u8 treg = ((opc.hex >> 11) & 0x1);
+
+ u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+ u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+
+ s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
+ Update_SR_Register64(prod);
+}
+
+// MULXAC $ax0.S, $ax1.T, $acR
+// 101s t01r xxxx xxxx
+// Add product register to accumulator register $acR. Multiply one part
+// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
+// T bits. Zero selects low part, one selects high part.
+void mulxac(const UDSPInstruction& opc)
+{
+ // add old prod to acc
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod();
+ dsp_set_long_acc(rreg, acR);
+
+ // math new prod
+ u8 sreg = (opc.hex >> 12) & 0x1;
+ u8 treg = (opc.hex >> 11) & 0x1;
+
+ u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+ u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+
+ s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
+ Update_SR_Register64(prod);
+}
+
+// MULXMV $ax0.S, $ax1.T, $acR
+// 101s t11r xxxx xxxx
+// Move product register to accumulator register $acR. Multiply one part
+// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and
+// T bits. Zero selects low part, one selects high part.
+void mulxmv(const UDSPInstruction& opc)
+{
+ // add old prod to acc
+ u8 rreg = ((opc.hex >> 8) & 0x1);
+ s64 acR = dsp_get_long_prod();
+ dsp_set_long_acc(rreg, acR);
+
+ // math new prod
+ u8 sreg = (opc.hex >> 12) & 0x1;
+ u8 treg = (opc.hex >> 11) & 0x1;
+
+ s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+ s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+
+ s64 prod = dsp_multiply_conditional_unsigned(val1, val2);
+ Update_SR_Register64(prod);
+}
+
+// MULXMV $ax0.S, $ax1.T, $acR
+// 101s t01r xxxx xxxx
+// Move product register to accumulator register $acR and clear low part
+// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat
+// them both as signed). Part is selected by S and T bits. Zero selects low part,
+// one selects high part.
+void mulxmvz(const UDSPInstruction& opc)
+{
+ // overwrite acc and clear low part
+ u8 rreg = (opc.hex >> 8) & 0x1;
+ s64 prod = dsp_get_long_prod();
+ s64 acc = prod & ~0xffff;
+ dsp_set_long_acc(rreg, acc);
+
+ // math prod
+ u8 sreg = (opc.hex >> 12) & 0x1;
+ u8 treg = (opc.hex >> 11) & 0x1;
+
+ u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+ u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+
+ prod = dsp_multiply_conditional_unsigned(val1, val2);
+ Update_SR_Register64(prod);
+}
+
+// MADDX ax0.S ax1.T
+// 1110 00st xxxx xxxx
+// Multiply one part of secondary accumulator $ax0 (selected by S) by
+// one part of secondary accumulator $ax1 (selected by T) (treat them both as
+// signed) and add result to product register.
+void maddx(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 9) & 0x1;
+ u8 treg = (opc.hex >> 8) & 0x1;
+
+ u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+ u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+
+ s64 prod = dsp_multiply_add(val1, val2);
+ Update_SR_Register64(prod);
+}
+
+// MSUBX $(0x18+S*2), $(0x19+T*2)
+// 1110 01st xxxx xxxx
+// Multiply one part of secondary accumulator $ax0 (selected by S) by
+// one part of secondary accumulator $ax1 (selected by T) (treat them both as
+// signed) and subtract result from product register.
+void msubx(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 9) & 0x1;
+ u8 treg = (opc.hex >> 8) & 0x1;
+
+ u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+ u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+
+ s64 prod = dsp_multiply_sub(val1, val2);
+ Update_SR_Register64(prod);
+}
+
+// MADDC $acS.m, $axT.h
+// 1110 10st xxxx xxxx
+// Multiply middle part of accumulator $acS.m by high part of secondary
+// accumulator $axT.h (treat them both as signed) and add result to product
+// register.
+void maddc(const UDSPInstruction& opc)
+{
+ u32 sreg = (opc.hex >> 9) & 0x1;
+ u32 treg = (opc.hex >> 8) & 0x1;
+
+ s64 prod = dsp_multiply_add(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
+ Update_SR_Register64(prod);
+}
+
+// MSUBC $acS.m, $axT.h
+// 1110 11st xxxx xxxx
+// Multiply middle part of accumulator $acS.m by high part of secondary
+// accumulator $axT.h (treat them both as signed) and subtract result from
+// product register.
+void msubc(const UDSPInstruction& opc)
+{
+ u32 sreg = (opc.hex >> 9) & 0x1;
+ u32 treg = (opc.hex >> 8) & 0x1;
+
+ s64 prod = dsp_multiply_sub(dsp_get_acc_m(sreg), dsp_get_ax_h(treg));
+ Update_SR_Register64(prod);
+}
+
+// MADD $axS.l, $axS.h
+// 1111 001s xxxx xxxx
+// Multiply low part $axS.l of secondary accumulator $axS by high part
+// $axS.h of secondary accumulator $axS (treat them both as signed) and add
+// result to product register.
+void madd(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 8) & 0x1;
+
+ s64 prod = dsp_multiply_add(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
+ Update_SR_Register64(prod);
+}
+
+// MSUB $axS.l, $axS.h
+// 1111 011s xxxx xxxx
+// Multiply low part $axS.l of secondary accumulator $axS by high part
+// $axS.h of secondary accumulator $axS (treat them both as signed) and
+// subtract result from product register.
+void msub(const UDSPInstruction& opc)
+{
+ u8 sreg = (opc.hex >> 8) & 0x1;
+
+ s64 prod = dsp_multiply_sub(dsp_get_ax_l(sreg), dsp_get_ax_h(sreg));
+ Update_SR_Register64(prod);
+}
+
+} // namespace
diff --git a/Source/Core/DSPCore/Src/LabelMap.cpp b/Source/Core/DSPCore/Src/LabelMap.cpp
index 6d3a475857..2765d302b9 100644
--- a/Source/Core/DSPCore/Src/LabelMap.cpp
+++ b/Source/Core/DSPCore/Src/LabelMap.cpp
@@ -1,85 +1,85 @@
-// 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++)
- {
- if (regnames[i].name)
- RegisterLabel(regnames[i].name, regnames[i].addr);
- }
- for (int i = 0; i < (int)pdlabels_size; i++)
- {
- if (pdlabels[i].name)
- RegisterLabel(pdlabels[i].name, pdlabels[i].addr);
- }
-}
-
-void LabelMap::RegisterLabel(const std::string &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.c_str(), lval, old_value);
- DeleteLabel(label);
- }
- labels.push_back(label_t(label, lval, type));
-}
-
-void LabelMap::DeleteLabel(const std::string &label)
-{
- for (std::vector<label_t>::iterator iter = labels.begin();
- iter != labels.end(); ++iter)
- {
- if (!label.compare(iter->name))
- {
- labels.erase(iter);
- return;
- }
- }
-}
-
-bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const
-{
- for (u32 i = 0; i < labels.size(); i++)
- {
- if (!label.compare(labels[i].name))
- {
- if (type & labels[i].type) {
- *value = labels[i].addr;
- return true;
- } else {
- printf("WARNING: Wrong label type requested. %s\n", label.c_str());
- }
- }
- }
- return false;
-}
-
-void LabelMap::Clear()
-{
- labels.clear();
-}
+// 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++)
+ {
+ if (regnames[i].name)
+ RegisterLabel(regnames[i].name, regnames[i].addr);
+ }
+ for (int i = 0; i < (int)pdlabels_size; i++)
+ {
+ if (pdlabels[i].name)
+ RegisterLabel(pdlabels[i].name, pdlabels[i].addr);
+ }
+}
+
+void LabelMap::RegisterLabel(const std::string &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.c_str(), lval, old_value);
+ DeleteLabel(label);
+ }
+ labels.push_back(label_t(label, lval, type));
+}
+
+void LabelMap::DeleteLabel(const std::string &label)
+{
+ for (std::vector<label_t>::iterator iter = labels.begin();
+ iter != labels.end(); ++iter)
+ {
+ if (!label.compare(iter->name))
+ {
+ labels.erase(iter);
+ return;
+ }
+ }
+}
+
+bool LabelMap::GetLabelValue(const std::string &label, u16 *value, LabelType type) const
+{
+ for (u32 i = 0; i < labels.size(); i++)
+ {
+ if (!label.compare(labels[i].name))
+ {
+ if (type & labels[i].type) {
+ *value = labels[i].addr;
+ return true;
+ } else {
+ printf("WARNING: Wrong label type requested. %s\n", label.c_str());
+ }
+ }
+ }
+ return false;
+}
+
+void LabelMap::Clear()
+{
+ labels.clear();
+}
diff --git a/Source/Core/DSPCore/Src/LabelMap.h b/Source/Core/DSPCore/Src/LabelMap.h
index 3b37712204..6fceef7347 100644
--- a/Source/Core/DSPCore/Src/LabelMap.h
+++ b/Source/Core/DSPCore/Src/LabelMap.h
@@ -1,55 +1,55 @@
-// 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 <string>
-#include <vector>
-
-#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 std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {}
- std::string name;
- s32 addr;
- LabelType type;
- };
- std::vector<label_t> labels;
-
-public:
- LabelMap();
- ~LabelMap() { }
- void RegisterDefaults();
- void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE);
- void DeleteLabel(const std::string &label);
- bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const;
- void Clear();
-};
-
-#endif // _LABELMAP_H
+// 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 <string>
+#include <vector>
+
+#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 std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {}
+ std::string name;
+ s32 addr;
+ LabelType type;
+ };
+ std::vector<label_t> labels;
+
+public:
+ LabelMap();
+ ~LabelMap() { }
+ void RegisterDefaults();
+ void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE);
+ void DeleteLabel(const std::string &label);
+ bool GetLabelValue(const std::string &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 2f14d70381..7516b4182f 100644
--- a/Source/Core/DSPCore/Src/assemble.cpp
+++ b/Source/Core/DSPCore/Src/assemble.cpp
@@ -1,1016 +1,1016 @@
-/*====================================================================
-
-$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $
-
-project: GameCube DSP Tool (gcdsp)
-mail: duddie@walla.com
-
-Copyright (c) 2005 Duddie
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-Revision 1.4 2008/10/04 10:30:00 Hermes
-added function to export the code to .h file
-added support for '/ *' '* /' and '//' for comentaries
-added some sintax detection when use registers
-
-$Log: not supported by cvs2svn $
-Revision 1.2 2005/09/14 02:19:29 wntrmute
-added header guards
-use standard main function
-
-Revision 1.1 2005/08/24 22:13:34 wntrmute
-Initial import
-
-
-====================================================================*/
-
-#include <cstdio>
-#include <cstdlib>
-
-#include <map>
-#include <iostream>
-#include <fstream>
-
-#include "Common.h"
-#include "FileUtil.h"
-#include "DSPInterpreter.h"
-#include "DSPTables.h"
-#include "disassemble.h"
-#include "assemble.h"
-
-static const char *err_string[] =
-{
- "",
- "Unknown Error",
- "Unknown opcode",
- "Not enough parameters",
- "Too many parameters",
- "Wrong parameter",
- "Expected parameter of type 'string'",
- "Expected parameter of type 'value'",
- "Expected parameter of type 'register'",
- "Expected parameter of type 'memory pointer'",
- "Expected parameter of type 'immediate'",
- "Incorrect binary value",
- "Incorrect hexadecimal value",
- "Incorrect decimal value",
- "Label already exists",
- "Label not defined",
- "No matching brackets",
- "This opcode cannot be extended",
- "Given extending params for non extensible opcode",
- "Wrong parameter: must be accumulator register",
- "Wrong parameter: must be mid accumulator register",
- "Invalid register",
- "Number out of range"
-};
-
-DSPAssembler::DSPAssembler(const AssemblerSettings &settings) :
- m_cur_addr(0),
- m_cur_pass(0),
- m_current_param(0),
- settings_(settings),
- gdg_buffer(NULL)
-{
-}
-
-DSPAssembler::~DSPAssembler()
-{
- if(gdg_buffer)
- free(gdg_buffer);
-}
-
-bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers)
-{
- if (line_numbers)
- line_numbers->clear();
- const char *fname = "tmp.asm";
- if (!File::WriteStringToFile(true, text, fname))
- return false;
- InitPass(1);
- if (!AssembleFile(fname, 1))
- return false;
-
- // We now have the size of the output buffer
- if (m_totalSize > 0)
- {
- gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4);
- if(!gdg_buffer)
- return false;
-
- memset(gdg_buffer, 0, m_totalSize * sizeof(u16));
- } else
- return false;
-
- InitPass(2);
- if (!AssembleFile(fname, 2))
- return false;
-
- code.resize(m_totalSize);
- for (int i = 0; i < m_totalSize; i++) {
- code[i] = *(u16 *)(gdg_buffer + i * 2);
- }
-
- if(gdg_buffer) {
- free(gdg_buffer);
- gdg_buffer = NULL;
- }
-
- last_error_str = "(no errors)";
- last_error = ERR_OK;
-
- return true;
-}
-
-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 ", code_line, cur_line.c_str());
- if (!extra_info)
- extra_info = "-";
-
- if (m_current_param == 0)
- buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
- else
- buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n",
- err_string[err_code], code_line, m_current_param, extra_info);
- last_error_str = error_buffer;
- last_error = err_code;
-}
-
-char *skip_spaces(char *ptr)
-{
- while (*ptr == ' ')
- ptr++;
- return ptr;
-}
-
-const char *skip_spaces(const char *ptr)
-{
- while (*ptr == ' ')
- ptr++;
- return ptr;
-}
-
-// Parse a standalone value - it can be a number in one of several formats or a label.
-s32 DSPAssembler::ParseValue(const char *str)
-{
- bool negative = false;
- s32 val = 0;
- const char *ptr = str;
-
- if (ptr[0] == '#')
- {
- ptr++;
- negative = true; // Wow! Double # (needed one to get in here) negates???
- }
- if (ptr[0] == '-')
- {
- ptr++;
- negative = true;
- }
- if (ptr[0] == '0')
- {
- if (ptr[1] >= '0' && ptr[1] <= '9')
- {
- for (int i = 0; ptr[i] != 0; i++)
- {
- val *= 10;
- if (ptr[i] >= '0' && ptr[i] <= '9')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_DEC, str);
- }
- }
- else
- {
- switch (ptr[1])
- {
- case 'X': // hex
- for (int i = 2 ; ptr[i] != 0 ; i++)
- {
- val <<= 4;
- if (ptr[i] >= 'a' && ptr[i] <= 'f')
- val += (ptr[i]-'a'+10);
- else if (ptr[i] >= 'A' && ptr[i] <= 'F')
- val += (ptr[i]-'A'+10);
- else if (ptr[i] >= '0' && ptr[i] <= '9')
- val += (ptr[i] - '0');
- else
- ShowError(ERR_INCORRECT_HEX, str);
- }
- break;
- case '\'': // binary
- for (int i = 2; ptr[i] != 0; i++)
- {
- val *=2;
- if(ptr[i] >= '0' && ptr[i] <= '1')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_BIN, str);
- }
- break;
- default:
- // value is 0 or error
- val = 0;
- break;
- }
- }
- }
- else
- {
- // Symbol starts with a digit - it's a dec number.
- if (ptr[0] >= '0' && ptr[0] <= '9')
- {
- for (int i = 0; ptr[i] != 0; i++)
- {
- val *= 10;
- if (ptr[i] >= '0' && ptr[i] <= '9')
- val += ptr[i] - '0';
- else
- ShowError(ERR_INCORRECT_DEC, str);
- }
- }
- else // Everything else is a label.
- {
- // Lookup label
- u16 value;
- if (labels.GetLabelValue(ptr, &value))
- return value;
- if (m_cur_pass == 2)
- ShowError(ERR_UNKNOWN_LABEL, str);
- }
- }
- if (negative)
- return -val;
- return val;
-}
-
-// Modifies both src and dst!
-// What does it do, really??
-char *DSPAssembler::FindBrackets(char *src, char *dst)
-{
- s32 len = (s32) strlen(src);
- s32 first = -1;
- s32 count = 0;
- s32 i, j;
- j = 0;
- for (i = 0 ; i < len ; i++)
- {
- if (src[i] == '(')
- {
- if (first < 0)
- {
- count = 1;
- src[i] = 0x0;
- first = i;
- }
- else
- {
- count++;
- dst[j++] = src[i];
- }
- }
- else if (src[i] == ')')
- {
- if (--count == 0)
- {
- dst[j] = 0;
- return &src[i+1];
- }
- else
- {
- dst[j++] = src[i];
- }
- }
- else
- {
- if (first >= 0)
- dst[j++] = src[i];
- }
- }
- if (count)
- ShowError(ERR_NO_MATCHING_BRACKETS);
- return NULL;
-}
-
-// Bizarre in-place expression evaluator.
-u32 DSPAssembler::ParseExpression(const char *ptr)
-{
- char *pbuf;
- s32 val = 0;
-
- char *d_buffer = (char *)malloc(1024);
- char *s_buffer = (char *)malloc(1024);
- strcpy(s_buffer, ptr);
-
- while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL)
- {
- val = ParseExpression(d_buffer);
- sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf);
- strcpy(s_buffer, d_buffer);
- }
-
- int j = 0;
- for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++)
- {
- char c = s_buffer[i];
- if (c != ' ')
- d_buffer[j++] = c;
- }
-
- for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++)
- {
- char c = d_buffer[i];
- if (c == '-')
- {
- if (i == 0)
- c = '#';
- else
- {
- switch (d_buffer[i - 1])
- {
- case '/':
- case '%':
- case '*':
- c = '#';
- }
- }
- }
- d_buffer[i] = c;
- }
-
- while ((pbuf = strstr(d_buffer, "+")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) + ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "-")) != NULL)
- {
- *pbuf = 0x0;
- 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
- fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line);
- }
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "*")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) * ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "/")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) / ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "|")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) | ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- while ((pbuf = strstr(d_buffer, "&")) != NULL)
- {
- *pbuf = 0x0;
- val = ParseExpression(d_buffer) & ParseExpression(pbuf+1);
- sprintf(d_buffer, "%d", val);
- }
-
- val = ParseValue(d_buffer);
- free(d_buffer);
- free(s_buffer);
- return val;
-}
-
-// Destroys parstr
-u32 DSPAssembler::GetParams(char *parstr, param_t *par)
-{
- u32 count = 0;
- char *tmpstr = skip_spaces(parstr);
- tmpstr = strtok(tmpstr, ",\x00");
- for (int i = 0; i < 10; i++)
- {
- if (tmpstr == NULL)
- break;
- tmpstr = skip_spaces(tmpstr);
- if (strlen(tmpstr) == 0)
- break;
- if (tmpstr)
- count++;
- else
- break;
-
- par[i].type = P_NONE;
- switch (tmpstr[0])
- {
- case '"':
- par[i].str = strtok(tmpstr, "\"");
- par[i].type = P_STR;
- break;
- case '#':
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_IMM;
- break;
- case '@':
- if (tmpstr[1] == '$')
- {
- par[i].val = ParseExpression(tmpstr + 2);
- par[i].type = P_PRG;
- }
- else
- {
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_MEM;
- }
- break;
- case '$':
- par[i].val = ParseExpression(tmpstr + 1);
- par[i].type = P_REG;
- break;
-
- default:
- par[i].val = ParseExpression(tmpstr);
- par[i].type = P_VAL;
- break;
- }
- tmpstr = strtok(NULL, ",\x00");
- }
- return count;
-}
-
-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;
-
- AliasMap::const_iterator alias_iter = aliases.find(opcode);
- if (alias_iter != aliases.end())
- opcode = alias_iter->second.c_str();
- for (int i = 0; i < opcod_size; i++)
- {
- const opc_t *opc = &opcod[i];
- if (strcmp(opc->name, opcode) == 0)
- {
- if (par_count < opc->param_count)
- {
- ShowError(ERR_NOT_ENOUGH_PARAMETERS);
- }
- if (par_count > opc->param_count)
- {
- ShowError(ERR_TOO_MANY_PARAMETERS);
- }
- return opc;
- }
- }
- ShowError(ERR_UNKNOWN_OPCODE);
- return NULL;
-}
-
-// weird...
-u16 get_mask_shifted_down(u16 mask)
-{
- while (!(mask & 1))
- mask >>= 1;
- return mask;
-}
-
-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.
- int value;
-
- // modified by Hermes: test the register range
- switch ((unsigned)opc->params[i].type)
- {
- case P_REG18:
- case P_REG19:
- case P_REG1A:
- value = (opc->params[i].type >> 8) & 31;
- if ((int)par[i].val < value ||
- (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
- {
- if (ext) fprintf(stderr, "(ext) ");
- fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- ShowError(ERR_INVALID_REGISTER);
- }
- break;
- case P_PRG:
- if ((int)par[i].val < 0 || (int)par[i].val > 0x3)
- {
- if (ext) fprintf(stderr, "(ext) ");
- fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
- 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) {
- 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 Ext: %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) {
- 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
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
- case P_ACCM:
- if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1c && par[i].val <= 0x1d)
- fprintf(stderr, "WARNING: $ACL%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 if (par[i].val >= 0x20 && par[i].val <= 0x21)
- 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
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
-
- case P_ACCL:
- if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d)
- {
- if (ext) fprintf(stderr, "(ext) ");
- if (par[i].val >= 0x1e && par[i].val <= 0x1f)
- {
- fprintf(stderr, "%s", cur_line.c_str());
- fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else if (par[i].val >= 0x20 && par[i].val <= 0x21) {
- fprintf(stderr, "%s", cur_line.c_str());
- fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n",
- (par[i].val & 1), (par[i].val & 1), code_line, current_param);
- }
- else
- ShowError(ERR_WRONG_PARAMETER_ACC);
- }
- break;
-/* case P_ACCM_D: //P_ACC_MID:
- if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
- {
- ShowError(ERR_WRONG_PARAMETER_MID_ACC);
- }
- break;*/
- }
- continue;
- }
-
- switch (par[i].type & (P_REG | 7))
- {
- case P_REG:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_REG);
- break;
- case P_MEM:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_MEM);
- break;
- case P_VAL:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_VAL);
- break;
- case P_IMM:
- if (ext) fprintf(stderr, "(ext) ");
- ShowError(ERR_EXPECTED_PARAM_IMM);
- break;
- }
- ShowError(ERR_WRONG_PARAMETER);
- break;
- }
- else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0)
- {
- // modified by Hermes: test NUMBER range
- int value = get_mask_shifted_down(opc->params[i].mask);
- unsigned int valueu = 0xffff & ~(value >> 1);
- if ((int)par[i].val < 0)
- {
- if (value == 7) // value 7 por sbclr/sbset
- {
- fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- else if (opc->params[i].type == P_MEM)
- {
- if (value < 256)
- fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1));
- else
- fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value);
-
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- else if ((int)par[i].val < -((value >> 1) + 1))
- {
- if (value < 128)
- fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n",
- (value >> 1) + 1, value >> 1, par[i].val);
- else
- 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);
-
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else
- {
- if (value == 7) // value 7 por sbclr/sbset
- {
- 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);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else if (opc->params[i].type == P_MEM)
- {
- if (value < 256)
- value >>= 1; // addressing 8 bit with sign
- if (par[i].val > (unsigned)value &&
- (par[i].val < valueu || par[i].val > (unsigned)0xffff))
- {
- if (value < 256)
- 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);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- else
- {
- if (value < 128)
- value >>= 1; // special case ASL/ASR/LSL/LSR
- if (par[i].val > (unsigned)value)
- {
- if (value < 64)
- 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);
- ShowError(ERR_OUT_RANGE_NUMBER);
- }
- }
- }
- continue;
- }
- }
- m_current_param = 0;
- return true;
-}
-
-
-// Merge opcode with params.
-void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
-{
- outbuf[m_cur_addr] |= opc->opcode;
- for (u32 i = 0; i < par_count; i++)
- {
- // Ignore the "reverse" parameters since they are implicit.
- if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D)
- {
- u16 t16 = outbuf[m_cur_addr + opc->params[i].loc];
- u16 v16 = par[i].val;
- if (opc->params[i].lshift > 0)
- v16 <<= opc->params[i].lshift;
- else
- v16 >>= -opc->params[i].lshift;
- v16 &= opc->params[i].mask;
- outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16;
- }
- }
-}
-
-void DSPAssembler::InitPass(int pass)
-{
- failed = false;
- if (pass == 1)
- {
- // Reset label table. Pre-populate with hw addresses and registers.
- labels.Clear();
- labels.RegisterDefaults();
- aliases.clear();
- aliases["S15"] = "SET15";
- aliases["S16"] = "SET16";
- aliases["S40"] = "SET40";
- }
- m_cur_addr = 0;
- m_totalSize = 0;
- cur_segment = SEGMENT_CODE;
- segment_addr[SEGMENT_CODE] = 0;
- segment_addr[SEGMENT_DATA] = 0;
- segment_addr[SEGMENT_OVERLAY] = 0;
-}
-
-bool DSPAssembler::AssembleFile(const char *fname, int pass)
-{
- int disable_text = 0; // modified by Hermes
-
- std::ifstream fsrc(fname);
-
- if (fsrc.fail())
- {
- std::cerr << "Cannot open file " << fname << std::endl;
- return false;
- }
-
- //printf("%s: Pass %d\n", fname, pass);
- code_line = 0;
- m_cur_pass = pass;
-
-#define LINEBUF_SIZE 1024
- char line[LINEBUF_SIZE] = {0};
- while (!failed && !fsrc.fail() && !fsrc.eof())
- {
- int opcode_size = 0;
- fsrc.getline(line, LINEBUF_SIZE);
- if(fsrc.fail())
- break;
-
- cur_line = line;
- //printf("A: %s\n", line);
- code_line++;
-
- param_t params[10] = {{0}};
- param_t params_ext[10] = {{0}};
-
- bool upper = true;
- for (int i = 0; i < LINEBUF_SIZE; i++)
- {
- char c = line[i];
- // This stuff handles /**/ and // comments.
- // modified by Hermes : added // and /* */ for long commentaries
- if (c == '/')
- {
- if (i < 1023)
- {
- if (line[i+1] == '/')
- c = 0x00;
- else if (line[i+1] == '*')
- {
- // toggle comment mode.
- disable_text = !disable_text;
- }
- }
- }
- else if (c == '*')
- {
- if (i < 1023 && line[i+1] == '/' && disable_text)
- {
- disable_text = 0;
- c = 32;
- line[i + 1] = 32;
- }
- }
-
- // turn text into spaces if disable_text is on (in a comment).
- if (disable_text && ((unsigned char)c) > 32) c = 32;
-
- if (c == 0x0a || c == 0x0d || c == ';')
- c = 0x00;
- if (c == 0x09) // tabs to spaces
- c = ' ';
- if (c == '"')
- upper = !upper;
- if (upper && c >= 'a' && c <= 'z') // convert to uppercase
- c = c - 'a' + 'A';
- line[i] = c;
- if (c == 0)
- break; // modified by Hermes
- }
- char *ptr = line;
-
- std::string label;
-
- size_t col_pos = std::string(line).find(":");
- if (col_pos != std::string::npos)
- {
- bool valid = true;
-
- for(int j = 0; j < (int)col_pos; j++)
- {
- if (j == 0)
- if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
- valid = false;
- if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
- valid = false;
- }
- if (valid)
- {
- label = std::string(line).substr(0, col_pos);
- ptr += col_pos + 1;
- }
- }
-
- char *opcode = NULL;
- opcode = strtok(ptr, " ");
- char *opcode_ext = NULL;
-
- u32 params_count = 0;
- u32 params_count_ext = 0;
- if (opcode)
- {
- if ((opcode_ext = strstr(opcode, "'")) != NULL)
- {
- opcode_ext[0] = '\0';
- opcode_ext++;
- if (strlen(opcode_ext) == 0)
- opcode_ext = NULL;
- }
- // now we have opcode and label
-
- params_count = 0;
- params_count_ext = 0;
-
- char *paramstr = strtok(NULL, "\0");
- char *paramstr_ext = 0;
- // there is valid opcode so probably we have parameters
-
- if (paramstr)
- {
- if ((paramstr_ext = strstr(paramstr, ":")) != NULL)
- {
- paramstr_ext[0] = '\0';
- paramstr_ext++;
- }
- }
-
- if (paramstr)
- params_count = GetParams(paramstr, params);
- if (paramstr_ext)
- params_count_ext = GetParams(paramstr_ext, params_ext);
- }
-
- if (!label.empty())
- {
- // there is a valid label so lets store it in labels table
- u32 lval = m_cur_addr;
- if (opcode)
- {
- if (strcmp(opcode, "EQU") == 0)
- {
- lval = params[0].val;
- opcode = NULL;
- }
- }
- if (pass == 1)
- labels.RegisterLabel(label, lval);
- }
-
- if (opcode == NULL)
- continue;
-
- // check if opcode is reserved compiler word
- if (strcmp("INCLUDE", opcode) == 0)
- {
- if (params[0].type == P_STR)
- {
- char *tmpstr;
- u32 thisCodeline = code_line;
-
- if (include_dir.size())
- {
- tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2);
- sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str);
- }
- else
- {
- tmpstr = (char *)malloc(strlen(params[0].str) + 1);
- strcpy(tmpstr, params[0].str);
- }
-
- AssembleFile(tmpstr, pass);
-
- code_line = thisCodeline;
-
- free(tmpstr);
- }
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- if (strcmp("INCDIR", opcode) == 0)
- {
- if (params[0].type == P_STR)
- include_dir = params[0].str;
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- if (strcmp("ORG", opcode) == 0)
- {
- if (params[0].type == P_VAL)
- m_cur_addr = params[0].val;
- else
- ShowError(ERR_EXPECTED_PARAM_VAL);
- continue;
- }
-
- if (strcmp("SEGMENT", opcode) == 0)
- {
- if (params[0].type == P_STR)
- {
- segment_addr[cur_segment] = m_cur_addr;
- if (strcmp("DATA", params[0].str) == 0)
- cur_segment = SEGMENT_DATA;
- if (strcmp("CODE", params[0].str) == 0)
- cur_segment = SEGMENT_CODE;
- m_cur_addr = segment_addr[cur_segment];
- }
- else
- ShowError(ERR_EXPECTED_PARAM_STR);
- continue;
- }
-
- const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
- if (!opc)
- opc = &cw;
-
- opcode_size = opc->size & ~P_EXT;
-
- VerifyParams(opc, params, params_count);
-
- const opc_t *opc_ext = NULL;
- // Check for opcode extensions.
- if (opc->size & P_EXT)
- {
- if (opcode_ext)
- {
- 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)
- ShowError(ERR_EXT_PAR_NOT_EXT);
- }
- else
- {
- if (opcode_ext)
- ShowError(ERR_EXT_CANT_EXTEND_OPCODE);
- if (params_count_ext)
- ShowError(ERR_EXT_PAR_NOT_EXT);
- }
-
- if (pass == 2)
- {
- // generate binary
- ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000;
- BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
- if (opc_ext)
- BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
- }
-
- m_cur_addr += opcode_size;
- m_totalSize += opcode_size;
- };
-
- if (!failed)
- fsrc.close();
-
- return !failed;
-}
+/*====================================================================
+
+$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $
+
+project: GameCube DSP Tool (gcdsp)
+mail: duddie@walla.com
+
+Copyright (c) 2005 Duddie
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Revision 1.4 2008/10/04 10:30:00 Hermes
+added function to export the code to .h file
+added support for '/ *' '* /' and '//' for comentaries
+added some sintax detection when use registers
+
+$Log: not supported by cvs2svn $
+Revision 1.2 2005/09/14 02:19:29 wntrmute
+added header guards
+use standard main function
+
+Revision 1.1 2005/08/24 22:13:34 wntrmute
+Initial import
+
+
+====================================================================*/
+
+#include <cstdio>
+#include <cstdlib>
+
+#include <map>
+#include <iostream>
+#include <fstream>
+
+#include "Common.h"
+#include "FileUtil.h"
+#include "DSPInterpreter.h"
+#include "DSPTables.h"
+#include "disassemble.h"
+#include "assemble.h"
+
+static const char *err_string[] =
+{
+ "",
+ "Unknown Error",
+ "Unknown opcode",
+ "Not enough parameters",
+ "Too many parameters",
+ "Wrong parameter",
+ "Expected parameter of type 'string'",
+ "Expected parameter of type 'value'",
+ "Expected parameter of type 'register'",
+ "Expected parameter of type 'memory pointer'",
+ "Expected parameter of type 'immediate'",
+ "Incorrect binary value",
+ "Incorrect hexadecimal value",
+ "Incorrect decimal value",
+ "Label already exists",
+ "Label not defined",
+ "No matching brackets",
+ "This opcode cannot be extended",
+ "Given extending params for non extensible opcode",
+ "Wrong parameter: must be accumulator register",
+ "Wrong parameter: must be mid accumulator register",
+ "Invalid register",
+ "Number out of range"
+};
+
+DSPAssembler::DSPAssembler(const AssemblerSettings &settings) :
+ m_cur_addr(0),
+ m_cur_pass(0),
+ m_current_param(0),
+ settings_(settings),
+ gdg_buffer(NULL)
+{
+}
+
+DSPAssembler::~DSPAssembler()
+{
+ if(gdg_buffer)
+ free(gdg_buffer);
+}
+
+bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers)
+{
+ if (line_numbers)
+ line_numbers->clear();
+ const char *fname = "tmp.asm";
+ if (!File::WriteStringToFile(true, text, fname))
+ return false;
+ InitPass(1);
+ if (!AssembleFile(fname, 1))
+ return false;
+
+ // We now have the size of the output buffer
+ if (m_totalSize > 0)
+ {
+ gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4);
+ if(!gdg_buffer)
+ return false;
+
+ memset(gdg_buffer, 0, m_totalSize * sizeof(u16));
+ } else
+ return false;
+
+ InitPass(2);
+ if (!AssembleFile(fname, 2))
+ return false;
+
+ code.resize(m_totalSize);
+ for (int i = 0; i < m_totalSize; i++) {
+ code[i] = *(u16 *)(gdg_buffer + i * 2);
+ }
+
+ if(gdg_buffer) {
+ free(gdg_buffer);
+ gdg_buffer = NULL;
+ }
+
+ last_error_str = "(no errors)";
+ last_error = ERR_OK;
+
+ return true;
+}
+
+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 ", code_line, cur_line.c_str());
+ if (!extra_info)
+ extra_info = "-";
+
+ if (m_current_param == 0)
+ buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
+ else
+ buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n",
+ err_string[err_code], code_line, m_current_param, extra_info);
+ last_error_str = error_buffer;
+ last_error = err_code;
+}
+
+char *skip_spaces(char *ptr)
+{
+ while (*ptr == ' ')
+ ptr++;
+ return ptr;
+}
+
+const char *skip_spaces(const char *ptr)
+{
+ while (*ptr == ' ')
+ ptr++;
+ return ptr;
+}
+
+// Parse a standalone value - it can be a number in one of several formats or a label.
+s32 DSPAssembler::ParseValue(const char *str)
+{
+ bool negative = false;
+ s32 val = 0;
+ const char *ptr = str;
+
+ if (ptr[0] == '#')
+ {
+ ptr++;
+ negative = true; // Wow! Double # (needed one to get in here) negates???
+ }
+ if (ptr[0] == '-')
+ {
+ ptr++;
+ negative = true;
+ }
+ if (ptr[0] == '0')
+ {
+ if (ptr[1] >= '0' && ptr[1] <= '9')
+ {
+ for (int i = 0; ptr[i] != 0; i++)
+ {
+ val *= 10;
+ if (ptr[i] >= '0' && ptr[i] <= '9')
+ val += ptr[i] - '0';
+ else
+ ShowError(ERR_INCORRECT_DEC, str);
+ }
+ }
+ else
+ {
+ switch (ptr[1])
+ {
+ case 'X': // hex
+ for (int i = 2 ; ptr[i] != 0 ; i++)
+ {
+ val <<= 4;
+ if (ptr[i] >= 'a' && ptr[i] <= 'f')
+ val += (ptr[i]-'a'+10);
+ else if (ptr[i] >= 'A' && ptr[i] <= 'F')
+ val += (ptr[i]-'A'+10);
+ else if (ptr[i] >= '0' && ptr[i] <= '9')
+ val += (ptr[i] - '0');
+ else
+ ShowError(ERR_INCORRECT_HEX, str);
+ }
+ break;
+ case '\'': // binary
+ for (int i = 2; ptr[i] != 0; i++)
+ {
+ val *=2;
+ if(ptr[i] >= '0' && ptr[i] <= '1')
+ val += ptr[i] - '0';
+ else
+ ShowError(ERR_INCORRECT_BIN, str);
+ }
+ break;
+ default:
+ // value is 0 or error
+ val = 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Symbol starts with a digit - it's a dec number.
+ if (ptr[0] >= '0' && ptr[0] <= '9')
+ {
+ for (int i = 0; ptr[i] != 0; i++)
+ {
+ val *= 10;
+ if (ptr[i] >= '0' && ptr[i] <= '9')
+ val += ptr[i] - '0';
+ else
+ ShowError(ERR_INCORRECT_DEC, str);
+ }
+ }
+ else // Everything else is a label.
+ {
+ // Lookup label
+ u16 value;
+ if (labels.GetLabelValue(ptr, &value))
+ return value;
+ if (m_cur_pass == 2)
+ ShowError(ERR_UNKNOWN_LABEL, str);
+ }
+ }
+ if (negative)
+ return -val;
+ return val;
+}
+
+// Modifies both src and dst!
+// What does it do, really??
+char *DSPAssembler::FindBrackets(char *src, char *dst)
+{
+ s32 len = (s32) strlen(src);
+ s32 first = -1;
+ s32 count = 0;
+ s32 i, j;
+ j = 0;
+ for (i = 0 ; i < len ; i++)
+ {
+ if (src[i] == '(')
+ {
+ if (first < 0)
+ {
+ count = 1;
+ src[i] = 0x0;
+ first = i;
+ }
+ else
+ {
+ count++;
+ dst[j++] = src[i];
+ }
+ }
+ else if (src[i] == ')')
+ {
+ if (--count == 0)
+ {
+ dst[j] = 0;
+ return &src[i+1];
+ }
+ else
+ {
+ dst[j++] = src[i];
+ }
+ }
+ else
+ {
+ if (first >= 0)
+ dst[j++] = src[i];
+ }
+ }
+ if (count)
+ ShowError(ERR_NO_MATCHING_BRACKETS);
+ return NULL;
+}
+
+// Bizarre in-place expression evaluator.
+u32 DSPAssembler::ParseExpression(const char *ptr)
+{
+ char *pbuf;
+ s32 val = 0;
+
+ char *d_buffer = (char *)malloc(1024);
+ char *s_buffer = (char *)malloc(1024);
+ strcpy(s_buffer, ptr);
+
+ while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL)
+ {
+ val = ParseExpression(d_buffer);
+ sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf);
+ strcpy(s_buffer, d_buffer);
+ }
+
+ int j = 0;
+ for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++)
+ {
+ char c = s_buffer[i];
+ if (c != ' ')
+ d_buffer[j++] = c;
+ }
+
+ for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++)
+ {
+ char c = d_buffer[i];
+ if (c == '-')
+ {
+ if (i == 0)
+ c = '#';
+ else
+ {
+ switch (d_buffer[i - 1])
+ {
+ case '/':
+ case '%':
+ case '*':
+ c = '#';
+ }
+ }
+ }
+ d_buffer[i] = c;
+ }
+
+ while ((pbuf = strstr(d_buffer, "+")) != NULL)
+ {
+ *pbuf = 0x0;
+ val = ParseExpression(d_buffer) + ParseExpression(pbuf+1);
+ sprintf(d_buffer, "%d", val);
+ }
+
+ while ((pbuf = strstr(d_buffer, "-")) != NULL)
+ {
+ *pbuf = 0x0;
+ 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
+ fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line);
+ }
+ sprintf(d_buffer, "%d", val);
+ }
+
+ while ((pbuf = strstr(d_buffer, "*")) != NULL)
+ {
+ *pbuf = 0x0;
+ val = ParseExpression(d_buffer) * ParseExpression(pbuf+1);
+ sprintf(d_buffer, "%d", val);
+ }
+
+ while ((pbuf = strstr(d_buffer, "/")) != NULL)
+ {
+ *pbuf = 0x0;
+ val = ParseExpression(d_buffer) / ParseExpression(pbuf+1);
+ sprintf(d_buffer, "%d", val);
+ }
+
+ while ((pbuf = strstr(d_buffer, "|")) != NULL)
+ {
+ *pbuf = 0x0;
+ val = ParseExpression(d_buffer) | ParseExpression(pbuf+1);
+ sprintf(d_buffer, "%d", val);
+ }
+
+ while ((pbuf = strstr(d_buffer, "&")) != NULL)
+ {
+ *pbuf = 0x0;
+ val = ParseExpression(d_buffer) & ParseExpression(pbuf+1);
+ sprintf(d_buffer, "%d", val);
+ }
+
+ val = ParseValue(d_buffer);
+ free(d_buffer);
+ free(s_buffer);
+ return val;
+}
+
+// Destroys parstr
+u32 DSPAssembler::GetParams(char *parstr, param_t *par)
+{
+ u32 count = 0;
+ char *tmpstr = skip_spaces(parstr);
+ tmpstr = strtok(tmpstr, ",\x00");
+ for (int i = 0; i < 10; i++)
+ {
+ if (tmpstr == NULL)
+ break;
+ tmpstr = skip_spaces(tmpstr);
+ if (strlen(tmpstr) == 0)
+ break;
+ if (tmpstr)
+ count++;
+ else
+ break;
+
+ par[i].type = P_NONE;
+ switch (tmpstr[0])
+ {
+ case '"':
+ par[i].str = strtok(tmpstr, "\"");
+ par[i].type = P_STR;
+ break;
+ case '#':
+ par[i].val = ParseExpression(tmpstr + 1);
+ par[i].type = P_IMM;
+ break;
+ case '@':
+ if (tmpstr[1] == '$')
+ {
+ par[i].val = ParseExpression(tmpstr + 2);
+ par[i].type = P_PRG;
+ }
+ else
+ {
+ par[i].val = ParseExpression(tmpstr + 1);
+ par[i].type = P_MEM;
+ }
+ break;
+ case '$':
+ par[i].val = ParseExpression(tmpstr + 1);
+ par[i].type = P_REG;
+ break;
+
+ default:
+ par[i].val = ParseExpression(tmpstr);
+ par[i].type = P_VAL;
+ break;
+ }
+ tmpstr = strtok(NULL, ",\x00");
+ }
+ return count;
+}
+
+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;
+
+ AliasMap::const_iterator alias_iter = aliases.find(opcode);
+ if (alias_iter != aliases.end())
+ opcode = alias_iter->second.c_str();
+ for (int i = 0; i < opcod_size; i++)
+ {
+ const opc_t *opc = &opcod[i];
+ if (strcmp(opc->name, opcode) == 0)
+ {
+ if (par_count < opc->param_count)
+ {
+ ShowError(ERR_NOT_ENOUGH_PARAMETERS);
+ }
+ if (par_count > opc->param_count)
+ {
+ ShowError(ERR_TOO_MANY_PARAMETERS);
+ }
+ return opc;
+ }
+ }
+ ShowError(ERR_UNKNOWN_OPCODE);
+ return NULL;
+}
+
+// weird...
+u16 get_mask_shifted_down(u16 mask)
+{
+ while (!(mask & 1))
+ mask >>= 1;
+ return mask;
+}
+
+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.
+ int value;
+
+ // modified by Hermes: test the register range
+ switch ((unsigned)opc->params[i].type)
+ {
+ case P_REG18:
+ case P_REG19:
+ case P_REG1A:
+ value = (opc->params[i].type >> 8) & 31;
+ if ((int)par[i].val < value ||
+ (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
+ {
+ if (ext) fprintf(stderr, "(ext) ");
+ fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
+ ShowError(ERR_INVALID_REGISTER);
+ }
+ break;
+ case P_PRG:
+ if ((int)par[i].val < 0 || (int)par[i].val > 0x3)
+ {
+ if (ext) fprintf(stderr, "(ext) ");
+ fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param);
+ 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) {
+ 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 Ext: %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) {
+ 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
+ ShowError(ERR_WRONG_PARAMETER_ACC);
+ }
+ break;
+ case P_ACCM:
+ if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
+ {
+ if (ext) fprintf(stderr, "(ext) ");
+ if (par[i].val >= 0x1c && par[i].val <= 0x1d)
+ fprintf(stderr, "WARNING: $ACL%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 if (par[i].val >= 0x20 && par[i].val <= 0x21)
+ 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
+ ShowError(ERR_WRONG_PARAMETER_ACC);
+ }
+ break;
+
+ case P_ACCL:
+ if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d)
+ {
+ if (ext) fprintf(stderr, "(ext) ");
+ if (par[i].val >= 0x1e && par[i].val <= 0x1f)
+ {
+ fprintf(stderr, "%s", cur_line.c_str());
+ fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n",
+ (par[i].val & 1), (par[i].val & 1), code_line, current_param);
+ }
+ else if (par[i].val >= 0x20 && par[i].val <= 0x21) {
+ fprintf(stderr, "%s", cur_line.c_str());
+ fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n",
+ (par[i].val & 1), (par[i].val & 1), code_line, current_param);
+ }
+ else
+ ShowError(ERR_WRONG_PARAMETER_ACC);
+ }
+ break;
+/* case P_ACCM_D: //P_ACC_MID:
+ if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
+ {
+ ShowError(ERR_WRONG_PARAMETER_MID_ACC);
+ }
+ break;*/
+ }
+ continue;
+ }
+
+ switch (par[i].type & (P_REG | 7))
+ {
+ case P_REG:
+ if (ext) fprintf(stderr, "(ext) ");
+ ShowError(ERR_EXPECTED_PARAM_REG);
+ break;
+ case P_MEM:
+ if (ext) fprintf(stderr, "(ext) ");
+ ShowError(ERR_EXPECTED_PARAM_MEM);
+ break;
+ case P_VAL:
+ if (ext) fprintf(stderr, "(ext) ");
+ ShowError(ERR_EXPECTED_PARAM_VAL);
+ break;
+ case P_IMM:
+ if (ext) fprintf(stderr, "(ext) ");
+ ShowError(ERR_EXPECTED_PARAM_IMM);
+ break;
+ }
+ ShowError(ERR_WRONG_PARAMETER);
+ break;
+ }
+ else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0)
+ {
+ // modified by Hermes: test NUMBER range
+ int value = get_mask_shifted_down(opc->params[i].mask);
+ unsigned int valueu = 0xffff & ~(value >> 1);
+ if ((int)par[i].val < 0)
+ {
+ if (value == 7) // value 7 por sbclr/sbset
+ {
+ fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value);
+ ShowError(ERR_OUT_RANGE_NUMBER);
+ }
+ else if (opc->params[i].type == P_MEM)
+ {
+ if (value < 256)
+ fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1));
+ else
+ fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value);
+
+ ShowError(ERR_OUT_RANGE_NUMBER);
+ }
+ else if ((int)par[i].val < -((value >> 1) + 1))
+ {
+ if (value < 128)
+ fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n",
+ (value >> 1) + 1, value >> 1, par[i].val);
+ else
+ 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);
+
+ ShowError(ERR_OUT_RANGE_NUMBER);
+ }
+ }
+ else
+ {
+ if (value == 7) // value 7 por sbclr/sbset
+ {
+ 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);
+ ShowError(ERR_OUT_RANGE_NUMBER);
+ }
+ }
+ else if (opc->params[i].type == P_MEM)
+ {
+ if (value < 256)
+ value >>= 1; // addressing 8 bit with sign
+ if (par[i].val > (unsigned)value &&
+ (par[i].val < valueu || par[i].val > (unsigned)0xffff))
+ {
+ if (value < 256)
+ 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);
+ ShowError(ERR_OUT_RANGE_NUMBER);
+ }
+ }
+ else
+ {
+ if (value < 128)
+ value >>= 1; // special case ASL/ASR/LSL/LSR
+ if (par[i].val > (unsigned)value)
+ {
+ if (value < 64)
+ 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);
+ ShowError(ERR_OUT_RANGE_NUMBER);
+ }
+ }
+ }
+ continue;
+ }
+ }
+ m_current_param = 0;
+ return true;
+}
+
+
+// Merge opcode with params.
+void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
+{
+ outbuf[m_cur_addr] |= opc->opcode;
+ for (u32 i = 0; i < par_count; i++)
+ {
+ // Ignore the "reverse" parameters since they are implicit.
+ if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D)
+ {
+ u16 t16 = outbuf[m_cur_addr + opc->params[i].loc];
+ u16 v16 = par[i].val;
+ if (opc->params[i].lshift > 0)
+ v16 <<= opc->params[i].lshift;
+ else
+ v16 >>= -opc->params[i].lshift;
+ v16 &= opc->params[i].mask;
+ outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16;
+ }
+ }
+}
+
+void DSPAssembler::InitPass(int pass)
+{
+ failed = false;
+ if (pass == 1)
+ {
+ // Reset label table. Pre-populate with hw addresses and registers.
+ labels.Clear();
+ labels.RegisterDefaults();
+ aliases.clear();
+ aliases["S15"] = "SET15";
+ aliases["S16"] = "SET16";
+ aliases["S40"] = "SET40";
+ }
+ m_cur_addr = 0;
+ m_totalSize = 0;
+ cur_segment = SEGMENT_CODE;
+ segment_addr[SEGMENT_CODE] = 0;
+ segment_addr[SEGMENT_DATA] = 0;
+ segment_addr[SEGMENT_OVERLAY] = 0;
+}
+
+bool DSPAssembler::AssembleFile(const char *fname, int pass)
+{
+ int disable_text = 0; // modified by Hermes
+
+ std::ifstream fsrc(fname);
+
+ if (fsrc.fail())
+ {
+ std::cerr << "Cannot open file " << fname << std::endl;
+ return false;
+ }
+
+ //printf("%s: Pass %d\n", fname, pass);
+ code_line = 0;
+ m_cur_pass = pass;
+
+#define LINEBUF_SIZE 1024
+ char line[LINEBUF_SIZE] = {0};
+ while (!failed && !fsrc.fail() && !fsrc.eof())
+ {
+ int opcode_size = 0;
+ fsrc.getline(line, LINEBUF_SIZE);
+ if(fsrc.fail())
+ break;
+
+ cur_line = line;
+ //printf("A: %s\n", line);
+ code_line++;
+
+ param_t params[10] = {{0}};
+ param_t params_ext[10] = {{0}};
+
+ bool upper = true;
+ for (int i = 0; i < LINEBUF_SIZE; i++)
+ {
+ char c = line[i];
+ // This stuff handles /**/ and // comments.
+ // modified by Hermes : added // and /* */ for long commentaries
+ if (c == '/')
+ {
+ if (i < 1023)
+ {
+ if (line[i+1] == '/')
+ c = 0x00;
+ else if (line[i+1] == '*')
+ {
+ // toggle comment mode.
+ disable_text = !disable_text;
+ }
+ }
+ }
+ else if (c == '*')
+ {
+ if (i < 1023 && line[i+1] == '/' && disable_text)
+ {
+ disable_text = 0;
+ c = 32;
+ line[i + 1] = 32;
+ }
+ }
+
+ // turn text into spaces if disable_text is on (in a comment).
+ if (disable_text && ((unsigned char)c) > 32) c = 32;
+
+ if (c == 0x0a || c == 0x0d || c == ';')
+ c = 0x00;
+ if (c == 0x09) // tabs to spaces
+ c = ' ';
+ if (c == '"')
+ upper = !upper;
+ if (upper && c >= 'a' && c <= 'z') // convert to uppercase
+ c = c - 'a' + 'A';
+ line[i] = c;
+ if (c == 0)
+ break; // modified by Hermes
+ }
+ char *ptr = line;
+
+ std::string label;
+
+ size_t col_pos = std::string(line).find(":");
+ if (col_pos != std::string::npos)
+ {
+ bool valid = true;
+
+ for(int j = 0; j < (int)col_pos; j++)
+ {
+ if (j == 0)
+ if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
+ valid = false;
+ if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
+ valid = false;
+ }
+ if (valid)
+ {
+ label = std::string(line).substr(0, col_pos);
+ ptr += col_pos + 1;
+ }
+ }
+
+ char *opcode = NULL;
+ opcode = strtok(ptr, " ");
+ char *opcode_ext = NULL;
+
+ u32 params_count = 0;
+ u32 params_count_ext = 0;
+ if (opcode)
+ {
+ if ((opcode_ext = strstr(opcode, "'")) != NULL)
+ {
+ opcode_ext[0] = '\0';
+ opcode_ext++;
+ if (strlen(opcode_ext) == 0)
+ opcode_ext = NULL;
+ }
+ // now we have opcode and label
+
+ params_count = 0;
+ params_count_ext = 0;
+
+ char *paramstr = strtok(NULL, "\0");
+ char *paramstr_ext = 0;
+ // there is valid opcode so probably we have parameters
+
+ if (paramstr)
+ {
+ if ((paramstr_ext = strstr(paramstr, ":")) != NULL)
+ {
+ paramstr_ext[0] = '\0';
+ paramstr_ext++;
+ }
+ }
+
+ if (paramstr)
+ params_count = GetParams(paramstr, params);
+ if (paramstr_ext)
+ params_count_ext = GetParams(paramstr_ext, params_ext);
+ }
+
+ if (!label.empty())
+ {
+ // there is a valid label so lets store it in labels table
+ u32 lval = m_cur_addr;
+ if (opcode)
+ {
+ if (strcmp(opcode, "EQU") == 0)
+ {
+ lval = params[0].val;
+ opcode = NULL;
+ }
+ }
+ if (pass == 1)
+ labels.RegisterLabel(label, lval);
+ }
+
+ if (opcode == NULL)
+ continue;
+
+ // check if opcode is reserved compiler word
+ if (strcmp("INCLUDE", opcode) == 0)
+ {
+ if (params[0].type == P_STR)
+ {
+ char *tmpstr;
+ u32 thisCodeline = code_line;
+
+ if (include_dir.size())
+ {
+ tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2);
+ sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str);
+ }
+ else
+ {
+ tmpstr = (char *)malloc(strlen(params[0].str) + 1);
+ strcpy(tmpstr, params[0].str);
+ }
+
+ AssembleFile(tmpstr, pass);
+
+ code_line = thisCodeline;
+
+ free(tmpstr);
+ }
+ else
+ ShowError(ERR_EXPECTED_PARAM_STR);
+ continue;
+ }
+
+ if (strcmp("INCDIR", opcode) == 0)
+ {
+ if (params[0].type == P_STR)
+ include_dir = params[0].str;
+ else
+ ShowError(ERR_EXPECTED_PARAM_STR);
+ continue;
+ }
+
+ if (strcmp("ORG", opcode) == 0)
+ {
+ if (params[0].type == P_VAL)
+ m_cur_addr = params[0].val;
+ else
+ ShowError(ERR_EXPECTED_PARAM_VAL);
+ continue;
+ }
+
+ if (strcmp("SEGMENT", opcode) == 0)
+ {
+ if (params[0].type == P_STR)
+ {
+ segment_addr[cur_segment] = m_cur_addr;
+ if (strcmp("DATA", params[0].str) == 0)
+ cur_segment = SEGMENT_DATA;
+ if (strcmp("CODE", params[0].str) == 0)
+ cur_segment = SEGMENT_CODE;
+ m_cur_addr = segment_addr[cur_segment];
+ }
+ else
+ ShowError(ERR_EXPECTED_PARAM_STR);
+ continue;
+ }
+
+ const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
+ if (!opc)
+ opc = &cw;
+
+ opcode_size = opc->size & ~P_EXT;
+
+ VerifyParams(opc, params, params_count);
+
+ const opc_t *opc_ext = NULL;
+ // Check for opcode extensions.
+ if (opc->size & P_EXT)
+ {
+ if (opcode_ext)
+ {
+ 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)
+ ShowError(ERR_EXT_PAR_NOT_EXT);
+ }
+ else
+ {
+ if (opcode_ext)
+ ShowError(ERR_EXT_CANT_EXTEND_OPCODE);
+ if (params_count_ext)
+ ShowError(ERR_EXT_PAR_NOT_EXT);
+ }
+
+ if (pass == 2)
+ {
+ // generate binary
+ ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000;
+ BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
+ if (opc_ext)
+ BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
+ }
+
+ m_cur_addr += opcode_size;
+ m_totalSize += opcode_size;
+ };
+
+ if (!failed)
+ fsrc.close();
+
+ return !failed;
+}
diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h
index 304b97aaab..f140d0e69e 100644
--- a/Source/Core/DSPCore/Src/assemble.h
+++ b/Source/Core/DSPCore/Src/assemble.h
@@ -1,139 +1,139 @@
-/*====================================================================
-
- project: GameCube DSP Tool (gcdsp)
- created: 2005.03.04
- mail: duddie@walla.com
-
- Copyright (c) 2005 Duddie
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- ====================================================================*/
-
-#ifndef _DSP_ASSEMBLE_H
-#define _DSP_ASSEMBLE_H
-
-#include <string>
-#include <map>
-
-#include "Common.h"
-#include "disassemble.h"
-#include "DSPTables.h"
-#include "LabelMap.h"
-
-enum err_t
-{
- ERR_OK = 0,
- ERR_UNKNOWN,
- ERR_UNKNOWN_OPCODE,
- ERR_NOT_ENOUGH_PARAMETERS,
- ERR_TOO_MANY_PARAMETERS,
- ERR_WRONG_PARAMETER,
- ERR_EXPECTED_PARAM_STR,
- ERR_EXPECTED_PARAM_VAL,
- ERR_EXPECTED_PARAM_REG,
- ERR_EXPECTED_PARAM_MEM,
- ERR_EXPECTED_PARAM_IMM,
- ERR_INCORRECT_BIN,
- ERR_INCORRECT_HEX,
- ERR_INCORRECT_DEC,
- ERR_LABEL_EXISTS,
- ERR_UNKNOWN_LABEL,
- ERR_NO_MATCHING_BRACKETS,
- ERR_EXT_CANT_EXTEND_OPCODE,
- ERR_EXT_PAR_NOT_EXT,
- ERR_WRONG_PARAMETER_ACC,
- ERR_WRONG_PARAMETER_MID_ACC,
- ERR_INVALID_REGISTER,
- 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
-{
-public:
- DSPAssembler(const AssemblerSettings &settings);
- ~DSPAssembler();
-
- // line_numbers is optional (and not yet implemented). It'll receieve a list of ints,
- // one for each word of code, indicating the source assembler code line number it came from.
-
- // If returns false, call GetErrorString to get some text to present to the user.
- bool Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers = NULL);
-
- std::string GetErrorString() const { return last_error_str; }
- err_t GetError() const { return last_error; }
-
-private:
- struct param_t
- {
- u32 val;
- partype_t type;
- char *str;
- };
-
- enum segment_t
- {
- SEGMENT_CODE = 0,
- SEGMENT_DATA,
- SEGMENT_OVERLAY,
- 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;
-
- std::string include_dir;
- std::string cur_line;
-
- u32 m_cur_addr;
- int m_totalSize;
- u8 m_cur_pass;
-
- LabelMap labels;
-
- u32 code_line;
- bool failed;
- std::string last_error_str;
- err_t last_error;
-
- typedef std::map<std::string, std::string> AliasMap;
- AliasMap aliases;
-
- segment_t cur_segment;
- u32 segment_addr[SEGMENT_MAX];
- int m_current_param;
- const AssemblerSettings settings_;
-};
-
-#endif // _DSP_ASSEMBLE_H
+/*====================================================================
+
+ project: GameCube DSP Tool (gcdsp)
+ created: 2005.03.04
+ mail: duddie@walla.com
+
+ Copyright (c) 2005 Duddie
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ ====================================================================*/
+
+#ifndef _DSP_ASSEMBLE_H
+#define _DSP_ASSEMBLE_H
+
+#include <string>
+#include <map>
+
+#include "Common.h"
+#include "disassemble.h"
+#include "DSPTables.h"
+#include "LabelMap.h"
+
+enum err_t
+{
+ ERR_OK = 0,
+ ERR_UNKNOWN,
+ ERR_UNKNOWN_OPCODE,
+ ERR_NOT_ENOUGH_PARAMETERS,
+ ERR_TOO_MANY_PARAMETERS,
+ ERR_WRONG_PARAMETER,
+ ERR_EXPECTED_PARAM_STR,
+ ERR_EXPECTED_PARAM_VAL,
+ ERR_EXPECTED_PARAM_REG,
+ ERR_EXPECTED_PARAM_MEM,
+ ERR_EXPECTED_PARAM_IMM,
+ ERR_INCORRECT_BIN,
+ ERR_INCORRECT_HEX,
+ ERR_INCORRECT_DEC,
+ ERR_LABEL_EXISTS,
+ ERR_UNKNOWN_LABEL,
+ ERR_NO_MATCHING_BRACKETS,
+ ERR_EXT_CANT_EXTEND_OPCODE,
+ ERR_EXT_PAR_NOT_EXT,
+ ERR_WRONG_PARAMETER_ACC,
+ ERR_WRONG_PARAMETER_MID_ACC,
+ ERR_INVALID_REGISTER,
+ 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
+{
+public:
+ DSPAssembler(const AssemblerSettings &settings);
+ ~DSPAssembler();
+
+ // line_numbers is optional (and not yet implemented). It'll receieve a list of ints,
+ // one for each word of code, indicating the source assembler code line number it came from.
+
+ // If returns false, call GetErrorString to get some text to present to the user.
+ bool Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers = NULL);
+
+ std::string GetErrorString() const { return last_error_str; }
+ err_t GetError() const { return last_error; }
+
+private:
+ struct param_t
+ {
+ u32 val;
+ partype_t type;
+ char *str;
+ };
+
+ enum segment_t
+ {
+ SEGMENT_CODE = 0,
+ SEGMENT_DATA,
+ SEGMENT_OVERLAY,
+ 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;
+
+ std::string include_dir;
+ std::string cur_line;
+
+ u32 m_cur_addr;
+ int m_totalSize;
+ u8 m_cur_pass;
+
+ LabelMap labels;
+
+ u32 code_line;
+ bool failed;
+ std::string last_error_str;
+ err_t last_error;
+
+ typedef std::map<std::string, std::string> AliasMap;
+ AliasMap aliases;
+
+ segment_t cur_segment;
+ u32 segment_addr[SEGMENT_MAX];
+ int m_current_param;
+ const AssemblerSettings settings_;
+};
+
+#endif // _DSP_ASSEMBLE_H