mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-14 04:19:29 +00:00
MemoryView can now view ARAM (rightclick -> toggle memory). Add "search for instruction" capability to debugger. Code cleanup, log zelda pb type (9 all the time in Zelda Four Swords)
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3479 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
9d9ce4274b
commit
51cbdea782
@ -11,7 +11,7 @@ protected:
|
||||
|
||||
public:
|
||||
virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
|
||||
virtual void getRawMemoryString(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
|
||||
virtual void getRawMemoryString(int memory, unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
|
||||
virtual int getInstructionSize(int /*instruction*/) {return 1;}
|
||||
virtual bool isAlive() {return true;}
|
||||
virtual bool isBreakpoint(unsigned int /*address*/) {return false;}
|
||||
@ -20,6 +20,7 @@ public:
|
||||
virtual void clearAllBreakpoints() {}
|
||||
virtual void toggleBreakpoint(unsigned int /*address*/){}
|
||||
virtual unsigned int readMemory(unsigned int /*address*/){return 0;}
|
||||
virtual unsigned int readExtraMemory(int memory, unsigned int address){return 0;}
|
||||
virtual unsigned int readInstruction(unsigned int /*address*/){return 0;}
|
||||
virtual unsigned int getPC() {return 0;}
|
||||
virtual void setPC(unsigned int /*address*/) {}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "PPCDebugInterface.h"
|
||||
#include "PowerPCDisasm.h"
|
||||
#include "../Core.h"
|
||||
#include "../HW/DSP.h"
|
||||
#include "../HW/Memmap.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../PowerPC/Jit64/Jit.h"
|
||||
@ -51,17 +52,17 @@ void PPCDebugInterface::disasm(unsigned int address, char *dest, int max_size)
|
||||
}
|
||||
}
|
||||
|
||||
void PPCDebugInterface::getRawMemoryString(unsigned int address, char *dest, int max_size)
|
||||
void PPCDebugInterface::getRawMemoryString(int memory, unsigned int address, char *dest, int max_size)
|
||||
{
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||
{
|
||||
if (Memory::IsRAMAddress(address, true))
|
||||
if (memory || Memory::IsRAMAddress(address, true))
|
||||
{
|
||||
snprintf(dest, max_size, "%08X", readMemory(address));
|
||||
snprintf(dest, max_size, "%08X%s", readExtraMemory(memory, address), memory ? " (ARAM)" : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(dest, "--------");
|
||||
strcpy(dest, memory ? "--ARAM--" : "--------");
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -75,6 +76,22 @@ unsigned int PPCDebugInterface::readMemory(unsigned int address)
|
||||
return Memory::ReadUnchecked_U32(address);
|
||||
}
|
||||
|
||||
unsigned int PPCDebugInterface::readExtraMemory(int memory, unsigned int address)
|
||||
{
|
||||
switch (memory)
|
||||
{
|
||||
case 0:
|
||||
return Memory::ReadUnchecked_U32(address);
|
||||
case 1:
|
||||
return (DSP::ReadARAM(address) << 24) |
|
||||
(DSP::ReadARAM(address + 1) << 16) |
|
||||
(DSP::ReadARAM(address + 2) << 8) |
|
||||
(DSP::ReadARAM(address + 3));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int PPCDebugInterface::readInstruction(unsigned int address)
|
||||
{
|
||||
return Memory::Read_Instruction(address);
|
||||
|
@ -12,7 +12,7 @@ class PPCDebugInterface : public DebugInterface
|
||||
public:
|
||||
PPCDebugInterface(){}
|
||||
virtual void disasm(unsigned int address, char *dest, int max_size);
|
||||
virtual void getRawMemoryString(unsigned int address, char *dest, int max_size);
|
||||
virtual void getRawMemoryString(int memory, unsigned int address, char *dest, int max_size);
|
||||
virtual int getInstructionSize(int instruction) {return 4;}
|
||||
virtual bool isAlive();
|
||||
virtual bool isBreakpoint(unsigned int address);
|
||||
@ -21,6 +21,11 @@ public:
|
||||
virtual void clearAllBreakpoints();
|
||||
virtual void toggleBreakpoint(unsigned int address);
|
||||
virtual unsigned int readMemory(unsigned int address);
|
||||
|
||||
enum {
|
||||
EXTRAMEM_ARAM = 1,
|
||||
};
|
||||
virtual unsigned int readExtraMemory(int memory, unsigned int address);
|
||||
virtual unsigned int readInstruction(unsigned int address);
|
||||
virtual unsigned int getPC();
|
||||
virtual void setPC(unsigned int address);
|
||||
|
@ -474,6 +474,7 @@ void UpdateAudioDMA()
|
||||
// Latch new parameters
|
||||
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
|
||||
g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
|
||||
DEBUG_LOG(DSPLLE, "ADMA read addresses: %08x", g_audioDMA.ReadAddress);
|
||||
GenerateDSPInterrupt(DSP::INT_AID);
|
||||
}
|
||||
} else {
|
||||
|
@ -11,11 +11,12 @@ static int histl2;
|
||||
static int histr1;
|
||||
static int histr2;
|
||||
|
||||
short ADPDecodeSample(int bits, int q, int *hist1p, int *hist2p) {
|
||||
int hist, cur;
|
||||
short ADPDecodeSample(int bits, int q, int *hist1p, int *hist2p)
|
||||
{
|
||||
const int hist1 = *hist1p;
|
||||
const int hist2 = *hist2p;
|
||||
|
||||
int hist;
|
||||
switch (q >> 4)
|
||||
{
|
||||
case 0:
|
||||
@ -35,7 +36,7 @@ short ADPDecodeSample(int bits, int q, int *hist1p, int *hist2p) {
|
||||
if (hist > 0x1fffff) hist = 0x1fffff;
|
||||
if (hist < -0x200000) hist = -0x200000;
|
||||
|
||||
cur = (((short)(bits << 12) >> (q & 0xf)) << 6) + hist;
|
||||
int cur = (((short)(bits << 12) >> (q & 0xf)) << 6) + hist;
|
||||
|
||||
*hist2p = *hist1p;
|
||||
*hist1p = cur;
|
||||
|
@ -108,7 +108,6 @@ void ps_div(UGeckoInstruction _inst)
|
||||
{
|
||||
rPS0(_inst.FD) = static_cast<float>(rPS0(_inst.FA) / rPS0(_inst.FB));
|
||||
rPS1(_inst.FD) = static_cast<float>(rPS1(_inst.FA) / rPS1(_inst.FB));
|
||||
FPSCR.FI = 0;
|
||||
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
||||
FPSCR.ZX = 1;
|
||||
}
|
||||
@ -119,12 +118,14 @@ void ps_res(UGeckoInstruction _inst)
|
||||
{
|
||||
rPS0(_inst.FD) = 1.0f / static_cast<float>(rPS0(_inst.FB));
|
||||
rPS1(_inst.FD) = 1.0f / static_cast<float>(rPS1(_inst.FB));
|
||||
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
||||
FPSCR.ZX = 1;
|
||||
}
|
||||
if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD));
|
||||
}
|
||||
|
||||
void ps_rsqrte(UGeckoInstruction _inst)
|
||||
{
|
||||
// PanicAlert("ps_rsqrte");
|
||||
rPS0(_inst.FD) = static_cast<double>(1.0f / sqrtf((float)rPS0(_inst.FB)));
|
||||
rPS1(_inst.FD) = static_cast<double>(1.0f / sqrtf((float)rPS1(_inst.FB)));
|
||||
if (fabs(rPS0(_inst.FB)) == 0.0) {
|
||||
|
@ -687,7 +687,7 @@ void InitTables()
|
||||
}
|
||||
|
||||
#define OPLOG
|
||||
#define OP_TO_LOG "mffs"
|
||||
#define OP_TO_LOG "mtfsb0x"
|
||||
|
||||
#ifdef OPLOG
|
||||
namespace {
|
||||
@ -695,6 +695,12 @@ namespace {
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *GetInstructionName(UGeckoInstruction _inst)
|
||||
{
|
||||
const GekkoOPInfo *info = GetOpInfo(_inst);
|
||||
return info ? info->opname : 0;
|
||||
}
|
||||
|
||||
void CompileInstruction(UGeckoInstruction _inst)
|
||||
{
|
||||
(jit.*dynaOpTable[_inst.OPCD])(_inst);
|
||||
@ -712,9 +718,9 @@ void CompileInstruction(UGeckoInstruction _inst)
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidInstruction(UGeckoInstruction _instCode)
|
||||
bool IsValidInstruction(UGeckoInstruction _inst)
|
||||
{
|
||||
const GekkoOPInfo *info = GetOpInfo(_instCode);
|
||||
const GekkoOPInfo *info = GetOpInfo(_inst);
|
||||
return info != 0;
|
||||
}
|
||||
|
||||
|
@ -102,8 +102,6 @@ class Jit64;
|
||||
namespace PPCTables
|
||||
{
|
||||
|
||||
|
||||
|
||||
typedef void (Jit64::*_recompilerInstruction) (UGeckoInstruction instCode);
|
||||
typedef void (*_interpreterInstruction)(UGeckoInstruction instCode);
|
||||
|
||||
@ -115,6 +113,7 @@ void CountInstruction(UGeckoInstruction _inst);
|
||||
void PrintInstructionRunCounts();
|
||||
void LogCompiledInstructions();
|
||||
void CompileInstruction(UGeckoInstruction _inst);
|
||||
const char *GetInstructionName(UGeckoInstruction _inst);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -283,9 +283,11 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
|
||||
// Insert blr or restore old value
|
||||
case IDM_INSERTBLR:
|
||||
InsertBlrNop(0);
|
||||
redraw();
|
||||
break;
|
||||
case IDM_INSERTNOP:
|
||||
InsertBlrNop(1);
|
||||
redraw();
|
||||
break;
|
||||
|
||||
case IDM_JITRESULTS:
|
||||
|
@ -46,6 +46,7 @@
|
||||
|
||||
#include "FileUtil.h"
|
||||
#include "Core.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "HLE/HLE.h"
|
||||
#include "Boot/Boot.h"
|
||||
#include "LogManager.h"
|
||||
@ -140,6 +141,7 @@ BEGIN_EVENT_TABLE(CCodeWindow, wxFrame)
|
||||
|
||||
EVT_MENU(IDM_CLEARCODECACHE, CCodeWindow::OnJitMenu)
|
||||
EVT_MENU(IDM_LOGINSTRUCTIONS, CCodeWindow::OnJitMenu)
|
||||
EVT_MENU(IDM_SEARCHINSTRUCTION, CCodeWindow::OnJitMenu)
|
||||
|
||||
EVT_MENU(IDM_PROFILEBLOCKS, CCodeWindow::OnProfilerMenu)
|
||||
EVT_MENU(IDM_WRITEPROFILE, CCodeWindow::OnProfilerMenu)
|
||||
@ -656,6 +658,18 @@ void CCodeWindow::OnJitMenu(wxCommandEvent& event)
|
||||
|
||||
case IDM_CLEARCODECACHE:
|
||||
jit.ClearCache(); break;
|
||||
|
||||
case IDM_SEARCHINSTRUCTION:
|
||||
{
|
||||
wxString str;
|
||||
str = wxGetTextFromUser("", "Op?", wxEmptyString, this);
|
||||
for (u32 addr = 0x80000000; addr < 0x80100000; addr += 4) {
|
||||
const char *name = PPCTables::GetInstructionName(Memory::ReadUnchecked_U32(addr));
|
||||
if (name && !strcmp(str.c_str(), name))
|
||||
NOTICE_LOG(POWERPC, "Found %s at %08x", str.c_str(), addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// =====================================
|
||||
|
@ -106,6 +106,7 @@ class CCodeWindow
|
||||
// JIT
|
||||
IDM_CLEARCODECACHE,
|
||||
IDM_LOGINSTRUCTIONS,
|
||||
IDM_SEARCHINSTRUCTION,
|
||||
|
||||
// Profiler
|
||||
IDM_PROFILEBLOCKS,
|
||||
|
@ -110,6 +110,7 @@ void CCodeWindow::CreateSymbolsMenu()
|
||||
wxMenu *pJitMenu = new wxMenu;
|
||||
pJitMenu->Append(IDM_CLEARCODECACHE, _T("&Clear code cache"));
|
||||
pJitMenu->Append(IDM_LOGINSTRUCTIONS, _T("&Log JIT instruction coverage"));
|
||||
pJitMenu->Append(IDM_SEARCHINSTRUCTION, _T("&Search for an op"));
|
||||
pMenuBar->Append(pJitMenu, _T("&JIT"));
|
||||
|
||||
wxMenu *pProfilerMenu = new wxMenu;
|
||||
|
@ -31,6 +31,7 @@ enum
|
||||
IDM_COPYCODE,
|
||||
IDM_RUNTOHERE,
|
||||
IDM_DYNARECRESULTS,
|
||||
IDM_TOGGLEMEMORY,
|
||||
};
|
||||
|
||||
|
||||
@ -54,7 +55,8 @@ CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent, wxWin
|
||||
selectionChanged(false),
|
||||
selecting(false),
|
||||
hasFocus(false),
|
||||
showHex(false)
|
||||
showHex(false),
|
||||
memory(0)
|
||||
{
|
||||
rowHeight = 13;
|
||||
align = debuginterface->getInstructionSize(0);
|
||||
@ -169,10 +171,15 @@ void CMemoryView::OnPopupMenu(wxCommandEvent& event)
|
||||
case IDM_COPYHEX:
|
||||
{
|
||||
char temp[24];
|
||||
sprintf(temp, "%08x", debugger->readMemory(selection));
|
||||
sprintf(temp, "%08x", debugger->readExtraMemory(memory, selection));
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::FromAscii(temp)));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case IDM_TOGGLEMEMORY:
|
||||
memory ^= 1;
|
||||
redraw();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -192,6 +199,7 @@ void CMemoryView::OnMouseUpR(wxMouseEvent& event)
|
||||
menu.Append(IDM_COPYADDRESS, wxString::FromAscii("Copy &address"));
|
||||
menu.Append(IDM_COPYHEX, wxString::FromAscii("Copy &hex"));
|
||||
#endif
|
||||
menu.Append(IDM_TOGGLEMEMORY, wxString::FromAscii("Toggle &memory (RAM/ARAM)"));
|
||||
PopupMenu(&menu);
|
||||
event.Skip(true);
|
||||
}
|
||||
@ -276,7 +284,7 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
||||
dc.SetTextForeground(_T("#600000"));
|
||||
dc.DrawText(temp, 17, rowY1);
|
||||
char mem[256];
|
||||
debugger->getRawMemoryString(address, mem, 256);
|
||||
debugger->getRawMemoryString(memory, address, mem, 256);
|
||||
dc.SetTextForeground(_T("#000080"));
|
||||
dc.DrawText(wxString::FromAscii(mem), 17+fontSize*(8), rowY1);
|
||||
dc.SetTextForeground(_T("#000000"));
|
||||
@ -284,12 +292,12 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
|
||||
if (debugger->isAlive())
|
||||
{
|
||||
char dis[256] = {0};
|
||||
u32 mem = debugger->readMemory(address);
|
||||
u32 mem = debugger->readExtraMemory(memory, address);
|
||||
float flt = *(float *)(&mem);
|
||||
sprintf(dis, "f: %f", flt);
|
||||
char desc[256] = "";
|
||||
|
||||
dc.DrawText(wxString::FromAscii(dis), 17 + fontSize*(8 + 8), rowY1);
|
||||
dc.DrawText(wxString::FromAscii(dis), 77 + fontSize*(8 + 8), rowY1);
|
||||
|
||||
if (desc[0] == 0)
|
||||
{
|
||||
|
@ -22,55 +22,47 @@
|
||||
#include "Common.h"
|
||||
#include "Debugger/DebugInterface.h"
|
||||
|
||||
|
||||
class CMemoryView
|
||||
: public wxControl
|
||||
class CMemoryView : public wxControl
|
||||
{
|
||||
public:
|
||||
public:
|
||||
CMemoryView(DebugInterface* debuginterface, wxWindow* parent, wxWindowID Id = -1, const wxSize& Size = wxDefaultSize);
|
||||
wxSize DoGetBestSize() const;
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnErase(wxEraseEvent& event);
|
||||
void OnMouseDown(wxMouseEvent& event);
|
||||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnMouseUpL(wxMouseEvent& event);
|
||||
void OnMouseUpR(wxMouseEvent& event);
|
||||
void OnPopupMenu(wxCommandEvent& event);
|
||||
|
||||
CMemoryView(DebugInterface* debuginterface, wxWindow* parent, wxWindowID Id = -1, const wxSize& Size = wxDefaultSize);
|
||||
wxSize DoGetBestSize() const;
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnErase(wxEraseEvent& event);
|
||||
void OnMouseDown(wxMouseEvent& event);
|
||||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnMouseUpL(wxMouseEvent& event);
|
||||
void OnMouseUpR(wxMouseEvent& event);
|
||||
void OnPopupMenu(wxCommandEvent& event);
|
||||
u32 GetSelection() {return(selection);}
|
||||
|
||||
void Center(u32 addr)
|
||||
{
|
||||
curAddress = addr;
|
||||
redraw();
|
||||
}
|
||||
|
||||
u32 GetSelection() {return(selection);}
|
||||
private:
|
||||
int YToAddress(int y);
|
||||
void redraw() {Refresh();}
|
||||
|
||||
DebugInterface* debugger;
|
||||
|
||||
void Center(u32 addr)
|
||||
{
|
||||
curAddress = addr;
|
||||
redraw();
|
||||
}
|
||||
int curAddress;
|
||||
int align;
|
||||
int rowHeight;
|
||||
|
||||
u32 selection;
|
||||
u32 oldSelection;
|
||||
bool selectionChanged;
|
||||
bool selecting;
|
||||
bool hasFocus;
|
||||
bool showHex;
|
||||
|
||||
private:
|
||||
int memory;
|
||||
|
||||
int YToAddress(int y);
|
||||
|
||||
|
||||
void redraw() {Refresh();}
|
||||
|
||||
|
||||
DebugInterface* debugger;
|
||||
|
||||
int curAddress;
|
||||
int align;
|
||||
int rowHeight;
|
||||
|
||||
u32 selection;
|
||||
u32 oldSelection;
|
||||
bool selectionChanged;
|
||||
bool selecting;
|
||||
bool hasFocus;
|
||||
bool showHex;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif /*MEMORYVIEW_H_*/
|
||||
|
@ -42,24 +42,11 @@
|
||||
|
||||
enum
|
||||
{
|
||||
IDM_DEBUG_GO = 350,
|
||||
IDM_STEP,
|
||||
IDM_STEPOVER,
|
||||
IDM_SKIP,
|
||||
IDM_SETPC,
|
||||
IDM_GOTOPC,
|
||||
IDM_ADDRBOX,
|
||||
IDM_CALLSTACKLIST,
|
||||
IDM_ADDRBOX = 350,
|
||||
IDM_SYMBOLLIST,
|
||||
IDM_INTERPRETER,
|
||||
IDM_DUALCORE,
|
||||
IDM_LOGWINDOW,
|
||||
IDM_REGISTERWINDOW,
|
||||
IDM_BREAKPOINTWINDOW,
|
||||
IDM_VALBOX,
|
||||
IDM_SETVALBUTTON,
|
||||
IDM_DUMP_MEMORY,
|
||||
|
||||
IDM_VALBOX,
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(CMemoryWindow, wxFrame)
|
||||
@ -70,7 +57,6 @@ BEGIN_EVENT_TABLE(CMemoryWindow, wxFrame)
|
||||
EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id,
|
||||
const wxString& title, const wxPoint& pos, const wxSize& size, long style)
|
||||
: wxFrame(parent, id, title, pos, size, style)
|
||||
@ -87,9 +73,7 @@ CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id,
|
||||
//sizerBig->Add(sizerLeft, 1, wxEXPAND);
|
||||
sizerBig->Add(memview, 20, wxEXPAND);
|
||||
sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
|
||||
sizerRight->Add(buttonGo = new wxButton(this, IDM_DEBUG_GO, _T("&Go")));
|
||||
sizerRight->Add(addrbox = new wxTextCtrl(this, IDM_ADDRBOX, _T("")));
|
||||
sizerRight->Add(new wxButton(this, IDM_SETPC, _T("S&et PC")));
|
||||
sizerRight->Add(valbox = new wxTextCtrl(this, IDM_VALBOX, _T("")));
|
||||
sizerRight->Add(new wxButton(this, IDM_SETVALBUTTON, _T("Set &Value")));
|
||||
|
||||
@ -162,14 +146,15 @@ void CMemoryWindow::SetMemoryValue(wxCommandEvent& event)
|
||||
Memory::Write_U32(val, addr);
|
||||
memview->Refresh();
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event)
|
||||
{
|
||||
wxString txt = addrbox->GetValue();
|
||||
if (txt.size() == 8)
|
||||
if (txt.size())
|
||||
{
|
||||
u32 addr;
|
||||
sscanf(txt.mb_str(), "%08x", &addr);
|
||||
memview->Center(addr);
|
||||
memview->Center(addr & ~3);
|
||||
}
|
||||
|
||||
event.Skip(1);
|
||||
|
@ -27,84 +27,63 @@
|
||||
#include "../main.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
|
||||
namespace {
|
||||
CompileTimeAssert<sizeof(ZPB) == 0x180> dummy_name;
|
||||
}
|
||||
|
||||
// TODO: replace with table from RAM.
|
||||
unsigned short afccoef[16][2] =
|
||||
{{0,0},
|
||||
{0x0800,0},
|
||||
{0,0x0800},
|
||||
{0x0400,0x0400},
|
||||
{0x1000,0xf800},
|
||||
{0x0e00,0xfa00},
|
||||
{0x0c00,0xfc00},
|
||||
{0x1200,0xf600},
|
||||
{0x1068,0xf738},
|
||||
{0x12c0,0xf704},
|
||||
{0x1400,0xf400},
|
||||
{0x0800,0xf800},
|
||||
{0x0400,0xfc00},
|
||||
{0xfc00,0x0400},
|
||||
{0xfc00,0},
|
||||
{0xf800,0}};
|
||||
|
||||
const u16 afccoef[16][2] =
|
||||
{
|
||||
{0,0}, {0x0800,0}, {0, 0x0800},{0x0400,0x0400},
|
||||
{0x1000,0xf800},{0x0e00,0xfa00},{0x0c00,0xfc00},{0x1200,0xf600},
|
||||
{0x1068,0xf738},{0x12c0,0xf704},{0x1400,0xf400},{0x0800,0xf800},
|
||||
{0x0400,0xfc00},{0xfc00,0x0400},{0xfc00,0}, {0xf800,0}
|
||||
};
|
||||
|
||||
// Decoder from in_cube by hcs/destop/etc. Haven't yet found a valid use for it.
|
||||
|
||||
// Looking at in_cube, it seems to be 9 bytes of input = 16 samples of output.
|
||||
// Different from AX ADPCM which is 8 bytes of input = 14 samples of output.
|
||||
void AFCdecodebuffer
|
||||
(
|
||||
u8 *input, // location of encoded source samples
|
||||
s16 *out, // location of destination buffer (16 bits / sample)
|
||||
short *histp,
|
||||
short *hist2p
|
||||
)
|
||||
// input = location of encoded source samples
|
||||
// out = location of destination buffer (16 bits / sample)
|
||||
void AFCdecodebuffer(const u8 *input, s16 *out, short *histp, short *hist2p)
|
||||
{
|
||||
int sample;
|
||||
short nibbles[16];
|
||||
u8 *src, *dst;
|
||||
short idx;
|
||||
short delta;
|
||||
short hist=*histp;
|
||||
short hist2=*hist2p;
|
||||
|
||||
dst = (u8 *)out;
|
||||
|
||||
src = input;
|
||||
delta = 1 << (((*src) >> 4)&0xf);
|
||||
idx = (*src) & 0xf;
|
||||
u8 *dst = (u8 *)out;
|
||||
short hist = *histp;
|
||||
short hist2 = *hist2p;
|
||||
const u8 *src = input;
|
||||
|
||||
// 9 bytes input - first byte contain delta scaling and coef index.
|
||||
const short delta = 1 << (((*src) >> 4) & 0xf);
|
||||
const short idx = *src & 0xf;
|
||||
src++;
|
||||
|
||||
for (int i = 0; i < 16; i = i + 2)
|
||||
// denibble the rest of the 8 bytes into 16 values.
|
||||
for (int i = 0; i < 16; i += 2)
|
||||
{
|
||||
int j = ( *src & 255) >> 4;
|
||||
int j = *src >> 4;
|
||||
nibbles[i] = j;
|
||||
j = *src & 255 & 15;
|
||||
j = *src & 0xF;
|
||||
nibbles[i + 1] = j;
|
||||
src++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i = i + 1)
|
||||
// make the nibbles signed.
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (nibbles[i] >= 8)
|
||||
nibbles[i] = nibbles[i] - 16;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i = i + 1)
|
||||
// Perform ADPCM filtering.
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
sample = (delta * nibbles[i]) << 11;
|
||||
int sample = (delta * nibbles[i]) << 11;
|
||||
sample += ((long)hist * afccoef[idx][0]) + ((long)hist2 * afccoef[idx][1]);
|
||||
sample = sample >> 11;
|
||||
|
||||
if(sample > 32767) {
|
||||
// Clamp sample.
|
||||
if (sample > 32767) {
|
||||
sample = 32767;
|
||||
}
|
||||
if(sample < -32768) {
|
||||
if (sample < -32768) {
|
||||
sample = -32768;
|
||||
}
|
||||
|
||||
@ -115,12 +94,12 @@ void AFCdecodebuffer
|
||||
hist = (short)sample;
|
||||
}
|
||||
|
||||
*histp=hist;
|
||||
*hist2p=hist2;
|
||||
// Store state.
|
||||
*histp = hist;
|
||||
*hist2p = hist2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler)
|
||||
: IUCode(_rMailHandler)
|
||||
, m_bSyncInProgress(false)
|
||||
@ -136,6 +115,9 @@ CUCode_Zelda::CUCode_Zelda(CMailHandler& _rMailHandler)
|
||||
, m_bListInProgress(false)
|
||||
, m_step(0)
|
||||
, m_readOffset(0)
|
||||
, num_param_blocks(0)
|
||||
, param_blocks_ptr(0)
|
||||
, param_blocks2_ptr(0)
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "UCode_Zelda - add boot mails for handshake");
|
||||
|
||||
@ -163,15 +145,7 @@ void CUCode_Zelda::Update(int cycles)
|
||||
|
||||
void CUCode_Zelda::HandleMail(u32 _uMail)
|
||||
{
|
||||
// XK: Sync mails spam the logs
|
||||
/*
|
||||
DEBUG_LOG(DSPHLE, "Zelda mail 0x%08X, list in progress? %s, sync in progress? %s", _uMail,
|
||||
m_bListInProgress ? "Yes" : "No", m_bSyncInProgress ? "Yes" : "No");
|
||||
*/
|
||||
// SetupTable
|
||||
// in WW we get SetDolbyDelay
|
||||
// SyncFrame
|
||||
// The last mails we get before the audio goes bye-bye
|
||||
// When we used to lose sync, the last mails we get before the audio goes bye-bye
|
||||
// 0
|
||||
// 0x00000
|
||||
// 0
|
||||
@ -180,8 +154,7 @@ void CUCode_Zelda::HandleMail(u32 _uMail)
|
||||
// 0x20000
|
||||
// 0
|
||||
// 0x30000
|
||||
// And then silence...
|
||||
|
||||
// And then silence... Looks like some reverse countdown :)
|
||||
if (m_bSyncInProgress)
|
||||
{
|
||||
if (m_bSyncCmdPending)
|
||||
@ -223,14 +196,15 @@ void CUCode_Zelda::HandleMail(u32 _uMail)
|
||||
return;
|
||||
}
|
||||
|
||||
if(_uMail != 0) {
|
||||
if (_uMail != 0)
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "Zelda mail 0x%08X, list in progress? %s", _uMail,
|
||||
m_bListInProgress ? "Yes" : "No");
|
||||
}
|
||||
|
||||
if (m_bListInProgress)
|
||||
{
|
||||
if (m_step < 0 || m_step >= sizeof(m_Buffer)/4)
|
||||
if (m_step < 0 || m_step >= sizeof(m_Buffer) / 4)
|
||||
PanicAlert("m_step out of range");
|
||||
|
||||
((u32*)m_Buffer)[m_step] = _uMail;
|
||||
@ -315,7 +289,7 @@ void CUCode_Zelda::ExecuteList()
|
||||
// SyncFrame ... zelda ww jumps to 0x0243
|
||||
case 0x02:
|
||||
{
|
||||
u32 tmp[3];
|
||||
u32 tmp[2];
|
||||
tmp[0] = Read32();
|
||||
tmp[1] = Read32();
|
||||
|
||||
@ -346,12 +320,13 @@ void CUCode_Zelda::ExecuteList()
|
||||
CopyPBsFromRAM();
|
||||
for (int i = 0; i < num_param_blocks; i++)
|
||||
{
|
||||
const ZPB &pb = zpbs[i];
|
||||
// The only thing that consistently looks like a pointer in the param blocks.
|
||||
u32 addr = (zpbs[i].addr_high << 16) | zpbs[i].addr_low;
|
||||
u32 addr = (pb.addr_high << 16) | pb.addr_low;
|
||||
if (addr)
|
||||
{
|
||||
DEBUG_LOG(DSPHLE, "Param block: ==== %i ( %08x ) ====", i, GetParamBlockAddr(i));
|
||||
DEBUG_LOG(DSPHLE, "Addr: %08x", addr);
|
||||
DEBUG_LOG(DSPHLE, "Addr: %08x Type: %i", addr, pb.type);
|
||||
|
||||
// Got one! Read from ARAM, dump to file.
|
||||
// I can't get the below to produce anything resembling sane audio :(
|
||||
@ -406,11 +381,9 @@ void CUCode_Zelda::ExecuteList()
|
||||
// DsetDolbyDelay ... zelda ww jumps to 0x00b2
|
||||
case 0x0d:
|
||||
{
|
||||
u32 tmp[2];
|
||||
tmp[0] = Read32();
|
||||
|
||||
u32 tmp = Read32();
|
||||
DEBUG_LOG(DSPHLE, "DSetDolbyDelay");
|
||||
DEBUG_LOG(DSPHLE, "DOLBY2_DELAY_BUF (size 0x960): 0x%08x", tmp[0]);
|
||||
DEBUG_LOG(DSPHLE, "DOLBY2_DELAY_BUF (size 0x960): 0x%08x", tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -473,11 +446,13 @@ void CUCode_Zelda::CopyPBsToRAM()
|
||||
}
|
||||
}
|
||||
|
||||
// size is in stereo samples.
|
||||
void CUCode_Zelda::MixAdd(short* buffer, int size)
|
||||
{
|
||||
//TODO(XK): Zelda UCode MixAdd?
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// buffer[i] = rand();
|
||||
// for (int i = 0; i < size; i++)
|
||||
// {
|
||||
// buffer[i*2] = rand();
|
||||
// buffer[i*2+1] = rand();
|
||||
// }
|
||||
}
|
||||
|
||||
|
@ -21,26 +21,36 @@
|
||||
#include "Common.h"
|
||||
#include "UCodes.h"
|
||||
|
||||
|
||||
// Here's a piece of pure guesswork, looking at random supposedly-PBs
|
||||
// from Zelda Four Swords.
|
||||
|
||||
// These are 0x180 bytes large.
|
||||
// Zelda WW param blocks. These are 0x180 bytes large.
|
||||
// According to FIRES, the ucodes copies 0xc0 shorts (0x180 bytes) from RAM
|
||||
// but only writes back 0x80 shorts (0x100 bytes). So the last 0x80 are "read only".
|
||||
struct ZPB
|
||||
{
|
||||
u16 temp[0x80];
|
||||
u16 temp2; u16 temp3;
|
||||
u16 whatever[0x14 / 2];
|
||||
// R/W data =============
|
||||
// AFC history (2 shorts) must be in here somewhere, plus lots of other state.
|
||||
u16 rw_unknown[0x80];
|
||||
|
||||
// Read only data
|
||||
u16 type; // 0x5, 0x9 = AFC.
|
||||
u16 r_unknown1;
|
||||
|
||||
u16 r_unknown2[0x14 / 2];
|
||||
|
||||
// Not sure what addresses this is, hopefully to sample data in ARAM.
|
||||
// These are the only things in the param blocks that look a lot like pointers.
|
||||
u16 addr_high; // at 0x18 = 0xC * 2
|
||||
u16 addr_low;
|
||||
|
||||
u16 filler[(0x80 - 0x1C) / 2];
|
||||
u16 r_unknown3[(0x80 - 0x1C) / 2];
|
||||
};
|
||||
|
||||
namespace {
|
||||
// If this miscompiles, adjust the size of ZPB to 0x180 bytes (0xc0 shorts).
|
||||
CompileTimeAssert<sizeof(ZPB) == 0x180> ensure_zpb_size_correct;
|
||||
} // namespace
|
||||
|
||||
|
||||
// Zelda UCode - the big mystery.
|
||||
class CUCode_Zelda : public IUCode
|
||||
{
|
||||
private:
|
||||
@ -54,6 +64,7 @@ private:
|
||||
DSP_UNKN = 0xDCD10005,
|
||||
};
|
||||
|
||||
// Sync =========================================
|
||||
bool m_bSyncInProgress;
|
||||
u32 m_SyncIndex;
|
||||
u32 m_SyncStep;
|
||||
@ -69,17 +80,24 @@ private:
|
||||
u32 m_SyncCount;
|
||||
u32 m_SyncMax;
|
||||
|
||||
// List in progress
|
||||
// List, buffer management =====================
|
||||
u32 m_numSteps;
|
||||
bool m_bListInProgress;
|
||||
u32 m_step;
|
||||
u8 m_Buffer[1024];
|
||||
void ExecuteList();
|
||||
|
||||
u32 m_readOffset;
|
||||
u32 Read32() {
|
||||
u32 res = *(u32*)&m_Buffer[m_readOffset];
|
||||
m_readOffset += 4;
|
||||
if ((m_readOffset >> 2) >= m_numSteps + 1) {
|
||||
WARN_LOG(DSPHLE, "Read32 out of bounds");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Param blocks, mixer state ====================
|
||||
// HLE state
|
||||
int num_param_blocks;
|
||||
|
||||
@ -96,27 +114,6 @@ private:
|
||||
return param_blocks_ptr + sizeof(ZPB) * block_no;
|
||||
}
|
||||
|
||||
u8 Read8()
|
||||
{
|
||||
return m_Buffer[m_readOffset++];
|
||||
}
|
||||
|
||||
u16 Read16()
|
||||
{
|
||||
u16 res = *(u16*)&m_Buffer[m_readOffset];
|
||||
m_readOffset += 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 Read32()
|
||||
{
|
||||
u32 res = *(u32*)&m_Buffer[m_readOffset];
|
||||
m_readOffset += 4;
|
||||
if ((m_readOffset >> 2) >= m_numSteps + 1) {
|
||||
WARN_LOG(DSPHLE, "Read32 out of bounds");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public:
|
||||
|
||||
CUCode_Zelda(CMailHandler& _rMailHandler);
|
||||
@ -128,4 +125,3 @@ public:
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -65,7 +65,7 @@ void DSPDebugInterface::disasm(unsigned int address, char *dest, int max_size)
|
||||
}*/
|
||||
}
|
||||
|
||||
void DSPDebugInterface::getRawMemoryString(unsigned int address, char *dest, int max_size)
|
||||
void DSPDebugInterface::getRawMemoryString(int memory, unsigned int address, char *dest, int max_size)
|
||||
{
|
||||
/*
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||
|
@ -10,7 +10,7 @@ class DSPDebugInterface : public DebugInterface
|
||||
public:
|
||||
DSPDebugInterface(){}
|
||||
virtual void disasm(unsigned int address, char *dest, int max_size);
|
||||
virtual void getRawMemoryString(unsigned int address, char *dest, int max_size);
|
||||
virtual void getRawMemoryString(int memory, unsigned int address, char *dest, int max_size);
|
||||
virtual int getInstructionSize(int instruction) {return 2;}
|
||||
virtual bool isAlive();
|
||||
virtual bool isBreakpoint(unsigned int address);
|
||||
|
Loading…
x
Reference in New Issue
Block a user