diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd83ddf3..7e63d2c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,7 +58,8 @@ add_library(core STATIC Wifi.cpp WifiAP.cpp - DSP_HLE/Ucode_Base.cpp + DSP_HLE/UcodeBase.cpp + DSP_HLE/GraphicsUcode.cpp fatfs/ff.c fatfs/ffsystem.c diff --git a/src/CRC32.cpp b/src/CRC32.cpp index 8417f9ce..593d1806 100644 --- a/src/CRC32.cpp +++ b/src/CRC32.cpp @@ -59,8 +59,17 @@ u32 CRC32(const u8 *data, int len, u32 start) u32 crc = start ^ 0xFFFFFFFF; - while (len--) - crc = (crc >> 8) ^ Crc32Table[(crc & 0xFF) ^ *data++]; + if (data) + { + while (len--) + crc = (crc >> 8) ^ Crc32Table[(crc & 0xFF) ^ *data++]; + } + else + { + // null data acts like checksumming a block of zeros + while (len--) + crc = (crc >> 8) ^ Crc32Table[(crc & 0xFF)]; + } return (crc ^ 0xFFFFFFFF); } diff --git a/src/DSP_HLE/GraphicsUcode.cpp b/src/DSP_HLE/GraphicsUcode.cpp new file mode 100644 index 00000000..6e104e0b --- /dev/null +++ b/src/DSP_HLE/GraphicsUcode.cpp @@ -0,0 +1,235 @@ +/* + Copyright 2016-2025 melonDS team + + This file is part of melonDS. + + melonDS 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 3 of the License, or (at your option) + any later version. + + melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include "../DSi.h" +#include "GraphicsUcode.h" +#include "../Platform.h" + + +namespace melonDS +{ +using Platform::Log; +using Platform::LogLevel; + +namespace DSP_HLE +{ + + +GraphicsUcode::GraphicsUcode(melonDS::DSi& dsi, int version) : UcodeBase(dsi) +{ + Log(LogLevel::Info, "DSP_HLE: initializing Graphics SDK ucode version %d\n", version); +} + +GraphicsUcode::~GraphicsUcode() +{ + // +} + +void GraphicsUcode::Reset() +{ + UcodeBase::Reset(); +} + +void GraphicsUcode::DoSavestate(Savestate *file) +{ + // +} + + +void GraphicsUcode::SendData(u8 index, u16 val) +{ + UcodeBase::SendData(index, val); + + if (index == 0) + { + if (UcodeCmd) + { + printf("???? there is already a command pending\n"); + return; + } + + // writing to CMD0 initiates a ucode-specific command + // parameters are then written to pipe 7 + UcodeCmd = val; + CmdWritten[index] = false; + + RunUcodeCmd(); + } + else if (index == 2) + { + // CMD2 serves to notify that a pipe was written to + // value is the pipe index + + CmdWritten[index] = false; + + if (UcodeCmd) + RunUcodeCmd(); + } +} + + +void GraphicsUcode::RunUcodeCmd() +{ + u16* pipe = LoadPipe(7); + u32 len = GetPipeLength(pipe); +printf("try to run ucode cmd: cmd=%d, len=%d\n", UcodeCmd, len); + switch (UcodeCmd) + { + case 1: // scaling + if (len < 14) return; + UcodeCmd_Scaling(pipe); + break; + } + + //UcodeCmd = 0; +} + +void GraphicsUcode::OnUcodeCmdFinish(u32 param) +{ + printf("finish cmd %d, param=%d, %d/%d\n", UcodeCmd, param, CmdWritten[2], ReplyWritten[2]); + UcodeCmd = 0; + SendReply(1, (u16)param); +} + +void GraphicsUcode::UcodeCmd_Scaling(u16* pipe) +{ + u16 params[14]; + ReadPipe(pipe, params, 14); + + u32 src_addr = (params[1] << 16) | params[0]; + u32 dst_addr = (params[3] << 16) | params[2]; + u16 filter = params[4]; + u16 src_width = params[5]; + u16 src_height = params[6]; + u16 width_scale = params[7]; + u16 height_scale = params[8]; + u16 rect_xoffset = params[9]; + u16 rect_yoffset = params[10]; + u16 rect_width = params[11]; + u16 rect_height = params[12]; + + u32 dst_width = (src_width * width_scale) / 1000; + u32 dst_height = (src_height * height_scale) / 1000; + + // TODO those are slightly different for bicubic + u32 x_factor = ((rect_width - 2) << 10) / (dst_width - 1); + u32 y_factor = ((rect_height - 2) << 10) / (dst_height - 1); + + // bound check + // CHECKME + //if (dst_width > rect_width) dst_width = rect_width; + //if (dst_height > rect_height) dst_height = rect_height; + // at 1700 it starts going out of bounds + + src_addr += (((rect_yoffset * src_width) + rect_xoffset) << 1); + + if (filter == 2) + { + // bilinear + + for (u32 y = 0; y < dst_height; y++) + { + u32 sy = (y * y_factor) + 0x200;// + 0x3FF; + u32 syf = sy & 0x3FF; + u32 src_line1 = src_addr + (((sy >> 10) * src_width) << 1); + u32 src_line2 = src_line1 + (src_width << 1); + + for (u32 x = 0; x < dst_width; x++) + { + u32 sx = (x * x_factor) + 0x200;// + 0x3FF; + u32 sxf = sx & 0x3FF; + + // TODO caching? see what the ucode does + // ucode loads enough lines to fill 32K buffer (16K dsp words) + // keeps last scanline from previous buffer + // uses 32bit DMA + // also starting pos is 0x200 (0.5), 0x600 for bicubic + u16 v[4]; + v[0] = DSi.ARM9Read16(src_line1 + ((sx >> 10) << 1)); + v[1] = DSi.ARM9Read16(src_line1 + ((sx >> 10) << 1) + 2); + v[2] = DSi.ARM9Read16(src_line2 + ((sx >> 10) << 1)); + v[3] = DSi.ARM9Read16(src_line2 + ((sx >> 10) << 1) + 2); + + u16 r[4], g[4], b[4]; + for (int i = 0; i < 4; i++) + { + r[i] = v[i] & 0x1F; + g[i] = (v[i] >> 5) & 0x1F; + b[i] = (v[i] >> 10) & 0x1F; + } + + u32 f_r, f_g, f_b; + u32 t1, t2; + + t1 = (r[0] * (0x400-sxf)) + (r[1] * sxf); + t2 = (r[2] * (0x400-sxf)) + (r[3] * sxf); + f_r = (t1 * (0x400-syf)) + (t2 * syf); + f_r = (f_r >> 20) & 0x1F; + + t1 = (g[0] * (0x400-sxf)) + (g[1] * sxf); + t2 = (g[2] * (0x400-sxf)) + (g[3] * sxf); + f_g = (t1 * (0x400-syf)) + (t2 * syf); + f_g = (f_g >> 15) & 0x3E0; + + t1 = (b[0] * (0x400-sxf)) + (b[1] * sxf); + t2 = (b[2] * (0x400-sxf)) + (b[3] * sxf); + f_b = (t1 * (0x400-syf)) + (t2 * syf); + f_b = (f_b >> 10) & 0x7C00; + + DSi.ARM9Write16(dst_addr, f_r | f_g | f_b | 0x8000); + + dst_addr += 2; + } + } + } + else if (filter == 3) + { + // bicubic + } + else + { + // nearest neighbor + + for (u32 y = 0; y < dst_height; y++) + { + u32 sy = ((y * y_factor) + 0x3FF) >> 10; + u32 src_line = src_addr + ((sy * src_width) << 1); + + for (u32 x = 0; x < dst_width; x++) + { + u32 sx = ((x * x_factor) + 0x3FF) >> 10; + + u16 v = DSi.ARM9Read16(src_line + (sx << 1)); + DSi.ARM9Write16(dst_addr, v); + + dst_addr += 2; + } + } + } + + // TODO the rest of the shit!! + + // TODO add a delay to this + // TODO make the delay realistic + //SendReply(1, 1); + DSi.ScheduleEvent(Event_DSi_DSPHLE, false, 600000, 0, 1); +} + + +} +} diff --git a/src/DSP_HLE/GraphicsUcode.h b/src/DSP_HLE/GraphicsUcode.h new file mode 100644 index 00000000..0c7031f3 --- /dev/null +++ b/src/DSP_HLE/GraphicsUcode.h @@ -0,0 +1,56 @@ +/* + Copyright 2016-2025 melonDS team + + This file is part of melonDS. + + melonDS 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 3 of the License, or (at your option) + any later version. + + melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef GRAPHICSUCODE_H +#define GRAPHICSUCODE_H + +#include + +#include "UcodeBase.h" +#include "../Savestate.h" + +namespace melonDS +{ +namespace DSP_HLE +{ + +class GraphicsUcode : public UcodeBase +{ +public: + GraphicsUcode(melonDS::DSi& dsi, int version); + ~GraphicsUcode(); + void Reset() override; + void DoSavestate(Savestate* file) override; + + typedef std::function fnReplyReadCb; + + //void SetRecvDataHandler(u8 index, std::function func); + //void SetSemaphoreHandler(std::function func); + + void SendData(u8 index, u16 val) override; + +protected: + void RunUcodeCmd(); + void OnUcodeCmdFinish(u32 param); + void UcodeCmd_Scaling(u16* pipe); +}; + +} +} + +#endif // GRAPHICSUCODE_H diff --git a/src/DSP_HLE/Ucode_Base.cpp b/src/DSP_HLE/UcodeBase.cpp similarity index 56% rename from src/DSP_HLE/Ucode_Base.cpp rename to src/DSP_HLE/UcodeBase.cpp index 402d8c46..4c789b45 100644 --- a/src/DSP_HLE/Ucode_Base.cpp +++ b/src/DSP_HLE/UcodeBase.cpp @@ -17,8 +17,7 @@ */ #include "../DSi.h" -#include "../DSi_DSP.h" -#include "Ucode_Base.h" +#include "UcodeBase.h" #include "../Platform.h" @@ -27,18 +26,21 @@ namespace melonDS using Platform::Log; using Platform::LogLevel; - -DSPHLE_UcodeBase::DSPHLE_UcodeBase(melonDS::DSi& dsi) : DSi(dsi) +namespace DSP_HLE { - DSi.RegisterEventFuncs(Event_DSi_DSPHLE, this, {MakeEventThunk(DSPHLE_UcodeBase, OnUcodeCmdFinish)}); + + +UcodeBase::UcodeBase(melonDS::DSi& dsi) : DSi(dsi) +{ + DSi.RegisterEventFuncs(Event_DSi_DSPHLE, this, {MakeEventThunk(UcodeBase, OnUcodeCmdFinish)}); } -DSPHLE_UcodeBase::~DSPHLE_UcodeBase() +UcodeBase::~UcodeBase() { // } -void DSPHLE_UcodeBase::Reset() +void UcodeBase::Reset() { DataMemory = nullptr; @@ -46,7 +48,6 @@ void DSPHLE_UcodeBase::Reset() memset(CmdWritten, 0, sizeof(CmdWritten)); memset(ReplyReg, 0, sizeof(ReplyReg)); memset(ReplyWritten, 0, sizeof(ReplyWritten)); - //memset(ReplyReadCb, 0, sizeof(ReplyReadCb)); ReplyReadCb[0] = nullptr; ReplyReadCb[1] = nullptr; ReplyReadCb[2] = nullptr; @@ -58,23 +59,23 @@ void DSPHLE_UcodeBase::Reset() UcodeCmd = 0; } -void DSPHLE_UcodeBase::DoSavestate(Savestate *file) +void UcodeBase::DoSavestate(Savestate *file) { - // + // TODO } -bool DSPHLE_UcodeBase::RecvDataIsReady(u8 index) +bool UcodeBase::RecvDataIsReady(u8 index) const { return ReplyWritten[index]; } -bool DSPHLE_UcodeBase::SendDataIsEmpty(u8 index) +bool UcodeBase::SendDataIsEmpty(u8 index) const { return !CmdWritten[index]; } -u16 DSPHLE_UcodeBase::RecvData(u8 index) +u16 UcodeBase::RecvData(u8 index) { if (!ReplyWritten[index]) printf("DSP: receive reply%d but empty\n", index); if (!ReplyWritten[index]) return 0; // CHECKME @@ -91,7 +92,7 @@ printf("DSP: receive reply%d %04X\n", index, ret); return ret; } -void DSPHLE_UcodeBase::SendData(u8 index, u16 val) +void UcodeBase::SendData(u8 index, u16 val) { // TODO less ambiguous naming for those functions if (CmdWritten[index]) @@ -104,35 +105,11 @@ void DSPHLE_UcodeBase::SendData(u8 index, u16 val) CmdWritten[index] = true; printf("DSP: send cmd%d %04X\n", index, val); - if (index == 0) - { - if (UcodeCmd) - { - printf("???? there is already a command pending\n"); - return; - } - - // writing to CMD0 initiates a ucode-specific command - // parameters are then written to pipe 7 - UcodeCmd = val; - CmdWritten[index] = false; - - RunUcodeCmd(); - } - else if (index == 2) - { - // CMD2 serves to notify that a pipe was written to - // value is the pipe index - - CmdWritten[index] = false; - - if (UcodeCmd) - RunUcodeCmd(); - } + // extra shit shall be implemented in subclasses } -void DSPHLE_UcodeBase::SendReply(u8 index, u16 val) +void UcodeBase::SendReply(u8 index, u16 val) { if (ReplyWritten[index]) { @@ -151,37 +128,43 @@ void DSPHLE_UcodeBase::SendReply(u8 index, u16 val) } } -void DSPHLE_UcodeBase::SetReplyReadCallback(u8 index, fnReplyReadCb callback) +void UcodeBase::SetReplyReadCallback(u8 index, fnReplyReadCb callback) { ReplyReadCb[index] = callback; } -u16 DSPHLE_UcodeBase::DMAChan0GetDstHigh() +u16 UcodeBase::DMAChan0GetSrcHigh() { // TODO? return 0; } -u16 DSPHLE_UcodeBase::AHBMGetDmaChannel(u16 index) +u16 UcodeBase::DMAChan0GetDstHigh() +{ + // TODO? + return 0; +} + +u16 UcodeBase::AHBMGetDmaChannel(u16 index) const { // return 0; } -u16 DSPHLE_UcodeBase::AHBMGetDirection(u16 index) +u16 UcodeBase::AHBMGetDirection(u16 index) const { // return 0; } -u16 DSPHLE_UcodeBase::AHBMGetUnitSize(u16 index) +u16 UcodeBase::AHBMGetUnitSize(u16 index) const { // return 0; } -u16 DSPHLE_UcodeBase::DataReadA32(u32 addr) +u16 UcodeBase::DataReadA32(u32 addr) const { printf("ucode: DataReadA32 %08X\n", addr); @@ -198,7 +181,7 @@ u16 DSPHLE_UcodeBase::DataReadA32(u32 addr) } } -void DSPHLE_UcodeBase::DataWriteA32(u32 addr, u16 val) +void UcodeBase::DataWriteA32(u32 addr, u16 val) { printf("ucode: DataWriteA32 %08X %04X\n", addr, val); @@ -215,71 +198,71 @@ void DSPHLE_UcodeBase::DataWriteA32(u32 addr, u16 val) } } -u16 DSPHLE_UcodeBase::MMIORead(u16 addr) +u16 UcodeBase::MMIORead(u16 addr) { // return 0; } -void DSPHLE_UcodeBase::MMIOWrite(u16 addr, u16 val) +void UcodeBase::MMIOWrite(u16 addr, u16 val) { // } -u16 DSPHLE_UcodeBase::ProgramRead(u32 addr) +u16 UcodeBase::ProgramRead(u32 addr) const { // return 0; } -void DSPHLE_UcodeBase::ProgramWrite(u32 addr, u16 val) +void UcodeBase::ProgramWrite(u32 addr, u16 val) { // } -u16 DSPHLE_UcodeBase::AHBMRead16(u32 addr) +u16 UcodeBase::AHBMRead16(u32 addr) { // return 0; } -u32 DSPHLE_UcodeBase::AHBMRead32(u32 addr) +u16 UcodeBase::AHBMRead32(u32 addr) { // return 0; } -void DSPHLE_UcodeBase::AHBMWrite16(u32 addr, u16 val) +void UcodeBase::AHBMWrite16(u32 addr, u16 val) { // } -void DSPHLE_UcodeBase::AHBMWrite32(u32 addr, u32 val) +void UcodeBase::AHBMWrite32(u32 addr, u32 val) { // } -u16 DSPHLE_UcodeBase::GetSemaphore() +u16 UcodeBase::GetSemaphore() const { return SemaphoreOut; } -void DSPHLE_UcodeBase::SetSemaphore(u16 val) +void UcodeBase::SetSemaphore(u16 val) { SemaphoreIn |= val; } -void DSPHLE_UcodeBase::ClearSemaphore(u16 val) +void UcodeBase::ClearSemaphore(u16 val) { SemaphoreOut &= ~val; } -void DSPHLE_UcodeBase::MaskSemaphore(u16 val) +void UcodeBase::MaskSemaphore(u16 val) { SemaphoreMask = val; } -void DSPHLE_UcodeBase::SetSemaphoreOut(u16 val) +void UcodeBase::SetSemaphoreOut(u16 val) { SemaphoreOut |= val; if (SemaphoreOut & (~SemaphoreMask)) @@ -287,7 +270,7 @@ void DSPHLE_UcodeBase::SetSemaphoreOut(u16 val) } -void DSPHLE_UcodeBase::Start() +void UcodeBase::Start() { printf("DSP HLE: start\n"); // TODO later: detect which ucode it is and create the right class! @@ -322,13 +305,7 @@ void DSPHLE_UcodeBase::Start() } -void DSPHLE_UcodeBase::Run(u32 cycles) -{ - // -} - - -u16* DSPHLE_UcodeBase::LoadPipe(u8 index) +u16* UcodeBase::LoadPipe(u8 index) { const u16 pipeaddr = 0x0800; u16* mem = (u16*)DSi.NWRAMMap_C[2][0]; @@ -337,7 +314,7 @@ u16* DSPHLE_UcodeBase::LoadPipe(u8 index) return pipe; } -u32 DSPHLE_UcodeBase::GetPipeLength(u16* pipe) +u32 UcodeBase::GetPipeLength(u16* pipe) { u32 ret; u16 rdptr = pipe[2]; @@ -356,7 +333,7 @@ u32 DSPHLE_UcodeBase::GetPipeLength(u16* pipe) return ret >> 1; } -u32 DSPHLE_UcodeBase::ReadPipe(u16* pipe, u16* data, u32 len) +u32 UcodeBase::ReadPipe(u16* pipe, u16* data, u32 len) { u16* mem = (u16*)DSi.NWRAMMap_C[2][0]; u16* pipebuf = &mem[pipe[0]]; @@ -380,86 +357,23 @@ printf("-> rd=%d\n", rdptr); return rdlen; } -void DSPHLE_UcodeBase::RunUcodeCmd() +void UcodeBase::RunUcodeCmd() { u16* pipe = LoadPipe(7); u32 len = GetPipeLength(pipe); printf("try to run ucode cmd: cmd=%d, len=%d\n", UcodeCmd, len); - switch (UcodeCmd) - { - case 1: // scaling - if (len < 14) return; - UcodeCmd_Scaling(pipe); - break; - } + // //UcodeCmd = 0; } -void DSPHLE_UcodeBase::OnUcodeCmdFinish(u32 param) +void UcodeBase::OnUcodeCmdFinish(u32 param) { printf("finish cmd %d, param=%d, %d/%d\n", UcodeCmd, param, CmdWritten[2], ReplyWritten[2]); UcodeCmd = 0; SendReply(1, (u16)param); } -void DSPHLE_UcodeBase::UcodeCmd_Scaling(u16* pipe) -{ - u16 params[14]; - ReadPipe(pipe, params, 14); - u32 src_addr = (params[1] << 16) | params[0]; - u32 dst_addr = (params[3] << 16) | params[2]; - u16 filter = params[4]; - u16 src_width = params[5]; - u16 src_height = params[6]; - u16 width_scale = params[7]; - u16 height_scale = params[8]; - u16 rect_xoffset = params[9]; - u16 rect_yoffset = params[10]; - u16 rect_width = params[11]; - u16 rect_height = params[12]; - - u32 dst_width = (src_width * width_scale) / 1000; - u32 dst_height = (src_height * height_scale) / 1000; - - // TODO those are slightly different for bicubic - u32 x_factor = ((rect_width - 2) << 10) / (dst_width - 1); - u32 y_factor = ((rect_height - 2) << 10) / (dst_height - 1); - - // bound check - // CHECKME - //if (dst_width > rect_width) dst_width = rect_width; - //if (dst_height > rect_height) dst_height = rect_height; - // at 1700 it starts going out of bounds - - src_addr += (((rect_yoffset * src_width) + rect_xoffset) << 1); -//printf("scale %08X -> %08X, %dx%d %dx%d %dx%d\n", src_addr, dst_addr, src_width, src_height, rect_width, rect_height, dst_width, dst_height); - for (u32 y = 0; y < dst_height; y++) - { - u32 sy = ((y * y_factor) + 0x3FF) >> 10; - u32 src_line = src_addr + ((sy * src_width) << 1); -//printf("line %d->%d %d %08X\n", y, sy, src_width, src_line); - for (u32 x = 0; x < dst_width; x++) - { - u32 sx = ((x * x_factor) + 0x3FF) >> 10; - - u16 v = DSi.ARM9Read16(src_line + (sx << 1)); - DSi.ARM9Write16(dst_addr, v); - //printf("%d,%d %08X -> %08X\n", y, x, src_line+(sx<<1),dst_addr); - dst_addr += 2; - } - - //src_addr += (src_width << 1); - } - - // TODO the rest of the shit!! - - // TODO add a delay to this - // TODO make the delay realistic - //SendReply(1, 1); - DSi.ScheduleEvent(Event_DSi_DSPHLE, false, 600000, 0, 1); } - - -} \ No newline at end of file +} diff --git a/src/DSP_HLE/Ucode_Base.h b/src/DSP_HLE/UcodeBase.h similarity index 70% rename from src/DSP_HLE/Ucode_Base.h rename to src/DSP_HLE/UcodeBase.h index 8c400ab3..7ada3bbe 100644 --- a/src/DSP_HLE/Ucode_Base.h +++ b/src/DSP_HLE/UcodeBase.h @@ -16,68 +16,58 @@ with melonDS. If not, see http://www.gnu.org/licenses/. */ -#ifndef UCODE_BASE_H -#define UCODE_BASE_H +#ifndef UCODEBASE_H +#define UCODEBASE_H #include -#include "../types.h" +#include "../DSi_DSP.h" #include "../Savestate.h" namespace melonDS { +namespace DSP_HLE +{ -class DSi; - -class DSPHLE_UcodeBase +class UcodeBase: public DSPInterface { public: - DSPHLE_UcodeBase(melonDS::DSi& dsi); - ~DSPHLE_UcodeBase(); - void Reset(); - void DoSavestate(Savestate* file); + UcodeBase(melonDS::DSi& dsi); + virtual ~UcodeBase(); + virtual void Reset(); + virtual void DoSavestate(Savestate* file); typedef std::function fnReplyReadCb; - //void SetRecvDataHandler(u8 index, std::function func); - //void SetSemaphoreHandler(std::function func); - - bool RecvDataIsReady(u8 index); - bool SendDataIsEmpty(u8 index); + bool RecvDataIsReady(u8 index) const; + bool SendDataIsEmpty(u8 index) const; u16 RecvData(u8 index); - void SendData(u8 index, u16 val); - - // TODO receive cmd - void SendReply(u8 index, u16 val); - void SetReplyReadCallback(u8 index, fnReplyReadCb callback); + virtual void SendData(u8 index, u16 val); + u16 DMAChan0GetSrcHigh(); u16 DMAChan0GetDstHigh(); - u16 AHBMGetDmaChannel(u16 index); - u16 AHBMGetDirection(u16 index); - u16 AHBMGetUnitSize(u16 index); + u16 AHBMGetDmaChannel(u16 index) const; + u16 AHBMGetDirection(u16 index) const; + u16 AHBMGetUnitSize(u16 index) const; - u16 DataReadA32(u32 addr); + u16 DataReadA32(u32 addr) const; void DataWriteA32(u32 addr, u16 val); u16 MMIORead(u16 addr); void MMIOWrite(u16 addr, u16 val); - u16 ProgramRead(u32 addr); + u16 ProgramRead(u32 addr) const; void ProgramWrite(u32 addr, u16 val); u16 AHBMRead16(u32 addr); - u32 AHBMRead32(u32 addr); + u16 AHBMRead32(u32 addr); void AHBMWrite16(u32 addr, u16 val); void AHBMWrite32(u32 addr, u32 val); - u16 GetSemaphore(); + u16 GetSemaphore() const; void SetSemaphore(u16 val); void ClearSemaphore(u16 val); void MaskSemaphore(u16 val); - void SetSemaphoreOut(u16 val); - void Start(); - void Run(u32 cycles); - protected: melonDS::DSi& DSi; u16* DataMemory; @@ -94,15 +84,20 @@ protected: u16 UcodeCmd; + void SendReply(u8 index, u16 val); + void SetReplyReadCallback(u8 index, fnReplyReadCb callback); + + void SetSemaphoreOut(u16 val); + u16* LoadPipe(u8 index); u32 GetPipeLength(u16* pipe); u32 ReadPipe(u16* pipe, u16* data, u32 len); void RunUcodeCmd(); void OnUcodeCmdFinish(u32 param); - void UcodeCmd_Scaling(u16* pipe); }; +} } -#endif // UCODE_BASE_H +#endif // UCODEBASE_H diff --git a/src/DSi_DSP.cpp b/src/DSi_DSP.cpp index bfb50fab..ad464157 100644 --- a/src/DSi_DSP.cpp +++ b/src/DSi_DSP.cpp @@ -17,7 +17,7 @@ */ #include "teakra/include/teakra/teakra.h" -#include "DSP_HLE/Ucode_Base.h" +#include "DSP_HLE/GraphicsUcode.h" #include "DSi.h" #include "DSi_DSP.h" @@ -34,6 +34,9 @@ using Platform::LogLevel; const u32 DSi_DSP::DataMemoryOffset = 0x20000; // from Teakra memory_interface.h // NOTE: ^ IS IN DSP WORDS, NOT IN BYTES! +// TODO add proper setting for this! +bool __temp_dsphle = true; + u16 DSi_DSP::GetPSTS() const { @@ -44,18 +47,15 @@ u16 DSi_DSP::GetPSTS() const if ( PDATAReadFifo.IsFull ()) r |= 1<<5; if (!PDATAReadFifo.IsEmpty()) r |=(1<<6)|(1<<0); - /*if (!TeakraCore->SendDataIsEmpty(0)) r |= 1<<13; - if (!TeakraCore->SendDataIsEmpty(1)) r |= 1<<14; - if (!TeakraCore->SendDataIsEmpty(2)) r |= 1<<15; - if ( TeakraCore->RecvDataIsReady(0)) r |= 1<<10; - if ( TeakraCore->RecvDataIsReady(1)) r |= 1<<11; - if ( TeakraCore->RecvDataIsReady(2)) r |= 1<<12;*/ - if (!HleCore->SendDataIsEmpty(0)) r |= 1<<13; - if (!HleCore->SendDataIsEmpty(1)) r |= 1<<14; - if (!HleCore->SendDataIsEmpty(2)) r |= 1<<15; - if ( HleCore->RecvDataIsReady(0)) r |= 1<<10; - if ( HleCore->RecvDataIsReady(1)) r |= 1<<11; - if ( HleCore->RecvDataIsReady(2)) r |= 1<<12; + if (DSPCore) + { + if (!DSPCore->SendDataIsEmpty(0)) r |= 1 << 13; + if (!DSPCore->SendDataIsEmpty(1)) r |= 1 << 14; + if (!DSPCore->SendDataIsEmpty(2)) r |= 1 << 15; + if (DSPCore->RecvDataIsReady(0)) r |= 1 << 10; + if (DSPCore->RecvDataIsReady(1)) r |= 1 << 11; + if (DSPCore->RecvDataIsReady(2)) r |= 1 << 12; + } //printf("GetPSTS: %04X\n", r); 8100 return r; } @@ -114,29 +114,64 @@ void DSi_DSP::AudioCb(std::array frame) // TODO } -DSi_DSP::DSi_DSP(melonDS::DSi& dsi) : DSi(dsi) + +void DSi_DSP::StartDSPHLE() { - DSi.RegisterEventFuncs(Event_DSi_DSP, this, {MakeEventThunk(DSi_DSP, DSPCatchUpU32)}); + // TODO + // check CRC32 of code + // fallback to Teakra if not found + printf("create HLE core\n"); - //TeakraCore = new Teakra::Teakra(); - HleCore = new DSPHLE_UcodeBase(DSi); - SCFG_RST = false; + u32 crc = 0; - // ???? - //if (!TeakraCore) return false; + // Hash NWRAM B, which contains the DSP program + // The hash should be in the DSP's memory view + for (u32 addr = 0; addr < 0x40000; addr += 0x8000) + { + const u8* ptr = DSi.NWRAMMap_B[2][(addr >> 15) & 0x7]; + crc = CRC32(ptr, 0x8000, crc); + } + + printf("CRC = %08X\n", crc); + + switch (crc) + { + case 0x63CAEC33: // Graphics SDK ucode v3 + DSPCore = new DSP_HLE::GraphicsUcode(DSi, 3); + break; + + default: + StartDSPLLE(); + break; + } + + if (DSPCore) + DSPCore->Reset(); +} + +void DSi_DSP::StopDSP() +{ + if (DSPCore) delete DSPCore; + DSPCore = nullptr; +} + +void DSi_DSP::StartDSPLLE() +{ + auto teakra = new Teakra::Teakra(); + DSPCore = teakra; using namespace std::placeholders; - /*TeakraCore->SetRecvDataHandler(0, std::bind(&DSi_DSP::IrqRep0, this)); - TeakraCore->SetRecvDataHandler(1, std::bind(&DSi_DSP::IrqRep1, this)); - TeakraCore->SetRecvDataHandler(2, std::bind(&DSi_DSP::IrqRep2, this)); + teakra->SetRecvDataHandler(0, std::bind(&DSi_DSP::IrqRep0, this)); + teakra->SetRecvDataHandler(1, std::bind(&DSi_DSP::IrqRep1, this)); + teakra->SetRecvDataHandler(2, std::bind(&DSi_DSP::IrqRep2, this)); - TeakraCore->SetSemaphoreHandler(std::bind(&DSi_DSP::IrqSem, this)); + teakra->SetSemaphoreHandler(std::bind(&DSi_DSP::IrqSem, this)); Teakra::SharedMemoryCallback smcb; smcb.read16 = std::bind(&DSi_DSP::DSPRead16, this, _1); smcb.write16 = std::bind(&DSi_DSP::DSPWrite16, this, _1, _2); - TeakraCore->SetSharedMemoryCallback(smcb); + teakra->SetSharedMemoryCallback(smcb); // these happen instantaneously and without too much regard for bus aribtration // rules, so, this might have to be changed later on @@ -147,9 +182,23 @@ DSi_DSP::DSi_DSP(melonDS::DSi& dsi) : DSi(dsi) cb.write16 = [this](auto addr, auto val) { DSi.ARM9Write16(addr, val); }; cb.read32 = [this](auto addr) { return DSi.ARM9Read32(addr); }; cb.write32 = [this](auto addr, auto val) { DSi.ARM9Write32(addr, val); }; - TeakraCore->SetAHBMCallback(cb); + teakra->SetAHBMCallback(cb); - TeakraCore->SetAudioCallback(std::bind(&DSi_DSP::AudioCb, this, _1));*/ + teakra->SetAudioCallback(std::bind(&DSi_DSP::AudioCb, this, _1)); +} + + +DSi_DSP::DSi_DSP(melonDS::DSi& dsi) : DSi(dsi) +{ + DSi.RegisterEventFuncs(Event_DSi_DSP, this, {MakeEventThunk(DSi_DSP, DSPCatchUpU32)}); + + DSPCore = nullptr; + SCFG_RST = false; + + if (!__temp_dsphle) + { + StartDSPLLE(); + } //PDATAReadFifo = new FIFO(16); //PDATAWriteFifo = new FIFO(16); @@ -158,13 +207,10 @@ DSi_DSP::DSi_DSP(melonDS::DSi& dsi) : DSi(dsi) DSi_DSP::~DSi_DSP() { //if (PDATAWriteFifo) delete PDATAWriteFifo; - //if (TeakraCore) delete TeakraCore; - if (HleCore) delete HleCore; + StopDSP(); //PDATAReadFifo = NULL; //PDATAWriteFifo = NULL; - //TeakraCore = NULL; - HleCore = nullptr; DSi.UnregisterEventFuncs(Event_DSi_DSP); } @@ -186,7 +232,7 @@ void DSi_DSP::Reset() PDATAReadFifo.Clear(); //PDATAWriteFifo->Clear(); //TeakraCore->Reset(); - HleCore->Reset(); + if (DSPCore) DSPCore->Reset(); DSi.CancelEvent(Event_DSi_DSP); @@ -248,58 +294,46 @@ void DSi_DSP::PDataDMAWrite(u16 wrval) { u32 addr = DSP_PADR; - switch (DSP_PCFG & (7<<12)) // memory region select + if (DSPCore) { - case 0<<12: // data - //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; - //TeakraCore->DataWriteA32(addr, wrval); - addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16; - HleCore->DataWriteA32(addr, wrval); - break; - case 1<<12: // mmio - //TeakraCore->MMIOWrite(addr & 0x7FF, wrval); - HleCore->MMIOWrite(addr & 0x7FF, wrval); - break; - case 5<<12: // program - //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; - //TeakraCore->ProgramWrite(addr, wrval); - addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16; - HleCore->ProgramWrite(addr, wrval); - break; - case 7<<12: -#if 0 - addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; - // only do stuff when AHBM is configured correctly - if (TeakraCore->AHBMGetDmaChannel(0) == 0 && TeakraCore->AHBMGetDirection(0) == 1/*W*/) + switch (DSP_PCFG & (7<<12)) // memory region select { - switch (TeakraCore->AHBMGetUnitSize(0)) + case 0<<12: // data + //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; + //TeakraCore->DataWriteA32(addr, wrval); + addr |= (u32)DSPCore->DMAChan0GetDstHigh() << 16; + DSPCore->DataWriteA32(addr, wrval); + break; + case 1<<12: // mmio + //TeakraCore->MMIOWrite(addr & 0x7FF, wrval); + DSPCore->MMIOWrite(addr & 0x7FF, wrval); + break; + case 5<<12: // program + //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; + //TeakraCore->ProgramWrite(addr, wrval); + addr |= (u32)DSPCore->DMAChan0GetDstHigh() << 16; + DSPCore->ProgramWrite(addr, wrval); + break; + case 7<<12: + addr |= (u32)DSPCore->DMAChan0GetDstHigh() << 16; + // only do stuff when AHBM is configured correctly + if (DSPCore->AHBMGetDmaChannel(0) == 0 && DSPCore->AHBMGetDirection(0) == 1/*W*/) { - case 0: /* 8bit */ DSi.ARM9Write8 (addr, (u8)wrval); break; - case 1: /* 16 b */ TeakraCore->AHBMWrite16(addr, wrval); break; - // does it work like this, or should it first buffer two u16's - // until it has enough data to write to the actual destination? - // -> this seems to be correct behavior! - case 2: /* 32 b */ TeakraCore->AHBMWrite32(addr, wrval); break; + switch (DSPCore->AHBMGetUnitSize(0)) + { + case 0: /* 8bit */ DSi.ARM9Write8 (addr, (u8)wrval); break; + case 1: /* 16 b */ DSPCore->AHBMWrite16(addr, wrval); break; + // does it work like this, or should it first buffer two u16's + // until it has enough data to write to the actual destination? + // -> this seems to be correct behavior! + case 2: /* 32 b */ DSPCore->AHBMWrite32(addr, wrval); break; + } } + break; + default: return; } -#endif - addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16; - // only do stuff when AHBM is configured correctly - if (HleCore->AHBMGetDmaChannel(0) == 0 && HleCore->AHBMGetDirection(0) == 1/*W*/) - { - switch (HleCore->AHBMGetUnitSize(0)) - { - case 0: /* 8bit */ DSi.ARM9Write8 (addr, (u8)wrval); break; - case 1: /* 16 b */ HleCore->AHBMWrite16(addr, wrval); break; - // does it work like this, or should it first buffer two u16's - // until it has enough data to write to the actual destination? - // -> this seems to be correct behavior! - case 2: /* 32 b */ HleCore->AHBMWrite32(addr, wrval); break; - } - } - break; - default: return; - }printf("DSP: PDATA write %08X -> %04X\n", addr, wrval); + } + printf("DSP: PDATA write %08X -> %04X\n", addr, wrval); if (DSP_PCFG & (1<<1)) // auto-increment ++DSP_PADR; // overflows and stays within a 64k 'page' // TODO: is this +1 or +2? @@ -311,52 +345,44 @@ u16 DSi_DSP::PDataDMARead() { u16 r = 0; u32 addr = DSP_PADR; - switch (DSP_PCFG & (7<<12)) // memory region select + + if (DSPCore) { - case 0<<12: // data - //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; - //r = TeakraCore->DataReadA32(addr); - addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16; - r = HleCore->DataReadA32(addr); - break; - case 1<<12: // mmio - //r = TeakraCore->MMIORead(addr & 0x7FF); - r = HleCore->MMIORead(addr & 0x7FF); - break; - case 5<<12: // program - //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; - //r = TeakraCore->ProgramRead(addr); - addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16; - r = HleCore->ProgramRead(addr); - break; - case 7<<12: -#if 0 - addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; - // only do stuff when AHBM is configured correctly - if (TeakraCore->AHBMGetDmaChannel(0) == 0 && TeakraCore->AHBMGetDirection(0) == 0/*R*/) + switch (DSP_PCFG & (7<<12)) // memory region select { - switch (TeakraCore->AHBMGetUnitSize(0)) + case 0<<12: // data + //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; + //r = TeakraCore->DataReadA32(addr); + addr |= (u32)DSPCore->DMAChan0GetDstHigh() << 16; + r = DSPCore->DataReadA32(addr); + break; + case 1<<12: // mmio + //r = TeakraCore->MMIORead(addr & 0x7FF); + r = DSPCore->MMIORead(addr & 0x7FF); + break; + case 5<<12: // program + //addr |= (u32)TeakraCore->DMAChan0GetDstHigh() << 16; + //r = TeakraCore->ProgramRead(addr); + addr |= (u32)DSPCore->DMAChan0GetDstHigh() << 16; + r = DSPCore->ProgramRead(addr); + break; + case 7<<12: + addr |= (u32)DSPCore->DMAChan0GetDstHigh() << 16; + // only do stuff when AHBM is configured correctly + if (DSPCore->AHBMGetDmaChannel(0) == 0 && DSPCore->AHBMGetDirection(0) == 0/*R*/) { - case 0: /* 8bit */ r = DSi.ARM9Read8 (addr); break; - case 1: /* 16 b */ r = TeakraCore->AHBMRead16(addr); break; - case 2: /* 32 b */ r = (u16)TeakraCore->AHBMRead32(addr); break; + switch (DSPCore->AHBMGetUnitSize(0)) + { + case 0: /* 8bit */ r = DSi.ARM9Read8 (addr); break; + case 1: /* 16 b */ r = DSPCore->AHBMRead16(addr); break; + case 2: /* 32 b */ r = (u16)DSPCore->AHBMRead32(addr); break; + } } + break; + default: return r; } -#endif - addr |= (u32)HleCore->DMAChan0GetDstHigh() << 16; - // only do stuff when AHBM is configured correctly - if (HleCore->AHBMGetDmaChannel(0) == 0 && HleCore->AHBMGetDirection(0) == 0/*R*/) - { - switch (HleCore->AHBMGetUnitSize(0)) - { - case 0: /* 8bit */ r = DSi.ARM9Read8 (addr); break; - case 1: /* 16 b */ r = HleCore->AHBMRead16(addr); break; - case 2: /* 32 b */ r = (u16)HleCore->AHBMRead32(addr); break; - } - } - break; - default: return r; - }printf("DSP: PDATA read %08X -> %04X (%04X)\n", addr, r, DSP_PCFG); + } + printf("DSP: PDATA read %08X -> %04X (%04X)\n", addr, r, DSP_PCFG); if (DSP_PCFG & (1<<1)) // auto-increment ++DSP_PADR; // overflows and stays within a 64k 'page' // TODO: is this +1 or +2? @@ -444,8 +470,12 @@ u8 DSi_DSP::Read8(u32 addr) // no DSP_PCLEAR read //case 0x1C: return TeakraCore->GetSemaphore() & 0xFF; // SEM //case 0x1D: return TeakraCore->GetSemaphore() >> 8; - case 0x1C: return HleCore->GetSemaphore() & 0xFF; // SEM - case 0x1D: return HleCore->GetSemaphore() >> 8; + case 0x1C: + if (!DSPCore) return 0; + return DSPCore->GetSemaphore() & 0xFF; // SEM + case 0x1D: + if (!DSPCore) return 0; + return DSPCore->GetSemaphore() >> 8; } return 0; @@ -468,8 +498,9 @@ u16 DSi_DSP::Read16(u32 addr) case 0x10: return DSP_PSEM; case 0x14: return DSP_PMASK; // no DSP_PCLEAR read - //case 0x1C: return TeakraCore->GetSemaphore(); // SEM - case 0x1C: return HleCore->GetSemaphore(); // SEM + case 0x1C: + if (!DSPCore) return 0; + return DSPCore->GetSemaphore(); // SEM case 0x20: return DSP_CMD[0]; case 0x28: return DSP_CMD[1]; @@ -477,20 +508,20 @@ u16 DSi_DSP::Read16(u32 addr) case 0x24: { - //u16 r = TeakraCore->RecvData(0);printf("DSP: read CMD0, %04X\n", r); - u16 r = HleCore->RecvData(0);printf("DSP: read CMD0, %04X\n", r); + if (!DSPCore) return 0; + u16 r = DSPCore->RecvData(0);printf("DSP: read CMD0, %04X\n", r); return r; } case 0x2C: { - //u16 r = TeakraCore->RecvData(1);printf("DSP: read CMD1, %04X\n", r); - u16 r = HleCore->RecvData(1);printf("DSP: read CMD1, %04X\n", r); + if (!DSPCore) return 0; + u16 r = DSPCore->RecvData(1);printf("DSP: read CMD1, %04X\n", r); return r; } case 0x34: { - //u16 r = TeakraCore->RecvData(2);printf("DSP: read CMD2, %04X\n", r); - u16 r = HleCore->RecvData(2);printf("DSP: read CMD2, %04X\n", r); + if (!DSPCore) return 0; + u16 r = DSPCore->RecvData(2);printf("DSP: read CMD2, %04X\n", r); return r; } } @@ -540,16 +571,18 @@ void DSi_DSP::Write16(u32 addr, u16 val) case 0x08: if ((DSP_PCFG & (1<<0)) && (!(val & (1<<0)))) - HleCore->Start(); - DSP_PCFG = val; - if (DSP_PCFG & (1<<0)) - //TeakraCore->Reset(); - HleCore->Reset(); - /*else if (!fazil) { - fazil = true; - DSi.debug(0); - }*/ + if (__temp_dsphle) + StartDSPHLE(); + } + else if ((!(DSP_PCFG & (1<<0))) && (val & (1<<0))) + { + if (__temp_dsphle) + StopDSP(); + else if (DSPCore) + DSPCore->Reset(); + } + DSP_PCFG = val; if (DSP_PCFG & (1<<4)) PDataDMAStart(); else @@ -558,38 +591,40 @@ void DSi_DSP::Write16(u32 addr, u16 val) // no PSTS writes case 0x10: DSP_PSEM = val; - //TeakraCore->SetSemaphore(val); - HleCore->SetSemaphore(val); + if (DSPCore) + DSPCore->SetSemaphore(val); break; case 0x14: DSP_PMASK = val; - //TeakraCore->MaskSemaphore(val); - HleCore->MaskSemaphore(val); + if (DSPCore) + DSPCore->MaskSemaphore(val); break; case 0x18: // PCLEAR - //TeakraCore->ClearSemaphore(val); - HleCore->ClearSemaphore(val); - //if (TeakraCore->GetSemaphore() == 0) - if (HleCore->GetSemaphore() == 0) + if (DSPCore) + { + DSPCore->ClearSemaphore(val); + if (DSPCore->GetSemaphore() == 0) + DSP_PSTS &= ~(1<<9); + } + else DSP_PSTS &= ~(1<<9); - break; // SEM not writable case 0x20: // CMD0 DSP_CMD[0] = val;printf("DSP: CMD0 = %04X\n", val); - //TeakraCore->SendData(0, val); - HleCore->SendData(0, val); + if (DSPCore) + DSPCore->SendData(0, val); break; case 0x28: // CMD1 DSP_CMD[1] = val;printf("DSP: CMD1 = %04X\n", val); - //TeakraCore->SendData(1, val); - HleCore->SendData(1, val); + if (DSPCore) + DSPCore->SendData(1, val); break; case 0x30: // CMD2 DSP_CMD[2] = val;printf("DSP: CMD2 = %04X\n", val); - //TeakraCore->SendData(2, val); - HleCore->SendData(2, val); + if (DSPCore) + DSPCore->SendData(2, val); break; // no REPx writes @@ -627,8 +662,8 @@ void DSi_DSP::Run(u32 cycles) return; } - //TeakraCore->Run(cycles); - HleCore->Run(cycles); + if (DSPCore) + DSPCore->Run(cycles); DSPTimestamp += cycles; diff --git a/src/DSi_DSP.h b/src/DSi_DSP.h index d7c8aa12..35b21f85 100644 --- a/src/DSi_DSP.h +++ b/src/DSi_DSP.h @@ -21,6 +21,7 @@ #include "types.h" #include "Savestate.h" +#include "FIFO.h" // TODO: for actual sound output // * audio callbacks @@ -29,8 +30,60 @@ namespace Teakra { class Teakra; } namespace melonDS { + class DSi; class DSPHLE_UcodeBase; + +class DSPInterface +{ +public: + virtual ~DSPInterface() {}; + + virtual void Reset() = 0; + virtual void DoSavestate(Savestate* file) = 0; + + // APBP Data + virtual bool SendDataIsEmpty(std::uint8_t index) const = 0; + virtual void SendData(std::uint8_t index, std::uint16_t value) = 0; + virtual bool RecvDataIsReady(std::uint8_t index) const = 0; + virtual std::uint16_t RecvData(std::uint8_t index) = 0; + //virtual std::uint16_t PeekRecvData(std::uint8_t index) = 0; + + // APBP Semaphore + virtual void SetSemaphore(std::uint16_t value) = 0; + virtual void ClearSemaphore(std::uint16_t value) = 0; + virtual void MaskSemaphore(std::uint16_t value) = 0; + virtual std::uint16_t GetSemaphore() const = 0; + + // for implementing DSP_PDATA/PADR DMA transfers + virtual std::uint16_t ProgramRead(std::uint32_t address) const = 0; + virtual void ProgramWrite(std::uint32_t address, std::uint16_t value) = 0; + //virtual std::uint16_t DataRead(std::uint16_t address, bool bypass_mmio = false) = 0; + //virtual void DataWrite(std::uint16_t address, std::uint16_t value, bool bypass_mmio = false) = 0; + virtual std::uint16_t DataReadA32(std::uint32_t address) const = 0; + virtual void DataWriteA32(std::uint32_t address, std::uint16_t value) = 0; + virtual std::uint16_t MMIORead(std::uint16_t address) = 0; + virtual void MMIOWrite(std::uint16_t address, std::uint16_t value) = 0; + + // DSP_PADR is only 16-bit, so this is where the DMA interface gets the + // upper 16-bits from + virtual std::uint16_t DMAChan0GetSrcHigh() = 0; + virtual std::uint16_t DMAChan0GetDstHigh() = 0; + + virtual std::uint16_t AHBMGetUnitSize(std::uint16_t i) const = 0; + virtual std::uint16_t AHBMGetDirection(std::uint16_t i) const = 0; + virtual std::uint16_t AHBMGetDmaChannel(std::uint16_t i) const = 0; + // we need these as AHBM does some weird stuff on unaligned accesses internally + virtual std::uint16_t AHBMRead16(std::uint32_t addr) = 0; + virtual void AHBMWrite16(std::uint32_t addr, std::uint16_t value) = 0; + virtual std::uint16_t AHBMRead32(std::uint32_t addr) = 0; + virtual void AHBMWrite32(std::uint32_t addr, std::uint32_t value) = 0; + + // core + virtual void Start() {}; + virtual void Run(unsigned cycle) {}; +}; + class DSi_DSP { public: @@ -39,6 +92,10 @@ public: void Reset(); void DoSavestate(Savestate* file); + void StartDSPLLE(); + void StartDSPHLE(); + void StopDSP(); + void DSPCatchUpU32(u32 _); // SCFG_RST bit0 @@ -74,8 +131,7 @@ private: // not sure whether to not rather put it somewhere else u16 SNDExCnt; - Teakra::Teakra* TeakraCore; - DSPHLE_UcodeBase* HleCore; + DSPInterface* DSPCore; bool SCFG_RST; diff --git a/src/teakra/include/teakra/teakra.h b/src/teakra/include/teakra/teakra.h index b0cbcf1e..42d6011d 100644 --- a/src/teakra/include/teakra/teakra.h +++ b/src/teakra/include/teakra/teakra.h @@ -5,6 +5,8 @@ #include #include +#include "../../../DSi_DSP.h" + namespace Teakra { struct SharedMemoryCallback { @@ -23,12 +25,13 @@ struct AHBMCallback { std::function write32; }; -class Teakra { +class Teakra : public melonDS::DSPInterface { public: Teakra(); ~Teakra(); void Reset(); + void DoSavestate(melonDS::Savestate* file); // APBP Data bool SendDataIsEmpty(std::uint8_t index) const; diff --git a/src/teakra/src/teakra.cpp b/src/teakra/src/teakra.cpp index fec900d7..d5bef22c 100644 --- a/src/teakra/src/teakra.cpp +++ b/src/teakra/src/teakra.cpp @@ -70,6 +70,10 @@ void Teakra::Reset() { impl->Reset(); } +void Teakra::DoSavestate(melonDS::Savestate* file) { + // TODO +} + void Teakra::Run(unsigned cycle) { impl->processor.Run(cycle); }