start SPU work

This commit is contained in:
StapleButter 2017-04-06 19:44:34 +02:00
parent 28cddadfbc
commit 8d66beba6b
6 changed files with 335 additions and 85 deletions

View File

@ -25,6 +25,7 @@
#include "DMA.h"
#include "FIFO.h"
#include "GPU.h"
#include "SPU.h"
#include "SPI.h"
#include "RTC.h"
#include "Wifi.h"
@ -37,11 +38,6 @@ namespace NDS
// * stick all the variables in a big structure?
// would make it easier to deal with savestates
/*SchedEvent SchedBuffer[SCHED_BUF_LEN];
SchedEvent* SchedQueue;
bool NeedReschedule;*/
ARM* ARM9;
ARM* ARM7;
@ -108,8 +104,6 @@ u32 SqrtRes;
u32 KeyInput;
u16 _soundbias; // temp
bool Running;
@ -132,6 +126,7 @@ bool Init()
if (!NDSCart::Init()) return false;
if (!GPU::Init()) return false;
if (!SPU::Init()) return false;
if (!SPI::Init()) return false;
if (!RTC::Init()) return false;
@ -151,6 +146,7 @@ void DeInit()
NDSCart::DeInit();
GPU::DeInit();
SPU::DeInit();
SPI::DeInit();
RTC::DeInit();
}
@ -300,14 +296,6 @@ void Reset()
for (i = 0; i < 8; i++) DMAs[i]->Reset();
memset(DMA9Fill, 0, 4*4);
NDSCart::Reset();
GPU::Reset();
SPI::Reset();
RTC::Reset();
Wifi::Reset();
// memset(SchedBuffer, 0, sizeof(SchedEvent)*SCHED_BUF_LEN);
// SchedQueue = NULL;
memset(SchedList, 0, sizeof(SchedList));
SchedListMask = 0;
@ -319,7 +307,12 @@ void Reset()
KeyInput = 0x007F03FF;
_soundbias = 0;
NDSCart::Reset();
GPU::Reset();
SPU::Reset();
SPI::Reset();
RTC::Reset();
Wifi::Reset();
}
void LoadROM(const char* path, bool direct)
@ -1629,7 +1622,6 @@ void ARM9IOWrite16(u32 addr, u16 val)
{
SetIRQ(1, IRQ_IPCSync);
}
//CompensateARM7();
return;
case 0x04000184:
@ -1901,8 +1893,7 @@ u8 ARM7IORead8(u32 addr)
if (addr >= 0x04000400 && addr < 0x04000520)
{
// sound I/O
return 0;
return SPU::Read8(addr);
}
printf("unknown ARM7 IO read8 %08X\n", addr);
@ -1972,14 +1963,11 @@ u16 ARM7IORead16(u32 addr)
case 0x04000300: return PostFlag7;
case 0x04000304: return PowerControl7;
case 0x04000308: return ARM7BIOSProt;
case 0x04000504: return _soundbias;
}
if (addr >= 0x04000400 && addr < 0x04000520)
{
// sound I/O
return 0;
return SPU::Read16(addr);
}
printf("unknown ARM7 IO read16 %08X %08X\n", addr, ARM9->R[15]);
@ -2057,8 +2045,7 @@ u32 ARM7IORead32(u32 addr)
if (addr >= 0x04000400 && addr < 0x04000520)
{
// sound I/O
return 0;
return SPU::Read32(addr);
}
printf("unknown ARM7 IO read32 %08X\n", addr);
@ -2116,7 +2103,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
if (addr >= 0x04000400 && addr < 0x04000520)
{
// sound I/O
SPU::Write8(addr, val);
return;
}
@ -2228,15 +2215,11 @@ void ARM7IOWrite16(u32 addr, u16 val)
if (ARM7BIOSProt == 0)
ARM7BIOSProt = val;
return;
case 0x04000504: // removeme
_soundbias = val & 0x3FF;
return;
}
if (addr >= 0x04000400 && addr < 0x04000520)
{
// sound I/O
SPU::Write16(addr, val);
return;
}
@ -2326,7 +2309,7 @@ void ARM7IOWrite32(u32 addr, u32 val)
if (addr >= 0x04000400 && addr < 0x04000520)
{
// sound I/O
SPU::Write32(addr, val);
return;
}

