chop the "testing" moniker off of dsp lle

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2934 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman
2009-04-08 20:02:22 +00:00
parent edf0be235b
commit f8ed0b5c4c
49 changed files with 1 additions and 46 deletions

View File

@ -0,0 +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/
#include "Common.h"
#include "IniFile.h"
#include "Config.h"
#include "AudioCommon.h"
#define LLE_CONFIG_FILE "DSPLLE.ini"
CConfig g_Config;
CConfig::CConfig()
{
Load();
}
void CConfig::Load()
{
// first load defaults
std::string temp;
IniFile file;
file.Load(FULL_CONFIG_DIR LLE_CONFIG_FILE);
ac_Config.Load(file);
}
void CConfig::Save()
{
IniFile file;
file.Load(FULL_CONFIG_DIR LLE_CONFIG_FILE);
ac_Config.Set(file);
file.Save(FULL_CONFIG_DIR LLE_CONFIG_FILE);
}

View File

@ -0,0 +1,34 @@
// 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 _PLUGIN_DSP_LLE_CONFIG_H
#define _PLUGIN_DSP_LLE_CONFIG_H
#include <string>
struct CConfig
{
CConfig();
void Load();
void Save();
};
extern CConfig g_Config;
#endif // _PLUGIN_DSP_LLE_CONFIG_H

View File

