diff --git a/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj b/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj index 6ef605075..c722afa40 100644 --- a/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj +++ b/Frameworks/lazyusf/lazyusf.xcodeproj/project.pbxproj @@ -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 = ""; }; 8309DC6220F6E24C0056CC70 /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; 8309DC6320F6E24C0056CC70 /* exception.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = exception.c; sourceTree = ""; }; - 8309DC6520F6E24C0056CC70 /* dbg_decoder.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dbg_decoder.c; sourceTree = ""; }; - 8309DC6620F6E24C0056CC70 /* dbg_decoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbg_decoder.h; sourceTree = ""; }; - 8309DC6720F6E24C0056CC70 /* dbg_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbg_types.h; sourceTree = ""; }; - 8309DC6820F6E24C0056CC70 /* dbg_decoder_local.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbg_decoder_local.h; sourceTree = ""; }; 8309DC6920F6E24C0056CC70 /* rsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rsp.h; sourceTree = ""; }; 8309DC6A20F6E24D0056CC70 /* dma.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dma.c; sourceTree = ""; }; 8309DC6B20F6E24D0056CC70 /* registers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = registers.h; sourceTree = ""; }; @@ -242,11 +238,15 @@ 83CA15161A988138005E7ED4 /* plugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = plugin.c; sourceTree = ""; }; 83CA15171A988138005E7ED4 /* ucodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucodes.h; sourceTree = ""; }; 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 = ""; }; + 83DA153A20F6F2A70096D348 /* dbg_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_types.h; sourceTree = ""; }; + 83DA153B20F6F2A70096D348 /* dbg_decoder_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_decoder_local.h; sourceTree = ""; }; + 83DA153C20F6F2A70096D348 /* dbg_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dbg_decoder.c; sourceTree = ""; }; + 83DA153D20F6F2A70096D348 /* dbg_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dbg_decoder.h; sourceTree = ""; }; 83E1578820F6E2D500BAA65A /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio.h; sourceTree = ""; }; 83E1578A20F6E2E000BAA65A /* interpreter_cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interpreter_cpu.h; sourceTree = ""; }; 83E1578B20F6E2E000BAA65A /* pif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pif.h; sourceTree = ""; }; 83E1578E20F6E32B00BAA65A /* lazyusf-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "lazyusf-Info.plist"; sourceTree = ""; }; - 83E1579120F6E33800BAA65A /* preproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preproc.h; sourceTree = ""; }; 83E1579420F6E39F00BAA65A /* our-stdbool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "our-stdbool.h"; sourceTree = ""; }; /* 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 = ""; @@ -463,7 +463,7 @@ 83E1579020F6E33800BAA65A /* osal */ = { isa = PBXGroup; children = ( - 83E1579120F6E33800BAA65A /* preproc.h */, + 83DA153820F6F28E0096D348 /* preproc.h */, ); path = osal; sourceTree = ""; @@ -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 */, diff --git a/Frameworks/lazyusf/lazyusf/audio.c b/Frameworks/lazyusf/lazyusf/audio.c index 6331dbb53..7ca10ec4f 100644 --- a/Frameworks/lazyusf/lazyusf/audio.c +++ b/Frameworks/lazyusf/lazyusf/audio.c @@ -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); } diff --git a/Frameworks/lazyusf/lazyusf/audio.h b/Frameworks/lazyusf/lazyusf/audio.h index 3721bab18..0ddf66ecf 100644 --- a/Frameworks/lazyusf/lazyusf/audio.h +++ b/Frameworks/lazyusf/lazyusf/audio.h @@ -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 diff --git a/Frameworks/lazyusf/lazyusf/cpu.c b/Frameworks/lazyusf/lazyusf/cpu.c index ef32418ae..cbc942e9c 100644 --- a/Frameworks/lazyusf/lazyusf/cpu.c +++ b/Frameworks/lazyusf/lazyusf/cpu.c @@ -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); diff --git a/Frameworks/lazyusf/lazyusf/cpu.h b/Frameworks/lazyusf/lazyusf/cpu.h index df328580e..027747773 100644 --- a/Frameworks/lazyusf/lazyusf/cpu.h +++ b/Frameworks/lazyusf/lazyusf/cpu.h @@ -37,6 +37,8 @@ #include "opcode.h" #include "usf.h" +#define COUNT_PER_OP_DEFAULT 2 + typedef struct { int32_t DoSomething; int32_t CloseCPU; diff --git a/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder.c b/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder.c new file mode 100644 index 000000000..6cd56ba7b --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder.c @@ -0,0 +1,822 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus -- dbg_decoder.c * + * Copyright (c) 2010 Marshall B. Rogers * + * 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 +#include +#include +#include +#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 ); +} + diff --git a/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder.h b/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder.h new file mode 100644 index 000000000..cd3b93098 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder.h @@ -0,0 +1,61 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - dbg_decoder.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2010 Marshall B. Rogers * + * * + * 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 +#include +#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__ */ + diff --git a/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder_local.h b/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder_local.h new file mode 100644 index 000000000..5ec6372ff --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/debugger/dbg_decoder_local.h @@ -0,0 +1,1481 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - dbg_debugger_local.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2010 Marshall B. Rogers * + * * + * 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_LOCAL_H__ +#define __DECODER_LOCAL_H__ + +#include + +/* $NetBSD: cpuregs.h,v 1.77 2009/12/14 00:46:04 matt Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * @(#)machConst.h 8.1 (Berkeley) 6/10/93 + * + * machConst.h -- + * + * Machine dependent constants. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machConst.h, + * v 9.2 89/10/21 15:55:22 jhh Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAddrs.h, + * v 1.2 89/08/15 18:28:21 rab Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/vm/ds3100.md/RCS/vmPmaxConst.h, + * v 9.1 89/09/18 17:33:00 shirriff Exp SPRITE (DECWRL) + */ + +#ifndef _MIPS_CPUREGS_H_ +#define _MIPS_CPUREGS_H_ + + +/* + * Address space. + * 32-bit mips CPUS partition their 32-bit address space into four segments: + * + * kuseg 0x00000000 - 0x7fffffff User virtual mem, mapped + * kseg0 0x80000000 - 0x9fffffff Physical memory, cached, unmapped + * kseg1 0xa0000000 - 0xbfffffff Physical memory, uncached, unmapped + * kseg2 0xc0000000 - 0xffffffff kernel-virtual, mapped + * + * mips1 physical memory is limited to 512Mbytes, which is + * doubly mapped in kseg0 (cached) and kseg1 (uncached.) + * Caching of mapped addresses is controlled by bits in the TLB entry. + */ + +#ifdef _LP64 +#define MIPS_XUSEG_START (0L << 62) +#define MIPS_XUSEG_P(x) (((uint64_t)(x) >> 62) == 0) +#define MIPS_USEG_P(x) ((uintptr_t)(x) < 0x80000000L) +#define MIPS_XSSEG_START (1L << 62) +#define MIPS_XSSEG_P(x) (((uint64_t)(x) >> 62) == 1) +#endif + +/* + * MIPS addresses are signed and we defining as negative so that + * in LP64 kern they get sign-extended correctly. + */ +#ifndef _LOCORE +#define MIPS_KSEG0_START (-0x7fffffffL-1) /* 0x80000000 */ +#define MIPS_KSEG1_START -0x60000000L /* 0xa0000000 */ +#define MIPS_KSEG2_START -0x40000000L /* 0xc0000000 */ +#define MIPS_MAX_MEM_ADDR -0x42000000L /* 0xbe000000 */ +#define MIPS_RESERVED_ADDR -0x40380000L /* 0xbfc80000 */ +#endif + +#define MIPS_PHYS_MASK 0x1fffffff + +#define MIPS_KSEG0_TO_PHYS(x) ((uintptr_t)(x) & MIPS_PHYS_MASK) +#define MIPS_PHYS_TO_KSEG0(x) ((uintptr_t)(x) | (intptr_t)MIPS_KSEG0_START) +#define MIPS_KSEG1_TO_PHYS(x) ((uintptr_t)(x) & MIPS_PHYS_MASK) +#define MIPS_PHYS_TO_KSEG1(x) ((uintptr_t)(x) | (intptr_t)MIPS_KSEG1_START) + +#define MIPS_KSEG0_P(x) (((intptr_t)(x) & ~MIPS_PHYS_MASK) == MIPS_KSEG0_START) +#define MIPS_KSEG1_P(x) (((intptr_t)(x) & ~MIPS_PHYS_MASK) == MIPS_KSEG1_START) +#define MIPS_KSEG2_P(x) ((uintptr_t)MIPS_KSEG2_START <= (uintptr_t)(x)) + +/* Map virtual address to index in mips3 r4k virtually-indexed cache */ +#define MIPS3_VA_TO_CINDEX(x) \ + (((intptr_t)(x) & 0xffffff) | MIPS_KSEG0_START) + +#ifndef _LOCORE +#define MIPS_XSEG_MASK (0x3fffffffffffffffLL) +#define MIPS_XKSEG_START (0x3ULL << 62) +#define MIPS_XKSEG_P(x) (((uint64_t)(x) >> 62) == 3) + +#define MIPS_XKPHYS_START (0x2ULL << 62) +#define MIPS_PHYS_TO_XKPHYS_UNCACHED(x) \ + (MIPS_XKPHYS_START | ((uint64_t)(CCA_UNCACHED) << 59) | (x)) +#define MIPS_PHYS_TO_XKPHYS_CACHED(x) \ + (mips3_xkphys_cached | (x)) +#define MIPS_PHYS_TO_XKPHYS(cca,x) \ + (MIPS_XKPHYS_START | ((uint64_t)(cca) << 59) | (x)) +#define MIPS_XKPHYS_TO_PHYS(x) ((uint64_t)(x) & 0x07ffffffffffffffLL) +#define MIPS_XKPHYS_TO_CCA(x) (((uint64_t)(x) >> 59) & 7) +#define MIPS_XKPHYS_P(x) (((uint64_t)(x) >> 62) == 2) +#endif /* _LOCORE */ + +#define CCA_UNCACHED 2 +#define CCA_CACHEABLE 3 /* cacheable non-coherent */ + +/* CPU dependent mtc0 hazard hook */ +#define COP0_SYNC /* nothing */ +#define COP0_HAZARD_FPUENABLE nop; nop; nop; nop; + +/* + * The bits in the cause register. + * + * Bits common to r3000 and r4000: + * + * MIPS_CR_BR_DELAY Exception happened in branch delay slot. + * MIPS_CR_COP_ERR Coprocessor error. + * MIPS_CR_IP Interrupt pending bits defined below. + * (same meaning as in CAUSE register). + * MIPS_CR_EXC_CODE The exception type (see exception codes below). + * + * Differences: + * r3k has 4 bits of execption type, r4k has 5 bits. + */ +#define MIPS_CR_BR_DELAY 0x80000000 +#define MIPS_CR_COP_ERR 0x30000000 +#define MIPS1_CR_EXC_CODE 0x0000003C /* four bits */ +#define MIPS3_CR_EXC_CODE 0x0000007C /* five bits */ +#define MIPS_CR_IP 0x0000FF00 +#define MIPS_CR_EXC_CODE_SHIFT 2 + +/* + * The bits in the status register. All bits are active when set to 1. + * + * R3000 status register fields: + * MIPS_SR_COP_USABILITY Control the usability of the four coprocessors. + * MIPS_SR_TS TLB shutdown. + * + * MIPS_SR_INT_IE Master (current) interrupt enable bit. + * + * Differences: + * r3k has cache control is via frobbing SR register bits, whereas the + * r4k cache control is via explicit instructions. + * r3k has a 3-entry stack of kernel/user bits, whereas the + * r4k has kernel/supervisor/user. + */ +#define MIPS_SR_COP_USABILITY 0xf0000000 +#define MIPS_SR_COP_0_BIT 0x10000000 +#define MIPS_SR_COP_1_BIT 0x20000000 + + /* r4k and r3k differences, see below */ + +#define MIPS_SR_MX 0x01000000 /* MIPS64 */ +#define MIPS_SR_PX 0x00800000 /* MIPS64 */ +#define MIPS_SR_BEV 0x00400000 /* Use boot exception vector */ +#define MIPS_SR_TS 0x00200000 + + /* r4k and r3k differences, see below */ + +#define MIPS_SR_INT_IE 0x00000001 +/*#define MIPS_SR_MBZ 0x0f8000c0*/ /* Never used, true for r3k */ +/*#define MIPS_SR_INT_MASK 0x0000ff00*/ + + +/* + * The R2000/R3000-specific status register bit definitions. + * all bits are active when set to 1. + * + * MIPS_SR_PARITY_ERR Parity error. + * MIPS_SR_CACHE_MISS Most recent D-cache load resulted in a miss. + * MIPS_SR_PARITY_ZERO Zero replaces outgoing parity bits. + * MIPS_SR_SWAP_CACHES Swap I-cache and D-cache. + * MIPS_SR_ISOL_CACHES Isolate D-cache from main memory. + * Interrupt enable bits defined below. + * MIPS_SR_KU_OLD Old kernel/user mode bit. 1 => user mode. + * MIPS_SR_INT_ENA_OLD Old interrupt enable bit. + * MIPS_SR_KU_PREV Previous kernel/user mode bit. 1 => user mode. + * MIPS_SR_INT_ENA_PREV Previous interrupt enable bit. + * MIPS_SR_KU_CUR Current kernel/user mode bit. 1 => user mode. + */ + +#define MIPS1_PARITY_ERR 0x00100000 +#define MIPS1_CACHE_MISS 0x00080000 +#define MIPS1_PARITY_ZERO 0x00040000 +#define MIPS1_SWAP_CACHES 0x00020000 +#define MIPS1_ISOL_CACHES 0x00010000 + +#define MIPS1_SR_KU_OLD 0x00000020 /* 2nd stacked KU/IE*/ +#define MIPS1_SR_INT_ENA_OLD 0x00000010 /* 2nd stacked KU/IE*/ +#define MIPS1_SR_KU_PREV 0x00000008 /* 1st stacked KU/IE*/ +#define MIPS1_SR_INT_ENA_PREV 0x00000004 /* 1st stacked KU/IE*/ +#define MIPS1_SR_KU_CUR 0x00000002 /* current KU */ + +/* backwards compatibility */ +#define MIPS_SR_PARITY_ERR MIPS1_PARITY_ERR +#define MIPS_SR_CACHE_MISS MIPS1_CACHE_MISS +#define MIPS_SR_PARITY_ZERO MIPS1_PARITY_ZERO +#define MIPS_SR_SWAP_CACHES MIPS1_SWAP_CACHES +#define MIPS_SR_ISOL_CACHES MIPS1_ISOL_CACHES + +#define MIPS_SR_KU_OLD MIPS1_SR_KU_OLD +#define MIPS_SR_INT_ENA_OLD MIPS1_SR_INT_ENA_OLD +#define MIPS_SR_KU_PREV MIPS1_SR_KU_PREV +#define MIPS_SR_KU_CUR MIPS1_SR_KU_CUR +#define MIPS_SR_INT_ENA_PREV MIPS1_SR_INT_ENA_PREV + +/* + * R4000 status register bit definitons, + * where different from r2000/r3000. + */ +#define MIPS3_SR_XX 0x80000000 +#define MIPS3_SR_RP 0x08000000 +#define MIPS3_SR_FR 0x04000000 +#define MIPS3_SR_RE 0x02000000 + +#define MIPS3_SR_DIAG_DL 0x01000000 /* QED 52xx */ +#define MIPS3_SR_DIAG_IL 0x00800000 /* QED 52xx */ +#define MIPS3_SR_PX 0x00800000 /* MIPS64 */ +#define MIPS3_SR_SR 0x00100000 +#define MIPS3_SR_NMI 0x00080000 /* MIPS32/64 */ +#define MIPS3_SR_DIAG_CH 0x00040000 +#define MIPS3_SR_DIAG_CE 0x00020000 +#define MIPS3_SR_DIAG_PE 0x00010000 +#define MIPS3_SR_EIE 0x00010000 /* TX79/R5900 */ +#define MIPS3_SR_KX 0x00000080 +#define MIPS3_SR_SX 0x00000040 +#define MIPS3_SR_UX 0x00000020 +#define MIPS3_SR_KSU_MASK 0x00000018 +#define MIPS3_SR_KSU_USER 0x00000010 +#define MIPS3_SR_KSU_SUPER 0x00000008 +#define MIPS3_SR_KSU_KERNEL 0x00000000 +#define MIPS3_SR_ERL 0x00000004 +#define MIPS3_SR_EXL 0x00000002 + +#ifdef MIPS3_5900 +#undef MIPS_SR_INT_IE +#define MIPS_SR_INT_IE 0x00010001 /* XXX */ +#endif + +#define MIPS_SR_SOFT_RESET MIPS3_SR_SOFT_RESET +#define MIPS_SR_DIAG_CH MIPS3_SR_DIAG_CH +#define MIPS_SR_DIAG_CE MIPS3_SR_DIAG_CE +#define MIPS_SR_DIAG_PE MIPS3_SR_DIAG_PE +#define MIPS_SR_KX MIPS3_SR_KX +#define MIPS_SR_SX MIPS3_SR_SX +#define MIPS_SR_UX MIPS3_SR_UX + +#define MIPS_SR_KSU_MASK MIPS3_SR_KSU_MASK +#define MIPS_SR_KSU_USER MIPS3_SR_KSU_USER +#define MIPS_SR_KSU_SUPER MIPS3_SR_KSU_SUPER +#define MIPS_SR_KSU_KERNEL MIPS3_SR_KSU_KERNEL +#define MIPS_SR_ERL MIPS3_SR_ERL +#define MIPS_SR_EXL MIPS3_SR_EXL + + +/* + * The interrupt masks. + * If a bit in the mask is 1 then the interrupt is enabled (or pending). + */ +#define MIPS_INT_MASK 0xff00 +#define MIPS_INT_MASK_5 0x8000 +#define MIPS_INT_MASK_4 0x4000 +#define MIPS_INT_MASK_3 0x2000 +#define MIPS_INT_MASK_2 0x1000 +#define MIPS_INT_MASK_1 0x0800 +#define MIPS_INT_MASK_0 0x0400 +#define MIPS_HARD_INT_MASK 0xfc00 +#define MIPS_SOFT_INT_MASK_1 0x0200 +#define MIPS_SOFT_INT_MASK_0 0x0100 + +/* + * mips3 CPUs have on-chip timer at INT_MASK_5. Each platform can + * choose to enable this interrupt. + */ +#if defined(MIPS3_ENABLE_CLOCK_INTR) +#define MIPS3_INT_MASK MIPS_INT_MASK +#define MIPS3_HARD_INT_MASK MIPS_HARD_INT_MASK +#else +#define MIPS3_INT_MASK (MIPS_INT_MASK & ~MIPS_INT_MASK_5) +#define MIPS3_HARD_INT_MASK (MIPS_HARD_INT_MASK & ~MIPS_INT_MASK_5) +#endif + +/* + * The bits in the context register. + */ +#define MIPS1_CNTXT_PTE_BASE 0xFFE00000 +#define MIPS1_CNTXT_BAD_VPN 0x001FFFFC + +#define MIPS3_CNTXT_PTE_BASE 0xFF800000 +#define MIPS3_CNTXT_BAD_VPN2 0x007FFFF0 + +/* + * The bits in the MIPS3 config register. + * + * bit 0..5: R/W, Bit 6..31: R/O + */ + +/* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ +#define MIPS3_CONFIG_K0_MASK 0x00000007 + +/* + * R/W Update on Store Conditional + * 0: Store Conditional uses coherency algorithm specified by TLB + * 1: Store Conditional uses cacheable coherent update on write + */ +#define MIPS3_CONFIG_CU 0x00000008 + +#define MIPS3_CONFIG_DB 0x00000010 /* Primary D-cache line size */ +#define MIPS3_CONFIG_IB 0x00000020 /* Primary I-cache line size */ +#define MIPS3_CONFIG_CACHE_L1_LSIZE(config, bit) \ + (((config) & (bit)) ? 32 : 16) + +#define MIPS3_CONFIG_DC_MASK 0x000001c0 /* Primary D-cache size */ +#define MIPS3_CONFIG_DC_SHIFT 6 +#define MIPS3_CONFIG_IC_MASK 0x00000e00 /* Primary I-cache size */ +#define MIPS3_CONFIG_IC_SHIFT 9 +#define MIPS3_CONFIG_C_DEFBASE 0x1000 /* default base 2^12 */ + +/* Cache size mode indication: available only on Vr41xx CPUs */ +#define MIPS3_CONFIG_CS 0x00001000 +#define MIPS3_CONFIG_C_4100BASE 0x0400 /* base is 2^10 if CS=1 */ +#define MIPS3_CONFIG_CACHE_SIZE(config, mask, base, shift) \ + ((base) << (((config) & (mask)) >> (shift))) + +/* External cache enable: Controls L2 for R5000/Rm527x and L3 for Rm7000 */ +#define MIPS3_CONFIG_SE 0x00001000 + +/* Block ordering: 0: sequential, 1: sub-block */ +#define MIPS3_CONFIG_EB 0x00002000 + +/* ECC mode - 0: ECC mode, 1: parity mode */ +#define MIPS3_CONFIG_EM 0x00004000 + +/* BigEndianMem - 0: kernel and memory are little endian, 1: big endian */ +#define MIPS3_CONFIG_BE 0x00008000 + +/* Dirty Shared coherency state - 0: enabled, 1: disabled */ +#define MIPS3_CONFIG_SM 0x00010000 + +/* Secondary Cache - 0: present, 1: not present */ +#define MIPS3_CONFIG_SC 0x00020000 + +/* System Port width - 0: 64-bit, 1: 32-bit (QED RM523x), 2,3: reserved */ +#define MIPS3_CONFIG_EW_MASK 0x000c0000 +#define MIPS3_CONFIG_EW_SHIFT 18 + +/* Secondary Cache port width - 0: 128-bit data path to S-cache, 1: reserved */ +#define MIPS3_CONFIG_SW 0x00100000 + +/* Split Secondary Cache Mode - 0: I/D mixed, 1: I/D separated by SCAddr(17) */ +#define MIPS3_CONFIG_SS 0x00200000 + +/* Secondary Cache line size */ +#define MIPS3_CONFIG_SB_MASK 0x00c00000 +#define MIPS3_CONFIG_SB_SHIFT 22 +#define MIPS3_CONFIG_CACHE_L2_LSIZE(config) \ + (0x10 << (((config) & MIPS3_CONFIG_SB_MASK) >> MIPS3_CONFIG_SB_SHIFT)) + +/* Write back data rate */ +#define MIPS3_CONFIG_EP_MASK 0x0f000000 +#define MIPS3_CONFIG_EP_SHIFT 24 + +/* System clock ratio - this value is CPU dependent */ +#define MIPS3_CONFIG_EC_MASK 0x70000000 +#define MIPS3_CONFIG_EC_SHIFT 28 + +/* Master-Checker Mode - 1: enabled */ +#define MIPS3_CONFIG_CM 0x80000000 + +/* + * The bits in the MIPS4 config register. + */ + +/* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ +#define MIPS4_CONFIG_K0_MASK MIPS3_CONFIG_K0_MASK +#define MIPS4_CONFIG_DN_MASK 0x00000018 /* Device number */ +#define MIPS4_CONFIG_CT 0x00000020 /* CohPrcReqTar */ +#define MIPS4_CONFIG_PE 0x00000040 /* PreElmReq */ +#define MIPS4_CONFIG_PM_MASK 0x00000180 /* PreReqMax */ +#define MIPS4_CONFIG_EC_MASK 0x00001e00 /* SysClkDiv */ +#define MIPS4_CONFIG_SB 0x00002000 /* SCBlkSize */ +#define MIPS4_CONFIG_SK 0x00004000 /* SCColEn */ +#define MIPS4_CONFIG_BE 0x00008000 /* MemEnd */ +#define MIPS4_CONFIG_SS_MASK 0x00070000 /* SCSize */ +#define MIPS4_CONFIG_SC_MASK 0x00380000 /* SCClkDiv */ +#define MIPS4_CONFIG_RESERVED 0x03c00000 /* Reserved wired 0 */ +#define MIPS4_CONFIG_DC_MASK 0x1c000000 /* Primary D-Cache size */ +#define MIPS4_CONFIG_IC_MASK 0xe0000000 /* Primary I-Cache size */ + +#define MIPS4_CONFIG_DC_SHIFT 26 +#define MIPS4_CONFIG_IC_SHIFT 29 + +#define MIPS4_CONFIG_CACHE_SIZE(config, mask, base, shift) \ + ((base) << (((config) & (mask)) >> (shift))) + +#define MIPS4_CONFIG_CACHE_L2_LSIZE(config) \ + (((config) & MIPS4_CONFIG_SB) ? 128 : 64) + +/* + * Location of exception vectors. + * + * Common vectors: reset and UTLB miss. + */ +#define MIPS_RESET_EXC_VEC MIPS_PHYS_TO_KSEG1(0x1FC00000) +#define MIPS_UTLB_MISS_EXC_VEC MIPS_PHYS_TO_KSEG0(0) + +/* + * MIPS-1 general exception vector (everything else) + */ +#define MIPS1_GEN_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0080) + +/* + * MIPS-III exception vectors + */ +#define MIPS3_XTLB_MISS_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0080) +#define MIPS3_CACHE_ERR_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0100) +#define MIPS3_GEN_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0180) + +/* + * TX79 (R5900) exception vectors + */ +#define MIPS_R5900_COUNTER_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0080) +#define MIPS_R5900_DEBUG_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0100) + +/* + * MIPS32/MIPS64 (and some MIPS3) dedicated interrupt vector. + */ +#define MIPS3_INTR_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0200) + +/* + * Coprocessor 0 registers: + * + * v--- width for mips I,III,32,64 + * (3=32bit, 6=64bit, i=impl dep) + * 0 MIPS_COP_0_TLB_INDEX 3333 TLB Index. + * 1 MIPS_COP_0_TLB_RANDOM 3333 TLB Random. + * 2 MIPS_COP_0_TLB_LOW 3... r3k TLB entry low. + * 2 MIPS_COP_0_TLB_LO0 .636 r4k TLB entry low. + * 3 MIPS_COP_0_TLB_LO1 .636 r4k TLB entry low, extended. + * 4 MIPS_COP_0_TLB_CONTEXT 3636 TLB Context. + * 5 MIPS_COP_0_TLB_PG_MASK .333 TLB Page Mask register. + * 6 MIPS_COP_0_TLB_WIRED .333 Wired TLB number. + * 8 MIPS_COP_0_BAD_VADDR 3636 Bad virtual address. + * 9 MIPS_COP_0_COUNT .333 Count register. + * 10 MIPS_COP_0_TLB_HI 3636 TLB entry high. + * 11 MIPS_COP_0_COMPARE .333 Compare (against Count). + * 12 MIPS_COP_0_STATUS 3333 Status register. + * 13 MIPS_COP_0_CAUSE 3333 Exception cause register. + * 14 MIPS_COP_0_EXC_PC 3636 Exception PC. + * 15 MIPS_COP_0_PRID 3333 Processor revision identifier. + * 15/1 MIPS_COP_0_EBASE ..33 Exception Base + * 16 MIPS_COP_0_CONFIG 3333 Configuration register. + * 16/1 MIPS_COP_0_CONFIG1 ..33 Configuration register 1. + * 16/2 MIPS_COP_0_CONFIG2 ..33 Configuration register 2. + * 16/3 MIPS_COP_0_CONFIG3 ..33 Configuration register 3. + * 17 MIPS_COP_0_LLADDR .336 Load Linked Address. + * 18 MIPS_COP_0_WATCH_LO .336 WatchLo register. + * 19 MIPS_COP_0_WATCH_HI .333 WatchHi register. + * 20 MIPS_COP_0_TLB_XCONTEXT .6.6 TLB XContext register. + * 23 MIPS_COP_0_DEBUG .... Debug JTAG register. + * 24 MIPS_COP_0_DEPC .... DEPC JTAG register. + * 25 MIPS_COP_0_PERFCNT ..36 Performance Counter register. + * 26 MIPS_COP_0_ECC .3ii ECC / Error Control register. + * 27 MIPS_COP_0_CACHE_ERR .3ii Cache Error register. + * 28/0 MIPS_COP_0_TAG_LO .3ii Cache TagLo register (instr). + * 28/1 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (instr). + * 28/2 MIPS_COP_0_TAG_LO ..ii Cache TagLo register (data). + * 28/3 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (data). + * 29/0 MIPS_COP_0_TAG_HI .3ii Cache TagHi register (instr). + * 29/1 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (instr). + * 29/2 MIPS_COP_0_TAG_HI ..ii Cache TagHi register (data). + * 29/3 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (data). + * 30 MIPS_COP_0_ERROR_PC .636 Error EPC register. + * 31 MIPS_COP_0_DESAVE .... DESAVE JTAG register. + */ +#ifdef _LOCORE +#define _(n) __CONCAT($,n) +#else +#define _(n) n +#endif +#define MIPS_COP_0_TLB_INDEX _(0) +#define MIPS_COP_0_TLB_RANDOM _(1) + /* Name and meaning of TLB bits for $2 differ on r3k and r4k. */ + +#define MIPS_COP_0_TLB_CONTEXT _(4) + /* $5 and $6 new with MIPS-III */ +#define MIPS_COP_0_BAD_VADDR _(8) +#define MIPS_COP_0_TLB_HI _(10) +#define MIPS_COP_0_STATUS _(12) +#define MIPS_COP_0_CAUSE _(13) +#define MIPS_COP_0_EXC_PC _(14) +#define MIPS_COP_0_PRID _(15) + + +/* MIPS-I */ +#define MIPS_COP_0_TLB_LOW _(2) + +/* MIPS-III */ +#define MIPS_COP_0_TLB_LO0 _(2) +#define MIPS_COP_0_TLB_LO1 _(3) + +#define MIPS_COP_0_TLB_PG_MASK _(5) +#define MIPS_COP_0_TLB_WIRED _(6) + +#define MIPS_COP_0_COUNT _(9) +#define MIPS_COP_0_COMPARE _(11) + +#define MIPS_COP_0_CONFIG _(16) +#define MIPS_COP_0_LLADDR _(17) +#define MIPS_COP_0_WATCH_LO _(18) +#define MIPS_COP_0_WATCH_HI _(19) +#define MIPS_COP_0_TLB_XCONTEXT _(20) +#define MIPS_COP_0_ECC _(26) +#define MIPS_COP_0_CACHE_ERR _(27) +#define MIPS_COP_0_TAG_LO _(28) +#define MIPS_COP_0_TAG_HI _(29) +#define MIPS_COP_0_ERROR_PC _(30) + +/* MIPS32/64 */ +#define MIPS_COP_0_DEBUG _(23) +#define MIPS_COP_0_DEPC _(24) +#define MIPS_COP_0_PERFCNT _(25) +#define MIPS_COP_0_DATA_LO _(28) +#define MIPS_COP_0_DATA_HI _(29) +#define MIPS_COP_0_DESAVE _(31) + +/* + * Values for the code field in a break instruction. + */ +#define MIPS_BREAK_INSTR 0x0000000d +#define MIPS_BREAK_VAL_MASK 0x03ff0000 +#define MIPS_BREAK_VAL_SHIFT 16 +#define MIPS_BREAK_KDB_VAL 512 +#define MIPS_BREAK_SSTEP_VAL 513 +#define MIPS_BREAK_BRKPT_VAL 514 +#define MIPS_BREAK_SOVER_VAL 515 +#define MIPS_BREAK_KDB (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_KDB_VAL << MIPS_BREAK_VAL_SHIFT)) +#define MIPS_BREAK_SSTEP (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_SSTEP_VAL << MIPS_BREAK_VAL_SHIFT)) +#define MIPS_BREAK_BRKPT (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_BRKPT_VAL << MIPS_BREAK_VAL_SHIFT)) +#define MIPS_BREAK_SOVER (MIPS_BREAK_INSTR | \ + (MIPS_BREAK_SOVER_VAL << MIPS_BREAK_VAL_SHIFT)) + +/* + * Mininum and maximum cache sizes. + */ +#define MIPS_MIN_CACHE_SIZE (16 * 1024) +#define MIPS_MAX_CACHE_SIZE (256 * 1024) +#define MIPS3_MAX_PCACHE_SIZE (32 * 1024) /* max. primary cache size */ + +/* + * The floating point version and status registers. + */ +#define MIPS_FPU_ID $0 +#define MIPS_FPU_CSR $31 + +/* + * The floating point coprocessor status register bits. + */ +#define MIPS_FPU_ROUNDING_BITS 0x00000003 +#define MIPS_FPU_ROUND_RN 0x00000000 +#define MIPS_FPU_ROUND_RZ 0x00000001 +#define MIPS_FPU_ROUND_RP 0x00000002 +#define MIPS_FPU_ROUND_RM 0x00000003 +#define MIPS_FPU_STICKY_BITS 0x0000007c +#define MIPS_FPU_STICKY_INEXACT 0x00000004 +#define MIPS_FPU_STICKY_UNDERFLOW 0x00000008 +#define MIPS_FPU_STICKY_OVERFLOW 0x00000010 +#define MIPS_FPU_STICKY_DIV0 0x00000020 +#define MIPS_FPU_STICKY_INVALID 0x00000040 +#define MIPS_FPU_ENABLE_BITS 0x00000f80 +#define MIPS_FPU_ENABLE_INEXACT 0x00000080 +#define MIPS_FPU_ENABLE_UNDERFLOW 0x00000100 +#define MIPS_FPU_ENABLE_OVERFLOW 0x00000200 +#define MIPS_FPU_ENABLE_DIV0 0x00000400 +#define MIPS_FPU_ENABLE_INVALID 0x00000800 +#define MIPS_FPU_EXCEPTION_BITS 0x0003f000 +#define MIPS_FPU_EXCEPTION_INEXACT 0x00001000 +#define MIPS_FPU_EXCEPTION_UNDERFLOW 0x00002000 +#define MIPS_FPU_EXCEPTION_OVERFLOW 0x00004000 +#define MIPS_FPU_EXCEPTION_DIV0 0x00008000 +#define MIPS_FPU_EXCEPTION_INVALID 0x00010000 +#define MIPS_FPU_EXCEPTION_UNIMPL 0x00020000 +#define MIPS_FPU_COND_BIT 0x00800000 +#define MIPS_FPU_FLUSH_BIT 0x01000000 /* r4k, MBZ on r3k */ +#define MIPS1_FPC_MBZ_BITS 0xff7c0000 +#define MIPS3_FPC_MBZ_BITS 0xfe7c0000 + + +/* + * Constants to determine if have a floating point instruction. + */ +#define MIPS_OPCODE_SHIFT 26 +#define MIPS_OPCODE_C1 0x11 + + +/* + * The low part of the TLB entry. + */ +#define MIPS1_TLB_PFN 0xfffff000 +#define MIPS1_TLB_NON_CACHEABLE_BIT 0x00000800 +#define MIPS1_TLB_DIRTY_BIT 0x00000400 +#define MIPS1_TLB_VALID_BIT 0x00000200 +#define MIPS1_TLB_GLOBAL_BIT 0x00000100 + +#define MIPS3_TLB_PFN 0x3fffffc0 +#define MIPS3_TLB_ATTR_MASK 0x00000038 +#define MIPS3_TLB_ATTR_SHIFT 3 +#define MIPS3_TLB_DIRTY_BIT 0x00000004 +#define MIPS3_TLB_VALID_BIT 0x00000002 +#define MIPS3_TLB_GLOBAL_BIT 0x00000001 + +#define MIPS1_TLB_PHYS_PAGE_SHIFT 12 +#define MIPS3_TLB_PHYS_PAGE_SHIFT 6 +#define MIPS1_TLB_PF_NUM MIPS1_TLB_PFN +#define MIPS3_TLB_PF_NUM MIPS3_TLB_PFN +#define MIPS1_TLB_MOD_BIT MIPS1_TLB_DIRTY_BIT +#define MIPS3_TLB_MOD_BIT MIPS3_TLB_DIRTY_BIT + +/* + * MIPS3_TLB_ATTR values - coherency algorithm: + * 0: cacheable, noncoherent, write-through, no write allocate + * 1: cacheable, noncoherent, write-through, write allocate + * 2: uncached + * 3: cacheable, noncoherent, write-back (noncoherent) + * 4: cacheable, coherent, write-back, exclusive (exclusive) + * 5: cacheable, coherent, write-back, exclusive on write (sharable) + * 6: cacheable, coherent, write-back, update on write (update) + * 7: uncached, accelerated (gather STORE operations) + */ +#define MIPS3_TLB_ATTR_WT 0 /* IDT */ +#define MIPS3_TLB_ATTR_WT_WRITEALLOCATE 1 /* IDT */ +#define MIPS3_TLB_ATTR_UNCACHED 2 /* R4000/R4400, IDT */ +#define MIPS3_TLB_ATTR_WB_NONCOHERENT 3 /* R4000/R4400, IDT */ +#define MIPS3_TLB_ATTR_WB_EXCLUSIVE 4 /* R4000/R4400 */ +#define MIPS3_TLB_ATTR_WB_SHARABLE 5 /* R4000/R4400 */ +#define MIPS3_TLB_ATTR_WB_UPDATE 6 /* R4000/R4400 */ +#define MIPS4_TLB_ATTR_UNCACHED_ACCELERATED 7 /* R10000 */ + + +/* + * The high part of the TLB entry. + */ +#define MIPS1_TLB_VPN 0xfffff000 +#define MIPS1_TLB_PID 0x00000fc0 +#define MIPS1_TLB_PID_SHIFT 6 + +#define MIPS3_TLB_VPN2 0xffffe000 +#define MIPS3_TLB_ASID 0x000000ff + +#define MIPS1_TLB_VIRT_PAGE_NUM MIPS1_TLB_VPN +#define MIPS3_TLB_VIRT_PAGE_NUM MIPS3_TLB_VPN2 +#define MIPS3_TLB_PID MIPS3_TLB_ASID +#define MIPS_TLB_VIRT_PAGE_SHIFT 12 + +/* + * r3000: shift count to put the index in the right spot. + */ +#define MIPS1_TLB_INDEX_SHIFT 8 + +/* + * The first TLB that write random hits. + */ +#define MIPS1_TLB_FIRST_RAND_ENTRY 8 +#define MIPS3_TLB_WIRED_UPAGES 1 + +/* + * The number of process id entries. + */ +#define MIPS1_TLB_NUM_PIDS 64 +#define MIPS3_TLB_NUM_ASIDS 256 + +/* + * Patch codes to hide CPU design differences between MIPS1 and MIPS3. + */ + +/* XXX simonb: this is before MIPS3_PLUS is defined (and is ugly!) */ + +#if !(defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ + && defined(MIPS1) /* XXX simonb must be neater! */ +#define MIPS_TLB_PID_SHIFT MIPS1_TLB_PID_SHIFT +#define MIPS_TLB_NUM_PIDS MIPS1_TLB_NUM_PIDS +#endif + +#if (defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ + && !defined(MIPS1) /* XXX simonb must be neater! */ +#define MIPS_TLB_PID_SHIFT 0 +#define MIPS_TLB_NUM_PIDS MIPS3_TLB_NUM_ASIDS +#endif + + +#if !defined(MIPS_TLB_PID_SHIFT) +#define MIPS_TLB_PID_SHIFT \ + ((MIPS_HAS_R4K_MMU) ? 0 : MIPS1_TLB_PID_SHIFT) + +#define MIPS_TLB_NUM_PIDS \ + ((MIPS_HAS_R4K_MMU) ? MIPS3_TLB_NUM_ASIDS : MIPS1_TLB_NUM_PIDS) +#endif + +/* + * CPU processor revision IDs for company ID == 0 (non mips32/64 chips) + */ +#define MIPS_R2000 0x01 /* MIPS R2000 ISA I */ +#define MIPS_R3000 0x02 /* MIPS R3000 ISA I */ +#define MIPS_R6000 0x03 /* MIPS R6000 ISA II */ +#define MIPS_R4000 0x04 /* MIPS R4000/R4400 ISA III */ +#define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivative ISA I */ +#define MIPS_R6000A 0x06 /* MIPS R6000A ISA II */ +#define MIPS_R3IDT 0x07 /* IDT R3041 or RC36100 ISA I */ +#define MIPS_R10000 0x09 /* MIPS R10000 ISA IV */ +#define MIPS_R4200 0x0a /* NEC VR4200 ISA III */ +#define MIPS_R4300 0x0b /* NEC VR4300 ISA III */ +#define MIPS_R4100 0x0c /* NEC VR4100 ISA III */ +#define MIPS_R12000 0x0e /* MIPS R12000 ISA IV */ +#define MIPS_R14000 0x0f /* MIPS R14000 ISA IV */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_RC32300 0x18 /* IDT RC32334,332,355 ISA 32 */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R4700 0x21 /* QED R4700 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based ISA I */ +#define MIPS_R4650 0x22 /* QED R4650 ISA III */ +#define MIPS_TX3900 0x22 /* Toshiba TX39 family ISA I */ +#define MIPS_R5000 0x23 /* MIPS R5000 ISA IV */ +#define MIPS_R3NKK 0x23 /* NKK R3000 based ISA I */ +#define MIPS_RC32364 0x26 /* IDT RC32364 ISA 32 */ +#define MIPS_RM7000 0x27 /* QED RM7000 ISA IV */ +#define MIPS_RM5200 0x28 /* QED RM5200s ISA IV */ +#define MIPS_TX4900 0x2d /* Toshiba TX49 family ISA III */ +#define MIPS_R5900 0x2e /* Toshiba R5900 (EECore) ISA --- */ +#define MIPS_RC64470 0x30 /* IDT RC64474/RC64475 ISA III */ +#define MIPS_TX7900 0x38 /* Toshiba TX79 ISA III+*/ +#define MIPS_R5400 0x54 /* NEC VR5400 ISA IV */ +#define MIPS_R5500 0x55 /* NEC VR5500 ISA IV */ +#define MIPS_LOONGSON2 0x63 /* ICT Loongson-2 ISA III */ + +/* + * CPU revision IDs for some prehistoric processors. + */ + +/* For MIPS_R3000 */ +#define MIPS_REV_R2000A 0x16 /* R2000A uses R3000 proc revision */ +#define MIPS_REV_R3000 0x20 +#define MIPS_REV_R3000A 0x30 + +/* For MIPS_TX3900 */ +#define MIPS_REV_TX3912 0x10 +#define MIPS_REV_TX3922 0x30 +#define MIPS_REV_TX3927 0x40 + +/* For MIPS_R4000 */ +#define MIPS_REV_R4000_A 0x00 +#define MIPS_REV_R4000_B 0x22 +#define MIPS_REV_R4000_C 0x30 +#define MIPS_REV_R4400_A 0x40 +#define MIPS_REV_R4400_B 0x50 +#define MIPS_REV_R4400_C 0x60 + +/* For MIPS_TX4900 */ +#define MIPS_REV_TX4927 0x22 + +/* For MIPS_LOONGSON2 */ +#define MIPS_REV_LOONGSON2E 0x02 +#define MIPS_REV_LOONGSON2F 0x03 + +/* + * CPU processor revision IDs for company ID == 1 (MIPS) + */ +#define MIPS_4Kc 0x80 /* MIPS 4Kc ISA 32 */ +#define MIPS_5Kc 0x81 /* MIPS 5Kc ISA 64 */ +#define MIPS_20Kc 0x82 /* MIPS 20Kc ISA 64 */ +#define MIPS_4Kmp 0x83 /* MIPS 4Km/4Kp ISA 32 */ +#define MIPS_4KEc 0x84 /* MIPS 4KEc ISA 32 */ +#define MIPS_4KEmp 0x85 /* MIPS 4KEm/4KEp ISA 32 */ +#define MIPS_4KSc 0x86 /* MIPS 4KSc ISA 32 */ +#define MIPS_M4K 0x87 /* MIPS M4K ISA 32 Rel 2 */ +#define MIPS_25Kf 0x88 /* MIPS 25Kf ISA 64 */ +#define MIPS_5KE 0x89 /* MIPS 5KE ISA 64 Rel 2 */ +#define MIPS_4KEc_R2 0x90 /* MIPS 4KEc_R2 ISA 32 Rel 2 */ +#define MIPS_4KEmp_R2 0x91 /* MIPS 4KEm/4KEp_R2 ISA 32 Rel 2 */ +#define MIPS_4KSd 0x92 /* MIPS 4KSd ISA 32 Rel 2 */ +#define MIPS_24K 0x93 /* MIPS 24Kc/24Kf ISA 32 Rel 2 */ +#define MIPS_34K 0x95 /* MIPS 34K ISA 32 R2 MT */ +#define MIPS_24KE 0x96 /* MIPS 24KEc ISA 32 Rel 2 */ +#define MIPS_74K 0x97 /* MIPS 74Kc/74Kf ISA 32 Rel 2 */ + +/* + * Alchemy (company ID 3) use the processor ID field to donote the CPU core + * revision and the company options field do donate the SOC chip type. + */ +/* CPU processor revision IDs */ +#define MIPS_AU_REV1 0x01 /* Alchemy Au1000 (Rev 1) ISA 32 */ +#define MIPS_AU_REV2 0x02 /* Alchemy Au1000 (Rev 2) ISA 32 */ +/* CPU company options IDs */ +#define MIPS_AU1000 0x00 +#define MIPS_AU1500 0x01 +#define MIPS_AU1100 0x02 +#define MIPS_AU1550 0x03 + +/* + * CPU processor revision IDs for company ID == 4 (SiByte) + */ +#define MIPS_SB1 0x01 /* SiByte SB1 ISA 64 */ + +/* + * CPU processor revision IDs for company ID == 5 (SandCraft) + */ +#define MIPS_SR7100 0x04 /* SandCraft SR7100 ISA 64 */ + +/* + * CPU processor revision IDs for company ID == 12 (RMI) + */ +#define MIPS_XLR732 0x00 /* RMI XLR732-C ISA 64 */ +#define MIPS_XLR716 0x02 /* RMI XLR716-C ISA 64 */ +#define MIPS_XLR532 0x08 /* RMI XLR532-C ISA 64 */ +#define MIPS_XLR516 0x0a /* RMI XLR516-C ISA 64 */ +#define MIPS_XLR508 0x0b /* RMI XLR508-C ISA 64 */ +#define MIPS_XLR308 0x0f /* RMI XLR308-C ISA 64 */ +#define MIPS_XLS616 0x40 /* RMI XLS616 ISA 64 */ +#define MIPS_XLS416 0x44 /* RMI XLS416 ISA 64 */ +#define MIPS_XLS608 0x4A /* RMI XLS608 ISA 64 */ +#define MIPS_XLS408 0x4E /* RMI XLS406 ISA 64 */ +#define MIPS_XLS404 0x4F /* RMI XLS404 ISA 64 */ +#define MIPS_XLS408LITE 0x88 /* RMI XLS408-Lite ISA 64 */ +#define MIPS_XLS404LITE 0x8C /* RMI XLS404-Lite ISA 64 */ +#define MIPS_XLS208 0x8E /* RMI XLS208 ISA 64 */ +#define MIPS_XLS204 0x8F /* RMI XLS204 ISA 64 */ +#define MIPS_XLS108 0xCE /* RMI XLS108 ISA 64 */ +#define MIPS_XLS104 0xCF /* RMI XLS104 ISA 64 */ + +/* + * FPU processor revision ID + */ +#define MIPS_SOFT 0x00 /* Software emulation ISA I */ +#define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ +#define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ +#define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ +#define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ +#define MIPS_R4010 0x05 /* MIPS R4010 FPC ISA II */ +#define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ + +#endif /* _MIPS_CPUREGS_H_ */ + +/* $NetBSD: cpu.h,v 1.94 2009/12/14 00:46:04 matt Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * @(#)cpu.h 8.4 (Berkeley) 1/4/94 + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + + +/* + * bitfield defines for cpu_cp0flags + */ +#define MIPS_CP0FL_USE __BIT(0) /* use these flags */ +#define MIPS_CP0FL_ECC __BIT(1) +#define MIPS_CP0FL_CACHE_ERR __BIT(2) +#define MIPS_CP0FL_EIRR __BIT(3) +#define MIPS_CP0FL_EIMR __BIT(4) +#define MIPS_CP0FL_EBASE __BIT(5) +#define MIPS_CP0FL_CONFIG __BIT(6) +#define MIPS_CP0FL_CONFIGn(n) (__BIT(7) << ((n) & 7)) + +/* + * cpu_cidflags defines, by company + */ +/* + * RMI company-specific cpu_cidflags + */ +#define MIPS_CIDFL_RMI_TYPE __BITS(0,2) +#define CIDFL_RMI_TYPE_XLR 0 +#define CIDFL_RMI_TYPE_XLS 1 +#define CIDFL_RMI_TYPE_XLP 2 + + +#define CPU_INFO_ITERATOR int +#define CPU_INFO_FOREACH(cii, ci) \ + (void)(cii), ci = &cpu_info_store; ci != NULL; ci = ci->ci_next + + +/* + * CTL_MACHDEP definitions. + */ +#define CPU_CONSDEV 1 /* dev_t: console terminal device */ +#define CPU_BOOTED_KERNEL 2 /* string: booted kernel name */ +#define CPU_ROOT_DEVICE 3 /* string: root device name */ +#define CPU_LLSC 4 /* OS/CPU supports LL/SC instruction */ + +/* + * Platform can override, but note this breaks userland compatibility + * with other mips platforms. + */ +#ifndef CPU_MAXID +#define CPU_MAXID 5 /* number of valid machdep ids */ + +#endif + +#ifdef _KERNEL +#if defined(_LKM) || defined(_STANDALONE) +/* Assume all CPU architectures are valid for LKM's and standlone progs */ +#define MIPS1 1 +#define MIPS3 1 +#define MIPS4 1 +#define MIPS32 1 +#define MIPS64 1 +#endif + +#if (MIPS1 + MIPS3 + MIPS4 + MIPS32 + MIPS64) == 0 +#error at least one of MIPS1, MIPS3, MIPS4, MIPS32 or MIPS64 must be specified +#endif + +/* Shortcut for MIPS3 or above defined */ +#if defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64) +#define MIPS3_PLUS 1 +#else +#undef MIPS3_PLUS +#endif + +/* + * Macros to find the CPU architecture we're on at run-time, + * or if possible, at compile-time. + */ + +#define CPU_ARCH_MIPSx 0 /* XXX unknown */ +#define CPU_ARCH_MIPS1 (1 << 0) +#define CPU_ARCH_MIPS2 (1 << 1) +#define CPU_ARCH_MIPS3 (1 << 2) +#define CPU_ARCH_MIPS4 (1 << 3) +#define CPU_ARCH_MIPS5 (1 << 4) +#define CPU_ARCH_MIPS32 (1 << 5) +#define CPU_ARCH_MIPS64 (1 << 6) + +/* Note: must be kept in sync with -ffixed-?? Makefile.mips. */ +#define MIPS_CURLWP $23 +#define MIPS_CURLWP_QUOTED "$23" +#define MIPS_CURLWP_CARD 23 +#define MIPS_CURLWP_FRAME(x) FRAME_S7(x) + +#ifndef _LOCORE + +#define curlwp mips_curlwp +#define curcpu() (curlwp->l_cpu) +#define curpcb ((struct pcb *)lwp_getpcb(curlwp)) +#define fpcurlwp (curcpu()->ci_fpcurlwp) +#define cpu_number() (0) +#define cpu_proc_fork(p1, p2) ((void)((p2)->p_md.md_abi = (p1)->p_md.md_abi)) + +/* XXX simonb + * Should the following be in a cpu_info type structure? + * And how many of these are per-cpu vs. per-system? (Ie, + * we can assume that all cpus have the same mmu-type, but + * maybe not that all cpus run at the same clock speed. + * Some SGI's apparently support R12k and R14k in the same + * box.) + */ + +#define CPU_MIPS_R4K_MMU 0x0001 +#define CPU_MIPS_NO_LLSC 0x0002 +#define CPU_MIPS_CAUSE_IV 0x0004 +#define CPU_MIPS_HAVE_SPECIAL_CCA 0x0008 /* Defaults to '3' if not set. */ +#define CPU_MIPS_CACHED_CCA_MASK 0x0070 +#define CPU_MIPS_CACHED_CCA_SHIFT 4 +#define CPU_MIPS_DOUBLE_COUNT 0x0080 /* 1 cp0 count == 2 clock cycles */ +#define CPU_MIPS_USE_WAIT 0x0100 /* Use "wait"-based cpu_idle() */ +#define CPU_MIPS_NO_WAIT 0x0200 /* Inverse of previous, for mips32/64 */ +#define CPU_MIPS_D_CACHE_COHERENT 0x0400 /* D-cache is fully coherent */ +#define CPU_MIPS_I_D_CACHE_COHERENT 0x0800 /* I-cache funcs don't need to flush the D-cache */ +#define CPU_MIPS_NO_LLADDR 0x1000 +#define CPU_MIPS_HAVE_MxCR 0x2000 /* have mfcr, mtcr insns */ +#define MIPS_NOT_SUPP 0x8000 + +#endif /* !_LOCORE */ + +#if ((MIPS1 + MIPS3 + MIPS4 + MIPS32 + MIPS64) == 1) || defined(_LOCORE) + +#if defined(MIPS1) + +# define CPUISMIPS3 0 +# define CPUIS64BITS 0 +# define CPUISMIPS32 0 +# define CPUISMIPS64 0 +# define CPUISMIPSNN 0 +# define MIPS_HAS_R4K_MMU 0 +# define MIPS_HAS_CLOCK 0 +# define MIPS_HAS_LLSC 0 +# define MIPS_HAS_LLADDR 0 + +#elif defined(MIPS3) || defined(MIPS4) + +# define CPUISMIPS3 1 +# define CPUIS64BITS 1 +# define CPUISMIPS32 0 +# define CPUISMIPS64 0 +# define CPUISMIPSNN 0 +# define MIPS_HAS_R4K_MMU 1 +# define MIPS_HAS_CLOCK 1 +# if defined(_LOCORE) +# if !defined(MIPS3_5900) && !defined(MIPS3_4100) +# define MIPS_HAS_LLSC 1 +# else +# define MIPS_HAS_LLSC 0 +# endif +# else /* _LOCORE */ +# define MIPS_HAS_LLSC (mips_has_llsc) +# endif /* _LOCORE */ +# define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) + +#elif defined(MIPS32) + +# define CPUISMIPS3 1 +# define CPUIS64BITS 0 +# define CPUISMIPS32 1 +# define CPUISMIPS64 0 +# define CPUISMIPSNN 1 +# define MIPS_HAS_R4K_MMU 1 +# define MIPS_HAS_CLOCK 1 +# define MIPS_HAS_LLSC 1 +# define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) + +#elif defined(MIPS64) + +# define CPUISMIPS3 1 +# define CPUIS64BITS 1 +# define CPUISMIPS32 0 +# define CPUISMIPS64 1 +# define CPUISMIPSNN 1 +# define MIPS_HAS_R4K_MMU 1 +# define MIPS_HAS_CLOCK 1 +# define MIPS_HAS_LLSC 1 +# define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) + +#endif + +#else /* run-time test */ + +#ifndef _LOCORE + +#define MIPS_HAS_R4K_MMU (mips_has_r4k_mmu) +#define MIPS_HAS_LLSC (mips_has_llsc) +#define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) + +/* This test is ... rather bogus */ +#define CPUISMIPS3 ((cpu_arch & \ + (CPU_ARCH_MIPS3 | CPU_ARCH_MIPS4 | CPU_ARCH_MIPS32 | CPU_ARCH_MIPS64)) != 0) + +/* And these aren't much better while the previous test exists as is... */ +#define CPUISMIPS32 ((cpu_arch & CPU_ARCH_MIPS32) != 0) +#define CPUISMIPS64 ((cpu_arch & CPU_ARCH_MIPS64) != 0) +#define CPUISMIPSNN ((cpu_arch & (CPU_ARCH_MIPS32 | CPU_ARCH_MIPS64)) != 0) +#define CPUIS64BITS ((cpu_arch & \ + (CPU_ARCH_MIPS3 | CPU_ARCH_MIPS4 | CPU_ARCH_MIPS64)) != 0) + +#define MIPS_HAS_CLOCK (cpu_arch >= CPU_ARCH_MIPS3) + +#else /* !_LOCORE */ + +#define MIPS_HAS_LLSC 0 + +#endif /* !_LOCORE */ + +#endif /* run-time test */ + +#ifndef _LOCORE + +/* + * A port must provde CLKF_USERMODE() for use in machine-independent code. + * These differ on r4000 and r3000 systems; provide them in the + * port-dependent file that includes this one, using the macros below. + */ + +/* mips1 versions */ +#define MIPS1_CLKF_USERMODE(framep) ((framep)->sr & MIPS_SR_KU_PREV) + +/* mips3 versions */ +#define MIPS3_CLKF_USERMODE(framep) ((framep)->sr & MIPS_SR_KSU_USER) + +#define CLKF_PC(framep) ((framep)->pc) +#define CLKF_INTR(framep) (0) + +#if defined(MIPS3_PLUS) && !defined(MIPS1) /* XXX bogus! */ +#define CLKF_USERMODE(framep) MIPS3_CLKF_USERMODE(framep) +#endif + +#if !defined(MIPS3_PLUS) && defined(MIPS1) /* XXX bogus! */ +#define CLKF_USERMODE(framep) MIPS1_CLKF_USERMODE(framep) +#endif + +#if defined(MIPS3_PLUS) && defined(MIPS1) /* XXX bogus! */ +#define CLKF_USERMODE(framep) \ + ((CPUISMIPS3) ? MIPS3_CLKF_USERMODE(framep): MIPS1_CLKF_USERMODE(framep)) +#endif + +/* + * This is used during profiling to integrate system time. It can safely + * assume that the process is resident. + */ +#define PROC_PC(p) \ + (((struct frame *)(p)->p_md.md_regs)->f_regs[37]) /* XXX PC */ + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the MIPS, request an ast to send us + * through trap, marking the proc as needing a profiling tick. + */ +#define cpu_need_proftick(l) \ +do { \ + (l)->l_pflag |= LP_OWEUPC; \ + aston(l); \ +} while (/*CONSTCOND*/0) + +/* + * Notify the current lwp (l) that it has a signal pending, + * process as soon as possible. + */ +#define cpu_signotify(l) aston(l) + +#define aston(l) ((l)->l_md.md_astpending = 1) + + +#endif /* ! _LOCORE */ +#endif /* _KERNEL */ +#endif /* _CPU_H_ */ + + +/* $NetBSD: mips_opcode.h,v 1.13 2009/08/06 04:34:50 msaitoh Exp $ */ + +/*- + * Copyright (c) 1992, 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. + * + * @(#)mips_opcode.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Define the instruction formats and opcode values for the + * MIPS instruction set. + */ + +/* + * Define the instruction formats. + */ + + +typedef union { + unsigned word; + struct { + unsigned imm: 16; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } IType; + + struct { + unsigned target: 26; + unsigned op: 6; + } JType; + + struct { + unsigned func: 6; + unsigned shamt: 5; + unsigned rd: 5; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } RType; + + struct { + unsigned func: 6; + unsigned fd: 5; + unsigned fs: 5; + unsigned ft: 5; + unsigned fmt: 4; + unsigned : 1; /* always '1' */ + unsigned op: 6; /* always '0x11' */ + } FRType; +} InstFmt; + +/* + * Values for the 'op' field. + */ +#define OP_SPECIAL 000 +#define OP_BCOND 001 +#define OP_J 002 +#define OP_JAL 003 +#define OP_BEQ 004 +#define OP_BNE 005 +#define OP_BLEZ 006 +#define OP_BGTZ 007 + +#define OP_ADDI 010 +#define OP_ADDIU 011 +#define OP_SLTI 012 +#define OP_SLTIU 013 +#define OP_ANDI 014 +#define OP_ORI 015 +#define OP_XORI 016 +#define OP_LUI 017 + +#define OP_COP0 020 +#define OP_COP1 021 +#define OP_COP2 022 +#define OP_COP3 023 +#define OP_BEQL 024 /* MIPS-II, for r4000 port */ +#define OP_BNEL 025 /* MIPS-II, for r4000 port */ +#define OP_BLEZL 026 /* MIPS-II, for r4000 port */ +#define OP_BGTZL 027 /* MIPS-II, for r4000 port */ + +#define OP_DADDI 030 /* MIPS-II, for r4000 port */ +#define OP_DADDIU 031 /* MIPS-II, for r4000 port */ +#define OP_LDL 032 /* MIPS-II, for r4000 port */ +#define OP_LDR 033 /* MIPS-II, for r4000 port */ + +#define OP_SPECIAL2 034 /* QED opcodes */ + +#define OP_LB 040 +#define OP_LH 041 +#define OP_LWL 042 +#define OP_LW 043 +#define OP_LBU 044 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LWU 047 /* MIPS-II, for r4000 port */ + +#define OP_SB 050 +#define OP_SH 051 +#define OP_SWL 052 +#define OP_SW 053 +#define OP_SDL 054 /* MIPS-II, for r4000 port */ +#define OP_SDR 055 /* MIPS-II, for r4000 port */ +#define OP_SWR 056 +#define OP_CACHE 057 /* MIPS-II, for r4000 port */ + +#define OP_LL 060 +#define OP_LWC0 OP_LL /* backwards source compatibility */ +#define OP_LWC1 061 +#define OP_LWC2 062 +#define OP_LWC3 063 +#define OP_LLD 064 /* MIPS-II, for r4000 port */ +#define OP_LDC1 065 +#define OP_LD 067 /* MIPS-II, for r4000 port */ + +#define OP_SC 070 +#define OP_SWC0 OP_SC /* backwards source compatibility */ +#define OP_SWC1 071 +#define OP_SWC2 072 +#define OP_SWC3 073 +#define OP_SCD 074 /* MIPS-II, for r4000 port */ +#define OP_SDC1 075 +#define OP_SD 077 /* MIPS-II, for r4000 port */ + +/* + * Values for the 'func' field when 'op' == OP_SPECIAL. + */ +#define OP_SLL 000 +#define OP_SRL 002 +#define OP_SRA 003 +#define OP_SLLV 004 +#define OP_SRLV 006 +#define OP_SRAV 007 + +#define OP_JR 010 +#define OP_JALR 011 +#define OP_SYSCALL 014 +#define OP_BREAK 015 +#define OP_SYNC 017 /* MIPS-II, for r4000 port */ + +#define OP_MFHI 020 +#define OP_MTHI 021 +#define OP_MFLO 022 +#define OP_MTLO 023 +#define OP_DSLLV 024 /* MIPS-II, for r4000 port */ +#define OP_DSRLV 026 /* MIPS-II, for r4000 port */ +#define OP_DSRAV 027 /* MIPS-II, for r4000 port */ + +#define OP_MULT 030 +#define OP_MULTU 031 +#define OP_DIV 032 +#define OP_DIVU 033 +#define OP_DMULT 034 /* MIPS-II, for r4000 port */ +#define OP_DMULTU 035 /* MIPS-II, for r4000 port */ +#define OP_DDIV 036 /* MIPS-II, for r4000 port */ +#define OP_DDIVU 037 /* MIPS-II, for r4000 port */ + +#define OP_ADD 040 +#define OP_ADDU 041 +#define OP_SUB 042 +#define OP_SUBU 043 +#define OP_AND 044 +#define OP_OR 045 +#define OP_XOR 046 +#define OP_NOR 047 + +#define OP_SLT 052 +#define OP_SLTU 053 +#define OP_DADD 054 /* MIPS-II, for r4000 port */ +#define OP_DADDU 055 /* MIPS-II, for r4000 port */ +#define OP_DSUB 056 /* MIPS-II, for r4000 port */ +#define OP_DSUBU 057 /* MIPS-II, for r4000 port */ + +#define OP_TGE 060 /* MIPS-II, for r4000 port */ +#define OP_TGEU 061 /* MIPS-II, for r4000 port */ +#define OP_TLT 062 /* MIPS-II, for r4000 port */ +#define OP_TLTU 063 /* MIPS-II, for r4000 port */ +#define OP_TEQ 064 /* MIPS-II, for r4000 port */ +#define OP_TNE 066 /* MIPS-II, for r4000 port */ + +#define OP_DSLL 070 /* MIPS-II, for r4000 port */ +#define OP_DSRL 072 /* MIPS-II, for r4000 port */ +#define OP_DSRA 073 /* MIPS-II, for r4000 port */ +#define OP_DSLL32 074 /* MIPS-II, for r4000 port */ +#define OP_DSRL32 076 /* MIPS-II, for r4000 port */ +#define OP_DSRA32 077 /* MIPS-II, for r4000 port */ + +/* + * Values for the 'func' field when 'op' == OP_SPECIAL2. + */ +#define OP_MAD 000 /* QED */ +#define OP_MADU 001 /* QED */ +#define OP_MUL 002 /* QED */ + +/* + * Values for the 'func' field when 'op' == OP_BCOND. + */ +#define OP_BLTZ 000 +#define OP_BGEZ 001 +#define OP_BLTZL 002 /* MIPS-II, for r4000 port */ +#define OP_BGEZL 003 /* MIPS-II, for r4000 port */ + +#define OP_TGEI 010 /* MIPS-II, for r4000 port */ +#define OP_TGEIU 011 /* MIPS-II, for r4000 port */ +#define OP_TLTI 012 /* MIPS-II, for r4000 port */ +#define OP_TLTIU 013 /* MIPS-II, for r4000 port */ +#define OP_TEQI 014 /* MIPS-II, for r4000 port */ +#define OP_TNEI 016 /* MIPS-II, for r4000 port */ + +#define OP_BLTZAL 020 /* MIPS-II, for r4000 port */ +#define OP_BGEZAL 021 +#define OP_BLTZALL 022 +#define OP_BGEZALL 023 + +/* + * Values for the 'rs' field when 'op' == OP_COPz. + */ +#define OP_MF 000 +#define OP_DMF 001 /* MIPS-II, for r4000 port */ +#define OP_CF 002 +#define OP_MFH 003 +#define OP_MT 004 +#define OP_DMT 005 /* MIPS-II, for r4000 port */ +#define OP_CT 006 +#define OP_MTH 007 +#define OP_BCx 010 +#define OP_BCy 014 + +/* + * Values for the 'rt' field when 'op' == OP_COPz. + */ +#define COPz_BC_TF_MASK 0x01 +#define COPz_BC_TRUE 0x01 +#define COPz_BC_FALSE 0x00 +#define COPz_BCL_TF_MASK 0x02 /* MIPS-II, for r4000 port */ +#define COPz_BCL_TRUE 0x02 /* MIPS-II, for r4000 port */ +#define COPz_BCL_FALSE 0x00 /* MIPS-II, for r4000 port */ + +#endif /* __DECODER_LOCAL_H__ */ + diff --git a/Frameworks/lazyusf/lazyusf/debugger/dbg_types.h b/Frameworks/lazyusf/lazyusf/debugger/dbg_types.h new file mode 100644 index 000000000..eaf93ea47 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/debugger/dbg_types.h @@ -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__ */ + diff --git a/Frameworks/lazyusf/lazyusf/interpreter_cpu.c b/Frameworks/lazyusf/lazyusf/interpreter_cpu.c index 75b2f73f9..94fdb7677 100644 --- a/Frameworks/lazyusf/lazyusf/interpreter_cpu.c +++ b/Frameworks/lazyusf/lazyusf/interpreter_cpu.c @@ -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; diff --git a/Frameworks/lazyusf2/lazyusf2/lazyusf-Info.plist b/Frameworks/lazyusf/lazyusf/lazyusf-Info.plist similarity index 100% rename from Frameworks/lazyusf2/lazyusf2/lazyusf-Info.plist rename to Frameworks/lazyusf/lazyusf/lazyusf-Info.plist diff --git a/Frameworks/lazyusf/lazyusf/memory.c b/Frameworks/lazyusf/lazyusf/memory.c index 444e501f8..6f89d77bb 100644 --- a/Frameworks/lazyusf/lazyusf/memory.c +++ b/Frameworks/lazyusf/lazyusf/memory.c @@ -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: diff --git a/Frameworks/lazyusf/lazyusf/osal/preproc.h b/Frameworks/lazyusf/lazyusf/osal/preproc.h new file mode 100644 index 000000000..c107506e1 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/osal/preproc.h @@ -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 + #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 */ + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/LICENSES b/Frameworks/lazyusf/lazyusf/rsp_hle/LICENSES new file mode 100644 index 000000000..e1403bd13 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/LICENSES @@ -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. + + + Copyright (C) 19yy + + 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. + + , 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. + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.c new file mode 100644 index 000000000..d3157155d --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.c @@ -0,0 +1,1032 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - alist.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 +#include +#include + +#include "alist.h" +#include "arithmetics.h" +#include "audio.h" +#include "hle_external.h" +#include "hle_internal.h" +#include "memory.h" + +struct ramp_t +{ + int64_t value; + int64_t step; + int64_t target; +}; + +/* local functions */ +static void swap(int16_t **a, int16_t **b) +{ + int16_t* tmp = *b; + *b = *a; + *a = tmp; +} + +static int16_t* sample(struct hle_t* hle, unsigned pos) +{ + return (int16_t*)hle->alist_buffer + (pos ^ S); +} + +static uint8_t* alist_u8(struct hle_t* hle, uint16_t dmem) +{ + return u8(hle->alist_buffer, dmem); +} + +static int16_t* alist_s16(struct hle_t* hle, uint16_t dmem) +{ + return (int16_t*)u16(hle->alist_buffer, dmem); +} + + +static void sample_mix(int16_t* dst, int16_t src, int16_t gain) +{ + *dst = clamp_s16(*dst + ((src * gain) >> 15)); +} + +static void alist_envmix_mix(size_t n, int16_t** dst, const int16_t* gains, int16_t src) +{ + size_t i; + + for(i = 0; i < n; ++i) + sample_mix(dst[i], src, gains[i]); +} + +static int16_t ramp_step(struct ramp_t* ramp) +{ + bool target_reached; + + ramp->value += ramp->step; + + target_reached = (ramp->step <= 0) + ? (ramp->value <= ramp->target) + : (ramp->value >= ramp->target); + + if (target_reached) + { + ramp->value = ramp->target; + ramp->step = 0; + } + + return (int16_t)(ramp->value >> 16); +} + +/* global functions */ +#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 w1, w2; + unsigned int acmd; + + const uint32_t *alist = dram_u32(hle, *dmem_u32(hle, TASK_DATA_PTR)); + const uint32_t *const alist_end = alist + (*dmem_u32(hle, TASK_DATA_SIZE) >> 2); + + while (alist != alist_end) { + w1 = *(alist++); + w2 = *(alist++); + + acmd = (w1 >> 24) & 0x7f; + + if (acmd < abi_size) + { + #ifdef DEBUG_INFO + HleVerboseMessage(hle->user_defined, "HLE: %s (%08x %08x)", abi_names[acmd], w1, w2); + #endif + (*abi[acmd])(hle, w1, w2); + } + else + HleWarnMessage(hle->user_defined, "Invalid ABI command %u", acmd); + } +} + +uint32_t alist_get_address(struct hle_t* hle, uint32_t so, const uint32_t *segments, size_t n) +{ + uint8_t segment = (so >> 24) & 0x3f; + uint32_t offset = (so & 0xffffff); + + if (segment >= n) { + HleWarnMessage(hle->user_defined, "Invalid segment %u", segment); + return offset; + } + + return segments[segment] + offset; +} + +void alist_set_address(struct hle_t* hle, uint32_t so, uint32_t *segments, size_t n) +{ + uint8_t segment = (so >> 24) & 0x3f; + uint32_t offset = (so & 0xffffff); + + if (segment >= n) { + HleWarnMessage(hle->user_defined, "Invalid segment %u", segment); + return; + } + + segments[segment] = offset; +} + +void alist_clear(struct hle_t* hle, uint16_t dmem, uint16_t count) +{ + while(count != 0) { + *alist_u8(hle, dmem++) = 0; + --count; + } +} + +void alist_load(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count) +{ + /* enforce DMA alignment constraints */ + dmem &= ~3; + address &= ~7; + count = align(count, 8); + memcpy(hle->alist_buffer + dmem, hle->dram + address, count); +} + +void alist_save(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count) +{ + /* enforce DMA alignment constraints */ + dmem &= ~3; + address &= ~7; + count = align(count, 8); + memcpy(hle->dram + address, hle->alist_buffer + dmem, count); +} + +void alist_move(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count) +{ + while (count != 0) { + *alist_u8(hle, dmemo++) = *alist_u8(hle, dmemi++); + --count; + } +} + +void alist_copy_every_other_sample(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count) +{ + while (count != 0) { + *alist_s16(hle, dmemo) = *alist_s16(hle, dmemi); + dmemo += 2; + dmemi += 4; + --count; + } +} + +void alist_repeat64(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint8_t count) +{ + uint16_t buffer[64]; + + memcpy(buffer, hle->alist_buffer + dmemi, 128); + + while(count != 0) { + memcpy(hle->alist_buffer + dmemo, buffer, 128); + dmemo += 128; + --count; + } +} + +void alist_copy_blocks(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t block_size, uint8_t count) +{ + int block_left = count; + + do + { + int bytes_left = block_size; + + do + { + memcpy(hle->alist_buffer + dmemo, hle->alist_buffer + dmemi, 0x20); + bytes_left -= 0x20; + + dmemi += 0x20; + dmemo += 0x20; + + } while(bytes_left > 0); + + --block_left; + } while(block_left > 0); +} + +void alist_interleave(struct hle_t* hle, uint16_t dmemo, uint16_t left, uint16_t right, uint16_t count) +{ + uint16_t *dst = (uint16_t*)(hle->alist_buffer + dmemo); + const uint16_t *srcL = (uint16_t*)(hle->alist_buffer + left); + const uint16_t *srcR = (uint16_t*)(hle->alist_buffer + right); + + count >>= 2; + + while(count != 0) { + uint16_t l1 = *(srcL++); + uint16_t l2 = *(srcL++); + uint16_t r1 = *(srcR++); + uint16_t r2 = *(srcR++); + +#if M64P_BIG_ENDIAN + *(dst++) = l1; + *(dst++) = r1; + *(dst++) = l2; + *(dst++) = r2; +#else + *(dst++) = r2; + *(dst++) = l2; + *(dst++) = r1; + *(dst++) = l1; +#endif + --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) +{ + size_t n = (aux) ? 4 : 2; + + const int16_t* const in = (int16_t*)(hle->alist_buffer + dmemi); + int16_t* const dl = (int16_t*)(hle->alist_buffer + dmem_dl); + int16_t* const dr = (int16_t*)(hle->alist_buffer + dmem_dr); + int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl); + int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr); + + struct ramp_t ramps[2]; + int32_t exp_seq[2]; + int32_t exp_rates[2]; + + uint32_t ptr = 0; + int x, y; + short save_buffer[40]; + + memcpy((uint8_t *)save_buffer, (hle->dram + address), sizeof(save_buffer)); + if (init) { + ramps[0].value = (vol[0] << 16); + ramps[1].value = (vol[1] << 16); + ramps[0].target = (target[0] << 16); + ramps[1].target = (target[1] << 16); + exp_rates[0] = rate[0]; + exp_rates[1] = rate[1]; + exp_seq[0] = (vol[0] * rate[0]); + exp_seq[1] = (vol[1] * rate[1]); + } else { + wet = *(int16_t *)(save_buffer + 0); /* 0-1 */ + dry = *(int16_t *)(save_buffer + 2); /* 2-3 */ + ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */ + ramps[1].target = *(int32_t *)(save_buffer + 6); /* 6-7 */ + exp_rates[0] = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */ + exp_rates[1] = *(int32_t *)(save_buffer + 10); /* 10-11 */ + exp_seq[0] = *(int32_t *)(save_buffer + 12); /* 12-13 */ + exp_seq[1] = *(int32_t *)(save_buffer + 14); /* 14-15 */ + ramps[0].value = *(int32_t *)(save_buffer + 16); /* 12-13 */ + ramps[1].value = *(int32_t *)(save_buffer + 18); /* 14-15 */ + } + + /* init which ensure ramp.step != 0 iff ramp.value == ramp.target */ + ramps[0].step = ramps[0].target - ramps[0].value; + ramps[1].step = ramps[1].target - ramps[1].value; + + for (y = 0; y < count; y += 16) { + + if (ramps[0].step != 0) + { + exp_seq[0] = ((int64_t)exp_seq[0]*(int64_t)exp_rates[0]) >> 16; + ramps[0].step = (exp_seq[0] - ramps[0].value) >> 3; + } + + if (ramps[1].step != 0) + { + exp_seq[1] = ((int64_t)exp_seq[1]*(int64_t)exp_rates[1]) >> 16; + ramps[1].step = (exp_seq[1] - ramps[1].value) >> 3; + } + + for (x = 0; x < 8; ++x) { + int16_t gains[4]; + int16_t* buffers[4]; + int16_t l_vol = ramp_step(&ramps[0]); + int16_t r_vol = ramp_step(&ramps[1]); + + buffers[0] = dl + (ptr^S); + buffers[1] = dr + (ptr^S); + buffers[2] = wl + (ptr^S); + buffers[3] = wr + (ptr^S); + + gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15); + gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15); + gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15); + gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15); + + alist_envmix_mix(n, buffers, gains, in[ptr^S]); + ++ptr; + } + } + + *(int16_t *)(save_buffer + 0) = wet; /* 0-1 */ + *(int16_t *)(save_buffer + 2) = dry; /* 2-3 */ + *(int32_t *)(save_buffer + 4) = (int32_t)ramps[0].target; /* 4-5 */ + *(int32_t *)(save_buffer + 6) = (int32_t)ramps[1].target; /* 6-7 */ + *(int32_t *)(save_buffer + 8) = exp_rates[0]; /* 8-9 (save_buffer is a 16bit pointer) */ + *(int32_t *)(save_buffer + 10) = exp_rates[1]; /* 10-11 */ + *(int32_t *)(save_buffer + 12) = exp_seq[0]; /* 12-13 */ + *(int32_t *)(save_buffer + 14) = exp_seq[1]; /* 14-15 */ + *(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 12-13 */ + *(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 14-15 */ + memcpy(hle->dram + address, (uint8_t *)save_buffer, sizeof(save_buffer)); +} + +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) +{ + unsigned k; + size_t n = (aux) ? 4 : 2; + + const int16_t* const in = (int16_t*)(hle->alist_buffer + dmemi); + int16_t* const dl = (int16_t*)(hle->alist_buffer + dmem_dl); + int16_t* const dr = (int16_t*)(hle->alist_buffer + dmem_dr); + int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl); + int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr); + + struct ramp_t ramps[2]; + short save_buffer[40]; + + memcpy((uint8_t *)save_buffer, (hle->dram + address), 80); + if (init) { + ramps[0].value = (vol[0] << 16); + ramps[1].value = (vol[1] << 16); + ramps[0].target = (target[0] << 16); + ramps[1].target = (target[1] << 16); + ramps[0].step = rate[0] / 8; + ramps[1].step = rate[1] / 8; + } else { + wet = *(int16_t *)(save_buffer + 0); /* 0-1 */ + dry = *(int16_t *)(save_buffer + 2); /* 2-3 */ + ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */ + ramps[1].target = *(int32_t *)(save_buffer + 6); /* 6-7 */ + ramps[0].step = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */ + ramps[1].step = *(int32_t *)(save_buffer + 10); /* 10-11 */ + /* *(int32_t *)(save_buffer + 12);*/ /* 12-13 */ + /* *(int32_t *)(save_buffer + 14);*/ /* 14-15 */ + ramps[0].value = *(int32_t *)(save_buffer + 16); /* 12-13 */ + ramps[1].value = *(int32_t *)(save_buffer + 18); /* 14-15 */ + } + + count >>= 1; + for (k = 0; k < count; ++k) { + int16_t gains[4]; + int16_t* buffers[4]; + int16_t l_vol = ramp_step(&ramps[0]); + int16_t r_vol = ramp_step(&ramps[1]); + + buffers[0] = dl + (k^S); + buffers[1] = dr + (k^S); + buffers[2] = wl + (k^S); + buffers[3] = wr + (k^S); + + gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15); + gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15); + gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15); + gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15); + + alist_envmix_mix(n, buffers, gains, in[k^S]); + } + + *(int16_t *)(save_buffer + 0) = wet; /* 0-1 */ + *(int16_t *)(save_buffer + 2) = dry; /* 2-3 */ + *(int32_t *)(save_buffer + 4) = (int32_t)ramps[0].target; /* 4-5 */ + *(int32_t *)(save_buffer + 6) = (int32_t)ramps[1].target; /* 6-7 */ + *(int32_t *)(save_buffer + 8) = (int32_t)ramps[0].step; /* 8-9 (save_buffer is a 16bit pointer) */ + *(int32_t *)(save_buffer + 10) = (int32_t)ramps[1].step; /* 10-11 */ + /**(int32_t *)(save_buffer + 12);*/ /* 12-13 */ + /**(int32_t *)(save_buffer + 14);*/ /* 14-15 */ + *(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 12-13 */ + *(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 14-15 */ + memcpy(hle->dram + address, (uint8_t *)save_buffer, 80); +} + +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) +{ + size_t k; + struct ramp_t ramps[2]; + int16_t save_buffer[40]; + + const int16_t * const in = (int16_t*)(hle->alist_buffer + dmemi); + int16_t* const dl = (int16_t*)(hle->alist_buffer + dmem_dl); + int16_t* const dr = (int16_t*)(hle->alist_buffer + dmem_dr); + int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl); + int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr); + + memcpy((uint8_t *)save_buffer, hle->dram + address, 80); + if (init) { + ramps[0].step = rate[0] / 8; + ramps[0].value = (vol[0] << 16); + ramps[0].target = (target[0] << 16); + ramps[1].step = rate[1] / 8; + ramps[1].value = (vol[1] << 16); + ramps[1].target = (target[1] << 16); + } + else { + wet = *(int16_t *)(save_buffer + 0); /* 0-1 */ + dry = *(int16_t *)(save_buffer + 2); /* 2-3 */ + ramps[0].target = *(int16_t *)(save_buffer + 4) << 16; /* 4-5 */ + ramps[1].target = *(int16_t *)(save_buffer + 6) << 16; /* 6-7 */ + ramps[0].step = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */ + ramps[1].step = *(int32_t *)(save_buffer + 10); /* 10-11 */ + ramps[0].value = *(int32_t *)(save_buffer + 16); /* 16-17 */ + ramps[1].value = *(int32_t *)(save_buffer + 18); /* 16-17 */ + } + + count >>= 1; + for(k = 0; k < count; ++k) { + int16_t gains[4]; + int16_t* buffers[4]; + int16_t l_vol = ramp_step(&ramps[0]); + int16_t r_vol = ramp_step(&ramps[1]); + + buffers[0] = dl + (k^S); + buffers[1] = dr + (k^S); + buffers[2] = wl + (k^S); + buffers[3] = wr + (k^S); + + gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15); + gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15); + gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15); + gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15); + + alist_envmix_mix(4, buffers, gains, in[k^S]); + } + + *(int16_t *)(save_buffer + 0) = wet; /* 0-1 */ + *(int16_t *)(save_buffer + 2) = dry; /* 2-3 */ + *(int16_t *)(save_buffer + 4) = (int16_t)(ramps[0].target >> 16); /* 4-5 */ + *(int16_t *)(save_buffer + 6) = (int16_t)(ramps[1].target >> 16); /* 6-7 */ + *(int32_t *)(save_buffer + 8) = (int32_t)ramps[0].step; /* 8-9 (save_buffer is a 16bit pointer) */ + *(int32_t *)(save_buffer + 10) = (int32_t)ramps[1].step; /* 10-11 */ + *(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 16-17 */ + *(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 18-19 */ + memcpy(hle->dram + address, (uint8_t *)save_buffer, 80); +} + +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) +{ + int16_t *in = (int16_t*)(hle->alist_buffer + dmemi); + int16_t *dl = (int16_t*)(hle->alist_buffer + dmem_dl); + int16_t *dr = (int16_t*)(hle->alist_buffer + dmem_dr); + int16_t *wl = (int16_t*)(hle->alist_buffer + dmem_wl); + int16_t *wr = (int16_t*)(hle->alist_buffer + dmem_wr); + + /* make sure count is a multiple of 8 */ + count = align(count, 8); + + if (swap_wet_LR) + swap(&wl, &wr); + + while (count != 0) { + size_t i; + for(i = 0; i < 8; ++i) { + int16_t l = (((int32_t)in[i^S] * (uint32_t)env_values[0]) >> 16) ^ xors[0]; + int16_t r = (((int32_t)in[i^S] * (uint32_t)env_values[1]) >> 16) ^ xors[1]; + int16_t l2 = (((int32_t)l * (uint32_t)env_values[2]) >> 16) ^ xors[2]; + int16_t r2 = (((int32_t)r * (uint32_t)env_values[2]) >> 16) ^ xors[3]; + + dl[i^S] = clamp_s16(dl[i^S] + l); + dr[i^S] = clamp_s16(dr[i^S] + r); + wl[i^S] = clamp_s16(wl[i^S] + l2); + wr[i^S] = clamp_s16(wr[i^S] + r2); + } + + env_values[0] += env_steps[0]; + env_values[1] += env_steps[1]; + env_values[2] += env_steps[2]; + + dl += 8; + dr += 8; + wl += 8; + wr += 8; + in += 8; + count -= 8; + } +} + + +void alist_mix(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count, int16_t gain) +{ + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); + const int16_t *src = (int16_t*)(hle->alist_buffer + dmemi); + + count >>= 1; + + while(count != 0) { + sample_mix(dst, *src, gain); + + ++dst; + ++src; + --count; + } +} + +void alist_multQ44(struct hle_t* hle, uint16_t dmem, uint16_t count, int8_t gain) +{ + int16_t *dst = (int16_t*)(hle->alist_buffer + dmem); + + count >>= 1; + + while(count != 0) { + *dst = clamp_s16(*dst * gain >> 4); + + ++dst; + --count; + } +} + +void alist_add(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count) +{ + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); + const int16_t *src = (int16_t*)(hle->alist_buffer + dmemi); + + count >>= 1; + + while(count != 0) { + *dst = clamp_s16(*dst + *src); + + ++dst; + ++src; + --count; + } +} + +static void alist_resample_reset(struct hle_t* hle, uint16_t pos, uint32_t* pitch_accu) +{ + unsigned k; + + for(k = 0; k < 4; ++k) + *sample(hle, pos + k) = 0; + + *pitch_accu = 0; +} + +static void alist_resample_load(struct hle_t* hle, uint32_t address, uint16_t pos, uint32_t* pitch_accu) +{ + *sample(hle, pos + 0) = *dram_u16(hle, address + 0); + *sample(hle, pos + 1) = *dram_u16(hle, address + 2); + *sample(hle, pos + 2) = *dram_u16(hle, address + 4); + *sample(hle, pos + 3) = *dram_u16(hle, address + 6); + + *pitch_accu = *dram_u16(hle, address + 8); +} + +static void alist_resample_save(struct hle_t* hle, uint32_t address, uint16_t pos, uint32_t pitch_accu) +{ + *dram_u16(hle, address + 0) = *sample(hle, pos + 0); + *dram_u16(hle, address + 2) = *sample(hle, pos + 1); + *dram_u16(hle, address + 4) = *sample(hle, pos + 2); + *dram_u16(hle, address + 6) = *sample(hle, pos + 3); + + *dram_u16(hle, address + 8) = pitch_accu; +} + +void alist_resample( + struct hle_t* hle, + bool init, + bool flag2, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint32_t pitch, /* Q16.16 */ + uint32_t address) +{ + uint32_t pitch_accu; + + uint16_t ipos = dmemi >> 1; + uint16_t opos = dmemo >> 1; + count >>= 1; + ipos -= 4; + + if (flag2) + HleWarnMessage(hle->user_defined, "alist_resample: flag2 is not implemented"); + + if (init) + alist_resample_reset(hle, ipos, &pitch_accu); + else + alist_resample_load(hle, address, ipos, &pitch_accu); + + while (count != 0) { + const int16_t* lut = RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8); + + *sample(hle, opos++) = clamp_s16( ( + (*sample(hle, ipos ) * lut[0]) + + (*sample(hle, ipos + 1) * lut[1]) + + (*sample(hle, ipos + 2) * lut[2]) + + (*sample(hle, ipos + 3) * lut[3]) ) >> 15); + + pitch_accu += pitch; + ipos += (pitch_accu >> 16); + pitch_accu &= 0xffff; + --count; + } + + alist_resample_save(hle, address, ipos, pitch_accu); +} + +void alist_resample_zoh( + struct hle_t* hle, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + uint32_t pitch, + uint32_t pitch_accu) +{ + uint16_t ipos = dmemi >> 1; + uint16_t opos = dmemo >> 1; + count >>= 1; + + while(count != 0) { + + *sample(hle, opos++) = *sample(hle, ipos); + + pitch_accu += pitch; + ipos += (pitch_accu >> 16); + pitch_accu &= 0xffff; + --count; + } +} + +typedef unsigned int (*adpcm_predict_frame_t)(struct hle_t* hle, + int16_t* dst, uint16_t dmemi, unsigned char scale); + +static unsigned int adpcm_predict_frame_4bits(struct hle_t* hle, + int16_t* dst, uint16_t dmemi, unsigned char scale) +{ + unsigned int i; + unsigned int rshift = (scale < 12) ? 12 - scale : 0; + + for(i = 0; i < 8; ++i) { + uint8_t byte = *alist_u8(hle, dmemi++); + + *(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift); + } + + return 8; +} + +static unsigned int adpcm_predict_frame_2bits(struct hle_t* hle, + int16_t* dst, uint16_t dmemi, unsigned char scale) +{ + unsigned int i; + unsigned int rshift = (scale < 14) ? 14 - scale : 0; + + for(i = 0; i < 4; ++i) { + uint8_t byte = *alist_u8(hle, dmemi++); + + *(dst++) = adpcm_predict_sample(byte, 0xc0, 8, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x30, 10, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x0c, 12, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x03, 14, rshift); + } + + return 4; +} + +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) +{ + int16_t last_frame[16]; + size_t i; + + adpcm_predict_frame_t predict_frame = (two_bit_per_sample) + ? adpcm_predict_frame_2bits + : adpcm_predict_frame_4bits; + + assert((count & 0x1f) == 0); + + if (init) + memset(last_frame, 0, 16*sizeof(last_frame[0])); + else + dram_load_u16(hle, (uint16_t*)last_frame, (loop) ? loop_address : last_frame_address, 16); + + for(i = 0; i < 16; ++i, dmemo += 2) + *alist_s16(hle, dmemo) = last_frame[i]; + + while (count != 0) { + int16_t frame[16]; + uint8_t code = *alist_u8(hle, dmemi++); + unsigned char scale = (code & 0xf0) >> 4; + const int16_t* const cb_entry = codebook + ((code & 0xf) << 4); + + dmemi += predict_frame(hle, frame, dmemi, scale); + + adpcm_compute_residuals(last_frame , frame , cb_entry, last_frame + 14, 8); + adpcm_compute_residuals(last_frame + 8, frame + 8, cb_entry, last_frame + 6 , 8); + + for(i = 0; i < 16; ++i, dmemo += 2) + *alist_s16(hle, dmemo) = last_frame[i]; + + count -= 32; + } + + dram_store_u16(hle, (uint16_t*)last_frame, last_frame_address, 16); +} + + +void alist_filter( + struct hle_t* hle, + uint16_t dmem, + uint16_t count, + uint32_t address, + const uint32_t* lut_address) +{ + int x; + int16_t outbuff[0x3c0]; + int16_t *outp = outbuff; + + int16_t* const lutt6 = (int16_t*)(hle->dram + lut_address[0]); + int16_t* const lutt5 = (int16_t*)(hle->dram + lut_address[1]); + + int16_t* in1 = (int16_t*)(hle->dram + address); + int16_t* in2 = (int16_t*)(hle->alist_buffer + dmem); + + + for (x = 0; x < 8; ++x) { + int32_t v = (lutt5[x] + lutt6[x]) >> 1; + lutt5[x] = lutt6[x] = v; + } + + for (x = 0; x < count; x += 16) { + int32_t v[8]; + + v[1] = in1[0] * lutt6[6]; + v[1] += in1[3] * lutt6[7]; + v[1] += in1[2] * lutt6[4]; + v[1] += in1[5] * lutt6[5]; + v[1] += in1[4] * lutt6[2]; + v[1] += in1[7] * lutt6[3]; + v[1] += in1[6] * lutt6[0]; + v[1] += in2[1] * lutt6[1]; /* 1 */ + + v[0] = in1[3] * lutt6[6]; + v[0] += in1[2] * lutt6[7]; + v[0] += in1[5] * lutt6[4]; + v[0] += in1[4] * lutt6[5]; + v[0] += in1[7] * lutt6[2]; + v[0] += in1[6] * lutt6[3]; + v[0] += in2[1] * lutt6[0]; + v[0] += in2[0] * lutt6[1]; + + v[3] = in1[2] * lutt6[6]; + v[3] += in1[5] * lutt6[7]; + v[3] += in1[4] * lutt6[4]; + v[3] += in1[7] * lutt6[5]; + v[3] += in1[6] * lutt6[2]; + v[3] += in2[1] * lutt6[3]; + v[3] += in2[0] * lutt6[0]; + v[3] += in2[3] * lutt6[1]; + + v[2] = in1[5] * lutt6[6]; + v[2] += in1[4] * lutt6[7]; + v[2] += in1[7] * lutt6[4]; + v[2] += in1[6] * lutt6[5]; + v[2] += in2[1] * lutt6[2]; + v[2] += in2[0] * lutt6[3]; + v[2] += in2[3] * lutt6[0]; + v[2] += in2[2] * lutt6[1]; + + v[5] = in1[4] * lutt6[6]; + v[5] += in1[7] * lutt6[7]; + v[5] += in1[6] * lutt6[4]; + v[5] += in2[1] * lutt6[5]; + v[5] += in2[0] * lutt6[2]; + v[5] += in2[3] * lutt6[3]; + v[5] += in2[2] * lutt6[0]; + v[5] += in2[5] * lutt6[1]; + + v[4] = in1[7] * lutt6[6]; + v[4] += in1[6] * lutt6[7]; + v[4] += in2[1] * lutt6[4]; + v[4] += in2[0] * lutt6[5]; + v[4] += in2[3] * lutt6[2]; + v[4] += in2[2] * lutt6[3]; + v[4] += in2[5] * lutt6[0]; + v[4] += in2[4] * lutt6[1]; + + v[7] = in1[6] * lutt6[6]; + v[7] += in2[1] * lutt6[7]; + v[7] += in2[0] * lutt6[4]; + v[7] += in2[3] * lutt6[5]; + v[7] += in2[2] * lutt6[2]; + v[7] += in2[5] * lutt6[3]; + v[7] += in2[4] * lutt6[0]; + v[7] += in2[7] * lutt6[1]; + + v[6] = in2[1] * lutt6[6]; + v[6] += in2[0] * lutt6[7]; + v[6] += in2[3] * lutt6[4]; + v[6] += in2[2] * lutt6[5]; + v[6] += in2[5] * lutt6[2]; + v[6] += in2[4] * lutt6[3]; + v[6] += in2[7] * lutt6[0]; + v[6] += in2[6] * lutt6[1]; + + outp[1] = ((v[1] + 0x4000) >> 15); + outp[0] = ((v[0] + 0x4000) >> 15); + outp[3] = ((v[3] + 0x4000) >> 15); + outp[2] = ((v[2] + 0x4000) >> 15); + outp[5] = ((v[5] + 0x4000) >> 15); + outp[4] = ((v[4] + 0x4000) >> 15); + outp[7] = ((v[7] + 0x4000) >> 15); + outp[6] = ((v[6] + 0x4000) >> 15); + in1 = in2; + in2 += 8; + outp += 8; + } + + memcpy(hle->dram + address, in2 - 8, 16); + memcpy(hle->alist_buffer + dmem, outbuff, count); +} + +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) +{ + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); + + const int16_t* const h1 = table; + int16_t* const h2 = table + 8; + + unsigned i; + int16_t l1, l2; + int16_t h2_before[8]; + + count = align(count, 16); + + if (init) { + l1 = 0; + l2 = 0; + } + else { + l1 = *dram_u16(hle, address + 4); + l2 = *dram_u16(hle, address + 6); + } + + for(i = 0; i < 8; ++i) { + h2_before[i] = h2[i]; + h2[i] = (((int32_t)h2[i] * gain) >> 14); + } + + do + { + int16_t frame[8]; + + for(i = 0; i < 8; ++i, dmemi += 2) + frame[i] = *alist_s16(hle, dmemi); + + for(i = 0; i < 8; ++i) { + int32_t accu = frame[i] * gain; + accu += h1[i]*l1 + h2_before[i]*l2 + rdot(i, h2, frame); + dst[i^S] = clamp_s16(accu >> 14); + } + + l1 = dst[6^S]; + l2 = dst[7^S]; + + dst += 8; + count -= 16; + } while (count != 0); + + dram_store_u32(hle, (uint32_t*)(dst - 4), address, 2); +} + +void alist_iirf( + struct hle_t* hle, + bool init, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + int16_t* table, + uint32_t address) +{ + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); + int32_t i, prev; + int16_t frame[8]; + int16_t ibuf[4]; + uint16_t index = 7; + + + count = align(count, 16); + + if(init) + { + for(i = 0; i < 8; ++i) + frame[i] = 0; + ibuf[1] = 0; + ibuf[2] = 0; + } + else + { + frame[6] = *dram_u16(hle, address + 4); + frame[7] = *dram_u16(hle, address + 6); + ibuf[1] = (int16_t)*dram_u16(hle, address + 8); + ibuf[2] = (int16_t)*dram_u16(hle, address + 10); + } + + prev = vmulf(table[9], frame[6]) * 2; + do + { + for(i = 0; i < 8; ++i) + { + int32_t accu; + ibuf[index&3] = *alist_s16(hle, dmemi); + + accu = prev + vmulf(table[0], ibuf[index&3]) + vmulf(table[1], ibuf[(index-1)&3]) + vmulf(table[0], ibuf[(index-2)&3]); + accu += vmulf(table[8], frame[index]) * 2; + prev = vmulf(table[9], frame[index]) * 2; + dst[i^S] = frame[i] = accu; + + index=(index+1)&7; + dmemi += 2; + } + dst += 8; + count -= 0x10; + } while (count > 0); + + dram_store_u16(hle, (uint16_t*)&frame[6], address + 4, 4); + dram_store_u16(hle, (uint16_t*)&ibuf[(index-2)&3], address+8, 2); + dram_store_u16(hle, (uint16_t*)&ibuf[(index-1)&3], address+10, 2); +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist.h b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.h new file mode 100644 index 000000000..f53db040a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist.h @@ -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 +#include +#include + +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 diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c new file mode 100644 index 000000000..3642cd44f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_audio.c @@ -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 +#include +#include + +#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 +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c new file mode 100644 index 000000000..127ae9131 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_naudio.c @@ -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 +#include + +#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 +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c new file mode 100644 index 000000000..5c0cbbc51 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/alist_nead.c @@ -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 +#include + +#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 +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h b/Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h new file mode 100644 index 000000000..529293d25 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/arithmetics.h @@ -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 + +#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 + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/audio.c b/Frameworks/lazyusf/lazyusf/rsp_hle/audio.c new file mode 100644 index 000000000..e473d3460 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/audio.c @@ -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 +#include +#include + +#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); + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/audio.h b/Frameworks/lazyusf/lazyusf/rsp_hle/audio.h new file mode 100644 index 000000000..8524972ea --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/audio.h @@ -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 +#include + +#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 diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c b/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c new file mode 100644 index 000000000..7ed8ae245 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/cicx105.c @@ -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 + +#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; + + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/common.h b/Frameworks/lazyusf/lazyusf/rsp_hle/common.h new file mode 100644 index 000000000..195b8641a --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/common.h @@ -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 + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/hle.c b/Frameworks/lazyusf/lazyusf/rsp_hle/hle.c new file mode 100644 index 000000000..abb744d66 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/hle.c @@ -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 +#include + +#ifdef ENABLE_TASK_DUMP +#include +#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 diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/hle.h b/Frameworks/lazyusf/lazyusf/rsp_hle/hle.h new file mode 100644 index 000000000..3c705a939 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/hle.h @@ -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 + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/hle_external.h b/Frameworks/lazyusf/lazyusf/rsp_hle/hle_external.h new file mode 100644 index 000000000..2f35a3c98 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/hle_external.h @@ -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 + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/hle_internal.h b/Frameworks/lazyusf/lazyusf/rsp_hle/hle_internal.h new file mode 100644 index 000000000..352d956b5 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/hle_internal.h @@ -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 + +#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 + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c b/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c new file mode 100644 index 000000000..bde1d6b69 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/jpeg.c @@ -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 +#include +#include + +#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; +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/memory.c b/Frameworks/lazyusf/lazyusf/rsp_hle/memory.c new file mode 100644 index 000000000..0c1b82d51 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/memory.c @@ -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 + +#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)); +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/memory.h b/Frameworks/lazyusf/lazyusf/rsp_hle/memory.h new file mode 100644 index 000000000..91a747b16 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/memory.h @@ -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 +#include +#include + +#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 + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c b/Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c new file mode 100644 index 000000000..20a42c4d6 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/mp3.c @@ -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 +#include + +#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; + } +} + diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c b/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c new file mode 100644 index 000000000..36b7b7c5f --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/musyx.c @@ -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 +#include +#include +#include + +#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); +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c new file mode 100644 index 000000000..844d395ad --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/plugin.c @@ -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 +#include +#include + +#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 */ +} diff --git a/Frameworks/lazyusf/lazyusf/rsp_hle/ucodes.h b/Frameworks/lazyusf/lazyusf/rsp_hle/ucodes.h new file mode 100644 index 000000000..1a12bf994 --- /dev/null +++ b/Frameworks/lazyusf/lazyusf/rsp_hle/ucodes.h @@ -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 + +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 + diff --git a/Frameworks/lazyusf/lazyusf/usf.c b/Frameworks/lazyusf/lazyusf/usf.c index 31aaf3d7f..64d8fc41a 100644 --- a/Frameworks/lazyusf/lazyusf/usf.c +++ b/Frameworks/lazyusf/lazyusf/usf.c @@ -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; diff --git a/Frameworks/lazyusf/lazyusf/usf_internal.h b/Frameworks/lazyusf/lazyusf/usf_internal.h index 345816d24..523f70f30 100644 --- a/Frameworks/lazyusf/lazyusf/usf_internal.h +++ b/Frameworks/lazyusf/lazyusf/usf_internal.h @@ -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 diff --git a/Frameworks/lazyusf2/lazyusf2/lazyusf2-Info.plist b/Frameworks/lazyusf2/lazyusf2/lazyusf2-Info.plist new file mode 100644 index 000000000..26de52dbd --- /dev/null +++ b/Frameworks/lazyusf2/lazyusf2/lazyusf2-Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright © 2014 Christopher Snowhill. All rights reserved. + NSPrincipalClass + + + diff --git a/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj b/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj index f5a2c757e..fc9ebfe35 100644 --- a/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj +++ b/Plugins/HighlyComplete/HighlyComplete.xcodeproj/project.pbxproj @@ -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 = ""; }; 8360EEF317F92AC8005208A4 /* HighlyComplete-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HighlyComplete-Prefix.pch"; sourceTree = ""; }; 83848FE61807623F00E7332D /* SSEQPlayer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SSEQPlayer.xcodeproj; path = ../../Frameworks/SSEQPlayer/SSEQPlayer.xcodeproj; sourceTree = ""; }; - 83C8B65018AF57770071B040 /* lazyusf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = lazyusf.xcodeproj; path = ../../Frameworks/lazyusf/lazyusf.xcodeproj; sourceTree = ""; }; 83CA241E1D7BC47C00F2EA53 /* mGBA.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mGBA.xcodeproj; path = ../../Frameworks/mGBA/mGBA.xcodeproj; sourceTree = ""; }; + 83DA152E20F6EFA80096D348 /* lazyusf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = lazyusf.xcodeproj; path = ../../Frameworks/lazyusf/lazyusf.xcodeproj; sourceTree = ""; }; 83DE0C34180A9BD400269051 /* vio2sf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = vio2sf.xcodeproj; path = ../../Frameworks/vio2sf/vio2sf.xcodeproj; sourceTree = ""; }; 83FAF8A318ADD27F00057CAF /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../../Playlist/PlaylistController.h; sourceTree = ""; }; 83FC32591BF5AB9000962B36 /* HighlyExperimental.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyExperimental.xcodeproj; path = ../../Frameworks/HighlyExperimental/HighlyExperimental.xcodeproj; sourceTree = ""; }; @@ -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 = ""; @@ -336,14 +336,6 @@ name = Products; sourceTree = ""; }; - 83C8B65118AF57770071B040 /* Products */ = { - isa = PBXGroup; - children = ( - 83C8B65618AF57770071B040 /* lazyusf.framework */, - ); - name = Products; - sourceTree = ""; - }; 83CA241F1D7BC47C00F2EA53 /* Products */ = { isa = PBXGroup; children = ( @@ -352,6 +344,14 @@ name = Products; sourceTree = ""; }; + 83DA152F20F6EFA80096D348 /* Products */ = { + isa = PBXGroup; + children = ( + 83DA153320F6EFA80096D348 /* lazyusf.framework */, + ); + name = Products; + sourceTree = ""; + }; 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;