View File

@ -24,30 +24,11 @@
namespace NDS
{
/*#define SCHED_BUF_LEN 64
typedef struct _SchedEvent
{
u32 Delay;
void (*Func)(u32);
u32 Param;
struct _SchedEvent* PrevEvent;
struct _SchedEvent* NextEvent;
} SchedEvent;*/
enum
{
Event_LCD = 0,
/*Event_Timer9_0,
Event_Timer9_1,
Event_Timer9_2,
Event_Timer9_3,
Event_Timer7_0,
Event_Timer7_1,
Event_Timer7_2,
Event_Timer7_3,*/
Event_SPU,
Event_MAX
};
@ -95,7 +76,6 @@ typedef struct
u16 Cnt;
u32 Counter;
u32 CycleShift;
//SchedEvent* Event;
} Timer;
@ -127,15 +107,9 @@ void ReleaseKey(u32 key);
void TouchScreen(u16 x, u16 y);
void ReleaseScreen();
/*SchedEvent* ScheduleEvent(s32 Delay, void (*Func)(u32), u32 Param);
void CancelEvent(SchedEvent* event);
void RunEvents(s32 cycles);*/
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
void CancelEvent(u32 id);
// DO NOT CALL FROM ARM7!!
void CompensateARM7();
void debug(u32 p);
void Halt();

View File