@ -0,0 +1,116 @@
// 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 "gdsp_memory.h"
namespace DSPAnalyzer {
// Holds data about all instructions in RAM.
u8 inst_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 4
#define MAX_IDLE_SIG_SIZE 6
// 0xFFFF means ignore.
const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] =
{
{ 0x26fc, // LRS $30, @DMBH
0x02c0, 0x8000, // ANDCF $30, #0x8000
0x029d, 0xFFFF, // JLZ 0x027a
0x02df, 0 }, // RET
{ 0x27fc, // LRS $31, @DMBH
0x03c0, 0x8000, // ANDCF $31, #0x8000
0x029d, 0xFFFF, // JLZ 0x027a
0x02df, 0 }, // RET
{ 0x26fe, // LRS $30, @CMBH
0x02c0, 0x8000, // ANDCF $30, #0x8000
0x029c, 0xFFFF, // JLNZ 0x0280
0x02df, 0 }, // RET
{ 0x27fe, // LRS $31, @CMBH
0x03c0, 0x8000, // ANDCF $31, #0x8000
0x029c, 0xFFFF, // JLNZ 0x0280
0x02df, 0 }, // RET
};
void Reset()
{
memset(inst_flags, 0, sizeof(inst_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, but should be good
// enough as a start.
int addr = start_addr;
while (addr < end_addr)
{
UDSPInstruction inst = dsp_imem_read(addr);
const DSPOPCTemplate *opcode = GetOpTemplate(inst);
if (!opcode)
{
addr++;
continue;
}
inst_flags[addr] |= CODE_START_OF_INST;
addr += opcode->size;
}
// 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);
inst_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

View File

@ -0,0 +1,45 @@
// 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
enum
{
CODE_START_OF_INST = 1,
CODE_IDLE_SKIP = 2,
};
// 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

View File

@ -0,0 +1,97 @@
// 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 "Config.h"
#include "DSPConfigDlgLLE.h"
BEGIN_EVENT_TABLE(DSPConfigDialogLLE, wxDialog)
EVT_BUTTON(wxID_OK, DSPConfigDialogLLE::SettingsChanged)
EVT_CHECKBOX(ID_ENABLE_DTK_MUSIC, DSPConfigDialogLLE::SettingsChanged)
EVT_CHECKBOX(ID_ENABLE_THROTTLE, DSPConfigDialogLLE::SettingsChanged)
END_EVENT_TABLE()
DSPConfigDialogLLE::DSPConfigDialogLLE(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
// Load config settings
g_Config.Load();
// Center window
CenterOnParent();
m_OK = new wxButton(this, wxID_OK, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
// Create items
m_buttonEnableDTKMusic = new wxCheckBox(this, ID_ENABLE_DTK_MUSIC, wxT("Enable DTK Music"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Other Audio (Throttle)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0);
m_BackendSelection = new wxComboBox(this, ID_BACKEND, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxArrayBackends, wxCB_READONLY, wxDefaultValidator);
// Update values
m_buttonEnableDTKMusic->SetValue(ac_Config.m_EnableDTKMusic ? true : false);
m_buttonEnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false);
// Add tooltips
m_buttonEnableDTKMusic->SetToolTip(wxT("This is sometimes used to play music tracks from the disc"));
m_buttonEnableThrottle->SetToolTip(wxT("This is sometimes used together with pre-rendered movies.\n"
"Disabling this also disables the speed throttle which this causes,\n"
"meaning that there will be no upper limit on your FPS."));
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
// Create sizer and add items to dialog
wxBoxSizer *sMain = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer *sbSettings = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Sound Settings"));
sbSettings->Add(m_buttonEnableDTKMusic, 0, wxALL, 5);
sbSettings->Add(m_buttonEnableThrottle, 0, wxALL, 5);
wxBoxSizer *sBackend = new wxBoxSizer(wxHORIZONTAL);
sBackend->Add(BackendText, 0, wxALIGN_CENTRE_VERTICAL|wxALL, 5);
sBackend->Add(m_BackendSelection);
sbSettings->Add(sBackend);
sMain->Add(sbSettings, 0, wxEXPAND|wxALL, 5);
wxBoxSizer *sButtons = new wxBoxSizer(wxHORIZONTAL);
sButtons->Add(150, 0); // Lazy way to make the dialog as wide as we want it
sButtons->Add(m_OK, 0, wxALL, 5);
sMain->Add(sButtons, 0, wxEXPAND);
this->SetSizerAndFit(sMain);
}
// Add audio output options
void DSPConfigDialogLLE::AddBackend(const char* backend)
{
m_BackendSelection->Append(wxString::FromAscii(backend));
// Update value
m_BackendSelection->SetValue(wxString::FromAscii(ac_Config.sBackend.c_str()));
}
DSPConfigDialogLLE::~DSPConfigDialogLLE()
{
}
void DSPConfigDialogLLE::SettingsChanged(wxCommandEvent& event)
{
ac_Config.m_EnableDTKMusic = m_buttonEnableDTKMusic->GetValue();
ac_Config.m_EnableThrottle = m_buttonEnableThrottle->GetValue();
ac_Config.sBackend = m_BackendSelection->GetValue().mb_str();
ac_Config.Update();
g_Config.Save();
if (event.GetId() == wxID_OK)
EndModal(wxID_OK);
}

View File

@ -0,0 +1,60 @@
// 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_LLE_CONFIGDIALOG_h__
#define __DSP_LLE_CONFIGDIALOG_h__
#include <wx/wx.h>
#include <wx/dialog.h>
#include <wx/button.h>
#include <wx/statbox.h>
#include "AudioCommon.h"
class DSPConfigDialogLLE : public wxDialog
{
public:
DSPConfigDialogLLE(wxWindow *parent,
wxWindowID id = 1,
const wxString &title = wxT("Dolphin DSP-LLE Plugin Settings"),
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE);
virtual ~DSPConfigDialogLLE();
void AddBackend(const char *backend);
private:
DECLARE_EVENT_TABLE();
wxButton *m_OK;
wxCheckBox *m_buttonEnableDTKMusic;
wxCheckBox *m_buttonEnableThrottle;
wxArrayString wxArrayBackends;
wxComboBox *m_BackendSelection;
enum
{
wxID_OK,
ID_ENABLE_DTK_MUSIC,
ID_ENABLE_THROTTLE,
ID_BACKEND
};
void OnOK(wxCommandEvent& event);
void SettingsChanged(wxCommandEvent& event);
};
#endif //__DSP_LLE_CONFIGDIALOG_h__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,150 @@
// 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
#define FLAG_ENABLE_INTERUPT 11
namespace DSPInterpreter {
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 orr(const UDSPInstruction& opc);
void andc(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 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 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 andfc(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

View File

@ -0,0 +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 {
};

View File

@ -0,0 +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

View File

@ -0,0 +1,408 @@
// 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 "Globals.h"
#include "DSPTables.h"
#include "DSPInterpreter.h"
#include "DSPJit.h"
#include "gdsp_ext_op.h"
void nop(const UDSPInstruction& opc) {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
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_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"IF NS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF S", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF G", 0x0272, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF LE", 0x0273, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF NZ", 0x0274, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF Z", 0x0275, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF L", 0x0276, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF GE", 0x0277, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF LNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF LZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // Hermes doesn't list this
{"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"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},
{"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, // 0x007f?
{"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL}, // 0x007f?
{"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x007f}}, NULL, NULL},
{"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x007f}}, 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_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL,},
{"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andfc, 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_ACC, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
{"ORF", 0x02e0, 0xfeff, nop, 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_ACC, 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_ACC, 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_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
{"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 2, 2, {{P_REG, 1, 0, 0, 0x00c0}, {P_REG, 2, 1, 0, 0x0003}}, 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},
// These guys probably change the precision or range of some operations.
// The question is which. 16-bit mode vs 40-bit mode sounds plausible for SET40/SET16.
// Maybe Set15 makes the dsp drop the top bit from all calculations or something? Or clamp?
// SET15/CLR15 is commonly used around MULXAC in Zeldas.
// SET16 is done around complicated loops with many madds etc.
{"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},
{"SET40", 0x8e00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SET16", 0x8f00, 0xffff, DSPInterpreter::srbith, nop, 1 | P_EXT, 0, {}, 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},
{"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},
{"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, 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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
// GUESSING NOT SURE AT ALL!!!!
{"TSTAXL", 0xa100, 0xffff, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, 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_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"CLRAL0", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0
{"CLRAL1", 0xfd00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl1
{"CLRA0", 0x8100, 0xffff, DSPInterpreter::clr, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0
{"CLRA1", 0x8900, 0xffff, DSPInterpreter::clr, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc1
{"CLRP", 0x8400, 0xffff, DSPInterpreter::clrp, nop, 1 | P_EXT, 0, {}, },
{"MOV", 0x6c00, 0xfeff, DSPInterpreter::mov, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 1, 0, 9, 0x0200}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADDP", 0x4e00, 0xfeff, DSPInterpreter::addp, nop, 1 | P_EXT, 1, {{P_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 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, nop, 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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 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_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 12, 0x1000}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 12, 0x1000}, {P_ACCM, 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_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 12, 0x1000}, {P_ACCM, 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_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 12, 0x1000}, {P_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_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_ACCM, 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_ACCM, 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_ACCM, 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_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 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},
};
DSPOPCTemplate opcodes_ext[] =
{
{"L", 0x0040, 0x00c4, nop, nop, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"LN", 0x0044, 0x00c4, nop, 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,},
{"LSN", 0x0084, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
{"LSM", 0x0088, 0x00ce, nop, nop, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, NULL, NULL,},
{"LSNM", 0x008c, 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,},
{"SLN", 0x0086, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
{"SLM", 0x008a, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
{"SLNM", 0x008e, 0x00ce, nop, nop, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, NULL, NULL,},
{"S", 0x0020, 0x00e4, nop, nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
{"SN", 0x0024, 0x00e4, nop, nop, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, NULL, NULL,},
{"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, 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, 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, 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, nop, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"MV", 0x0010, 0x00f0, nop, nop, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"DR", 0x0004, 0x00fc, nop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"IR", 0x0008, 0x00fc, nop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"NR", 0x000c, 0x00fc, nop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
};
const u32 opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
const u32 opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
u8 opSize[OPTABLE_SIZE];
dspInstFunc opTable[OPTABLE_SIZE];
dspInstFunc prologueTable[OPTABLE_SIZE];
dspInstFunc epilogueTable[OPTABLE_SIZE];
const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
{
for (u32 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 (u32 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);
}
}
}
}
}
void ComputeInstruction(const UDSPInstruction& inst)
{
if (prologueTable[inst.hex])
prologueTable[inst.hex](inst);
opTable[inst.hex](inst);
if (epilogueTable[inst.hex])
epilogueTable[inst.hex](inst);
}

View File

@ -0,0 +1,125 @@
// 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"
enum parameterType
{
P_NONE = 0x0000,
P_VAL = 0x0001,
P_IMM = 0x0002,
P_MEM = 0x0003,
P_STR = 0x0004,
P_REG = 0x8000,
P_REG08 = P_REG | 0x0800,
P_REG10 = P_REG | 0x1000,
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 | 0x1a00,
P_REG1C = P_REG | 0x1c00,
// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value)
P_ACCD = P_REG | 0x1c80,
P_ACCM = P_REG | 0x1e00, // used for mid accum
// The following are not in gcdsptool
P_ACCM_D = P_REG | 0x1e80,
P_ACC = P_REG | 0x2000,
P_ACC_D = P_REG | 0x2080,
P_AX = P_REG | 0x2200,
P_AX_D = P_REG | 0x2280,
P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
P_REF = P_REG | 0x4000,
P_PRG = P_REF | P_REG,
};
#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&);
typedef struct
{
parameterType type;
u8 size;
u8 loc;
s8 lshift;
u16 mask;
} DSPOParams;
typedef struct
{
const char *name;
u16 opcode;
u16 opcode_mask;
dspInstFunc interpFunc;
dspInstFunc jitFunc;
u8 size;
u8 param_count;
DSPOParams params[8];
dspInstFunc prologue;
dspInstFunc epilogue;
} DSPOPCTemplate;
extern DSPOPCTemplate opcodes[];
extern const u32 opcodes_size;
extern DSPOPCTemplate opcodes_ext[];
extern const u32 opcodes_ext_size;
extern u8 opSize[OPTABLE_SIZE];
extern dspInstFunc opTable[];
void InitInstructionTable();
void ComputeInstruction(const UDSPInstruction& 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

View File

@ -0,0 +1,94 @@
// 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 "Debugger.h"
#include "DSPRegisterView.h"
wxString CRegTable::GetValue(int row, int col)
{
if (row < 36) // 32 "normal" regs
{
switch (col)
{
case 0: return wxString::FromAscii(gd_dis_get_reg_name(row));
case 1: return wxString::Format(wxT("0x%04x"), g_dsp.r[row]);
default: return wxString::FromAscii("");
}
}
return wxString::FromAscii("");
}
void CRegTable::SetValue(int, int, const wxString &)
{
}
void CRegTable::UpdateCachedRegs()
{
if (m_CachedCounter == g_dsp.step_counter)
{
return;
}
m_CachedCounter = g_dsp.step_counter;
for (int i = 0; i < 36; ++i)
{
m_CachedRegHasChanged[i] = (m_CachedRegs[i] != g_dsp.r[i]);
m_CachedRegs[i] = g_dsp.r[i];
}
}
wxGridCellAttr *CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
{
wxGridCellAttr *attr = new wxGridCellAttr();
attr->SetBackgroundColour(wxColour(wxT("#FFFFFF")));
switch (col)
{
case 1:
attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
break;
default:
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
break;
}
if (col == 1)
attr->SetTextColour(m_CachedRegHasChanged[row] ? wxColor(wxT("#FF0000")) : wxColor(wxT("#000000")));
attr->IncRef();
return attr;
}
DSPRegisterView::DSPRegisterView(wxWindow *parent, wxWindowID id)
: wxGrid(parent, id)
{
SetTable(new CRegTable(), true);
SetRowLabelSize(0);
SetColLabelSize(0);
DisableDragRowSize();
AutoSizeColumns();
}
void DSPRegisterView::Update()
{
ForceRefresh();
((CRegTable *)GetTable())->UpdateCachedRegs();
}

View File

@ -0,0 +1,56 @@
// 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 __DSPREGISTERVIEW_h__
#define __DSPREGISTERVIEW_h__
#include <wx/grid.h>
class CRegTable : public wxGridTableBase
{
private:
u64 m_CachedCounter;
u16 m_CachedRegs[32];
bool m_CachedRegHasChanged[32];
DECLARE_NO_COPY_CLASS(CRegTable);
public:
CRegTable()
{
memset(m_CachedRegs, 0, sizeof(m_CachedRegs));
memset(m_CachedRegHasChanged, 0, sizeof(m_CachedRegHasChanged));
}
int GetNumberCols(void) {return 2;}
int GetNumberRows(void) {return 36;}
bool IsEmptyCell(int row, int col) {return false;}
wxString GetValue(int row, int col);
void SetValue(int row, int col, const wxString &);
wxGridCellAttr *GetAttr(int, int, wxGridCellAttr::wxAttrKind);
void UpdateCachedRegs();
};
class DSPRegisterView : public wxGrid
{
public:
DSPRegisterView(wxWindow* parent, wxWindowID id);
void Update();
};
#endif //__DSPREGISTERVIEW_h__

View File

@ -0,0 +1,477 @@
// 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 "Common.h" // Common
#include <iostream> // System
#include <fstream>
#include <sstream>
#include "Debugger.h"
#include "DSPRegisterView.h"
// Event table and class
BEGIN_EVENT_TABLE(DSPDebuggerLLE, wxFrame)
EVT_CLOSE(DSPDebuggerLLE::OnClose)
EVT_MENU_RANGE(ID_RUNTOOL, ID_STEPTOOL, DSPDebuggerLLE::OnChangeState)
EVT_MENU(ID_SHOWPCTOOL, DSPDebuggerLLE::OnShowPC)
EVT_MENU(ID_DUMPCODETOOL, DSPDebuggerLLE::OnDumpCode)
EVT_LIST_ITEM_RIGHT_CLICK(ID_DISASM, DSPDebuggerLLE::OnRightClick)
EVT_LIST_ITEM_ACTIVATED(ID_DISASM, DSPDebuggerLLE::OnDoubleClick)
END_EVENT_TABLE()
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow *parent, wxWindowID id, const wxString &title,
const wxPoint &position, const wxSize& size, long style)
: wxFrame(parent, id, title, position, size, style)
, m_CachedStepCounter(-1)
, m_CachedCR(-1)
, m_State(RUN)
, m_CachedUCodeCRC(-1)
{
CreateGUIControls();
}
DSPDebuggerLLE::~DSPDebuggerLLE()
{
}
void DSPDebuggerLLE::CreateGUIControls()
{
// Basic settings
SetSize(700, 500);
this->SetSizeHints(700, 500);
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
m_Toolbar = CreateToolBar(wxTB_NODIVIDER|wxTB_NOICONS|wxTB_HORZ_TEXT|wxTB_DOCKABLE, ID_TOOLBAR);
m_Toolbar->AddTool(ID_RUNTOOL, wxT("Run"), wxNullBitmap, wxEmptyString, wxITEM_NORMAL);
m_Toolbar->AddTool(ID_STEPTOOL, wxT("Step"), wxNullBitmap, wxT("Step Code "), wxITEM_NORMAL);
m_Toolbar->AddTool(ID_SHOWPCTOOL, wxT("Show Pc"), wxNullBitmap, wxT("Reset To PC counter"), wxITEM_NORMAL);
m_Toolbar->AddTool(ID_JUMPTOTOOL, wxT("Jump"), wxNullBitmap, wxT("Jump to a specific Address"), wxITEM_NORMAL);
m_Toolbar->AddSeparator();
m_Toolbar->AddCheckTool(ID_DUMPCODETOOL, wxT("Dump"), wxNullBitmap, wxNullBitmap, wxT("Dump UCode to file and disasm"));
m_Toolbar->AddSeparator();
m_Toolbar->AddCheckTool(ID_CHECK_ASSERTINT, wxT("AssertInt"), wxNullBitmap, wxNullBitmap, wxEmptyString);
m_Toolbar->AddCheckTool(ID_CHECK_HALT, wxT("Halt"), wxNullBitmap, wxNullBitmap, wxEmptyString);
m_Toolbar->AddCheckTool(ID_CHECK_INIT, wxT("Init"), wxNullBitmap, wxNullBitmap, wxEmptyString);
m_Toolbar->Realize();
wxBoxSizer* sMain = new wxBoxSizer(wxHORIZONTAL);
m_Disasm = new wxListCtrl(this, ID_DISASM, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
sMain->Add(m_Disasm, 4, wxALL|wxEXPAND, 5);
wxStaticLine* m_staticline = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL);
sMain->Add(m_staticline, 0, wxEXPAND|wxALL, 5);
m_Regs = new DSPRegisterView(this, ID_DSP_REGS);
sMain->Add(m_Regs, 1, wxEXPAND|wxALL, 5);
this->SetSizer(sMain);
this->Layout();
// Add the disasm columns
m_Disasm->InsertColumn(COLUMN_BP, wxT("BP"), wxLIST_FORMAT_LEFT, 25);
m_Disasm->InsertColumn(COLUMN_FUNCTION, wxT("Function"), wxLIST_FORMAT_LEFT, 160);
m_Disasm->InsertColumn(COLUMN_ADDRESS, wxT("Address"), wxLIST_FORMAT_LEFT, 55);
m_Disasm->InsertColumn(COLUMN_MNEMONIC, wxT("Mnemonic"), wxLIST_FORMAT_LEFT, 55);
m_Disasm->InsertColumn(COLUMN_OPCODE, wxT("Opcode"), wxLIST_FORMAT_LEFT, 60);
m_Disasm->InsertColumn(COLUMN_EXT, wxT("Ext"), wxLIST_FORMAT_LEFT, 40);
m_Disasm->InsertColumn(COLUMN_PARAM, wxT("Param"), wxLIST_FORMAT_LEFT, 500);
}
void DSPDebuggerLLE::OnClose(wxCloseEvent& event)
{
wxWindow::Destroy();
event.Skip();
}
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
{
switch (event.GetId())
{
case ID_RUNTOOL:
if ((m_State == RUN) || (m_State == RUN_START))
m_State = PAUSE;
else
m_State = RUN_START;
break;
case ID_STEPTOOL:
m_State = STEP;
break;
}
UpdateState();
}
void DSPDebuggerLLE::OnShowPC(wxCommandEvent& event)
{
Refresh();
FocusOnPC();
}
void DSPDebuggerLLE::OnDumpCode(wxCommandEvent& event)
{
g_dsp.dump_imem = event.IsChecked();
}
void DSPDebuggerLLE::OnRightClick(wxListEvent& event)
{
long item = m_Disasm->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
u16 SelectedPC = static_cast<u16>(m_Disasm->GetItemData(item));
g_dsp.pc = SelectedPC;
Refresh();
}
void DSPDebuggerLLE::OnDoubleClick(wxListEvent& event)
{
long item = m_Disasm->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
u16 SelectedPC = static_cast<u16>(m_Disasm->GetItemData(item));
ToggleBreakPoint(SelectedPC);
if (IsBreakPoint(SelectedPC))
m_Disasm->SetItem(item, COLUMN_BP, wxT("*"));
else
m_Disasm->SetItem(item, COLUMN_BP, wxT(""));
}
void DSPDebuggerLLE::Refresh()
{
UpdateSymbolMap();
UpdateDisAsmListView();
UpdateRegisterFlags();
UpdateState();
}
void DSPDebuggerLLE::FocusOnPC()
{
UnselectAll();
for (int i = 0; i < m_Disasm->GetItemCount(); i++)
{
if (m_Disasm->GetItemData(i) == g_dsp.pc)
{
m_Disasm->EnsureVisible(i - 5);
m_Disasm->EnsureVisible(i + 5);
m_Disasm->SetItemState(i, wxLIST_STATE_FOCUSED|wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED|wxLIST_STATE_SELECTED);
break;
}
}
}
void DSPDebuggerLLE::UnselectAll()
{
for (int i = 0; i < m_Disasm->GetItemCount(); i++)
{
m_Disasm->SetItemState(i, 0, wxLIST_STATE_SELECTED);
}
}
void DSPDebuggerLLE::UpdateState()
{
if ((m_State == RUN) || (m_State == RUN_START))
m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Pause"));
else
m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Run"));
m_Toolbar->Realize();
}
void DSPDebuggerLLE::RebuildDisAsmListView()
{
m_Disasm->Freeze();
m_Disasm->DeleteAllItems();
char Buffer[256];
gd_globals_t gdg;
if (g_dsp.pc & 0x8000)
gdg.binbuf = g_dsp.irom;
else
gdg.binbuf = g_dsp.iram;
gdg.buffer = Buffer;
gdg.buffer_size = 256;
gdg.ext_separator = (char)0xff;
gdg.show_pc = false;
gdg.show_hex = false;
gdg.print_tabs = true;
gdg.decode_names = true;
gdg.decode_registers = true;
for (gdg.pc = 0; gdg.pc < DSP_IROM_SIZE;)
{
u16 CurrentPC = gdg.pc;
if (g_dsp.pc & 0x8000)
CurrentPC |= 0x8000;
char Temp[256];
sprintf(Temp, "0x%04x", CurrentPC);
char Temp2[256];
sprintf(Temp2, "0x%04x", dsp_imem_read(CurrentPC));
char* pOpcode = gd_dis_opcode(&gdg);
const char* pParameter = NULL;
const char* pExtension = NULL;
size_t WholeString = strlen(pOpcode);
for (size_t i = 0; i < WholeString; i++)
{
if (pOpcode[i] == (char)0xff)
{
pOpcode[i] = 0x00;
pExtension = &pOpcode[i + 1];
}
if (pOpcode[i] == 0x09)
{
pOpcode[i] = 0x00;
pParameter = &pOpcode[i + 1];
}
}
const char* pFunctionName = NULL;
if (m_SymbolMap.find(CurrentPC) != m_SymbolMap.end())
{
pFunctionName = m_SymbolMap[CurrentPC].Name.c_str();
}
int Item = m_Disasm->InsertItem(gdg.pc, wxEmptyString);
m_Disasm->SetItem(Item, COLUMN_BP, wxEmptyString);
m_Disasm->SetItem(Item, COLUMN_FUNCTION, wxString::FromAscii(pFunctionName));
m_Disasm->SetItem(Item, COLUMN_ADDRESS, wxString::FromAscii(Temp));
m_Disasm->SetItem(Item, COLUMN_MNEMONIC, wxString::FromAscii(Temp2));
m_Disasm->SetItem(Item, COLUMN_OPCODE, wxString::FromAscii(pOpcode));
m_Disasm->SetItem(Item, COLUMN_EXT, wxString::FromAscii(pExtension));
if (!strcasecmp(pOpcode, "CALL"))
{
u32 FunctionAddress = -1;
sscanf(pParameter, "0x%04x", &FunctionAddress);
if (m_SymbolMap.find(FunctionAddress) != m_SymbolMap.end())
{
pParameter = m_SymbolMap[FunctionAddress].Name.c_str();
}
}
m_Disasm->SetItem(Item, COLUMN_PARAM, wxString::FromAscii(pParameter));
m_Disasm->SetItemData(Item, CurrentPC);
}
// m_Disasm->SortItems(CompareFunc, this); // TODO verify
m_Disasm->Thaw();
}
void DSPDebuggerLLE::UpdateDisAsmListView()
{
if (g_dsp.dram == NULL)
return;
// check if we have to rebuild the list view
if (m_Disasm->GetItemCount() == 0)
{
RebuildDisAsmListView();
}
else
{
u16 FirstPC = static_cast<u16>(m_Disasm->GetItemData(0)); // TODO verify
if ((FirstPC & 0x8000) != (g_dsp.pc & 0x8000))
{
RebuildDisAsmListView();
}
}
if (m_CachedStepCounter == g_dsp.step_counter)
return;
// show PC
FocusOnPC();
m_CachedStepCounter = g_dsp.step_counter;
m_Regs->Update();
}
void DSPDebuggerLLE::UpdateSymbolMap()
{
if (g_dsp.dram == NULL)
return;
if (m_CachedUCodeCRC != g_dsp.iram_crc)
{
// load symbol map (if there is one)
m_CachedUCodeCRC = g_dsp.iram_crc;
char FileName[256];
sprintf(FileName, "%sDSP_%08x.map", FULL_MAPS_DIR, m_CachedUCodeCRC);
LoadSymbolMap(FileName);
// rebuild the disasm
RebuildDisAsmListView();
}
}
void DSPDebuggerLLE::UpdateRegisterFlags()
{
if (m_CachedCR == g_dsp.cr)
return;
m_Toolbar->ToggleTool(ID_DUMPCODETOOL, g_dsp.dump_imem);
m_Toolbar->ToggleTool(ID_CHECK_ASSERTINT, g_dsp.cr & 0x02 ? true : false);
m_Toolbar->ToggleTool(ID_CHECK_HALT, g_dsp.cr & 0x04 ? true : false);
m_Toolbar->ToggleTool(ID_CHECK_INIT, g_dsp.cr & 0x800 ? true : false);
m_CachedCR = g_dsp.cr;
}
bool DSPDebuggerLLE::CanDoStep()
{
// update the symbols all the time because they're script cmds like bps
UpdateSymbolMap();
switch (m_State)
{
case RUN_START:
m_State = RUN;
return true;
case RUN:
if (IsBreakPoint(g_dsp.pc))
{
Refresh();
m_State = PAUSE;
return false;
}
return true;
case PAUSE:
Refresh();
return false;
case STEP:
Refresh();
m_State = PAUSE;
return true;
}
return false;
}
void DSPDebuggerLLE::DebugBreak()
{
m_State = PAUSE;
}
bool DSPDebuggerLLE::IsBreakPoint(u16 _Address)
{
return(std::find(m_BreakPoints.begin(), m_BreakPoints.end(), _Address) != m_BreakPoints.end());
}
void DSPDebuggerLLE::ToggleBreakPoint(u16 _Address)
{
if (IsBreakPoint(_Address))
RemoveBreakPoint(_Address);
else
AddBreakPoint(_Address);
}
void DSPDebuggerLLE::RemoveBreakPoint(u16 _Address)
{
CBreakPointList::iterator itr = std::find(m_BreakPoints.begin(), m_BreakPoints.end(), _Address);
if (itr != m_BreakPoints.end())
m_BreakPoints.erase(itr);
}
void DSPDebuggerLLE::AddBreakPoint(u16 _Address)
{
CBreakPointList::iterator itr = std::find(m_BreakPoints.begin(), m_BreakPoints.end(), _Address);
if (itr == m_BreakPoints.end())
m_BreakPoints.push_back(_Address);
}
void DSPDebuggerLLE::ClearBreakPoints()
{
m_BreakPoints.clear();
}
bool DSPDebuggerLLE::LoadSymbolMap(const char* _pFileName)
{
m_SymbolMap.clear();
FILE* pFile = fopen(_pFileName, "r");
if (!pFile)
return false;
char Name[1024];
u32 AddressStart, AddressEnd;
while (!feof(pFile))
{
char line[512];
fgets(line, 511, pFile);
if (strlen(line) < 2)
continue;
// check for comment
if (line[0] == '.')
continue;
// clear all breakpoints
if (line[0] == 'C')
{
ClearBreakPoints();
continue;
}
// add breakpoint
if (line[0] == 'B')
{
sscanf(line, "B %04x", &AddressStart);
AddBreakPoint(static_cast<u16>(AddressStart));
continue;
}
// default add new symbol
sscanf(line, "%04x %04x %s", &AddressStart, &AddressEnd, Name);
if (m_SymbolMap.find(AddressStart) == m_SymbolMap.end())
m_SymbolMap.insert(std::pair<u16, SSymbol>(AddressStart, SSymbol(AddressStart, AddressEnd, Name)));
else
m_SymbolMap[AddressStart] = SSymbol(AddressStart, AddressEnd, Name);
}
fclose(pFile);
return true;
}

View File

@ -0,0 +1,162 @@
// 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_DEBUGGER_LLE_H
#define _DSP_DEBUGGER_LLE_H
// general things
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <wx/wx.h>
#include <wx/frame.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/statbox.h>
#include <wx/sizer.h>
#include <wx/listctrl.h>
#include <wx/statline.h>
#include "../disassemble.h"
#include "../gdsp_interpreter.h"
#include "../gdsp_memory.h"
class DSPRegisterView;
class DSPDebuggerLLE : public wxFrame
{
public:
DSPDebuggerLLE(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString &title = wxT("DSP LLE Debugger"),
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE);
virtual ~DSPDebuggerLLE();
bool CanDoStep();
void DebugBreak();
private:
DECLARE_EVENT_TABLE();
enum
{
// Toolbar
ID_TOOLBAR = 1000,
ID_RUNTOOL,
ID_STEPTOOL,
ID_SHOWPCTOOL,
ID_JUMPTOTOOL,
ID_DUMPCODETOOL,
ID_DISASMDUMPTOOL,
ID_CHECK_ASSERTINT,
ID_CHECK_HALT,
ID_CHECK_INIT,
// Disasm view
ID_DISASM,
// Register View
ID_DSP_REGS,
};
// Disasm listctrl columns
enum
{
COLUMN_BP,
COLUMN_FUNCTION,
COLUMN_ADDRESS,
COLUMN_MNEMONIC,
COLUMN_OPCODE,
COLUMN_EXT,
COLUMN_PARAM,
};
enum EState
{
PAUSE,
STEP,
RUN,
RUN_START // ignores breakpoints and switches after one step to RUN
};
EState m_State;
u64 m_CachedStepCounter;
u16 m_CachedCR;
u32 m_CachedUCodeCRC;
// Break point handling
typedef std::list<u16>CBreakPointList;
CBreakPointList m_BreakPoints;
bool IsBreakPoint(u16 _Address);
void ToggleBreakPoint(u16 _Address);
void RemoveBreakPoint(u16 _Address);
void AddBreakPoint(u16 _Address);
void ClearBreakPoints();
// Symbols
struct SSymbol
{
u32 AddressStart;
u32 AddressEnd;
std::string Name;
SSymbol(u32 _AddressStart = 0, u32 _AddressEnd = 0, char* _Name = NULL)
: AddressStart(_AddressStart)
, AddressEnd(_AddressEnd)
, Name(_Name)
{
}
};
typedef std::map<u16, SSymbol>CSymbolMap;
CSymbolMap m_SymbolMap;
bool LoadSymbolMap(const char* _pFileName);
// GUI updaters
void UpdateDisAsmListView();
void UpdateRegisterFlags();
void UpdateSymbolMap();
void UpdateState();
void RebuildDisAsmListView();
// GUI items
wxToolBar* m_Toolbar;
wxListCtrl* m_Disasm;
DSPRegisterView* m_Regs;
void OnClose(wxCloseEvent& event);
void OnChangeState(wxCommandEvent& event);
void OnShowPC(wxCommandEvent& event);
void OnDumpCode(wxCommandEvent& event);
void OnRightClick(wxListEvent& event);
void OnDoubleClick(wxListEvent& event);
void CreateGUIControls();
void Refresh();
void FocusOnPC();
void UnselectAll();
};
#endif //_DSP_DEBUGGER_LLE_H

View File

@ -0,0 +1,86 @@
// 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> // I hope this doesn't break anything
#include <stdio.h>
#include <stdarg.h>
#include "Common.h" // for Common::swap
#include "Globals.h"
#include "gdsp_interpreter.h"
// =======================================================================================
// For PB address detection
// --------------
u32 RAM_MASK = 0x1FFFFFF;
u16 Memory_Read_U16(u32 _uAddress)
{
_uAddress &= RAM_MASK;
return Common::swap16(*(u16*)&g_dsp.cpu_ram[_uAddress]);
}
u32 Memory_Read_U32(u32 _uAddress)
{
_uAddress &= RAM_MASK;
return Common::swap32(*(u32*)&g_dsp.cpu_ram[_uAddress]);
}
#if PROFILE
#define PROFILE_MAP_SIZE 0x10000
u64 g_profileMap[PROFILE_MAP_SIZE];
bool g_profile = false;
void ProfilerStart()
{
g_profile = true;
}
void ProfilerAddDelta(int _addr, int _delta)
{
if (g_profile)
{
g_profileMap[_addr] += _delta;
}
}
void ProfilerInit()
{
memset(g_profileMap, 0, sizeof(g_profileMap));
}
void ProfilerDump(u64 count)
{
FILE* pFile = fopen("DSP_Prof.txt", "wt");
if (pFile != NULL)
{
fprintf(pFile, "Number of DSP steps: %llu\n\n", count);
for (int i=0; i<PROFILE_MAP_SIZE;i++)
{
if (g_profileMap[i] > 0)
{
fprintf(pFile, "0x%04X: %llu\n", i, g_profileMap[i]);
}
}
fclose(pFile);
}
}
#endif

View File

@ -0,0 +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 _GLOBALS_H
#define _GLOBALS_H
#include "Common.h"
#include "AudioCommon.h"
#include <stdio.h>
#define WITH_DSP_ON_THREAD 1
#define PROFILE 0
void DSP_DebugBreak();
u16 Memory_Read_U16(u32 _uAddress); // For PB address detection
u32 Memory_Read_U32(u32 _uAddress);
#if PROFILE
void ProfilerDump(u64 _count);
void ProfilerInit();
void ProfilerAddDelta(int _addr, int _delta);
void ProfilerStart();
#endif
#endif

View File

@ -0,0 +1,91 @@
// 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 "../Globals.h"
#include "Common.h"
extern u32 m_addressPBs;
// Get the parameter block location - Example SSBM: We get the addr 8049cf00,
// first we always get 0 and go to AXLIST_STUDIOADDR, then we end up at
// AXLIST_PBADDR.
bool AXTask(u32& _uMail)
{
u32 uAddress = _uMail;
DEBUG_LOG(DSPLLE, "AXTask - ================================================================");
DEBUG_LOG(DSPLLE, "AXTask - AXCommandList-Addr: 0x%08x", uAddress);
bool bExecuteList = true;
while (bExecuteList)
{
// SSBM: We get the addr 8049cf00, first we always get 0
u16 iCommand = Memory_Read_U16(uAddress);
uAddress += 2;
switch (iCommand)
{
// ?
case 0: // AXLIST_STUDIOADDR: //00
{
uAddress += 4;
DEBUG_LOG(DSPLLE, "AXLIST AXLIST_SBUFFER: %08x", uAddress);
}
break;
case 2: // AXLIST_PBADDR: // 02
{
m_addressPBs = Memory_Read_U32(uAddress);
uAddress += 4;
DEBUG_LOG(DSPLLE, "AXLIST PB address: %08x", m_addressPBs);
bExecuteList = false;
}
break;
case 7: // AXLIST_SBUFFER: // 7
{
// Hopefully this is where in main ram to write.
uAddress += 4;
DEBUG_LOG(DSPLLE, "AXLIST AXLIST_SBUFFER: %08x", uAddress);
}
break;
default:
{
// Stop the execution of this TaskList
DEBUG_LOG(DSPLLE, "AXLIST default: %08x", uAddress);
bExecuteList = false;
}
break;
} // end of switch
}
DEBUG_LOG(DSPLLE, "AXTask - done, send resume");
DEBUG_LOG(DSPLLE, "AXTask - ================================================================");
// now resume
return true;
}

View File

@ -0,0 +1,334 @@
// 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 <string> // So that we can test if std::string == abc
#include "Common.h"
#include "UCode_AXStructs.h" // they are only in a virtual dir called UCodes AX
// Settings
#define NUMBER_OF_PBS 64 // Todo: move this to a logging class
// Externals
extern u32 m_addressPBs;
float ratioFactor;
int globaliSize;
short globalpBuffer;
u32 gLastBlock;
// Vectors and other things
std::vector<u32> gloopPos(64);
std::vector<u32> gsampleEnd(64);
std::vector<u32> gsamplePos(64);
std::vector<u32> gratio(64);
std::vector<u32> gratiohi(64);
std::vector<u32> gratiolo(64);
std::vector<u32> gfrac(64);
std::vector<u32> gcoef(64);
// PBSampleRateConverter mixer
std::vector<u16> gvolume_left(64);
std::vector<u16> gvolume_right(64);
std::vector<u16> gmixer_control(64);
std::vector<u16> gcur_volume(64);
std::vector<u16> gcur_volume_delta(64);
std::vector<u16> gaudioFormat(64);
std::vector<u16> glooping(64);
std::vector<u16> gsrc_type(64);
std::vector<u16> gis_stream(64);
// loop
std::vector<u16> gloop1(64);
std::vector<u16> gloop2(64);
std::vector<u16> gloop3(64);
std::vector<u16> gadloop1(64);
std::vector<u16> gadloop2(64);
std::vector<u16> gadloop3(64);
// updates
std::vector<u16> gupdates1(64);
std::vector<u16> gupdates2(64);
std::vector<u16> gupdates3(64);
std::vector<u16> gupdates4(64);
std::vector<u16> gupdates5(64);
std::vector<u32> gupdates_addr(64);
// Other things
std::vector<u16> Jump(64); // this is 1 or 0
std::vector<int> musicLength(64);
std::vector< std::vector<int> > vector1(64, std::vector<int>(100,0));
std::vector<int> numberRunning(64);
int j = 0;
int k = 0;
s64 l = 0;
int iupd = 0;
bool iupdonce = false;
std::vector<u16> viupd(15); // the length of the update frequency bar
int vectorLength = 15; // the length of the playback history bar and how long
// old blocks are shown
std::vector<u16> vector62(vectorLength);
std::vector<u16> vector63(vectorLength);
int ReadOutPBs(AXParamBlock * _pPBs, int _num);
// Main logging function
void Logging()
{
// Control how often the screen is updated
j++;
l++;
if (j>1000000) // TODO: make the update frequency adjustable from the logging window
{
AXParamBlock PBs[NUMBER_OF_PBS];
int numberOfPBs = ReadOutPBs(PBs, NUMBER_OF_PBS);
// =======================================================================================
// Vector1 is a vector1[64][100] vector
/*
Move all items back like this
1 to 2
2 3
3 ...
*/
// ----------------
for (int i = 0; i < 64; i++)
{
for (int j = 1; j < vectorLength; j++)
{
vector1.at(i).at(j-1) = vector1.at(i).at(j);
}
}
// =================
// Enter the latest value
for (int i = 0; i < numberOfPBs; i++)
{
vector1.at(i).at(vectorLength-1) = PBs[i].running;
}
// Count how many blocks we have running now
int jj = 0;
for (int i = 0; i < 64; i++)
{
for (int j = 0; j < vectorLength-1; j++)
{
if (vector1.at(i).at(j) == 1)
{
jj++;
}
numberRunning.at(i) = jj;
}
}
// Write the first row
char buffer [1000] = "";
std::string sbuff;
//sbuff = sbuff + " Nr | | frac ratio | old new \n"; // 5
sbuff = sbuff + " Nr pos / end lpos | voll volr curv vold mix | isl[pre yn1 yn2] iss | frac ratio[hi lo] | 1 2 3 4 5\n";
// Read out values for all blocks
for (int i = 0; i < numberOfPBs; i++)
{
if (numberRunning.at(i) > 0)
{
// Write the playback bar
for (int j = 0; j < vectorLength; j++)
{
if(vector1.at(i).at(j) == 0)
{
sbuff = sbuff + " ";
}
else
{
sprintf(buffer, "%c", 177);
sbuff = sbuff + buffer; strcpy(buffer, "");
}
}
int sampleJump;
int loopJump;
//if (PBs[i].running && PBs[i].adpcm_loop_info.yn1 && PBs[i].mixer.volume_left)
if (true)
{
// AXPB base
//int running = pb.running;
gcoef[i] = PBs[i].unknown1;
sampleJump = ((PBs[i].audio_addr.cur_addr_hi << 16) | PBs[i].audio_addr.cur_addr_lo) - gsamplePos[i];
loopJump = ((PBs[i].audio_addr.loop_addr_hi << 16) | PBs[i].audio_addr.loop_addr_lo) - gloopPos[i];
gloopPos[i] = (PBs[i].audio_addr.loop_addr_hi << 16) | PBs[i].audio_addr.loop_addr_lo;
gsampleEnd[i] = (PBs[i].audio_addr.end_addr_hi << 16) | PBs[i].audio_addr.end_addr_lo;
gsamplePos[i] = (PBs[i].audio_addr.cur_addr_hi << 16) | PBs[i].audio_addr.cur_addr_lo;
// PBSampleRateConverter src
gratio[i] = (u32)(((PBs[i].src.ratio_hi << 16) + PBs[i].src.ratio_lo) * ratioFactor);
gratiohi[i] = PBs[i].src.ratio_hi;
gratiolo[i] = PBs[i].src.ratio_lo;
gfrac[i] = PBs[i].src.cur_addr_frac;
// adpcm_loop_info
gadloop1[i] = PBs[i].adpcm.pred_scale;
gadloop2[i] = PBs[i].adpcm.yn1;
gadloop3[i] = PBs[i].adpcm.yn2;
gloop1[i] = PBs[i].adpcm_loop_info.pred_scale;
gloop2[i] = PBs[i].adpcm_loop_info.yn1;
gloop3[i] = PBs[i].adpcm_loop_info.yn2;
// updates
gupdates1[i] = PBs[i].updates.num_updates[0];
gupdates2[i] = PBs[i].updates.num_updates[1];
gupdates3[i] = PBs[i].updates.num_updates[2];
gupdates4[i] = PBs[i].updates.num_updates[3];
gupdates5[i] = PBs[i].updates.num_updates[4];
gupdates_addr[i] = (PBs[i].updates.data_hi << 16) | PBs[i].updates.data_lo;
gaudioFormat[i] = PBs[i].audio_addr.sample_format;
glooping[i] = PBs[i].audio_addr.looping;
gsrc_type[i] = PBs[i].src_type;
gis_stream[i] = PBs[i].is_stream;
// mixer
gvolume_left[i] = PBs[i].mixer.volume_left;
gvolume_right[i] = PBs[i].mixer.volume_right;
gmixer_control[i] = PBs[i].mixer_control;
gcur_volume[i] = PBs[i].vol_env.cur_volume;
gcur_volume_delta[i] = PBs[i].vol_env.cur_volume_delta;
// other stuff
Jump[i] = (gfrac[i] >> 16); // This is 1 or 0
musicLength[i] = gsampleEnd[i] - gloopPos[i];
}
// PRESETS
/*
/" Nr pos / end lpos | voll volr curv vold mix | isl[pre yn1 yn2] iss | frac ratio[hi lo] | 1 2 3 4 5\n";
"---------------|00 12341234/12341234 12341234 | 00000 00000 00000 0000 00000 | 0[000 00000 00000] 0 | 00000 00000[0 00000] |
*/
sprintf(buffer,"%c%i %08i/%08i %08i | %05i %05i %05i %04i %05i | %i[%03i %05i %05i] %i | %05i %05i[%i %05i] | %i %i %i %i %i",
223, i, gsamplePos[i], gsampleEnd[i], gloopPos[i],
gvolume_left[i], gvolume_right[i], gcur_volume[i], gcur_volume_delta[i], gmixer_control[i],
glooping[i], gloop1[i], gloop2[i], gloop3[i], gis_stream[i],
gfrac[i], gratio[i], gratiohi[i], gratiolo[i],
gupdates1[i], gupdates2[i], gupdates3[i], gupdates4[i], gupdates5[i]
);
// write a new line
sbuff = sbuff + buffer; strcpy(buffer, "");
sbuff = sbuff + "\n";
} // end of if (true)
} // end of big loop - for (int i = 0; i < numberOfPBs; i++)
// Write global values
sprintf(buffer, "\nParameter blocks span from %08x | to %08x | distance %i %i\n", m_addressPBs, gLastBlock, (gLastBlock-m_addressPBs), (gLastBlock-m_addressPBs) / 192);
sbuff = sbuff + buffer; strcpy(buffer, "");
// Show update frequency
sbuff = sbuff + "\n";
if(!iupdonce)
{
/*
for (int i = 0; i < 10; i++)
{
viupd.at(i) == 0;
}
*/
viupd.at(0) = 1;
viupd.at(1) = 1;
viupd.at(2) = 1;
iupdonce = true;
}
for (int i = 0; i < (int)viupd.size(); i++) // 0, 1,..., 9
{
if (i < (int)viupd.size()-1)
{
viupd.at(viupd.size()-i-1) = viupd.at(viupd.size()-i-2); // move all forward
}
else
{
viupd.at(0) = viupd.at(viupd.size()-1);
}
// Correction
if (viupd.at(viupd.size()-3) == 1 && viupd.at(viupd.size()-2) == 1 && viupd.at(viupd.size()-1) == 1)
{
viupd.at(0) = 0;
}
if(viupd.at(0) == 0 && viupd.at(1) == 1 && viupd.at(2) == 1 && viupd.at(3) == 0)
{
viupd.at(0) = 1;
}
}
for (int i = 0; i < (int)viupd.size(); i++)
{
if(viupd.at(i) == 0)
sbuff = sbuff + " ";
else
sbuff = sbuff + ".";
}
// ================
// Print
INFO_LOG(DSPLLE, "%s", sbuff.c_str());
sbuff.clear(); strcpy(buffer, "");
// ---------------
k=0;
j=0;
// ---------------
}
}

View File

@ -0,0 +1,23 @@
// 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 LOGGING_H
#define LOGGING_H
void Logging();
#endif

View File

@ -0,0 +1,103 @@
// 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/
// Turn on and off logging modes
// --------------
//#define LOG1 // writes selected parameters only and with more readable formatting
//#define LOG2 // writes all parameters
#include "Common.h"
#include "../Globals.h"
#include "CommonTypes.h" // Pluginspecs
#include "UCode_AXStructs.h" // For the AXParamBlock structure
u32 m_addressPBs = 0;
extern u32 gLastBlock;
int m = 0;
int n = 0;
#ifdef LOG2
bool logall = true;
#else
bool logall = false;
#endif
int ReadOutPBs(AXParamBlock * _pPBs, int _num)
{
int count = 0;
u32 blockAddr = m_addressPBs;
u32 OldblockAddr = blockAddr;
u32 paraAddr = blockAddr;
// reading and 'halfword' swap
n++;
//FIXME if (n > 20 && logall) {Console::ClearScreen();}
for (int i = 0; i < _num; i++)
{
// Check if there is something here.
const short * pSrc = (const short *)g_dspInitialize.pGetMemoryPointer(blockAddr);
// -------------
if (pSrc != NULL) // only read non-blank blocks
{
// Create a shortcut that let us update struct members
short * pDest = (short *) & _pPBs[i];
if (n > 20 && logall) {DEBUG_LOG(DSPLLE, "%c%i:", 223, i);} // logging
// Here we update the PB. We do it by going through all 192 / 2 = 96 u16 values
for (size_t p = 0; p < sizeof(AXParamBlock) / 2; p++)
{
paraAddr += 2;
if(pSrc != NULL)
{
if (pSrc[p] != 0 && n > 20 && logall)
{
DEBUG_LOG(DSPLLE, "%i %04x | ", p, Common::swap16(pSrc[p]));
}
}
pDest[p] = Common::swap16(pSrc[p]);
}
if(n > 20 && logall) {DEBUG_LOG(DSPLLE, "\n");} // logging
// Here we update the block address to the starting point of the next PB
blockAddr = (_pPBs[i].next_pb_hi << 16) | _pPBs[i].next_pb_lo;
// save some values
count++;
gLastBlock = paraAddr; // blockAddr
// ============
}
else
{
break;
}
} // end of the big loop
if (n > 20) {n = 0;} // for logging
// return the number of readed PBs
return count;
}

View File

@ -0,0 +1,143 @@
// 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 UCODE_AX_STRUCTS
#define UCODE_AX_STRUCTS
struct PBMixer
{
u16 volume_left;
u16 unknown;
u16 volume_right;
u16 unknown2;
u16 unknown3[8];
u16 unknown4[6];
};
struct PBInitialTimeDelay
{
u16 unknown[7];
};
// Update data - read these each 1ms subframe and use them!
// It seems that to provide higher time precisions for MIDI events, some games
// use this thing to update the parameter blocks per 1ms sub-block (a block is 5ms).
// Using this data should fix games that are missing MIDI notes.
struct PBUpdates
{
u16 num_updates[5];
u16 data_hi; // These point to main RAM. Not sure about the structure of the data.
u16 data_lo;
};
struct PBUnknown
{
s16 unknown[9];
};
struct PBVolumeEnvelope
{
u16 cur_volume;
s16 cur_volume_delta;
};
struct PBUnknown2
{
u16 unknown_reserved[3];
};
struct PBAudioAddr
{
u16 looping;
u16 sample_format;
u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is active)
u16 loop_addr_lo;
u16 end_addr_hi; // End of sample (and loop), inclusive
u16 end_addr_lo;
u16 cur_addr_hi;
u16 cur_addr_lo;
};
struct PBADPCMInfo
{
s16 coefs[16];
u16 unknown;
u16 pred_scale;
s16 yn1;
s16 yn2;
};
struct PBSampleRateConverter
{
u16 ratio_hi;
u16 ratio_lo;
u16 cur_addr_frac;
u16 last_samples[4];
};
struct PBADPCMLoopInfo
{
u16 pred_scale;
u16 yn1;
u16 yn2;
};
struct AXParamBlock
{
u16 next_pb_hi;
u16 next_pb_lo;
u16 this_pb_hi;
u16 this_pb_lo;
u16 src_type; // Type of sample rate converter (2 = none, ?, linear)
u16 unknown1;
u16 mixer_control;
u16 running; // 1=RUN 0=STOP
u16 is_stream; // 1 = stream, 0 = one shot
PBMixer mixer;
PBInitialTimeDelay initial_time_delay;
PBUpdates updates;
PBUnknown unknown2;
PBVolumeEnvelope vol_env;
PBUnknown2 unknown3;
PBAudioAddr audio_addr;
PBADPCMInfo adpcm;
PBSampleRateConverter src;
PBADPCMLoopInfo adpcm_loop_info;
u16 unknown_maybe_padding[3];
};
enum {
AUDIOFORMAT_ADPCM = 0,
AUDIOFORMAT_PCM8 = 0x19,
AUDIOFORMAT_PCM16 = 0xA,
};
enum {
SRCTYPE_LINEAR = 1,
SRCTYPE_NEAREST = 2,
MIXCONTROL_RAMPING = 8,
};
#endif

View File

@ -0,0 +1,43 @@
# -*- python -*-
Import('env')
import sys
name = "Plugin_DSP_LLE"
if not env['HAVE_AO']:
print name + " must have AO to be build"
Return()
files = [
"Config.cpp",
"DSPConfigDlgLLE.cpp",
"disassemble.cpp",
"gdsp_aram.cpp",
"gdsp_condition_codes.cpp",
"gdsp_ext_op.cpp",
"gdsp_interface.cpp",
"gdsp_interpreter.cpp",
"gdsp_memory.cpp",
"gdsp_registers.cpp",
"Globals.cpp",
"DSPInterpreter.cpp",
"DSPJit.cpp",
"DSPTables.cpp",
"main.cpp",
"Tools.cpp",
"Debugger/Debugger.cpp",
"Debugger/DSPRegisterView.cpp",
"Logging/AXTask.cpp",
"Logging/Logging.cpp",
"Logging/ReadPBs.cpp",
]
lleenv = env.Clone()
lleenv.Append(
CXXFLAGS = [ '-fPIC' ],
LIBS = [ 'common', 'audiocommon' ],
)
lleenv.SharedLibrary(env['plugin_dir']+name, files)

View File

@ -0,0 +1,114 @@
// 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 <stdio.h>
#include <stdlib.h>
#include "Common.h"
#include "Globals.h"
#include "Tools.h"
#include "disassemble.h"
#include "gdsp_interpreter.h"
bool DumpDSPCode(const u8 *data, u32 _Length, u32 crc)
{
char szFilename[MAX_PATH];
sprintf(szFilename, "%sDSP_UC_%08X.bin", FULL_DSP_DUMP_DIR, crc);
FILE* pFile = fopen(szFilename, "wb");
if (pFile)
{
fwrite(data, _Length, 1, pFile);
fclose(pFile);
}
else
{
PanicAlert("Cant open file (%s) to dump UCode!!", szFilename);
return false;
}
if (!DisasmUCodeDump(crc))
{
PanicAlert("Failed to disasm UCode!!", szFilename);
return false;
}
return true;
}
bool DisasmUCodeDump(u32 crc)
{
char binFile[MAX_PATH];
char txtFile[MAX_PATH];
sprintf(binFile, "%sDSP_UC_%08X.bin", FULL_DSP_DUMP_DIR, crc);
sprintf(txtFile, "%sDSP_UC_%08X.txt", FULL_DSP_DUMP_DIR, crc);
FILE* t = fopen(txtFile, "wb");
if (t != NULL)
{
gd_globals_t gdg;
gd_dis_file(&gdg, binFile, t);
fclose(t);
return true;
}
else
return false;
}
u32 GenerateCRC(const unsigned char* _pBuffer, int _pLength)
{
unsigned long CRC = 0xFFFFFFFF;
while (_pLength--)
{
unsigned long Temp = (unsigned long)((CRC & 0xFF) ^ *_pBuffer++);
for (int j = 0; j < 8; j++)
{
if (Temp & 0x1)
Temp = (Temp >> 1) ^ 0xEDB88320;
else
Temp >>= 1;
}
CRC = (CRC >> 8) ^ Temp;
}
return(CRC ^ 0xFFFFFFFF);
}
// TODO make this useful :p
bool DumpCWCode(u32 _Address, u32 _Length)
{
char filename[256];
sprintf(filename, "%sDSP_UCode.bin", FULL_DSP_DUMP_DIR);
FILE* pFile = fopen(filename, "wb");
if (pFile != NULL)
{
for (size_t i = _Address; i < _Address + _Length; i++)
{
u16 val = Common::swap16(g_dsp.iram[i]);
fprintf(pFile, " cw 0x%04x \n", val);
}
fclose(pFile);
return true;
}
return false;
}

View File

@ -0,0 +1,50 @@
// 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/
#pragma once
// UDSPControl
union UDSPControl
{
u16 Hex;
struct
{
unsigned DSPReset : 1; // Write 1 to reset and waits for 0
unsigned DSPAssertInt : 1;
unsigned DSPHalt : 1;
unsigned AI : 1;
unsigned AI_mask : 1;
unsigned ARAM : 1;
unsigned ARAM_mask : 1;
unsigned DSP : 1;
unsigned DSP_mask : 1;
unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag
unsigned unk3 : 1;
unsigned DSPInit : 1; // DSPInit() writes to this flag
unsigned pad : 4;
};
UDSPControl(u16 _Hex = 0)
: Hex(_Hex) {}
};
bool DumpDSPCode(const u8 *data, u32 _Length, u32 crc);
bool DisasmUCodeDump(u32 crc);
u32 GenerateCRC(const unsigned char* _pBuffer, int _pLength);
bool DumpCWCode(u32 _Address, u32 _Length);

View File

@ -0,0 +1,571 @@
/*====================================================================
filename: disassemble.cpp
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.
====================================================================*/
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include "Globals.h"
#include "disassemble.h"
#include "DSPTables.h"
// #include "gdsp_tool.h"
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
u32 unk_opcodes[0x10000];
// predefined labels
typedef struct pdlabel_t
{
u16 addr;
const char* name;
const char* description;
} pdlabels_t;
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",},
{0xffc9, "DSCR", "DSP DMA Control Reg",},
{0xffcb, "DSBL", "DSP DMA Block Length",},
{0xffcd, "DSPA", "DSP DMA DMEM Address",},
{0xffce, "DSMAH", "DSP DMA Mem Address H",},
{0xffcf, "DSMAL", "DSP DMA Mem Address L",},
{0xffd1, "SampleFormat", "SampleFormat",},
{0xffd3, "Unk Zelda", "Unk Zelda writes 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",},
{0xffef, "AMDM", "ARAM DMA Request Mask",},
{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",},
};
pdlabel_t regnames[] =
{
{0x00, "R00", "Register 00",},
{0x01, "R01", "Register 01",},
{0x02, "R02", "Register 02",},
{0x03, "R03", "Register 03",},
{0x04, "R04", "Register 04",},
{0x05, "R05", "Register 05",},
{0x06, "R06", "Register 06",},
{0x07, "R07", "Register 07",},
{0x08, "R08", "Register 08",},
{0x09, "R09", "Register 09",},
{0x0a, "R10", "Register 10",},
{0x0b, "R11", "Register 11",},
{0x0c, "ST0", "Call stack",},
{0x0d, "ST1", "Data stack",},
{0x0e, "ST2", "Loop addr stack",},
{0x0f, "ST3", "Loop counter",},
{0x00, "ACH0", "Accu High 0",},
{0x11, "ACH1", "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", "Register 28",},
{0x1d, "AC1.L", "Register 29",},
{0x1e, "AC0.M", "Register 00",},
{0x1f, "AC1.M", "Register 00",},
// To resolve special names.
{0x20, "ACC0", "Accu Full 0",},
{0x21, "ACC1", "Accu Full 1",},
{0x22, "AX0", "Extra Accu 0",},
{0x23, "AX1", "Extra Accu 1",},
};
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;
}
extern void nop(const UDSPInstruction& opc);
char* gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf)
{
char* buf = strbuf;
u32 val;
for (int j = 0; j < opc->param_count; j++)
{
if (j > 0)
{
sprintf(buf, ", ");
buf += strlen(buf);
}
if (opc->params[j].loc >= 1)
val = op2;
else
val = op1;
val &= opc->params[j].mask;
if (opc->params[j].lshift < 0)
val = val << (-opc->params[j].lshift);
else
val = val >> opc->params[j].lshift;
u32 type;
type = opc->params[j].type;
if ((type & 0xff) == 0x10)
type &= 0xff00;
if (type & P_REG)
{
if (type == P_ACCD) // Used to be P_ACCM_D TODO verify
val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8);
else
val |= (type & P_REGS_MASK) >> 8;
type &= ~P_REGS_MASK;
}
switch (type)
{
case P_REG:
if (gdg->decode_registers)
sprintf(buf, "$%s", regnames[val].name);
else
sprintf(buf, "$%d", val);
break;
case P_PRG:
if (gdg->decode_registers)
sprintf(buf, "@$%s", regnames[val].name);
else
sprintf(buf, "@$%d", val);
break;
case P_VAL:
if (gdg->decode_names)
sprintf(buf, "%s", pdname(val));
else
sprintf(buf, "0x%04x", val);
break;
case P_IMM:
if (opc->params[j].size != 2)
{
if (opc->params[j].mask == 0x007f) // LSL, LSR, ASL, ASR
sprintf(buf, "#%d", val < 64 ? val : -(0x80 - (s32)val));
else
sprintf(buf, "#0x%02x", val);
}
else
sprintf(buf, "#0x%04x", val);
break;
case P_MEM:
if (opc->params[j].size != 2)
val = (u16)(s8)val;
if (gdg->decode_names)
sprintf(buf, "@%s", pdname(val));
else
sprintf(buf, "@0x%04x", val);
break;
default:
ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc->params[j].type);
// exit(-1);
break;
}
buf += strlen(buf);
}
return strbuf;
}
gd_globals_t* gd_init()
{
gd_globals_t* gdg = (gd_globals_t*)malloc(sizeof(gd_globals_t));
memset(gdg, 0, sizeof(gd_globals_t));
return(gdg);
}
u16 gd_dis_get_opcode_size(gd_globals_t* gdg)
{
DSPOPCTemplate* opc = 0;
DSPOPCTemplate* opc_ext = 0;
bool extended;
if ((gdg->pc & 0x7fff) >= 0x1000)
return 1;
u32 op1 = Common::swap16(gdg->binbuf[gdg->pc & 0x0fff]);
for (u32 j = 0; j < opcodes_size; j++)
{
u16 mask;
if (opcodes[j].size & P_EXT)
mask = opcodes[j].opcode_mask & 0xff00;
else
mask = opcodes[j].opcode_mask;
if ((op1 & mask) == opcodes[j].opcode)
{
opc = &opcodes[j];
break;
}
}
if (!opc)
{
ERROR_LOG(DSPLLE, "get_opcode_size ARGH");
exit(0);
}
if (opc->size & P_EXT && op1 & 0x00ff)
extended = true;
else
extended = false;
if (extended)
{
// opcode has an extension
// find opcode
for (u32 j = 0; j < opcodes_ext_size; j++)
{
if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode)
{
opc_ext = &opcodes_ext[j];
break;
}
}
if (!opc_ext)
{
ERROR_LOG(DSPLLE, "get_opcode_size ext ARGH");
}
return opc_ext->size;
}
return(opc->size & ~P_EXT);
}
char* gd_dis_opcode(gd_globals_t* gdg)
{
u32 j;
u32 op1, op2;
const DSPOPCTemplate *opc = NULL;
const DSPOPCTemplate *opc_ext = NULL;
u16 pc;
char* buf = gdg->buffer;
bool extended;
pc = gdg->pc;
*buf = '\0';
if ((pc & 0x7fff) >= 0x1000)
{
gdg->pc++;
return gdg->buffer;
}
pc &= 0x0fff;
op1 = Common::swap16(gdg->binbuf[pc]);
// find opcode
for (j = 0; j < opcodes_size; j++)
{
u16 mask;
if (opcodes[j].size & P_EXT)
mask = opcodes[j].opcode_mask & 0xff00;
else
mask = opcodes[j].opcode_mask;
if ((op1 & mask) == opcodes[j].opcode)
{
opc = &opcodes[j];
break;
}
}
const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
if (!opc)
opc = &fake_op;
if (opc->size & P_EXT && op1 & 0x00ff)
extended = true;
else
extended = false;
if (extended)
{
// opcode has an extension
// find opcode
for (j = 0; j < opcodes_ext_size; j++)
{
if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode)
{
opc_ext = &opcodes_ext[j];
break;
}
}
}
// printing
if (gdg->show_pc)
sprintf(buf, "%04x ", gdg->pc);
buf += strlen(buf);
if ((opc->size & ~P_EXT) == 2)
{
op2 = Common::swap16(gdg->binbuf[pc + 1]);
if (gdg->show_hex)
sprintf(buf, "%04x %04x ", op1, op2);
}
else
{
op2 = 0;
if (gdg->show_hex)
sprintf(buf, "%04x ", op1);
}
buf += strlen(buf);
char tmpbuf[20];
if (extended)
sprintf(tmpbuf, "%s%c%s", opc->name, gdg->ext_separator, opc_ext->name);
else
sprintf(tmpbuf, "%s", opc->name);
if (gdg->print_tabs)
sprintf(buf, "%s\t", tmpbuf);
else
sprintf(buf, "%-12s", tmpbuf);
buf += strlen(buf);
if (opc->param_count > 0)
gd_dis_params(gdg, opc, op1, op2, buf);
buf += strlen(buf);
if (extended)
{
if (opc->param_count > 0)
sprintf(buf, " ");
buf += strlen(buf);
sprintf(buf, ": ");
buf += strlen(buf);
if (opc_ext->param_count > 0)
gd_dis_params(gdg, opc_ext, op1, op2, buf);
buf += strlen(buf);
}
if (opc->opcode_mask == 0)
{
// unknown opcode
unk_opcodes[op1]++;
sprintf(buf, "\t\t; *** UNKNOWN OPCODE ***");
}
if (extended)
gdg->pc += opc_ext->size;
else
gdg->pc += opc->size & ~P_EXT;
return(gdg->buffer);
}
bool gd_dis_file(gd_globals_t* gdg, char* name, FILE* output)
{
gd_dis_open_unkop();
FILE* in;
u32 size;
in = fopen(name, "rb");
if (in == NULL)
return false;
fseek(in, 0, SEEK_END);
size = (int)ftell(in);
fseek(in, 0, SEEK_SET);
gdg->binbuf = (u16*)malloc(size);
fread(gdg->binbuf, 1, size, in);
gdg->buffer = (char*)malloc(256);
gdg->buffer_size = 256;
for (gdg->pc = 0; gdg->pc < (size / 2);)
fprintf(output, "%s\n", gd_dis_opcode(gdg));
fclose(in);
free(gdg->binbuf);
gdg->binbuf = NULL;
free(gdg->buffer);
gdg->buffer = NULL;
gdg->buffer_size = 0;
gd_dis_close_unkop();
return true;
}
void gd_dis_close_unkop()
{
FILE* uo;
int i, j;
u32 count = 0;
char filename[MAX_PATH];
sprintf(filename, "%sUnkOps.bin", FULL_DSP_DUMP_DIR);
uo = fopen(filename, "wb");
if (uo)
{
fwrite(unk_opcodes, 1, sizeof(unk_opcodes), uo);
fclose(uo);
}
sprintf(filename, "%sUnkOps.txt", FULL_DSP_DUMP_DIR);
uo = fopen(filename, "w");
if (uo)
{
for (i = 0; i < 0x10000; i++)
{
if (unk_opcodes[i])
{
count++;
fprintf(uo, "OP%04x\t%d", i, unk_opcodes[i]);
for (j = 15; j >= 0; j--)
{
if ((j & 0x3) == 3)
fprintf(uo, "\tb");
fprintf(uo, "%d", (i >> j) & 0x1);
}
fprintf(uo, "\n");
}
}
fprintf(uo, "Unknown opcodes count: %d\n", count);
fclose(uo);
}
}
void gd_dis_open_unkop()
{
FILE* uo;
char filename[MAX_PATH];
sprintf(filename, "%sUnkOps.bin", FULL_DSP_DUMP_DIR);
uo = fopen(filename, "rb");
if (uo)
{
fread(unk_opcodes, 1, sizeof(unk_opcodes), uo);
fclose(uo);
}
else
{
int i;
for (i = 0; i < 0x10000; i++)
{
unk_opcodes[i] = 0;
}
}
}
const char *gd_dis_get_reg_name(u16 reg)
{
return regnames[reg].name;
}

View File

@ -0,0 +1,50 @@
/*====================================================================
filename: opcodes.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.
====================================================================*/
#pragma once
#include "Common.h"
typedef struct gd_globals_t
{
bool print_tabs;
bool show_hex;
bool show_pc;
bool decode_names;
bool decode_registers;
u16* binbuf;
u16 pc;
char* buffer;
u16 buffer_size;
char ext_separator;
} gd_globals_t;
char* gd_dis_opcode(gd_globals_t* gdg);
bool gd_dis_file(gd_globals_t* gdg, char* name, FILE* output);
void gd_dis_close_unkop();
void gd_dis_open_unkop();
const char* gd_dis_get_reg_name(u16 reg);

View File

@ -0,0 +1,116 @@
// 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 "Globals.h"
#include "gdsp_interface.h"
#include "gdsp_interpreter.h"
extern u16 dsp_swap16(u16 x);
// The hardware adpcm decoder :)
s16 ADPCM_Step(u32& _rSamplePos, u32 _BaseAddress)
{
s16* pCoefTable = (s16*)&gdsp_ifx_regs[DSP_COEF_A1_0];
if (((_rSamplePos) & 15) == 0)
{
gdsp_ifx_regs[DSP_PRED_SCALE] = g_dspInitialize.pARAM_Read_U8((_rSamplePos & ~15) >> 1);
_rSamplePos += 2;
}
int scale = 1 << (gdsp_ifx_regs[DSP_PRED_SCALE] & 0xF);
int coef_idx = gdsp_ifx_regs[DSP_PRED_SCALE] >> 4;
s32 coef1 = pCoefTable[coef_idx * 2 + 0];
s32 coef2 = pCoefTable[coef_idx * 2 + 1];
int temp = (_rSamplePos & 1) ?
(g_dspInitialize.pARAM_Read_U8(_rSamplePos >> 1) & 0xF) :
(g_dspInitialize.pARAM_Read_U8(_rSamplePos >> 1) >> 4);
if (temp >= 8)
temp -= 16;
// 0x400 = 0.5 in 11-bit fixed point
int val = (scale * temp) + ((0x400 + coef1 * (s16)gdsp_ifx_regs[DSP_YN1] + coef2 * (s16)gdsp_ifx_regs[DSP_YN2]) >> 11);
// Clamp values.
if (val > 0x7FFF)
val = 0x7FFF;
else if (val < -0x7FFF)
val = -0x7FFF;
gdsp_ifx_regs[DSP_YN2] = gdsp_ifx_regs[DSP_YN1];
gdsp_ifx_regs[DSP_YN1] = val;
_rSamplePos++;
// The advanced interpolation (linear, polyphase,...) is done by the UCode, so we don't
// need to bother with it here.
return val;
}
u16 dsp_read_aram()
{
// u32 BaseAddress = (gdsp_ifx_regs[DSP_ACSAH] << 16) | gdsp_ifx_regs[DSP_ACSAL];
u32 EndAddress = (gdsp_ifx_regs[DSP_ACEAH] << 16) | gdsp_ifx_regs[DSP_ACEAL];
u32 Address = (gdsp_ifx_regs[DSP_ACCAH] << 16) | gdsp_ifx_regs[DSP_ACCAL];
u16 val;
// lets the "hardware" decode
switch (gdsp_ifx_regs[DSP_FORMAT])
{
case 0x00:
val = ADPCM_Step(Address, EndAddress);
break;
case 0x0A:
val = (g_dspInitialize.pARAM_Read_U8(Address) << 8) | g_dspInitialize.pARAM_Read_U8(Address + 1);
gdsp_ifx_regs[DSP_YN2] = gdsp_ifx_regs[DSP_YN1];
gdsp_ifx_regs[DSP_YN1] = val;
Address += 2;
break;
default:
val = (g_dspInitialize.pARAM_Read_U8(Address) << 8) | g_dspInitialize.pARAM_Read_U8(Address + 1);
Address += 2;
ERROR_LOG(DSPLLE, "Unknown DSP Format %i", gdsp_ifx_regs[DSP_FORMAT]);
break;
}
// TODO: Take ifx GAIN into account.
// check for loop
if (Address > EndAddress)
{
Address = (gdsp_ifx_regs[DSP_ACSAH] << 16) | gdsp_ifx_regs[DSP_ACSAL];
gdsp_generate_exception(3);
gdsp_generate_exception(5);
// Somehow, YN1 and YN2 must be initialized with their "loop" values, so yeah,
// it seems likely that we should raise an exception to let the DSP program do that,
// at least if DSP_FORMAT == 0x0A.
}
gdsp_ifx_regs[DSP_ACCAH] = Address >> 16;
gdsp_ifx_regs[DSP_ACCAL] = Address & 0xffff;
return(val);
}

View File

@ -0,0 +1,23 @@
// 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 _GDSP_ARAM_H
#define _GDSP_ARAM_H
u16 dsp_read_aram();
#endif

View File

@ -0,0 +1,156 @@
// 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 "gdsp_condition_codes.h"
#include "gdsp_interpreter.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] |= 0x8;
}
if (_Value == 0)
{
g_dsp.r[DSP_REG_SR] |= 0x4;
}
// 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] |= 0x8;
}
if (_Value == 0)
{
g_dsp.r[DSP_REG_SR] |= 0x4;
}
// weird
if ((_Value >> 14) == 0)
{
g_dsp.r[DSP_REG_SR] |= 0x20;
}
}
int GetMultiplyModifier()
{
if (g_dsp.r[DSP_REG_SR] & (1 << 13))
return 1;
else
return 2;
}
// 0x02 - overflow????
// 0x04 - Zero bit
// 0x08 - Sign bit
// 0x40 - Logical Zero bit
bool CheckCondition(u8 _Condition)
{
bool taken = false;
switch (_Condition & 0xf)
{
case 0x0: //NS - NOT SIGN
if ((!(g_dsp.r[DSP_REG_SR] & 0x02)) && (!(g_dsp.r[DSP_REG_SR] & 0x08)))
taken = true;
break;
case 0x1: // S - SIGN
if ((!(g_dsp.r[DSP_REG_SR] & 0x02)) && (g_dsp.r[DSP_REG_SR] & 0x08))
taken = true;
break;
case 0x2: // G - GREATER
if ((!(g_dsp.r[DSP_REG_SR] & 0x02)) && (!(g_dsp.r[DSP_REG_SR] & 0x08)) && !((g_dsp.r[DSP_REG_SR] & 0x04))) // gets zelda stuck
taken = true;
break;
case 0x3: // LE - LESS EQUAL
if ((!(g_dsp.r[DSP_REG_SR] & 0x02)) && ((g_dsp.r[DSP_REG_SR] & 0x08) || (g_dsp.r[DSP_REG_SR] & 0x04)))
taken = true;
break;
case 0x4: // NZ - NOT ZERO
if (!(g_dsp.r[DSP_REG_SR] & 0x04))
taken = true;
break;
case 0x5: // Z - ZERO
if (g_dsp.r[DSP_REG_SR] & 0x04)
taken = true;
break;
case 0x6: // L - LESS
if (!(g_dsp.r[DSP_REG_SR] & 0x02) && (g_dsp.r[DSP_REG_SR] & 0x08))
taken = true;
break;
case 0x7: // GE - GREATER EQUAL
if ((!(g_dsp.r[DSP_REG_SR] & 0x02)) && (!(g_dsp.r[DSP_REG_SR] & 0x08) || (g_dsp.r[DSP_REG_SR] & 0x04)))
taken = true;
break;
case 0xc: // LNZ - LOGIC NOT ZERO
if (!(g_dsp.r[DSP_REG_SR] & 0x40))
taken = true;
break;
case 0xd: // LZ - LOGIC ZERO
if (g_dsp.r[DSP_REG_SR] & 0x40)
taken = true;
break;
case 0xf: // Empty
taken = true;
break;
default:
ERROR_LOG(DSPLLE, "Unknown condition check: 0x%04x\n", _Condition & 0xf);
break;
}
return taken;
}
} // namespace

View File

@ -0,0 +1,52 @@
// 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 "Globals.h"
#include "gdsp_registers.h"
namespace DSPInterpreter {
// SR flag defines.
#define SR_CMP_MASK 0x3f // Shouldn't this include 0x40?
// These are probably not accurate. Do not use yet.
#define SR_UNKNOWN 0x0002 // ????????
#define SR_ARITH_ZERO 0x0004
#define SR_SIGN 0x0008
#define SR_TOP2BITS 0x0020 // this is an odd one.
#define SR_LOGIC_ZERO 0x0040 // ?? duddie's doc sometimes say & 1<<6 (0x40), sometimes 1<<14 (0x4000), while we have 0x20 .. eh
#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so.
#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2
bool CheckCondition(u8 _Condition);
int GetMultiplyModifier();
void Update_SR_Register16(s16 _Value);
void Update_SR_Register64(s64 _Value);
} // namespace
#endif // _GDSP_CONDITION_CODES_H

View File

@ -0,0 +1,284 @@
/*====================================================================
filename: opcodes.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.
====================================================================*/
//
//
// At the moment just ls and sl are using the prolog
// perhaps all actions on r03 must be in the prolog
//
#include "Globals.h"
#include "gdsp_opcodes_helper.h"
//
void dsp_op_ext_r_epi(const UDSPInstruction& opc)
{
u8 op = (opc.hex >> 2) & 0x3;
u8 reg = opc.hex & 0x3;
switch (op)
{
case 0x00:
ERROR_LOG(DSPLLE, "dsp_op_ext_r_epi");
break;
case 0x01:
g_dsp.r[reg]--;
break;
case 0x02:
g_dsp.r[reg]++;
break;
case 0x03:
g_dsp.r[reg] += g_dsp.r[reg + 4];
break;
}
}
void dsp_op_ext_mv(const UDSPInstruction& opc)
{
u8 sreg = opc.hex & 0x3;
u8 dreg = ((opc.hex >> 2) & 0x3);
g_dsp.r[dreg + 0x18] = g_dsp.r[sreg + 0x1c];
}
void dsp_op_ext_s(const UDSPInstruction& opc)
{
u8 dreg = opc.hex & 0x3;
u8 sreg = ((opc.hex >> 3) & 0x3) + 0x1c;
dsp_dmem_write(g_dsp.r[dreg], g_dsp.r[sreg]);
if (opc.hex & 0x04)
{
g_dsp.r[dreg] += g_dsp.r[dreg + 4];
}
else
{
g_dsp.r[dreg]++;
}
}
void dsp_op_ext_l(const UDSPInstruction& opc)
{
u8 sreg = opc.hex & 0x3;
u8 dreg = ((opc.hex >> 3) & 0x7) + 0x18;
u16 val = dsp_dmem_read(g_dsp.r[sreg]);
g_dsp.r[dreg] = val;
if (opc.hex & 0x04)
{
g_dsp.r[sreg] += g_dsp.r[sreg + 4];
}
else
{
g_dsp.r[sreg]++;
}
}
void dsp_op_ext_ls_pro(const UDSPInstruction& opc)
{
u8 areg = (opc.hex & 0x1) + 0x1e;
dsp_dmem_write(g_dsp.r[0x03], g_dsp.r[areg]);
if (opc.hex & 0x8)
{
g_dsp.r[0x03] += g_dsp.r[0x07];
}
else
{
g_dsp.r[0x03]++;
}
}
void dsp_op_ext_ls_epi(const UDSPInstruction& opc)
{
u8 dreg = ((opc.hex >> 4) & 0x3) + 0x18;
u16 val = dsp_dmem_read(g_dsp.r[0x00]);
dsp_op_write_reg(dreg, val);
if (opc.hex & 0x4)
{
g_dsp.r[0x00] += g_dsp.r[0x04];
}
else
{
g_dsp.r[0x00]++;
}
}
void dsp_op_ext_sl_pro(const UDSPInstruction& opc)
{
u8 areg = (opc.hex & 0x1) + 0x1e;
dsp_dmem_write(g_dsp.r[0x00], g_dsp.r[areg]);
if (opc.hex & 0x4)
{
g_dsp.r[0x00] += g_dsp.r[0x04];
}
else
{
g_dsp.r[0x00]++;
}
}
void dsp_op_ext_sl_epi(const UDSPInstruction& opc)
{
u8 dreg = ((opc.hex >> 4) & 0x3) + 0x18;
u16 val = dsp_dmem_read(g_dsp.r[0x03]);
dsp_op_write_reg(dreg, val);
if (opc.hex & 0x8)
{
g_dsp.r[0x03] += g_dsp.r[0x07];
}
else
{
g_dsp.r[0x03]++;
}
}
void dsp_op_ext_ld(const UDSPInstruction& opc)
{
u8 dreg1 = (((opc.hex >> 5) & 0x1) << 1) + 0x18;
u8 dreg2 = (((opc.hex >> 4) & 0x1) << 1) + 0x19;
u8 sreg = opc.hex & 0x3;
g_dsp.r[dreg1] = dsp_dmem_read(g_dsp.r[sreg]);
g_dsp.r[dreg2] = dsp_dmem_read(g_dsp.r[0x03]);
if (opc.hex & 0x04)
{
g_dsp.r[sreg] += g_dsp.r[sreg + 0x04];
}
else
{
g_dsp.r[sreg]++;
}
if (opc.hex & 0x08)
{
g_dsp.r[0x03] += g_dsp.r[0x07];
}
else
{
g_dsp.r[0x03]++;
}
}
// ================================================================================
//
//
//
// ================================================================================
void dsp_op_ext_ops_pro(const UDSPInstruction& opc)
{
if ((opc.hex & 0xFF) == 0){return;}
switch ((opc.hex >> 4) & 0xf)
{
case 0x00:
dsp_op_ext_r_epi(opc.hex);
break;
case 0x01:
dsp_op_ext_mv(opc.hex);
break;
case 0x02:
case 0x03:
dsp_op_ext_s(opc.hex);
break;
case 0x04:
case 0x05:
case 0x06:
case 0x07:
dsp_op_ext_l(opc.hex);
break;
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
if (opc.hex & 0x2)
{
dsp_op_ext_sl_pro(opc.hex);
}
else
{
dsp_op_ext_ls_pro(opc.hex);
}
return;
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
dsp_op_ext_ld(opc.hex);
break;
}
}
void dsp_op_ext_ops_epi(const UDSPInstruction& opc)
{
if ((opc.hex & 0xFF) == 0){return;}
switch ((opc.hex >> 4) & 0xf)
{
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
if (opc.hex & 0x2)
{
dsp_op_ext_sl_epi(opc.hex);
}
else
{
dsp_op_ext_ls_epi(opc.hex);
}
return;
}
}

View File

@ -0,0 +1,41 @@
/*====================================================================
filename: opcodes.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 _GDSP_EXT_OP_H
#define _GDSP_EXT_OP_H
#include "DSPTables.h"
// Extended opcode support.
// Many opcode have the lower 0xFF free - there, an opcode extension
// can be stored. The ones that must be executed before the operation
// is handled as a prologue, the ones that must be executed afterwards
// is handled as an epilogue.
void dsp_op_ext_ops_pro(const UDSPInstruction& opc); // run any prologs
void dsp_op_ext_ops_epi(const UDSPInstruction& opc); // run any epilogs
#endif

View File

@ -0,0 +1,328 @@
/*====================================================================
filename: gdsp_interface.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.
====================================================================*/
#include <stdlib.h>
#include "Globals.h"
#include "Thread.h"
#include "MemoryUtil.h"
#include "DSPAnalyzer.h"
#include "gdsp_aram.h"
#include "gdsp_interpreter.h"
#include "gdsp_interface.h"
#include "Tools.h"
void gdsp_dma();
#if WITH_DSP_ON_THREAD
Common::CriticalSection g_CriticalSection;
#endif
static volatile u16 gdsp_mbox[2][2];
u16 gdsp_ifx_regs[256];
void gdsp_ifx_init()
{
for (int i = 0; i < 256; i++)
{
gdsp_ifx_regs[i] = 0;
}
gdsp_mbox[0][0] = 0;
gdsp_mbox[0][1] = 0;
gdsp_mbox[1][0] = 0;
gdsp_mbox[1][1] = 0;
}
u32 gdsp_mbox_peek(u8 mbx)
{
#if WITH_DSP_ON_THREAD
g_CriticalSection.Enter();
#endif
u32 value = ((gdsp_mbox[mbx][0] << 16) | gdsp_mbox[mbx][1]);
#if WITH_DSP_ON_THREAD
g_CriticalSection.Leave();
#endif
return value;
}
void gdsp_mbox_write_h(u8 mbx, u16 val)
{
#if WITH_DSP_ON_THREAD
g_CriticalSection.Enter();
#endif
gdsp_mbox[mbx][0] = val & 0x7fff;
#if WITH_DSP_ON_THREAD
g_CriticalSection.Leave();
#endif
}
void gdsp_mbox_write_l(u8 mbx, u16 val)
{
#if WITH_DSP_ON_THREAD
g_CriticalSection.Enter();
#endif
gdsp_mbox[mbx][1] = val;
gdsp_mbox[mbx][0] |= 0x8000;
#if WITH_DSP_ON_THREAD
g_CriticalSection.Leave();
#endif
if (mbx == GDSP_MBOX_DSP)
{
DEBUG_LOG(DSPLLE, " - DSP writes mail to mbx %i: 0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(GDSP_MBOX_DSP), g_dsp.err_pc);
}
}
u16 gdsp_mbox_read_h(u8 mbx)
{
return (gdsp_mbox[mbx][0]); // TODO: mask away the top bit?
}
u16 gdsp_mbox_read_l(u8 mbx)
{
u16 val;
#if WITH_DSP_ON_THREAD
g_CriticalSection.Enter();
#endif
val = gdsp_mbox[mbx][1];
gdsp_mbox[mbx][0] &= ~0x8000;
DEBUG_LOG(DSPLLE, "- DSP reads mail from mbx %i: %08x (pc=0x%04x)", mbx, gdsp_mbox_peek(mbx), g_dsp.err_pc);
#if WITH_DSP_ON_THREAD
g_CriticalSection.Leave();
#endif
return val;
}
void gdsp_ifx_write(u16 addr, u16 val)
{
addr &= 0xff;
switch (addr & 0xff)
{
case 0xfb: // DIRQ
if (val & 0x1)
g_dsp.irq_request();
break;
case 0xfc: // DMBH
gdsp_mbox_write_h(GDSP_MBOX_DSP, val);
break;
case 0xfd: // DMBL
gdsp_mbox_write_l(GDSP_MBOX_DSP, val);
break;
case 0xcb: // DSBL
gdsp_ifx_regs[addr] = val;
gdsp_dma();
gdsp_ifx_regs[DSP_DSCR] &= ~0x0004;
break;
case 0xcd:
case 0xce:
case 0xcf:
case 0xc9:
gdsp_ifx_regs[addr] = val;
break;
default:
/* if ((addr & 0xff) >= 0xa0 && reg_names[addr - 0xa0])
DEBUG_LOG(DSPLLE, "%04x MW %s (%04x)\n", g_dsp.pc, reg_names[addr - 0xa0], val);
else
DEBUG_LOG(DSPLLE, "%04x MW %04x (%04x)\n", g_dsp.pc, addr, val);*/
gdsp_ifx_regs[addr] = val;
break;
}
}
u16 gdsp_ifx_read(u16 addr)
{
u16 val;
addr &= 0xff;
switch (addr & 0xff)
{
case 0xfc: // DMBH
val = gdsp_mbox_read_h(GDSP_MBOX_DSP);
break;
case 0xfe: // CMBH
val = gdsp_mbox_read_h(GDSP_MBOX_CPU);
break;
case 0xff: // CMBL
val = gdsp_mbox_read_l(GDSP_MBOX_CPU);
break;
case 0xc9:
val = gdsp_ifx_regs[addr];
break;
case 0xdd:
val = dsp_read_aram();
break;
default:
val = gdsp_ifx_regs[addr];
/* if ((addr & 0xff) >= 0xc0 && reg_names[addr & 0x3f])
printf("%04x MR %s (%04x)\n", g_dsp.pc, reg_names[addr & 0x3f], val);
else
printf("%04x MR %04x (%04x)\n", g_dsp.pc, addr, val);*/
break;
}
return(val);
}
void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size)
{
UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
u8* dst = ((u8*)g_dsp.iram);
for (u32 i = 0; i < size; i += 2)
{
// TODO : this may be different on Wii.
*(u16*)&dst[dsp_addr + i] = *(u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff];
}
WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
g_dsp.iram_crc = GenerateCRC(g_dsp.cpu_ram + (addr & 0x0fffffff), size);
INFO_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)\n", addr, dsp_addr, g_dsp.iram_crc);
DSPAnalyzer::Analyze();
if (g_dsp.dump_imem)
DumpDSPCode(&dst[dsp_addr], size, g_dsp.iram_crc);
}
void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size)
{
ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)\n", dsp_addr / 2, addr, size);
}
void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size)
{
if ((addr & 0x7FFFFFFF) > 0x01FFFFFF)
{
ERROR_LOG(DSPLLE, "*** ddma_in read from invalid addr (0x%08x)\n", addr);
return;
}
u8* dst = ((u8*)g_dsp.dram);
for (u32 i = 0; i < size; i += 2)
{
*(u16*)&dst[dsp_addr + i] = *(u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF];
}
INFO_LOG(DSPLLE, "*** ddma_in RAM (0x%08x) -> DRAM_DSP (0x%04x) : size (0x%08x)\n", addr, dsp_addr / 2, size);
}
void gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size)
{
if ((addr & 0x7FFFFFFF) > 0x01FFFFFF)
{
ERROR_LOG(DSPLLE, "*** gdsp_ddma_out to invalid addr (0x%08x)\n", addr);
return;
}
u8* src = ((u8*)g_dsp.dram);
for (u32 i = 0; i < size; i += 2)
{
*(u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF] = *(u16*)&src[dsp_addr + i];
}
INFO_LOG(DSPLLE, "*** ddma_out DRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)\n", dsp_addr / 2, addr, size);
}
#define DSP_CR_IMEM (2)
#define DSP_CR_DMEM (0)
#define DSP_CR_TO_CPU (1)
#define DSP_CR_FROM_CPU (0)
void gdsp_dma()
{
u16 ctl;
u32 addr;
u16 dsp_addr;
u16 len;
addr = (gdsp_ifx_regs[DSP_DSMAH] << 16) | gdsp_ifx_regs[DSP_DSMAL];
ctl = gdsp_ifx_regs[DSP_DSCR];
dsp_addr = gdsp_ifx_regs[DSP_DSPA] * 2;
len = gdsp_ifx_regs[DSP_DSBL];
if ((ctl > 3) || (len > 0x4000))
{
ERROR_LOG(DSPLLE, "DMA ERROR pc: %04x ctl: %04x addr: %08x da: %04x size: %04x\n", g_dsp.pc, ctl, addr, dsp_addr, len);
exit(0);
}
switch (ctl & 0x3)
{
case (DSP_CR_DMEM | DSP_CR_TO_CPU):
gdsp_ddma_out(dsp_addr, addr, len);
break;
case (DSP_CR_DMEM | DSP_CR_FROM_CPU):
gdsp_ddma_in(dsp_addr, addr, len);
break;
case (DSP_CR_IMEM | DSP_CR_TO_CPU):
gdsp_idma_out(dsp_addr, addr, len);
break;
case (DSP_CR_IMEM | DSP_CR_FROM_CPU):
gdsp_idma_in(dsp_addr, addr, len);
break;
}
}

View File

@ -0,0 +1,70 @@
/*====================================================================
filename: gdsp_interface.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 _GDSP_INTERFACE_H
#define _GDSP_INTERFACE_H
#include "Globals.h"
#define GDSP_MBOX_CPU 0
#define GDSP_MBOX_DSP 1
#define DSP_DSMAH 0xce
#define DSP_DSMAL 0xcf
#define DSP_DSCR 0xc9
#define DSP_DSPA 0xcd
#define DSP_DSBL 0xcb
#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_COEF_A1_0 0xa0
#define DSP_FORMAT 0xd1
#define DSP_PRED_SCALE 0xda
#define DSP_YN1 0xdb
#define DSP_YN2 0xdc
#define DSP_ARAM 0xdd
#define DSP_GAIN 0xde
extern u16 gdsp_ifx_regs[256];
u32 gdsp_mbox_peek(u8 mbx);
void gdsp_mbox_write_h(u8 mbx, u16 val);
void gdsp_mbox_write_l(u8 mbx, u16 val);
u16 gdsp_mbox_read_h(u8 mbx);
u16 gdsp_mbox_read_l(u8 mbx);
void gdsp_ifx_init();
void gdsp_ifx_write(u16 addr, u16 val);
u16 gdsp_ifx_read(u16 addr);
void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size);
#endif

View File

@ -0,0 +1,320 @@
/*====================================================================
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 <stdio.h>
#include <stdlib.h>
#include "DSPTables.h"
#include "DSPAnalyzer.h"
#include "gdsp_interface.h"
#include "gdsp_opcodes_helper.h"
#include "Tools.h"
#include "MemoryUtil.h"
//-------------------------------------------------------------------------------
SDSP g_dsp;
bool gdsp_running;
extern volatile u32 dsp_running;
static bool cr_halt = true;
static bool cr_external_int = false;
void UpdateCachedCR()
{
cr_halt = (g_dsp.cr & 0x4) != 0;
cr_external_int = (g_dsp.cr & 0x02) != 0;
}
//-------------------------------------------------------------------------------
void gdsp_init()
{
// Dump IMEM when ucodes get uploaded. Why not... still a plugin heavily in dev.
g_dsp.dump_imem = true;
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);
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] = 0x0021;
}
// copied from a real console after the custom UCode has been loaded
g_dsp.r[0x08] = 0xffff;
g_dsp.r[0x09] = 0xffff;
g_dsp.r[0x0a] = 0xffff;
g_dsp.r[0x0b] = 0xffff;
g_dsp.cr = 0x804;
gdsp_ifx_init();
UpdateCachedCR();
// 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();
}
void gdsp_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 gdsp_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;
}
void gdsp_generate_exception(u8 level)
{
g_dsp.exceptions |= 1 << level;
}
bool gdsp_load_irom(const char *fname)
{
FILE *pFile = fopen(fname, "rb");
if (pFile)
{
size_t size_in_bytes = DSP_IROM_SIZE * sizeof(u16);
size_t read_bytes = fread(g_dsp.irom, 1, size_in_bytes, pFile);
if (read_bytes != size_in_bytes)
{
PanicAlert("IROM too short : %i/%i", (int)read_bytes, (int)size_in_bytes);
fclose(pFile);
return false;
}
fclose(pFile);
return true;
}
// Always keep IROM write protected.
WriteProtectMemory(g_dsp.irom, DSP_IROM_BYTE_SIZE, false);
return false;
}
bool gdsp_load_coef(const char *fname)
{
FILE *pFile = fopen(fname, "rb");
if (pFile)
{
size_t size_in_bytes = DSP_COEF_SIZE * sizeof(u16);
size_t read_bytes = fread(g_dsp.coef, 1, size_in_bytes, pFile);
if (read_bytes != size_in_bytes)
{
PanicAlert("COEF too short : %i/%i", (int)read_bytes, (int)size_in_bytes);
fclose(pFile);
return false;
}
fclose(pFile);
return true;
}
// Always keep COEF write protected. We unprotect only when DMA-ing
WriteProtectMemory(g_dsp.coef, DSP_COEF_BYTE_SIZE, false);
return false;
}
// Hm, should instructions that change CR use this? Probably not (but they
// should call UpdateCachedCR())
void gdsp_write_cr(u16 val)
{
// reset
if (val & 0x0001)
{
gdsp_reset();
}
val &= ~0x0001;
// update cr
g_dsp.cr = val;
UpdateCachedCR();
}
// Hm, should instructions that read CR use this? (Probably not).
u16 gdsp_read_cr()
{
if (g_dsp.pc & 0x8000)
{
g_dsp.cr |= 0x800;
}
else
{
g_dsp.cr &= ~0x800;
}
UpdateCachedCR();
return g_dsp.cr;
}
void gdsp_step()
{
g_dsp.step_counter++;
g_dsp.err_pc = g_dsp.pc;
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
if (g_dsp.step_counter == 1)
{
ProfilerInit();
}
if ((g_dsp.step_counter & 0xFFFFF) == 0)
{
ProfilerDump(g_dsp.step_counter);
}
#endif
u16 opc = dsp_fetch_code();
ComputeInstruction(UDSPInstruction(opc));
u16& rLoopCounter = g_dsp.r[DSP_REG_ST0 + 3];
if (rLoopCounter > 0)
{
const u16& rCallAddress = g_dsp.r[DSP_REG_ST0 + 0];
const u16& rLoopAddress = g_dsp.r[DSP_REG_ST0 + 2];
if (g_dsp.pc == (rLoopAddress + 1))
{
rLoopCounter--;
if (rLoopCounter > 0)
{
g_dsp.pc = rCallAddress;
}
else
{
// end of loop
dsp_reg_load_stack(0);
dsp_reg_load_stack(2);
dsp_reg_load_stack(3);
}
}
}
// check if there is an external interrupt
if (cr_external_int)
{
if (dsp_SR_is_flag_set(FLAG_ENABLE_INTERUPT) && (g_dsp.exception_in_progress_hack == false))
{
// level 7 is the interrupt exception
gdsp_generate_exception(7);
g_dsp.cr &= ~0x0002;
UpdateCachedCR();
}
}
// check exceptions
if ((g_dsp.exceptions != 0) && (!g_dsp.exception_in_progress_hack))
{
for (int i = 0; i < 8; i++)
{
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);
g_dsp.exception_in_progress_hack = true;
break;
}
}
}
}
bool gdsp_run()
{
gdsp_running = true;
while (!cr_halt)
{
// Are we running?
if(*g_dspInitialize.pEmulatorState)
break;
gdsp_step();
if (!gdsp_running)
break;
}
gdsp_running = false;
return true;
}
void gdsp_stop()
{
gdsp_running = false;
}

View File

@ -0,0 +1,123 @@
// 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/
/*====================================================================
filename: gdsp_interpreter.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 _GDSP_INTERPRETER_H
#define _GDSP_INTERPRETER_H
#include "Globals.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
struct SDSP
{
u16 r[32];
u16 pc;
u16 err_pc;
u16* iram;
u16* dram;
u16* irom;
u16* coef;
u8* cpu_ram;
u16 cr;
u8 reg_stack_ptr[4];
u8 exceptions; // pending exceptiosn?
// lets make stack depth to 32 for now
u16 reg_stack[4][DSP_STACK_DEPTH];
void (* irq_request)(void);
// for debugger only
bool dump_imem;
u32 iram_crc;
u64 step_counter;
bool exception_in_progress_hack;
};
extern SDSP g_dsp;
void gdsp_init();
void gdsp_reset();
void gdsp_shutdown();
bool gdsp_load_irom(const char *fname);
bool gdsp_load_coef(const char *fname);
// steps through DSP code, returns false if error occured
void gdsp_step(void);
void gdsp_loop_step();
bool gdsp_run(void);
bool gdsp_runx(u16 cnt);
void gdsp_stop(void);
void gdsp_write_cr(u16 val);
u16 gdsp_read_cr(void);
u16* gdsp_get_iram(void);
u16* gdsp_get_irom(void);
u16* gdsp_get_dram(void);
u16* gdsp_get_drom(void);
// sets a flag in the pending exception register.
void gdsp_generate_exception(u8 level);
#endif

View File

@ -0,0 +1,110 @@
/*====================================================================
filename: gdsp_memory.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 <stdio.h>
#include "Globals.h"
#include "gdsp_interpreter.h"
#include "gdsp_memory.h"
#include "gdsp_interface.h"
u16 dsp_swap16(u16 x)
{
return (x >> 8) | (x << 8);
}
u16 dsp_imem_read(u16 addr)
{
switch (addr >> 12)
{
case 0:
return dsp_swap16(g_dsp.iram[addr & DSP_IRAM_MASK]);
case 8:
return dsp_swap16(g_dsp.irom[addr & DSP_IROM_MASK]);
default:
ERROR_LOG(DSPLLE, "%04x DSP ERROR: Executing from invalid (%04x) memory", g_dsp.pc, addr);
return 0;
}
}
u16 dsp_dmem_read(u16 addr)
{
switch (addr >> 12)
{
case 0x0: // 0xxx DRAM
return dsp_swap16(g_dsp.dram[addr & DSP_DRAM_MASK]);
case 0x1: // 1xxx COEF
return dsp_swap16(g_dsp.coef[addr & DSP_COEF_MASK]);
// FIXME: unknown addresses used by zelda
/* case 0x2:
case 0x3:
case 0x4:
break;*/
case 0xf: // Fxxx HW regs
return gdsp_ifx_read(addr);
default: // error
ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, addr);
return 0;
}
}
void dsp_dmem_write(u16 addr, u16 val)
{
switch (addr >> 12)
{
case 0x0: // 0xxx DRAM
g_dsp.dram[addr & DSP_DRAM_MASK] = dsp_swap16(val);
break;
case 0x1: // 1xxx COEF
ERROR_LOG(DSPLLE, "someone writes to COEF");
break;
case 0xf: // Fxxx HW regs
gdsp_ifx_write(addr, val);
break;
default: // error
ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", g_dsp.pc, addr);
break;
}
}
u16 dsp_fetch_code()
{
u16 opc = dsp_imem_read(g_dsp.pc);
g_dsp.pc++;
return opc;
}
u16 dsp_peek_code()
{
return dsp_imem_read(g_dsp.pc);
}

View File

@ -0,0 +1,36 @@
/*====================================================================
filename: gdsp_memory.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 _GDSP_MEMORY_H
#define _GDSP_MEMORY_H
#include "Globals.h"
u16 dsp_fetch_code();
u16 dsp_peek_code();
u16 dsp_imem_read(u16 addr);
void dsp_dmem_write(u16 addr, u16 val);
u16 dsp_dmem_read(u16 addr);
#endif

View File

@ -0,0 +1,226 @@
/*====================================================================
filename: opcodes.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 _GDSP_OPCODES_HELPER_H
#define _GDSP_OPCODES_HELPER_H
#include "Globals.h"
#include "DSPInterpreter.h"
#include "gdsp_memory.h"
#include "gdsp_interpreter.h"
#include "gdsp_registers.h"
#include "gdsp_ext_op.h"
// ---------------------------------------------------------------------------------------
//
// --- SR
//
// ---------------------------------------------------------------------------------------
inline void dsp_SR_set_flag(int flag)
{
g_dsp.r[DSP_REG_SR] |= (1 << flag);
}
inline bool dsp_SR_is_flag_set(int flag)
{
return (g_dsp.r[DSP_REG_SR] & (1 << flag)) != 0;
}
// ---------------------------------------------------------------------------------------
//
// --- reg
//
// ---------------------------------------------------------------------------------------
inline u16 dsp_op_read_reg(u8 reg)
{
u16 val;
switch (reg & 0x1f)
{
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
val = dsp_reg_load_stack(reg - 0x0c);
break;
default:
val = g_dsp.r[reg];
break;
}
return val;
}
inline void dsp_op_write_reg(u8 reg, u16 val)
{
switch (reg & 0x1f)
{
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
dsp_reg_store_stack(reg - 0x0c, val);
break;
default:
g_dsp.r[reg] = val;
break;
}
}
// ---------------------------------------------------------------------------------------
//
// --- prod
//
// ---------------------------------------------------------------------------------------
inline s64 dsp_get_long_prod()
{
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
#endif
s64 val;
s64 low_prod;
val = (s8)g_dsp.r[0x16];
val <<= 32;
low_prod = g_dsp.r[0x15];
low_prod += g_dsp.r[0x17];
low_prod <<= 16;
low_prod |= g_dsp.r[0x14];
val += low_prod;
return val;
}
inline void dsp_set_long_prod(s64 val)
{
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
#endif
g_dsp.r[0x14] = (u16)val;
val >>= 16;
g_dsp.r[0x15] = (u16)val;
val >>= 16;
g_dsp.r[0x16] = (u16)val;
g_dsp.r[0x17] = 0;
}
// ---------------------------------------------------------------------------------------
// --- acc
// ---------------------------------------------------------------------------------------
inline s64 dsp_get_long_acc(int reg)
{
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
#endif
_assert_(reg < 2);
s64 high = (s64)(s8)g_dsp.r[0x10 + reg] << 32;
u32 mid_low = ((u32)g_dsp.r[0x1e + reg] << 16) | g_dsp.r[0x1c + reg];
return high | mid_low;
}
inline void dsp_set_long_acc(int _reg, s64 val)
{
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
#endif
_assert_(_reg < 2);
g_dsp.r[0x1c + _reg] = (u16)val;
val >>= 16;
g_dsp.r[0x1e + _reg] = (u16)val;
val >>= 16;
g_dsp.r[0x10 + _reg] = (u16)val;
}
inline s16 dsp_get_acc_l(int _reg)
{
_assert_(_reg < 2);
return g_dsp.r[0x1c + _reg];
}
inline s16 dsp_get_acc_m(int _reg)
{
_assert_(_reg < 2);
return g_dsp.r[0x1e + _reg];
}
inline s16 dsp_get_acc_h(int _reg)
{
_assert_(_reg < 2);
return g_dsp.r[0x10 + _reg];
}
// ---------------------------------------------------------------------------------------
//
// --- acx
//
// ---------------------------------------------------------------------------------------
inline s64 dsp_get_long_acx(int _reg)
{
#if PROFILE
ProfilerAddDelta(g_dsp.err_pc, 1);
#endif
_assert_(_reg < 2);
s64 val = (s16)g_dsp.r[0x1a + _reg];
val <<= 16;
s64 low_acc = g_dsp.r[0x18 + _reg];
val |= low_acc;
return val;
}
inline s16 dsp_get_ax_l(int _reg)
{
_assert_(_reg < 2);
return g_dsp.r[0x18 + _reg];
}
inline s16 dsp_get_ax_h(int _reg)
{
_assert_(_reg < 2);
return g_dsp.r[0x1a + _reg];
}
#endif

View File

@ -0,0 +1,57 @@
/*====================================================================
filename: gdsp_registers.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 "Globals.h"
#include "gdsp_registers.h"
#include "gdsp_interpreter.h"
// Stacks. The stacks are outside the DSP RAM, in dedicated hardware.
void dsp_reg_stack_push(u8 stack_reg)
{
g_dsp.reg_stack_ptr[stack_reg]++;
g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK;
g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg];
}
void dsp_reg_stack_pop(u8 stack_reg)
{
g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]];
g_dsp.reg_stack_ptr[stack_reg]--;
g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK;
}
void dsp_reg_store_stack(u8 stack_reg, u16 val)
{
dsp_reg_stack_push(stack_reg);
g_dsp.r[DSP_REG_ST0 + stack_reg] = val;
}
u16 dsp_reg_load_stack(u8 stack_reg)
{
u16 val = g_dsp.r[DSP_REG_ST0 + stack_reg];
dsp_reg_stack_pop(stack_reg);
return val;
}

View File

@ -0,0 +1,100 @@
/*====================================================================
filename: gdsp_registers.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 _GDSP_REGISTERS_H
#define _GDSP_REGISTERS_H
#include "Globals.h"
// 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 // used as jump function selector
#define DSP_REG_IX0 0x04 // LEFT_VOLUME accel
#define DSP_REG_IX1 0x05 // RIGHT_VOLUME accel
#define DSP_REG_IX2 0x06 // ADDRH_SMP accel
#define DSP_REG_IX3 0x07 // ADDRL_SMP accel
#define DSP_REG_R08 0x08 // fixed to 48000 value
#define DSP_REG_R09 0x09 // problems using this
#define DSP_REG_R0A 0x0a // ADDREH_SMP accel
#define DSP_REG_R0B 0x0b // ADDREL_SMP accel
#define DSP_REG_ST0 0x0c
#define DSP_REG_ST1 0x0d
#define DSP_REG_ST2 0x0e
#define DSP_REG_ST3 0x0f
#define DSP_REG_CONFIG 0x12
#define DSP_REG_SR 0x13
#define DSP_REG_PRODL 0x14
#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 // SMP_R accel
#define DSP_REG_AXH1 0x1b // SMP_L accel
#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_REG_DSCR 0xffc9 // DSP DMA Control Reg
#define DSP_REG_DSBL 0xffcb // DSP DMA Block Length
#define DSP_REG_DSPA 0xffcd // DSP DMA DMEM Address
#define DSP_REG_DSMAH 0xffce // DSP DMA Mem Address H
#define DSP_REG_DSMAL 0xffcf // DSP DMA Mem Address L
#define DSP_REG_DIRQ 0xfffb // DSP Irq Rest
#define DSP_REG_DMBH 0xfffc // DSP Mailbox H
#define DSP_REG_DMBL 0xfffd // DSP Mailbox L
#define DSP_REG_CMBH 0xfffe // CPU Mailbox H
#define DSP_REG_CMBL 0xffff // CPU Mailbox L
#define DMA_TO_DSP 0
#define DMA_TO_CPU 1
// Stacks
#define DSP_STACK_C 0
#define DSP_STACK_D 1
void dsp_reg_store_stack(u8 stack_reg, u16 val);
u16 dsp_reg_load_stack(u8 stack_reg);
#endif

View File

@ -0,0 +1,365 @@
// 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 "Common.h" // Common
#include "CommonTypes.h"
#include "Mixer.h"
#include "Globals.h" // Local
#include "gdsp_interpreter.h"
#include "gdsp_interface.h"
#include "disassemble.h"
#include "Config.h"
#include "AudioCommon.h"
#include "Logging/Logging.h" // For Logging
#include "Thread.h"
#include "ChunkFile.h"
#include "DSPTables.h"
#if defined(HAVE_WX) && HAVE_WX
#include "DSPConfigDlgLLE.h"
#include "Debugger/Debugger.h" // For the DSPDebuggerLLE class
DSPDebuggerLLE* m_DebuggerFrame = NULL;
#endif
PLUGIN_GLOBALS* globals = NULL;
DSPInitialize g_dspInitialize;
Common::Thread *g_hDSPThread = NULL;
SoundStream *soundStream = NULL;
#define GDSP_MBOX_CPU 0
#define GDSP_MBOX_DSP 1
extern u32 m_addressPBs;
bool AXTask(u32& _uMail);
bool bCanWork = false;
bool bIsRunning = false;
//////////////////////////////////////////////////////////////////////////
// UGLY wxw stuff, TODO fix up
// wxWidgets: Create the wxApp
#if defined(HAVE_WX) && HAVE_WX
class wxDLLApp : public wxApp
{
bool OnInit()
{
return true;
}
};
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
// DllMain
#ifdef _WIN32
HINSTANCE g_hInstance = NULL;
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD dwReason, // reason called
LPVOID lpvReserved) // reserved
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
// more stuff wx needs
wxSetInstance((HINSTANCE)hinstDLL);
int argc = 0;
char **argv = NULL;
wxEntryStart(argc, argv);
// This is for ?
if ( !wxTheApp || !wxTheApp->CallOnInit() )
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
wxEntryCleanup(); // use this or get a crash
break;
default:
break;
}
g_hInstance = hinstDLL;
return(TRUE);
}
#endif
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_DSP;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE-Testing Plugin (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE-Testing Plugin");
#else
sprintf(_PluginInfo->Name, "Dolphin DSP-LLE-Testing Plugin (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
}
void DllAbout(HWND _hParent)
{
}
void DllConfig(HWND _hParent)
{
#if defined(HAVE_WX) && HAVE_WX
// (shuffle2) TODO: reparent dlg with DolphinApp
DSPConfigDialogLLE dlg(NULL);
// add backends
std::vector<std::string> backends = AudioCommon::GetSoundBackends();
for (std::vector<std::string>::const_iterator iter = backends.begin();
iter != backends.end(); ++iter) {
dlg.AddBackend((*iter).c_str());
}
// Show the window
dlg.ShowModal();
#endif
}
void DoState(unsigned char **ptr, int mode)
{
PointerWrap p(ptr, mode);
}
void DllDebugger(HWND _hParent, bool Show)
{
#if defined(HAVE_WX) && HAVE_WX
DSPDebuggerLLE *debugger = new DSPDebuggerLLE(NULL);
debugger->Show();
#endif
}
// Regular thread
THREAD_RETURN dsp_thread(void* lpParameter)
{
while (bIsRunning)
{
if (!gdsp_run())
{
ERROR_LOG(AUDIO, "DSP Halt");
return 0;
}
}
return 0;
}
void DSP_DebugBreak()
{
#if defined(HAVE_WX) && HAVE_WX
m_DebuggerFrame->DebugBreak();
#endif
}
void dspi_req_dsp_irq()
{
// Fire an interrupt on the PPC ASAP.
g_dspInitialize.pGenerateDSPInterrupt();
}
void Initialize(void *init)
{
bCanWork = true;
g_dspInitialize = *(DSPInitialize*)init;
g_Config.Load();
gdsp_init();
g_dsp.step_counter = 0;
g_dsp.cpu_ram = g_dspInitialize.pGetMemoryPointer(0);
g_dsp.irq_request = dspi_req_dsp_irq;
// g_dsp.exception_in_progress_hack = false;
gdsp_reset();
if (!gdsp_load_irom(DSP_IROM_FILE))
{
bCanWork = false;
PanicAlert("Failed loading DSP ROM from " DSP_IROM_FILE);
}
if (!gdsp_load_coef(DSP_COEF_FILE))
{
bCanWork = false;
PanicAlert("Failed loading DSP COEF from " DSP_COEF_FILE);
}
if (!bCanWork) {
gdsp_shutdown();
return;
}
bIsRunning = true;
InitInstructionTable();
g_hDSPThread = new Common::Thread(dsp_thread, NULL);
soundStream = AudioCommon::InitSoundStream();
}
void DSP_StopSoundStream()
{
gdsp_stop();
bIsRunning = false;
delete g_hDSPThread;
g_hDSPThread = NULL;
}
void Shutdown()
{
AudioCommon::ShutdownSoundStream();
gdsp_shutdown();
}
u16 DSP_WriteControlRegister(u16 _uFlag)
{
gdsp_write_cr(_uFlag);
return gdsp_read_cr();
}
u16 DSP_ReadControlRegister()
{
return gdsp_read_cr();
}
u16 DSP_ReadMailboxHigh(bool _CPUMailbox)
{
if (_CPUMailbox)
return gdsp_mbox_read_h(GDSP_MBOX_CPU);
else
return gdsp_mbox_read_h(GDSP_MBOX_DSP);
}
u16 DSP_ReadMailboxLow(bool _CPUMailbox)
{
if (_CPUMailbox)
return gdsp_mbox_read_l(GDSP_MBOX_CPU);
else
return gdsp_mbox_read_l(GDSP_MBOX_DSP);
}
void DSP_WriteMailboxHigh(bool _CPUMailbox, u16 _uHighMail)
{
if (_CPUMailbox)
{
if (gdsp_mbox_peek(GDSP_MBOX_CPU) & 0x80000000)
{
ERROR_LOG(DSPLLE, "Mailbox isnt empty ... strange");
}
#if PROFILE
if ((_uHighMail) == 0xBABE)
{
ProfilerStart();
}
#endif
gdsp_mbox_write_h(GDSP_MBOX_CPU, _uHighMail);
}
else
{
ERROR_LOG(DSPLLE, "CPU cant write to DSP mailbox");
}
}
void DSP_WriteMailboxLow(bool _CPUMailbox, u16 _uLowMail)
{
if (_CPUMailbox)
{
gdsp_mbox_write_l(GDSP_MBOX_CPU, _uLowMail);
u32 uAddress = gdsp_mbox_peek(GDSP_MBOX_CPU);
u16 errpc = g_dsp.err_pc;
DEBUG_LOG(DSPLLE, "CPU writes mail to mbx 0: 0x%08x (pc=0x%04x)\n", uAddress, errpc);
// I couldn't find any better way to detect the AX mails so this had to
// do. Please feel free to change it.
if ((errpc == 0x0054 || errpc == 0x0055) && m_addressPBs == 0)
{
DEBUG_LOG(DSPLLE, "AXTask ======== 0x%08x (pc=0x%04x)", uAddress, errpc);
AXTask(uAddress);
}
}
else
{
ERROR_LOG(DSPLLE, "CPU cant write to DSP mailbox");
}
}
void DSP_Update(int cycles)
{
soundStream->Update();
#if defined(HAVE_WX) && HAVE_WX
// TODO fix? dunno how we should handle debug thread or whatever
// if (m_DebuggerFrame->CanDoStep())
// gdsp_runx(100); // cycles
#endif
}
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
{
if (soundStream->GetMixer())
{
short samples[16] = {0}; // interleaved stereo
if (address)
{
for (int i = 0; i < 16; i++)
{
samples[i] = Memory_Read_U16(address + i * 2);
}
}
soundStream->GetMixer()->PushSamples(samples, 32 / 4, sample_rate);
}
// SoundStream is updated only when necessary (there is no 70 ms limit
// so each sample now triggers the sound stream)
// TODO: think about this.
//static int counter = 0;
//counter++;
if (/*(counter & 31) == 0 &&*/ soundStream)
soundStream->Update();
}

View File

@ -0,0 +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 "stdafx.h"

View File

@ -0,0 +1,27 @@
// 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/
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define _CRT_SECURE_NO_DEPRECATE 1
#include <windows.h>
#include <tchar.h>
#include "PluginSpecs_DSP.h"