DSP: Remove all mentions of the mysterious DROM. Write protect the ROMs and IRAM as much as possible while loaded (to make sure they don't get corrupted by some memory overwrite or whatever). Make instruction reads stricter - iram and irom don't wrap anymore (not 100% sure about this one). Misc cleanup + changes.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2904 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
13ac45db1a
commit
0fd2edbf98
|
@ -22,10 +22,8 @@ void* AllocateExecutableMemory(size_t size, bool low = true);
|
|||
void* AllocateMemoryPages(size_t size);
|
||||
void FreeMemoryPages(void* ptr, size_t size);
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute);
|
||||
|
||||
|
||||
inline int GetPageSize() {return 4096;}
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
||||
|
||||
inline int GetPageSize() { return 4096; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,11 +54,18 @@ public:
|
|||
|
||||
virtual bool Open(u32 _CommandAddress, u32 _Mode)
|
||||
{
|
||||
ERROR_LOG(WII_IPC_SD, "STM: Open");
|
||||
ERROR_LOG(WII_IPC_SD, "STM immediate: Open");
|
||||
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Close(u32 _CommandAddress)
|
||||
{
|
||||
ERROR_LOG(WII_IPC_SD, "STM immediate: Close");
|
||||
Memory::Write_U32(0, _CommandAddress+4);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool IOCtl(u32 _CommandAddress)
|
||||
{
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress +0x0C);
|
||||
|
@ -141,6 +148,13 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool Close(u32 _CommandAddress)
|
||||
{
|
||||
INFO_LOG(WII_IPC_SD, "STM eventhook: Close");
|
||||
Memory::Write_U32(0, _CommandAddress+4);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool IOCtl(u32 _CommandAddress)
|
||||
{
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress +0x0C);
|
||||
|
|
|
@ -26,7 +26,6 @@ struct CConfig
|
|||
CConfig();
|
||||
|
||||
void Load();
|
||||
|
||||
void Save();
|
||||
};
|
||||
|
||||
|
|
|
@ -288,6 +288,7 @@ void srr(const UDSPInstruction& opc)
|
|||
u16 val = dsp_op_read_reg(sreg);
|
||||
dsp_dmem_write(g_dsp.r[dreg], val);
|
||||
}
|
||||
|
||||
// SRRD @$D, $S
|
||||
// 0001 1010 1dds ssss
|
||||
// Store value from source register $S to a memory location pointed by
|
||||
|
|
|
@ -114,6 +114,7 @@ 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);
|
||||
|
||||
// FIXME inside
|
||||
void rti(const UDSPInstruction& opc);
|
||||
|
@ -122,7 +123,6 @@ void srbith(const UDSPInstruction& opc);
|
|||
|
||||
void andfc(const UDSPInstruction& opc);
|
||||
void andf(const UDSPInstruction& opc);
|
||||
void cmpi(const UDSPInstruction& opc);
|
||||
void xori(const UDSPInstruction& opc);
|
||||
void andi(const UDSPInstruction& opc);
|
||||
void ori(const UDSPInstruction& opc);
|
||||
|
@ -130,11 +130,14 @@ void ori(const UDSPInstruction& opc);
|
|||
|
||||
// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED
|
||||
|
||||
// The mysterious a100
|
||||
|
||||
// END OF UNIMPLEMENTED
|
||||
|
||||
|
||||
// Helpers
|
||||
inline void tsta(int reg);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _DSPINTERPRETER_H
|
||||
|
|
|
@ -336,9 +336,27 @@ dspInstFunc opTable[OPTABLE_SIZE];
|
|||
dspInstFunc prologueTable[OPTABLE_SIZE];
|
||||
dspInstFunc epilogueTable[OPTABLE_SIZE];
|
||||
|
||||
const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst)
|
||||
{
|
||||
for (int 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 (u32 i = 0; i < OPTABLE_SIZE; i++)
|
||||
for (int i = 0; i < OPTABLE_SIZE; i++)
|
||||
{
|
||||
opTable[i] = DSPInterpreter::unknown;
|
||||
prologueTable[i] = NULL;
|
||||
|
@ -346,7 +364,7 @@ void InitInstructionTable()
|
|||
opSize[i] = 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < OPTABLE_SIZE; i++)
|
||||
for (int i = 0; i < OPTABLE_SIZE; i++)
|
||||
{
|
||||
for (u32 j = 0; j < opcodes_size; j++)
|
||||
{
|
||||
|
|
|
@ -118,4 +118,8 @@ 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
|
||||
|
|
|
@ -24,8 +24,10 @@
|
|||
====================================================================*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Thread.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
#include "gdsp_aram.h"
|
||||
#include "gdsp_interpreter.h"
|
||||
|
@ -163,11 +165,8 @@ void gdsp_ifx_write(u16 addr, u16 val)
|
|||
switch (addr & 0xff)
|
||||
{
|
||||
case 0xfb: // DIRQ
|
||||
|
||||
if (val & 0x1)
|
||||
{
|
||||
g_dsp.irq_request();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -246,13 +245,15 @@ u16 gdsp_ifx_read(u16 addr)
|
|||
|
||||
void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size)
|
||||
{
|
||||
u8* dst = ((u8*)g_dsp.iram);
|
||||
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);
|
||||
|
|
|
@ -31,34 +31,12 @@
|
|||
#include "gdsp_interface.h"
|
||||
#include "gdsp_opcodes_helper.h"
|
||||
#include "Tools.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
SDSP g_dsp;
|
||||
|
||||
u16 SDSP::r[32];
|
||||
u16 SDSP::pc = 0;
|
||||
u16 SDSP::err_pc = 0;
|
||||
u16* SDSP::iram = 0;
|
||||
u16* SDSP::dram = 0;
|
||||
u16* SDSP::irom = 0;
|
||||
u16* SDSP::drom = 0;
|
||||
u16* SDSP::coef = 0;
|
||||
u8* SDSP::cpu_ram = 0;
|
||||
u16 SDSP::cr = 0;
|
||||
u8 SDSP::reg_stack_ptr[4];
|
||||
u8 SDSP::exceptions;
|
||||
|
||||
// lets make stack depth to 32 for now
|
||||
u16 SDSP::reg_stack[4][DSP_STACK_DEPTH];
|
||||
void (*SDSP::irq_request)() = NULL;
|
||||
bool SDSP::exception_in_progress_hack = false; // should be replaced with bit9 in SR?
|
||||
|
||||
// for debugger only
|
||||
bool SDSP::dump_imem = true;
|
||||
u32 SDSP::iram_crc = 0;
|
||||
u64 SDSP::step_counter = 0;
|
||||
|
||||
bool gdsp_running;
|
||||
extern volatile u32 dsp_running;
|
||||
|
||||
|
@ -75,28 +53,17 @@ void UpdateCachedCR()
|
|||
|
||||
void gdsp_init()
|
||||
{
|
||||
// Why do we have DROM? Does it exist? Has it been dumped?
|
||||
g_dsp.irom = (u16*)malloc(DSP_IROM_SIZE * sizeof(u16));
|
||||
g_dsp.iram = (u16*)malloc(DSP_IRAM_SIZE * sizeof(u16));
|
||||
g_dsp.drom = (u16*)malloc(DSP_DROM_SIZE * sizeof(u16));
|
||||
g_dsp.dram = (u16*)malloc(DSP_DRAM_SIZE * sizeof(u16));
|
||||
g_dsp.coef = (u16*)malloc(DSP_COEF_SIZE * sizeof(u16));
|
||||
// Dump IMEM when ucodes get uploaded. Why not... still a plugin heavily in dev.
|
||||
g_dsp.dump_imem = true;
|
||||
|
||||
// Fill memories with junk.
|
||||
for (int i = 0; i < DSP_IRAM_SIZE; i++)
|
||||
{
|
||||
g_dsp.iram[i] = 0x0021; // HALT opcode
|
||||
}
|
||||
|
||||
for (int i = 0; i < DSP_DRAM_SIZE; i++)
|
||||
{
|
||||
g_dsp.dram[i] = 0x0021; // HALT opcode
|
||||
}
|
||||
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_SIZE * sizeof(u16));
|
||||
memset(g_dsp.drom, 0, DSP_DROM_SIZE * sizeof(u16));
|
||||
memset(g_dsp.coef, 0, DSP_COEF_SIZE * sizeof(u16));
|
||||
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++)
|
||||
{
|
||||
|
@ -113,6 +80,17 @@ void gdsp_init()
|
|||
}
|
||||
}
|
||||
|
||||
// Fill memories with junk.
|
||||
for (int i = 0; i < DSP_IRAM_SIZE; i++)
|
||||
{
|
||||
g_dsp.iram[i] = 0x0021; // HALT opcode
|
||||
}
|
||||
|
||||
for (int i = 0; i < DSP_DRAM_SIZE; i++)
|
||||
{
|
||||
g_dsp.dram[i] = 0x0021; // HALT opcode
|
||||
}
|
||||
|
||||
// copied from a real console after the custom UCode has been loaded
|
||||
g_dsp.r[0x08] = 0xffff;
|
||||
g_dsp.r[0x09] = 0xffff;
|
||||
|
@ -123,12 +101,23 @@ void gdsp_init()
|
|||
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);
|
||||
}
|
||||
|
||||
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_(0, "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;
|
||||
|
@ -140,11 +129,9 @@ void gdsp_generate_exception(u8 level)
|
|||
g_dsp.exceptions |= 1 << level;
|
||||
}
|
||||
|
||||
|
||||
bool gdsp_load_rom(const char *fname)
|
||||
bool gdsp_load_irom(const char *fname)
|
||||
{
|
||||
FILE *pFile = fopen(fname, "rb");
|
||||
|
||||
if (pFile)
|
||||
{
|
||||
size_t size_in_bytes = DSP_IROM_SIZE * sizeof(u16);
|
||||
|
@ -158,15 +145,14 @@ bool gdsp_load_rom(const char *fname)
|
|||
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);
|
||||
|
@ -180,7 +166,8 @@ bool gdsp_load_coef(const char *fname)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,55 +45,60 @@
|
|||
|
||||
#include "Globals.h"
|
||||
|
||||
// Are these in bytes or 16-bit words? Probably 16-bit words.
|
||||
#define DSP_IRAM_SIZE (0x1000)
|
||||
#define DSP_IRAM_MASK (0x0fff)
|
||||
#define DSP_IROM_SIZE (0x1000)
|
||||
#define DSP_IROM_MASK (0x0fff)
|
||||
#define DSP_DRAM_SIZE (0x1000)
|
||||
#define DSP_DRAM_MASK (0x0fff)
|
||||
#define DSP_DROM_SIZE (0x1000)
|
||||
#define DSP_DROM_MASK (0x0fff)
|
||||
#define DSP_COEF_SIZE (0x1000)
|
||||
#define DSP_COEF_MASK (0x0fff)
|
||||
#define DSP_IRAM_BYTE_SIZE 0x2000
|
||||
#define DSP_IRAM_SIZE 0x1000
|
||||
#define DSP_IRAM_MASK 0x0fff
|
||||
|
||||
#define DSP_RESET_VECTOR (0x8000)
|
||||
#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
|
||||
{
|
||||
static u16 r[32];
|
||||
static u16 pc;
|
||||
static u16 err_pc;
|
||||
static u16* iram;
|
||||
static u16* dram;
|
||||
static u16* irom;
|
||||
static u16* drom;
|
||||
static u16* coef;
|
||||
static u8* cpu_ram;
|
||||
static u16 cr;
|
||||
static u8 reg_stack_ptr[4];
|
||||
static u8 exceptions; // pending exceptiosn?
|
||||
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
|
||||
static u16 reg_stack[4][DSP_STACK_DEPTH];
|
||||
static void (* irq_request)(void);
|
||||
u16 reg_stack[4][DSP_STACK_DEPTH];
|
||||
void (* irq_request)(void);
|
||||
|
||||
// for debugger only
|
||||
static bool dump_imem;
|
||||
static u32 iram_crc;
|
||||
static u64 step_counter;
|
||||
static bool exception_in_progress_hack;
|
||||
bool dump_imem;
|
||||
u32 iram_crc;
|
||||
u64 step_counter;
|
||||
bool exception_in_progress_hack;
|
||||
};
|
||||
|
||||
extern SDSP g_dsp;
|
||||
|
||||
|
||||
void gdsp_init(void);
|
||||
void gdsp_reset(void);
|
||||
bool gdsp_load_rom(const char *fname);
|
||||
void gdsp_init();
|
||||
void gdsp_reset();
|
||||
void gdsp_shutdown();
|
||||
|
||||
bool gdsp_load_irom(const char *fname);
|
||||
bool gdsp_load_coef(const char *fname);
|
||||
|
||||
|
||||
|
|
|
@ -37,15 +37,22 @@ u16 dsp_swap16(u16 x)
|
|||
|
||||
u16 dsp_imem_read(u16 addr)
|
||||
{
|
||||
if (g_dsp.pc & 0x8000)
|
||||
return dsp_swap16(g_dsp.irom[addr & DSP_IROM_MASK]);
|
||||
else
|
||||
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) {
|
||||
switch (addr >> 12)
|
||||
{
|
||||
case 0x0: // 0xxx DRAM
|
||||
return dsp_swap16(g_dsp.dram[addr & DSP_DRAM_MASK]);
|
||||
|
||||
|
@ -58,10 +65,6 @@ u16 dsp_dmem_read(u16 addr)
|
|||
case 0x4:
|
||||
break;*/
|
||||
|
||||
case 0x8: // 8xxx DROM
|
||||
ERROR_LOG(DSPLLE, "someone reads from ROM");
|
||||
return dsp_swap16(g_dsp.drom[addr & DSP_DROM_MASK]);
|
||||
|
||||
case 0xf: // Fxxx HW regs
|
||||
return gdsp_ifx_read(addr);
|
||||
|
||||
|
@ -84,12 +87,6 @@ void dsp_dmem_write(u16 addr, u16 val)
|
|||
ERROR_LOG(DSPLLE, "someone writes to COEF");
|
||||
break;
|
||||
|
||||
case 0x8: // 8xxx DROM
|
||||
ERROR_LOG(DSPLLE, "someone writes to DROM");
|
||||
/* val = dsp_swap16(val);
|
||||
g_dsp.drom[addr & DSP_DROM_MASK] = val;*/
|
||||
break;
|
||||
|
||||
case 0xf: // Fxxx HW regs
|
||||
gdsp_ifx_write(addr, val);
|
||||
break;
|
||||
|
|
|
@ -231,14 +231,17 @@ void Initialize(void *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_rom(DSP_IROM_FILE)) {
|
||||
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)) {
|
||||
if (!gdsp_load_coef(DSP_COEF_FILE))
|
||||
{
|
||||
bCanWork = false;
|
||||
PanicAlert("Failed loading DSP COEF from " DSP_COEF_FILE);
|
||||
}
|
||||
|
@ -248,10 +251,10 @@ void Initialize(void *init)
|
|||
|
||||
bIsRunning = true;
|
||||
|
||||
InitInstructionTable();
|
||||
|
||||
g_hDSPThread = new Common::Thread(dsp_thread, NULL);
|
||||
soundStream = AudioCommon::InitSoundStream();
|
||||
|
||||
InitInstructionTable();
|
||||
}
|
||||
|
||||
void DSP_StopSoundStream()
|
||||
|
@ -262,9 +265,10 @@ void DSP_StopSoundStream()
|
|||
g_hDSPThread = NULL;
|
||||
}
|
||||
|
||||
void Shutdown(void)
|
||||
void Shutdown()
|
||||
{
|
||||
AudioCommon::ShutdownSoundStream();
|
||||
gdsp_shutdown();
|
||||
}
|
||||
|
||||
u16 DSP_WriteControlRegister(u16 _uFlag)
|
||||
|
|
Loading…
Reference in New Issue