diff options
Diffstat (limited to 'Source/Core/DSPCore')
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 |
