mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
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:
49
Source/Plugins/Plugin_DSP_LLE/Src/Config.cpp
Normal file
49
Source/Plugins/Plugin_DSP_LLE/Src/Config.cpp
Normal 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);
|
||||
}
|
34
Source/Plugins/Plugin_DSP_LLE/Src/Config.h
Normal file
34
Source/Plugins/Plugin_DSP_LLE/Src/Config.h
Normal 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
|
||||
|
116
Source/Plugins/Plugin_DSP_LLE/Src/DSPAnalyzer.cpp
Normal file
116
Source/Plugins/Plugin_DSP_LLE/Src/DSPAnalyzer.cpp
Normal 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
|
45
Source/Plugins/Plugin_DSP_LLE/Src/DSPAnalyzer.h
Normal file
45
Source/Plugins/Plugin_DSP_LLE/Src/DSPAnalyzer.h
Normal 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
|
97
Source/Plugins/Plugin_DSP_LLE/Src/DSPConfigDlgLLE.cpp
Normal file
97
Source/Plugins/Plugin_DSP_LLE/Src/DSPConfigDlgLLE.cpp
Normal 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);
|
||||
}
|
60
Source/Plugins/Plugin_DSP_LLE/Src/DSPConfigDlgLLE.h
Normal file
60
Source/Plugins/Plugin_DSP_LLE/Src/DSPConfigDlgLLE.h
Normal 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__
|
1708
Source/Plugins/Plugin_DSP_LLE/Src/DSPInterpreter.cpp
Normal file
1708
Source/Plugins/Plugin_DSP_LLE/Src/DSPInterpreter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
150
Source/Plugins/Plugin_DSP_LLE/Src/DSPInterpreter.h
Normal file
150
Source/Plugins/Plugin_DSP_LLE/Src/DSPInterpreter.h
Normal 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
|
22
Source/Plugins/Plugin_DSP_LLE/Src/DSPJit.cpp
Normal file
22
Source/Plugins/Plugin_DSP_LLE/Src/DSPJit.cpp
Normal 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 {
|
||||
|
||||
};
|
28
Source/Plugins/Plugin_DSP_LLE/Src/DSPJit.h
Normal file
28
Source/Plugins/Plugin_DSP_LLE/Src/DSPJit.h
Normal 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
|
408
Source/Plugins/Plugin_DSP_LLE/Src/DSPTables.cpp
Normal file
408
Source/Plugins/Plugin_DSP_LLE/Src/DSPTables.cpp
Normal 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);
|
||||
}
|
125
Source/Plugins/Plugin_DSP_LLE/Src/DSPTables.h
Normal file
125
Source/Plugins/Plugin_DSP_LLE/Src/DSPTables.h
Normal 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
|
@ -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();
|
||||
}
|
56
Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.h
Normal file
56
Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.h
Normal 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__
|
477
Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp
Normal file
477
Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp
Normal 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;
|
||||
}
|
162
Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.h
Normal file
162
Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.h
Normal 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
|
86
Source/Plugins/Plugin_DSP_LLE/Src/Globals.cpp
Normal file
86
Source/Plugins/Plugin_DSP_LLE/Src/Globals.cpp
Normal 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
|
43
Source/Plugins/Plugin_DSP_LLE/Src/Globals.h
Normal file
43
Source/Plugins/Plugin_DSP_LLE/Src/Globals.h
Normal 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
|
||||
|
91
Source/Plugins/Plugin_DSP_LLE/Src/Logging/AXTask.cpp
Normal file
91
Source/Plugins/Plugin_DSP_LLE/Src/Logging/AXTask.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
334
Source/Plugins/Plugin_DSP_LLE/Src/Logging/Logging.cpp
Normal file
334
Source/Plugins/Plugin_DSP_LLE/Src/Logging/Logging.cpp
Normal 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;
|
||||
// ---------------
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
23
Source/Plugins/Plugin_DSP_LLE/Src/Logging/Logging.h
Normal file
23
Source/Plugins/Plugin_DSP_LLE/Src/Logging/Logging.h
Normal 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
|
103
Source/Plugins/Plugin_DSP_LLE/Src/Logging/ReadPBs.cpp
Normal file
103
Source/Plugins/Plugin_DSP_LLE/Src/Logging/ReadPBs.cpp
Normal 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;
|
||||
}
|
143
Source/Plugins/Plugin_DSP_LLE/Src/Logging/UCode_AXStructs.h
Normal file
143
Source/Plugins/Plugin_DSP_LLE/Src/Logging/UCode_AXStructs.h
Normal 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
|
||||
|
||||
|
43
Source/Plugins/Plugin_DSP_LLE/Src/SConscript
Normal file
43
Source/Plugins/Plugin_DSP_LLE/Src/SConscript
Normal 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)
|
114
Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp
Normal file
114
Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp
Normal 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;
|
||||
}
|
50
Source/Plugins/Plugin_DSP_LLE/Src/Tools.h
Normal file
50
Source/Plugins/Plugin_DSP_LLE/Src/Tools.h
Normal 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);
|
571
Source/Plugins/Plugin_DSP_LLE/Src/disassemble.cpp
Normal file
571
Source/Plugins/Plugin_DSP_LLE/Src/disassemble.cpp
Normal 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;
|
||||
}
|
50
Source/Plugins/Plugin_DSP_LLE/Src/disassemble.h
Normal file
50
Source/Plugins/Plugin_DSP_LLE/Src/disassemble.h
Normal 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);
|
116
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_aram.cpp
Normal file
116
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_aram.cpp
Normal 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);
|
||||
}
|
23
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_aram.h
Normal file
23
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_aram.h
Normal 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
|
156
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_condition_codes.cpp
Normal file
156
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_condition_codes.cpp
Normal 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
|
52
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_condition_codes.h
Normal file
52
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_condition_codes.h
Normal 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
|
284
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_ext_op.cpp
Normal file
284
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_ext_op.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
41
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_ext_op.h
Normal file
41
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_ext_op.h
Normal 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
|
328
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interface.cpp
Normal file
328
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interface.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
70
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interface.h
Normal file
70
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interface.h
Normal 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
|
||||
|
320
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interpreter.cpp
Normal file
320
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interpreter.cpp
Normal 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;
|
||||
}
|
||||
|
123
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interpreter.h
Normal file
123
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_interpreter.h
Normal 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
|
110
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_memory.cpp
Normal file
110
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_memory.cpp
Normal 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);
|
||||
}
|
36
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_memory.h
Normal file
36
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_memory.h
Normal 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
|
226
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_opcodes_helper.h
Normal file
226
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_opcodes_helper.h
Normal 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
|
57
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_registers.cpp
Normal file
57
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_registers.cpp
Normal 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;
|
||||
}
|
100
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_registers.h
Normal file
100
Source/Plugins/Plugin_DSP_LLE/Src/gdsp_registers.h
Normal 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
|
365
Source/Plugins/Plugin_DSP_LLE/Src/main.cpp
Normal file
365
Source/Plugins/Plugin_DSP_LLE/Src/main.cpp
Normal 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();
|
||||
}
|
19
Source/Plugins/Plugin_DSP_LLE/Src/stdafx.cpp
Normal file
19
Source/Plugins/Plugin_DSP_LLE/Src/stdafx.cpp
Normal 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"
|
||||
|
27
Source/Plugins/Plugin_DSP_LLE/Src/stdafx.h
Normal file
27
Source/Plugins/Plugin_DSP_LLE/Src/stdafx.h
Normal 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"
|
||||
|
Reference in New Issue
Block a user