@ -25,38 +25,269 @@
namespace SPU
{
//SDL_AudioDeviceID device;
//
const u32 OutputBufferSize = 2*1024;
s16 OutputBuffer[2 * OutputBufferSize];
u32 OutputReadOffset;
u32 OutputWriteOffset;
u16 Cnt;
u8 MasterVolume;
u16 Bias;
Channel* Channels[16];
bool Init()
{
/*SDL_AudioSpec whatIwant, whatIget;
memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
whatIwant.freq = 32824; // 32823.6328125
whatIwant.format = AUDIO_S16LSB;
whatIwant.channels = 2;
whatIwant.samples = 2048;
whatIwant.callback = zorp;
device = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
if (!device)
{
printf("Audio init failed: %s\n", SDL_GetError());
return false;
}*/
for (int i = 0; i < 16; i++)
Channels[i] = new Channel(i);
return true;
}
void DeInit()
{
//if (device) SDL_CloseAudioDevice(device);
for (int i = 0; i < 16; i++)
delete Channels[i];
}
void Reset()
{
memset(OutputBuffer, 0, 2*OutputBufferSize*2);
OutputReadOffset = 0;
OutputWriteOffset = 0;
Cnt = 0;
MasterVolume = 0;
Bias = 0;
for (int i = 0; i < 16; i++)
Channels[i]->Reset();
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16);
}
Channel::Channel(u32 num)
{
//
}
Channel::~Channel()
{
//
}
void Channel::Reset()
{
SetCnt(0);
SrcAddr = 0;
TimerReload = 0;
LoopPos = 0;
Length = 0;
}
void Mix(u32 samples)
{
//
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16);
}
void ReadOutput(s16* data, int samples)
{
for (int i = 0; i < samples; i++)
{
*data++ = OutputBuffer[OutputReadOffset];
*data++ = OutputBuffer[OutputReadOffset + 1];
if (OutputReadOffset != OutputWriteOffset)
{
OutputReadOffset += 2;
OutputReadOffset &= ((2*OutputBufferSize)-1);
}
}
}
u8 Read8(u32 addr)
{
if (addr < 0x04000500)
{
Channel* chan = Channels[(addr >> 4) & 0xF];
switch (addr & 0xF)
{
case 0x0: return chan->Cnt & 0xFF;
case 0x1: return (chan->Cnt >> 8) & 0xFF;
case 0x2: return (chan->Cnt >> 16) & 0xFF;
case 0x3: return chan->Cnt >> 24;
}
}
else
{
switch (addr)
{
case 0x04000500: return Cnt & 0x7F;
case 0x04000501: return Cnt >> 8;
}
}
printf("unknown SPU read8 %08X\n", addr);
return 0;
}
u16 Read16(u32 addr)
{
if (addr < 0x04000500)
{
Channel* chan = Channels[(addr >> 4) & 0xF];
switch (addr & 0xF)
{
case 0x0: return chan->Cnt & 0xFFFF;
case 0x2: return chan->Cnt >> 16;
}
}
else
{
switch (addr)
{
case 0x04000500: return Cnt;
case 0x04000504: return Bias;
}
}
printf("unknown SPU read16 %08X\n", addr);
return 0;
}
u32 Read32(u32 addr)
{
if (addr < 0x04000500)
{
Channel* chan = Channels[(addr >> 4) & 0xF];
switch (addr & 0xF)
{
case 0x0: return chan->Cnt;
}
}
else
{
switch (addr)
{
case 0x04000500: return Cnt;
case 0x04000504: return Bias;
}
}
printf("unknown SPU read32 %08X\n", addr);
return 0;
}
void Write8(u32 addr, u8 val)
{
if (addr < 0x04000500)
{
Channel* chan = Channels[(addr >> 4) & 0xF];
switch (addr & 0xF)
{
case 0x0: chan->SetCnt((chan->Cnt & 0xFFFFFF00) | val); return;
case 0x1: chan->SetCnt((chan->Cnt & 0xFFFF00FF) | (val << 8)); return;
case 0x2: chan->SetCnt((chan->Cnt & 0xFF00FFFF) | (val << 16)); return;
case 0x3: chan->SetCnt((chan->Cnt & 0x00FFFFFF) | (val << 24)); return;
}
}
else
{
switch (addr)
{
case 0x04000500:
Cnt = (Cnt & 0xBF00) | (val & 0x7F);
MasterVolume = Cnt & 0x7F;
if (MasterVolume == 127) MasterVolume++;
return;
case 0x04000501:
Cnt = (Cnt & 0x007F) | ((val & 0xBF) << 8);
return;
}
}
printf("unknown SPU write8 %08X %02X\n", addr, val);
}
void Write16(u32 addr, u16 val)
{
if (addr < 0x04000500)
{
Channel* chan = Channels[(addr >> 4) & 0xF];
switch (addr & 0xF)
{
case 0x0: chan->SetCnt((chan->Cnt & 0xFFFF0000) | val); return;
case 0x2: chan->SetCnt((chan->Cnt & 0x0000FFFF) | (val << 16)); return;
case 0x8: chan->SetTimerReload(val); return;
case 0xA: chan->SetLoopPos(val); return;
}
}
else
{
switch (addr)
{
case 0x04000500:
Cnt = val & 0xBF7F;
MasterVolume = Cnt & 0x7F;
if (MasterVolume == 127) MasterVolume++;
return;
case 0x04000504:
Bias = val & 0x3FF;
return;
}
}
printf("unknown SPU write16 %08X %04X\n", addr, val);
}
void Write32(u32 addr, u32 val)
{
if (addr < 0x04000500)
{
Channel* chan = Channels[(addr >> 4) & 0xF];
switch (addr & 0xF)
{
case 0x0: chan->SetCnt(val); return;
case 0x4: chan->SetSrcAddr(val); return;
case 0x8:
chan->SetTimerReload(val & 0xFFFF);
chan->SetLoopPos(val >> 16);
return;
case 0xC: chan->SetLength(val); return;
}
}
else
{
switch (addr)
{
case 0x04000500:
Cnt = val & 0xBF7F;
MasterVolume = Cnt & 0x7F;
if (MasterVolume == 127) MasterVolume++;
return;
case 0x04000504:
Bias = val & 0x3FF;
return;
}
}
printf("unknown SPU write32 %08X %08X\n", addr, val);
}
}

View File

