Replaced lazyusf2 with more compatible lazyusf1, and updated its timing code significantly.
parent
8859e9a83c
commit
88079f6041
|
@ -29,17 +29,20 @@
|
|||
83CA15F01A988138005E7ED4 /* musyx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15151A988138005E7ED4 /* musyx.c */; };
|
||||
83CA15F11A988138005E7ED4 /* plugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 83CA15161A988138005E7ED4 /* plugin.c */; };
|
||||
83CA15F21A988138005E7ED4 /* ucodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CA15171A988138005E7ED4 /* ucodes.h */; };
|
||||
83DA153920F6F28E0096D348 /* preproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DA153820F6F28E0096D348 /* preproc.h */; };
|
||||
83DA153E20F6F2A70096D348 /* dbg_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DA153A20F6F2A70096D348 /* dbg_types.h */; };
|
||||
83DA153F20F6F2A70096D348 /* dbg_decoder_local.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DA153B20F6F2A70096D348 /* dbg_decoder_local.h */; };
|
||||
83DA154020F6F2A70096D348 /* dbg_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83DA153C20F6F2A70096D348 /* dbg_decoder.c */; };
|
||||
83DA154120F6F2A70096D348 /* dbg_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DA153D20F6F2A70096D348 /* dbg_decoder.h */; };
|
||||
83E1578920F6E2D500BAA65A /* audio.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E1578820F6E2D500BAA65A /* audio.h */; };
|
||||
83E1578C20F6E2E000BAA65A /* interpreter_cpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E1578A20F6E2E000BAA65A /* interpreter_cpu.h */; };
|
||||
83E1578D20F6E2E000BAA65A /* pif.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E1578B20F6E2E000BAA65A /* pif.h */; };
|
||||
83E1578F20F6E32B00BAA65A /* lazyusf-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 83E1578E20F6E32B00BAA65A /* lazyusf-Info.plist */; };
|
||||
83E1579220F6E33900BAA65A /* preproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E1579120F6E33800BAA65A /* preproc.h */; };
|
||||
83E1579520F6E3A000BAA65A /* our-stdbool.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E1579420F6E39F00BAA65A /* our-stdbool.h */; };
|
||||
83E1579620F6E3F100BAA65A /* audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 835E768C20F6E2BD008F45E7 /* audio.c */; };
|
||||
83E1579720F6E3F500BAA65A /* audiolib.c in Sources */ = {isa = PBXBuildFile; fileRef = 8309DC5E20F6E24C0056CC70 /* audiolib.c */; };
|
||||
83E1579820F6E3F900BAA65A /* cpu_hle.c in Sources */ = {isa = PBXBuildFile; fileRef = 835E768420F6E2BC008F45E7 /* cpu_hle.c */; };
|
||||
83E1579920F6E3FD00BAA65A /* cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 835E768F20F6E2BD008F45E7 /* cpu.c */; };
|
||||
83E1579A20F6E40200BAA65A /* dbg_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8309DC6520F6E24C0056CC70 /* dbg_decoder.c */; };
|
||||
83E1579B20F6E40900BAA65A /* dma.c in Sources */ = {isa = PBXBuildFile; fileRef = 8309DC6A20F6E24D0056CC70 /* dma.c */; };
|
||||
83E1579C20F6E40C00BAA65A /* exception.c in Sources */ = {isa = PBXBuildFile; fileRef = 8309DC6320F6E24C0056CC70 /* exception.c */; };
|
||||
83E1579D20F6E41100BAA65A /* interpreter_cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 835E768620F6E2BC008F45E7 /* interpreter_cpu.c */; };
|
||||
|
@ -57,9 +60,6 @@
|
|||
83E157A920F6E5C600BAA65A /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 8309DC6220F6E24C0056CC70 /* config.h */; };
|
||||
83E157AA20F6E5CA00BAA65A /* cpu_hle.h in Headers */ = {isa = PBXBuildFile; fileRef = 835E768520F6E2BC008F45E7 /* cpu_hle.h */; };
|
||||
83E157AB20F6E5CE00BAA65A /* cpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 835E769420F6E2BE008F45E7 /* cpu.h */; };
|
||||
83E157AC20F6E5D300BAA65A /* dbg_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 8309DC6620F6E24C0056CC70 /* dbg_decoder.h */; };
|
||||
83E157AD20F6E5D700BAA65A /* dbg_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 8309DC6720F6E24C0056CC70 /* dbg_types.h */; };
|
||||
83E157AE20F6E5DA00BAA65A /* dbg_decoder_local.h in Headers */ = {isa = PBXBuildFile; fileRef = 8309DC6820F6E24C0056CC70 /* dbg_decoder_local.h */; };
|
||||
83E157AF20F6E5E000BAA65A /* dma.h in Headers */ = {isa = PBXBuildFile; fileRef = 835E768320F6E2BC008F45E7 /* dma.h */; };
|
||||
83E157B020F6E5E600BAA65A /* exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 835E768920F6E2BD008F45E7 /* exception.h */; };
|
||||
83E157B120F6E5EE00BAA65A /* interpreter_ops.h in Headers */ = {isa = PBXBuildFile; fileRef = 8309DC5D20F6E24B0056CC70 /* interpreter_ops.h */; };
|
||||
|
@ -135,10 +135,6 @@
|
|||
8309DC6120F6E24C0056CC70 /* registers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = registers.c; sourceTree = "<group>"; };
|
||||
8309DC6220F6E24C0056CC70 /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
|
||||
8309DC6320F6E24C0056CC70 /* exception.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = exception.c; sourceTree = "<group>"; };
|
||||
8309DC6520F6E24C0056CC70 /* dbg_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dbg_decoder.c; sourceTree = "<group>"; };
|
||||
8309DC6620F6E24C0056CC70 /* dbg_decoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbg_decoder.h; sourceTree = "<group>"; };
|
||||
8309DC6720F6E24C0056CC70 /* dbg_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbg_types.h; sourceTree = "<group>"; };
|
||||
8309DC6820F6E24C0056CC70 /* dbg_decoder_local.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbg_decoder_local.h; sourceTree = "<group>"; };
|
||||
8309DC6920F6E24C0056CC70 /* rsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rsp.h; sourceTree = "<group>"; };
|
||||
8309DC6A20F6E24D0056CC70 /* dma.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dma.c; sourceTree = "<group>"; };
|
||||
8309DC6B20F6E24D0056CC70 /* registers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = registers.h; sourceTree = "<group>"; };
|
||||
|
@ -242,11 +238,15 @@
|
|||
83CA15161A988138005E7ED4 /* plugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugin.c; sourceTree = "<group>"; };
|
||||
83CA15171A988138005E7ED4 /* ucodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucodes.h; sourceTree = "<group>"; };
|
||||
83CA16381A988191005E7ED4 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
83DA153820F6F28E0096D348 /* preproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preproc.h; sourceTree = "<group>"; };
|
||||
83DA153A20F6F2A70096D348 /* dbg_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_types.h; sourceTree = "<group>"; };
|
||||
83DA153B20F6F2A70096D348 /* dbg_decoder_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_decoder_local.h; sourceTree = "<group>"; };
|
||||
83DA153C20F6F2A70096D348 /* dbg_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dbg_decoder.c; sourceTree = "<group>"; };
|
||||
83DA153D20F6F2A70096D348 /* dbg_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_decoder.h; sourceTree = "<group>"; };
|
||||
83E1578820F6E2D500BAA65A /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = "<group>"; };
|
||||
83E1578A20F6E2E000BAA65A /* interpreter_cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interpreter_cpu.h; sourceTree = "<group>"; };
|
||||
83E1578B20F6E2E000BAA65A /* pif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pif.h; sourceTree = "<group>"; };
|
||||
83E1578E20F6E32B00BAA65A /* lazyusf-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "lazyusf-Info.plist"; sourceTree = "<group>"; };
|
||||
83E1579120F6E33800BAA65A /* preproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preproc.h; sourceTree = "<group>"; };
|
||||
83E1579420F6E39F00BAA65A /* our-stdbool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "our-stdbool.h"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -265,10 +265,10 @@
|
|||
8309DC6420F6E24C0056CC70 /* debugger */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8309DC6520F6E24C0056CC70 /* dbg_decoder.c */,
|
||||
8309DC6620F6E24C0056CC70 /* dbg_decoder.h */,
|
||||
8309DC6720F6E24C0056CC70 /* dbg_types.h */,
|
||||
8309DC6820F6E24C0056CC70 /* dbg_decoder_local.h */,
|
||||
83DA153B20F6F2A70096D348 /* dbg_decoder_local.h */,
|
||||
83DA153C20F6F2A70096D348 /* dbg_decoder.c */,
|
||||
83DA153D20F6F2A70096D348 /* dbg_decoder.h */,
|
||||
83DA153A20F6F2A70096D348 /* dbg_types.h */,
|
||||
);
|
||||
path = debugger;
|
||||
sourceTree = "<group>";
|
||||
|
@ -463,7 +463,7 @@
|
|||
83E1579020F6E33800BAA65A /* osal */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83E1579120F6E33800BAA65A /* preproc.h */,
|
||||
83DA153820F6F28E0096D348 /* preproc.h */,
|
||||
);
|
||||
path = osal;
|
||||
sourceTree = "<group>";
|
||||
|
@ -489,10 +489,8 @@
|
|||
83E157A920F6E5C600BAA65A /* config.h in Headers */,
|
||||
83E157AA20F6E5CA00BAA65A /* cpu_hle.h in Headers */,
|
||||
83E157AB20F6E5CE00BAA65A /* cpu.h in Headers */,
|
||||
83E157AC20F6E5D300BAA65A /* dbg_decoder.h in Headers */,
|
||||
83E157AD20F6E5D700BAA65A /* dbg_types.h in Headers */,
|
||||
83E157AE20F6E5DA00BAA65A /* dbg_decoder_local.h in Headers */,
|
||||
83E157AF20F6E5E000BAA65A /* dma.h in Headers */,
|
||||
83DA153F20F6F2A70096D348 /* dbg_decoder_local.h in Headers */,
|
||||
83E157B020F6E5E600BAA65A /* exception.h in Headers */,
|
||||
83E1578C20F6E2E000BAA65A /* interpreter_cpu.h in Headers */,
|
||||
83E157B120F6E5EE00BAA65A /* interpreter_ops.h in Headers */,
|
||||
|
@ -500,7 +498,6 @@
|
|||
83E157B320F6E5F500BAA65A /* memory.h in Headers */,
|
||||
83E157B420F6E5F800BAA65A /* opcode.h in Headers */,
|
||||
83E157B520F6E5FA00BAA65A /* os.h in Headers */,
|
||||
83E1579220F6E33900BAA65A /* preproc.h in Headers */,
|
||||
83E1578D20F6E2E000BAA65A /* pif.h in Headers */,
|
||||
83E157B620F6E60A00BAA65A /* registers.h in Headers */,
|
||||
83E157B720F6E61A00BAA65A /* resampler.h in Headers */,
|
||||
|
@ -517,6 +514,7 @@
|
|||
83E157C220F6E62900BAA65A /* vnand.h in Headers */,
|
||||
83E157C320F6E62900BAA65A /* vrsq.h in Headers */,
|
||||
83E157C420F6E62900BAA65A /* vnop.h in Headers */,
|
||||
83DA153E20F6F2A70096D348 /* dbg_types.h in Headers */,
|
||||
83E157C520F6E62900BAA65A /* vabs.h in Headers */,
|
||||
83E157C620F6E62900BAA65A /* vadd.h in Headers */,
|
||||
83E157C720F6E62900BAA65A /* vmacu.h in Headers */,
|
||||
|
@ -524,6 +522,7 @@
|
|||
83E157C920F6E62900BAA65A /* vsub.h in Headers */,
|
||||
83E157CA20F6E62900BAA65A /* vmudl.h in Headers */,
|
||||
83E157CB20F6E62900BAA65A /* vlt.h in Headers */,
|
||||
83DA153920F6F28E0096D348 /* preproc.h in Headers */,
|
||||
83E157CC20F6E62900BAA65A /* vmudh.h in Headers */,
|
||||
83E157CD20F6E62900BAA65A /* vge.h in Headers */,
|
||||
83E157CE20F6E62900BAA65A /* vmadl.h in Headers */,
|
||||
|
@ -569,6 +568,7 @@
|
|||
83E157EC20F6E67400BAA65A /* tlb.h in Headers */,
|
||||
83E157ED20F6E67700BAA65A /* types.h in Headers */,
|
||||
83E157EE20F6E67D00BAA65A /* usf_internal.h in Headers */,
|
||||
83DA154120F6F2A70096D348 /* dbg_decoder.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -645,7 +645,6 @@
|
|||
83E1579720F6E3F500BAA65A /* audiolib.c in Sources */,
|
||||
83E1579820F6E3F900BAA65A /* cpu_hle.c in Sources */,
|
||||
83E1579920F6E3FD00BAA65A /* cpu.c in Sources */,
|
||||
83E1579A20F6E40200BAA65A /* dbg_decoder.c in Sources */,
|
||||
83E1579B20F6E40900BAA65A /* dma.c in Sources */,
|
||||
83E1579C20F6E40C00BAA65A /* exception.c in Sources */,
|
||||
83E1579D20F6E41100BAA65A /* interpreter_cpu.c in Sources */,
|
||||
|
@ -668,6 +667,7 @@
|
|||
83CA15EC1A988138005E7ED4 /* memory.c in Sources */,
|
||||
83CA15EE1A988138005E7ED4 /* mp3.c in Sources */,
|
||||
83CA15F01A988138005E7ED4 /* musyx.c in Sources */,
|
||||
83DA154020F6F2A70096D348 /* dbg_decoder.c in Sources */,
|
||||
83CA15F11A988138005E7ED4 /* plugin.c in Sources */,
|
||||
83E157A620F6E47600BAA65A /* tlb.c in Sources */,
|
||||
83E157A720F6E47A00BAA65A /* usf.c in Sources */,
|
||||
|
|
|
@ -6,6 +6,29 @@
|
|||
|
||||
#include "usf_internal.h"
|
||||
|
||||
static const uint32_t AI_STATUS_BUSY = 0x40000000;
|
||||
static const uint32_t AI_STATUS_FULL = 0x80000000;
|
||||
|
||||
static uint32_t get_remaining_dma_length(usf_state_t *state)
|
||||
{
|
||||
unsigned int next_ai_event;
|
||||
unsigned int remaining_dma_duration;
|
||||
|
||||
if (state->fifo[0].duration == 0)
|
||||
return 0;
|
||||
|
||||
next_ai_event = state->Timers->NextTimer[AiTimer] + state->Timers->Timer;
|
||||
if (!state->Timers->Active[AiTimer])
|
||||
return 0;
|
||||
|
||||
remaining_dma_duration = next_ai_event;
|
||||
|
||||
if (remaining_dma_duration >= 0x80000000)
|
||||
return 0;
|
||||
|
||||
return (uint32_t)((uint64_t)remaining_dma_duration * state->fifo[0].length / state->fifo[0].duration);
|
||||
}
|
||||
|
||||
void AddBuffer(usf_state_t *state, unsigned char *buf, unsigned int length) {
|
||||
unsigned int i, do_max;
|
||||
int16_t * sample_buffer = state->sample_buffer;
|
||||
|
@ -48,42 +71,73 @@ void AddBuffer(usf_state_t *state, unsigned char *buf, unsigned int length) {
|
|||
}
|
||||
}
|
||||
|
||||
void AiLenChanged(usf_state_t * state) {
|
||||
int32_t length = 0;
|
||||
uint32_t address = (AI_DRAM_ADDR_REG & 0x00FFFFF8);
|
||||
|
||||
length = AI_LEN_REG & 0x3FFF8;
|
||||
static unsigned int get_dma_duration(usf_state_t *state)
|
||||
{
|
||||
unsigned int samples_per_sec = state->ROM_PARAMS.aidacrate / (1 + AI_DACRATE_REG);
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
fprintf(state->debug_log, "Audio DMA push: %d %d\n", AI_DRAM_ADDR_REG, length);
|
||||
#endif
|
||||
return (uint32_t)(((uint64_t)(AI_LEN_REG)*state->VI_INTR_TIME*state->ROM_PARAMS.vilimit)
|
||||
/ (4 * samples_per_sec));
|
||||
}
|
||||
|
||||
AddBuffer(state, state->RDRAM+address, length);
|
||||
void do_dma(usf_state_t * state, const struct ai_dma * dma) {
|
||||
AddBuffer(state, state->RDRAM + (dma->address & (state->RdramSize - 1) & ~3), dma->length);
|
||||
|
||||
if(length && !(AI_STATUS_REG&0x80000000)) {
|
||||
const float VSyncTiming = 789000.0f;
|
||||
double BytesPerSecond = 48681812.0 / (AI_DACRATE_REG + 1) * 4;
|
||||
double CountsPerSecond = (double)((((double)VSyncTiming) * (double)60.0)) * 2.0;
|
||||
double CountsPerByte = (double)CountsPerSecond / (double)BytesPerSecond;
|
||||
unsigned int IntScheduled = (unsigned int)((double)AI_LEN_REG * CountsPerByte);
|
||||
|
||||
ChangeTimer(state,AiTimer,IntScheduled);
|
||||
if(!(AI_STATUS_REG&AI_STATUS_FULL)) {
|
||||
if (state->enableFIFOfull) {
|
||||
ChangeTimer(state,AiTimer,dma->duration + state->Timers->Timer);
|
||||
}
|
||||
else {
|
||||
state->AudioIntrReg|=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(state->enableFIFOfull) {
|
||||
if(AI_STATUS_REG&0x40000000)
|
||||
AI_STATUS_REG|=0x80000000;
|
||||
}
|
||||
void AiQueueInt(usf_state_t *state) {
|
||||
ChangeTimer(state,AiTimer,state->enableFIFOfull ? get_dma_duration(state) + state->Timers->Timer : 0);
|
||||
}
|
||||
|
||||
AI_STATUS_REG|=0x40000000;
|
||||
void AiLenChanged(usf_state_t *state) {
|
||||
unsigned int duration = get_dma_duration(state);
|
||||
|
||||
if (AI_STATUS_REG & AI_STATUS_BUSY) {
|
||||
state->fifo[1].address = AI_DRAM_ADDR_REG;
|
||||
state->fifo[1].length = AI_LEN_REG;
|
||||
state->fifo[1].duration = duration;
|
||||
|
||||
if (state->enableFIFOfull)
|
||||
AI_STATUS_REG |= AI_STATUS_FULL;
|
||||
else
|
||||
do_dma(state, &state->fifo[1]);
|
||||
}
|
||||
else {
|
||||
state->fifo[0].address = AI_DRAM_ADDR_REG;
|
||||
state->fifo[0].length = AI_LEN_REG;
|
||||
state->fifo[0].duration = duration;
|
||||
AI_STATUS_REG |= AI_STATUS_BUSY;
|
||||
|
||||
do_dma(state, &state->fifo[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void AiTimerDone(usf_state_t *state) {
|
||||
if (AI_STATUS_REG & AI_STATUS_FULL) {
|
||||
state->fifo[0].address = state->fifo[1].address;
|
||||
state->fifo[0].length = state->fifo[1].length;
|
||||
state->fifo[0].duration = state->fifo[1].duration;
|
||||
AI_STATUS_REG &= ~AI_STATUS_FULL;
|
||||
|
||||
do_dma(state, &state->fifo[0]);
|
||||
}
|
||||
else {
|
||||
AI_STATUS_REG &= ~AI_STATUS_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int AiReadLength(usf_state_t * state) {
|
||||
AI_LEN_REG = 0;
|
||||
return AI_LEN_REG;
|
||||
return get_remaining_dma_length(state);
|
||||
}
|
||||
|
||||
void AiDacrateChanged(usf_state_t * state, unsigned int value) {
|
||||
AI_DACRATE_REG = value;
|
||||
state->SampleRate = 48681812 / (AI_DACRATE_REG + 1);
|
||||
state->SampleRate = (state->ROM_PARAMS.aidacrate) / (AI_DACRATE_REG + 1);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,17 @@
|
|||
#include "cpu.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct ai_dma
|
||||
{
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
unsigned int duration;
|
||||
};
|
||||
|
||||
uint32_t AiReadLength(usf_state_t *);
|
||||
void AiLenChanged(usf_state_t *);
|
||||
void AiDacrateChanged(usf_state_t *, uint32_t value);
|
||||
void AiTimerDone(usf_state_t *);
|
||||
void AiQueueInt(usf_state_t *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -466,18 +466,28 @@ void StartEmulationFromSave ( usf_state_t * state, void * savestate ) {
|
|||
init_rsp(state);
|
||||
|
||||
Machine_LoadStateFromRAM(state, savestate);
|
||||
|
||||
AI_STATUS_REG = 0;
|
||||
|
||||
((uint32_t *)(state->RDRAM))[0x300/4] = state->ROM_PARAMS.systemtype;
|
||||
|
||||
state->SampleRate = 48681812 / (AI_DACRATE_REG + 1);
|
||||
|
||||
state->SampleRate = (state->ROM_PARAMS.aidacrate) / (AI_DACRATE_REG + 1);
|
||||
|
||||
if(state->enableFIFOfull) {
|
||||
const float VSyncTiming = 789000.0f;
|
||||
double BytesPerSecond = 48681812.0 / (AI_DACRATE_REG + 1) * 4;
|
||||
double CountsPerSecond = (double)(((double)VSyncTiming) * (double)60.0);
|
||||
double CountsPerByte = (double)CountsPerSecond / (double)BytesPerSecond;
|
||||
uint32_t IntScheduled = (uint32_t)((double)AI_LEN_REG * CountsPerByte);
|
||||
|
||||
ChangeTimer(state,AiTimer,IntScheduled);
|
||||
AI_STATUS_REG|=0x40000000;
|
||||
if (VI_V_SYNC_REG == 0)
|
||||
{
|
||||
state->VI_INTR_TIME = 500000;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->VI_INTR_TIME = (VI_V_SYNC_REG + 1) * 1500;
|
||||
if ((VI_V_SYNC_REG & 1) != 0)
|
||||
{
|
||||
state->VI_INTR_TIME -= 38;
|
||||
}
|
||||
}
|
||||
AiQueueInt(state);
|
||||
AI_STATUS_REG |= 0x40000000;
|
||||
}
|
||||
|
||||
state->OLD_VI_V_SYNC_REG = ~VI_V_SYNC_REG;
|
||||
|
@ -594,10 +604,9 @@ void TimerDone (usf_state_t * state) {
|
|||
*state->WaitMode=0;
|
||||
break;
|
||||
case AiTimer:
|
||||
ChangeTimer(state,AiTimer,0);
|
||||
AI_STATUS_REG=0;
|
||||
AiTimerDone(state);
|
||||
state->AudioIntrReg|=4;
|
||||
//CheckInterrupts(state);
|
||||
CheckInterrupts(state);
|
||||
break;
|
||||
}
|
||||
CheckTimer(state);
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include "opcode.h"
|
||||
#include "usf.h"
|
||||
|
||||
#define COUNT_PER_OP_DEFAULT 2
|
||||
|
||||
typedef struct {
|
||||
int32_t DoSomething;
|
||||
int32_t CloseCPU;
|
||||
|
|
|
@ -0,0 +1,822 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus -- dbg_decoder.c *
|
||||
* Copyright (c) 2010 Marshall B. Rogers <mbr@64.vg> *
|
||||
* http://64.vg/ *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*
|
||||
* This is a heavily modified reentrant version of the MIPS disassembler found
|
||||
* in the NetBSD operating system. I chose to use this as a base due to the
|
||||
* small, compact, and easily manageable code.
|
||||
*
|
||||
* Original copyright/license information is contained below.
|
||||
*/
|
||||
|
||||
/* $NetBSD: db_disasm.c,v 1.21 2009/12/14 00:46:06 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ralph Campbell.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)kadb.c 8.1 (Berkeley) 6/10/93
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef MIPS32
|
||||
#define MIPS32
|
||||
#endif
|
||||
#include "dbg_decoder.h"
|
||||
#include "dbg_decoder_local.h"
|
||||
#include "osal/preproc.h"
|
||||
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Data types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
typedef uint32_t db_addr_t;
|
||||
|
||||
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Local variables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
static const char * const r4k_str_op_name[64] =
|
||||
{
|
||||
/* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz",
|
||||
/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui",
|
||||
/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl",
|
||||
/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37",
|
||||
/*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu",
|
||||
/*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache",
|
||||
/*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld",
|
||||
/*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd"
|
||||
};
|
||||
|
||||
static const char * const r4k_str_spec_name[64] =
|
||||
{
|
||||
/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav",
|
||||
/* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync",
|
||||
/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav",
|
||||
/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu",
|
||||
/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor",
|
||||
/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu",
|
||||
/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
|
||||
/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
|
||||
};
|
||||
|
||||
static const char * const r4k_str_spec2_name[4] = /* QED RM4650, R5000, etc. */
|
||||
{
|
||||
/* 0 */ "mad", "madu", "mul", "spec3"
|
||||
};
|
||||
|
||||
static const char * const r4k_str_bcond_name[32] =
|
||||
{
|
||||
/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
|
||||
/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
|
||||
/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
|
||||
/*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
|
||||
};
|
||||
|
||||
static const char * const r4k_str_cop1_name[64] =
|
||||
{
|
||||
/* 0 */ "add", "sub", "mul", "div", "sqrt","abs", "mov", "neg",
|
||||
/* 8 */ "fop08", "trunc.l","fop0a","fop0b","fop0c","trunc.w","fop0e","fop0f",
|
||||
/*16 */ "fop10", "fop11","fop12","fop13","fop14","fop15","fop16","fop17",
|
||||
/*24 */ "fop18", "fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
|
||||
/*32 */ "cvt.s", "cvt.d","fop22","fop23","cvt.w","cvt.l","fop26","fop27",
|
||||
/*40 */ "fop28", "fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
|
||||
/*48 */ "c.f", "c.un","c.eq","c.ueq","c.olt","c.ult",
|
||||
"c.ole", "c.ule",
|
||||
/*56 */ "c.sf", "c.ngle","c.seq","c.ngl","c.lt","c.nge",
|
||||
"c.le", "c.ngt"
|
||||
};
|
||||
|
||||
static const char * const r4k_str_fmt_name[16] =
|
||||
{
|
||||
|
||||
"s", "d", "e", "fmt3",
|
||||
"w", "l", "fmt6", "fmt7",
|
||||
"fmt8", "fmt9", "fmta", "fmtb",
|
||||
"fmtc", "fmtd", "fmte", "fmtf"
|
||||
};
|
||||
|
||||
|
||||
static const char * const r4k_str_reg_name[32] =
|
||||
{
|
||||
"$zero", "$at", "v0", "v1", "a0", "a1", "a2", "a3",
|
||||
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
|
||||
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"t8", "t9", "k0", "k1", "$gp", "$sp", "s8", "$ra"
|
||||
};
|
||||
|
||||
static const char * const r4k_str_c0_opname[64] =
|
||||
{
|
||||
"c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
|
||||
"tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
|
||||
"rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
|
||||
"eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
|
||||
"c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
|
||||
"c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
|
||||
"c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
|
||||
"c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
|
||||
};
|
||||
|
||||
static const char * const r4k_str_c0_reg[32] =
|
||||
{
|
||||
"C0_INX", "C0_RAND", "C0_ENTRYLO0", "C0_ENTRYLO1",
|
||||
"C0_CONTEXT", "C0_PAGEMASK", "C0_WIRED", "cp0r7",
|
||||
"C0_BADVADDR", "C0_COUNT", "C0_ENTRYHI", "C0_COMPARE",
|
||||
"C0_SR", "C0_CAUSE", "C0_EPC", "C0_PRID",
|
||||
"C0_CONFIG", "C0_LLADDR", "C0_WATCHLO", "C0_WATCHHI",
|
||||
"xcontext", "cp0r21", "cp0r22", "debug",
|
||||
"depc", "perfcnt", "C0_ECC", "C0_CACHE_ERR",
|
||||
"C0_TAGLO", "C0_TAGHI", "C0_ERROR_EPC", "desave"
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Local functions - lookup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/* Look up a symbol */
|
||||
static char *
|
||||
lookup_sym ( struct r4k_dis_t * state,
|
||||
uint32_t address )
|
||||
{
|
||||
if( state->lookup_sym )
|
||||
return state->lookup_sym( address, state->lookup_sym_d );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Look up an upper 16-bits relocation */
|
||||
static char *
|
||||
lookup_rel_hi16 ( struct r4k_dis_t * state,
|
||||
uint32_t address )
|
||||
{
|
||||
if( state->lookup_rel_hi16 )
|
||||
return state->lookup_rel_hi16( address, state->lookup_rel_hi16_d );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Look up a lower 16-bits relocation */
|
||||
static char *
|
||||
lookup_rel_lo16 ( struct r4k_dis_t * state,
|
||||
uint32_t address )
|
||||
{
|
||||
if( state->lookup_rel_lo16 )
|
||||
return state->lookup_rel_lo16( address, state->lookup_rel_lo16_d );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Local functions - disassembler
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/* Print text into the destination buffer */
|
||||
static int
|
||||
db_printf ( struct r4k_dis_t * state,
|
||||
char * fmt,
|
||||
... )
|
||||
{
|
||||
int l;
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
|
||||
|
||||
/* Prepare user provided */
|
||||
va_start( ap, fmt );
|
||||
l = vsnprintf( buffer, sizeof(buffer), fmt, ap );
|
||||
va_end( ap );
|
||||
|
||||
/* Add it to our string */
|
||||
state->dest += sprintf(
|
||||
state->dest,
|
||||
"%s",
|
||||
buffer
|
||||
);
|
||||
state->length += l;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
/* Print an address to a string. If there's a symbol, the name will be printed */
|
||||
static int
|
||||
print_addr ( struct r4k_dis_t * state,
|
||||
uint32_t address )
|
||||
{
|
||||
int len;
|
||||
char * sym;
|
||||
|
||||
|
||||
/* Try to lookup symbol */
|
||||
if( (sym = lookup_sym(state, address)) )
|
||||
{
|
||||
len = db_printf( state, "%s", sym );
|
||||
}
|
||||
else
|
||||
{
|
||||
len = db_printf( state, "0x%08X", address );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Disassemble an instruction */
|
||||
static db_addr_t
|
||||
db_disasm_insn ( struct r4k_dis_t * state,
|
||||
int insn,
|
||||
db_addr_t loc,
|
||||
bool altfmt )
|
||||
{
|
||||
char * rel;
|
||||
InstFmt i;
|
||||
|
||||
i.word = insn;
|
||||
|
||||
switch (i.JType.op) {
|
||||
case OP_SPECIAL:
|
||||
if (i.word == 0) {
|
||||
db_printf(state, "nop");
|
||||
break;
|
||||
}
|
||||
/* XXX
|
||||
* "addu" is a "move" only in 32-bit mode. What's the correct
|
||||
* answer - never decode addu/daddu as "move"?
|
||||
*/
|
||||
if (i.RType.func == OP_ADDU && i.RType.rt == 0) {
|
||||
db_printf(state, "%-16s%s,%s",
|
||||
"move",
|
||||
r4k_str_reg_name[i.RType.rd],
|
||||
r4k_str_reg_name[i.RType.rs]);
|
||||
break;
|
||||
}
|
||||
db_printf(state, "%-16s", r4k_str_spec_name[i.RType.func]);
|
||||
switch (i.RType.func) {
|
||||
case OP_SLL:
|
||||
case OP_SRL:
|
||||
case OP_SRA:
|
||||
case OP_DSLL:
|
||||
|
||||
case OP_DSRL:
|
||||
case OP_DSRA:
|
||||
case OP_DSLL32:
|
||||
case OP_DSRL32:
|
||||
case OP_DSRA32:
|
||||
db_printf(state, "%s,%s,%d",
|
||||
r4k_str_reg_name[i.RType.rd],
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.shamt);
|
||||
break;
|
||||
|
||||
case OP_SLLV:
|
||||
case OP_SRLV:
|
||||
case OP_SRAV:
|
||||
case OP_DSLLV:
|
||||
case OP_DSRLV:
|
||||
case OP_DSRAV:
|
||||
db_printf(state, "%s,%s,%s",
|
||||
r4k_str_reg_name[i.RType.rd],
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
r4k_str_reg_name[i.RType.rs]);
|
||||
break;
|
||||
|
||||
case OP_MFHI:
|
||||
case OP_MFLO:
|
||||
db_printf(state, "%s", r4k_str_reg_name[i.RType.rd]);
|
||||
break;
|
||||
|
||||
case OP_JR:
|
||||
case OP_JALR:
|
||||
db_printf(state, "%s", r4k_str_reg_name[i.RType.rs]);
|
||||
break;
|
||||
case OP_MTLO:
|
||||
case OP_MTHI:
|
||||
db_printf(state, "%s", r4k_str_reg_name[i.RType.rs]);
|
||||
break;
|
||||
|
||||
case OP_MULT:
|
||||
case OP_MULTU:
|
||||
case OP_DMULT:
|
||||
case OP_DMULTU:
|
||||
db_printf(state, "%s,%s",
|
||||
r4k_str_reg_name[i.RType.rs],
|
||||
r4k_str_reg_name[i.RType.rt]);
|
||||
break;
|
||||
|
||||
case OP_DIV:
|
||||
case OP_DIVU:
|
||||
case OP_DDIV:
|
||||
case OP_DDIVU:
|
||||
db_printf(state, "$zero,%s,%s",
|
||||
r4k_str_reg_name[i.RType.rs],
|
||||
r4k_str_reg_name[i.RType.rt]);
|
||||
break;
|
||||
|
||||
|
||||
case OP_SYSCALL:
|
||||
case OP_SYNC:
|
||||
break;
|
||||
|
||||
case OP_BREAK:
|
||||
db_printf(state, "%d", (i.RType.rs << 5) | i.RType.rt);
|
||||
break;
|
||||
|
||||
default:
|
||||
db_printf(state, "%s,%s,%s",
|
||||
r4k_str_reg_name[i.RType.rd],
|
||||
r4k_str_reg_name[i.RType.rs],
|
||||
r4k_str_reg_name[i.RType.rt]);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SPECIAL2:
|
||||
if (i.RType.func == OP_MUL)
|
||||
db_printf(state, "%s\t%s,%s,%s",
|
||||
r4k_str_spec2_name[i.RType.func & 0x3],
|
||||
r4k_str_reg_name[i.RType.rd],
|
||||
r4k_str_reg_name[i.RType.rs],
|
||||
r4k_str_reg_name[i.RType.rt]);
|
||||
else
|
||||
db_printf(state, "%s\t%s,%s",
|
||||
r4k_str_spec2_name[i.RType.func & 0x3],
|
||||
r4k_str_reg_name[i.RType.rs],
|
||||
r4k_str_reg_name[i.RType.rt]);
|
||||
|
||||
break;
|
||||
|
||||
case OP_BCOND:
|
||||
db_printf(state, "%-16s%s,", r4k_str_bcond_name[i.IType.rt],
|
||||
r4k_str_reg_name[i.IType.rs]);
|
||||
goto pr_displ;
|
||||
|
||||
case OP_BLEZ:
|
||||
case OP_BLEZL:
|
||||
case OP_BGTZ:
|
||||
case OP_BGTZL:
|
||||
db_printf(state, "%-16s%s,", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rs]);
|
||||
goto pr_displ;
|
||||
|
||||
case OP_BEQ:
|
||||
case OP_BEQL:
|
||||
if (i.IType.rs == 0 && i.IType.rt == 0) {
|
||||
db_printf(state, "%-16s", "b");
|
||||
goto pr_displ;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case OP_BNE:
|
||||
case OP_BNEL:
|
||||
db_printf(state, "%-16s%s,%s,", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rs],
|
||||
r4k_str_reg_name[i.IType.rt]);
|
||||
pr_displ:
|
||||
print_addr( state, loc + 4 + ((short)i.IType.imm << 2) );
|
||||
break;
|
||||
|
||||
case OP_COP0:
|
||||
switch (i.RType.rs) {
|
||||
case OP_BCx:
|
||||
case OP_BCy:
|
||||
|
||||
db_printf(state, "bc0%c\t",
|
||||
"ft"[i.RType.rt & COPz_BC_TF_MASK]);
|
||||
goto pr_displ;
|
||||
|
||||
case OP_MT:
|
||||
db_printf(state, "%-16s%s,%s",
|
||||
"mtc0",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
r4k_str_c0_reg[i.RType.rd]);
|
||||
break;
|
||||
|
||||
case OP_DMT:
|
||||
db_printf(state, "%-16s%s,%s",
|
||||
"dmtc0",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
r4k_str_c0_reg[i.RType.rd]);
|
||||
break;
|
||||
|
||||
case OP_MF:
|
||||
db_printf(state, "%-16s%s,%s", "mfc0",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
r4k_str_c0_reg[i.RType.rd]);
|
||||
break;
|
||||
|
||||
case OP_DMF:
|
||||
db_printf(state, "%-16s%s,%s","dmfc0",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
r4k_str_c0_reg[i.RType.rd]);
|
||||
break;
|
||||
|
||||
default:
|
||||
db_printf(state, "%s", r4k_str_c0_opname[i.FRType.func]);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_COP1:
|
||||
switch (i.RType.rs) {
|
||||
case OP_BCx:
|
||||
case OP_BCy:
|
||||
db_printf(state, "bc1%c%s\t\t",
|
||||
"ft"[i.RType.rt & COPz_BC_TF_MASK],
|
||||
(insn >> 16 & 0x1F) == 2 || (insn >> 16 & 0x1F) == 3 ? "l" : "");
|
||||
goto pr_displ;
|
||||
|
||||
case OP_MT:
|
||||
db_printf(state, "mtc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_MF:
|
||||
db_printf(state, "mfc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_CT:
|
||||
db_printf(state, "ctc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_CF:
|
||||
db_printf(state, "cfc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_DMT:
|
||||
db_printf(state, "dmtc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_DMF:
|
||||
db_printf(state, "dmfc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_MTH:
|
||||
db_printf(state, "mthc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
case OP_MFH:
|
||||
db_printf(state, "mfhc1\t\t%s,$f%d",
|
||||
r4k_str_reg_name[i.RType.rt],
|
||||
i.RType.rd);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
|
||||
if( i.FRType.func == 0x21 || i.FRType.func == 0x20 || i.FRType.func == 0x24 || i.FRType.func == 0x25 ||
|
||||
i.FRType.func == 7 || i.FRType.func == 6 || i.FRType.func == 0xd ||
|
||||
i.FRType.func == 4 || i.FRType.func == 5 || i.FRType.func == 9 )
|
||||
{/*NEG.fmt fd, fs*/
|
||||
|
||||
db_printf(state, "%s.%s\t\t$f%d,$f%d",
|
||||
r4k_str_cop1_name[i.FRType.func],
|
||||
r4k_str_fmt_name[i.FRType.fmt],
|
||||
i.FRType.fd, i.FRType.fs);
|
||||
}
|
||||
else if( i.FRType.func != 1 && i.FRType.func != 2 && (insn & 0x3F) && !(insn >> 6 & 0x1F) ) /* C */
|
||||
{
|
||||
db_printf(state, "%s.%s\t\t$f%d,$f%d",
|
||||
r4k_str_cop1_name[i.FRType.func],
|
||||
r4k_str_fmt_name[i.FRType.fmt],
|
||||
i.FRType.fs, i.FRType.ft);
|
||||
}
|
||||
else
|
||||
{
|
||||
db_printf(state, "%s.%s\t\t$f%d,$f%d,$f%d",
|
||||
r4k_str_cop1_name[i.FRType.func],
|
||||
r4k_str_fmt_name[i.FRType.fmt],
|
||||
i.FRType.fd, i.FRType.fs, i.FRType.ft);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_J:
|
||||
case OP_JAL:
|
||||
db_printf(state, "%-16s", r4k_str_op_name[i.JType.op]);
|
||||
print_addr(state, (loc & 0xF0000000) | (i.JType.target << 2));
|
||||
break;
|
||||
|
||||
case OP_LDC1:
|
||||
case OP_LWC1:
|
||||
case OP_SWC1:
|
||||
case OP_SDC1:
|
||||
db_printf(state, "%-16s$f%d,", r4k_str_op_name[i.IType.op],
|
||||
i.IType.rt);
|
||||
goto loadstore;
|
||||
|
||||
case OP_LB:
|
||||
case OP_LH:
|
||||
case OP_LW:
|
||||
case OP_LWL:
|
||||
case OP_LWR:
|
||||
case OP_LD:
|
||||
case OP_LBU:
|
||||
case OP_LHU:
|
||||
case OP_LWU:
|
||||
case OP_SB:
|
||||
case OP_SH:
|
||||
case OP_SW:
|
||||
case OP_SWL:
|
||||
case OP_SWR:
|
||||
case OP_SD:
|
||||
db_printf(state, "%-16s%s,", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt]);
|
||||
loadstore:
|
||||
|
||||
/* Part of a relocation? */
|
||||
if( (rel = lookup_rel_lo16(state, loc)) )
|
||||
{
|
||||
/* Yes. */
|
||||
db_printf(state,
|
||||
"%%lo(%s)(%s)",
|
||||
rel,
|
||||
r4k_str_reg_name[i.IType.rs]
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
db_printf(state, "%d(%s)", (short)i.IType.imm,
|
||||
r4k_str_reg_name[i.IType.rs]);
|
||||
break;
|
||||
|
||||
case OP_ORI:
|
||||
case OP_XORI:
|
||||
if( i.IType.op == OP_ORI )
|
||||
{
|
||||
/* Part of a relocation? */
|
||||
if( (rel = lookup_rel_lo16(state, loc)) )
|
||||
{
|
||||
/* Yes. */
|
||||
db_printf(state,
|
||||
"%-16s%s,%s,%%lo(%s)",
|
||||
r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
r4k_str_reg_name[i.IType.rs],
|
||||
rel
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
db_printf(state, "%-16s%s,%s,0x%x", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
r4k_str_reg_name[i.IType.rs],
|
||||
i.IType.imm);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (i.IType.rs == 0) {
|
||||
db_printf(state, "%-16s%s,0x%x",
|
||||
"li",
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
i.IType.imm);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case OP_ANDI:
|
||||
db_printf(state, "%-16s%s,%s,0x%x", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
r4k_str_reg_name[i.IType.rs],
|
||||
i.IType.imm);
|
||||
break;
|
||||
|
||||
case OP_LUI:
|
||||
{
|
||||
/* Part of a relocation? */
|
||||
if( (rel = lookup_rel_hi16(state, loc)) )
|
||||
{
|
||||
/* Yes. */
|
||||
db_printf(state,
|
||||
"%-16s%s,%%hi(%s)",
|
||||
r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
rel
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
db_printf(state, "%-16s%s,0x%x", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
i.IType.imm);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_CACHE:
|
||||
db_printf(state, "%-16s0x%x,0x%x(%s)",
|
||||
r4k_str_op_name[i.IType.op],
|
||||
i.IType.rt,
|
||||
i.IType.imm,
|
||||
r4k_str_reg_name[i.IType.rs]);
|
||||
break;
|
||||
|
||||
case OP_ADDI:
|
||||
case OP_DADDI:
|
||||
case OP_ADDIU:
|
||||
case OP_DADDIU:
|
||||
{
|
||||
|
||||
/* Part of a relocation? */
|
||||
if( (rel = lookup_rel_lo16(state, loc)) )
|
||||
{
|
||||
/* Yes. */
|
||||
db_printf(state,
|
||||
"%-16s%s,%s,%%lo(%s)",
|
||||
r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
r4k_str_reg_name[i.IType.rs],
|
||||
rel
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i.IType.rs == 0) {
|
||||
db_printf(state, "%-16s%s,%d", "li",
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
(short)i.IType.imm);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
|
||||
default:
|
||||
|
||||
db_printf(state, "%-16s%s,%s,%d", r4k_str_op_name[i.IType.op],
|
||||
r4k_str_reg_name[i.IType.rt],
|
||||
r4k_str_reg_name[i.IType.rs],
|
||||
(short)i.IType.imm);
|
||||
} }
|
||||
/*db_printf(state, "\n");*/
|
||||
|
||||
return (loc + 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Global functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/* Disassemble an instruction with state */
|
||||
static int
|
||||
r4k_disassemble ( struct r4k_dis_t * state,
|
||||
uint32_t instruction,
|
||||
uint32_t location,
|
||||
char * dest )
|
||||
{
|
||||
state->dest = dest;
|
||||
db_disasm_insn( state, instruction, location, 0 );
|
||||
|
||||
return state->length;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Disassemble an instruction but split the opcode/operands into two char *'s */
|
||||
static int
|
||||
r4k_disassemble_split ( struct r4k_dis_t * state,
|
||||
uint32_t instruction,
|
||||
uint32_t location,
|
||||
char ** opcode,
|
||||
char ** operands )
|
||||
{
|
||||
int v, i;
|
||||
char buff[128], * dupd;
|
||||
|
||||
v = r4k_disassemble(
|
||||
state,
|
||||
instruction,
|
||||
location,
|
||||
buff
|
||||
);
|
||||
|
||||
dupd = strdup( buff );
|
||||
*opcode = &dupd[0];
|
||||
|
||||
for( i = 0; buff[i] && buff[i] != ' '; i++ );
|
||||
|
||||
dupd[i] = '\0';
|
||||
|
||||
for( ; buff[i] && buff[i] == ' '; i++ );
|
||||
|
||||
*operands = &dupd[i];
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Disassemble an instruction with a blank state but split op/operands */
|
||||
static int
|
||||
r4k_disassemble_split_quick ( uint32_t instruction,
|
||||
uint32_t location,
|
||||
char ** opcode,
|
||||
char ** operands )
|
||||
{
|
||||
struct r4k_dis_t state;
|
||||
|
||||
/* Init state */
|
||||
memset( &state, 0, sizeof(state) );
|
||||
|
||||
/* Perform */
|
||||
return r4k_disassemble_split(
|
||||
&state,
|
||||
instruction,
|
||||
location,
|
||||
opcode,
|
||||
operands
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ DECODE_OP ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[//
|
||||
|
||||
void r4300_decode_op ( uint32 instr, char * opcode, char * arguments, int counter )
|
||||
{
|
||||
char * _op, * _args;
|
||||
|
||||
_op = NULL;
|
||||
_args = NULL;
|
||||
|
||||
r4k_disassemble_split_quick(
|
||||
instr,
|
||||
counter,
|
||||
&_op,
|
||||
&_args
|
||||
);
|
||||
|
||||
strcpy( opcode, _op );
|
||||
strcpy( arguments, _args );
|
||||
|
||||
free( _op );
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - dbg_decoder.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2010 Marshall B. Rogers <mbr@64.vg> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef __DECODER_H__
|
||||
#define __DECODER_H__
|
||||
|
||||
#include "dbg_types.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned char bool;
|
||||
#define false 0
|
||||
#define true 1
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
/* Disassembler lookup handler */
|
||||
typedef char * (*r4k_lookup_func)(uint32_t, void *);
|
||||
|
||||
/* Disassembler state */
|
||||
typedef
|
||||
struct r4k_dis_t
|
||||
{
|
||||
r4k_lookup_func lookup_sym;
|
||||
void * lookup_sym_d;
|
||||
r4k_lookup_func lookup_rel_hi16;
|
||||
void * lookup_rel_hi16_d;
|
||||
r4k_lookup_func lookup_rel_lo16;
|
||||
void * lookup_rel_lo16_d;
|
||||
|
||||
/* Private */
|
||||
char * dest;
|
||||
int length;
|
||||
}
|
||||
R4kDis;
|
||||
|
||||
extern void r4300_decode_op ( uint32, char *, char *, int );
|
||||
|
||||
|
||||
#endif /* __DECODER_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - dbg_types.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2002 davFr *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
#endif /* __TYPES_H__ */
|
||||
|
|
@ -727,7 +727,7 @@ void ExecuteInterpreterOpCode (usf_state_t * state) {
|
|||
}
|
||||
#endif
|
||||
|
||||
COUNT_REGISTER += 2;
|
||||
COUNT_REGISTER += state->ROM_PARAMS.countperop;
|
||||
state->Timers->Timer -= 2;
|
||||
|
||||
RANDOM_REGISTER -= 1;
|
||||
|
|
|
@ -711,8 +711,7 @@ int32_t r4300i_SW_NonMemory ( usf_state_t * state, uint32_t PAddr, uint32_t Valu
|
|||
CheckInterrupts(state);
|
||||
break;
|
||||
case 0x04500010:
|
||||
AI_DACRATE_REG = Value;
|
||||
//if (AiDacrateChanged != NULL) { AiDacrateChanged(SYSTEM_NTSC); }
|
||||
AiDacrateChanged(state, Value);
|
||||
break;
|
||||
case 0x04500014: AI_BITRATE_REG = Value; break;
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-core - osal/preproc.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* this header file is for system-dependent #defines, #includes, and typedefs */
|
||||
|
||||
#if !defined (OSAL_PREPROC_H)
|
||||
#define OSAL_PREPROC_H
|
||||
|
||||
#if defined(WIN32) && !defined(__MINGW32__)
|
||||
|
||||
/* macros */
|
||||
#define OSAL_BREAKPOINT_INTERRUPT __asm{ int 3 };
|
||||
#define ALIGN(BYTES,DATA) __declspec(align(BYTES)) DATA
|
||||
#define osal_inline __inline
|
||||
|
||||
/* string functions */
|
||||
#define osal_insensitive_strcmp(x, y) _stricmp(x, y)
|
||||
#define snprintf _snprintf
|
||||
#define strdup _strdup
|
||||
|
||||
/* for isnan() */
|
||||
#include <float.h>
|
||||
#define isnan _isnan
|
||||
|
||||
#else /* Not WIN32 */
|
||||
|
||||
/* macros */
|
||||
#define OSAL_BREAKPOINT_INTERRUPT __asm__(" int $3; ");
|
||||
#define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES)))
|
||||
#define osal_inline inline
|
||||
|
||||
/* string functions */
|
||||
#define osal_insensitive_strcmp(x, y) strcasecmp(x, y)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* OSAL_PREPROC_H */
|
||||
|
|
@ -0,0 +1,369 @@
|
|||
Mupen64Plus-rsp-hle LICENSE
|
||||
---------------------------
|
||||
|
||||
Mupen64Plus-rsp-hle is licensed under the GNU General Public License version 2.
|
||||
|
||||
The authors of Mupen64Plus-rsp-hle are:
|
||||
* Richard Goedeken (Richard42)
|
||||
* Bobby Smiles
|
||||
* John Chadwick (NMN)
|
||||
* James Hood (Ebenblues)
|
||||
* Scott Gorman (okaygo)
|
||||
* Scott Knauert (Tillin9)
|
||||
* Jesse Dean (DarkJezter)
|
||||
* Louai Al-Khanji (slougi)
|
||||
* Bob Forder (orbitaldecay)
|
||||
* Jason Espinosa (hasone)
|
||||
* HyperHacker
|
||||
* and others.
|
||||
|
||||
Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally written by:
|
||||
* Hacktarux
|
||||
* Dave2001
|
||||
* Zilmar
|
||||
* Gregor Anich (Blight)
|
||||
* Juha Luotio (JttL)
|
||||
* and others.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,174 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ALIST_INTERNAL_H
|
||||
#define ALIST_INTERNAL_H
|
||||
|
||||
#include <our-stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct hle_t;
|
||||
|
||||
typedef void (*acmd_callback_t)(struct hle_t* hle, uint32_t w1, uint32_t w2);
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
void alist_process(struct hle_t* hle, const acmd_callback_t abi[], unsigned int abi_size, const char* abi_names[]);
|
||||
#else
|
||||
void alist_process(struct hle_t* hle, const acmd_callback_t abi[], unsigned int abi_size);
|
||||
#endif
|
||||
uint32_t alist_get_address(struct hle_t* hle, uint32_t so, const uint32_t *segments, size_t n);
|
||||
void alist_set_address(struct hle_t* hle, uint32_t so, uint32_t *segments, size_t n);
|
||||
void alist_clear(struct hle_t* hle, uint16_t dmem, uint16_t count);
|
||||
void alist_load(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count);
|
||||
void alist_save(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count);
|
||||
void alist_move(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count);
|
||||
void alist_copy_every_other_sample(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count);
|
||||
void alist_repeat64(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint8_t count);
|
||||
void alist_copy_blocks(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t block_size, uint8_t count);
|
||||
void alist_interleave(struct hle_t* hle, uint16_t dmemo, uint16_t left, uint16_t right, uint16_t count);
|
||||
|
||||
void alist_envmix_exp(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool aux,
|
||||
uint16_t dmem_dl, uint16_t dmem_dr,
|
||||
uint16_t dmem_wl, uint16_t dmem_wr,
|
||||
uint16_t dmemi, uint16_t count,
|
||||
int16_t dry, int16_t wet,
|
||||
const int16_t *vol,
|
||||
const int16_t *target,
|
||||
const int32_t *rate,
|
||||
uint32_t address);
|
||||
|
||||
void alist_envmix_ge(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool aux,
|
||||
uint16_t dmem_dl, uint16_t dmem_dr,
|
||||
uint16_t dmem_wl, uint16_t dmem_wr,
|
||||
uint16_t dmemi, uint16_t count,
|
||||
int16_t dry, int16_t wet,
|
||||
const int16_t *vol,
|
||||
const int16_t *target,
|
||||
const int32_t *rate,
|
||||
uint32_t address);
|
||||
|
||||
void alist_envmix_lin(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
uint16_t dmem_dl, uint16_t dmem_dr,
|
||||
uint16_t dmem_wl, uint16_t dmem_wr,
|
||||
uint16_t dmemi, uint16_t count,
|
||||
int16_t dry, int16_t wet,
|
||||
const int16_t *vol,
|
||||
const int16_t *target,
|
||||
const int32_t *rate,
|
||||
uint32_t address);
|
||||
|
||||
void alist_envmix_nead(
|
||||
struct hle_t* hle,
|
||||
bool swap_wet_LR,
|
||||
uint16_t dmem_dl,
|
||||
uint16_t dmem_dr,
|
||||
uint16_t dmem_wl,
|
||||
uint16_t dmem_wr,
|
||||
uint16_t dmemi,
|
||||
unsigned count,
|
||||
uint16_t *env_values,
|
||||
uint16_t *env_steps,
|
||||
const int16_t *xors);
|
||||
|
||||
void alist_mix(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count, int16_t gain);
|
||||
void alist_multQ44(struct hle_t* hle, uint16_t dmem, uint16_t count, int8_t gain);
|
||||
void alist_add(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count);
|
||||
|
||||
void alist_adpcm(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool loop,
|
||||
bool two_bit_per_sample,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
const int16_t* codebook,
|
||||
uint32_t loop_address,
|
||||
uint32_t last_frame_address);
|
||||
|
||||
void alist_resample(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
bool flag2,
|
||||
uint16_t dmemo, uint16_t dmemi, uint16_t count,
|
||||
uint32_t pitch, uint32_t address);
|
||||
|
||||
void alist_resample_zoh(
|
||||
struct hle_t* hle,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
uint32_t pitch,
|
||||
uint32_t pitch_accu);
|
||||
|
||||
void alist_filter(
|
||||
struct hle_t* hle,
|
||||
uint16_t dmem,
|
||||
uint16_t count,
|
||||
uint32_t address,
|
||||
const uint32_t* lut_address);
|
||||
|
||||
void alist_polef(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
uint16_t gain,
|
||||
int16_t* table,
|
||||
uint32_t address);
|
||||
|
||||
void alist_iirf(
|
||||
struct hle_t* hle,
|
||||
bool init,
|
||||
uint16_t dmemo,
|
||||
uint16_t dmemi,
|
||||
uint16_t count,
|
||||
int16_t* table,
|
||||
uint32_t address);
|
||||
|
||||
/*
|
||||
* Audio flags
|
||||
*/
|
||||
|
||||
#define A_INIT 0x01
|
||||
#define A_CONTINUE 0x00
|
||||
#define A_LOOP 0x02
|
||||
#define A_OUT 0x02
|
||||
#define A_LEFT 0x02
|
||||
#define A_RIGHT 0x00
|
||||
#define A_VOL 0x04
|
||||
#define A_RATE 0x00
|
||||
#define A_AUX 0x08
|
||||
#define A_NOAUX 0x00
|
||||
#define A_MAIN 0x00
|
||||
#define A_MIX 0x10
|
||||
|
||||
#endif
|
|
@ -0,0 +1,346 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_audio.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alist.h"
|
||||
#include "common.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
enum { DMEM_BASE = 0x5c0 };
|
||||
|
||||
/* helper functions */
|
||||
static uint32_t get_address(struct hle_t* hle, uint32_t so)
|
||||
{
|
||||
return alist_get_address(hle, so, hle->alist_audio.segments, N_SEGMENTS);
|
||||
}
|
||||
|
||||
static void set_address(struct hle_t* hle, uint32_t so)
|
||||
{
|
||||
alist_set_address(hle, so, hle->alist_audio.segments, N_SEGMENTS);
|
||||
}
|
||||
|
||||
static void clear_segments(struct hle_t* hle)
|
||||
{
|
||||
memset(hle->alist_audio.segments, 0, N_SEGMENTS*sizeof(hle->alist_audio.segments[0]));
|
||||
}
|
||||
|
||||
/* audio commands definition */
|
||||
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmem = w1 + DMEM_BASE;
|
||||
uint16_t count = w2;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_clear(hle, dmem, align(count, 16));
|
||||
}
|
||||
|
||||
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_envmix_exp(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & A_AUX,
|
||||
hle->alist_audio.out, hle->alist_audio.dry_right,
|
||||
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
|
||||
hle->alist_audio.in, hle->alist_audio.count,
|
||||
hle->alist_audio.dry, hle->alist_audio.wet,
|
||||
hle->alist_audio.vol,
|
||||
hle->alist_audio.target,
|
||||
hle->alist_audio.rate,
|
||||
address);
|
||||
}
|
||||
|
||||
static void ENVMIXER_GE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_envmix_ge(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
flags & A_AUX,
|
||||
hle->alist_audio.out, hle->alist_audio.dry_right,
|
||||
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
|
||||
hle->alist_audio.in, hle->alist_audio.count,
|
||||
hle->alist_audio.dry, hle->alist_audio.wet,
|
||||
hle->alist_audio.vol,
|
||||
hle->alist_audio.target,
|
||||
hle->alist_audio.rate,
|
||||
address);
|
||||
}
|
||||
|
||||
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t pitch = w1;
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_resample(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
flags & 0x2,
|
||||
hle->alist_audio.out,
|
||||
hle->alist_audio.in,
|
||||
align(hle->alist_audio.count, 16),
|
||||
pitch << 1,
|
||||
address);
|
||||
}
|
||||
|
||||
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
|
||||
if (flags & A_AUX) {
|
||||
hle->alist_audio.dry = w1;
|
||||
hle->alist_audio.wet = w2;
|
||||
}
|
||||
else {
|
||||
unsigned lr = (flags & A_LEFT) ? 0 : 1;
|
||||
|
||||
if (flags & A_VOL)
|
||||
hle->alist_audio.vol[lr] = w1;
|
||||
else {
|
||||
hle->alist_audio.target[lr] = w1;
|
||||
hle->alist_audio.rate[lr] = w2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_audio.loop = get_address(hle, w2);
|
||||
}
|
||||
|
||||
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
alist_adpcm(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
flags & 0x2,
|
||||
false, /* unsupported in this ucode */
|
||||
hle->alist_audio.out,
|
||||
hle->alist_audio.in,
|
||||
align(hle->alist_audio.count, 32),
|
||||
hle->alist_audio.table,
|
||||
hle->alist_audio.loop,
|
||||
address);
|
||||
}
|
||||
|
||||
static void LOADBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_load(hle, hle->alist_audio.in, address, hle->alist_audio.count);
|
||||
}
|
||||
|
||||
static void SAVEBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_save(hle, hle->alist_audio.out, address, hle->alist_audio.count);
|
||||
}
|
||||
|
||||
static void SETBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
|
||||
if (flags & A_AUX) {
|
||||
hle->alist_audio.dry_right = w1 + DMEM_BASE;
|
||||
hle->alist_audio.wet_left = (w2 >> 16) + DMEM_BASE;
|
||||
hle->alist_audio.wet_right = w2 + DMEM_BASE;
|
||||
} else {
|
||||
hle->alist_audio.in = w1 + DMEM_BASE;
|
||||
hle->alist_audio.out = (w2 >> 16) + DMEM_BASE;
|
||||
hle->alist_audio.count = w2;
|
||||
}
|
||||
}
|
||||
|
||||
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmemi = w1 + DMEM_BASE;
|
||||
uint16_t dmemo = (w2 >> 16) + DMEM_BASE;
|
||||
uint16_t count = w2;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_move(hle, dmemo, dmemi, align(count, 16));
|
||||
}
|
||||
|
||||
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
dram_load_u16(hle, (uint16_t*)hle->alist_audio.table, address, align(count, 8) >> 1);
|
||||
}
|
||||
|
||||
static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint16_t left = (w2 >> 16) + DMEM_BASE;
|
||||
uint16_t right = w2 + DMEM_BASE;
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_interleave(hle, hle->alist_audio.out, left, right, align(hle->alist_audio.count, 16));
|
||||
}
|
||||
|
||||
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t gain = w1;
|
||||
uint16_t dmemi = (w2 >> 16) + DMEM_BASE;
|
||||
uint16_t dmemo = w2 + DMEM_BASE;
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_mix(hle, dmemo, dmemi, align(hle->alist_audio.count, 32), gain);
|
||||
}
|
||||
|
||||
static void SEGMENT(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
set_address(hle, w2);
|
||||
}
|
||||
|
||||
static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t gain = w1;
|
||||
uint32_t address = get_address(hle, w2);
|
||||
|
||||
if (hle->alist_audio.count == 0)
|
||||
return;
|
||||
|
||||
alist_polef(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
hle->alist_audio.out,
|
||||
hle->alist_audio.in,
|
||||
align(hle->alist_audio.count, 16),
|
||||
gain,
|
||||
hle->alist_audio.table,
|
||||
address);
|
||||
}
|
||||
|
||||
/* global functions */
|
||||
void alist_process_audio(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
|
||||
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, POLEF, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "ENVMIXER",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "SEGMENT",
|
||||
"SETBUFF", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "POLEF", "SETLOOP"
|
||||
};
|
||||
#endif
|
||||
|
||||
clear_segments(hle);
|
||||
#ifdef DEBUG_INFO
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_audio_ge(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
|
||||
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, POLEF, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "ENVMIXER_GE",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "SEGMENT",
|
||||
"SETBUFF", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "POLEF", "SETLOOP"
|
||||
};
|
||||
#endif
|
||||
|
||||
clear_segments(hle);
|
||||
#ifdef DEBUG_INFO
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_audio_bc(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
|
||||
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, POLEF, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "ENVMIXER_GE",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "SEGMENT",
|
||||
"SETBUFF", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "POLEF", "SETLOOP"
|
||||
};
|
||||
#endif
|
||||
|
||||
clear_segments(hle);
|
||||
#ifdef DEBUG_INFO
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,383 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_naudio.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "alist.h"
|
||||
#include "common.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
enum { NAUDIO_COUNT = 0x170 }; /* ie 184 samples */
|
||||
enum {
|
||||
NAUDIO_MAIN = 0x4f0,
|
||||
NAUDIO_MAIN2 = 0x660,
|
||||
NAUDIO_DRY_LEFT = 0x9d0,
|
||||
NAUDIO_DRY_RIGHT = 0xb40,
|
||||
NAUDIO_WET_LEFT = 0xcb0,
|
||||
NAUDIO_WET_RIGHT = 0xe20
|
||||
};
|
||||
|
||||
|
||||
/* audio commands definition */
|
||||
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t acmd = (w1 >> 24);
|
||||
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"Unknown audio command %d: %08x %08x",
|
||||
acmd, w1, w2);
|
||||
}
|
||||
|
||||
|
||||
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void NAUDIO_0000(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
/* ??? */
|
||||
UNKNOWN(hle, w1, w2);
|
||||
}
|
||||
|
||||
static void NAUDIO_02B0(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
/* emulate code at 0x12b0 (inside SETVOL), because PC always execute in IMEM */
|
||||
hle->alist_naudio.rate[1] &= ~0xffff;
|
||||
hle->alist_naudio.rate[1] |= (w2 & 0xffff);
|
||||
}
|
||||
|
||||
static void NAUDIO_14(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t gain = w1;
|
||||
uint8_t select_main = (w2 >> 24);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
uint16_t dmem = (select_main == 0) ? NAUDIO_MAIN : NAUDIO_MAIN2;
|
||||
|
||||
if (hle->alist_naudio.table[0] == 0 && hle->alist_naudio.table[1] == 0) {
|
||||
alist_polef(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
dmem,
|
||||
dmem,
|
||||
NAUDIO_COUNT,
|
||||
gain,
|
||||
hle->alist_naudio.table,
|
||||
address);
|
||||
}
|
||||
else
|
||||
{
|
||||
alist_iirf(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
dmem,
|
||||
dmem,
|
||||
NAUDIO_COUNT,
|
||||
hle->alist_naudio.table,
|
||||
address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
|
||||
if (flags & 0x4) {
|
||||
if (flags & 0x2) {
|
||||
hle->alist_naudio.vol[0] = w1;
|
||||
hle->alist_naudio.dry = (w2 >> 16);
|
||||
hle->alist_naudio.wet = w2;
|
||||
}
|
||||
else {
|
||||
hle->alist_naudio.target[1] = w1;
|
||||
hle->alist_naudio.rate[1] = w2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
hle->alist_naudio.target[0] = w1;
|
||||
hle->alist_naudio.rate[0] = w2;
|
||||
}
|
||||
}
|
||||
|
||||
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
hle->alist_naudio.vol[1] = w1;
|
||||
|
||||
alist_envmix_lin(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
NAUDIO_DRY_LEFT,
|
||||
NAUDIO_DRY_RIGHT,
|
||||
NAUDIO_WET_LEFT,
|
||||
NAUDIO_WET_RIGHT,
|
||||
NAUDIO_MAIN,
|
||||
NAUDIO_COUNT,
|
||||
hle->alist_naudio.dry,
|
||||
hle->alist_naudio.wet,
|
||||
hle->alist_naudio.vol,
|
||||
hle->alist_naudio.target,
|
||||
hle->alist_naudio.rate,
|
||||
address);
|
||||
}
|
||||
|
||||
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmem = w1 + NAUDIO_MAIN;
|
||||
uint16_t count = w2 & 0xfff;
|
||||
|
||||
alist_clear(hle, dmem, count);
|
||||
}
|
||||
|
||||
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t gain = w1;
|
||||
uint16_t dmemi = (w2 >> 16) + NAUDIO_MAIN;
|
||||
uint16_t dmemo = w2 + NAUDIO_MAIN;
|
||||
|
||||
alist_mix(hle, dmemo, dmemi, NAUDIO_COUNT, gain);
|
||||
}
|
||||
|
||||
static void LOADBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_load(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_save(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
dram_load_u16(hle, (uint16_t*)hle->alist_naudio.table, address, count >> 1);
|
||||
}
|
||||
|
||||
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmemi = w1 + NAUDIO_MAIN;
|
||||
uint16_t dmemo = (w2 >> 16) + NAUDIO_MAIN;
|
||||
uint16_t count = w2;
|
||||
|
||||
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
|
||||
}
|
||||
|
||||
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_naudio.loop = (w2 & 0xffffff);
|
||||
}
|
||||
|
||||
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint32_t address = (w1 & 0xffffff);
|
||||
uint8_t flags = (w2 >> 28);
|
||||
uint16_t count = (w2 >> 16) & 0xfff;
|
||||
uint16_t dmemi = ((w2 >> 12) & 0xf) + NAUDIO_MAIN;
|
||||
uint16_t dmemo = (w2 & 0xfff) + NAUDIO_MAIN;
|
||||
|
||||
alist_adpcm(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
flags & 0x2,
|
||||
false, /* unsuported by this ucode */
|
||||
dmemo,
|
||||
dmemi,
|
||||
(count + 0x1f) & ~0x1f,
|
||||
hle->alist_naudio.table,
|
||||
hle->alist_naudio.loop,
|
||||
address);
|
||||
}
|
||||
|
||||
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint32_t address = (w1 & 0xffffff);
|
||||
uint8_t flags = (w2 >> 30);
|
||||
uint16_t pitch = (w2 >> 14);
|
||||
uint16_t dmemi = ((w2 >> 2) & 0xfff) + NAUDIO_MAIN;
|
||||
uint16_t dmemo = (w2 & 0x3) ? NAUDIO_MAIN2 : NAUDIO_MAIN;
|
||||
|
||||
alist_resample(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
false, /* TODO: check which ABI supports it */
|
||||
dmemo,
|
||||
dmemi,
|
||||
NAUDIO_COUNT,
|
||||
pitch << 1,
|
||||
address);
|
||||
}
|
||||
|
||||
static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
alist_interleave(hle, NAUDIO_MAIN, NAUDIO_DRY_LEFT, NAUDIO_DRY_RIGHT, NAUDIO_COUNT);
|
||||
}
|
||||
|
||||
static void MP3ADDY(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void MP3(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
unsigned index = (w1 & 0x1e);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
mp3_task(hle, index, address);
|
||||
}
|
||||
|
||||
/* global functions */
|
||||
void alist_process_naudio(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000,
|
||||
NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "ENVMIXER",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "NAUDIO_0000",
|
||||
"NAUDIO_0000", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "NAUDIO_02B0", "SETLOOP"
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_naudio_bk(struct hle_t* hle)
|
||||
{
|
||||
/* TODO: see what differs from alist_process_naudio */
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000,
|
||||
NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "ENVMIXER",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "NAUDIO_0000",
|
||||
"NAUDIO_0000", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "NAUDIO_02B0", "SETLOOP"
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_naudio_dk(struct hle_t* hle)
|
||||
{
|
||||
/* TODO: see what differs from alist_process_naudio */
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, MIXER,
|
||||
MIXER, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "ENVMIXER",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "MIXER",
|
||||
"MIXER", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "NAUDIO_02B0", "SETLOOP"
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_naudio_mp3(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, MP3,
|
||||
MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_14, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "ENVMIXER",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "MP3",
|
||||
"MP3ADDY", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "NAUDIO_14", "SETLOOP"
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_naudio_cbfd(struct hle_t* hle)
|
||||
{
|
||||
/* TODO: see what differs from alist_process_naudio_mp3 */
|
||||
static const acmd_callback_t ABI[0x10] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER,
|
||||
LOADBUFF, RESAMPLE, SAVEBUFF, MP3,
|
||||
MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, NAUDIO_14, SETLOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x10] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "ENVMIXER",
|
||||
"LOADBUFF", "RESAMPLE", "SAVEBUFF", "MP3",
|
||||
"MP3ADDY", "SETVOL", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "NAUDIO_14", "SETLOOP"
|
||||
};
|
||||
|
||||
alist_process(hle, ABI, 0x10, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x10);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,665 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - alist_nead.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "alist.h"
|
||||
#include "common.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
#include "ucodes.h"
|
||||
|
||||
/* remove windows define to 0x06 */
|
||||
#ifdef DUPLICATE
|
||||
#undef DUPLICATE
|
||||
#endif
|
||||
|
||||
/* audio commands definition */
|
||||
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t acmd = (w1 >> 24);
|
||||
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"Unknown audio command %d: %08x %08x",
|
||||
acmd, w1, w2);
|
||||
}
|
||||
|
||||
|
||||
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
dram_load_u16(hle, (uint16_t*)hle->alist_nead.table, address, count >> 1);
|
||||
}
|
||||
|
||||
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.loop = w2 & 0xffffff;
|
||||
}
|
||||
|
||||
static void SETBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.in = w1;
|
||||
hle->alist_nead.out = (w2 >> 16);
|
||||
hle->alist_nead.count = w2;
|
||||
}
|
||||
|
||||
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_adpcm(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
flags & 0x2,
|
||||
flags & 0x4,
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
(hle->alist_nead.count + 0x1f) & ~0x1f,
|
||||
hle->alist_nead.table,
|
||||
hle->alist_nead.loop,
|
||||
address);
|
||||
}
|
||||
|
||||
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmem = w1;
|
||||
uint16_t count = w2 & 0xfff;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_clear(hle, dmem, count);
|
||||
}
|
||||
|
||||
static void LOADBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_load(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xfff;
|
||||
uint16_t dmem = (w1 & 0xfff);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_save(hle, dmem, address, count);
|
||||
}
|
||||
|
||||
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xff0;
|
||||
int16_t gain = w1;
|
||||
uint16_t dmemi = (w2 >> 16);
|
||||
uint16_t dmemo = w2;
|
||||
|
||||
alist_mix(hle, dmemo, dmemi, count, gain);
|
||||
}
|
||||
|
||||
|
||||
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t pitch = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
alist_resample(
|
||||
hle,
|
||||
flags & 0x1,
|
||||
false, /* TODO: check which ABI supports it */
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
(hle->alist_nead.count + 0xf) & ~0xf,
|
||||
pitch << 1,
|
||||
address);
|
||||
}
|
||||
|
||||
static void RESAMPLE_ZOH(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t pitch = w1;
|
||||
uint16_t pitch_accu = w2;
|
||||
|
||||
alist_resample_zoh(
|
||||
hle,
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
hle->alist_nead.count,
|
||||
pitch << 1,
|
||||
pitch_accu);
|
||||
}
|
||||
|
||||
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t dmemi = w1;
|
||||
uint16_t dmemo = (w2 >> 16);
|
||||
uint16_t count = w2;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
|
||||
}
|
||||
|
||||
static void ENVSETUP1_MK(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
|
||||
hle->alist_nead.env_steps[2] = 0;
|
||||
hle->alist_nead.env_steps[0] = (w2 >> 16);
|
||||
hle->alist_nead.env_steps[1] = w2;
|
||||
}
|
||||
|
||||
static void ENVSETUP1(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
|
||||
hle->alist_nead.env_steps[2] = w1;
|
||||
hle->alist_nead.env_steps[0] = (w2 >> 16);
|
||||
hle->alist_nead.env_steps[1] = w2;
|
||||
}
|
||||
|
||||
static void ENVSETUP2(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
hle->alist_nead.env_values[0] = (w2 >> 16);
|
||||
hle->alist_nead.env_values[1] = w2;
|
||||
}
|
||||
|
||||
static void ENVMIXER_MK(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t xors[4];
|
||||
|
||||
uint16_t dmemi = (w1 >> 12) & 0xff0;
|
||||
uint8_t count = (w1 >> 8) & 0xff;
|
||||
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
|
||||
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
|
||||
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
|
||||
uint16_t dmem_wr = (w2 << 4) & 0xff0;
|
||||
|
||||
xors[2] = 0; /* unsupported by this ucode */
|
||||
xors[3] = 0; /* unsupported by this ucode */
|
||||
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
|
||||
xors[1] = 0 - (int16_t)((w1 & 0x1) );
|
||||
|
||||
alist_envmix_nead(
|
||||
hle,
|
||||
false, /* unsupported by this ucode */
|
||||
dmem_dl, dmem_dr,
|
||||
dmem_wl, dmem_wr,
|
||||
dmemi, count,
|
||||
hle->alist_nead.env_values,
|
||||
hle->alist_nead.env_steps,
|
||||
xors);
|
||||
}
|
||||
|
||||
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int16_t xors[4];
|
||||
|
||||
uint16_t dmemi = (w1 >> 12) & 0xff0;
|
||||
uint8_t count = (w1 >> 8) & 0xff;
|
||||
bool swap_wet_LR = (w1 >> 4) & 0x1;
|
||||
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
|
||||
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
|
||||
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
|
||||
uint16_t dmem_wr = (w2 << 4) & 0xff0;
|
||||
|
||||
xors[2] = 0 - (int16_t)((w1 & 0x8) >> 1);
|
||||
xors[3] = 0 - (int16_t)((w1 & 0x4) >> 1);
|
||||
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
|
||||
xors[1] = 0 - (int16_t)((w1 & 0x1) );
|
||||
|
||||
alist_envmix_nead(
|
||||
hle,
|
||||
swap_wet_LR,
|
||||
dmem_dl, dmem_dr,
|
||||
dmem_wl, dmem_wr,
|
||||
dmemi, count,
|
||||
hle->alist_nead.env_values,
|
||||
hle->alist_nead.env_steps,
|
||||
xors);
|
||||
}
|
||||
|
||||
static void DUPLICATE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t count = (w1 >> 16);
|
||||
uint16_t dmemi = w1;
|
||||
uint16_t dmemo = (w2 >> 16);
|
||||
|
||||
alist_repeat64(hle, dmemo, dmemi, count);
|
||||
}
|
||||
|
||||
static void INTERL(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = w1;
|
||||
uint16_t dmemi = (w2 >> 16);
|
||||
uint16_t dmemo = w2;
|
||||
|
||||
alist_copy_every_other_sample(hle, dmemo, dmemi, count);
|
||||
}
|
||||
|
||||
static void INTERLEAVE_MK(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
|
||||
{
|
||||
uint16_t left = (w2 >> 16);
|
||||
uint16_t right = w2;
|
||||
|
||||
if (hle->alist_nead.count == 0)
|
||||
return;
|
||||
|
||||
alist_interleave(hle, hle->alist_nead.out, left, right, hle->alist_nead.count);
|
||||
}
|
||||
|
||||
static void INTERLEAVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = ((w1 >> 12) & 0xff0);
|
||||
uint16_t dmemo = w1;
|
||||
uint16_t left = (w2 >> 16);
|
||||
uint16_t right = w2;
|
||||
|
||||
alist_interleave(hle, dmemo, left, right, count);
|
||||
}
|
||||
|
||||
static void ADDMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint16_t count = (w1 >> 12) & 0xff0;
|
||||
uint16_t dmemi = (w2 >> 16);
|
||||
uint16_t dmemo = w2;
|
||||
|
||||
alist_add(hle, dmemo, dmemi, count);
|
||||
}
|
||||
|
||||
static void HILOGAIN(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
int8_t gain = (w1 >> 16); /* Q4.4 signed */
|
||||
uint16_t count = w1;
|
||||
uint16_t dmem = (w2 >> 16);
|
||||
|
||||
alist_multQ44(hle, dmem, count, gain);
|
||||
}
|
||||
|
||||
static void FILTER(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
if (flags > 1) {
|
||||
hle->alist_nead.filter_count = w1;
|
||||
hle->alist_nead.filter_lut_address[0] = address; /* t6 */
|
||||
}
|
||||
else {
|
||||
uint16_t dmem = w1;
|
||||
|
||||
hle->alist_nead.filter_lut_address[1] = address + 0x10; /* t5 */
|
||||
alist_filter(hle, dmem, hle->alist_nead.filter_count, address, hle->alist_nead.filter_lut_address);
|
||||
}
|
||||
}
|
||||
|
||||
static void SEGMENT(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
|
||||
{
|
||||
}
|
||||
|
||||
static void NEAD_16(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t count = (w1 >> 16);
|
||||
uint16_t dmemi = w1;
|
||||
uint16_t dmemo = (w2 >> 16);
|
||||
uint16_t block_size = w2;
|
||||
|
||||
alist_copy_blocks(hle, dmemo, dmemi, block_size, count);
|
||||
}
|
||||
|
||||
static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
|
||||
{
|
||||
uint8_t flags = (w1 >> 16);
|
||||
uint16_t gain = w1;
|
||||
uint32_t address = (w2 & 0xffffff);
|
||||
|
||||
if (hle->alist_nead.count == 0)
|
||||
return;
|
||||
|
||||
alist_polef(
|
||||
hle,
|
||||
flags & A_INIT,
|
||||
hle->alist_nead.out,
|
||||
hle->alist_nead.in,
|
||||
hle->alist_nead.count,
|
||||
gain,
|
||||
hle->alist_nead.table,
|
||||
address);
|
||||
}
|
||||
|
||||
|
||||
void alist_process_nead_mk(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
SPNOOP, RESAMPLE, SPNOOP, SEGMENT,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1_MK, ENVMIXER_MK,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x20] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"SPNOOP", "RESAMPLE", "SPNOOP", "SEGMENT",
|
||||
"SETBUFF", "SPNOOP", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE_MK", "POLEF", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1_MK", "ENVMIXER_MK",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "SPNOOP",
|
||||
"SPNOOP", "SPNOOP", "SPNOOP", "SPNOOP",
|
||||
"SPNOOP", "SPNOOP", "SPNOOP", "SPNOOP"
|
||||
};
|
||||
alist_process(hle, ABI, 0x20, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_sf(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
|
||||
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x20] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "SPNOOP",
|
||||
"SETBUFF", "SPNOOP", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE_MK", "POLEF", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "SPNOOP",
|
||||
"HILOGAIN", "UNKNOWN", "DUPLICATE", "SPNOOP",
|
||||
"SPNOOP", "SPNOOP", "SPNOOP", "SPNOOP"
|
||||
};
|
||||
alist_process(hle, ABI, 0x20, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_sfj(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
|
||||
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x20] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "SPNOOP",
|
||||
"SETBUFF", "SPNOOP", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE_MK", "POLEF", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN",
|
||||
"HILOGAIN", "UNKNOWN", "DUPLICATE", "SPNOOP",
|
||||
"SPNOOP", "SPNOOP", "SPNOOP", "SPNOOP"
|
||||
};
|
||||
alist_process(hle, ABI, 0x20, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_fz(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, SPNOOP, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
|
||||
SPNOOP, UNKNOWN, DUPLICATE, SPNOOP,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x20] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"ADDMIXER", "RESAMPLE", "SPNOOP", "SPNOOP",
|
||||
"SETBUFF", "SPNOOP", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "SPNOOP", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN",
|
||||
"SPNOOP", "UNKNOWN", "DUPLICATE", "SPNOOP",
|
||||
"SPNOOP", "SPNOOP", "SPNOOP", "SPNOOP"
|
||||
};
|
||||
alist_process(hle, ABI, 0x20, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_wrjb(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x20] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
|
||||
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
|
||||
HILOGAIN, UNKNOWN, DUPLICATE, FILTER,
|
||||
SPNOOP, SPNOOP, SPNOOP, SPNOOP
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x20] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "UNKNOWN",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "SPNOOP",
|
||||
"SETBUFF", "SPNOOP", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "SPNOOP", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN",
|
||||
"HILOGAIN", "UNKNOWN", "DUPLICATE", "FILTER",
|
||||
"SPNOOP", "SPNOOP", "SPNOOP", "SPNOOP"
|
||||
};
|
||||
alist_process(hle, ABI, 0x20, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x20);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_ys(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x18] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "UNKNOWN",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "FILTER",
|
||||
"SETBUFF", "DUPLICATE", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "HILOGAIN", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN"
|
||||
};
|
||||
alist_process(hle, ABI, 0x18, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x18);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_1080(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x18] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "UNKNOWN",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "FILTER",
|
||||
"SETBUFF", "DUPLICATE", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "HILOGAIN", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN"
|
||||
};
|
||||
alist_process(hle, ABI, 0x18, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x18);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_oot(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x18] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "UNKNOWN",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "FILTER",
|
||||
"SETBUFF", "DUPLICATE", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "HILOGAIN", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN"
|
||||
};
|
||||
alist_process(hle, ABI, 0x18, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x18);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_mm(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x18] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "FILTER",
|
||||
"SETBUFF", "DUPLICATE", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "HILOGAIN", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN"
|
||||
};
|
||||
alist_process(hle, ABI, 0x18, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x18);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_mmb(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x18] = {
|
||||
"SPNOOP", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "FILTER",
|
||||
"SETBUFF", "DUPLICATE", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "HILOGAIN", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN"
|
||||
};
|
||||
alist_process(hle, ABI, 0x18, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x18);
|
||||
#endif
|
||||
}
|
||||
|
||||
void alist_process_nead_ac(struct hle_t* hle)
|
||||
{
|
||||
static const acmd_callback_t ABI[0x18] = {
|
||||
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
|
||||
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
|
||||
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
|
||||
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
|
||||
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
|
||||
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
|
||||
};
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
static const char * ABI_names[0x18] = {
|
||||
"UNKNOWN", "ADPCM", "CLEARBUFF", "SPNOOP",
|
||||
"ADDMIXER", "RESAMPLE", "RESAMPLE_ZOH", "FILTER",
|
||||
"SETBUFF", "DUPLICATE", "DMEMMOVE", "LOADADPCM",
|
||||
"MIXER", "INTERLEAVE", "HILOGAIN", "SETLOOP",
|
||||
"NEAD_16", "INTERL", "ENVSETUP1", "ENVMIXER",
|
||||
"LOADBUFF", "SAVEBUFF", "ENVSETUP2", "UNKNOWN"
|
||||
};
|
||||
alist_process(hle, ABI, 0x18, ABI_names);
|
||||
#else
|
||||
alist_process(hle, ABI, 0x18);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - arithmetics.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef ARITHMETICS_H
|
||||
#define ARITHMETICS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static inline int16_t clamp_s16(int_fast32_t x)
|
||||
{
|
||||
x = (x < INT16_MIN) ? INT16_MIN: x;
|
||||
x = (x > INT16_MAX) ? INT16_MAX: x;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int32_t vmulf(int16_t x, int16_t y)
|
||||
{
|
||||
return (((int32_t)(x))*((int32_t)(y))+0x4000)>>15;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - audio.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "arithmetics.h"
|
||||
|
||||
const int16_t RESAMPLE_LUT[64 * 4] = {
|
||||
(int16_t)0x0c39, (int16_t)0x66ad, (int16_t)0x0d46, (int16_t)0xffdf,
|
||||
(int16_t)0x0b39, (int16_t)0x6696, (int16_t)0x0e5f, (int16_t)0xffd8,
|
||||
(int16_t)0x0a44, (int16_t)0x6669, (int16_t)0x0f83, (int16_t)0xffd0,
|
||||
(int16_t)0x095a, (int16_t)0x6626, (int16_t)0x10b4, (int16_t)0xffc8,
|
||||
(int16_t)0x087d, (int16_t)0x65cd, (int16_t)0x11f0, (int16_t)0xffbf,
|
||||
(int16_t)0x07ab, (int16_t)0x655e, (int16_t)0x1338, (int16_t)0xffb6,
|
||||
(int16_t)0x06e4, (int16_t)0x64d9, (int16_t)0x148c, (int16_t)0xffac,
|
||||
(int16_t)0x0628, (int16_t)0x643f, (int16_t)0x15eb, (int16_t)0xffa1,
|
||||
(int16_t)0x0577, (int16_t)0x638f, (int16_t)0x1756, (int16_t)0xff96,
|
||||
(int16_t)0x04d1, (int16_t)0x62cb, (int16_t)0x18cb, (int16_t)0xff8a,
|
||||
(int16_t)0x0435, (int16_t)0x61f3, (int16_t)0x1a4c, (int16_t)0xff7e,
|
||||
(int16_t)0x03a4, (int16_t)0x6106, (int16_t)0x1bd7, (int16_t)0xff71,
|
||||
(int16_t)0x031c, (int16_t)0x6007, (int16_t)0x1d6c, (int16_t)0xff64,
|
||||
(int16_t)0x029f, (int16_t)0x5ef5, (int16_t)0x1f0b, (int16_t)0xff56,
|
||||
(int16_t)0x022a, (int16_t)0x5dd0, (int16_t)0x20b3, (int16_t)0xff48,
|
||||
(int16_t)0x01be, (int16_t)0x5c9a, (int16_t)0x2264, (int16_t)0xff3a,
|
||||
(int16_t)0x015b, (int16_t)0x5b53, (int16_t)0x241e, (int16_t)0xff2c,
|
||||
(int16_t)0x0101, (int16_t)0x59fc, (int16_t)0x25e0, (int16_t)0xff1e,
|
||||
(int16_t)0x00ae, (int16_t)0x5896, (int16_t)0x27a9, (int16_t)0xff10,
|
||||
(int16_t)0x0063, (int16_t)0x5720, (int16_t)0x297a, (int16_t)0xff02,
|
||||
(int16_t)0x001f, (int16_t)0x559d, (int16_t)0x2b50, (int16_t)0xfef4,
|
||||
(int16_t)0xffe2, (int16_t)0x540d, (int16_t)0x2d2c, (int16_t)0xfee8,
|
||||
(int16_t)0xffac, (int16_t)0x5270, (int16_t)0x2f0d, (int16_t)0xfedb,
|
||||
(int16_t)0xff7c, (int16_t)0x50c7, (int16_t)0x30f3, (int16_t)0xfed0,
|
||||
(int16_t)0xff53, (int16_t)0x4f14, (int16_t)0x32dc, (int16_t)0xfec6,
|
||||
(int16_t)0xff2e, (int16_t)0x4d57, (int16_t)0x34c8, (int16_t)0xfebd,
|
||||
(int16_t)0xff0f, (int16_t)0x4b91, (int16_t)0x36b6, (int16_t)0xfeb6,
|
||||
(int16_t)0xfef5, (int16_t)0x49c2, (int16_t)0x38a5, (int16_t)0xfeb0,
|
||||
(int16_t)0xfedf, (int16_t)0x47ed, (int16_t)0x3a95, (int16_t)0xfeac,
|
||||
(int16_t)0xfece, (int16_t)0x4611, (int16_t)0x3c85, (int16_t)0xfeab,
|
||||
(int16_t)0xfec0, (int16_t)0x4430, (int16_t)0x3e74, (int16_t)0xfeac,
|
||||
(int16_t)0xfeb6, (int16_t)0x424a, (int16_t)0x4060, (int16_t)0xfeaf,
|
||||
(int16_t)0xfeaf, (int16_t)0x4060, (int16_t)0x424a, (int16_t)0xfeb6,
|
||||
(int16_t)0xfeac, (int16_t)0x3e74, (int16_t)0x4430, (int16_t)0xfec0,
|
||||
(int16_t)0xfeab, (int16_t)0x3c85, (int16_t)0x4611, (int16_t)0xfece,
|
||||
(int16_t)0xfeac, (int16_t)0x3a95, (int16_t)0x47ed, (int16_t)0xfedf,
|
||||
(int16_t)0xfeb0, (int16_t)0x38a5, (int16_t)0x49c2, (int16_t)0xfef5,
|
||||
(int16_t)0xfeb6, (int16_t)0x36b6, (int16_t)0x4b91, (int16_t)0xff0f,
|
||||
(int16_t)0xfebd, (int16_t)0x34c8, (int16_t)0x4d57, (int16_t)0xff2e,
|
||||
(int16_t)0xfec6, (int16_t)0x32dc, (int16_t)0x4f14, (int16_t)0xff53,
|
||||
(int16_t)0xfed0, (int16_t)0x30f3, (int16_t)0x50c7, (int16_t)0xff7c,
|
||||
(int16_t)0xfedb, (int16_t)0x2f0d, (int16_t)0x5270, (int16_t)0xffac,
|
||||
(int16_t)0xfee8, (int16_t)0x2d2c, (int16_t)0x540d, (int16_t)0xffe2,
|
||||
(int16_t)0xfef4, (int16_t)0x2b50, (int16_t)0x559d, (int16_t)0x001f,
|
||||
(int16_t)0xff02, (int16_t)0x297a, (int16_t)0x5720, (int16_t)0x0063,
|
||||
(int16_t)0xff10, (int16_t)0x27a9, (int16_t)0x5896, (int16_t)0x00ae,
|
||||
(int16_t)0xff1e, (int16_t)0x25e0, (int16_t)0x59fc, (int16_t)0x0101,
|
||||
(int16_t)0xff2c, (int16_t)0x241e, (int16_t)0x5b53, (int16_t)0x015b,
|
||||
(int16_t)0xff3a, (int16_t)0x2264, (int16_t)0x5c9a, (int16_t)0x01be,
|
||||
(int16_t)0xff48, (int16_t)0x20b3, (int16_t)0x5dd0, (int16_t)0x022a,
|
||||
(int16_t)0xff56, (int16_t)0x1f0b, (int16_t)0x5ef5, (int16_t)0x029f,
|
||||
(int16_t)0xff64, (int16_t)0x1d6c, (int16_t)0x6007, (int16_t)0x031c,
|
||||
(int16_t)0xff71, (int16_t)0x1bd7, (int16_t)0x6106, (int16_t)0x03a4,
|
||||
(int16_t)0xff7e, (int16_t)0x1a4c, (int16_t)0x61f3, (int16_t)0x0435,
|
||||
(int16_t)0xff8a, (int16_t)0x18cb, (int16_t)0x62cb, (int16_t)0x04d1,
|
||||
(int16_t)0xff96, (int16_t)0x1756, (int16_t)0x638f, (int16_t)0x0577,
|
||||
(int16_t)0xffa1, (int16_t)0x15eb, (int16_t)0x643f, (int16_t)0x0628,
|
||||
(int16_t)0xffac, (int16_t)0x148c, (int16_t)0x64d9, (int16_t)0x06e4,
|
||||
(int16_t)0xffb6, (int16_t)0x1338, (int16_t)0x655e, (int16_t)0x07ab,
|
||||
(int16_t)0xffbf, (int16_t)0x11f0, (int16_t)0x65cd, (int16_t)0x087d,
|
||||
(int16_t)0xffc8, (int16_t)0x10b4, (int16_t)0x6626, (int16_t)0x095a,
|
||||
(int16_t)0xffd0, (int16_t)0x0f83, (int16_t)0x6669, (int16_t)0x0a44,
|
||||
(int16_t)0xffd8, (int16_t)0x0e5f, (int16_t)0x6696, (int16_t)0x0b39,
|
||||
(int16_t)0xffdf, (int16_t)0x0d46, (int16_t)0x66ad, (int16_t)0x0c39
|
||||
};
|
||||
|
||||
int32_t rdot(size_t n, const int16_t *x, const int16_t *y)
|
||||
{
|
||||
int32_t accu = 0;
|
||||
|
||||
y += n;
|
||||
|
||||
while (n != 0) {
|
||||
accu += *(x++) * *(--y);
|
||||
--n;
|
||||
}
|
||||
|
||||
return accu;
|
||||
}
|
||||
|
||||
void adpcm_compute_residuals(int16_t* dst, const int16_t* src,
|
||||
const int16_t* cb_entry, const int16_t* last_samples, size_t count)
|
||||
{
|
||||
const int16_t* const book1 = cb_entry;
|
||||
const int16_t* const book2 = cb_entry + 8;
|
||||
|
||||
const int16_t l1 = last_samples[0];
|
||||
const int16_t l2 = last_samples[1];
|
||||
|
||||
size_t i;
|
||||
|
||||
assert(count <= 8);
|
||||
|
||||
for(i = 0; i < count; ++i) {
|
||||
int32_t accu = (int32_t)src[i] << 11;
|
||||
accu += book1[i]*l1 + book2[i]*l2 + rdot(i, book2, src);
|
||||
dst[i] = clamp_s16(accu >> 11);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - audio.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "osal/preproc.h"
|
||||
|
||||
extern const int16_t RESAMPLE_LUT[64 * 4];
|
||||
|
||||
int32_t rdot(size_t n, const int16_t *x, const int16_t *y);
|
||||
|
||||
static osal_inline int16_t adpcm_predict_sample(uint8_t byte, uint8_t mask,
|
||||
unsigned lshift, unsigned rshift)
|
||||
{
|
||||
int16_t sample = (uint16_t)(byte & mask) << lshift;
|
||||
sample >>= rshift; /* signed */
|
||||
return sample;
|
||||
}
|
||||
|
||||
void adpcm_compute_residuals(int16_t* dst, const int16_t* src,
|
||||
const int16_t* cb_entry, const int16_t* last_samples, size_t count);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - cicx105.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2012 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hle_internal.h"
|
||||
|
||||
/**
|
||||
* During IPL3 stage of CIC x105 games, the RSP performs some checks and transactions
|
||||
* necessary for booting the game.
|
||||
*
|
||||
* We only implement the needed DMA transactions for booting.
|
||||
*
|
||||
* Found in Banjo-Tooie, Zelda, Perfect Dark, ...)
|
||||
**/
|
||||
void cicx105_ucode(struct hle_t* hle)
|
||||
{
|
||||
/* memcpy is okay to use because access constrains are met (alignment, size) */
|
||||
unsigned int i;
|
||||
unsigned char *dst = hle->dram + 0x2fb1f0;
|
||||
unsigned char *src = hle->imem + 0x120;
|
||||
|
||||
/* dma_read(0x1120, 0x1e8, 0x1e8) */
|
||||
memcpy(hle->imem + 0x120, hle->dram + 0x1e8, 0x1f0);
|
||||
|
||||
/* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */
|
||||
for (i = 0; i < 24; ++i) {
|
||||
memcpy(dst, src, 8);
|
||||
dst += 0xff0;
|
||||
src += 0x8;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - common.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
/* macro for unused variable warning suppression */
|
||||
#ifdef __GNUC__
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
||||
#else
|
||||
# define UNUSED(x) UNUSED_ ## x
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define inline __forceinline
|
||||
#elif defined __GNUC__
|
||||
# define inline inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2012 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include "ucodes.h"
|
||||
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/* some rsp status flags */
|
||||
#define SP_STATUS_HALT 0x1
|
||||
#define SP_STATUS_BROKE 0x2
|
||||
#define SP_STATUS_INTR_ON_BREAK 0x40
|
||||
#define SP_STATUS_TASKDONE 0x200
|
||||
|
||||
/* some rdp status flags */
|
||||
#define DP_STATUS_FREEZE 0x2
|
||||
|
||||
/* some mips interface interrupt flags */
|
||||
#define MI_INTR_SP 0x1
|
||||
|
||||
|
||||
/* helper functions prototypes */
|
||||
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size);
|
||||
static bool is_task(struct hle_t* hle);
|
||||
static void rsp_break(struct hle_t* hle, unsigned int setbits);
|
||||
static void forward_gfx_task(struct hle_t* hle);
|
||||
static bool try_fast_audio_dispatching(struct hle_t* hle);
|
||||
static bool try_fast_task_dispatching(struct hle_t* hle);
|
||||
static void normal_task_dispatching(struct hle_t* hle);
|
||||
static void non_task_dispatching(struct hle_t* hle);
|
||||
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
static void dump_binary(const char *const filename, const unsigned char *const bytes,
|
||||
unsigned int size);
|
||||
static void dump_task(struct hle_t* hle, const char *const filename);
|
||||
static void dump_unknown_task(struct hle_t* hle, unsigned int sum);
|
||||
static void dump_unknown_non_task(struct hle_t* hle, unsigned int sum);
|
||||
#endif
|
||||
|
||||
/* local variables */
|
||||
static const bool FORWARD_AUDIO = false, FORWARD_GFX = true;
|
||||
|
||||
/* Global functions */
|
||||
void hle_init(struct hle_t* hle,
|
||||
unsigned char* dram,
|
||||
unsigned char* dmem,
|
||||
unsigned char* imem,
|
||||
unsigned int* mi_intr,
|
||||
unsigned int* sp_mem_addr,
|
||||
unsigned int* sp_dram_addr,
|
||||
unsigned int* sp_rd_length,
|
||||
unsigned int* sp_wr_length,
|
||||
unsigned int* sp_status,
|
||||
unsigned int* sp_dma_full,
|
||||
unsigned int* sp_dma_busy,
|
||||
unsigned int* sp_pc,
|
||||
unsigned int* sp_semaphore,
|
||||
unsigned int* dpc_start,
|
||||
unsigned int* dpc_end,
|
||||
unsigned int* dpc_current,
|
||||
unsigned int* dpc_status,
|
||||
unsigned int* dpc_clock,
|
||||
unsigned int* dpc_bufbusy,
|
||||
unsigned int* dpc_pipebusy,
|
||||
unsigned int* dpc_tmem,
|
||||
void* user_defined)
|
||||
{
|
||||
hle->dram = dram;
|
||||
hle->dmem = dmem;
|
||||
hle->imem = imem;
|
||||
hle->mi_intr = mi_intr;
|
||||
hle->sp_mem_addr = sp_mem_addr;
|
||||
hle->sp_dram_addr = sp_dram_addr;
|
||||
hle->sp_rd_length = sp_rd_length;
|
||||
hle->sp_wr_length = sp_wr_length;
|
||||
hle->sp_status = sp_status;
|
||||
hle->sp_dma_full = sp_dma_full;
|
||||
hle->sp_dma_busy = sp_dma_busy;
|
||||
hle->sp_pc = sp_pc;
|
||||
hle->sp_semaphore = sp_semaphore;
|
||||
hle->dpc_start = dpc_start;
|
||||
hle->dpc_end = dpc_end;
|
||||
hle->dpc_current = dpc_current;
|
||||
hle->dpc_status = dpc_status;
|
||||
hle->dpc_clock = dpc_clock;
|
||||
hle->dpc_bufbusy = dpc_bufbusy;
|
||||
hle->dpc_pipebusy = dpc_pipebusy;
|
||||
hle->dpc_tmem = dpc_tmem;
|
||||
hle->user_defined = user_defined;
|
||||
}
|
||||
|
||||
void hle_execute(struct hle_t* hle)
|
||||
{
|
||||
if (is_task(hle)) {
|
||||
if (!try_fast_task_dispatching(hle))
|
||||
normal_task_dispatching(hle);
|
||||
rsp_break(hle, SP_STATUS_TASKDONE);
|
||||
} else {
|
||||
non_task_dispatching(hle);
|
||||
rsp_break(hle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size)
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
const unsigned char *const bytes_end = bytes + size;
|
||||
|
||||
while (bytes != bytes_end)
|
||||
sum += *bytes++;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to figure if the RSP was launched using osSpTask* functions
|
||||
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
|
||||
*
|
||||
* Previously, the ucode_size field was used to determine this,
|
||||
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
|
||||
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
|
||||
*
|
||||
* Using ucode_boot_size should be more robust in this regard.
|
||||
**/
|
||||
static bool is_task(struct hle_t* hle)
|
||||
{
|
||||
return (*dmem_u32(hle, TASK_UCODE_BOOT_SIZE) <= 0x1000);
|
||||
}
|
||||
|
||||
static void rsp_break(struct hle_t* hle, unsigned int setbits)
|
||||
{
|
||||
*hle->sp_status |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT;
|
||||
|
||||
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK)) {
|
||||
*hle->mi_intr |= MI_INTR_SP;
|
||||
HleCheckInterrupts(hle->user_defined);
|
||||
}
|
||||
}
|
||||
|
||||
static void forward_gfx_task(struct hle_t* hle)
|
||||
{
|
||||
HleProcessDlistList(hle->user_defined);
|
||||
*hle->dpc_status &= ~DP_STATUS_FREEZE;
|
||||
}
|
||||
|
||||
static bool try_fast_audio_dispatching(struct hle_t* hle)
|
||||
{
|
||||
/* identify audio ucode by using the content of ucode_data */
|
||||
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
|
||||
uint32_t v;
|
||||
|
||||
if (*dram_u32(hle, ucode_data) == 0x00000001) {
|
||||
if (*dram_u32(hle, ucode_data + 0x30) == 0xf0000f00) {
|
||||
v = *dram_u32(hle, ucode_data + 0x28);
|
||||
switch(v)
|
||||
{
|
||||
case 0x1e24138c: /* audio ABI (most common) */
|
||||
alist_process_audio(hle); return true;
|
||||
case 0x1dc8138c: /* GoldenEye */
|
||||
alist_process_audio_ge(hle); return true;
|
||||
case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */
|
||||
alist_process_audio_bc(hle); return true;
|
||||
default:
|
||||
HleWarnMessage(hle->user_defined, "ABI1 identification regression: v=%08x", v);
|
||||
}
|
||||
} else {
|
||||
v = *dram_u32(hle, ucode_data + 0x10);
|
||||
switch(v)
|
||||
{
|
||||
case 0x11181350: /* MarioKart, WaveRace (E) */
|
||||
alist_process_nead_mk(hle); return true;
|
||||
case 0x111812e0: /* StarFox (J) */
|
||||
alist_process_nead_sfj(hle); return true;
|
||||
case 0x110412ac: /* WaveRace (J RevB) */
|
||||
alist_process_nead_wrjb(hle); return true;
|
||||
case 0x110412cc: /* StarFox/LylatWars (except J) */
|
||||
alist_process_nead_sf(hle); return true;
|
||||
case 0x1cd01250: /* FZeroX */
|
||||
alist_process_nead_fz(hle); return true;
|
||||
case 0x1f08122c: /* YoshisStory */
|
||||
alist_process_nead_ys(hle); return true;
|
||||
case 0x1f38122c: /* 1080° Snowboarding */
|
||||
alist_process_nead_1080(hle); return true;
|
||||
case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */
|
||||
alist_process_nead_oot(hle); return true;
|
||||
case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */
|
||||
alist_process_nead_mm(hle); return true;
|
||||
case 0x109411f8: /* Zelda MM (E Beta) */
|
||||
alist_process_nead_mmb(hle); return true;
|
||||
case 0x1eac11b8: /* AnimalCrossing */
|
||||
alist_process_nead_ac(hle); return true;
|
||||
case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */
|
||||
musyx_v2_task(hle); return true;
|
||||
|
||||
default:
|
||||
HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v = *dram_u32(hle, ucode_data + 0x10);
|
||||
switch(v)
|
||||
{
|
||||
case 0x00000001: /* MusyX v1
|
||||
RogueSquadron, ResidentEvil2, PolarisSnoCross,
|
||||
TheWorldIsNotEnough, RugratsInParis, NBAShowTime,
|
||||
HydroThunder, Tarzan, GauntletLegend, Rush2049 */
|
||||
musyx_v1_task(hle); return true;
|
||||
case 0x0000127c: /* naudio (many games) */
|
||||
alist_process_naudio(hle); return true;
|
||||
case 0x00001280: /* BanjoKazooie */
|
||||
alist_process_naudio_bk(hle); return true;
|
||||
case 0x1c58126c: /* DonkeyKong */
|
||||
alist_process_naudio_dk(hle); return true;
|
||||
case 0x1ae8143c: /* BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark */
|
||||
alist_process_naudio_mp3(hle); return true;
|
||||
case 0x1ab0140c: /* ConkerBadFurDay */
|
||||
alist_process_naudio_cbfd(hle); return true;
|
||||
|
||||
default:
|
||||
HleWarnMessage(hle->user_defined, "ABI3 identification regression: v=%08x", v);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool try_fast_task_dispatching(struct hle_t* hle)
|
||||
{
|
||||
/* identify task ucode by its type */
|
||||
switch (*dmem_u32(hle, TASK_TYPE)) {
|
||||
case 1:
|
||||
if (FORWARD_GFX) {
|
||||
forward_gfx_task(hle);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (FORWARD_AUDIO) {
|
||||
HleProcessAlistList(hle->user_defined);
|
||||
return true;
|
||||
} else if (try_fast_audio_dispatching(hle))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
HleShowCFB(hle->user_defined);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void normal_task_dispatching(struct hle_t* hle)
|
||||
{
|
||||
const unsigned int sum =
|
||||
sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), min(*dmem_u32(hle, TASK_UCODE_SIZE), 0xf80) >> 1);
|
||||
|
||||
switch (sum) {
|
||||
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
|
||||
case 0x278:
|
||||
/* Nothing to emulate */
|
||||
return;
|
||||
|
||||
/* GFX: Twintris [misleading task->type == 0] */
|
||||
case 0x212ee:
|
||||
if (FORWARD_GFX) {
|
||||
forward_gfx_task(hle);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
/* JPEG: found in Pokemon Stadium J */
|
||||
case 0x2c85a:
|
||||
jpeg_decode_PS0(hle);
|
||||
return;
|
||||
|
||||
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
|
||||
case 0x2caa6:
|
||||
jpeg_decode_PS(hle);
|
||||
return;
|
||||
|
||||
/* JPEG: found in Ogre Battle, Bottom of the 9th */
|
||||
case 0x130de:
|
||||
case 0x278b0:
|
||||
jpeg_decode_OB(hle);
|
||||
return;
|
||||
}
|
||||
|
||||
HleWarnMessage(hle->user_defined, "unknown OSTask: sum: %x PC:%x", sum, *hle->sp_pc);
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
dump_unknown_task(hle, sum);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void non_task_dispatching(struct hle_t* hle)
|
||||
{
|
||||
const unsigned int sum = sum_bytes(hle->imem, 44);
|
||||
|
||||
if (sum == 0x9e2)
|
||||
{
|
||||
/* CIC x105 ucode (used during boot of CIC x105 games) */
|
||||
cicx105_ucode(hle);
|
||||
return;
|
||||
}
|
||||
|
||||
HleWarnMessage(hle->user_defined, "unknown RSP code: sum: %x PC:%x", sum, *hle->sp_pc);
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
dump_unknown_non_task(hle, sum);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_TASK_DUMP
|
||||
static void dump_unknown_task(struct hle_t* hle, unsigned int sum)
|
||||
{
|
||||
char filename[256];
|
||||
uint32_t ucode = *dmem_u32(hle, TASK_UCODE);
|
||||
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
|
||||
uint32_t data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
|
||||
sprintf(&filename[0], "task_%x.log", sum);
|
||||
dump_task(hle, filename);
|
||||
|
||||
/* dump ucode_boot */
|
||||
sprintf(&filename[0], "ucode_boot_%x.bin", sum);
|
||||
dump_binary(filename, (void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE_BOOT)), *dmem_u32(hle, TASK_UCODE_BOOT_SIZE));
|
||||
|
||||
/* dump ucode */
|
||||
if (ucode != 0) {
|
||||
sprintf(&filename[0], "ucode_%x.bin", sum);
|
||||
dump_binary(filename, (void*)dram_u32(hle, ucode), 0xf80);
|
||||
}
|
||||
|
||||
/* dump ucode_data */
|
||||
if (ucode_data != 0) {
|
||||
sprintf(&filename[0], "ucode_data_%x.bin", sum);
|
||||
dump_binary(filename, (void*)dram_u32(hle, ucode_data), *dmem_u32(hle, TASK_UCODE_DATA_SIZE));
|
||||
}
|
||||
|
||||
/* dump data */
|
||||
if (data_ptr != 0) {
|
||||
sprintf(&filename[0], "data_%x.bin", sum);
|
||||
dump_binary(filename, (void*)dram_u32(hle, data_ptr), *dmem_u32(hle, TASK_DATA_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_unknown_non_task(struct hle_t* hle, unsigned int sum)
|
||||
{
|
||||
char filename[256];
|
||||
|
||||
/* dump IMEM & DMEM for further analysis */
|
||||
sprintf(&filename[0], "imem_%x.bin", sum);
|
||||
dump_binary(filename, hle->imem, 0x1000);
|
||||
|
||||
sprintf(&filename[0], "dmem_%x.bin", sum);
|
||||
dump_binary(filename, hle->dmem, 0x1000);
|
||||
}
|
||||
|
||||
static void dump_binary(const char *const filename, const unsigned char *const bytes,
|
||||
unsigned int size)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
/* if file already exists, do nothing */
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
/* else we write bytes to the file */
|
||||
f = fopen(filename, "wb");
|
||||
if (f != NULL) {
|
||||
if (fwrite(bytes, 1, size, f) != size)
|
||||
hleErrorMessage(hle->user_defined, "Writing error on %s", filename);
|
||||
fclose(f);
|
||||
} else
|
||||
hleErrorMessage(hle->user_defined, "Couldn't open %s for writing !", filename);
|
||||
} else
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void dump_task(struct hle_t* hle, const char *const filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
f = fopen(filename, "w");
|
||||
fprintf(f,
|
||||
"type = %d\n"
|
||||
"flags = %d\n"
|
||||
"ucode_boot = %#08x size = %#x\n"
|
||||
"ucode = %#08x size = %#x\n"
|
||||
"ucode_data = %#08x size = %#x\n"
|
||||
"dram_stack = %#08x size = %#x\n"
|
||||
"output_buff = %#08x *size = %#x\n"
|
||||
"data = %#08x size = %#x\n"
|
||||
"yield_data = %#08x size = %#x\n",
|
||||
*dmem_u32(hle, TASK_TYPE),
|
||||
*dmem_u32(hle, TASK_FLAGS),
|
||||
*dmem_u32(hle, TASK_UCODE_BOOT), *dmem_u32(hle, TASK_UCODE_BOOT_SIZE),
|
||||
*dmem_u32(hle, TASK_UCODE), *dmem_u32(hle, TASK_UCODE_SIZE),
|
||||
*dmem_u32(hle, TASK_UCODE_DATA), *dmem_u32(hle, TASK_UCODE_DATA_SIZE),
|
||||
*dmem_u32(hle, TASK_DRAM_STACK), *dmem_u32(hle, TASK_DRAM_STACK_SIZE),
|
||||
*dmem_u32(hle, TASK_OUTPUT_BUFF), *dmem_u32(hle, TASK_OUTPUT_BUFF_SIZE),
|
||||
*dmem_u32(hle, TASK_DATA_PTR), *dmem_u32(hle, TASK_DATA_SIZE),
|
||||
*dmem_u32(hle, TASK_YIELD_DATA_PTR), *dmem_u32(hle, TASK_YIELD_DATA_SIZE));
|
||||
fclose(f);
|
||||
} else
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef HLE_H
|
||||
#define HLE_H
|
||||
|
||||
#include "hle_internal.h"
|
||||
|
||||
void hle_init(struct hle_t* hle,
|
||||
unsigned char* dram,
|
||||
unsigned char* dmem,
|
||||
unsigned char* imem,
|
||||
unsigned int* mi_intr,
|
||||
unsigned int* sp_mem_addr,
|
||||
unsigned int* sp_dram_addr,
|
||||
unsigned int* sp_rd_length,
|
||||
unsigned int* sp_wr_length,
|
||||
unsigned int* sp_status,
|
||||
unsigned int* sp_dma_full,
|
||||
unsigned int* sp_dma_busy,
|
||||
unsigned int* sp_pc,
|
||||
unsigned int* sp_semaphore,
|
||||
unsigned int* dpc_start,
|
||||
unsigned int* dpc_end,
|
||||
unsigned int* dpc_current,
|
||||
unsigned int* dpc_status,
|
||||
unsigned int* dpc_clock,
|
||||
unsigned int* dpc_bufbusy,
|
||||
unsigned int* dpc_pipebusy,
|
||||
unsigned int* dpc_tmem,
|
||||
void* user_defined);
|
||||
|
||||
void hle_execute(struct hle_t* hle);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle_external.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef HLE_EXTERNAL_H
|
||||
#define HLE_EXTERNAL_H
|
||||
|
||||
/* users of the hle core are expected to define these functions */
|
||||
|
||||
void HleVerboseMessage(void* user_defined, const char *message, ...);
|
||||
void HleErrorMessage(void* user_defined, const char *message, ...);
|
||||
void HleWarnMessage(void* user_defined, const char *message, ...);
|
||||
|
||||
void HleCheckInterrupts(void* user_defined);
|
||||
void HleProcessDlistList(void* user_defined);
|
||||
void HleProcessAlistList(void* user_defined);
|
||||
void HleProcessRdpList(void* user_defined);
|
||||
void HleShowCFB(void* user_defined);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - hle_internal.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef HLE_INTERNAL_H
|
||||
#define HLE_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ucodes.h"
|
||||
|
||||
/* rsp hle internal state - internal usage only */
|
||||
struct hle_t
|
||||
{
|
||||
unsigned char* dram;
|
||||
unsigned char* dmem;
|
||||
unsigned char* imem;
|
||||
|
||||
unsigned int* mi_intr;
|
||||
|
||||
unsigned int* sp_mem_addr;
|
||||
unsigned int* sp_dram_addr;
|
||||
unsigned int* sp_rd_length;
|
||||
unsigned int* sp_wr_length;
|
||||
unsigned int* sp_status;
|
||||
unsigned int* sp_dma_full;
|
||||
unsigned int* sp_dma_busy;
|
||||
unsigned int* sp_pc;
|
||||
unsigned int* sp_semaphore;
|
||||
|
||||
unsigned int* dpc_start;
|
||||
unsigned int* dpc_end;
|
||||
unsigned int* dpc_current;
|
||||
unsigned int* dpc_status;
|
||||
unsigned int* dpc_clock;
|
||||
unsigned int* dpc_bufbusy;
|
||||
unsigned int* dpc_pipebusy;
|
||||
unsigned int* dpc_tmem;
|
||||
|
||||
/* for user convenience, this will be passed to "external" functions */
|
||||
void* user_defined;
|
||||
|
||||
|
||||
/* alist.c */
|
||||
uint8_t alist_buffer[0x1000];
|
||||
|
||||
/* alist_audio.c */
|
||||
struct alist_audio_t alist_audio;
|
||||
|
||||
/* alist_naudio.c */
|
||||
struct alist_naudio_t alist_naudio;
|
||||
|
||||
/* alist_nead.c */
|
||||
struct alist_nead_t alist_nead;
|
||||
|
||||
/* mp3.c */
|
||||
uint8_t mp3_buffer[0x1000];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,596 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - jpeg.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2012 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "arithmetics.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define SUBBLOCK_SIZE 64
|
||||
|
||||
typedef void (*tile_line_emitter_t)(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address);
|
||||
typedef void (*subblock_transform_t)(int16_t *dst, const int16_t *src);
|
||||
|
||||
/* standard jpeg ucode decoder */
|
||||
static void jpeg_decode_std(struct hle_t* hle,
|
||||
const char *const version,
|
||||
const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
const tile_line_emitter_t emit_line);
|
||||
|
||||
/* helper functions */
|
||||
static uint8_t clamp_u8(int16_t x);
|
||||
static int16_t clamp_s12(int16_t x);
|
||||
static uint16_t clamp_RGBA_component(int16_t x);
|
||||
|
||||
/* pixel conversion & formatting */
|
||||
static uint32_t GetUYVY(int16_t y1, int16_t y2, int16_t u, int16_t v);
|
||||
static uint16_t GetRGBA(int16_t y, int16_t u, int16_t v);
|
||||
|
||||
/* tile line emitters */
|
||||
static void EmitYUVTileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address);
|
||||
static void EmitRGBATileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address);
|
||||
|
||||
/* macroblocks operations */
|
||||
static void decode_macroblock_ob(int16_t *macroblock, int32_t *y_dc, int32_t *u_dc, int32_t *v_dc, const int16_t *qtable);
|
||||
static void decode_macroblock_std(const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
int16_t *macroblock,
|
||||
unsigned int subblock_count,
|
||||
const int16_t qtables[3][SUBBLOCK_SIZE]);
|
||||
static void EmitTilesMode0(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address);
|
||||
static void EmitTilesMode2(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address);
|
||||
|
||||
/* subblocks operations */
|
||||
static void TransposeSubBlock(int16_t *dst, const int16_t *src);
|
||||
static void ZigZagSubBlock(int16_t *dst, const int16_t *src);
|
||||
static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int *table);
|
||||
static void MultSubBlocks(int16_t *dst, const int16_t *src1, const int16_t *src2, unsigned int shift);
|
||||
static void ScaleSubBlock(int16_t *dst, const int16_t *src, int16_t scale);
|
||||
static void RShiftSubBlock(int16_t *dst, const int16_t *src, unsigned int shift);
|
||||
static void InverseDCT1D(const float *const x, float *dst, unsigned int stride);
|
||||
static void InverseDCTSubBlock(int16_t *dst, const int16_t *src);
|
||||
static void RescaleYSubBlock(int16_t *dst, const int16_t *src);
|
||||
static void RescaleUVSubBlock(int16_t *dst, const int16_t *src);
|
||||
|
||||
/* transposed dequantization table */
|
||||
static const int16_t DEFAULT_QTABLE[SUBBLOCK_SIZE] = {
|
||||
16, 12, 14, 14, 18, 24, 49, 72,
|
||||
11, 12, 13, 17, 22, 35, 64, 92,
|
||||
10, 14, 16, 22, 37, 55, 78, 95,
|
||||
16, 19, 24, 29, 56, 64, 87, 98,
|
||||
24, 26, 40, 51, 68, 81, 103, 112,
|
||||
40, 58, 57, 87, 109, 104, 121, 100,
|
||||
51, 60, 69, 80, 103, 113, 120, 103,
|
||||
61, 55, 56, 62, 77, 92, 101, 99
|
||||
};
|
||||
|
||||
/* zig-zag indices */
|
||||
static const unsigned int ZIGZAG_TABLE[SUBBLOCK_SIZE] = {
|
||||
0, 1, 5, 6, 14, 15, 27, 28,
|
||||
2, 4, 7, 13, 16, 26, 29, 42,
|
||||
3, 8, 12, 17, 25, 30, 41, 43,
|
||||
9, 11, 18, 24, 31, 40, 44, 53,
|
||||
10, 19, 23, 32, 39, 45, 52, 54,
|
||||
20, 22, 33, 38, 46, 51, 55, 60,
|
||||
21, 34, 37, 47, 50, 56, 59, 61,
|
||||
35, 36, 48, 49, 57, 58, 62, 63
|
||||
};
|
||||
|
||||
/* transposition indices */
|
||||
static const unsigned int TRANSPOSE_TABLE[SUBBLOCK_SIZE] = {
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
1, 9, 17, 25, 33, 41, 49, 57,
|
||||
2, 10, 18, 26, 34, 42, 50, 58,
|
||||
3, 11, 19, 27, 35, 43, 51, 59,
|
||||
4, 12, 20, 28, 36, 44, 52, 60,
|
||||
5, 13, 21, 29, 37, 45, 53, 61,
|
||||
6, 14, 22, 30, 38, 46, 54, 62,
|
||||
7, 15, 23, 31, 39, 47, 55, 63
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* IDCT related constants
|
||||
* Cn = alpha * cos(n * PI / 16) (alpha is chosen such as C4 = 1) */
|
||||
static const float IDCT_C3 = 1.175875602f;
|
||||
static const float IDCT_C6 = 0.541196100f;
|
||||
static const float IDCT_K[10] = {
|
||||
0.765366865f, /* C2-C6 */
|
||||
-1.847759065f, /* -C2-C6 */
|
||||
-0.390180644f, /* C5-C3 */
|
||||
-1.961570561f, /* -C5-C3 */
|
||||
1.501321110f, /* C1+C3-C5-C7 */
|
||||
2.053119869f, /* C1+C3-C5+C7 */
|
||||
3.072711027f, /* C1+C3+C5-C7 */
|
||||
0.298631336f, /* -C1+C3+C5-C7 */
|
||||
-0.899976223f, /* C7-C3 */
|
||||
-2.562915448f /* -C1-C3 */
|
||||
};
|
||||
|
||||
|
||||
/* global functions */
|
||||
|
||||
/***************************************************************************
|
||||
* JPEG decoding ucode found in Japanese exclusive version of Pokemon Stadium.
|
||||
**************************************************************************/
|
||||
void jpeg_decode_PS0(struct hle_t* hle)
|
||||
{
|
||||
jpeg_decode_std(hle, "PS0", RescaleYSubBlock, RescaleUVSubBlock, EmitYUVTileLine);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* JPEG decoding ucode found in Ocarina of Time, Pokemon Stadium 1 and
|
||||
* Pokemon Stadium 2.
|
||||
**************************************************************************/
|
||||
void jpeg_decode_PS(struct hle_t* hle)
|
||||
{
|
||||
jpeg_decode_std(hle, "PS", NULL, NULL, EmitRGBATileLine);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* JPEG decoding ucode found in Ogre Battle and Bottom of the 9th.
|
||||
**************************************************************************/
|
||||
void jpeg_decode_OB(struct hle_t* hle)
|
||||
{
|
||||
int16_t qtable[SUBBLOCK_SIZE];
|
||||
unsigned int mb;
|
||||
|
||||
int32_t y_dc = 0;
|
||||
int32_t u_dc = 0;
|
||||
int32_t v_dc = 0;
|
||||
|
||||
uint32_t address = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
const unsigned int macroblock_count = *dmem_u32(hle, TASK_DATA_SIZE);
|
||||
const int qscale = *dmem_u32(hle, TASK_YIELD_DATA_SIZE);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"jpeg_decode_OB: *buffer=%x, #MB=%d, qscale=%d",
|
||||
address,
|
||||
macroblock_count,
|
||||
qscale);
|
||||
|
||||
if (qscale != 0) {
|
||||
if (qscale > 0)
|
||||
ScaleSubBlock(qtable, DEFAULT_QTABLE, qscale);
|
||||
else
|
||||
RShiftSubBlock(qtable, DEFAULT_QTABLE, -qscale);
|
||||
}
|
||||
|
||||
for (mb = 0; mb < macroblock_count; ++mb) {
|
||||
int16_t macroblock[6 * SUBBLOCK_SIZE];
|
||||
|
||||
dram_load_u16(hle, (uint16_t *)macroblock, address, 6 * SUBBLOCK_SIZE);
|
||||
decode_macroblock_ob(macroblock, &y_dc, &u_dc, &v_dc, (qscale != 0) ? qtable : NULL);
|
||||
EmitTilesMode2(hle, EmitYUVTileLine, macroblock, address);
|
||||
|
||||
address += (2 * 6 * SUBBLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* local functions */
|
||||
static void jpeg_decode_std(struct hle_t* hle,
|
||||
const char *const version,
|
||||
const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
const tile_line_emitter_t emit_line)
|
||||
{
|
||||
int16_t qtables[3][SUBBLOCK_SIZE];
|
||||
unsigned int mb;
|
||||
uint32_t address;
|
||||
uint32_t macroblock_count;
|
||||
uint32_t mode;
|
||||
uint32_t qtableY_ptr;
|
||||
uint32_t qtableU_ptr;
|
||||
uint32_t qtableV_ptr;
|
||||
unsigned int subblock_count;
|
||||
unsigned int macroblock_size;
|
||||
/* macroblock contains at most 6 subblocks */
|
||||
int16_t macroblock[6 * SUBBLOCK_SIZE];
|
||||
uint32_t data_ptr;
|
||||
|
||||
if (*dmem_u32(hle, TASK_FLAGS) & 0x1) {
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"jpeg_decode_%s: task yielding not implemented", version);
|
||||
return;
|
||||
}
|
||||
|
||||
data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
address = *dram_u32(hle, data_ptr);
|
||||
macroblock_count = *dram_u32(hle, data_ptr + 4);
|
||||
mode = *dram_u32(hle, data_ptr + 8);
|
||||
qtableY_ptr = *dram_u32(hle, data_ptr + 12);
|
||||
qtableU_ptr = *dram_u32(hle, data_ptr + 16);
|
||||
qtableV_ptr = *dram_u32(hle, data_ptr + 20);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"jpeg_decode_%s: *buffer=%x, #MB=%d, mode=%d, *Qy=%x, *Qu=%x, *Qv=%x",
|
||||
version,
|
||||
address,
|
||||
macroblock_count,
|
||||
mode,
|
||||
qtableY_ptr,
|
||||
qtableU_ptr,
|
||||
qtableV_ptr);
|
||||
|
||||
if (mode != 0 && mode != 2) {
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"jpeg_decode_%s: invalid mode %d", version, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
subblock_count = mode + 4;
|
||||
macroblock_size = subblock_count * SUBBLOCK_SIZE;
|
||||
|
||||
dram_load_u16(hle, (uint16_t *)qtables[0], qtableY_ptr, SUBBLOCK_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)qtables[1], qtableU_ptr, SUBBLOCK_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)qtables[2], qtableV_ptr, SUBBLOCK_SIZE);
|
||||
|
||||
for (mb = 0; mb < macroblock_count; ++mb) {
|
||||
dram_load_u16(hle, (uint16_t *)macroblock, address, macroblock_size);
|
||||
decode_macroblock_std(transform_luma, transform_chroma,
|
||||
macroblock, subblock_count, (const int16_t (*)[SUBBLOCK_SIZE])qtables);
|
||||
|
||||
if (mode == 0)
|
||||
EmitTilesMode0(hle, emit_line, macroblock, address);
|
||||
else
|
||||
EmitTilesMode2(hle, emit_line, macroblock, address);
|
||||
|
||||
address += 2 * macroblock_size;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t clamp_u8(int16_t x)
|
||||
{
|
||||
return (x & (0xff00)) ? ((-x) >> 15) & 0xff : x;
|
||||
}
|
||||
|
||||
static int16_t clamp_s12(int16_t x)
|
||||
{
|
||||
if (x < -0x800)
|
||||
x = -0x800;
|
||||
else if (x > 0x7f0)
|
||||
x = 0x7f0;
|
||||
return x;
|
||||
}
|
||||
|
||||
static uint16_t clamp_RGBA_component(int16_t x)
|
||||
{
|
||||
if (x > 0xff0)
|
||||
x = 0xff0;
|
||||
else if (x < 0)
|
||||
x = 0;
|
||||
return (x & 0xf80);
|
||||
}
|
||||
|
||||
static uint32_t GetUYVY(int16_t y1, int16_t y2, int16_t u, int16_t v)
|
||||
{
|
||||
return (uint32_t)clamp_u8(u) << 24 |
|
||||
(uint32_t)clamp_u8(y1) << 16 |
|
||||
(uint32_t)clamp_u8(v) << 8 |
|
||||
(uint32_t)clamp_u8(y2);
|
||||
}
|
||||
|
||||
static uint16_t GetRGBA(int16_t y, int16_t u, int16_t v)
|
||||
{
|
||||
const float fY = (float)y + 2048.0f;
|
||||
const float fU = (float)u;
|
||||
const float fV = (float)v;
|
||||
|
||||
const uint16_t r = clamp_RGBA_component((int16_t)(fY + 1.4025 * fV));
|
||||
const uint16_t g = clamp_RGBA_component((int16_t)(fY - 0.3443 * fU - 0.7144 * fV));
|
||||
const uint16_t b = clamp_RGBA_component((int16_t)(fY + 1.7729 * fU));
|
||||
|
||||
return (r << 4) | (g >> 1) | (b >> 6) | 1;
|
||||
}
|
||||
|
||||
static void EmitYUVTileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address)
|
||||
{
|
||||
uint32_t uyvy[8];
|
||||
|
||||
const int16_t *const v = u + SUBBLOCK_SIZE;
|
||||
const int16_t *const y2 = y + SUBBLOCK_SIZE;
|
||||
|
||||
uyvy[0] = GetUYVY(y[0], y[1], u[0], v[0]);
|
||||
uyvy[1] = GetUYVY(y[2], y[3], u[1], v[1]);
|
||||
uyvy[2] = GetUYVY(y[4], y[5], u[2], v[2]);
|
||||
uyvy[3] = GetUYVY(y[6], y[7], u[3], v[3]);
|
||||
uyvy[4] = GetUYVY(y2[0], y2[1], u[4], v[4]);
|
||||
uyvy[5] = GetUYVY(y2[2], y2[3], u[5], v[5]);
|
||||
uyvy[6] = GetUYVY(y2[4], y2[5], u[6], v[6]);
|
||||
uyvy[7] = GetUYVY(y2[6], y2[7], u[7], v[7]);
|
||||
|
||||
dram_store_u32(hle, uyvy, address, 8);
|
||||
}
|
||||
|
||||
static void EmitRGBATileLine(struct hle_t* hle, const int16_t *y, const int16_t *u, uint32_t address)
|
||||
{
|
||||
uint16_t rgba[16];
|
||||
|
||||
const int16_t *const v = u + SUBBLOCK_SIZE;
|
||||
const int16_t *const y2 = y + SUBBLOCK_SIZE;
|
||||
|
||||
rgba[0] = GetRGBA(y[0], u[0], v[0]);
|
||||
rgba[1] = GetRGBA(y[1], u[0], v[0]);
|
||||
rgba[2] = GetRGBA(y[2], u[1], v[1]);
|
||||
rgba[3] = GetRGBA(y[3], u[1], v[1]);
|
||||
rgba[4] = GetRGBA(y[4], u[2], v[2]);
|
||||
rgba[5] = GetRGBA(y[5], u[2], v[2]);
|
||||
rgba[6] = GetRGBA(y[6], u[3], v[3]);
|
||||
rgba[7] = GetRGBA(y[7], u[3], v[3]);
|
||||
rgba[8] = GetRGBA(y2[0], u[4], v[4]);
|
||||
rgba[9] = GetRGBA(y2[1], u[4], v[4]);
|
||||
rgba[10] = GetRGBA(y2[2], u[5], v[5]);
|
||||
rgba[11] = GetRGBA(y2[3], u[5], v[5]);
|
||||
rgba[12] = GetRGBA(y2[4], u[6], v[6]);
|
||||
rgba[13] = GetRGBA(y2[5], u[6], v[6]);
|
||||
rgba[14] = GetRGBA(y2[6], u[7], v[7]);
|
||||
rgba[15] = GetRGBA(y2[7], u[7], v[7]);
|
||||
|
||||
dram_store_u16(hle, rgba, address, 16);
|
||||
}
|
||||
|
||||
static void EmitTilesMode0(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned int y_offset = 0;
|
||||
unsigned int u_offset = 2 * SUBBLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
emit_line(hle, ¯oblock[y_offset], ¯oblock[u_offset], address);
|
||||
|
||||
y_offset += 8;
|
||||
u_offset += 8;
|
||||
address += 32;
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitTilesMode2(struct hle_t* hle, const tile_line_emitter_t emit_line, const int16_t *macroblock, uint32_t address)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned int y_offset = 0;
|
||||
unsigned int u_offset = 4 * SUBBLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
emit_line(hle, ¯oblock[y_offset], ¯oblock[u_offset], address);
|
||||
emit_line(hle, ¯oblock[y_offset + 8], ¯oblock[u_offset], address + 32);
|
||||
|
||||
y_offset += (i == 3) ? SUBBLOCK_SIZE + 16 : 16;
|
||||
u_offset += 8;
|
||||
address += 64;
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_macroblock_ob(int16_t *macroblock, int32_t *y_dc, int32_t *u_dc, int32_t *v_dc, const int16_t *qtable)
|
||||
{
|
||||
int sb;
|
||||
|
||||
for (sb = 0; sb < 6; ++sb) {
|
||||
int16_t tmp_sb[SUBBLOCK_SIZE];
|
||||
|
||||
/* update DC */
|
||||
int32_t dc = (int32_t)macroblock[0];
|
||||
switch (sb) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
*y_dc += dc;
|
||||
macroblock[0] = *y_dc & 0xffff;
|
||||
break;
|
||||
case 4:
|
||||
*u_dc += dc;
|
||||
macroblock[0] = *u_dc & 0xffff;
|
||||
break;
|
||||
case 5:
|
||||
*v_dc += dc;
|
||||
macroblock[0] = *v_dc & 0xffff;
|
||||
break;
|
||||
}
|
||||
|
||||
ZigZagSubBlock(tmp_sb, macroblock);
|
||||
if (qtable != NULL)
|
||||
MultSubBlocks(tmp_sb, tmp_sb, qtable, 0);
|
||||
TransposeSubBlock(macroblock, tmp_sb);
|
||||
InverseDCTSubBlock(macroblock, macroblock);
|
||||
|
||||
macroblock += SUBBLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_macroblock_std(const subblock_transform_t transform_luma,
|
||||
const subblock_transform_t transform_chroma,
|
||||
int16_t *macroblock,
|
||||
unsigned int subblock_count,
|
||||
const int16_t qtables[3][SUBBLOCK_SIZE])
|
||||
{
|
||||
unsigned int sb;
|
||||
unsigned int q = 0;
|
||||
|
||||
for (sb = 0; sb < subblock_count; ++sb) {
|
||||
int16_t tmp_sb[SUBBLOCK_SIZE];
|
||||
const int isChromaSubBlock = (subblock_count - sb <= 2);
|
||||
|
||||
if (isChromaSubBlock)
|
||||
++q;
|
||||
|
||||
MultSubBlocks(macroblock, macroblock, qtables[q], 4);
|
||||
ZigZagSubBlock(tmp_sb, macroblock);
|
||||
InverseDCTSubBlock(macroblock, tmp_sb);
|
||||
|
||||
if (isChromaSubBlock) {
|
||||
if (transform_chroma != NULL)
|
||||
transform_chroma(macroblock, macroblock);
|
||||
} else {
|
||||
if (transform_luma != NULL)
|
||||
transform_luma(macroblock, macroblock);
|
||||
}
|
||||
|
||||
macroblock += SUBBLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void TransposeSubBlock(int16_t *dst, const int16_t *src)
|
||||
{
|
||||
ReorderSubBlock(dst, src, TRANSPOSE_TABLE);
|
||||
}
|
||||
|
||||
static void ZigZagSubBlock(int16_t *dst, const int16_t *src)
|
||||
{
|
||||
ReorderSubBlock(dst, src, ZIGZAG_TABLE);
|
||||
}
|
||||
|
||||
static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int *table)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* source and destination sublocks cannot overlap */
|
||||
assert(abs(dst - src) > SUBBLOCK_SIZE);
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
dst[i] = src[table[i]];
|
||||
}
|
||||
|
||||
static void MultSubBlocks(int16_t *dst, const int16_t *src1, const int16_t *src2, unsigned int shift)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i) {
|
||||
int32_t v = src1[i] * src2[i];
|
||||
dst[i] = clamp_s16(v) << shift;
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleSubBlock(int16_t *dst, const int16_t *src, int16_t scale)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i) {
|
||||
int32_t v = src[i] * scale;
|
||||
dst[i] = clamp_s16(v);
|
||||
}
|
||||
}
|
||||
|
||||
static void RShiftSubBlock(int16_t *dst, const int16_t *src, unsigned int shift)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
dst[i] = src[i] >> shift;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Fast 2D IDCT using separable formulation and normalization
|
||||
* Computations use single precision floats
|
||||
* Implementation based on Wikipedia :
|
||||
* http://fr.wikipedia.org/wiki/Transform%C3%A9e_en_cosinus_discr%C3%A8te
|
||||
**************************************************************************/
|
||||
static void InverseDCT1D(const float *const x, float *dst, unsigned int stride)
|
||||
{
|
||||
float e[4];
|
||||
float f[4];
|
||||
float x26, x1357, x15, x37, x17, x35;
|
||||
|
||||
x15 = IDCT_K[2] * (x[1] + x[5]);
|
||||
x37 = IDCT_K[3] * (x[3] + x[7]);
|
||||
x17 = IDCT_K[8] * (x[1] + x[7]);
|
||||
x35 = IDCT_K[9] * (x[3] + x[5]);
|
||||
x1357 = IDCT_C3 * (x[1] + x[3] + x[5] + x[7]);
|
||||
x26 = IDCT_C6 * (x[2] + x[6]);
|
||||
|
||||
f[0] = x[0] + x[4];
|
||||
f[1] = x[0] - x[4];
|
||||
f[2] = x26 + IDCT_K[0] * x[2];
|
||||
f[3] = x26 + IDCT_K[1] * x[6];
|
||||
|
||||
e[0] = x1357 + x15 + IDCT_K[4] * x[1] + x17;
|
||||
e[1] = x1357 + x37 + IDCT_K[6] * x[3] + x35;
|
||||
e[2] = x1357 + x15 + IDCT_K[5] * x[5] + x35;
|
||||
e[3] = x1357 + x37 + IDCT_K[7] * x[7] + x17;
|
||||
|
||||
*dst = f[0] + f[2] + e[0];
|
||||
dst += stride;
|
||||
*dst = f[1] + f[3] + e[1];
|
||||
dst += stride;
|
||||
*dst = f[1] - f[3] + e[2];
|
||||
dst += stride;
|
||||
*dst = f[0] - f[2] + e[3];
|
||||
dst += stride;
|
||||
*dst = f[0] - f[2] - e[3];
|
||||
dst += stride;
|
||||
*dst = f[1] - f[3] - e[2];
|
||||
dst += stride;
|
||||
*dst = f[1] + f[3] - e[1];
|
||||
dst += stride;
|
||||
*dst = f[0] + f[2] - e[0];
|
||||
}
|
||||
|
||||
static void InverseDCTSubBlock(int16_t *dst, const int16_t *src)
|
||||
{
|
||||
float x[8];
|
||||
float block[SUBBLOCK_SIZE];
|
||||
unsigned int i, j;
|
||||
|
||||
/* idct 1d on rows (+transposition) */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (j = 0; j < 8; ++j)
|
||||
x[j] = (float)src[i * 8 + j];
|
||||
|
||||
InverseDCT1D(x, &block[i], 8);
|
||||
}
|
||||
|
||||
/* idct 1d on columns (thanks to previous transposition) */
|
||||
for (i = 0; i < 8; ++i) {
|
||||
InverseDCT1D(&block[i * 8], x, 1);
|
||||
|
||||
/* C4 = 1 normalization implies a division by 8 */
|
||||
for (j = 0; j < 8; ++j)
|
||||
dst[i + j * 8] = (int16_t)x[j] >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void RescaleYSubBlock(int16_t *dst, const int16_t *src)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
dst[i] = (((uint32_t)(clamp_s12(src[i]) + 0x800) * 0xdb0) >> 16) + 0x10;
|
||||
}
|
||||
|
||||
static void RescaleUVSubBlock(int16_t *dst, const int16_t *src)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBBLOCK_SIZE; ++i)
|
||||
dst[i] = (((int)clamp_s12(src[i]) * 0xe00) >> 16) + 0x80;
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - memory.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
/* Global functions */
|
||||
void load_u8(uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*(dst++) = *u8(buffer, address);
|
||||
address += 1;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*(dst++) = *u16(buffer, address);
|
||||
address += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void load_u32(uint32_t* dst, const unsigned char* buffer, unsigned address, size_t count)
|
||||
{
|
||||
/* Optimization for uint32_t */
|
||||
memcpy(dst, u32(buffer, address), count * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void store_u8(unsigned char* buffer, unsigned address, const uint8_t* src, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*u8(buffer, address) = *(src++);
|
||||
address += 1;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void store_u16(unsigned char* buffer, unsigned address, const uint16_t* src, size_t count)
|
||||
{
|
||||
while (count != 0) {
|
||||
*u16(buffer, address) = *(src++);
|
||||
address += 2;
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
void store_u32(unsigned char* buffer, unsigned address, const uint32_t* src, size_t count)
|
||||
{
|
||||
/* Optimization for uint32_t */
|
||||
memcpy(u32(buffer, address), src, count * sizeof(uint32_t));
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - memory.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hle_internal.h"
|
||||
|
||||
#ifdef M64P_BIG_ENDIAN
|
||||
#define S 0
|
||||
#define S16 0
|
||||
#define S8 0
|
||||
#else
|
||||
#define S 1
|
||||
#define S16 2
|
||||
#define S8 3
|
||||
#endif
|
||||
|
||||
enum {
|
||||
TASK_TYPE = 0xfc0,
|
||||
TASK_FLAGS = 0xfc4,
|
||||
TASK_UCODE_BOOT = 0xfc8,
|
||||
TASK_UCODE_BOOT_SIZE = 0xfcc,
|
||||
TASK_UCODE = 0xfd0,
|
||||
TASK_UCODE_SIZE = 0xfd4,
|
||||
TASK_UCODE_DATA = 0xfd8,
|
||||
TASK_UCODE_DATA_SIZE = 0xfdc,
|
||||
TASK_DRAM_STACK = 0xfe0,
|
||||
TASK_DRAM_STACK_SIZE = 0xfe4,
|
||||
TASK_OUTPUT_BUFF = 0xfe8,
|
||||
TASK_OUTPUT_BUFF_SIZE = 0xfec,
|
||||
TASK_DATA_PTR = 0xff0,
|
||||
TASK_DATA_SIZE = 0xff4,
|
||||
TASK_YIELD_DATA_PTR = 0xff8,
|
||||
TASK_YIELD_DATA_SIZE = 0xffc
|
||||
};
|
||||
|
||||
static inline unsigned int align(unsigned int x, unsigned amount)
|
||||
{
|
||||
--amount;
|
||||
return (x + amount) & ~amount;
|
||||
}
|
||||
|
||||
static inline uint8_t* u8(const unsigned char* buffer, unsigned address)
|
||||
{
|
||||
return (uint8_t*)(buffer + (address ^ S8));
|
||||
}
|
||||
|
||||
static inline uint16_t* u16(const unsigned char* buffer, unsigned address)
|
||||
{
|
||||
assert((address & 1) == 0);
|
||||
return (uint16_t*)(buffer + (address ^ S16));
|
||||
}
|
||||
|
||||
static inline uint32_t* u32(const unsigned char* buffer, unsigned address)
|
||||
{
|
||||
assert((address & 3) == 0);
|
||||
return (uint32_t*)(buffer + address);
|
||||
}
|
||||
|
||||
void load_u8 (uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count);
|
||||
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count);
|
||||
void load_u32(uint32_t* dst, const unsigned char* buffer, unsigned address, size_t count);
|
||||
void store_u8 (unsigned char* buffer, unsigned address, const uint8_t* src, size_t count);
|
||||
void store_u16(unsigned char* buffer, unsigned address, const uint16_t* src, size_t count);
|
||||
void store_u32(unsigned char* buffer, unsigned address, const uint32_t* src, size_t count);
|
||||
|
||||
|
||||
/* convenient functions for DMEM access */
|
||||
static inline uint8_t* dmem_u8(struct hle_t* hle, uint16_t address)
|
||||
{
|
||||
return u8(hle->dmem, address & 0xfff);
|
||||
}
|
||||
|
||||
static inline uint16_t* dmem_u16(struct hle_t* hle, uint16_t address)
|
||||
{
|
||||
return u16(hle->dmem, address & 0xfff);
|
||||
}
|
||||
|
||||
static inline uint32_t* dmem_u32(struct hle_t* hle, uint16_t address)
|
||||
{
|
||||
return u32(hle->dmem, address & 0xfff);
|
||||
}
|
||||
|
||||
static inline void dmem_load_u8(struct hle_t* hle, uint8_t* dst, uint16_t address, size_t count)
|
||||
{
|
||||
load_u8(dst, hle->dmem, address & 0xfff, count);
|
||||
}
|
||||
|
||||
static inline void dmem_load_u16(struct hle_t* hle, uint16_t* dst, uint16_t address, size_t count)
|
||||
{
|
||||
load_u16(dst, hle->dmem, address & 0xfff, count);
|
||||
}
|
||||
|
||||
static inline void dmem_load_u32(struct hle_t* hle, uint32_t* dst, uint16_t address, size_t count)
|
||||
{
|
||||
load_u32(dst, hle->dmem, address & 0xfff, count);
|
||||
}
|
||||
|
||||
static inline void dmem_store_u8(struct hle_t* hle, const uint8_t* src, uint16_t address, size_t count)
|
||||
{
|
||||
store_u8(hle->dmem, address & 0xfff, src, count);
|
||||
}
|
||||
|
||||
static inline void dmem_store_u16(struct hle_t* hle, const uint16_t* src, uint16_t address, size_t count)
|
||||
{
|
||||
store_u16(hle->dmem, address & 0xfff, src, count);
|
||||
}
|
||||
|
||||
static inline void dmem_store_u32(struct hle_t* hle, const uint32_t* src, uint16_t address, size_t count)
|
||||
{
|
||||
store_u32(hle->dmem, address & 0xfff, src, count);
|
||||
}
|
||||
|
||||
/* convenient functions DRAM access */
|
||||
static inline uint8_t* dram_u8(struct hle_t* hle, uint32_t address)
|
||||
{
|
||||
return u8(hle->dram, address & 0xffffff);
|
||||
}
|
||||
|
||||
static inline uint16_t* dram_u16(struct hle_t* hle, uint32_t address)
|
||||
{
|
||||
return u16(hle->dram, address & 0xffffff);
|
||||
}
|
||||
|
||||
static inline uint32_t* dram_u32(struct hle_t* hle, uint32_t address)
|
||||
{
|
||||
return u32(hle->dram, address & 0xffffff);
|
||||
}
|
||||
|
||||
static inline void dram_load_u8(struct hle_t* hle, uint8_t* dst, uint32_t address, size_t count)
|
||||
{
|
||||
load_u8(dst, hle->dram, address & 0xffffff, count);
|
||||
}
|
||||
|
||||
static inline void dram_load_u16(struct hle_t* hle, uint16_t* dst, uint32_t address, size_t count)
|
||||
{
|
||||
load_u16(dst, hle->dram, address & 0xffffff, count);
|
||||
}
|
||||
|
||||
static inline void dram_load_u32(struct hle_t* hle, uint32_t* dst, uint32_t address, size_t count)
|
||||
{
|
||||
load_u32(dst, hle->dram, address & 0xffffff, count);
|
||||
}
|
||||
|
||||
static inline void dram_store_u8(struct hle_t* hle, const uint8_t* src, uint32_t address, size_t count)
|
||||
{
|
||||
store_u8(hle->dram, address & 0xffffff, src, count);
|
||||
}
|
||||
|
||||
static inline void dram_store_u16(struct hle_t* hle, const uint16_t* src, uint32_t address, size_t count)
|
||||
{
|
||||
store_u16(hle->dram, address & 0xffffff, src, count);
|
||||
}
|
||||
|
||||
static inline void dram_store_u32(struct hle_t* hle, const uint32_t* src, uint32_t address, size_t count)
|
||||
{
|
||||
store_u32(hle->dram, address & 0xffffff, src, count);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,686 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - mp3.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "arithmetics.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
static void InnerLoop(struct hle_t* hle,
|
||||
uint32_t outPtr, uint32_t inPtr,
|
||||
uint32_t t6, uint32_t t5, uint32_t t4);
|
||||
|
||||
static const uint16_t DeWindowLUT [0x420] = {
|
||||
0x0000, 0xFFF3, 0x005D, 0xFF38, 0x037A, 0xF736, 0x0B37, 0xC00E,
|
||||
0x7FFF, 0x3FF2, 0x0B37, 0x08CA, 0x037A, 0x00C8, 0x005D, 0x000D,
|
||||
0x0000, 0xFFF3, 0x005D, 0xFF38, 0x037A, 0xF736, 0x0B37, 0xC00E,
|
||||
0x7FFF, 0x3FF2, 0x0B37, 0x08CA, 0x037A, 0x00C8, 0x005D, 0x000D,
|
||||
0x0000, 0xFFF2, 0x005F, 0xFF1D, 0x0369, 0xF697, 0x0A2A, 0xBCE7,
|
||||
0x7FEB, 0x3CCB, 0x0C2B, 0x082B, 0x0385, 0x00AF, 0x005B, 0x000B,
|
||||
0x0000, 0xFFF2, 0x005F, 0xFF1D, 0x0369, 0xF697, 0x0A2A, 0xBCE7,
|
||||
0x7FEB, 0x3CCB, 0x0C2B, 0x082B, 0x0385, 0x00AF, 0x005B, 0x000B,
|
||||
0x0000, 0xFFF1, 0x0061, 0xFF02, 0x0354, 0xF5F9, 0x0905, 0xB9C4,
|
||||
0x7FB0, 0x39A4, 0x0D08, 0x078C, 0x038C, 0x0098, 0x0058, 0x000A,
|
||||
0x0000, 0xFFF1, 0x0061, 0xFF02, 0x0354, 0xF5F9, 0x0905, 0xB9C4,
|
||||
0x7FB0, 0x39A4, 0x0D08, 0x078C, 0x038C, 0x0098, 0x0058, 0x000A,
|
||||
0x0000, 0xFFEF, 0x0062, 0xFEE6, 0x033B, 0xF55C, 0x07C8, 0xB6A4,
|
||||
0x7F4D, 0x367E, 0x0DCE, 0x06EE, 0x038F, 0x0080, 0x0056, 0x0009,
|
||||
0x0000, 0xFFEF, 0x0062, 0xFEE6, 0x033B, 0xF55C, 0x07C8, 0xB6A4,
|
||||
0x7F4D, 0x367E, 0x0DCE, 0x06EE, 0x038F, 0x0080, 0x0056, 0x0009,
|
||||
0x0000, 0xFFEE, 0x0063, 0xFECA, 0x031C, 0xF4C3, 0x0671, 0xB38C,
|
||||
0x7EC2, 0x335D, 0x0E7C, 0x0652, 0x038E, 0x006B, 0x0053, 0x0008,
|
||||
0x0000, 0xFFEE, 0x0063, 0xFECA, 0x031C, 0xF4C3, 0x0671, 0xB38C,
|
||||
0x7EC2, 0x335D, 0x0E7C, 0x0652, 0x038E, 0x006B, 0x0053, 0x0008,
|
||||
0x0000, 0xFFEC, 0x0064, 0xFEAC, 0x02F7, 0xF42C, 0x0502, 0xB07C,
|
||||
0x7E12, 0x3041, 0x0F14, 0x05B7, 0x038A, 0x0056, 0x0050, 0x0007,
|
||||
0x0000, 0xFFEC, 0x0064, 0xFEAC, 0x02F7, 0xF42C, 0x0502, 0xB07C,
|
||||
0x7E12, 0x3041, 0x0F14, 0x05B7, 0x038A, 0x0056, 0x0050, 0x0007,
|
||||
0x0000, 0xFFEB, 0x0064, 0xFE8E, 0x02CE, 0xF399, 0x037A, 0xAD75,
|
||||
0x7D3A, 0x2D2C, 0x0F97, 0x0520, 0x0382, 0x0043, 0x004D, 0x0007,
|
||||
0x0000, 0xFFEB, 0x0064, 0xFE8E, 0x02CE, 0xF399, 0x037A, 0xAD75,
|
||||
0x7D3A, 0x2D2C, 0x0F97, 0x0520, 0x0382, 0x0043, 0x004D, 0x0007,
|
||||
0xFFFF, 0xFFE9, 0x0063, 0xFE6F, 0x029E, 0xF30B, 0x01D8, 0xAA7B,
|
||||
0x7C3D, 0x2A1F, 0x1004, 0x048B, 0x0377, 0x0030, 0x004A, 0x0006,
|
||||
0xFFFF, 0xFFE9, 0x0063, 0xFE6F, 0x029E, 0xF30B, 0x01D8, 0xAA7B,
|
||||
0x7C3D, 0x2A1F, 0x1004, 0x048B, 0x0377, 0x0030, 0x004A, 0x0006,
|
||||
0xFFFF, 0xFFE7, 0x0062, 0xFE4F, 0x0269, 0xF282, 0x001F, 0xA78D,
|
||||
0x7B1A, 0x271C, 0x105D, 0x03F9, 0x036A, 0x001F, 0x0046, 0x0006,
|
||||
0xFFFF, 0xFFE7, 0x0062, 0xFE4F, 0x0269, 0xF282, 0x001F, 0xA78D,
|
||||
0x7B1A, 0x271C, 0x105D, 0x03F9, 0x036A, 0x001F, 0x0046, 0x0006,
|
||||
0xFFFF, 0xFFE4, 0x0061, 0xFE2F, 0x022F, 0xF1FF, 0xFE4C, 0xA4AF,
|
||||
0x79D3, 0x2425, 0x10A2, 0x036C, 0x0359, 0x0010, 0x0043, 0x0005,
|
||||
0xFFFF, 0xFFE4, 0x0061, 0xFE2F, 0x022F, 0xF1FF, 0xFE4C, 0xA4AF,
|
||||
0x79D3, 0x2425, 0x10A2, 0x036C, 0x0359, 0x0010, 0x0043, 0x0005,
|
||||
0xFFFF, 0xFFE2, 0x005E, 0xFE10, 0x01EE, 0xF184, 0xFC61, 0xA1E1,
|
||||
0x7869, 0x2139, 0x10D3, 0x02E3, 0x0346, 0x0001, 0x0040, 0x0004,
|
||||
0xFFFF, 0xFFE2, 0x005E, 0xFE10, 0x01EE, 0xF184, 0xFC61, 0xA1E1,
|
||||
0x7869, 0x2139, 0x10D3, 0x02E3, 0x0346, 0x0001, 0x0040, 0x0004,
|
||||
0xFFFF, 0xFFE0, 0x005B, 0xFDF0, 0x01A8, 0xF111, 0xFA5F, 0x9F27,
|
||||
0x76DB, 0x1E5C, 0x10F2, 0x025E, 0x0331, 0xFFF3, 0x003D, 0x0004,
|
||||
0xFFFF, 0xFFE0, 0x005B, 0xFDF0, 0x01A8, 0xF111, 0xFA5F, 0x9F27,
|
||||
0x76DB, 0x1E5C, 0x10F2, 0x025E, 0x0331, 0xFFF3, 0x003D, 0x0004,
|
||||
0xFFFF, 0xFFDE, 0x0057, 0xFDD0, 0x015B, 0xF0A7, 0xF845, 0x9C80,
|
||||
0x752C, 0x1B8E, 0x1100, 0x01DE, 0x0319, 0xFFE7, 0x003A, 0x0003,
|
||||
0xFFFF, 0xFFDE, 0x0057, 0xFDD0, 0x015B, 0xF0A7, 0xF845, 0x9C80,
|
||||
0x752C, 0x1B8E, 0x1100, 0x01DE, 0x0319, 0xFFE7, 0x003A, 0x0003,
|
||||
0xFFFE, 0xFFDB, 0x0053, 0xFDB0, 0x0108, 0xF046, 0xF613, 0x99EE,
|
||||
0x735C, 0x18D1, 0x10FD, 0x0163, 0x0300, 0xFFDC, 0x0037, 0x0003,
|
||||
0xFFFE, 0xFFDB, 0x0053, 0xFDB0, 0x0108, 0xF046, 0xF613, 0x99EE,
|
||||
0x735C, 0x18D1, 0x10FD, 0x0163, 0x0300, 0xFFDC, 0x0037, 0x0003,
|
||||
0xFFFE, 0xFFD8, 0x004D, 0xFD90, 0x00B0, 0xEFF0, 0xF3CC, 0x9775,
|
||||
0x716C, 0x1624, 0x10EA, 0x00EE, 0x02E5, 0xFFD2, 0x0033, 0x0003,
|
||||
0xFFFE, 0xFFD8, 0x004D, 0xFD90, 0x00B0, 0xEFF0, 0xF3CC, 0x9775,
|
||||
0x716C, 0x1624, 0x10EA, 0x00EE, 0x02E5, 0xFFD2, 0x0033, 0x0003,
|
||||
0xFFFE, 0xFFD6, 0x0047, 0xFD72, 0x0051, 0xEFA6, 0xF16F, 0x9514,
|
||||
0x6F5E, 0x138A, 0x10C8, 0x007E, 0x02CA, 0xFFC9, 0x0030, 0x0003,
|
||||
0xFFFE, 0xFFD6, 0x0047, 0xFD72, 0x0051, 0xEFA6, 0xF16F, 0x9514,
|
||||
0x6F5E, 0x138A, 0x10C8, 0x007E, 0x02CA, 0xFFC9, 0x0030, 0x0003,
|
||||
0xFFFE, 0xFFD3, 0x0040, 0xFD54, 0xFFEC, 0xEF68, 0xEEFC, 0x92CD,
|
||||
0x6D33, 0x1104, 0x1098, 0x0014, 0x02AC, 0xFFC0, 0x002D, 0x0002,
|
||||
0xFFFE, 0xFFD3, 0x0040, 0xFD54, 0xFFEC, 0xEF68, 0xEEFC, 0x92CD,
|
||||
0x6D33, 0x1104, 0x1098, 0x0014, 0x02AC, 0xFFC0, 0x002D, 0x0002,
|
||||
0x0030, 0xFFC9, 0x02CA, 0x007E, 0x10C8, 0x138A, 0x6F5E, 0x9514,
|
||||
0xF16F, 0xEFA6, 0x0051, 0xFD72, 0x0047, 0xFFD6, 0xFFFE, 0x0003,
|
||||
0x0030, 0xFFC9, 0x02CA, 0x007E, 0x10C8, 0x138A, 0x6F5E, 0x9514,
|
||||
0xF16F, 0xEFA6, 0x0051, 0xFD72, 0x0047, 0xFFD6, 0xFFFE, 0x0003,
|
||||
0x0033, 0xFFD2, 0x02E5, 0x00EE, 0x10EA, 0x1624, 0x716C, 0x9775,
|
||||
0xF3CC, 0xEFF0, 0x00B0, 0xFD90, 0x004D, 0xFFD8, 0xFFFE, 0x0003,
|
||||
0x0033, 0xFFD2, 0x02E5, 0x00EE, 0x10EA, 0x1624, 0x716C, 0x9775,
|
||||
0xF3CC, 0xEFF0, 0x00B0, 0xFD90, 0x004D, 0xFFD8, 0xFFFE, 0x0003,
|
||||
0x0037, 0xFFDC, 0x0300, 0x0163, 0x10FD, 0x18D1, 0x735C, 0x99EE,
|
||||
0xF613, 0xF046, 0x0108, 0xFDB0, 0x0053, 0xFFDB, 0xFFFE, 0x0003,
|
||||
0x0037, 0xFFDC, 0x0300, 0x0163, 0x10FD, 0x18D1, 0x735C, 0x99EE,
|
||||
0xF613, 0xF046, 0x0108, 0xFDB0, 0x0053, 0xFFDB, 0xFFFE, 0x0003,
|
||||
0x003A, 0xFFE7, 0x0319, 0x01DE, 0x1100, 0x1B8E, 0x752C, 0x9C80,
|
||||
0xF845, 0xF0A7, 0x015B, 0xFDD0, 0x0057, 0xFFDE, 0xFFFF, 0x0003,
|
||||
0x003A, 0xFFE7, 0x0319, 0x01DE, 0x1100, 0x1B8E, 0x752C, 0x9C80,
|
||||
0xF845, 0xF0A7, 0x015B, 0xFDD0, 0x0057, 0xFFDE, 0xFFFF, 0x0004,
|
||||
0x003D, 0xFFF3, 0x0331, 0x025E, 0x10F2, 0x1E5C, 0x76DB, 0x9F27,
|
||||
0xFA5F, 0xF111, 0x01A8, 0xFDF0, 0x005B, 0xFFE0, 0xFFFF, 0x0004,
|
||||
0x003D, 0xFFF3, 0x0331, 0x025E, 0x10F2, 0x1E5C, 0x76DB, 0x9F27,
|
||||
0xFA5F, 0xF111, 0x01A8, 0xFDF0, 0x005B, 0xFFE0, 0xFFFF, 0x0004,
|
||||
0x0040, 0x0001, 0x0346, 0x02E3, 0x10D3, 0x2139, 0x7869, 0xA1E1,
|
||||
0xFC61, 0xF184, 0x01EE, 0xFE10, 0x005E, 0xFFE2, 0xFFFF, 0x0004,
|
||||
0x0040, 0x0001, 0x0346, 0x02E3, 0x10D3, 0x2139, 0x7869, 0xA1E1,
|
||||
0xFC61, 0xF184, 0x01EE, 0xFE10, 0x005E, 0xFFE2, 0xFFFF, 0x0005,
|
||||
0x0043, 0x0010, 0x0359, 0x036C, 0x10A2, 0x2425, 0x79D3, 0xA4AF,
|
||||
0xFE4C, 0xF1FF, 0x022F, 0xFE2F, 0x0061, 0xFFE4, 0xFFFF, 0x0005,
|
||||
0x0043, 0x0010, 0x0359, 0x036C, 0x10A2, 0x2425, 0x79D3, 0xA4AF,
|
||||
0xFE4C, 0xF1FF, 0x022F, 0xFE2F, 0x0061, 0xFFE4, 0xFFFF, 0x0006,
|
||||
0x0046, 0x001F, 0x036A, 0x03F9, 0x105D, 0x271C, 0x7B1A, 0xA78D,
|
||||
0x001F, 0xF282, 0x0269, 0xFE4F, 0x0062, 0xFFE7, 0xFFFF, 0x0006,
|
||||
0x0046, 0x001F, 0x036A, 0x03F9, 0x105D, 0x271C, 0x7B1A, 0xA78D,
|
||||
0x001F, 0xF282, 0x0269, 0xFE4F, 0x0062, 0xFFE7, 0xFFFF, 0x0006,
|
||||
0x004A, 0x0030, 0x0377, 0x048B, 0x1004, 0x2A1F, 0x7C3D, 0xAA7B,
|
||||
0x01D8, 0xF30B, 0x029E, 0xFE6F, 0x0063, 0xFFE9, 0xFFFF, 0x0006,
|
||||
0x004A, 0x0030, 0x0377, 0x048B, 0x1004, 0x2A1F, 0x7C3D, 0xAA7B,
|
||||
0x01D8, 0xF30B, 0x029E, 0xFE6F, 0x0063, 0xFFE9, 0xFFFF, 0x0007,
|
||||
0x004D, 0x0043, 0x0382, 0x0520, 0x0F97, 0x2D2C, 0x7D3A, 0xAD75,
|
||||
0x037A, 0xF399, 0x02CE, 0xFE8E, 0x0064, 0xFFEB, 0x0000, 0x0007,
|
||||
0x004D, 0x0043, 0x0382, 0x0520, 0x0F97, 0x2D2C, 0x7D3A, 0xAD75,
|
||||
0x037A, 0xF399, 0x02CE, 0xFE8E, 0x0064, 0xFFEB, 0x0000, 0x0007,
|
||||
0x0050, 0x0056, 0x038A, 0x05B7, 0x0F14, 0x3041, 0x7E12, 0xB07C,
|
||||
0x0502, 0xF42C, 0x02F7, 0xFEAC, 0x0064, 0xFFEC, 0x0000, 0x0007,
|
||||
0x0050, 0x0056, 0x038A, 0x05B7, 0x0F14, 0x3041, 0x7E12, 0xB07C,
|
||||
0x0502, 0xF42C, 0x02F7, 0xFEAC, 0x0064, 0xFFEC, 0x0000, 0x0008,
|
||||
0x0053, 0x006B, 0x038E, 0x0652, 0x0E7C, 0x335D, 0x7EC2, 0xB38C,
|
||||
0x0671, 0xF4C3, 0x031C, 0xFECA, 0x0063, 0xFFEE, 0x0000, 0x0008,
|
||||
0x0053, 0x006B, 0x038E, 0x0652, 0x0E7C, 0x335D, 0x7EC2, 0xB38C,
|
||||
0x0671, 0xF4C3, 0x031C, 0xFECA, 0x0063, 0xFFEE, 0x0000, 0x0009,
|
||||
0x0056, 0x0080, 0x038F, 0x06EE, 0x0DCE, 0x367E, 0x7F4D, 0xB6A4,
|
||||
0x07C8, 0xF55C, 0x033B, 0xFEE6, 0x0062, 0xFFEF, 0x0000, 0x0009,
|
||||
0x0056, 0x0080, 0x038F, 0x06EE, 0x0DCE, 0x367E, 0x7F4D, 0xB6A4,
|
||||
0x07C8, 0xF55C, 0x033B, 0xFEE6, 0x0062, 0xFFEF, 0x0000, 0x000A,
|
||||
0x0058, 0x0098, 0x038C, 0x078C, 0x0D08, 0x39A4, 0x7FB0, 0xB9C4,
|
||||
0x0905, 0xF5F9, 0x0354, 0xFF02, 0x0061, 0xFFF1, 0x0000, 0x000A,
|
||||
0x0058, 0x0098, 0x038C, 0x078C, 0x0D08, 0x39A4, 0x7FB0, 0xB9C4,
|
||||
0x0905, 0xF5F9, 0x0354, 0xFF02, 0x0061, 0xFFF1, 0x0000, 0x000B,
|
||||
0x005B, 0x00AF, 0x0385, 0x082B, 0x0C2B, 0x3CCB, 0x7FEB, 0xBCE7,
|
||||
0x0A2A, 0xF697, 0x0369, 0xFF1D, 0x005F, 0xFFF2, 0x0000, 0x000B,
|
||||
0x005B, 0x00AF, 0x0385, 0x082B, 0x0C2B, 0x3CCB, 0x7FEB, 0xBCE7,
|
||||
0x0A2A, 0xF697, 0x0369, 0xFF1D, 0x005F, 0xFFF2, 0x0000, 0x000D,
|
||||
0x005D, 0x00C8, 0x037A, 0x08CA, 0x0B37, 0x3FF2, 0x7FFF, 0xC00E,
|
||||
0x0B37, 0xF736, 0x037A, 0xFF38, 0x005D, 0xFFF3, 0x0000, 0x000D,
|
||||
0x005D, 0x00C8, 0x037A, 0x08CA, 0x0B37, 0x3FF2, 0x7FFF, 0xC00E,
|
||||
0x0B37, 0xF736, 0x037A, 0xFF38, 0x005D, 0xFFF3, 0x0000, 0x0000
|
||||
};
|
||||
|
||||
static void MP3AB0(int32_t* v)
|
||||
{
|
||||
/* Part 2 - 100% Accurate */
|
||||
static const uint16_t LUT2[8] = {
|
||||
0xFEC4, 0xF4FA, 0xC5E4, 0xE1C4,
|
||||
0x1916, 0x4A50, 0xA268, 0x78AE
|
||||
};
|
||||
static const uint16_t LUT3[4] = { 0xFB14, 0xD4DC, 0x31F2, 0x8E3A };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[16 + i] = v[0 + i] + v[8 + i];
|
||||
v[24 + i] = ((v[0 + i] - v[8 + i]) * LUT2[i]) >> 0x10;
|
||||
}
|
||||
|
||||
/* Part 3: 4-wide butterflies */
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v[0 + i] = v[16 + i] + v[20 + i];
|
||||
v[4 + i] = ((v[16 + i] - v[20 + i]) * LUT3[i]) >> 0x10;
|
||||
|
||||
v[8 + i] = v[24 + i] + v[28 + i];
|
||||
v[12 + i] = ((v[24 + i] - v[28 + i]) * LUT3[i]) >> 0x10;
|
||||
}
|
||||
|
||||
/* Part 4: 2-wide butterflies - 100% Accurate */
|
||||
|
||||
for (i = 0; i < 16; i += 4) {
|
||||
v[16 + i] = v[0 + i] + v[2 + i];
|
||||
v[18 + i] = ((v[0 + i] - v[2 + i]) * 0xEC84) >> 0x10;
|
||||
|
||||
v[17 + i] = v[1 + i] + v[3 + i];
|
||||
v[19 + i] = ((v[1 + i] - v[3 + i]) * 0x61F8) >> 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address)
|
||||
{
|
||||
uint32_t inPtr, outPtr;
|
||||
uint32_t t6;/* = 0x08A0; - I think these are temporary storage buffers */
|
||||
uint32_t t5;/* = 0x0AC0; */
|
||||
uint32_t t4;/* = (w1 & 0x1E); */
|
||||
|
||||
/* Initialization Code */
|
||||
uint32_t readPtr; /* s5 */
|
||||
uint32_t writePtr; /* s6 */
|
||||
uint32_t tmp;
|
||||
int cnt, cnt2;
|
||||
|
||||
/* I think these are temporary storage buffers */
|
||||
t6 = 0x08A0;
|
||||
t5 = 0x0AC0;
|
||||
t4 = index;
|
||||
|
||||
writePtr = readPtr = address;
|
||||
/* Just do that for efficiency... may remove and use directly later anyway */
|
||||
memcpy(hle->mp3_buffer + 0xCE8, hle->dram + readPtr, 8);
|
||||
/* This must be a header byte or whatnot */
|
||||
readPtr += 8;
|
||||
|
||||
for (cnt = 0; cnt < 0x480; cnt += 0x180) {
|
||||
/* DMA: 0xCF0 <- RDRAM[s5] : 0x180 */
|
||||
memcpy(hle->mp3_buffer + 0xCF0, hle->dram + readPtr, 0x180);
|
||||
inPtr = 0xCF0; /* s7 */
|
||||
outPtr = 0xE70; /* s3 */
|
||||
/* --------------- Inner Loop Start -------------------- */
|
||||
for (cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) {
|
||||
t6 &= 0xFFE0;
|
||||
t5 &= 0xFFE0;
|
||||
t6 |= t4;
|
||||
t5 |= t4;
|
||||
InnerLoop(hle, outPtr, inPtr, t6, t5, t4);
|
||||
t4 = (t4 - 2) & 0x1E;
|
||||
tmp = t6;
|
||||
t6 = t5;
|
||||
t5 = tmp;
|
||||
inPtr += 0x40;
|
||||
outPtr += 0x40;
|
||||
}
|
||||
/* --------------- Inner Loop End -------------------- */
|
||||
memcpy(hle->dram + writePtr, hle->mp3_buffer + 0xe70, 0x180);
|
||||
writePtr += 0x180;
|
||||
readPtr += 0x180;
|
||||
}
|
||||
}
|
||||
|
||||
static void InnerLoop(struct hle_t* hle,
|
||||
uint32_t outPtr, uint32_t inPtr,
|
||||
uint32_t t6, uint32_t t5, uint32_t t4)
|
||||
{
|
||||
/* Part 1: 100% Accurate */
|
||||
|
||||
/* 0, 1, 3, 2, 7, 6, 4, 5, 7, 6, 4, 5, 0, 1, 3, 2 */
|
||||
static const uint16_t LUT6[16] = {
|
||||
0xFFB2, 0xFD3A, 0xF10A, 0xF854,
|
||||
0xBDAE, 0xCDA0, 0xE76C, 0xDB94,
|
||||
0x1920, 0x4B20, 0xAC7C, 0x7C68,
|
||||
0xABEC, 0x9880, 0xDAE8, 0x839C
|
||||
};
|
||||
int i;
|
||||
uint32_t t0;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t t3;
|
||||
int32_t v2 = 0, v4 = 0, v6 = 0, v8 = 0;
|
||||
uint32_t offset;
|
||||
uint32_t addptr;
|
||||
int x;
|
||||
int32_t mult6;
|
||||
int32_t mult4;
|
||||
int tmp;
|
||||
int32_t hi0;
|
||||
int32_t hi1;
|
||||
int32_t vt;
|
||||
int32_t v[32];
|
||||
|
||||
v[0] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x00 ^ S16));
|
||||
v[31] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3E ^ S16));
|
||||
v[0] += v[31];
|
||||
v[1] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x02 ^ S16));
|
||||
v[30] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3C ^ S16));
|
||||
v[1] += v[30];
|
||||
v[2] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x06 ^ S16));
|
||||
v[28] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x38 ^ S16));
|
||||
v[2] += v[28];
|
||||
v[3] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x04 ^ S16));
|
||||
v[29] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3A ^ S16));
|
||||
v[3] += v[29];
|
||||
|
||||
v[4] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0E ^ S16));
|
||||
v[24] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x30 ^ S16));
|
||||
v[4] += v[24];
|
||||
v[5] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0C ^ S16));
|
||||
v[25] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x32 ^ S16));
|
||||
v[5] += v[25];
|
||||
v[6] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x08 ^ S16));
|
||||
v[27] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x36 ^ S16));
|
||||
v[6] += v[27];
|
||||
v[7] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0A ^ S16));
|
||||
v[26] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x34 ^ S16));
|
||||
v[7] += v[26];
|
||||
|
||||
v[8] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1E ^ S16));
|
||||
v[16] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x20 ^ S16));
|
||||
v[8] += v[16];
|
||||
v[9] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1C ^ S16));
|
||||
v[17] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x22 ^ S16));
|
||||
v[9] += v[17];
|
||||
v[10] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x18 ^ S16));
|
||||
v[19] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x26 ^ S16));
|
||||
v[10] += v[19];
|
||||
v[11] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1A ^ S16));
|
||||
v[18] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x24 ^ S16));
|
||||
v[11] += v[18];
|
||||
|
||||
v[12] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x10 ^ S16));
|
||||
v[23] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2E ^ S16));
|
||||
v[12] += v[23];
|
||||
v[13] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x12 ^ S16));
|
||||
v[22] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2C ^ S16));
|
||||
v[13] += v[22];
|
||||
v[14] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x16 ^ S16));
|
||||
v[20] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x28 ^ S16));
|
||||
v[14] += v[20];
|
||||
v[15] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x14 ^ S16));
|
||||
v[21] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2A ^ S16));
|
||||
v[15] += v[21];
|
||||
|
||||
/* Part 2-4 */
|
||||
|
||||
MP3AB0(v);
|
||||
|
||||
/* Part 5 - 1-Wide Butterflies - 100% Accurate but need SSVs!!! */
|
||||
|
||||
t0 = t6 + 0x100;
|
||||
t1 = t6 + 0x200;
|
||||
t2 = t5 + 0x100;
|
||||
t3 = t5 + 0x200;
|
||||
|
||||
/* 0x13A8 */
|
||||
v[1] = 0;
|
||||
v[11] = ((v[16] - v[17]) * 0xB504) >> 0x10;
|
||||
|
||||
v[16] = -v[16] - v[17];
|
||||
v[2] = v[18] + v[19];
|
||||
/* ** Store v[11] -> (T6 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x0))) = (short)v[11];
|
||||
|
||||
|
||||
v[11] = -v[11];
|
||||
/* ** Store v[16] -> (T3 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0x0))) = (short)v[16];
|
||||
/* ** Store v[11] -> (T5 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x0))) = (short)v[11];
|
||||
/* 0x13E8 - Verified.... */
|
||||
v[2] = -v[2];
|
||||
/* ** Store v[2] -> (T2 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x0))) = (short)v[2];
|
||||
v[3] = (((v[18] - v[19]) * 0x16A09) >> 0x10) + v[2];
|
||||
/* ** Store v[3] -> (T0 + 0)** */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x0))) = (short)v[3];
|
||||
/* 0x1400 - Verified */
|
||||
v[4] = -v[20] - v[21];
|
||||
v[6] = v[22] + v[23];
|
||||
v[5] = ((v[20] - v[21]) * 0x16A09) >> 0x10;
|
||||
/* ** Store v[4] -> (T3 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFF80))) = (short)v[4];
|
||||
v[7] = ((v[22] - v[23]) * 0x2D413) >> 0x10;
|
||||
v[5] = v[5] - v[4];
|
||||
v[7] = v[7] - v[5];
|
||||
v[6] = v[6] + v[6];
|
||||
v[5] = v[5] - v[6];
|
||||
v[4] = -v[4] - v[6];
|
||||
/* *** Store v[7] -> (T1 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFF80))) = (short)v[7];
|
||||
/* *** Store v[4] -> (T2 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFF80))) = (short)v[4];
|
||||
/* *** Store v[5] -> (T0 + 0xFF80) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFF80))) = (short)v[5];
|
||||
v[8] = v[24] + v[25];
|
||||
|
||||
|
||||
v[9] = ((v[24] - v[25]) * 0x16A09) >> 0x10;
|
||||
v[2] = v[8] + v[9];
|
||||
v[11] = ((v[26] - v[27]) * 0x2D413) >> 0x10;
|
||||
v[13] = ((v[28] - v[29]) * 0x2D413) >> 0x10;
|
||||
|
||||
v[10] = v[26] + v[27];
|
||||
v[10] = v[10] + v[10];
|
||||
v[12] = v[28] + v[29];
|
||||
v[12] = v[12] + v[12];
|
||||
v[14] = v[30] + v[31];
|
||||
v[3] = v[8] + v[10];
|
||||
v[14] = v[14] + v[14];
|
||||
v[13] = (v[13] - v[2]) + v[12];
|
||||
v[15] = (((v[30] - v[31]) * 0x5A827) >> 0x10) - (v[11] + v[2]);
|
||||
v[14] = -(v[14] + v[14]) + v[3];
|
||||
v[17] = v[13] - v[10];
|
||||
v[9] = v[9] + v[14];
|
||||
/* ** Store v[9] -> (T6 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x40))) = (short)v[9];
|
||||
v[11] = v[11] - v[13];
|
||||
/* ** Store v[17] -> (T0 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFFC0))) = (short)v[17];
|
||||
v[12] = v[8] - v[12];
|
||||
/* ** Store v[11] -> (T0 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x40))) = (short)v[11];
|
||||
v[8] = -v[8];
|
||||
/* ** Store v[15] -> (T1 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFFC0))) = (short)v[15];
|
||||
v[10] = -v[10] - v[12];
|
||||
/* ** Store v[12] -> (T2 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x40))) = (short)v[12];
|
||||
/* ** Store v[8] -> (T3 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFFC0))) = (short)v[8];
|
||||
/* ** Store v[14] -> (T5 + 0x40) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x40))) = (short)v[14];
|
||||
/* ** Store v[10] -> (T2 + 0xFFC0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFFC0))) = (short)v[10];
|
||||
/* 0x14FC - Verified... */
|
||||
|
||||
/* Part 6 - 100% Accurate */
|
||||
|
||||
v[0] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x00 ^ S16));
|
||||
v[31] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3E ^ S16));
|
||||
v[0] -= v[31];
|
||||
v[1] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x02 ^ S16));
|
||||
v[30] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3C ^ S16));
|
||||
v[1] -= v[30];
|
||||
v[2] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x06 ^ S16));
|
||||
v[28] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x38 ^ S16));
|
||||
v[2] -= v[28];
|
||||
v[3] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x04 ^ S16));
|
||||
v[29] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x3A ^ S16));
|
||||
v[3] -= v[29];
|
||||
|
||||
v[4] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0E ^ S16));
|
||||
v[24] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x30 ^ S16));
|
||||
v[4] -= v[24];
|
||||
v[5] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0C ^ S16));
|
||||
v[25] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x32 ^ S16));
|
||||
v[5] -= v[25];
|
||||
v[6] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x08 ^ S16));
|
||||
v[27] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x36 ^ S16));
|
||||
v[6] -= v[27];
|
||||
v[7] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x0A ^ S16));
|
||||
v[26] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x34 ^ S16));
|
||||
v[7] -= v[26];
|
||||
|
||||
v[8] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1E ^ S16));
|
||||
v[16] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x20 ^ S16));
|
||||
v[8] -= v[16];
|
||||
v[9] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1C ^ S16));
|
||||
v[17] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x22 ^ S16));
|
||||
v[9] -= v[17];
|
||||
v[10] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x18 ^ S16));
|
||||
v[19] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x26 ^ S16));
|
||||
v[10] -= v[19];
|
||||
v[11] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x1A ^ S16));
|
||||
v[18] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x24 ^ S16));
|
||||
v[11] -= v[18];
|
||||
|
||||
v[12] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x10 ^ S16));
|
||||
v[23] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2E ^ S16));
|
||||
v[12] -= v[23];
|
||||
v[13] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x12 ^ S16));
|
||||
v[22] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2C ^ S16));
|
||||
v[13] -= v[22];
|
||||
v[14] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x16 ^ S16));
|
||||
v[20] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x28 ^ S16));
|
||||
v[14] -= v[20];
|
||||
v[15] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x14 ^ S16));
|
||||
v[21] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x2A ^ S16));
|
||||
v[15] -= v[21];
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
v[0 + i] = (v[0 + i] * LUT6[i]) >> 0x10;
|
||||
v[0] = v[0] + v[0];
|
||||
v[1] = v[1] + v[1];
|
||||
v[2] = v[2] + v[2];
|
||||
v[3] = v[3] + v[3];
|
||||
v[4] = v[4] + v[4];
|
||||
v[5] = v[5] + v[5];
|
||||
v[6] = v[6] + v[6];
|
||||
v[7] = v[7] + v[7];
|
||||
v[12] = v[12] + v[12];
|
||||
v[13] = v[13] + v[13];
|
||||
v[15] = v[15] + v[15];
|
||||
|
||||
MP3AB0(v);
|
||||
|
||||
/* Part 7: - 100% Accurate + SSV - Unoptimized */
|
||||
|
||||
v[0] = (v[17] + v[16]) >> 1;
|
||||
v[1] = ((v[17] * (int)((short)0xA57E * 2)) + (v[16] * 0xB504)) >> 0x10;
|
||||
v[2] = -v[18] - v[19];
|
||||
v[3] = ((v[18] - v[19]) * 0x16A09) >> 0x10;
|
||||
v[4] = v[20] + v[21] + v[0];
|
||||
v[5] = (((v[20] - v[21]) * 0x16A09) >> 0x10) + v[1];
|
||||
v[6] = (((v[22] + v[23]) << 1) + v[0]) - v[2];
|
||||
v[7] = (((v[22] - v[23]) * 0x2D413) >> 0x10) + v[0] + v[1] + v[3];
|
||||
/* 0x16A8 */
|
||||
/* Save v[0] -> (T3 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFFE0))) = (short) - v[0];
|
||||
v[8] = v[24] + v[25];
|
||||
v[9] = ((v[24] - v[25]) * 0x16A09) >> 0x10;
|
||||
v[10] = ((v[26] + v[27]) << 1) + v[8];
|
||||
v[11] = (((v[26] - v[27]) * 0x2D413) >> 0x10) + v[8] + v[9];
|
||||
v[12] = v[4] - ((v[28] + v[29]) << 1);
|
||||
/* ** Store v12 -> (T2 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x20))) = (short)v[12];
|
||||
v[13] = (((v[28] - v[29]) * 0x2D413) >> 0x10) - v[12] - v[5];
|
||||
v[14] = v[30] + v[31];
|
||||
v[14] = v[14] + v[14];
|
||||
v[14] = v[14] + v[14];
|
||||
v[14] = v[6] - v[14];
|
||||
v[15] = (((v[30] - v[31]) * 0x5A827) >> 0x10) - v[7];
|
||||
/* Store v14 -> (T5 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x20))) = (short)v[14];
|
||||
v[14] = v[14] + v[1];
|
||||
/* Store v[14] -> (T6 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x20))) = (short)v[14];
|
||||
/* Store v[15] -> (T1 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFFE0))) = (short)v[15];
|
||||
v[9] = v[9] + v[10];
|
||||
v[1] = v[1] + v[6];
|
||||
v[6] = v[10] - v[6];
|
||||
v[1] = v[9] - v[1];
|
||||
/* Store v[6] -> (T5 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t5 + (short)0x60))) = (short)v[6];
|
||||
v[10] = v[10] + v[2];
|
||||
v[10] = v[4] - v[10];
|
||||
/* Store v[10] -> (T2 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFFA0))) = (short)v[10];
|
||||
v[12] = v[2] - v[12];
|
||||
/* Store v[12] -> (T2 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0xFFE0))) = (short)v[12];
|
||||
v[5] = v[4] + v[5];
|
||||
v[4] = v[8] - v[4];
|
||||
/* Store v[4] -> (T2 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t2 + (short)0x60))) = (short)v[4];
|
||||
v[0] = v[0] - v[8];
|
||||
/* Store v[0] -> (T3 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t3 + (short)0xFFA0))) = (short)v[0];
|
||||
v[7] = v[7] - v[11];
|
||||
/* Store v[7] -> (T1 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t1 + (short)0xFFA0))) = (short)v[7];
|
||||
v[11] = v[11] - v[3];
|
||||
/* Store v[1] -> (T6 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t6 + (short)0x60))) = (short)v[1];
|
||||
v[11] = v[11] - v[5];
|
||||
/* Store v[11] -> (T0 + 0x60) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x60))) = (short)v[11];
|
||||
v[3] = v[3] - v[13];
|
||||
/* Store v[3] -> (T0 + 0x20) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0x20))) = (short)v[3];
|
||||
v[13] = v[13] + v[2];
|
||||
/* Store v[13] -> (T0 + 0xFFE0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFFE0))) = (short)v[13];
|
||||
v[2] = (v[5] - v[2]) - v[9];
|
||||
/* Store v[2] -> (T0 + 0xFFA0) */
|
||||
*(int16_t *)(hle->mp3_buffer + ((t0 + (short)0xFFA0))) = (short)v[2];
|
||||
/* 0x7A8 - Verified... */
|
||||
|
||||
/* Step 8 - Dewindowing */
|
||||
|
||||
addptr = t6 & 0xFFE0;
|
||||
|
||||
offset = 0x10 - (t4 >> 1);
|
||||
for (x = 0; x < 8; x++) {
|
||||
int32_t v0;
|
||||
int32_t v18;
|
||||
v2 = v4 = v6 = v8 = 0;
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
v6 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x20) * (short)DeWindowLUT[offset + 0x20] + 0x4000) >> 0xF;
|
||||
v8 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x30) * (short)DeWindowLUT[offset + 0x28] + 0x4000) >> 0xF;
|
||||
addptr += 2;
|
||||
offset++;
|
||||
}
|
||||
v0 = v2 + v4;
|
||||
v18 = v6 + v8;
|
||||
/* Clamp(v0); */
|
||||
/* Clamp(v18); */
|
||||
/* clamp??? */
|
||||
*(int16_t *)(hle->mp3_buffer + (outPtr ^ S16)) = v0;
|
||||
*(int16_t *)(hle->mp3_buffer + ((outPtr + 2)^S16)) = v18;
|
||||
outPtr += 4;
|
||||
addptr += 0x30;
|
||||
offset += 0x38;
|
||||
}
|
||||
|
||||
offset = 0x10 - (t4 >> 1) + 8 * 0x40;
|
||||
v2 = v4 = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
addptr += 2;
|
||||
offset++;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
addptr += 2;
|
||||
offset++;
|
||||
}
|
||||
mult6 = *(int32_t *)(hle->mp3_buffer + 0xCE8);
|
||||
mult4 = *(int32_t *)(hle->mp3_buffer + 0xCEC);
|
||||
if (t4 & 0x2) {
|
||||
v2 = (v2 **(uint32_t *)(hle->mp3_buffer + 0xCE8)) >> 0x10;
|
||||
*(int16_t *)(hle->mp3_buffer + (outPtr ^ S16)) = v2;
|
||||
} else {
|
||||
v4 = (v4 **(uint32_t *)(hle->mp3_buffer + 0xCE8)) >> 0x10;
|
||||
*(int16_t *)(hle->mp3_buffer + (outPtr ^ S16)) = v4;
|
||||
mult4 = *(uint32_t *)(hle->mp3_buffer + 0xCE8);
|
||||
}
|
||||
addptr -= 0x50;
|
||||
|
||||
for (x = 0; x < 8; x++) {
|
||||
int32_t v0;
|
||||
int32_t v18;
|
||||
v2 = v4 = v6 = v8 = 0;
|
||||
|
||||
offset = (0x22F - (t4 >> 1) + x * 0x40);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v2 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x20) * (short)DeWindowLUT[offset + 0x00] + 0x4000) >> 0xF;
|
||||
v2 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x20) * (short)DeWindowLUT[offset + 0x01] + 0x4000) >> 0xF;
|
||||
v4 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x30) * (short)DeWindowLUT[offset + 0x08] + 0x4000) >> 0xF;
|
||||
v4 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x30) * (short)DeWindowLUT[offset + 0x09] + 0x4000) >> 0xF;
|
||||
v6 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x00) * (short)DeWindowLUT[offset + 0x20] + 0x4000) >> 0xF;
|
||||
v6 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x00) * (short)DeWindowLUT[offset + 0x21] + 0x4000) >> 0xF;
|
||||
v8 += ((int) * (int16_t *)(hle->mp3_buffer + (addptr) + 0x10) * (short)DeWindowLUT[offset + 0x28] + 0x4000) >> 0xF;
|
||||
v8 -= ((int) * (int16_t *)(hle->mp3_buffer + ((addptr + 2)) + 0x10) * (short)DeWindowLUT[offset + 0x29] + 0x4000) >> 0xF;
|
||||
addptr += 4;
|
||||
offset += 2;
|
||||
}
|
||||
v0 = v2 + v4;
|
||||
v18 = v6 + v8;
|
||||
/* Clamp(v0); */
|
||||
/* Clamp(v18); */
|
||||
/* clamp??? */
|
||||
*(int16_t *)(hle->mp3_buffer + ((outPtr + 2)^S16)) = v0;
|
||||
*(int16_t *)(hle->mp3_buffer + ((outPtr + 4)^S16)) = v18;
|
||||
outPtr += 4;
|
||||
addptr -= 0x50;
|
||||
}
|
||||
|
||||
tmp = outPtr;
|
||||
hi0 = mult6;
|
||||
hi1 = mult4;
|
||||
|
||||
hi0 = (int)hi0 >> 0x10;
|
||||
hi1 = (int)hi1 >> 0x10;
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* v0 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x40)^S16)) = clamp_s16(vt);
|
||||
|
||||
/* v17 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x30)^S16)) * hi0);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x30)^S16)) = clamp_s16(vt);
|
||||
|
||||
/* v2 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x1E)^S16)) * hi1);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x1E)^S16)) = clamp_s16(vt);
|
||||
|
||||
/* v4 */
|
||||
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0xE)^S16)) * hi1);
|
||||
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0xE)^S16)) = clamp_s16(vt);
|
||||
|
||||
tmp += 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,985 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - musyx.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2013 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "arithmetics.h"
|
||||
#include "audio.h"
|
||||
#include "hle_external.h"
|
||||
#include "hle_internal.h"
|
||||
#include "memory.h"
|
||||
|
||||
/* various constants */
|
||||
enum { SUBFRAME_SIZE = 192 };
|
||||
enum { MAX_VOICES = 32 };
|
||||
|
||||
enum { SAMPLE_BUFFER_SIZE = 0x200 };
|
||||
|
||||
|
||||
enum {
|
||||
SFD_VOICE_COUNT = 0x0,
|
||||
SFD_SFX_INDEX = 0x2,
|
||||
SFD_VOICE_BITMASK = 0x4,
|
||||
SFD_STATE_PTR = 0x8,
|
||||
SFD_SFX_PTR = 0xc,
|
||||
SFD_VOICES = 0x10,
|
||||
|
||||
/* v2 only */
|
||||
SFD2_10_PTR = 0x10,
|
||||
SFD2_14_BITMASK = 0x14,
|
||||
SFD2_15_BITMASK = 0x15,
|
||||
SFD2_16_BITMASK = 0x16,
|
||||
SFD2_18_PTR = 0x18,
|
||||
SFD2_1C_PTR = 0x1c,
|
||||
SFD2_20_PTR = 0x20,
|
||||
SFD2_24_PTR = 0x24,
|
||||
SFD2_VOICES = 0x28
|
||||
};
|
||||
|
||||
enum {
|
||||
VOICE_ENV_BEGIN = 0x00,
|
||||
VOICE_ENV_STEP = 0x10,
|
||||
VOICE_PITCH_Q16 = 0x20,
|
||||
VOICE_PITCH_SHIFT = 0x22,
|
||||
VOICE_CATSRC_0 = 0x24,
|
||||
VOICE_CATSRC_1 = 0x30,
|
||||
VOICE_ADPCM_FRAMES = 0x3c,
|
||||
VOICE_SKIP_SAMPLES = 0x3e,
|
||||
|
||||
/* for PCM16 */
|
||||
VOICE_U16_40 = 0x40,
|
||||
VOICE_U16_42 = 0x42,
|
||||
|
||||
/* for ADPCM */
|
||||
VOICE_ADPCM_TABLE_PTR = 0x40,
|
||||
|
||||
VOICE_INTERLEAVED_PTR = 0x44,
|
||||
VOICE_END_POINT = 0x48,
|
||||
VOICE_RESTART_POINT = 0x4a,
|
||||
VOICE_U16_4C = 0x4c,
|
||||
VOICE_U16_4E = 0x4e,
|
||||
|
||||
VOICE_SIZE = 0x50
|
||||
};
|
||||
|
||||
enum {
|
||||
CATSRC_PTR1 = 0x00,
|
||||
CATSRC_PTR2 = 0x04,
|
||||
CATSRC_SIZE1 = 0x08,
|
||||
CATSRC_SIZE2 = 0x0a
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_LAST_SAMPLE = 0x0,
|
||||
STATE_BASE_VOL = 0x100,
|
||||
STATE_CC0 = 0x110,
|
||||
STATE_740_LAST4_V1 = 0x290,
|
||||
|
||||
STATE_740_LAST4_V2 = 0x110
|
||||
};
|
||||
|
||||
enum {
|
||||
SFX_CBUFFER_PTR = 0x00,
|
||||
SFX_CBUFFER_LENGTH = 0x04,
|
||||
SFX_TAP_COUNT = 0x08,
|
||||
SFX_FIR4_HGAIN = 0x0a,
|
||||
SFX_TAP_DELAYS = 0x0c,
|
||||
SFX_TAP_GAINS = 0x2c,
|
||||
SFX_U16_3C = 0x3c,
|
||||
SFX_U16_3E = 0x3e,
|
||||
SFX_FIR4_HCOEFFS = 0x40
|
||||
};
|
||||
|
||||
|
||||
/* struct definition */
|
||||
typedef struct {
|
||||
/* internal subframes */
|
||||
int16_t left[SUBFRAME_SIZE];
|
||||
int16_t right[SUBFRAME_SIZE];
|
||||
int16_t cc0[SUBFRAME_SIZE];
|
||||
int16_t e50[SUBFRAME_SIZE];
|
||||
|
||||
/* internal subframes base volumes */
|
||||
int32_t base_vol[4];
|
||||
|
||||
/* */
|
||||
int16_t subframe_740_last4[4];
|
||||
} musyx_t;
|
||||
|
||||
typedef void (*mix_sfx_with_main_subframes_t)(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains);
|
||||
|
||||
/* helper functions prototypes */
|
||||
static void load_base_vol(struct hle_t* hle, int32_t *base_vol, uint32_t address);
|
||||
static void save_base_vol(struct hle_t* hle, const int32_t *base_vol, uint32_t address);
|
||||
static void update_base_vol(struct hle_t* hle, int32_t *base_vol,
|
||||
uint32_t voice_mask, uint32_t last_sample_ptr,
|
||||
uint8_t mask_15, uint32_t ptr_24);
|
||||
|
||||
static void init_subframes_v1(musyx_t *musyx);
|
||||
static void init_subframes_v2(musyx_t *musyx);
|
||||
|
||||
static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, uint32_t last_sample_ptr);
|
||||
|
||||
static void dma_cat8(struct hle_t* hle, uint8_t *dst, uint32_t catsrc_ptr);
|
||||
static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr);
|
||||
|
||||
static void load_samples_PCM16(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset);
|
||||
static void load_samples_ADPCM(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset);
|
||||
|
||||
static void adpcm_decode_frames(struct hle_t* hle,
|
||||
int16_t *dst, const uint8_t *src,
|
||||
const int16_t *table, uint8_t count,
|
||||
uint8_t skip_samples);
|
||||
|
||||
static void adpcm_predict_frame(int16_t *dst, const uint8_t *src,
|
||||
const uint8_t *nibbles,
|
||||
unsigned int rshift);
|
||||
|
||||
static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, const int16_t *samples,
|
||||
unsigned segbase, unsigned offset, uint32_t last_sample_ptr);
|
||||
|
||||
static void sfx_stage(struct hle_t* hle,
|
||||
mix_sfx_with_main_subframes_t mix_sfx_with_main_subframes,
|
||||
musyx_t *musyx, uint32_t sfx_ptr, uint16_t idx);
|
||||
|
||||
static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains);
|
||||
static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains);
|
||||
|
||||
static void mix_samples(int16_t *y, int16_t x, int16_t hgain);
|
||||
static void mix_subframes(int16_t *y, const int16_t *x, int16_t hgain);
|
||||
static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t *hcoeffs);
|
||||
|
||||
|
||||
static void interleave_stage_v1(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t output_ptr);
|
||||
|
||||
static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
|
||||
uint16_t mask_16, uint32_t ptr_18,
|
||||
uint32_t ptr_1c, uint32_t output_ptr);
|
||||
|
||||
static int32_t dot4(const int16_t *x, const int16_t *y)
|
||||
{
|
||||
size_t i;
|
||||
int32_t accu = 0;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
accu = clamp_s16(accu + (((int32_t)x[i] * (int32_t)y[i]) >> 15));
|
||||
|
||||
return accu;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* MusyX v1 audio ucode
|
||||
**************************************************************************/
|
||||
void musyx_v1_task(struct hle_t* hle)
|
||||
{
|
||||
uint32_t sfd_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
uint32_t sfd_count = *dmem_u32(hle, TASK_DATA_SIZE);
|
||||
uint32_t state_ptr;
|
||||
musyx_t musyx;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"musyx_v1_task: *data=%x, #SF=%d",
|
||||
sfd_ptr,
|
||||
sfd_count);
|
||||
|
||||
state_ptr = *dram_u32(hle, sfd_ptr + SFD_STATE_PTR);
|
||||
|
||||
/* load initial state */
|
||||
load_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_load_u16(hle, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE);
|
||||
dram_load_u16(hle, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1,
|
||||
4);
|
||||
|
||||
for (;;) {
|
||||
/* parse SFD structure */
|
||||
uint16_t sfx_index = *dram_u16(hle, sfd_ptr + SFD_SFX_INDEX);
|
||||
uint32_t voice_mask = *dram_u32(hle, sfd_ptr + SFD_VOICE_BITMASK);
|
||||
uint32_t sfx_ptr = *dram_u32(hle, sfd_ptr + SFD_SFX_PTR);
|
||||
uint32_t voice_ptr = sfd_ptr + SFD_VOICES;
|
||||
uint32_t last_sample_ptr = state_ptr + STATE_LAST_SAMPLE;
|
||||
uint32_t output_ptr;
|
||||
|
||||
/* initialize internal subframes using updated base volumes */
|
||||
update_base_vol(hle, musyx.base_vol, voice_mask, last_sample_ptr, 0, 0);
|
||||
init_subframes_v1(&musyx);
|
||||
|
||||
/* active voices get mixed into L,R,cc0,e50 subframes (optional) */
|
||||
output_ptr = voice_stage(hle, &musyx, voice_ptr, last_sample_ptr);
|
||||
|
||||
/* apply delay-based effects (optional) */
|
||||
sfx_stage(hle, mix_sfx_with_main_subframes_v1,
|
||||
&musyx, sfx_ptr, sfx_index);
|
||||
|
||||
/* emit interleaved L,R subframes */
|
||||
interleave_stage_v1(hle, &musyx, output_ptr);
|
||||
|
||||
--sfd_count;
|
||||
if (sfd_count == 0)
|
||||
break;
|
||||
|
||||
sfd_ptr += SFD_VOICES + MAX_VOICES * VOICE_SIZE;
|
||||
state_ptr = *dram_u32(hle, sfd_ptr + SFD_STATE_PTR);
|
||||
}
|
||||
|
||||
/* writeback updated state */
|
||||
save_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_store_u16(hle, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE);
|
||||
dram_store_u16(hle, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1,
|
||||
4);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* MusyX v2 audio ucode
|
||||
**************************************************************************/
|
||||
void musyx_v2_task(struct hle_t* hle)
|
||||
{
|
||||
uint32_t sfd_ptr = *dmem_u32(hle, TASK_DATA_PTR);
|
||||
uint32_t sfd_count = *dmem_u32(hle, TASK_DATA_SIZE);
|
||||
musyx_t musyx;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"musyx_v2_task: *data=%x, #SF=%d",
|
||||
sfd_ptr,
|
||||
sfd_count);
|
||||
|
||||
for (;;) {
|
||||
/* parse SFD structure */
|
||||
uint16_t sfx_index = *dram_u16(hle, sfd_ptr + SFD_SFX_INDEX);
|
||||
uint32_t voice_mask = *dram_u32(hle, sfd_ptr + SFD_VOICE_BITMASK);
|
||||
uint32_t state_ptr = *dram_u32(hle, sfd_ptr + SFD_STATE_PTR);
|
||||
uint32_t sfx_ptr = *dram_u32(hle, sfd_ptr + SFD_SFX_PTR);
|
||||
uint32_t voice_ptr = sfd_ptr + SFD2_VOICES;
|
||||
|
||||
uint32_t ptr_10 = *dram_u32(hle, sfd_ptr + SFD2_10_PTR);
|
||||
uint8_t mask_14 = *dram_u8 (hle, sfd_ptr + SFD2_14_BITMASK);
|
||||
uint8_t mask_15 = *dram_u8 (hle, sfd_ptr + SFD2_15_BITMASK);
|
||||
uint16_t mask_16 = *dram_u16(hle, sfd_ptr + SFD2_16_BITMASK);
|
||||
uint32_t ptr_18 = *dram_u32(hle, sfd_ptr + SFD2_18_PTR);
|
||||
uint32_t ptr_1c = *dram_u32(hle, sfd_ptr + SFD2_1C_PTR);
|
||||
uint32_t ptr_20 = *dram_u32(hle, sfd_ptr + SFD2_20_PTR);
|
||||
uint32_t ptr_24 = *dram_u32(hle, sfd_ptr + SFD2_24_PTR);
|
||||
|
||||
uint32_t last_sample_ptr = state_ptr + STATE_LAST_SAMPLE;
|
||||
uint32_t output_ptr;
|
||||
|
||||
/* load state */
|
||||
load_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_load_u16(hle, (uint16_t *)musyx.subframe_740_last4,
|
||||
state_ptr + STATE_740_LAST4_V2, 4);
|
||||
|
||||
/* initialize internal subframes using updated base volumes */
|
||||
update_base_vol(hle, musyx.base_vol, voice_mask, last_sample_ptr, mask_15, ptr_24);
|
||||
init_subframes_v2(&musyx);
|
||||
|
||||
if (ptr_10) {
|
||||
/* TODO */
|
||||
HleWarnMessage(hle->user_defined,
|
||||
"ptr_10=%08x mask_14=%02x ptr_24=%08x",
|
||||
ptr_10, mask_14, ptr_24);
|
||||
}
|
||||
|
||||
/* active voices get mixed into L,R,cc0,e50 subframes (optional) */
|
||||
output_ptr = voice_stage(hle, &musyx, voice_ptr, last_sample_ptr);
|
||||
|
||||
/* apply delay-based effects (optional) */
|
||||
sfx_stage(hle, mix_sfx_with_main_subframes_v2,
|
||||
&musyx, sfx_ptr, sfx_index);
|
||||
|
||||
dram_store_u16(hle, (uint16_t*)musyx.left, output_ptr , SUBFRAME_SIZE);
|
||||
dram_store_u16(hle, (uint16_t*)musyx.right, output_ptr + 2*SUBFRAME_SIZE, SUBFRAME_SIZE);
|
||||
dram_store_u16(hle, (uint16_t*)musyx.cc0, output_ptr + 4*SUBFRAME_SIZE, SUBFRAME_SIZE);
|
||||
|
||||
/* store state */
|
||||
save_base_vol(hle, musyx.base_vol, state_ptr + STATE_BASE_VOL);
|
||||
dram_store_u16(hle, (uint16_t*)musyx.subframe_740_last4,
|
||||
state_ptr + STATE_740_LAST4_V2, 4);
|
||||
|
||||
if (mask_16)
|
||||
interleave_stage_v2(hle, &musyx, mask_16, ptr_18, ptr_1c, ptr_20);
|
||||
|
||||
--sfd_count;
|
||||
if (sfd_count == 0)
|
||||
break;
|
||||
|
||||
sfd_ptr += SFD2_VOICES + MAX_VOICES * VOICE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void load_base_vol(struct hle_t* hle, int32_t *base_vol, uint32_t address)
|
||||
{
|
||||
base_vol[0] = ((uint32_t)(*dram_u16(hle, address)) << 16) | (*dram_u16(hle, address + 8));
|
||||
base_vol[1] = ((uint32_t)(*dram_u16(hle, address + 2)) << 16) | (*dram_u16(hle, address + 10));
|
||||
base_vol[2] = ((uint32_t)(*dram_u16(hle, address + 4)) << 16) | (*dram_u16(hle, address + 12));
|
||||
base_vol[3] = ((uint32_t)(*dram_u16(hle, address + 6)) << 16) | (*dram_u16(hle, address + 14));
|
||||
}
|
||||
|
||||
static void save_base_vol(struct hle_t* hle, const int32_t *base_vol, uint32_t address)
|
||||
{
|
||||
unsigned k;
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
*dram_u16(hle, address) = (uint16_t)(base_vol[k] >> 16);
|
||||
address += 2;
|
||||
}
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
*dram_u16(hle, address) = (uint16_t)(base_vol[k]);
|
||||
address += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_base_vol(struct hle_t* hle, int32_t *base_vol,
|
||||
uint32_t voice_mask, uint32_t last_sample_ptr,
|
||||
uint8_t mask_15, uint32_t ptr_24)
|
||||
{
|
||||
unsigned i, k;
|
||||
uint32_t mask;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "base_vol voice_mask = %08x", voice_mask);
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"BEFORE: base_vol = %08x %08x %08x %08x",
|
||||
base_vol[0], base_vol[1], base_vol[2], base_vol[3]);
|
||||
|
||||
/* optim: skip voices contributions entirely if voice_mask is empty */
|
||||
if (voice_mask != 0) {
|
||||
for (i = 0, mask = 1; i < MAX_VOICES;
|
||||
++i, mask <<= 1, last_sample_ptr += 8) {
|
||||
if ((voice_mask & mask) == 0)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < 4; ++k)
|
||||
base_vol[k] += (int16_t)*dram_u16(hle, last_sample_ptr + k * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* optim: skip contributions entirely if mask_15 is empty */
|
||||
if (mask_15 != 0) {
|
||||
for(i = 0, mask = 1; i < 4;
|
||||
++i, mask <<= 1, ptr_24 += 8) {
|
||||
if ((mask_15 & mask) == 0)
|
||||
continue;
|
||||
|
||||
for(k = 0; k < 4; ++k)
|
||||
base_vol[k] += (int16_t)*dram_u16(hle, ptr_24 + k * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* apply 3% decay */
|
||||
for (k = 0; k < 4; ++k)
|
||||
base_vol[k] = (base_vol[k] * 0x0000f850) >> 16;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"AFTER: base_vol = %08x %08x %08x %08x",
|
||||
base_vol[0], base_vol[1], base_vol[2], base_vol[3]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void init_subframes_v1(musyx_t *musyx)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
int16_t base_cc0 = clamp_s16(musyx->base_vol[2]);
|
||||
int16_t base_e50 = clamp_s16(musyx->base_vol[3]);
|
||||
|
||||
int16_t *left = musyx->left;
|
||||
int16_t *right = musyx->right;
|
||||
int16_t *cc0 = musyx->cc0;
|
||||
int16_t *e50 = musyx->e50;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
*(e50++) = base_e50;
|
||||
*(left++) = clamp_s16(*cc0 + base_cc0);
|
||||
*(right++) = clamp_s16(-*cc0 - base_cc0);
|
||||
*(cc0++) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_subframes_v2(musyx_t *musyx)
|
||||
{
|
||||
unsigned i,k;
|
||||
int16_t values[4];
|
||||
int16_t* subframes[4];
|
||||
|
||||
for(k = 0; k < 4; ++k)
|
||||
values[k] = clamp_s16(musyx->base_vol[k]);
|
||||
|
||||
subframes[0] = musyx->left;
|
||||
subframes[1] = musyx->right;
|
||||
subframes[2] = musyx->cc0;
|
||||
subframes[3] = musyx->e50;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
|
||||
for(k = 0; k < 4; ++k)
|
||||
*(subframes[k]++) = values[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* Process voices, and returns interleaved subframe destination address */
|
||||
static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, uint32_t last_sample_ptr)
|
||||
{
|
||||
uint32_t output_ptr;
|
||||
int i = 0;
|
||||
|
||||
/* voice stage can be skipped if first voice has no samples */
|
||||
if (*dram_u16(hle, voice_ptr + VOICE_CATSRC_0 + CATSRC_SIZE1) == 0) {
|
||||
HleVerboseMessage(hle->user_defined, "Skipping Voice stage");
|
||||
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
|
||||
} else {
|
||||
/* otherwise process voices until a non null output_ptr is encountered */
|
||||
for (;;) {
|
||||
/* load voice samples (PCM16 or APDCM) */
|
||||
int16_t samples[SAMPLE_BUFFER_SIZE];
|
||||
unsigned segbase;
|
||||
unsigned offset;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Processing Voice #%d", i);
|
||||
|
||||
if (*dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES) == 0)
|
||||
load_samples_PCM16(hle, voice_ptr, samples, &segbase, &offset);
|
||||
else
|
||||
load_samples_ADPCM(hle, voice_ptr, samples, &segbase, &offset);
|
||||
|
||||
/* mix them with each internal subframes */
|
||||
mix_voice_samples(hle, musyx, voice_ptr, samples, segbase, offset,
|
||||
last_sample_ptr + i * 8);
|
||||
|
||||
/* check break condition */
|
||||
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
|
||||
if (output_ptr != 0)
|
||||
break;
|
||||
|
||||
/* next voice */
|
||||
++i;
|
||||
voice_ptr += VOICE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return output_ptr;
|
||||
}
|
||||
|
||||
static void dma_cat8(struct hle_t* hle, uint8_t *dst, uint32_t catsrc_ptr)
|
||||
{
|
||||
uint32_t ptr1 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR1);
|
||||
uint32_t ptr2 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR2);
|
||||
uint16_t size1 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE1);
|
||||
uint16_t size2 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE2);
|
||||
|
||||
size_t count1 = size1;
|
||||
size_t count2 = size2;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"dma_cat: %08x %08x %04x %04x",
|
||||
ptr1,
|
||||
ptr2,
|
||||
size1,
|
||||
size2);
|
||||
|
||||
dram_load_u8(hle, dst, ptr1, count1);
|
||||
|
||||
if (size2 == 0)
|
||||
return;
|
||||
|
||||
dram_load_u8(hle, dst + count1, ptr2, count2);
|
||||
}
|
||||
|
||||
static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr)
|
||||
{
|
||||
uint32_t ptr1 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR1);
|
||||
uint32_t ptr2 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR2);
|
||||
uint16_t size1 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE1);
|
||||
uint16_t size2 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE2);
|
||||
|
||||
size_t count1 = size1 >> 1;
|
||||
size_t count2 = size2 >> 1;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"dma_cat: %08x %08x %04x %04x",
|
||||
ptr1,
|
||||
ptr2,
|
||||
size1,
|
||||
size2);
|
||||
|
||||
dram_load_u16(hle, dst, ptr1, count1);
|
||||
|
||||
if (size2 == 0)
|
||||
return;
|
||||
|
||||
dram_load_u16(hle, dst + count1, ptr2, count2);
|
||||
}
|
||||
|
||||
static void load_samples_PCM16(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset)
|
||||
{
|
||||
|
||||
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES);
|
||||
uint16_t u16_40 = *dram_u16(hle, voice_ptr + VOICE_U16_40);
|
||||
uint16_t u16_42 = *dram_u16(hle, voice_ptr + VOICE_U16_42);
|
||||
|
||||
unsigned count = align(u16_40 + u8_3e, 4);
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Format: PCM16");
|
||||
|
||||
*segbase = SAMPLE_BUFFER_SIZE - count;
|
||||
*offset = u8_3e;
|
||||
|
||||
dma_cat16(hle, (uint16_t *)samples + *segbase, voice_ptr + VOICE_CATSRC_0);
|
||||
|
||||
if (u16_42 != 0)
|
||||
dma_cat16(hle, (uint16_t *)samples, voice_ptr + VOICE_CATSRC_1);
|
||||
}
|
||||
|
||||
static void load_samples_ADPCM(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
|
||||
unsigned *segbase, unsigned *offset)
|
||||
{
|
||||
/* decompressed samples cannot exceed 0x400 bytes;
|
||||
* ADPCM has a compression ratio of 5/16 */
|
||||
uint8_t buffer[SAMPLE_BUFFER_SIZE * 2 * 5 / 16];
|
||||
int16_t adpcm_table[128];
|
||||
|
||||
uint8_t u8_3c = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES );
|
||||
uint8_t u8_3d = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES + 1);
|
||||
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES );
|
||||
uint8_t u8_3f = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES + 1);
|
||||
uint32_t adpcm_table_ptr = *dram_u32(hle, voice_ptr + VOICE_ADPCM_TABLE_PTR);
|
||||
unsigned count;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Format: ADPCM");
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "Loading ADPCM table: %08x", adpcm_table_ptr);
|
||||
dram_load_u16(hle, (uint16_t *)adpcm_table, adpcm_table_ptr, 128);
|
||||
|
||||
count = u8_3c << 5;
|
||||
|
||||
*segbase = SAMPLE_BUFFER_SIZE - count;
|
||||
*offset = u8_3e & 0x1f;
|
||||
|
||||
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_0);
|
||||
adpcm_decode_frames(hle, samples + *segbase, buffer, adpcm_table, u8_3c, u8_3e);
|
||||
|
||||
if (u8_3d != 0) {
|
||||
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_1);
|
||||
adpcm_decode_frames(hle, samples, buffer, adpcm_table, u8_3d, u8_3f);
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_decode_frames(struct hle_t* hle,
|
||||
int16_t *dst, const uint8_t *src,
|
||||
const int16_t *table, uint8_t count,
|
||||
uint8_t skip_samples)
|
||||
{
|
||||
int16_t frame[32];
|
||||
const uint8_t *nibbles = src + 8;
|
||||
unsigned i;
|
||||
bool jump_gap = false;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"ADPCM decode: count=%d, skip=%d",
|
||||
count, skip_samples);
|
||||
|
||||
if (skip_samples >= 32) {
|
||||
jump_gap = true;
|
||||
nibbles += 16;
|
||||
src += 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uint8_t c2 = nibbles[0];
|
||||
|
||||
const int16_t *book = (c2 & 0xf0) + table;
|
||||
unsigned int rshift = (c2 & 0x0f);
|
||||
|
||||
adpcm_predict_frame(frame, src, nibbles, rshift);
|
||||
|
||||
memcpy(dst, frame, 2 * sizeof(frame[0]));
|
||||
adpcm_compute_residuals(dst + 2, frame + 2, book, dst , 6);
|
||||
adpcm_compute_residuals(dst + 8, frame + 8, book, dst + 6, 8);
|
||||
adpcm_compute_residuals(dst + 16, frame + 16, book, dst + 14, 8);
|
||||
adpcm_compute_residuals(dst + 24, frame + 24, book, dst + 22, 8);
|
||||
|
||||
if (jump_gap) {
|
||||
nibbles += 8;
|
||||
src += 32;
|
||||
}
|
||||
|
||||
jump_gap = !jump_gap;
|
||||
nibbles += 16;
|
||||
src += 4;
|
||||
dst += 32;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_predict_frame(int16_t *dst, const uint8_t *src,
|
||||
const uint8_t *nibbles,
|
||||
unsigned int rshift)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
*(dst++) = (src[0] << 8) | src[1];
|
||||
*(dst++) = (src[2] << 8) | src[3];
|
||||
|
||||
for (i = 1; i < 16; ++i) {
|
||||
uint8_t byte = nibbles[i];
|
||||
|
||||
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
|
||||
*(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift);
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
|
||||
uint32_t voice_ptr, const int16_t *samples,
|
||||
unsigned segbase, unsigned offset, uint32_t last_sample_ptr)
|
||||
{
|
||||
int i, k;
|
||||
|
||||
/* parse VOICE structure */
|
||||
const uint16_t pitch_q16 = *dram_u16(hle, voice_ptr + VOICE_PITCH_Q16);
|
||||
const uint16_t pitch_shift = *dram_u16(hle, voice_ptr + VOICE_PITCH_SHIFT); /* Q4.12 */
|
||||
|
||||
const uint16_t end_point = *dram_u16(hle, voice_ptr + VOICE_END_POINT);
|
||||
const uint16_t restart_point = *dram_u16(hle, voice_ptr + VOICE_RESTART_POINT);
|
||||
|
||||
const uint16_t u16_4e = *dram_u16(hle, voice_ptr + VOICE_U16_4E);
|
||||
|
||||
/* init values and pointers */
|
||||
const int16_t *sample = samples + segbase + offset + u16_4e;
|
||||
const int16_t *const sample_end = samples + segbase + end_point;
|
||||
const int16_t *const sample_restart = samples + (restart_point & 0x7fff) +
|
||||
(((restart_point & 0x8000) != 0) ? 0x000 : segbase);
|
||||
|
||||
|
||||
uint32_t pitch_accu = pitch_q16;
|
||||
uint32_t pitch_step = pitch_shift << 4;
|
||||
|
||||
int32_t v4_env[4];
|
||||
int32_t v4_env_step[4];
|
||||
int16_t *v4_dst[4];
|
||||
int16_t v4[4];
|
||||
|
||||
dram_load_u32(hle, (uint32_t *)v4_env, voice_ptr + VOICE_ENV_BEGIN, 4);
|
||||
dram_load_u32(hle, (uint32_t *)v4_env_step, voice_ptr + VOICE_ENV_STEP, 4);
|
||||
|
||||
v4_dst[0] = musyx->left;
|
||||
v4_dst[1] = musyx->right;
|
||||
v4_dst[2] = musyx->cc0;
|
||||
v4_dst[3] = musyx->e50;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"Voice debug: segbase=%d"
|
||||
"\tu16_4e=%04x\n"
|
||||
"\tpitch: frac0=%04x shift=%04x\n"
|
||||
"\tend_point=%04x restart_point=%04x\n"
|
||||
"\tenv = %08x %08x %08x %08x\n"
|
||||
"\tenv_step = %08x %08x %08x %08x\n",
|
||||
segbase,
|
||||
u16_4e,
|
||||
pitch_q16, pitch_shift,
|
||||
end_point, restart_point,
|
||||
v4_env[0], v4_env[1], v4_env[2], v4_env[3],
|
||||
v4_env_step[0], v4_env_step[1], v4_env_step[2], v4_env_step[3]);
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
/* update sample and lut pointers and then pitch_accu */
|
||||
const int16_t *lut = (RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8));
|
||||
int dist;
|
||||
int16_t v;
|
||||
|
||||
sample += (pitch_accu >> 16);
|
||||
pitch_accu &= 0xffff;
|
||||
pitch_accu += pitch_step;
|
||||
|
||||
/* handle end/restart points */
|
||||
dist = sample - sample_end;
|
||||
if (dist >= 0)
|
||||
sample = sample_restart + dist;
|
||||
|
||||
/* apply resample filter */
|
||||
v = clamp_s16(dot4(sample, lut));
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
/* envmix */
|
||||
int32_t accu = (v * (v4_env[k] >> 16)) >> 15;
|
||||
v4[k] = clamp_s16(accu);
|
||||
*(v4_dst[k]) = clamp_s16(accu + *(v4_dst[k]));
|
||||
|
||||
/* update envelopes and dst pointers */
|
||||
++(v4_dst[k]);
|
||||
v4_env[k] += v4_env_step[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* save last resampled sample */
|
||||
dram_store_u16(hle, (uint16_t *)v4, last_sample_ptr, 4);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"last_sample = %04x %04x %04x %04x",
|
||||
v4[0], v4[1], v4[2], v4[3]);
|
||||
}
|
||||
|
||||
|
||||
static void sfx_stage(struct hle_t* hle, mix_sfx_with_main_subframes_t mix_sfx_with_main_subframes,
|
||||
musyx_t *musyx, uint32_t sfx_ptr, uint16_t idx)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
int16_t buffer[SUBFRAME_SIZE + 4];
|
||||
int16_t *subframe = buffer + 4;
|
||||
|
||||
uint32_t tap_delays[8];
|
||||
int16_t tap_gains[8];
|
||||
int16_t fir4_hcoeffs[4];
|
||||
|
||||
int16_t delayed[SUBFRAME_SIZE];
|
||||
int dpos, dlength;
|
||||
|
||||
const uint32_t pos = idx * SUBFRAME_SIZE;
|
||||
|
||||
uint32_t cbuffer_ptr;
|
||||
uint32_t cbuffer_length;
|
||||
uint16_t tap_count;
|
||||
int16_t fir4_hgain;
|
||||
uint16_t sfx_gains[2];
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx);
|
||||
|
||||
if (sfx_ptr == 0)
|
||||
return;
|
||||
|
||||
/* load sfx parameters */
|
||||
cbuffer_ptr = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_PTR);
|
||||
cbuffer_length = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_LENGTH);
|
||||
|
||||
tap_count = *dram_u16(hle, sfx_ptr + SFX_TAP_COUNT);
|
||||
|
||||
dram_load_u32(hle, tap_delays, sfx_ptr + SFX_TAP_DELAYS, 8);
|
||||
dram_load_u16(hle, (uint16_t *)tap_gains, sfx_ptr + SFX_TAP_GAINS, 8);
|
||||
|
||||
fir4_hgain = *dram_u16(hle, sfx_ptr + SFX_FIR4_HGAIN);
|
||||
dram_load_u16(hle, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4);
|
||||
|
||||
sfx_gains[0] = *dram_u16(hle, sfx_ptr + SFX_U16_3C);
|
||||
sfx_gains[1] = *dram_u16(hle, sfx_ptr + SFX_U16_3E);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"cbuffer: ptr=%08x length=%x", cbuffer_ptr,
|
||||
cbuffer_length);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"fir4: hgain=%04x hcoeff=%04x %04x %04x %04x",
|
||||
fir4_hgain,
|
||||
fir4_hcoeffs[0], fir4_hcoeffs[1], fir4_hcoeffs[2], fir4_hcoeffs[3]);
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"tap count=%d\n"
|
||||
"delays: %08x %08x %08x %08x %08x %08x %08x %08x\n"
|
||||
"gains: %04x %04x %04x %04x %04x %04x %04x %04x",
|
||||
tap_count,
|
||||
tap_delays[0], tap_delays[1], tap_delays[2], tap_delays[3],
|
||||
tap_delays[4], tap_delays[5], tap_delays[6], tap_delays[7],
|
||||
tap_gains[0], tap_gains[1], tap_gains[2], tap_gains[3],
|
||||
tap_gains[4], tap_gains[5], tap_gains[6], tap_gains[7]);
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "sfx_gains=%04x %04x", sfx_gains[0], sfx_gains[1]);
|
||||
|
||||
/* mix up to 8 delayed subframes */
|
||||
memset(subframe, 0, SUBFRAME_SIZE * sizeof(subframe[0]));
|
||||
for (i = 0; i < tap_count; ++i) {
|
||||
|
||||
dpos = pos - tap_delays[i];
|
||||
if (dpos <= 0)
|
||||
dpos += cbuffer_length;
|
||||
dlength = SUBFRAME_SIZE;
|
||||
|
||||
if ((uint32_t)(dpos + SUBFRAME_SIZE) > cbuffer_length) {
|
||||
dlength = cbuffer_length - dpos;
|
||||
dram_load_u16(hle, (uint16_t *)delayed + dlength, cbuffer_ptr, SUBFRAME_SIZE - dlength);
|
||||
}
|
||||
|
||||
dram_load_u16(hle, (uint16_t *)delayed, cbuffer_ptr + dpos * 2, dlength);
|
||||
|
||||
mix_subframes(subframe, delayed, tap_gains[i]);
|
||||
}
|
||||
|
||||
/* add resulting subframe to main subframes */
|
||||
mix_sfx_with_main_subframes(musyx, subframe, sfx_gains);
|
||||
|
||||
/* apply FIR4 filter and writeback filtered result */
|
||||
memcpy(buffer, musyx->subframe_740_last4, 4 * sizeof(int16_t));
|
||||
memcpy(musyx->subframe_740_last4, subframe + SUBFRAME_SIZE - 4, 4 * sizeof(int16_t));
|
||||
mix_fir4(musyx->e50, buffer + 1, fir4_hgain, fir4_hcoeffs);
|
||||
dram_store_u16(hle, (uint16_t *)musyx->e50, cbuffer_ptr + pos * 2, SUBFRAME_SIZE);
|
||||
}
|
||||
|
||||
static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* UNUSED(gains))
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int16_t v = subframe[i];
|
||||
musyx->left[i] = clamp_s16(musyx->left[i] + v);
|
||||
musyx->right[i] = clamp_s16(musyx->right[i] + v);
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subframe,
|
||||
const uint16_t* gains)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int16_t v = subframe[i];
|
||||
int16_t v1 = (int32_t)(v * gains[0]) >> 16;
|
||||
int16_t v2 = (int32_t)(v * gains[1]) >> 16;
|
||||
|
||||
musyx->left[i] = clamp_s16(musyx->left[i] + v1);
|
||||
musyx->right[i] = clamp_s16(musyx->right[i] + v1);
|
||||
musyx->cc0[i] = clamp_s16(musyx->cc0[i] + v2);
|
||||
}
|
||||
}
|
||||
|
||||
static void mix_samples(int16_t *y, int16_t x, int16_t hgain)
|
||||
{
|
||||
*y = clamp_s16(*y + ((x * hgain + 0x4000) >> 15));
|
||||
}
|
||||
|
||||
static void mix_subframes(int16_t *y, const int16_t *x, int16_t hgain)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i)
|
||||
mix_samples(&y[i], x[i], hgain);
|
||||
}
|
||||
|
||||
static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t *hcoeffs)
|
||||
{
|
||||
unsigned int i;
|
||||
int32_t h[4];
|
||||
|
||||
h[0] = (hgain * hcoeffs[0]) >> 15;
|
||||
h[1] = (hgain * hcoeffs[1]) >> 15;
|
||||
h[2] = (hgain * hcoeffs[2]) >> 15;
|
||||
h[3] = (hgain * hcoeffs[3]) >> 15;
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int32_t v = (h[0] * x[i] + h[1] * x[i + 1] + h[2] * x[i + 2] + h[3] * x[i + 3]) >> 15;
|
||||
y[i] = clamp_s16(y[i] + v);
|
||||
}
|
||||
}
|
||||
|
||||
static void interleave_stage_v1(struct hle_t* hle, musyx_t *musyx, uint32_t output_ptr)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
int16_t base_left;
|
||||
int16_t base_right;
|
||||
|
||||
int16_t *left;
|
||||
int16_t *right;
|
||||
uint32_t *dst;
|
||||
|
||||
HleVerboseMessage(hle->user_defined, "interleave: %08x", output_ptr);
|
||||
|
||||
base_left = clamp_s16(musyx->base_vol[0]);
|
||||
base_right = clamp_s16(musyx->base_vol[1]);
|
||||
|
||||
left = musyx->left;
|
||||
right = musyx->right;
|
||||
dst = dram_u32(hle, output_ptr);
|
||||
|
||||
for (i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
uint16_t l = clamp_s16(*(left++) + base_left);
|
||||
uint16_t r = clamp_s16(*(right++) + base_right);
|
||||
|
||||
*(dst++) = (l << 16) | r;
|
||||
}
|
||||
}
|
||||
|
||||
static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
|
||||
uint16_t mask_16, uint32_t ptr_18,
|
||||
uint32_t ptr_1c, uint32_t output_ptr)
|
||||
{
|
||||
unsigned i, k;
|
||||
int16_t subframe[SUBFRAME_SIZE];
|
||||
uint32_t *dst;
|
||||
uint16_t mask;
|
||||
|
||||
HleVerboseMessage(hle->user_defined,
|
||||
"mask_16=%04x ptr_18=%08x ptr_1c=%08x output_ptr=%08x",
|
||||
mask_16, ptr_18, ptr_1c, output_ptr);
|
||||
|
||||
/* compute L_total, R_total and update subframe @ptr_1c */
|
||||
memset(subframe, 0, SUBFRAME_SIZE*sizeof(subframe[0]));
|
||||
|
||||
for(i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
int16_t v = *dram_u16(hle, ptr_1c + i*2);
|
||||
musyx->left[i] = v;
|
||||
musyx->right[i] = clamp_s16(-v);
|
||||
}
|
||||
|
||||
for (k = 0, mask = 1; k < 8; ++k, mask <<= 1, ptr_18 += 8) {
|
||||
int16_t hgain;
|
||||
uint32_t address;
|
||||
|
||||
if ((mask_16 & mask) == 0)
|
||||
continue;
|
||||
|
||||
address = *dram_u32(hle, ptr_18);
|
||||
hgain = *dram_u16(hle, ptr_18 + 4);
|
||||
|
||||
for(i = 0; i < SUBFRAME_SIZE; ++i, address += 2) {
|
||||
mix_samples(&musyx->left[i], *dram_u16(hle, address), hgain);
|
||||
mix_samples(&musyx->right[i], *dram_u16(hle, address + 2*SUBFRAME_SIZE), hgain);
|
||||
mix_samples(&subframe[i], *dram_u16(hle, address + 4*SUBFRAME_SIZE), hgain);
|
||||
}
|
||||
}
|
||||
|
||||
/* interleave L_total and R_total */
|
||||
dst = dram_u32(hle, output_ptr);
|
||||
for(i = 0; i < SUBFRAME_SIZE; ++i) {
|
||||
uint16_t l = musyx->left[i];
|
||||
uint16_t r = musyx->right[i];
|
||||
*(dst++) = (l << 16) | r;
|
||||
}
|
||||
|
||||
/* writeback subframe @ptr_1c */
|
||||
dram_store_u16(hle, (uint16_t*)subframe, ptr_1c, SUBFRAME_SIZE);
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - plugin.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../usf.h"
|
||||
#include "../main.h"
|
||||
#include "../usf_internal.h"
|
||||
|
||||
#include "hle.h"
|
||||
|
||||
/* Global functions needed by HLE core */
|
||||
void HleVerboseMessage(void* user_defined, const char *message, ...)
|
||||
{
|
||||
#ifdef DEBUG_INFO
|
||||
usf_state_t* state;
|
||||
va_list ap;
|
||||
size_t len;
|
||||
|
||||
state = (usf_state_t*)user_defined;
|
||||
|
||||
if (state->debug_log)
|
||||
{
|
||||
va_start( ap, message );
|
||||
vfprintf( state->debug_log, message, ap );
|
||||
va_end( ap );
|
||||
|
||||
fputs( "\n", state->debug_log );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HleErrorMessage(void* user_defined, const char *message, ...)
|
||||
{
|
||||
usf_state_t* state;
|
||||
va_list ap;
|
||||
size_t len;
|
||||
|
||||
state = (usf_state_t*)user_defined;
|
||||
len = strlen( state->error_message );
|
||||
|
||||
if ( len )
|
||||
state->error_message[ len++ ] = '\n';
|
||||
|
||||
va_start( ap, message );
|
||||
vsprintf( state->error_message + len, message, ap );
|
||||
va_end( ap );
|
||||
|
||||
state->last_error = state->error_message;
|
||||
StopEmulation( state );
|
||||
}
|
||||
|
||||
void HleWarnMessage(void* user_defined, const char *message, ...)
|
||||
{
|
||||
usf_state_t* state;
|
||||
va_list ap;
|
||||
size_t len;
|
||||
|
||||
state = (usf_state_t*)user_defined;
|
||||
len = strlen( state->error_message );
|
||||
|
||||
if ( len )
|
||||
state->error_message[ len++ ] = '\n';
|
||||
|
||||
va_start( ap, message );
|
||||
vsprintf( state->error_message + len, message, ap );
|
||||
va_end( ap );
|
||||
|
||||
state->last_error = state->error_message;
|
||||
StopEmulation( state );
|
||||
}
|
||||
|
||||
void HleCheckInterrupts(void* user_defined)
|
||||
{
|
||||
CheckInterrupts((usf_state_t*)user_defined);
|
||||
}
|
||||
|
||||
void HleProcessDlistList(void* user_defined)
|
||||
{
|
||||
/* disabled */
|
||||
}
|
||||
|
||||
void HleProcessAlistList(void* user_defined)
|
||||
{
|
||||
/* disabled */
|
||||
}
|
||||
|
||||
void HleProcessRdpList(void* user_defined)
|
||||
{
|
||||
/* disabled */
|
||||
}
|
||||
|
||||
void HleShowCFB(void* user_defined)
|
||||
{
|
||||
/* disabled */
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-rsp-hle - ucodes.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2014 Bobby Smiles *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef UCODES_H
|
||||
#define UCODES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct hle_t;
|
||||
|
||||
|
||||
/* cic_x105 ucode */
|
||||
void cicx105_ucode(struct hle_t* hle);
|
||||
|
||||
|
||||
/* audio list ucodes - audio */
|
||||
enum { N_SEGMENTS = 16 };
|
||||
struct alist_audio_t {
|
||||
/* segments */
|
||||
uint32_t segments[N_SEGMENTS];
|
||||
|
||||
/* main buffers */
|
||||
uint16_t in;
|
||||
uint16_t out;
|
||||
uint16_t count;
|
||||
|
||||
/* auxiliary buffers */
|
||||
uint16_t dry_right;
|
||||
uint16_t wet_left;
|
||||
uint16_t wet_right;
|
||||
|
||||
/* gains */
|
||||
int16_t dry;
|
||||
int16_t wet;
|
||||
|
||||
/* envelopes (0:left, 1:right) */
|
||||
int16_t vol[2];
|
||||
int16_t target[2];
|
||||
int32_t rate[2];
|
||||
|
||||
/* ADPCM loop point address */
|
||||
uint32_t loop;
|
||||
|
||||
/* storage for ADPCM table and polef coefficients */
|
||||
int16_t table[16 * 8];
|
||||
};
|
||||
|
||||
void alist_process_audio (struct hle_t* hle);
|
||||
void alist_process_audio_ge(struct hle_t* hle);
|
||||
void alist_process_audio_bc(struct hle_t* hle);
|
||||
|
||||
|
||||
/* audio list ucodes - naudio */
|
||||
struct alist_naudio_t {
|
||||
/* gains */
|
||||
int16_t dry;
|
||||
int16_t wet;
|
||||
|
||||
/* envelopes (0:left, 1:right) */
|
||||
int16_t vol[2];
|
||||
int16_t target[2];
|
||||
int32_t rate[2];
|
||||
|
||||
/* ADPCM loop point address */
|
||||
uint32_t loop;
|
||||
|
||||
/* storage for ADPCM table and polef coefficients */
|
||||
int16_t table[16 * 8];
|
||||
};
|
||||
|
||||
void alist_process_naudio (struct hle_t* hle);
|
||||
void alist_process_naudio_bk (struct hle_t* hle);
|
||||
void alist_process_naudio_dk (struct hle_t* hle);
|
||||
void alist_process_naudio_mp3 (struct hle_t* hle);
|
||||
void alist_process_naudio_cbfd(struct hle_t* hle);
|
||||
|
||||
|
||||
/* audio list ucodes - nead */
|
||||
struct alist_nead_t {
|
||||
/* main buffers */
|
||||
uint16_t in;
|
||||
uint16_t out;
|
||||
uint16_t count;
|
||||
|
||||
/* envmixer ramps */
|
||||
uint16_t env_values[3];
|
||||
uint16_t env_steps[3];
|
||||
|
||||
/* ADPCM loop point address */
|
||||
uint32_t loop;
|
||||
|
||||
/* storage for ADPCM table and polef coefficients */
|
||||
int16_t table[16 * 8];
|
||||
|
||||
/* filter audio command state */
|
||||
uint16_t filter_count;
|
||||
uint32_t filter_lut_address[2];
|
||||
};
|
||||
|
||||
void alist_process_nead_mk (struct hle_t* hle);
|
||||
void alist_process_nead_sfj (struct hle_t* hle);
|
||||
void alist_process_nead_sf (struct hle_t* hle);
|
||||
void alist_process_nead_fz (struct hle_t* hle);
|
||||
void alist_process_nead_wrjb(struct hle_t* hle);
|
||||
void alist_process_nead_ys (struct hle_t* hle);
|
||||
void alist_process_nead_1080(struct hle_t* hle);
|
||||
void alist_process_nead_oot (struct hle_t* hle);
|
||||
void alist_process_nead_mm (struct hle_t* hle);
|
||||
void alist_process_nead_mmb (struct hle_t* hle);
|
||||
void alist_process_nead_ac (struct hle_t* hle);
|
||||
|
||||
|
||||
/* mp3 ucode */
|
||||
void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address);
|
||||
|
||||
|
||||
/* musyx ucodes */
|
||||
void musyx_v1_task(struct hle_t* hle);
|
||||
void musyx_v2_task(struct hle_t* hle);
|
||||
|
||||
|
||||
/* jpeg ucodes */
|
||||
void jpeg_decode_PS0(struct hle_t* hle);
|
||||
void jpeg_decode_PS(struct hle_t* hle);
|
||||
void jpeg_decode_OB(struct hle_t* hle);
|
||||
|
||||
#endif
|
||||
|
|
@ -170,10 +170,128 @@ int usf_upload_section(void * state, const uint8_t * data, size_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int is_valid_rom(const unsigned char *buffer)
|
||||
{
|
||||
/* Test if rom is a native .z64 image with header 0x80371240. [ABCD] */
|
||||
if((buffer[0]==0x80)&&(buffer[1]==0x37)&&(buffer[2]==0x12)&&(buffer[3]==0x40))
|
||||
return 1;
|
||||
/* Test if rom is a byteswapped .v64 image with header 0x37804012. [BADC] */
|
||||
else if((buffer[0]==0x37)&&(buffer[1]==0x80)&&(buffer[2]==0x40)&&(buffer[3]==0x12))
|
||||
return 1;
|
||||
/* Test if rom is a wordswapped .n64 image with header 0x40123780. [DCBA] */
|
||||
else if((buffer[0]==0x40)&&(buffer[1]==0x12)&&(buffer[2]==0x37)&&(buffer[3]==0x80))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void swap_rom(const unsigned char* signature, unsigned char* localrom, int loadlength)
|
||||
{
|
||||
unsigned char temp;
|
||||
int i;
|
||||
|
||||
/* Btyeswap if .v64 image. */
|
||||
if(signature[0]==0x37)
|
||||
{
|
||||
for (i = 0; i < loadlength; i+=2)
|
||||
{
|
||||
temp=localrom[i];
|
||||
localrom[i]=localrom[i+1];
|
||||
localrom[i+1]=temp;
|
||||
}
|
||||
}
|
||||
/* Wordswap if .n64 image. */
|
||||
else if(signature[0]==0x40)
|
||||
{
|
||||
for (i = 0; i < loadlength; i+=4)
|
||||
{
|
||||
temp=localrom[i];
|
||||
localrom[i]=localrom[i+3];
|
||||
localrom[i+3]=temp;
|
||||
temp=localrom[i+1];
|
||||
localrom[i+1]=localrom[i+2];
|
||||
localrom[i+2]=temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static _system_type rom_country_code_to_system_type(unsigned short country_code)
|
||||
{
|
||||
switch (country_code & 0xFF)
|
||||
{
|
||||
// PAL codes
|
||||
case 0x44:
|
||||
case 0x46:
|
||||
case 0x49:
|
||||
case 0x50:
|
||||
case 0x53:
|
||||
case 0x55:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
return SYSTEM_PAL;
|
||||
|
||||
// NTSC codes
|
||||
case 0x37:
|
||||
case 0x41:
|
||||
case 0x45:
|
||||
case 0x4a:
|
||||
default: // Fallback for unknown codes
|
||||
return SYSTEM_NTSC;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the VI (vertical interrupt) limit associated to a ROM system type.
|
||||
static int rom_system_type_to_vi_limit(_system_type system_type)
|
||||
{
|
||||
switch (system_type)
|
||||
{
|
||||
case SYSTEM_PAL:
|
||||
case SYSTEM_MPAL:
|
||||
return 50;
|
||||
|
||||
case SYSTEM_NTSC:
|
||||
default:
|
||||
return 60;
|
||||
}
|
||||
}
|
||||
|
||||
static int rom_system_type_to_ai_dac_rate(_system_type system_type)
|
||||
{
|
||||
switch (system_type)
|
||||
{
|
||||
case SYSTEM_PAL:
|
||||
return 49656530;
|
||||
case SYSTEM_MPAL:
|
||||
return 48628316;
|
||||
case SYSTEM_NTSC:
|
||||
default:
|
||||
return 48681812;
|
||||
}
|
||||
}
|
||||
|
||||
void open_rom_header(usf_state_t * state, unsigned char * header, int header_size)
|
||||
{
|
||||
if (header_size >= sizeof(_rom_header))
|
||||
memcpy(&state->ROM_HEADER, header, sizeof(_rom_header));
|
||||
|
||||
if (is_valid_rom((const unsigned char *)&state->ROM_HEADER))
|
||||
swap_rom((const unsigned char *)&state->ROM_HEADER, (unsigned char *)&state->ROM_HEADER, sizeof(_rom_header));
|
||||
|
||||
/* add some useful properties to ROM_PARAMS */
|
||||
state->ROM_PARAMS.systemtype = rom_country_code_to_system_type(state->ROM_HEADER.Country_code);
|
||||
state->ROM_PARAMS.vilimit = rom_system_type_to_vi_limit(state->ROM_PARAMS.systemtype);
|
||||
state->ROM_PARAMS.aidacrate = rom_system_type_to_ai_dac_rate(state->ROM_PARAMS.systemtype);
|
||||
state->ROM_PARAMS.countperop = COUNT_PER_OP_DEFAULT;
|
||||
}
|
||||
|
||||
static int usf_startup(usf_state_t * state)
|
||||
{
|
||||
// Detect region
|
||||
|
||||
open_rom_header(state, state->savestatespace + 8, sizeof(_rom_header));
|
||||
|
||||
// Detect the Ramsize before the memory allocation
|
||||
|
||||
|
||||
if(get_le32(state->savestatespace + 4) == 0x400000) {
|
||||
void * savestate;
|
||||
state->RdramSize = 0x400000;
|
||||
|
|
|
@ -1,10 +1,75 @@
|
|||
#ifndef _USF_INTERNAL_H_
|
||||
#define _USF_INTERNAL_H_
|
||||
|
||||
#include "audio.h"
|
||||
#include "cpu.h"
|
||||
#include "rsp_hle/hle.h"
|
||||
#include "cpu_hle.h"
|
||||
|
||||
/* Supported rom image types. */
|
||||
enum
|
||||
{
|
||||
Z64IMAGE,
|
||||
V64IMAGE,
|
||||
N64IMAGE
|
||||
};
|
||||
|
||||
/* Supported CIC chips. */
|
||||
enum
|
||||
{
|
||||
CIC_NUS_6101,
|
||||
CIC_NUS_6102,
|
||||
CIC_NUS_6103,
|
||||
CIC_NUS_6105,
|
||||
CIC_NUS_6106
|
||||
};
|
||||
|
||||
/* Supported save types. */
|
||||
enum
|
||||
{
|
||||
EEPROM_4KB,
|
||||
EEPROM_16KB,
|
||||
SRAM,
|
||||
FLASH_RAM,
|
||||
CONTROLLER_PACK,
|
||||
NONE
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSTEM_NTSC = 0,
|
||||
SYSTEM_PAL,
|
||||
SYSTEM_MPAL
|
||||
} _system_type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char init_PI_BSB_DOM1_LAT_REG; /* 0x00 */
|
||||
unsigned char init_PI_BSB_DOM1_PGS_REG; /* 0x01 */
|
||||
unsigned char init_PI_BSB_DOM1_PWD_REG; /* 0x02 */
|
||||
unsigned char init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */
|
||||
unsigned int ClockRate; /* 0x04 */
|
||||
unsigned int PC; /* 0x08 */
|
||||
unsigned int Release; /* 0x0C */
|
||||
unsigned int CRC1; /* 0x10 */
|
||||
unsigned int CRC2; /* 0x14 */
|
||||
unsigned int Unknown[2]; /* 0x18 */
|
||||
unsigned char Name[20]; /* 0x20 */
|
||||
unsigned int unknown; /* 0x34 */
|
||||
unsigned int Manufacturer_ID; /* 0x38 */
|
||||
unsigned short Cartridge_ID; /* 0x3C - Game serial number */
|
||||
unsigned short Country_code; /* 0x3E */
|
||||
} _rom_header;
|
||||
|
||||
typedef struct _rom_params
|
||||
{
|
||||
_system_type systemtype;
|
||||
int vilimit;
|
||||
int aidacrate;
|
||||
char headername[21]; /* ROM Name as in the header, removing trailing whitespace */
|
||||
unsigned char countperop;
|
||||
} rom_params;
|
||||
|
||||
struct usf_state_helper
|
||||
{
|
||||
size_t offset_to_structure;
|
||||
|
@ -66,6 +131,9 @@ struct usf_state
|
|||
|
||||
// rsp_hle
|
||||
struct hle_t hle;
|
||||
|
||||
_rom_header ROM_HEADER;
|
||||
rom_params ROM_PARAMS;
|
||||
|
||||
uint32_t cpu_running, cpu_stopped;
|
||||
|
||||
|
@ -89,6 +157,8 @@ struct usf_state
|
|||
// stored here until the next call to usf_render()
|
||||
int16_t samplebuf[16384];
|
||||
size_t samples_in_buffer;
|
||||
|
||||
struct ai_dma fifo[2];
|
||||
|
||||
// usf.c
|
||||
// This takes care of automatically resampling the console audio
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2014 Christopher Snowhill. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -19,10 +19,10 @@
|
|||
8360EEF217F92AC8005208A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8360EEF017F92AC8005208A4 /* InfoPlist.strings */; };
|
||||
8384904A180764B500E7332D /* SSEQPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83848FEC1807624000E7332D /* SSEQPlayer.framework */; };
|
||||
8384904B180764C200E7332D /* SSEQPlayer.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83848FEC1807624000E7332D /* SSEQPlayer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
83C8B6FB18AF58FA0071B040 /* lazyusf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83C8B65618AF57770071B040 /* lazyusf.framework */; };
|
||||
83C8B6FC18AF59080071B040 /* lazyusf.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83C8B65618AF57770071B040 /* lazyusf.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
83CA2E3D1D7BCF9B00F2EA53 /* mGBA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83CA24241D7BC47E00F2EA53 /* mGBA.framework */; };
|
||||
83CA2E4D1D7BE41300F2EA53 /* mGBA.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83CA24241D7BC47E00F2EA53 /* mGBA.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
83DA153620F6EFD00096D348 /* lazyusf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83DA153320F6EFA80096D348 /* lazyusf.framework */; };
|
||||
83DA153720F6EFE10096D348 /* lazyusf.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83DA153320F6EFA80096D348 /* lazyusf.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
83DE0CBC180B02CC00269051 /* vio2sf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83DE0C3A180A9BD500269051 /* vio2sf.framework */; };
|
||||
83DE0CBD180B02D800269051 /* vio2sf.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83DE0C3A180A9BD500269051 /* vio2sf.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
83FC32C51BF5AEFB00962B36 /* HighlyExperimental.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83FC325E1BF5AB9000962B36 /* HighlyExperimental.framework */; };
|
||||
|
@ -93,13 +93,6 @@
|
|||
remoteGlobalIDString = 83848FB71807623F00E7332D;
|
||||
remoteInfo = SSEQPlayer;
|
||||
};
|
||||
83C8B65518AF57770071B040 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83C8B65018AF57770071B040 /* lazyusf.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 83C8B62218AF57770071B040;
|
||||
remoteInfo = lazyusf;
|
||||
};
|
||||
83CA24231D7BC47E00F2EA53 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CA241E1D7BC47C00F2EA53 /* mGBA.xcodeproj */;
|
||||
|
@ -114,9 +107,16 @@
|
|||
remoteGlobalIDString = 83CA24121D7BC47C00F2EA53;
|
||||
remoteInfo = mGBA;
|
||||
};
|
||||
83CA2E401D7BCFB800F2EA53 /* PBXContainerItemProxy */ = {
|
||||
83DA153220F6EFA80096D348 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83C8B65018AF57770071B040 /* lazyusf.xcodeproj */;
|
||||
containerPortal = 83DA152E20F6EFA80096D348 /* lazyusf.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 83C8B62218AF57770071B040;
|
||||
remoteInfo = lazyusf;
|
||||
};
|
||||
83DA153420F6EFC90096D348 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83DA152E20F6EFA80096D348 /* lazyusf.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 83C8B62118AF57770071B040;
|
||||
remoteInfo = lazyusf;
|
||||
|
@ -167,9 +167,9 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
83DA153720F6EFE10096D348 /* lazyusf.framework in CopyFiles */,
|
||||
83CA2E4D1D7BE41300F2EA53 /* mGBA.framework in CopyFiles */,
|
||||
83FC32C61BF5AF0600962B36 /* HighlyExperimental.framework in CopyFiles */,
|
||||
83C8B6FC18AF59080071B040 /* lazyusf.framework in CopyFiles */,
|
||||
83DE0CBD180B02D800269051 /* vio2sf.framework in CopyFiles */,
|
||||
8384904B180764C200E7332D /* SSEQPlayer.framework in CopyFiles */,
|
||||
8343792A17F96F2600584396 /* HighlyQuixotic.framework in CopyFiles */,
|
||||
|
@ -199,8 +199,8 @@
|
|||
8360EEF117F92AC8005208A4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
8360EEF317F92AC8005208A4 /* HighlyComplete-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HighlyComplete-Prefix.pch"; sourceTree = "<group>"; };
|
||||
83848FE61807623F00E7332D /* SSEQPlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SSEQPlayer.xcodeproj; path = ../../Frameworks/SSEQPlayer/SSEQPlayer.xcodeproj; sourceTree = "<group>"; };
|
||||
83C8B65018AF57770071B040 /* lazyusf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = lazyusf.xcodeproj; path = ../../Frameworks/lazyusf/lazyusf.xcodeproj; sourceTree = "<group>"; };
|
||||
83CA241E1D7BC47C00F2EA53 /* mGBA.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mGBA.xcodeproj; path = ../../Frameworks/mGBA/mGBA.xcodeproj; sourceTree = "<group>"; };
|
||||
83DA152E20F6EFA80096D348 /* lazyusf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = lazyusf.xcodeproj; path = ../../Frameworks/lazyusf/lazyusf.xcodeproj; sourceTree = "<group>"; };
|
||||
83DE0C34180A9BD400269051 /* vio2sf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = vio2sf.xcodeproj; path = ../../Frameworks/vio2sf/vio2sf.xcodeproj; sourceTree = "<group>"; };
|
||||
83FAF8A318ADD27F00057CAF /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = "<group>"; };
|
||||
83FC32591BF5AB9000962B36 /* HighlyExperimental.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyExperimental.xcodeproj; path = ../../Frameworks/HighlyExperimental/HighlyExperimental.xcodeproj; sourceTree = "<group>"; };
|
||||
|
@ -211,9 +211,9 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
83DA153620F6EFD00096D348 /* lazyusf.framework in Frameworks */,
|
||||
83CA2E3D1D7BCF9B00F2EA53 /* mGBA.framework in Frameworks */,
|
||||
83FC32C51BF5AEFB00962B36 /* HighlyExperimental.framework in Frameworks */,
|
||||
83C8B6FB18AF58FA0071B040 /* lazyusf.framework in Frameworks */,
|
||||
83DE0CBC180B02CC00269051 /* vio2sf.framework in Frameworks */,
|
||||
8384904A180764B500E7332D /* SSEQPlayer.framework in Frameworks */,
|
||||
8343792917F96F1D00584396 /* HighlyQuixotic.framework in Frameworks */,
|
||||
|
@ -290,7 +290,7 @@
|
|||
8343796317F97BDB00584396 /* HighlyAdvanced.xcodeproj */,
|
||||
83848FE61807623F00E7332D /* SSEQPlayer.xcodeproj */,
|
||||
83DE0C34180A9BD400269051 /* vio2sf.xcodeproj */,
|
||||
83C8B65018AF57770071B040 /* lazyusf.xcodeproj */,
|
||||
83DA152E20F6EFA80096D348 /* lazyusf.xcodeproj */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -336,14 +336,6 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83C8B65118AF57770071B040 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83C8B65618AF57770071B040 /* lazyusf.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83CA241F1D7BC47C00F2EA53 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -352,6 +344,14 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83DA152F20F6EFA80096D348 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83DA153320F6EFA80096D348 /* lazyusf.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83DE0C35180A9BD400269051 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -384,7 +384,7 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
83CA2E411D7BCFB800F2EA53 /* PBXTargetDependency */,
|
||||
83DA153520F6EFC90096D348 /* PBXTargetDependency */,
|
||||
83CA2E3F1D7BCFB000F2EA53 /* PBXTargetDependency */,
|
||||
83FC32C21BF5AEF300962B36 /* PBXTargetDependency */,
|
||||
83DE0CBB180B02C500269051 /* PBXTargetDependency */,
|
||||
|
@ -442,8 +442,8 @@
|
|||
ProjectRef = 8343789C17F9658E00584396 /* HighlyTheoretical.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 83C8B65118AF57770071B040 /* Products */;
|
||||
ProjectRef = 83C8B65018AF57770071B040 /* lazyusf.xcodeproj */;
|
||||
ProductGroup = 83DA152F20F6EFA80096D348 /* Products */;
|
||||
ProjectRef = 83DA152E20F6EFA80096D348 /* lazyusf.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 83CA241F1D7BC47C00F2EA53 /* Products */;
|
||||
|
@ -505,13 +505,6 @@
|
|||
remoteRef = 83848FEB1807624000E7332D /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
83C8B65618AF57770071B040 /* lazyusf.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = lazyusf.framework;
|
||||
remoteRef = 83C8B65518AF57770071B040 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
83CA24241D7BC47E00F2EA53 /* mGBA.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
|
@ -519,6 +512,13 @@
|
|||
remoteRef = 83CA24231D7BC47E00F2EA53 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
83DA153320F6EFA80096D348 /* lazyusf.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = lazyusf.framework;
|
||||
remoteRef = 83DA153220F6EFA80096D348 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
83DE0C3A180A9BD500269051 /* vio2sf.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
|
@ -583,10 +583,10 @@
|
|||
name = mGBA;
|
||||
targetProxy = 83CA2E3E1D7BCFB000F2EA53 /* PBXContainerItemProxy */;
|
||||
};
|
||||
83CA2E411D7BCFB800F2EA53 /* PBXTargetDependency */ = {
|
||||
83DA153520F6EFC90096D348 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = lazyusf;
|
||||
targetProxy = 83CA2E401D7BCFB800F2EA53 /* PBXContainerItemProxy */;
|
||||
targetProxy = 83DA153420F6EFC90096D348 /* PBXContainerItemProxy */;
|
||||
};
|
||||
83DE0CBB180B02C500269051 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
|
|
Loading…
Reference in New Issue