@ -26,6 +26,41 @@ bool Init();
void DeInit();
void Reset();
void Mix(u32 samples);
void ReadOutput(s16* data, int samples);
u8 Read8(u32 addr);
u16 Read16(u32 addr);
u32 Read32(u32 addr);
void Write8(u32 addr, u8 val);
void Write16(u32 addr, u16 val);
void Write32(u32 addr, u32 val);
class Channel
{
public:
Channel(u32 num);
~Channel();
void Reset();
u32 Cnt;
u32 SrcAddr;
u16 TimerReload;
u32 LoopPos;
u32 Length;
void SetCnt(u32 val)
{
Cnt = val & 0xFF7F837F;
}
void SetSrcAddr(u32 val) { SrcAddr = val & 0x07FFFFFF; }
void SetTimerReload(u32 val) { TimerReload = val & 0xFFFF; }
void SetLoopPos(u32 val) { LoopPos = (val & 0xFFFF) << 2; }
void SetLength(u32 val) { Length = (val & 0x001FFFFF) << 2; }
};
}
#endif // SPU_H

View File

@ -22,6 +22,7 @@
#include "../Config.h"
#include "../NDS.h"
#include "../GPU.h"
#include "../SPU.h"
#include "InputConfig.h"
#include "EmuConfig.h"
@ -86,7 +87,7 @@ bool wxApp_melonDS::OnInit()
printf("melonDS " MELONDS_VERSION "\n" MELONDS_URL "\n");
Config::Load();
emuthread = new EmuThread();
if (emuthread->Run() != wxTHREAD_NO_ERROR)
{
@ -97,7 +98,7 @@ bool wxApp_melonDS::OnInit()
MainFrame* melon = new MainFrame();
melon->Show(true);
melon->emuthread = emuthread;
emuthread->parent = melon;
@ -108,7 +109,7 @@ int wxApp_melonDS::OnExit()
{
emuthread->Wait();
delete emuthread;
return wxApp::OnExit();
}
@ -169,7 +170,7 @@ void MainFrame::OnClose(wxCloseEvent& event)
{
emuthread->EmuPause();
emuthread->EmuExit();
NDS::DeInit();
if (joy)
@ -313,6 +314,11 @@ EmuThread::~EmuThread()
{
}
static void AudioCallback(void* data, Uint8* stream, int len)
{
SPU::ReadOutput((s16*)stream, len>>2);
}
wxThread::ExitCode EmuThread::Entry()
{
emustatus = 3;
@ -344,6 +350,23 @@ wxThread::ExitCode EmuThread::Entry()
botdst.x = 0; botdst.y = 192;
botdst.w = 256; botdst.h = 192;
SDL_AudioSpec whatIwant, whatIget;
memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
whatIwant.freq = 32824; // 32823.6328125
whatIwant.format = AUDIO_S16LSB;
whatIwant.channels = 2;
whatIwant.samples = 1024;
whatIwant.callback = AudioCallback;
audio = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
if (!audio)
{
printf("Audio init failed: %s\n", SDL_GetError());
}
else
{
SDL_PauseAudioDevice(audio, 0);
}
Touching = false;
axismask = 0;
@ -430,9 +453,11 @@ wxThread::ExitCode EmuThread::Entry()
emupaused = true;
}
}
emupaused = true;
if (audio) SDL_CloseAudioDevice(audio);
SDL_DestroyTexture(sdltex);
SDL_DestroyRenderer(sdlrend);
SDL_DestroyWindow(sdlwin);
@ -462,7 +487,7 @@ void EmuThread::ProcessEvents()
{
int w = evt.window.data1;
int h = evt.window.data2;
// SDL_SetWindowMinimumSize() doesn't seem to work on Linux. oh well
if ((w < 256) || (h < 384))
{
@ -514,7 +539,7 @@ void EmuThread::ProcessEvents()
{
Touching = true;
NDS::PressKey(16+6);
int mx, my;
SDL_GetGlobalMouseState(&mx, &my);
txoffset = mx - evt.button.x;

View File

@ -46,7 +46,7 @@ class wxApp_melonDS : public wxApp
public:
virtual bool OnInit();
virtual int OnExit();
EmuThread* emuthread;
};
@ -91,7 +91,7 @@ public:
bool EmuIsRunning() { return (emustatus == 1) || (emustatus == 2); }
bool EmuIsPaused() { return (emustatus == 2) && emupaused; }
MainFrame* parent;
protected:
@ -105,6 +105,8 @@ protected:
SDL_Rect topsrc, topdst;
SDL_Rect botsrc, botdst;
SDL_AudioDeviceID audio;
bool Touching;
int txoffset, tyoffset;