From 64c2a5023d9de5a2b7b3eca70b46b15e191aaa1b Mon Sep 17 00:00:00 2001 From: mudlord Date: Sat, 7 May 2022 16:49:40 +1000 Subject: [PATCH] Update to most recent HLE RSP. --- Makefile.common | 1 + mupen64plus-rsp-hle/src/alist.c | 1033 ++++++++++++------------ mupen64plus-rsp-hle/src/alist.h | 28 +- mupen64plus-rsp-hle/src/alist_audio.c | 335 ++++---- mupen64plus-rsp-hle/src/alist_naudio.c | 319 ++++---- mupen64plus-rsp-hle/src/alist_nead.c | 605 +++++++------- mupen64plus-rsp-hle/src/arithmetics.h | 12 +- mupen64plus-rsp-hle/src/audio.c | 36 +- mupen64plus-rsp-hle/src/audio.h | 12 +- mupen64plus-rsp-hle/src/cicx105.c | 30 +- mupen64plus-rsp-hle/src/common.h | 7 +- mupen64plus-rsp-hle/src/hle.c | 625 ++++++++------ mupen64plus-rsp-hle/src/hle.h | 2 +- mupen64plus-rsp-hle/src/hle_external.h | 16 +- mupen64plus-rsp-hle/src/hle_internal.h | 18 +- mupen64plus-rsp-hle/src/hle_memory.c | 57 +- mupen64plus-rsp-hle/src/hle_plugin.c | 249 ++++-- mupen64plus-rsp-hle/src/hvqm.c | 354 ++++++++ mupen64plus-rsp-hle/src/jpeg.c | 7 +- mupen64plus-rsp-hle/src/memory.h | 143 +++- mupen64plus-rsp-hle/src/mp3.c | 84 +- mupen64plus-rsp-hle/src/musyx.c | 760 +++++++++-------- mupen64plus-rsp-hle/src/re2.c | 131 ++- mupen64plus-rsp-hle/src/ucodes.h | 26 +- 24 files changed, 2918 insertions(+), 1972 deletions(-) create mode 100644 mupen64plus-rsp-hle/src/hvqm.c diff --git a/Makefile.common b/Makefile.common index 117d232c..ebc77a03 100644 --- a/Makefile.common +++ b/Makefile.common @@ -63,6 +63,7 @@ SOURCES_C += $(RSPDIR)/src/alist.c \ $(RSPDIR)/src/mp3.c \ $(RSPDIR)/src/musyx.c \ $(RSPDIR)/src/re2.c \ + $(RSPDIR)/src/hvqm.c \ $(RSPDIR)/src/hle_plugin.c SOURCES_C += $(CXD4DIR)/rsp.c diff --git a/mupen64plus-rsp-hle/src/alist.c b/mupen64plus-rsp-hle/src/alist.c index eca78650..84860e7b 100644 --- a/mupen64plus-rsp-hle/src/alist.c +++ b/mupen64plus-rsp-hle/src/alist.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - alist.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -21,11 +21,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include +#include #include #include -#include - #include "alist.h" #include "arithmetics.h" #include "audio.h" @@ -48,22 +48,39 @@ static void swap(int16_t **a, int16_t **b) *a = tmp; } -#define sample(hle, pos) ((int16_t*)(hle)->alist_buffer + ((pos ^ S) & 0xfff)) -#define alist_u8(hle, dmem) ((uint8_t*)((hle)->alist_buffer + ((dmem ^ S8) & 0xfff))) -#define alist_s16(hle, dmem) ((int16_t*)u16((hle)->alist_buffer, (dmem))) -#define sample_mix(dst, src, gain) (clamp_s16(*(dst) + (((src) * (gain)) >> 15))) +static int16_t* sample(struct hle_t* hle, unsigned pos) +{ + return (int16_t*)hle->alist_buffer + ((pos ^ S) & 0xfff); +} + +static uint8_t* alist_u8(struct hle_t* hle, uint16_t dmem) +{ + return (uint8_t*)(hle->alist_buffer + ((dmem ^ S8) & 0xfff)); +} + +static int16_t* alist_s16(struct hle_t* hle, uint16_t dmem) +{ + return (int16_t*)(hle->alist_buffer + ((dmem ^ S16) & 0xfff)); +} + + +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) - *dst[i] = sample_mix(dst[i], src, gains[i]); + sample_mix(dst[i], src, gains[i]); } static int16_t ramp_step(struct ramp_t* ramp) { - bool target_reached; + bool target_reached; + ramp->value += ramp->step; target_reached = (ramp->step <= 0) @@ -82,24 +99,28 @@ static int16_t ramp_step(struct ramp_t* ramp) /* global functions */ void alist_process(struct hle_t* hle, const acmd_callback_t abi[], unsigned int abi_size) { - uint32_t addr = *dmem_u32(hle, TASK_DATA_PTR); - const uint32_t *alist = dram_u32(hle, addr); - const uint32_t *const alist_end = alist + (*dmem_u32(hle, TASK_DATA_SIZE) >> 2); + uint32_t w1, w2; + unsigned int acmd; - while (alist != alist_end) - { - uint32_t w1 = *(alist++); - uint32_t w2 = *(alist++); - uint32_t acmd = (w1 >> 24) & 0x7f; + 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); - if (acmd < abi_size) - (*abi[acmd])(hle, w1, w2); - } + while (alist != alist_end) { + w1 = *(alist++); + w2 = *(alist++); + + acmd = (w1 >> 24) & 0x7f; + + if (acmd < abi_size) + (*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); + uint8_t segment = (so >> 24) & 0x3f; uint32_t offset = (so & 0xffffff); if (segment >= n) { @@ -112,7 +133,7 @@ uint32_t alist_get_address(struct hle_t* hle, uint32_t so, const uint32_t *segme void alist_set_address(struct hle_t* hle, uint32_t so, uint32_t *segments, size_t n) { - uint8_t segment = (so >> 24); + uint8_t segment = (so >> 24) & 0x3f; uint32_t offset = (so & 0xffffff); if (segment >= n) { @@ -125,7 +146,10 @@ void alist_set_address(struct hle_t* hle, uint32_t so, uint32_t *segments, size_ void alist_clear(struct hle_t* hle, uint16_t dmem, uint16_t count) { - memset(hle->alist_buffer + dmem, 0, 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) @@ -148,88 +172,84 @@ void alist_save(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t cou void alist_move(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count) { - while (count) - { - *alist_u8(hle, dmemo++) = *alist_u8(hle, dmemi++); - --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) - { - *alist_s16(hle, dmemo) = *alist_s16(hle, dmemi); - dmemo += 2; - dmemi += 4; - --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]; + uint16_t buffer[64]; - memcpy(buffer, hle->alist_buffer + dmemi, 128); + memcpy(buffer, hle->alist_buffer + dmemi, 128); - while(count) - { - memcpy(hle->alist_buffer + dmemo, buffer, 128); - dmemo += 128; - --count; - } + 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; + int block_left = count; - do - { - int bytes_left = block_size; + do + { + int bytes_left = block_size; - do - { - memcpy(hle->alist_buffer + dmemo, hle->alist_buffer + dmemi, 0x20); - bytes_left -= 0x20; + do + { + memcpy(hle->alist_buffer + dmemo, hle->alist_buffer + dmemi, 0x20); + bytes_left -= 0x20; - dmemi += 0x20; - dmemo += 0x20; + dmemi += 0x20; + dmemo += 0x20; - } while(bytes_left > 0); + } while(bytes_left > 0); - --block_left; - } while(block_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); + 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; + count >>= 2; - while(count) - { - uint16_t l1 = *(srcL++); - uint16_t l2 = *(srcL++); - uint16_t r1 = *(srcR++); - uint16_t r2 = *(srcR++); + while(count != 0) { + uint16_t l1 = *(srcL++); + uint16_t l2 = *(srcL++); + uint16_t r1 = *(srcR++); + uint16_t r2 = *(srcR++); -#ifdef MSB_FIRST - *(dst++) = l1; - *(dst++) = r1; - *(dst++) = l2; - *(dst++) = r2; +#if M64P_BIG_ENDIAN + *(dst++) = l1; + *(dst++) = r1; + *(dst++) = l2; + *(dst++) = r2; #else - *(dst++) = r2; - *(dst++) = l2; - *(dst++) = r1; - *(dst++) = l1; + *(dst++) = r2; + *(dst++) = l2; + *(dst++) = r1; + *(dst++) = l1; #endif - --count; - } + --count; + } } @@ -246,22 +266,24 @@ void alist_envmix_exp( 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; - size_t n = (aux) ? 4 : 2; + short 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); - uint32_t ptr = 0; - short *save_buffer = (short*)((uint8_t*)hle->dram + address); - - if (init) - { + 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); @@ -270,9 +292,7 @@ void alist_envmix_exp( exp_rates[1] = rate[1]; exp_seq[0] = (vol[0] * rate[0]); exp_seq[1] = (vol[1] * rate[1]); - } - else - { + } 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 */ @@ -289,52 +309,52 @@ void alist_envmix_exp( 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) - { - exp_seq[0] = ((int64_t)exp_seq[0]*(int64_t)exp_rates[0]) >> 16; - ramps[0].step = (exp_seq[0] - ramps[0].value) >> 3; - } + for (y = 0; y < count; y += 16) { - if (ramps[1].step) - { - exp_seq[1] = ((int64_t)exp_seq[1]*(int64_t)exp_rates[1]) >> 16; - ramps[1].step = (exp_seq[1] - ramps[1].value) >> 3; - } + 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; + } - 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]); + 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; + } - buffers[0] = dl + (ptr^S); - buffers[1] = dr + (ptr^S); - buffers[2] = wl + (ptr^S); - buffers[3] = wr + (ptr^S); + 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]); - 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); + buffers[0] = dl + (ptr^S); + buffers[1] = dr + (ptr^S); + buffers[2] = wl + (ptr^S); + buffers[3] = wr + (ptr^S); - alist_envmix_mix(n, buffers, gains, in[ptr^S]); - ++ptr; - } + 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 */ + *(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( @@ -351,27 +371,26 @@ void alist_envmix_ge( uint32_t address) { unsigned k; - struct ramp_t ramps[2]; - size_t n = (aux) ? 4 : 2; + 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); - short *save_buffer = (short*)((uint8_t*)hle->dram + address); + 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); - if (init) - { + 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 - { + } 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 */ @@ -385,36 +404,36 @@ void alist_envmix_ge( } 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]); + 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); + 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); + 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]); + 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 */ + *(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( @@ -431,7 +450,7 @@ void alist_envmix_lin( { size_t k; struct ramp_t ramps[2]; - short *save_buffer = (short*)((uint8_t*)hle->dram + address); + 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); @@ -439,8 +458,8 @@ void alist_envmix_lin( int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl); int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr); - if (init) - { + 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); @@ -448,8 +467,7 @@ void alist_envmix_lin( ramps[1].value = (vol[1] << 16); ramps[1].target = (target[1] << 16); } - else - { + 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 */ @@ -480,14 +498,15 @@ void alist_envmix_lin( 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) = (ramps[0].target>>16)&0xFFFF; /* 4-5 */ - *(int16_t *)(save_buffer + 6) = (ramps[1].target>>16)&0xFFFF; /* 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 */ + *(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( @@ -515,98 +534,91 @@ void alist_envmix_nead( if (swap_wet_LR) swap(&wl, &wr); - while (count) - { - size_t i; + 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]; - 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); + } - 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]; - 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; + 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); + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); + const int16_t *src = (int16_t*)(hle->alist_buffer + dmemi); - count >>= 1; + count >>= 1; - while(count) - { - *dst = sample_mix(dst, *src, gain); + while(count != 0) { + sample_mix(dst, *src, gain); - ++dst; - ++src; - --count; - } + ++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); + int16_t *dst = (int16_t*)(hle->alist_buffer + dmem); - count >>= 1; + count >>= 1; - while(count) - { - *dst = clamp_s16(*dst * gain >> 4); + while(count != 0) { + *dst = clamp_s16(*dst * gain >> 4); - ++dst; - --count; - } + ++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); + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); + const int16_t *src = (int16_t*)(hle->alist_buffer + dmemi); - count >>= 1; + count >>= 1; - while(count) - { - *dst = clamp_s16(*dst + *src); + while(count != 0) { + *dst = clamp_s16(*dst + *src); - ++dst; - ++src; - --count; - } + ++dst; + ++src; + --count; + } } static void alist_resample_reset(struct hle_t* hle, uint16_t pos, uint32_t* pitch_accu) { - unsigned k; + unsigned k; - for(k = 0; k < 4; ++k) - *sample(hle, pos + k) = 0; + for(k = 0; k < 4; ++k) + *sample(hle, pos + k) = 0; - *pitch_accu = 0; + *pitch_accu = 0; } -static void alist_resample_load(struct hle_t* hle, - uint32_t address, uint16_t pos, uint32_t* pitch_accu) +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); @@ -616,8 +628,7 @@ static void alist_resample_load(struct hle_t* hle, *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) +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); @@ -637,39 +648,37 @@ void alist_resample( uint32_t pitch, /* Q16.16 */ uint32_t address) { - uint32_t pitch_accu; - uint16_t ipos = (dmemi >> 1) - 4; - uint16_t opos = dmemo >> 1; + uint32_t pitch_accu; - count >>= 1; + uint16_t ipos = dmemi >> 1; + uint16_t opos = dmemo >> 1; + count >>= 1; + ipos -= 4; -#ifndef NDEBUG - if (flag2) - HleWarnMessage(hle->user_defined, "alist_resample: flag2 is not implemented"); -#endif + 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); + if (init) + alist_resample_reset(hle, ipos, &pitch_accu); + else + alist_resample_load(hle, address, ipos, &pitch_accu); - while (count) - { - const int16_t* lut = RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8); + 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); + *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; - } + pitch_accu += pitch; + ipos += (pitch_accu >> 16); + pitch_accu &= 0xffff; + --count; + } - alist_resample_save(hle, address, ipos, pitch_accu); + alist_resample_save(hle, address, ipos, pitch_accu); } void alist_resample_zoh( @@ -680,58 +689,56 @@ void alist_resample_zoh( uint32_t pitch, uint32_t pitch_accu) { - uint16_t ipos = dmemi >> 1; - uint16_t opos = dmemo >> 1; - count >>= 1; + uint16_t ipos = dmemi >> 1; + uint16_t opos = dmemo >> 1; + count >>= 1; - while(count) - { - *sample(hle, opos++) = *sample(hle, ipos); + while(count != 0) { - pitch_accu += pitch; - ipos += (pitch_accu >> 16); - pitch_accu &= 0xffff; - --count; - } + *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); + 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) + int16_t* dst, uint16_t dmemi, unsigned char scale) { - unsigned int i; - unsigned int rshift = (scale < 12) ? 12 - scale : 0; + unsigned int i; + unsigned int rshift = (scale < 12) ? 12 - scale : 0; - for(i = 0; i < 8; ++i) - { - uint8_t byte = *alist_u8(hle, dmemi++); + 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); - } + *(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift); + *(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift); + } - return 8; + return 8; } static unsigned int adpcm_predict_frame_2bits(struct hle_t* hle, - int16_t* dst, uint16_t dmemi, unsigned char scale) + int16_t* dst, uint16_t dmemi, unsigned char scale) { - unsigned int i; - unsigned int rshift = (scale < 14) ? 14 - scale : 0; + unsigned int i; + unsigned int rshift = (scale < 14) ? 14 - scale : 0; - for(i = 0; i < 4; ++i) - { - uint8_t byte = *alist_u8(hle, dmemi++); + 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); - } + *(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; + return 4; } void alist_adpcm( @@ -746,49 +753,41 @@ void alist_adpcm( uint32_t loop_address, uint32_t last_frame_address) { - int16_t last_frame[16]; - size_t i; - adpcm_predict_frame_t predict_frame; + int16_t last_frame[16]; + size_t i; - if (!hle || !codebook) - return; + adpcm_predict_frame_t predict_frame = (two_bit_per_sample) + ? adpcm_predict_frame_2bits + : adpcm_predict_frame_4bits; - predict_frame = (two_bit_per_sample) - ? adpcm_predict_frame_2bits - : adpcm_predict_frame_4bits; + assert((count & 0x1f) == 0); - 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); - if (init) - { - for (i = 0; i < 16; i++) - last_frame[i] = 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]; - 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); - while (count) - { - 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); - 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); - 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]; - for(i = 0; i < 16; ++i, dmemo += 2) - *alist_s16(hle, dmemo) = last_frame[i]; + count -= 32; + } - count -= 32; - } - - dram_store_u16(hle, (uint16_t*)last_frame, last_frame_address, 16); + dram_store_u16(hle, (uint16_t*)last_frame, last_frame_address, 16); } @@ -799,113 +798,112 @@ void alist_filter( uint32_t address, const uint32_t* lut_address) { - int x; - int16_t outbuff[0x3c0]; - int16_t *outp = outbuff; + 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* 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); + 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]; + for (x = 0; x < 8; ++x) { + int32_t v = (lutt5[x] + lutt6[x]) >> 1; + lutt5[x] = lutt6[x] = v; + } - 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 */ + for (x = 0; x < count; x += 16) { + int32_t v[8]; - 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[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[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[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[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[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[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[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[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[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[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[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[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]; + 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]; - 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; - } + 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]; - memcpy(hle->dram + address, in2 - 8, 16); - memcpy(hle->alist_buffer + dmem, outbuff, count); + 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( @@ -918,108 +916,123 @@ void alist_polef( int16_t* table, uint32_t address) { - unsigned i; - int16_t h2_before[8]; - int16_t l1 = 0; - int16_t l2 = 0; - int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); - const int16_t* const h1 = table; - int16_t* const h2 = table + 8; + int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); - count = align(count, 16); + const int16_t* const h1 = table; + int16_t* const h2 = table + 8; - if (!init) - { - l1 = *dram_u16(hle, address + 4); - l2 = *dram_u16(hle, address + 6); - } + unsigned i; + int16_t l1, l2; + int16_t h2_before[8]; - for(i = 0; i < 8; ++i) - { - h2_before[i] = h2[i]; - h2[i] = (((int32_t)h2[i] * gain) >> 14); - } + count = align(count, 16); - do - { - int16_t frame[8]; + 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, dmemi += 2) - frame[i] = *alist_s16(hle, dmemi); + for(i = 0; i < 8; ++i) { + h2_before[i] = h2[i]; + h2[i] = (((int32_t)h2[i] * gain) >> 14); + } - for(i = 0; i < 8; ++i) - { - int32_t accu = frame[i] * gain; - accu += h1[i]*l1 + h2_before[i]*l2 + rdot(i, h2, frame + i); - dst[i^S] = clamp_s16(accu >> 14); - } + do + { + int16_t frame[8]; - l1 = dst[6^S]; - l2 = dst[7^S]; + for(i = 0; i < 8; ++i, dmemi += 2) + frame[i] = *alist_s16(hle, dmemi); - dst += 8; - count -= 16; - }while(count); + 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); + } - dram_store_u32(hle, (uint32_t*)(dst - 4), address, 2); + 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) + struct hle_t* hle, + bool init, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + int16_t* table, + uint32_t address) { - int32_t i, prev; - int16_t frame[8]; - int16_t ibuf[4]; - uint16_t index = 7; - int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo); - count = align(count, 16); + 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; - 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; + count = align(count, 16); - do - { - for(i = 0; i < 8; ++i) - { - int32_t accu; + 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); + } - 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]); + 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 += 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); + 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; - 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); + index=(index+1)&7; + dmemi += 2; + } + dst += 8; + count -= 0x10; + } while (count > 0); + + dram_store_u16(hle, (uint16_t*)&frame[6], address + 4, 2); + dram_store_u16(hle, (uint16_t*)&ibuf[(index-2)&3], address+8, 1); + dram_store_u16(hle, (uint16_t*)&ibuf[(index-1)&3], address+10, 1); +} + +/* Perform a clamped gain, then attenuate it back by an amount */ +void alist_overload(struct hle_t* hle, uint16_t dmem, int16_t count, int16_t gain, uint16_t attenuation) +{ + int16_t accu; + int16_t * sample = (int16_t*)(hle->alist_buffer + dmem); + + while (count != 0) + { + accu = clamp_s16(*sample * gain); + *sample = (accu * attenuation) >> 16; + sample++; + count --; + } } diff --git a/mupen64plus-rsp-hle/src/alist.h b/mupen64plus-rsp-hle/src/alist.h index f6db482d..9db985ef 100644 --- a/mupen64plus-rsp-hle/src/alist.h +++ b/mupen64plus-rsp-hle/src/alist.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - alist.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -22,9 +22,9 @@ #ifndef ALIST_INTERNAL_H #define ALIST_INTERNAL_H -#include +#include #include -#include +#include struct hle_t; @@ -142,13 +142,21 @@ void alist_polef( 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); + struct hle_t* hle, + bool init, + uint16_t dmemo, + uint16_t dmemi, + uint16_t count, + int16_t* table, + uint32_t address); + +void alist_overload( + struct hle_t* hle, + uint16_t dmem, + int16_t count, + int16_t gain, + uint16_t attenuation); + /* * Audio flags */ diff --git a/mupen64plus-rsp-hle/src/alist_audio.c b/mupen64plus-rsp-hle/src/alist_audio.c index 827c10bf..0d2dceac 100644 --- a/mupen64plus-rsp-hle/src/alist_audio.c +++ b/mupen64plus-rsp-hle/src/alist_audio.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - alist_audio.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -21,41 +21,33 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include #include #include -#include - -#include "common.h" #include "alist.h" +#include "common.h" #include "hle_internal.h" #include "memory.h" +#include "ucodes.h" -enum -{ - DMEM_BASE = 0x5c0 -}; +enum { DMEM_BASE = 0x5c0 }; /* helper functions */ -#define get_address(hle, so) (alist_get_address((hle), (so), (hle)->alist_audio.segments, N_SEGMENTS)) -#define set_address(hle, so) alist_set_address((hle), (so), (hle)->alist_audio.segments, N_SEGMENTS) -#define clear_segments(hle) \ - (hle)->alist_audio.segments[0] = 0; \ - (hle)->alist_audio.segments[1] = 0; \ - (hle)->alist_audio.segments[2] = 0; \ - (hle)->alist_audio.segments[3] = 0; \ - (hle)->alist_audio.segments[4] = 0; \ - (hle)->alist_audio.segments[5] = 0; \ - (hle)->alist_audio.segments[6] = 0; \ - (hle)->alist_audio.segments[7] = 0; \ - (hle)->alist_audio.segments[8] = 0; \ - (hle)->alist_audio.segments[9] = 0; \ - (hle)->alist_audio.segments[10] = 0; \ - (hle)->alist_audio.segments[11] = 0; \ - (hle)->alist_audio.segments[12] = 0; \ - (hle)->alist_audio.segments[13] = 0; \ - (hle)->alist_audio.segments[14] = 0; \ - (hle)->alist_audio.segments[15] = 0 +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)) @@ -64,195 +56,189 @@ static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUS static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint16_t dmem = w1 + DMEM_BASE; - uint16_t count = w2 & 0xfff; + uint16_t dmem = w1 + DMEM_BASE; + uint16_t count = w2 & 0xfff; - if (count != 0) - alist_clear(hle, dmem, align(count, 16)); + 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); + 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); + 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); + 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); + 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); + 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); + alist_resample( + hle, + flags & A_INIT, + 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) { - unsigned lr; - uint8_t flags = (w1 >> 16); + uint8_t flags = (w1 >> 16); - if (!hle) - return; + 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_AUX) - { - hle->alist_audio.dry = w1; - hle->alist_audio.wet = w2; - return; - } - - 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; - } + 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) { - if (!hle) - return; - - hle->alist_audio.loop = get_address(hle, 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); + uint8_t flags = (w1 >> 16); + uint32_t address = get_address(hle, w2); - if (!hle) - return; - - 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); + alist_adpcm( + hle, + flags & A_INIT, + flags & A_LOOP, + 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); + uint32_t address = get_address(hle, w2); - if (hle->alist_audio.count != 0) - alist_load(hle, hle->alist_audio.in, address, hle->alist_audio.count); + 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); + uint32_t address = get_address(hle, w2); - if (hle->alist_audio.count != 0) - alist_save(hle, hle->alist_audio.out, address, hle->alist_audio.count); + 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) - { + 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 - { + } 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 count) +static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint16_t dmemi = w1 + DMEM_BASE; - uint16_t dmemo = (count >> 16) + DMEM_BASE; + uint16_t dmemi = w1 + DMEM_BASE; + uint16_t dmemo = (w2 >> 16) + DMEM_BASE; + uint16_t count = w2; - if (count != 0) - alist_move(hle, dmemo, dmemi, align(count, 16)); + 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); + uint16_t count = w1; + uint32_t address = get_address(hle, w2); - if (!hle) - return; - - dram_load_u16(hle, (uint16_t*)hle->alist_audio.table, address, align(count, 8) >> 1); + 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; + uint16_t left = (w2 >> 16) + DMEM_BASE; + uint16_t right = w2 + DMEM_BASE; - if (hle->alist_audio.count != 0) - alist_interleave(hle, hle->alist_audio.out, - left, right, align(hle->alist_audio.count, 16)); + 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; + int16_t gain = w1; + uint16_t dmemi = (w2 >> 16) + DMEM_BASE; + uint16_t dmemo = w2 + DMEM_BASE; - if (hle->alist_audio.count != 0) - alist_mix(hle, dmemo, dmemi, align(hle->alist_audio.count, 32), gain); + 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) @@ -262,12 +248,14 @@ static void SEGMENT(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t 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); + uint8_t flags = (w1 >> 16); + uint16_t gain = w1; + uint32_t address = get_address(hle, w2); - if (hle->alist_audio.count != 0) - alist_polef( + if (hle->alist_audio.count == 0) + return; + + alist_polef( hle, flags & A_INIT, hle->alist_audio.out, @@ -281,39 +269,42 @@ static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2) /* 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 - }; + static const acmd_callback_t ABI[0x10] = { + SPNOOP, ADPCM , CLEARBUFF, ENVMIXER, + LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT, + SETBUFF, SETVOL, DMEMMOVE, LOADADPCM, + MIXER, INTERLEAVE, POLEF, SETLOOP + }; - clear_segments(hle); - alist_process(hle, ABI, 0x10); + clear_segments(hle); + alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } 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 - }; + static const acmd_callback_t ABI[0x10] = { + SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE, + LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT, + SETBUFF, SETVOL, DMEMMOVE, LOADADPCM, + MIXER, INTERLEAVE, POLEF, SETLOOP + }; - clear_segments(hle); - alist_process(hle, ABI, 0x10); + clear_segments(hle); + alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } 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 - }; + static const acmd_callback_t ABI[0x10] = { + SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE, + LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT, + SETBUFF, SETVOL, DMEMMOVE, LOADADPCM, + MIXER, INTERLEAVE, POLEF, SETLOOP + }; - clear_segments(hle); - alist_process(hle, ABI, 0x10); + clear_segments(hle); + alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } diff --git a/mupen64plus-rsp-hle/src/alist_naudio.c b/mupen64plus-rsp-hle/src/alist_naudio.c index e9bbc2ea..25cf674e 100644 --- a/mupen64plus-rsp-hle/src/alist_naudio.c +++ b/mupen64plus-rsp-hle/src/alist_naudio.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - alist_naudio.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -21,24 +21,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include #include -#include - -#include "common.h" #include "alist.h" +#include "common.h" #include "hle_external.h" #include "hle_internal.h" #include "memory.h" #include "ucodes.h" -enum -{ - NAUDIO_COUNT = 0x170 -}; /* ie 184 samples */ - -enum -{ +enum { NAUDIO_COUNT = 0x170 }; /* ie 184 samples */ +enum { NAUDIO_MAIN = 0x4f0, NAUDIO_MAIN2 = 0x660, NAUDIO_DRY_LEFT = 0x9d0, @@ -47,24 +41,23 @@ enum 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); + uint8_t acmd = (w1 >> 24); - HleWarnMessage(hle->user_defined, - "Unknown audio command %d: %08x %08x", - acmd, w1, w2); + 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 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) +static void NAUDIO_0000(struct hle_t* hle, uint32_t w1, uint32_t w2) { /* ??? */ UNKNOWN(hle, w1, w2); @@ -72,8 +65,6 @@ static void NAUDIO_0000(struct hle_t* hle, static void NAUDIO_02B0(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2) { - if (!hle) - return; /* 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); @@ -81,187 +72,183 @@ static void NAUDIO_02B0(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2) 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; + uint8_t flags = (w1 >> 16); + uint16_t gain = w1; + uint8_t select_main = (w2 >> 24); + uint32_t address = (w2 & 0xffffff); - 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); - return; - } + 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); + } - 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); + 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; - } - return; - } - - hle->alist_naudio.target[0] = w1; - hle->alist_naudio.rate[0] = w2; + if (flags & A_VOL) { + if (flags & A_LEFT) { + hle->alist_naudio.vol[0] = w1; + hle->alist_naudio.dry = (w2 >> 16); + hle->alist_naudio.wet = w2; + } + else { /* A_RIGHT */ + hle->alist_naudio.target[1] = w1; + hle->alist_naudio.rate[1] = w2; + } + } + else { /* A_RATE */ + 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); + uint8_t flags = (w1 >> 16); + uint32_t address = (w2 & 0xffffff); - hle->alist_naudio.vol[1] = w1; + 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); + alist_envmix_lin( + hle, + flags & A_INIT, + 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; + uint16_t dmem = w1 + NAUDIO_MAIN; + uint16_t count = w2 & 0xfff; - alist_clear(hle, dmem, count); + 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; + 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); + 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); + uint16_t count = (w1 >> 12) & 0xfff; + uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN; + uint32_t address = (w2 & 0xffffff); - alist_load(hle, dmem, address, count); + 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); + uint16_t count = (w1 >> 12) & 0xfff; + uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN; + uint32_t address = (w2 & 0xffffff); - alist_save(hle, dmem, address, count); + alist_save(hle, dmem, address, count); } -static void NAUDIO_LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2) +static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint16_t count = w1; - uint32_t address = (w2 & 0xffffff); + uint16_t count = w1; + uint32_t address = (w2 & 0xffffff); - if (!hle) - return; - - dram_load_u16(hle, (uint16_t*)hle->alist_naudio.table, address, count >> 1); + 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; + 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); + 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); + 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; + 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); + alist_adpcm( + hle, + flags & A_INIT, + flags & A_LOOP, + 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; + 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); + alist_resample( + hle, + flags & A_INIT, + 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); + 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)) @@ -270,10 +257,20 @@ static void MP3ADDY(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNU static void MP3(struct hle_t* hle, uint32_t w1, uint32_t w2) { - unsigned index = (w1 & 0x1e); - uint32_t address = (w2 & 0xffffff); + unsigned index = (w1 & 0x1e); + uint32_t address = (w2 & 0xffffff); - mp3_task(hle, index, address); + mp3_task(hle, index, address); +} + +static void OVERLOAD(struct hle_t* hle, uint32_t w1, uint32_t w2) +{ + /* Overload distortion effect for Conker's Bad Fur Day */ + uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN; + int16_t gain = (int16_t)(uint16_t)w2; + uint16_t attenuation = w2 >> 16; + + alist_overload(hle, dmem, NAUDIO_COUNT, gain, attenuation); } /* global functions */ @@ -282,11 +279,12 @@ 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, NAUDIO_LOADADPCM, + NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM, MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP }; alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } void alist_process_naudio_bk(struct hle_t* hle) @@ -295,11 +293,12 @@ void alist_process_naudio_bk(struct hle_t* hle) static const acmd_callback_t ABI[0x10] = { SPNOOP, ADPCM, CLEARBUFF, ENVMIXER, LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000, - NAUDIO_0000, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM, + NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM, MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP }; alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } void alist_process_naudio_dk(struct hle_t* hle) @@ -308,34 +307,48 @@ void alist_process_naudio_dk(struct hle_t* hle) static const acmd_callback_t ABI[0x10] = { SPNOOP, ADPCM, CLEARBUFF, ENVMIXER, LOADBUFF, RESAMPLE, SAVEBUFF, MIXER, - MIXER, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM, + MIXER, SETVOL, DMEMMOVE, LOADADPCM, MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP }; alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } void alist_process_naudio_mp3(struct hle_t* hle) { static const acmd_callback_t ABI[0x10] = { - UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER, + OVERLOAD, ADPCM, CLEARBUFF, ENVMIXER, LOADBUFF, RESAMPLE, SAVEBUFF, MP3, - MP3ADDY, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM, + MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM, MIXER, INTERLEAVE, NAUDIO_14, SETLOOP }; alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } void alist_process_naudio_cbfd(struct hle_t* hle) { - /* TODO: see what differs from alist_process_naudio_mp3 */ + /* What differs from alist_process_naudio_mp3? + * + * JoshW: It appears that despite being a newer game, CBFD appears to have a slightly older ucode version + * compared to JFG, B.T. et al. + * For naudio_mp3, the functions DMEM parameters have an additional protective AND on them + * (basically dmem & 0xffff). + * But there are minor differences are in the RESAMPLE and ENVMIXER functions. + * I don't think it is making any noticeable difference, as it could be just a simplification of the logic. + * + * bsmiles32: The only difference I could remember between mp3 and cbfd variants is in the MP3ADDY command. + * And the MP3 overlay is also different. + */ static const acmd_callback_t ABI[0x10] = { - UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER, + OVERLOAD, ADPCM, CLEARBUFF, ENVMIXER, LOADBUFF, RESAMPLE, SAVEBUFF, MP3, - MP3ADDY, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM, + MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM, MIXER, INTERLEAVE, NAUDIO_14, SETLOOP }; alist_process(hle, ABI, 0x10); + rsp_break(hle, SP_STATUS_TASKDONE); } diff --git a/mupen64plus-rsp-hle/src/alist_nead.c b/mupen64plus-rsp-hle/src/alist_nead.c index f5758096..11dcb805 100644 --- a/mupen64plus-rsp-hle/src/alist_nead.c +++ b/mupen64plus-rsp-hle/src/alist_nead.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - alist_nead.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -21,15 +21,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include #include -#include - -#include "common.h" #include "alist.h" +#include "common.h" #include "hle_external.h" #include "hle_internal.h" #include "memory.h" +#include "ucodes.h" /* remove windows define to 0x06 */ #ifdef DUPLICATE @@ -39,11 +39,11 @@ /* audio commands definition */ static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint8_t acmd = (w1 >> 24); + uint8_t acmd = (w1 >> 24); - HleWarnMessage(hle->user_defined, - "Unknown audio command %d: %08x %08x", - acmd, w1, w2); + HleWarnMessage(hle->user_defined, + "Unknown audio command %d: %08x %08x", + acmd, w1, w2); } @@ -51,298 +51,302 @@ static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUS { } -static void NEAD_LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2) +static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint16_t count = w1; - uint32_t address = (w2 & 0xffffff); + uint16_t count = w1; + uint32_t address = (w2 & 0xffffff); - if (!hle) - return; - - dram_load_u16(hle, (uint16_t*)hle->alist_nead.table, address, count >> 1); + 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; + 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; + 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); + 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); + 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; + uint16_t dmem = w1; + uint16_t count = w2 & 0xfff; - if (count != 0) - alist_clear(hle, dmem, count); + 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); + uint16_t count = (w1 >> 12) & 0xfff; + uint16_t dmem = (w1 & 0xfff); + uint32_t address = (w2 & 0xffffff); - alist_load(hle, dmem, address, count); + 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); + uint16_t count = (w1 >> 12) & 0xfff; + uint16_t dmem = (w1 & 0xfff); + uint32_t address = (w2 & 0xffffff); - alist_save(hle, dmem, address, count); + 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; + 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); + 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); + 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); + 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; + 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); + 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 count) +static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint16_t dmemi = w1; - uint16_t dmemo = (count >> 16); + uint16_t dmemi = w1; + uint16_t dmemo = (w2 >> 16); + uint16_t count = w2; - if (count != 0) - alist_move(hle, dmemo, dmemi, (count + 3) & ~3); + 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; + 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; + 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; + 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]; + 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; + 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) ); + 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); + 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]; + 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; + 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) ); + 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); + 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); + uint8_t count = (w1 >> 16); + uint16_t dmemi = w1; + uint16_t dmemo = (w2 >> 16); - alist_repeat64(hle, dmemo, dmemi, count); + 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; + uint16_t count = w1; + uint16_t dmemi = (w2 >> 16); + uint16_t dmemo = w2; - alist_copy_every_other_sample(hle, dmemo, dmemi, count); + 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; + uint16_t left = (w2 >> 16); + uint16_t right = w2; - if (hle->alist_nead.count != 0) - alist_interleave(hle, hle->alist_nead.out, left, right, hle->alist_nead.count); + 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; + 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); + 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; + uint16_t count = (w1 >> 12) & 0xff0; + uint16_t dmemi = (w2 >> 16); + uint16_t dmemo = w2; - alist_add(hle, dmemo, dmemi, count); + 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 & 0xfff; - uint16_t dmem = (w2 >> 16); + int8_t gain = (w1 >> 16); /* Q4.4 signed */ + uint16_t count = w1 & 0xfff; + uint16_t dmem = (w2 >> 16); - alist_multQ44(hle, dmem, count, gain); + alist_multQ44(hle, dmem, count, gain); } static void FILTER(struct hle_t* hle, uint32_t w1, uint32_t w2) { - uint16_t dmem = w1; - uint8_t flags = (w1 >> 16); - uint32_t address = (w2 & 0xffffff); + 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 */ - return; - } + 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); + 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 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; + 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); + 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); + uint8_t flags = (w1 >> 16); + uint16_t gain = w1; + uint32_t address = (w2 & 0xffffff); - if (hle->alist_nead.count != 0) - alist_polef( + if (hle->alist_nead.count == 0) + return; + + alist_polef( hle, flags & A_INIT, hle->alist_nead.out, @@ -356,164 +360,197 @@ static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2) 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, NEAD_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 - }; + 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 + }; - alist_process(hle, ABI, 0x20); + alist_process(hle, ABI, 0x20); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE_MK, POLEF, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP, - HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP, - SPNOOP, SPNOOP, SPNOOP, SPNOOP - }; + 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 + }; - alist_process(hle, ABI, 0x20); + alist_process(hle, ABI, 0x20); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE_MK, POLEF, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN, - HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP, - SPNOOP, SPNOOP, SPNOOP, SPNOOP - }; + 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 + }; - alist_process(hle, ABI, 0x20); + alist_process(hle, ABI, 0x20); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, SPNOOP, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN, - SPNOOP, UNKNOWN, DUPLICATE, SPNOOP, - SPNOOP, SPNOOP, SPNOOP, SPNOOP - }; + 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 + }; - alist_process(hle, ABI, 0x20); + alist_process(hle, ABI, 0x20); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, SPNOOP, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN, - HILOGAIN, UNKNOWN, DUPLICATE, FILTER, - SPNOOP, SPNOOP, SPNOOP, SPNOOP - }; + 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 + }; - alist_process(hle, ABI, 0x20); + alist_process(hle, ABI, 0x20); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, HILOGAIN, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN - }; + 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 + }; - alist_process(hle, ABI, 0x18); + alist_process(hle, ABI, 0x18); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, HILOGAIN, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN - }; + 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 + }; - alist_process(hle, ABI, 0x18); + alist_process(hle, ABI, 0x18); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, HILOGAIN, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN - }; + 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 + }; - alist_process(hle, ABI, 0x18); + alist_process(hle, ABI, 0x18); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, HILOGAIN, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN - }; + 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 + }; - alist_process(hle, ABI, 0x18); + alist_process(hle, ABI, 0x18); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, HILOGAIN, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN - }; + 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 + }; - alist_process(hle, ABI, 0x18); + alist_process(hle, ABI, 0x18); + rsp_break(hle, SP_STATUS_TASKDONE); } 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, NEAD_LOADADPCM, - MIXER, INTERLEAVE, HILOGAIN, SETLOOP, - NEAD_16, INTERL, ENVSETUP1, ENVMIXER, - LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN - }; + 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 + }; - alist_process(hle, ABI, 0x18); + alist_process(hle, ABI, 0x18); + rsp_break(hle, SP_STATUS_TASKDONE); +} + +void alist_process_nead_mats(struct hle_t* hle) +{ + /* FIXME: implement proper ucode + * Forward the task if possible, + * otherwise better to have no sound than garbage sound + */ + if (HleForwardTask(hle->user_defined) != 0) { + rsp_break(hle, SP_STATUS_TASKDONE); + } +} + +void alist_process_nead_efz(struct hle_t* hle) +{ + /* FIXME: implement proper ucode + * Forward the task if possible, + * otherwise use FZero ucode which should be very similar + */ + if (HleForwardTask(hle->user_defined) != 0) { + alist_process_nead_fz(hle); + } } diff --git a/mupen64plus-rsp-hle/src/arithmetics.h b/mupen64plus-rsp-hle/src/arithmetics.h index a939e82c..2250b248 100644 --- a/mupen64plus-rsp-hle/src/arithmetics.h +++ b/mupen64plus-rsp-hle/src/arithmetics.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - arithmetics.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -22,11 +22,11 @@ #ifndef ARITHMETICS_H #define ARITHMETICS_H -#include - #include -static INLINE int16_t clamp_s16(int_fast32_t x) +#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; @@ -34,9 +34,9 @@ static INLINE int16_t clamp_s16(int_fast32_t x) return x; } -static INLINE int32_t vmulf(int16_t x, int16_t y) +static inline int32_t vmulf(int16_t x, int16_t y) { - return (((int32_t)(x))*((int32_t)(y))+0x4000)>>15; + return (((int32_t)(x))*((int32_t)(y))+0x4000)>>15; } #endif diff --git a/mupen64plus-rsp-hle/src/audio.c b/mupen64plus-rsp-hle/src/audio.c index 1187d5a2..fac2a101 100644 --- a/mupen64plus-rsp-hle/src/audio.c +++ b/mupen64plus-rsp-hle/src/audio.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - audio.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -94,29 +94,35 @@ const int16_t RESAMPLE_LUT[64 * 4] = { int32_t rdot(size_t n, const int16_t *x, const int16_t *y) { - int32_t accu = 0; + int32_t accu = 0; - while (n-- != 0) - accu += *(x++) * *(--y); + y += n; - return accu; + 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) { - size_t i; - const int16_t* const book1 = cb_entry; - const int16_t* const book2 = cb_entry + 8; + 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]; + const int16_t l1 = last_samples[0]; + const int16_t l2 = last_samples[1]; - 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 + i); - dst[i] = clamp_s16(accu >> 11); + 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/mupen64plus-rsp-hle/src/audio.h b/mupen64plus-rsp-hle/src/audio.h index 818bcb91..21c7a091 100644 --- a/mupen64plus-rsp-hle/src/audio.h +++ b/mupen64plus-rsp-hle/src/audio.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - audio.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -25,11 +25,19 @@ #include #include +#include "common.h" + extern const int16_t RESAMPLE_LUT[64 * 4]; int32_t rdot(size_t n, const int16_t *x, const int16_t *y); -#define adpcm_predict_sample(byte, mask, lshift, rshift) (((int16_t)(((uint16_t)((byte) & (mask)) << (lshift))) >> (rshift))) +static 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); diff --git a/mupen64plus-rsp-hle/src/cicx105.c b/mupen64plus-rsp-hle/src/cicx105.c index 84d7baf6..bda5ecab 100644 --- a/mupen64plus-rsp-hle/src/cicx105.c +++ b/mupen64plus-rsp-hle/src/cicx105.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - cicx105.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -35,20 +35,22 @@ **/ 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; + /* 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_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; - } + /* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */ + for (i = 0; i < 24; ++i) { + memcpy(dst, src, 8); + dst += 0xff0; + src += 0x8; + + } + + rsp_break(hle, 0); } diff --git a/mupen64plus-rsp-hle/src/common.h b/mupen64plus-rsp-hle/src/common.h index 3b285627..cd5dfa69 100644 --- a/mupen64plus-rsp-hle/src/common.h +++ b/mupen64plus-rsp-hle/src/common.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - common.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -29,5 +29,10 @@ # define UNUSED(x) UNUSED_ ## x #endif +/* macro for inline keyword */ +#ifdef _MSC_VER +#define inline __inline +#endif + #endif diff --git a/mupen64plus-rsp-hle/src/hle.c b/mupen64plus-rsp-hle/src/hle.c index cc9c97d2..4e65113a 100644 --- a/mupen64plus-rsp-hle/src/hle.c +++ b/mupen64plus-rsp-hle/src/hle.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - hle.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -21,44 +21,41 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include #include -#include + +#ifdef ENABLE_TASK_DUMP +#include +#endif #include "hle_external.h" #include "hle_internal.h" #include "memory.h" -#include "m64p_plugin.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 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); +static bool is_task(struct hle_t* hle); +static void send_dlist_to_gfx_plugin(struct hle_t* hle); +static ucode_func_t try_audio_task_detection(struct hle_t* hle); +static ucode_func_t try_normal_task_detection(struct hle_t* hle); +static ucode_func_t non_task_detection(struct hle_t* hle); +static ucode_func_t task_detection(struct hle_t* hle); -extern RSP_INFO rsp_info; - -/* local variables */ -static const bool FORWARD_AUDIO = false, FORWARD_GFX = true; +#ifdef ENABLE_TASK_DUMP +static void dump_binary(struct hle_t* hle, 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 uc_start); +static void dump_unknown_non_task(struct hle_t* hle, unsigned int uc_start); +#endif /* Global functions */ void hle_init(struct hle_t* hle, @@ -109,30 +106,40 @@ void hle_init(struct hle_t* hle, hle->user_defined = user_defined; } -/** - * 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. - **/ -#define is_task(hle) ((*dmem_u32((hle), TASK_UCODE_BOOT_SIZE) <= 0x1000)) - 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); - return; - } + uint32_t uc_start = *dmem_u32(hle, TASK_UCODE); + uint32_t uc_dstart = *dmem_u32(hle, TASK_UCODE_DATA); + uint32_t uc_dsize = *dmem_u32(hle, TASK_UCODE_DATA_SIZE); - non_task_dispatching(hle); - rsp_break(hle, 0); + bool match = false; + struct cached_ucodes_t * cached_ucodes = &hle->cached_ucodes; + struct ucode_info_t *info = NULL; + if (cached_ucodes->count > 0) + info = &cached_ucodes->infos[cached_ucodes->count-1]; + for (int i = 0; i < cached_ucodes->count; i++) + { + if (info->uc_start == uc_start && info->uc_dstart == uc_dstart && info->uc_dsize == uc_dsize) + { + match = true; + break; + } + info--; + } + + if (!match) + { + info = &cached_ucodes->infos[cached_ucodes->count]; + info->uc_start = uc_start; + info->uc_dstart = uc_dstart; + info->uc_dsize = uc_dsize; + info->uc_pfunc = task_detection(hle); + cached_ucodes->count++; + assert(cached_ucodes->count <= CACHED_UCODES_MAX_SIZE); + assert(info->uc_pfunc != NULL); + } + + info->uc_pfunc(hle); } /* local functions */ @@ -147,233 +154,371 @@ static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size) return sum; } - -static void rsp_break(struct hle_t* hle, unsigned int setbits) +/** + * 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) { - *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; - if (rsp_info.CheckInterrupts) - rsp_info.CheckInterrupts(); - } + return (*dmem_u32(hle, TASK_UCODE_BOOT_SIZE) <= 0x1000); } -static void forward_gfx_task(struct hle_t* hle) +void rsp_break(struct hle_t* hle, unsigned int setbits) { - if (rsp_info.ProcessDlistList) - rsp_info.ProcessDlistList(); + *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 bool try_fast_audio_dispatching(struct hle_t* hle) +static void send_alist_to_audio_plugin(struct hle_t* hle) +{ + HleProcessAlistList(hle->user_defined); + rsp_break(hle, SP_STATUS_TASKDONE); +} + +static void send_dlist_to_gfx_plugin(struct hle_t* hle) +{ + /* Since GFX_INFO version 2, these bits are set before calling the ProcessDlistList function. + * And the GFX plugin is responsible to unset them if needed. + * For GFX_INFO version < 2, the GFX plugin didn't have access to sp_status so + * it doesn't matter if we set these bits before calling ProcessDlistList function. + */ + *hle->sp_status |= SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT; + + HleProcessDlistList(hle->user_defined); + + if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK) && (*hle->sp_status & (SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT))) { + *hle->mi_intr |= MI_INTR_SP; + HleCheckInterrupts(hle->user_defined); + } +} + +static void task_done(struct hle_t* hle) +{ + rsp_break(hle, SP_STATUS_TASKDONE); +} + +static void unknown_ucode(struct hle_t* hle) +{ + /* Forward task to RSP Fallback. + * If task is not forwarded, use the regular "unknown ucode" path */ + if (HleForwardTask(hle->user_defined) != 0) { + + uint32_t uc_start = *dmem_u32(hle, TASK_UCODE); + HleWarnMessage(hle->user_defined, "unknown RSP code: uc_start: %x PC:%x", uc_start, *hle->sp_pc); +#ifdef ENABLE_TASK_DUMP + dump_unknown_non_task(hle, uc_start); +#endif + } +} + +static void unknown_task(struct hle_t* hle) +{ + /* Forward task to RSP Fallback. + * If task is not forwarded, use the regular "unknown task" path */ + if (HleForwardTask(hle->user_defined) != 0) { + + /* Send task_done signal for unknown ucodes to allow further processings */ + rsp_break(hle, SP_STATUS_TASKDONE); + + uint32_t uc_start = *dmem_u32(hle, TASK_UCODE); + HleWarnMessage(hle->user_defined, "unknown OSTask: uc_start: %x PC:%x", uc_start, *hle->sp_pc); +#ifdef ENABLE_TASK_DUMP + dump_unknown_task(hle, uc_start); +#endif + } +} + +static ucode_func_t try_audio_task_detection(struct hle_t* hle) { - uint32_t v; /* 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); - } + 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) */ + return &alist_process_audio; + case 0x1dc8138c: /* GoldenEye */ + return &alist_process_audio_ge; + case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */ + return &alist_process_audio_bc; + 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) */ + return &alist_process_nead_mk; + case 0x111812e0: /* StarFox (J) */ + return &alist_process_nead_sfj; + case 0x110412ac: /* WaveRace (J RevB) */ + return &alist_process_nead_wrjb; + case 0x110412cc: /* StarFox/LylatWars (except J) */ + return &alist_process_nead_sf; + case 0x1cd01250: /* FZeroX */ + return &alist_process_nead_fz; + case 0x1f08122c: /* YoshisStory */ + return &alist_process_nead_ys; + case 0x1f38122c: /* 1080° Snowboarding */ + return &alist_process_nead_1080; + case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */ + return &alist_process_nead_oot; + case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */ + return &alist_process_nead_mm; + case 0x109411f8: /* Zelda MM (E Beta) */ + return &alist_process_nead_mmb; + case 0x1eac11b8: /* AnimalCrossing */ + return &alist_process_nead_ac; + case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */ + return &musyx_v2_task; + case 0x1f701238: /* Mario Artist Talent Studio */ + return &alist_process_nead_mats; + case 0x1f4c1230: /* FZeroX Expansion */ + return &alist_process_nead_efz; + default: + HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v); + } } - else + } else { + v = *dram_u32(hle, ucode_data + 0x10); + switch(v) { - 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; + case 0x00000001: /* MusyX v1 + RogueSquadron, ResidentEvil2, PolarisSnoCross, + TheWorldIsNotEnough, RugratsInParis, NBAShowTime, + HydroThunder, Tarzan, GauntletLegend, Rush2049 */ + return &musyx_v1_task; + case 0x0000127c: /* naudio (many games) */ + return &alist_process_naudio; + case 0x00001280: /* BanjoKazooie */ + return &alist_process_naudio_bk; + case 0x1c58126c: /* DonkeyKong */ + return &alist_process_naudio_dk; + case 0x1ae8143c: /* BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark */ + return &alist_process_naudio_mp3; + case 0x1ab0140c: /* ConkerBadFurDay */ + return &alist_process_naudio_cbfd; - default: - HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v); - } + default: + HleWarnMessage(hle->user_defined, "ABI3 identification regression: v=%08x", v); } } - else - { - v = *dram_u32(hle, ucode_data + 0x10); - switch(v) - { - /* -- MusyX v1 -- - Star Wars: Rogue Squadron - Resident Evil 2 - Polaris SnoCross - 007: The World Is Not Enough - Rugrats In Paris - NBA ShowTime - Hydro Thunder - Tarzan - Gauntlet Legends - Rush 2049 - */ - case 0x00000001: - musyx_v1_task(hle); - return true; - /* NAUDIO (many games) */ - case 0x0000127c: - alist_process_naudio(hle); - return true; - /* Banjo Kazooie */ - case 0x00001280: - alist_process_naudio_bk(hle); - return true; - /* Donkey Kong 64 */ - case 0x1c58126c: - alist_process_naudio_dk(hle); - return true; - /* Banjo Tooie - * Jet Force Gemini - * Mickey's SpeedWay USA - * Perfect Dark */ - case 0x1ae8143c: - alist_process_naudio_mp3(hle); - return true; - case 0x1ab0140c: - /* Conker's Bad Fur Day */ - alist_process_naudio_cbfd(hle); - return true; - default: - HleWarnMessage(hle->user_defined, "ABI3 identification regression: v=%08x", v); - } + + return NULL; +} + +static ucode_func_t try_normal_task_detection(struct hle_t* hle) +{ + 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 &task_done; + + /* GFX: Twintris [misleading task->type == 0] */ + case 0x212ee: + if (hle->hle_gfx) { + return &send_dlist_to_gfx_plugin; + } + return NULL; + + /* JPEG: found in Pokemon Stadium J */ + case 0x2c85a: + return &jpeg_decode_PS0; + + /* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */ + case 0x2caa6: + return &jpeg_decode_PS; + + /* JPEG: found in Ogre Battle, Bottom of the 9th */ + case 0x130de: + case 0x278b0: + return &jpeg_decode_OB; } - return false; -} + /* Resident Evil 2 */ + sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 256); + switch (sum) { -static bool try_fast_task_dispatching(struct hle_t* hle) -{ - /* identify task ucode by its type */ - switch (*dmem_u32(hle, TASK_TYPE)) - { - case 1: - /* Resident evil 2 */ - if (*dmem_u32(hle, TASK_DATA_PTR) == 0) - return false; + case 0x450f: + return &resize_bilinear_task; - if (FORWARD_GFX) - { - forward_gfx_task(hle); - return true; - } - break; + case 0x3b44: + return &decode_video_frame_task; - case 2: - if (FORWARD_AUDIO) - { - if (rsp_info.ProcessAlistList) - rsp_info.ProcessAlistList(); - return true; - } - if (try_fast_audio_dispatching(hle)) - return true; - break; - - case 7: - if (rsp_info.ShowCFB) - rsp_info.ShowCFB(); - return true; + case 0x3d84: + return &fill_video_double_buffer_task; } - return false; + /* HVQM */ + sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 1488); + switch (sum) { + case 0x19495: + return &hvqm2_decode_sp1_task; + + case 0x19728: + return &hvqm2_decode_sp2_task; + } + + return NULL; } -static void normal_task_dispatching(struct hle_t* hle) +static ucode_func_t non_task_detection(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); + const unsigned int sum = sum_bytes(hle->imem, 44); - 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; - - /* Resident evil 2 */ - case 0x29a20: /* USA */ - case 0x298c5: /* Europe */ - case 0x298b8: /* USA Rev A */ - case 0x296d9: /* J */ - resize_bilinear_task(hle); - return; - } - - HleWarnMessage(hle->user_defined, "unknown OSTask: sum: %x PC:%x", sum, *hle->sp_pc); + if (sum == 0x9e2) + { + /* CIC x105 ucode (used during boot of CIC x105 games) */ + return &cicx105_ucode; + } + return &unknown_ucode; } -static void non_task_dispatching(struct hle_t* hle) +static ucode_func_t task_detection(struct hle_t* hle) { - const unsigned int sum = sum_bytes(hle->imem, 44); + if (is_task(hle)) { + ucode_func_t uc_pfunc; + uint32_t type = *dmem_u32(hle, TASK_TYPE); - if (sum == 0x9e2) - { - /* CIC x105 ucode (used during boot of CIC x105 games) */ - cicx105_ucode(hle); - return; - } + if (type == 2) { + if (hle->hle_aud) { + return &send_alist_to_audio_plugin; + } + uc_pfunc = try_audio_task_detection(hle); + if (uc_pfunc) + return uc_pfunc; + } - HleWarnMessage(hle->user_defined, "unknown RSP code: sum: %x PC:%x", sum, *hle->sp_pc); + uc_pfunc = try_normal_task_detection(hle); + if (uc_pfunc) + return uc_pfunc; + + if (type == 1) { + if (hle->hle_gfx) { + return &send_dlist_to_gfx_plugin; + } + } + + return &unknown_task; + } + else { + return non_task_detection(hle); + } } +#ifdef ENABLE_TASK_DUMP +static void dump_unknown_task(struct hle_t* hle, unsigned int uc_start) +{ + 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", uc_start); + dump_task(hle, filename); + + /* dump ucode_boot */ + sprintf(&filename[0], "ucode_boot_%x.bin", uc_start); + dump_binary(hle, 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", uc_start); + dump_binary(hle, filename, (void*)dram_u32(hle, ucode), 0xf80); + } + + /* dump ucode_data */ + if (ucode_data != 0) { + sprintf(&filename[0], "ucode_data_%x.bin", uc_start); + dump_binary(hle, 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", uc_start); + dump_binary(hle, 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 uc_start) +{ + char filename[256]; + + /* dump IMEM & DMEM for further analysis */ + sprintf(&filename[0], "imem_%x.bin", uc_start); + dump_binary(hle, filename, hle->imem, 0x1000); + + sprintf(&filename[0], "dmem_%x.bin", uc_start); + dump_binary(hle, filename, hle->dmem, 0x1000); +} + +static void dump_binary(struct hle_t* hle, 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/mupen64plus-rsp-hle/src/hle.h b/mupen64plus-rsp-hle/src/hle.h index 3c705a93..a420b752 100644 --- a/mupen64plus-rsp-hle/src/hle.h +++ b/mupen64plus-rsp-hle/src/hle.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - hle.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * diff --git a/mupen64plus-rsp-hle/src/hle_external.h b/mupen64plus-rsp-hle/src/hle_external.h index 2f35a3c9..766cc51e 100644 --- a/mupen64plus-rsp-hle/src/hle_external.h +++ b/mupen64plus-rsp-hle/src/hle_external.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - hle_external.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -22,17 +22,25 @@ #ifndef HLE_EXTERNAL_H #define HLE_EXTERNAL_H +#if defined(__GNUC__) +#define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) +#else +#define ATTR_FMT(fmtpos, attrpos) +#endif + /* 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 HleVerboseMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3); +void HleInfoMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3); +void HleErrorMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3); +void HleWarnMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3); 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); +int HleForwardTask(void* user_defined); #endif diff --git a/mupen64plus-rsp-hle/src/hle_internal.h b/mupen64plus-rsp-hle/src/hle_internal.h index b0bcb6a1..efdca5c2 100644 --- a/mupen64plus-rsp-hle/src/hle_internal.h +++ b/mupen64plus-rsp-hle/src/hle_internal.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - hle_internal.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -57,6 +57,9 @@ struct hle_t /* for user convenience, this will be passed to "external" functions */ void* user_defined; + int hle_gfx; + int hle_aud; + /* alist.c */ uint8_t alist_buffer[0x1000]; @@ -71,7 +74,20 @@ struct hle_t /* mp3.c */ uint8_t mp3_buffer[0x1000]; + + struct cached_ucodes_t cached_ucodes; }; +/* some mips interface interrupt flags */ +#define MI_INTR_SP 0x1 + +/* 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 + +void rsp_break(struct hle_t* hle, unsigned int setbits); + #endif diff --git a/mupen64plus-rsp-hle/src/hle_memory.c b/mupen64plus-rsp-hle/src/hle_memory.c index f8245ea1..7d5066bf 100644 --- a/mupen64plus-rsp-hle/src/hle_memory.c +++ b/mupen64plus-rsp-hle/src/hle_memory.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - memory.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -26,30 +26,49 @@ /* Global functions */ void load_u8(uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count) { - while (count) - { - *(dst++) = *u8(buffer, address); - address += 1; - --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) - { - *(dst++) = *u16(buffer, address); - address += 2; - --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) - { - *u16(buffer, address) = *(src++); - address += 2; - --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/mupen64plus-rsp-hle/src/hle_plugin.c b/mupen64plus-rsp-hle/src/hle_plugin.c index df491db9..f1c79282 100644 --- a/mupen64plus-rsp-hle/src/hle_plugin.c +++ b/mupen64plus-rsp-hle/src/hle_plugin.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - plugin.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -23,62 +23,39 @@ #include #include +#include #include "common.h" #include "hle.h" +#include "hle_internal.h" +#include "hle_external.h" #define M64P_PLUGIN_PROTOTYPES 1 -#include "m64p_types.h" #include "m64p_common.h" +#include "m64p_config.h" +#include "m64p_frontend.h" #include "m64p_plugin.h" +#include "m64p_types.h" -#define RSP_HLE_VERSION 0x020000 +#define CONFIG_API_VERSION 0x020100 +#define CONFIG_PARAM_VERSION 1.00 + +#define RSP_API_VERSION 0x20000 +#define RSP_HLE_VERSION 0x020509 #define RSP_PLUGIN_API_VERSION 0x020000 /* local variables */ static struct hle_t g_hle; +static void (*l_CheckInterrupts)(void) = NULL; +static void (*l_ProcessDlistList)(void) = NULL; +static void (*l_ProcessAlistList)(void) = NULL; +static void (*l_ProcessRdpList)(void) = NULL; +static void (*l_ShowCFB)(void) = NULL; +static void (*l_DebugCallback)(void *, int, const char *) = NULL; +static void *l_DebugCallContext = NULL; +static int l_PluginInit = 0; -static unsigned l_PluginInit = 0; - -/* local function */ -static void DebugMessage(int level, const char *message, va_list args) -{ - char msgbuf[1024]; - - vsprintf(msgbuf, message, args); -} - -/* Global functions needed by HLE core */ -void HleVerboseMessage(void* UNUSED(user_defined), const char *message, ...) -{ - va_list args; - va_start(args, message); - DebugMessage(M64MSG_VERBOSE, message, args); - va_end(args); -} - -void HleWarnMessage(void* UNUSED(user_defined), const char *message, ...) -{ - va_list args; - va_start(args, message); - DebugMessage(M64MSG_WARNING, message, args); - va_end(args); -} - -/* DLL-exported functions */ -m64p_error hlePluginStartup(m64p_dynlib_handle UNUSED(CoreLibHandle), void *Context, void (*DebugCallback)(void *, int, const char *)) -{ - l_PluginInit = 1; - return M64ERR_SUCCESS; -} - -m64p_error hlePluginShutdown(void) -{ - l_PluginInit = 0; - return M64ERR_SUCCESS; -} - -m64p_error hlePluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) +EXPORT m64p_error CALL hlePluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { /* set version info */ if (PluginType != NULL) @@ -99,48 +76,164 @@ m64p_error hlePluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, return M64ERR_SUCCESS; } -extern RSP_INFO rsp_info; - -void hleInitiateRSP(RSP_INFO Rsp_Info, unsigned int* UNUSED(CycleCount)) +/* local function */ +static void DebugMessage(int level, const char *message, va_list args) { - hle_init(&g_hle, - rsp_info.RDRAM, - rsp_info.DMEM, - rsp_info.IMEM, - rsp_info.MI_INTR_REG, - rsp_info.SP_MEM_ADDR_REG, - rsp_info.SP_DRAM_ADDR_REG, - rsp_info.SP_RD_LEN_REG, - rsp_info.SP_WR_LEN_REG, - rsp_info.SP_STATUS_REG, - rsp_info.SP_DMA_FULL_REG, - rsp_info.SP_DMA_BUSY_REG, - rsp_info.SP_PC_REG, - rsp_info.SP_SEMAPHORE_REG, - rsp_info.DPC_START_REG, - rsp_info.DPC_END_REG, - rsp_info.DPC_CURRENT_REG, - rsp_info.DPC_STATUS_REG, - rsp_info.DPC_CLOCK_REG, - rsp_info.DPC_BUFBUSY_REG, - rsp_info.DPC_PIPEBUSY_REG, - rsp_info.DPC_TMEM_REG, - NULL); + char msgbuf[1024]; + + if (l_DebugCallback == NULL) + return; + + vsprintf(msgbuf, message, args); + + (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); +} + +/* Global functions needed by HLE core */ +void HleVerboseMessage(void* UNUSED(user_defined), const char *message, ...) +{ +} + +void HleErrorMessage(void* UNUSED(user_defined), const char *message, ...) +{ +} + +void HleWarnMessage(void* UNUSED(user_defined), const char *message, ...) +{ +} + +void HleCheckInterrupts(void* UNUSED(user_defined)) +{ + if (l_CheckInterrupts == NULL) + return; + + (*l_CheckInterrupts)(); +} + +void HleProcessDlistList(void* UNUSED(user_defined)) +{ + if (l_ProcessDlistList == NULL) + return; + + (*l_ProcessDlistList)(); +} + +void HleProcessAlistList(void* UNUSED(user_defined)) +{ + if (l_ProcessAlistList == NULL) + return; + + (*l_ProcessAlistList)(); +} + +void HleProcessRdpList(void* UNUSED(user_defined)) +{ + if (l_ProcessRdpList == NULL) + return; + + (*l_ProcessRdpList)(); +} + +void HleShowCFB(void* UNUSED(user_defined)) +{ + if (l_ShowCFB == NULL) + return; + + (*l_ShowCFB)(); +} + +int HleForwardTask(void* user_defined) +{ + return -1; +} + +/* DLL-exported functions */ +EXPORT m64p_error CALL hlePluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, + void (*DebugCallback)(void *, int, const char *)) +{ + if (l_PluginInit) + return M64ERR_ALREADY_INIT; + + /* first thing is to set the callback function for debug info */ + l_DebugCallback = DebugCallback; + l_DebugCallContext = Context; + + /* this plugin doesn't use any Core library functions (ex for Configuration), so no need to keep the CoreLibHandle */ l_PluginInit = 1; + return M64ERR_SUCCESS; } -unsigned int hleDoRspCycles(unsigned int Cycles) +EXPORT m64p_error CALL hlePluginShutdown(void) { - if (!l_PluginInit) - hleInitiateRSP(rsp_info, NULL); + if (!l_PluginInit) + return M64ERR_NOT_INIT; - hle_execute(&g_hle); - return Cycles; + /* reset some local variable */ + l_DebugCallback = NULL; + l_DebugCallContext = NULL; + + l_PluginInit = 0; + return M64ERR_SUCCESS; } - -void hleRomClosed(void) +EXPORT unsigned int CALL hleDoRspCycles(unsigned int Cycles) { - /* do nothing */ + hle_execute(&g_hle); + return Cycles; +} + +EXPORT void CALL hleInitiateRSP(RSP_INFO Rsp_Info, unsigned int* CycleCount) +{ + hle_init(&g_hle, + Rsp_Info.RDRAM, + Rsp_Info.DMEM, + Rsp_Info.IMEM, + Rsp_Info.MI_INTR_REG, + Rsp_Info.SP_MEM_ADDR_REG, + Rsp_Info.SP_DRAM_ADDR_REG, + Rsp_Info.SP_RD_LEN_REG, + Rsp_Info.SP_WR_LEN_REG, + Rsp_Info.SP_STATUS_REG, + Rsp_Info.SP_DMA_FULL_REG, + Rsp_Info.SP_DMA_BUSY_REG, + Rsp_Info.SP_PC_REG, + Rsp_Info.SP_SEMAPHORE_REG, + Rsp_Info.DPC_START_REG, + Rsp_Info.DPC_END_REG, + Rsp_Info.DPC_CURRENT_REG, + Rsp_Info.DPC_STATUS_REG, + Rsp_Info.DPC_CLOCK_REG, + Rsp_Info.DPC_BUFBUSY_REG, + Rsp_Info.DPC_PIPEBUSY_REG, + Rsp_Info.DPC_TMEM_REG, + NULL); + + l_CheckInterrupts = Rsp_Info.CheckInterrupts; + l_ProcessDlistList = Rsp_Info.ProcessDlistList; + l_ProcessAlistList = Rsp_Info.ProcessAlistList; + l_ProcessRdpList = Rsp_Info.ProcessRdpList; + l_ShowCFB = Rsp_Info.ShowCFB; + + // Is the DoCommand really needed? It's upstream + m64p_rom_header rom_header; + CoreDoCommand(M64CMD_ROM_GET_HEADER, sizeof(rom_header), &rom_header); + + g_hle.hle_gfx = 1; + g_hle.hle_aud = 0; + + /* notify fallback plugin */ + /*if (l_InitiateRSP) { + l_InitiateRSP(Rsp_Info, CycleCount); + }*/ +} + +EXPORT void CALL hleRomClosed(void) +{ + g_hle.cached_ucodes.count = 0; + + /* notify fallback plugin */ + /*if (l_RomClosed) { + l_RomClosed(); + }*/ } diff --git a/mupen64plus-rsp-hle/src/hvqm.c b/mupen64plus-rsp-hle/src/hvqm.c new file mode 100644 index 00000000..8f8a943b --- /dev/null +++ b/mupen64plus-rsp-hle/src/hvqm.c @@ -0,0 +1,354 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-rsp-hle - hvqm.c * + * Mupen64Plus homepage: https://mupen64plus.org/ * + * Copyright (C) 2020 Gilles Siberlin * + * * + * 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 + +#include "hle_external.h" +#include "hle_internal.h" +#include "memory.h" + + /* Nest size */ +#define HVQM2_NESTSIZE_L 70 /* Number of elements on long side */ +#define HVQM2_NESTSIZE_S 38 /* Number of elements on short side */ +#define HVQM2_NESTSIZE (HVQM2_NESTSIZE_L * HVQM2_NESTSIZE_S) + +struct HVQM2Block { + uint8_t nbase; + uint8_t dc; + uint8_t dc_l; + uint8_t dc_r; + uint8_t dc_u; + uint8_t dc_d; +}; + +struct HVQM2Basis { + uint8_t sx; + uint8_t sy; + int16_t scale; + uint16_t offset; + uint16_t lineskip; +}; + +struct HVQM2Arg { + uint32_t info; + uint32_t buf; + uint16_t buf_width; + uint8_t chroma_step_h; + uint8_t chroma_step_v; + uint16_t hmcus; + uint16_t vmcus; + uint8_t alpha; + uint32_t nest; +}; + +struct RGBA { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +static struct HVQM2Arg arg; + +static const int16_t constant[5][16] = { +{0x0006,0x0008,0x0008,0x0006,0x0008,0x000A,0x000A,0x0008,0x0008,0x000A,0x000A,0x0008,0x0006,0x0008,0x0008,0x0006}, +{0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF}, +{0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002}, +{0x0002,0x0002,0x0002,0x0002,0x0000,0x0000,0x0000,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, +{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0002,0x0002,0x0002,0x0002} +}; + +static int process_info(struct hle_t* hle, uint8_t* base, int16_t* out) +{ + struct HVQM2Block block; + uint8_t nbase = *base; + + dram_load_u8(hle, (uint8_t*)&block, arg.info, sizeof(struct HVQM2Block)); + arg.info += 8; + + *base = block.nbase & 0x7; + + if ((block.nbase & nbase) != 0) + return 0; + + if (block.nbase == 0) + { + //LABEL8 + for (int i = 0; i < 16; i++) + { + out[i] = constant[0][i] * block.dc; + out[i] += constant[1][i] * block.dc_l; + out[i] += constant[2][i] * block.dc_r; + out[i] += constant[3][i] * block.dc_u; + out[i] += constant[4][i] * block.dc_d; + out[i] += 4; + out[i] >>= 3; + } + } + else if ((block.nbase & 0xf) == 0) + { + //LABEL7 + for (int i = 0; i < 16; i++) + { + out[i] = *dram_u8(hle, arg.info); + arg.info++; + } + } + else if (*base == 0) + { + //LABEL6 + for (int i = 0; i < 16; i++) + { + out[i] = *(int8_t*)dram_u8(hle, arg.info) + block.dc; + arg.info++; + } + } + else + { + //LABEL5 + struct HVQM2Basis basis; + + for (int i = 0; i < 16; i++) + out[i] = block.dc; + + for (; *base != 0; (*base)--) + { + basis.sx = *dram_u8(hle, arg.info); + arg.info++; + basis.sy = *dram_u8(hle, arg.info); + arg.info++; + basis.scale = *dram_u16(hle, arg.info); + arg.info += 2; + basis.offset = *dram_u16(hle, arg.info); + arg.info += 2; + basis.lineskip = *dram_u16(hle, arg.info); + arg.info += 2; + + int16_t vec[16]; + uint32_t addr = arg.nest + basis.offset; + int shift = (basis.sx != 0) ? 1 : 0; + + //LABEL9 + //LABEL10 + for (int i = 0; i < 16; i += 4) + { + vec[i] = *dram_u8(hle, addr); + vec[i + 1] = *dram_u8(hle, addr + (1 << shift)); + vec[i + 2] = *dram_u8(hle, addr + (2 << shift)); + vec[i + 3] = *dram_u8(hle, addr + (3 << shift)); + addr += basis.lineskip; + } + + //LABEL11 + int16_t sum = 0x8; + for (int i = 0; i < 16; i++) + sum += vec[i]; + + sum >>= 4; + + int16_t max = 0; + for (int i = 0; i < 16; i++) + { + vec[i] -= sum; + max = (abs(vec[i]) > max) ? abs(vec[i]) : max; + } + + double dmax = 0.0; + if (max > 0) + dmax = (double)(basis.scale << 2) / (double)max; + + for (int i = 0; i < 16; i++) + out[i] += (vec[i] < 0) ? (int16_t)((double)vec[i] * dmax - 0.5) : (int16_t)((double)vec[i] * dmax + 0.5); + + block.nbase &= 8; + } + + assert(block.nbase == 0); + //if(block.nbase != 0) + // LABEL6 + } + + return 1; +} + +#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255)) +static struct RGBA YCbCr_to_RGBA(int16_t Y, int16_t Cb, int16_t Cr, uint8_t alpha) +{ + struct RGBA color; + + //Format S10.6 + int r = (int)(((double)Y + 0.5) + (1.765625 * (double)(Cr - 128))); + int g = (int)(((double)Y + 0.5) - (0.34375 * (double)(Cr - 128)) - (0.71875 * (double)(Cb - 128))); + int b = (int)(((double)Y + 0.5) + (1.40625 * (double)(Cb - 128))); + + color.r = SATURATE8(r); + color.g = SATURATE8(g); + color.b = SATURATE8(b); + color.a = alpha; + + return color; +} + +void store_rgba5551(struct hle_t* hle, struct RGBA color, uint32_t * addr) +{ + uint16_t pixel = ((color.b >> 3) << 11) | ((color.g >> 3) << 6) | ((color.r >> 3) << 1) | (color.a & 1); + dram_store_u16(hle, &pixel, *addr, 1); + *addr += 2; +} + +void store_rgba8888(struct hle_t* hle, struct RGBA color, uint32_t * addr) +{ + uint32_t pixel = (color.b << 24) | (color.g << 16) | (color.r << 8) | color.a; + dram_store_u32(hle, &pixel, *addr, 1); + *addr += 4; +} + +typedef void(*store_pixel_t)(struct hle_t* hle, struct RGBA color, uint32_t * addr); + +static void hvqm2_decode(struct hle_t* hle, int is32) +{ + //uint32_t uc_data_ptr = *dmem_u32(hle, TASK_UCODE_DATA); + uint32_t data_ptr = *dmem_u32(hle, TASK_DATA_PTR); + + assert((*dmem_u32(hle, TASK_FLAGS) & 0x1) == 0); + + /* Fill HVQM2Arg struct */ + arg.info = *dram_u32(hle, data_ptr); + data_ptr += 4; + arg.buf = *dram_u32(hle, data_ptr); + data_ptr += 4; + arg.buf_width = *dram_u16(hle, data_ptr); + data_ptr += 2; + arg.chroma_step_h = *dram_u8(hle, data_ptr); + data_ptr++; + arg.chroma_step_v = *dram_u8(hle, data_ptr); + data_ptr++; + arg.hmcus = *dram_u16(hle, data_ptr); + data_ptr += 2; + arg.vmcus = *dram_u16(hle, data_ptr); + data_ptr += 2; + arg.alpha = *dram_u8(hle, data_ptr); + arg.nest = data_ptr + 1; + + assert(arg.chroma_step_h == 2); + assert((arg.chroma_step_v == 1) || (arg.chroma_step_v == 2)); + assert((*hle->sp_status & 0x80) == 0); //SP_STATUS_YIELD + + int length, skip; + store_pixel_t store_pixel; + + if (is32) + { + length = 0x20; + skip = arg.buf_width << 2; + arg.buf_width <<= 4; + store_pixel = &store_rgba8888; + } + else + { + length = 0x10; + skip = arg.buf_width << 1; + arg.buf_width <<= 3; + store_pixel = &store_rgba5551; + } + + if (arg.chroma_step_v == 2) + arg.buf_width += arg.buf_width; + + for (int i = arg.vmcus; i != 0; i--) + { + uint32_t out; + int j; + + for (j = arg.hmcus, out = arg.buf; j != 0; j--, out += length) + { + uint8_t base = 0x80; + int16_t Cb[16], Cr[16], Y1[32], Y2[32]; + int16_t* pCb = Cb; + int16_t* pCr = Cr; + int16_t* pY1 = Y1; + int16_t* pY2 = Y2; + + if (arg.chroma_step_v == 2) + { + if (process_info(hle, &base, pY1) == 0) + continue; + if (process_info(hle, &base, pY2) == 0) + continue; + + pY1 = &Y1[16]; + pY2 = &Y2[16]; + } + + if (process_info(hle, &base, pY1) == 0) + continue; + if (process_info(hle, &base, pY2) == 0) + continue; + if (process_info(hle, &base, Cr) == 0) + continue; + if (process_info(hle, &base, Cb) == 0) + continue; + + pY1 = Y1; + pY2 = Y2; + + uint32_t out_buf = out; + for (int k = 0; k < 4; k++) + { + for (int m = 0; m < arg.chroma_step_v; m++) + { + uint32_t addr = out_buf; + for (int l = 0; l < 4; l++) + { + struct RGBA color = YCbCr_to_RGBA(pY1[l], pCb[l >> 1], pCr[l >> 1], arg.alpha); + store_pixel(hle, color, &addr); + } + for (int l = 0; l < 4; l++) + { + struct RGBA color = YCbCr_to_RGBA(pY2[l], pCb[(l + 4) >> 1], pCr[(l + 4) >> 1], arg.alpha); + store_pixel(hle, color, &addr); + } + out_buf += skip; + pY1 += 4; + pY2 += 4; + } + pCr += 4; + pCb += 4; + } + } + arg.buf += arg.buf_width; + } + rsp_break(hle, SP_STATUS_TASKDONE); +} + +void hvqm2_decode_sp1_task(struct hle_t* hle) +{ + hvqm2_decode(hle, 0); +} + +void hvqm2_decode_sp2_task(struct hle_t* hle) +{ + hvqm2_decode(hle, 1); +} \ No newline at end of file diff --git a/mupen64plus-rsp-hle/src/jpeg.c b/mupen64plus-rsp-hle/src/jpeg.c index 4365c05f..ff424c40 100644 --- a/mupen64plus-rsp-hle/src/jpeg.c +++ b/mupen64plus-rsp-hle/src/jpeg.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - jpeg.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -141,6 +141,7 @@ static const float IDCT_K[10] = { void jpeg_decode_PS0(struct hle_t* hle) { jpeg_decode_std(hle, "PS0", RescaleYSubBlock, RescaleUVSubBlock, EmitYUVTileLine); + rsp_break(hle, SP_STATUS_TASKDONE); } /*************************************************************************** @@ -150,6 +151,7 @@ void jpeg_decode_PS0(struct hle_t* hle) void jpeg_decode_PS(struct hle_t* hle) { jpeg_decode_std(hle, "PS", NULL, NULL, EmitRGBATileLine); + rsp_break(hle, SP_STATUS_TASKDONE); } /*************************************************************************** @@ -190,6 +192,7 @@ void jpeg_decode_OB(struct hle_t* hle) address += (2 * 6 * SUBBLOCK_SIZE); } + rsp_break(hle, SP_STATUS_TASKDONE); } @@ -472,7 +475,7 @@ static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int unsigned int i; /* source and destination sublocks cannot overlap */ - assert(abs(dst - src) > SUBBLOCK_SIZE); + assert(labs(dst - src) > SUBBLOCK_SIZE); for (i = 0; i < SUBBLOCK_SIZE; ++i) dst[i] = src[table[i]]; diff --git a/mupen64plus-rsp-hle/src/memory.h b/mupen64plus-rsp-hle/src/memory.h index 2b431fc9..9c851048 100644 --- a/mupen64plus-rsp-hle/src/memory.h +++ b/mupen64plus-rsp-hle/src/memory.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - memory.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -25,13 +25,11 @@ #include #include #include -#include - -#include +#include "common.h" #include "hle_internal.h" -#ifdef MSB_FIRST +#ifdef M64P_BIG_ENDIAN #define S 0 #define S16 0 #define S8 0 @@ -60,47 +58,128 @@ enum { TASK_YIELD_DATA_SIZE = 0xffc }; -static INLINE unsigned int align(unsigned int x, unsigned amount) +static inline unsigned int align(unsigned int x, unsigned amount) { - --amount; - return (x + amount) & ~amount; + --amount; + return (x + amount) & ~amount; } -#define u8(buffer, address) ((uint8_t*)((buffer) + ((address) ^ S8))) -#define u16(buffer, address) ((uint16_t*)((buffer) + ((address) ^ S16))) -#define u32(buffer, address) ((uint32_t*)((buffer) + (address))) +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); - -#define load_u32(dst, buffer, address, count) memcpy((dst), u32((buffer), (address)), (count) * sizeof(uint32_t)) - +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); -#define store_u32(buffer, address, src, count) memcpy(u32((buffer), (address)), (src), (count) * sizeof(uint32_t)) /* convenient functions for DMEM access */ -#define dmem_u8(hle, address) (u8((hle)->dmem, (address) & 0xFFF) -#define dmem_u16(hle, address) (u16((hle)->dmem, (address) & 0xfff); -#define dmem_u32(hle, address) (u32((hle)->dmem, (address) & 0xfff)) -#define dmem_load_u8(hle, dst, address, count) load_u8((dst), (hle)->dmem, (address) & 0xfff, (count)) -#define dmem_load_u16(hle, dst, address, count) load_u16((dst), (hle)->dmem, (address) & 0xfff, (count)) -#define dmem_load_u32(hle, dst, address, count) load_u32((dst), (hle)->dmem, (address) & 0xfff, (count)) -#define dmem_store_u16(hle, src, address, count) store_u16((hle)->dmem, (address) & 0xfff, (src), (count)) -#define dmem_store_u32(hle, src, address, count) store_u32((hle)->dmem, (address) & 0xfff, (src), (count)) +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 */ -#define dram_u8(hle, address) (u8((hle)->dram, (address) & 0xffffff)) -#define dram_u16(hle, address) (u16((hle)->dram, (address) & 0xffffff)) -#define dram_u32(hle, address) (u32((hle)->dram, (address) & 0xffffff)) +static inline uint8_t* dram_u8(struct hle_t* hle, uint32_t address) +{ + return u8(hle->dram, address & 0xffffff); +} -#define dram_load_u8(hle, dst, address, count) load_u8((dst), (hle)->dram, (address) & 0xffffff, (count)) -#define dram_load_u16(hle, dst, address, count) load_u16((dst), (hle)->dram, (address) & 0xffffff, (count)) -#define dram_load_u32(hle, dst, address, count) load_u32((dst), (hle)->dram, (address) & 0xffffff, (count)) -#define dram_store_u8(hle, src, address, count) store_u8((hle)->dram, (address) & 0xffffff, (src), (count)) -#define dram_store_u16(hle, src, address, count) store_u16((hle)->dram, (address) & 0xffffff, (src), (count)) -#define dram_store_u32(hle, src, address, count) store_u32((hle)->dram, (address) & 0xffffff, (src), (count)) +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/mupen64plus-rsp-hle/src/mp3.c b/mupen64plus-rsp-hle/src/mp3.c index fa182eb1..4e8ea14a 100644 --- a/mupen64plus-rsp-hle/src/mp3.c +++ b/mupen64plus-rsp-hle/src/mp3.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - mp3.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2002 Hacktarux * @@ -21,8 +21,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include #include +#include #include "arithmetics.h" #include "hle_internal.h" @@ -205,6 +205,7 @@ static void MP3AB0(int32_t* v) 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); */ @@ -226,32 +227,29 @@ void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address) /* This must be a header byte or whatnot */ readPtr += 8; - for (cnt = 0; cnt < 0x480; cnt += 0x180) - { - uint32_t inPtr, outPtr; - - /* 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; + 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; } } @@ -282,6 +280,7 @@ static void InnerLoop(struct hle_t* hle, 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)); @@ -662,25 +661,24 @@ static void InnerLoop(struct hle_t* hle, hi0 = (int)hi0 >> 0x10; hi1 = (int)hi1 >> 0x10; - for (i = 0; i < 8; i++) - { - /* v0 */ - int32_t vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0); - *(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x40)^S16)) = clamp_s16(vt); + 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); + /* 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); + /* 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); + /* 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; + tmp += 2; } } diff --git a/mupen64plus-rsp-hle/src/musyx.c b/mupen64plus-rsp-hle/src/musyx.c index 6c0b67f3..d5a630a0 100644 --- a/mupen64plus-rsp-hle/src/musyx.c +++ b/mupen64plus-rsp-hle/src/musyx.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - musyx.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2013 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -19,15 +19,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include +#include #include #include -#include -#include - -#include "common.h" #include "arithmetics.h" #include "audio.h" +#include "common.h" #include "hle_external.h" #include "hle_internal.h" #include "memory.h" @@ -175,6 +174,7 @@ static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subfra 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); @@ -256,6 +256,8 @@ void musyx_v1_task(struct hle_t* hle) 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); + + rsp_break(hle, SP_STATUS_TASKDONE); } /************************************************************************** @@ -333,6 +335,8 @@ void musyx_v2_task(struct hle_t* hle) sfd_ptr += SFD2_VOICES + MAX_VOICES * VOICE_SIZE; } + + rsp_break(hle, SP_STATUS_TASKDONE); } @@ -375,31 +379,27 @@ static void update_base_vol(struct hle_t* hle, int32_t *base_vol, 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; + 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); - } + 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; + 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); - } + for(k = 0; k < 4; ++k) + base_vol[k] += (int16_t)*dram_u16(hle, ptr_24 + k * 2); + } } /* apply 3% decay */ @@ -448,10 +448,10 @@ static void init_subframes_v2(musyx_t *musyx) 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]; + for (i = 0; i < SUBFRAME_SIZE; ++i) { + + for(k = 0; k < 4; ++k) + *(subframes[k]++) = values[k]; } } @@ -460,45 +460,40 @@ 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 - { - unsigned i = 0; + 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; - /* 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); - 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); - 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); - /* 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; - /* 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; - } + /* next voice */ + ++i; + voice_ptr += VOICE_SIZE; + } } return output_ptr; @@ -506,25 +501,27 @@ static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx, 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); + 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; + size_t count1 = size1; + size_t count2 = size2; - HleVerboseMessage(hle->user_defined, - "dma_cat: %08x %08x %04x %04x", - ptr1, - ptr2, - size1, - size2); + HleVerboseMessage(hle->user_defined, + "dma_cat: %08x %08x %04x %04x", + ptr1, + ptr2, + size1, + size2); - dram_load_u8(hle, dst, ptr1, count1); + dram_load_u8(hle, dst, ptr1, count1); - if (size2 != 0) - dram_load_u8(hle, dst + count1, ptr2, count2); + 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) @@ -546,63 +543,65 @@ static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr) dram_load_u16(hle, dst, ptr1, count1); - if (size2 != 0) - dram_load_u16(hle, dst + count1, ptr2, count2); + 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); + 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); - HleVerboseMessage(hle->user_defined, "Format: PCM16"); + unsigned count = align(u16_40 + u8_3e, 4); - *segbase = SAMPLE_BUFFER_SIZE - count; - *offset = u8_3e; + HleVerboseMessage(hle->user_defined, "Format: PCM16"); - dma_cat16(hle, (uint16_t *)samples + *segbase, voice_ptr + VOICE_CATSRC_0); + *segbase = SAMPLE_BUFFER_SIZE - count; + *offset = u8_3e; - if (u16_42 != 0) - dma_cat16(hle, (uint16_t *)samples, voice_ptr + VOICE_CATSRC_1); + 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]; + /* 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; + 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, "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); + 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; + count = u8_3c << 5; - *segbase = SAMPLE_BUFFER_SIZE - count; - *offset = u8_3e & 0x1f; + *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); + 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) - return; - - dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_1); - adpcm_decode_frames(hle, samples, buffer, adpcm_table, u8_3d, u8_3f); + 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, @@ -610,381 +609,380 @@ static void adpcm_decode_frames(struct hle_t* hle, const int16_t *table, uint8_t count, uint8_t skip_samples) { - unsigned i; - int16_t frame[32]; - const uint8_t *nibbles = src + 8; - bool jump_gap = false; + 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); + HleVerboseMessage(hle->user_defined, + "ADPCM decode: count=%d, skip=%d", + count, skip_samples); - if (skip_samples >= 32) - { - jump_gap = true; - nibbles += 16; - src += 4; - } + 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); + for (i = 0; i < count; ++i) { + uint8_t c2 = nibbles[0]; - adpcm_predict_frame(frame, src, nibbles, rshift); + const int16_t *book = (c2 & 0xf0) + table; + unsigned int rshift = (c2 & 0x0f); - 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); + adpcm_predict_frame(frame, src, nibbles, rshift); - if (jump_gap) - { - nibbles += 8; - src += 32; - } + 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); - jump_gap = !jump_gap; - nibbles += 16; - src += 4; - dst += 32; - } + 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) + const uint8_t *nibbles, + unsigned int rshift) { - unsigned int i; + unsigned int i; - *(dst++) = (src[0] << 8) | src[1]; - *(dst++) = (src[2] << 8) | src[3]; + *(dst++) = (src[0] << 8) | src[1]; + *(dst++) = (src[2] << 8) | src[3]; - for (i = 1; i < 16; ++i) - { - uint8_t byte = nibbles[i]; + 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); - } + *(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) + uint32_t voice_ptr, const int16_t *samples, + unsigned segbase, unsigned offset, uint32_t last_sample_ptr) { - int i, k; - int32_t v4_env[4]; - int32_t v4_env_step[4]; - int16_t *v4_dst[4]; - int16_t v4[4]; + 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 */ + /* 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 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); + 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); + /* 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; - 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); + uint32_t pitch_accu = pitch_q16; + uint32_t pitch_step = pitch_shift << 4; - v4_dst[0] = musyx->left; - v4_dst[1] = musyx->right; - v4_dst[2] = musyx->cc0; - v4_dst[3] = musyx->e50; + int32_t v4_env[4]; + int32_t v4_env_step[4]; + int16_t *v4_dst[4]; + int16_t v4[4]; - 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]); + 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); - for (i = 0; i < SUBFRAME_SIZE; ++i) - { - int dist; - int16_t v; - /* update sample and lut pointers and then pitch_accu */ - const int16_t *lut = (RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8)); + v4_dst[0] = musyx->left; + v4_dst[1] = musyx->right; + v4_dst[2] = musyx->cc0; + v4_dst[3] = musyx->e50; - sample += (pitch_accu >> 16); - pitch_accu &= 0xffff; - pitch_accu += pitch_step; + 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]); - /* handle end/restart points */ - dist = sample - sample_end; - if (dist >= 0) - sample = sample_restart + dist; + 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; - /* apply resample filter */ - v = clamp_s16(dot4(sample, lut)); + sample += (pitch_accu >> 16); + pitch_accu &= 0xffff; + pitch_accu += pitch_step; - 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])); + /* handle end/restart points */ + dist = sample - sample_end; + if (dist >= 0) + sample = sample_restart + dist; - /* update envelopes and dst pointers */ - ++(v4_dst[k]); - v4_env[k] += v4_env_step[k]; - } - } + /* apply resample filter */ + v = clamp_s16(dot4(sample, lut)); - /* save last resampled sample */ - dram_store_u16(hle, (uint16_t *)v4, last_sample_ptr, 4); + 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])); - HleVerboseMessage(hle->user_defined, - "last_sample = %04x %04x %04x %04x", - v4[0], v4[1], v4[2], v4[3]); + /* 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) { - uint32_t cbuffer_ptr; - uint32_t cbuffer_length; - uint16_t tap_count; - int16_t fir4_hgain; - uint16_t sfx_gains[2]; - unsigned int i; + unsigned int i; - int16_t buffer[SUBFRAME_SIZE + 4]; - uint32_t tap_delays[8]; - int16_t tap_gains[8]; - int16_t fir4_hcoeffs[4]; + int16_t buffer[SUBFRAME_SIZE + 4]; + int16_t *subframe = buffer + 4; - int16_t delayed[SUBFRAME_SIZE]; + uint32_t tap_delays[8]; + int16_t tap_gains[8]; + int16_t fir4_hcoeffs[4]; - int16_t *subframe = buffer + 4; - const uint32_t pos = idx * SUBFRAME_SIZE; + int16_t delayed[SUBFRAME_SIZE]; + int dpos, dlength; - HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx); + const uint32_t pos = idx * SUBFRAME_SIZE; - if (sfx_ptr == 0) - return; + uint32_t cbuffer_ptr; + uint32_t cbuffer_length; + uint16_t tap_count; + int16_t fir4_hgain; + uint16_t sfx_gains[2]; - /* load sfx parameters */ - cbuffer_ptr = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_PTR); - cbuffer_length = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_LENGTH); + HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx); - tap_count = *dram_u16(hle, sfx_ptr + SFX_TAP_COUNT); + if (sfx_ptr == 0) + return; - 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); + /* load sfx parameters */ + cbuffer_ptr = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_PTR); + cbuffer_length = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_LENGTH); - fir4_hgain = *dram_u16(hle, sfx_ptr + SFX_FIR4_HGAIN); - dram_load_u16(hle, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4); + tap_count = *dram_u16(hle, sfx_ptr + SFX_TAP_COUNT); - sfx_gains[0] = *dram_u16(hle, sfx_ptr + SFX_U16_3C); - sfx_gains[1] = *dram_u16(hle, sfx_ptr + SFX_U16_3E); + 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); - HleVerboseMessage(hle->user_defined, - "cbuffer: ptr=%08x length=%x", cbuffer_ptr, - cbuffer_length); + fir4_hgain = *dram_u16(hle, sfx_ptr + SFX_FIR4_HGAIN); + dram_load_u16(hle, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4); - 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]); + 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, - "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, + "cbuffer: ptr=%08x length=%x", cbuffer_ptr, + cbuffer_length); - HleVerboseMessage(hle->user_defined, "sfx_gains=%04x %04x", sfx_gains[0], sfx_gains[1]); + 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]); - /* mix up to 8 delayed subframes */ - memset(subframe, 0, SUBFRAME_SIZE * sizeof(subframe[0])); - for (i = 0; i < tap_count; ++i) - { - int dlength; - int dpos = pos - tap_delays[i]; - if (dpos <= 0) - dpos += cbuffer_length; - dlength = SUBFRAME_SIZE; + 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]); - 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); - } + HleVerboseMessage(hle->user_defined, "sfx_gains=%04x %04x", sfx_gains[0], sfx_gains[1]); - dram_load_u16(hle, (uint16_t *)delayed, cbuffer_ptr + dpos * 2, dlength); + /* mix up to 8 delayed subframes */ + memset(subframe, 0, SUBFRAME_SIZE * sizeof(subframe[0])); + for (i = 0; i < tap_count; ++i) { - mix_subframes(subframe, delayed, tap_gains[i]); - } + dpos = pos - tap_delays[i]; + if (dpos <= 0) + dpos += cbuffer_length; + dlength = SUBFRAME_SIZE; - /* add resulting subframe to main subframes */ - mix_sfx_with_main_subframes(musyx, subframe, sfx_gains); + 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); + } - /* 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); + 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; + 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); - } + 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; + 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; + 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); - } + 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); + } } -#define mix_samples(y, x, hgain) (clamp_s16(*(y) + (((x) * (hgain) + 0x4000) >> 15))) +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) - y[i] = mix_samples(&y[i], x[i], hgain); + 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]; + 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; + 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); - } + 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 = clamp_s16(musyx->base_vol[0]); - int16_t base_right = clamp_s16(musyx->base_vol[1]); - int16_t *left = musyx->left; - int16_t *right = musyx->right; - uint32_t *dst = dram_u32(hle, output_ptr); + size_t i; -#ifndef NDEBUG - HleVerboseMessage(hle->user_defined, "interleave: %08x", output_ptr); -#endif + int16_t base_left; + int16_t base_right; - for (i = 0; i < SUBFRAME_SIZE; ++i) - { - uint16_t l = clamp_s16(*(left++) + base_left); - uint16_t r = clamp_s16(*(right++) + base_right); + int16_t *left; + int16_t *right; + uint32_t *dst; - *(dst++) = (l << 16) | r; - } + 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) + 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; + unsigned i, k; + int16_t subframe[SUBFRAME_SIZE]; + uint32_t *dst; + uint16_t mask; -#ifndef NDEBUG - HleVerboseMessage(hle->user_defined, - "mask_16=%04x ptr_18=%08x ptr_1c=%08x output_ptr=%08x", - mask_16, ptr_18, ptr_1c, output_ptr); -#endif + 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])); + /* 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(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; + 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; + if ((mask_16 & mask) == 0) + continue; - address = *dram_u32(hle, ptr_18); - hgain = *dram_u16(hle, ptr_18 + 4); + address = *dram_u32(hle, ptr_18); + hgain = *dram_u16(hle, ptr_18 + 4); - for(i = 0; i < SUBFRAME_SIZE; ++i, address += 2) - { - musyx->left[i] = mix_samples(&musyx->left[i], *dram_u16(hle, address), hgain); - musyx->right[i] = mix_samples(&musyx->right[i], *dram_u16(hle, address + 2*SUBFRAME_SIZE), hgain); - subframe[i] = mix_samples(&subframe[i], *dram_u16(hle, address + 4*SUBFRAME_SIZE), hgain); - } - } + 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); + /* 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; + } - 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); + /* writeback subframe @ptr_1c */ + dram_store_u16(hle, (uint16_t*)subframe, ptr_1c, SUBFRAME_SIZE); } diff --git a/mupen64plus-rsp-hle/src/re2.c b/mupen64plus-rsp-hle/src/re2.c index 5a2775bd..8ae17880 100644 --- a/mupen64plus-rsp-hle/src/re2.c +++ b/mupen64plus-rsp-hle/src/re2.c @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - re2.c * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Gilles Siberlin * * * * This program is free software; you can redistribute it and/or modify * @@ -27,8 +27,10 @@ #include "hle_internal.h" #include "memory.h" +#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255)) + /************************************************************************** - * Resident evil 2 ucode + * Resident evil 2 ucodes **************************************************************************/ void resize_bilinear_task(struct hle_t* hle) { @@ -94,4 +96,129 @@ void resize_bilinear_task(struct hle_t* hle) } y += y_ratio; } + + rsp_break(hle, SP_STATUS_TASKDONE); +} + +static uint32_t YCbCr_to_RGBA(uint8_t Y, uint8_t Cb, uint8_t Cr) +{ + int r, g, b; + + r = (int)(((double)Y * 0.582199097) + (0.701004028 * (double)(Cr - 128))); + g = (int)(((double)Y * 0.582199097) - (0.357070923 * (double)(Cr - 128)) - (0.172073364 * (double)(Cb - 128))); + b = (int)(((double)Y * 0.582199097) + (0.886001587 * (double)(Cb - 128))); + + r = SATURATE8(r); + g = SATURATE8(g); + b = SATURATE8(b); + + return (r << 24) | (g << 16) | (b << 8) | 0; +} + +void decode_video_frame_task(struct hle_t* hle) +{ + int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA); + + int pLuminance = *dram_u32(hle, data_ptr); + int pCb = *dram_u32(hle, data_ptr + 4); + int pCr = *dram_u32(hle, data_ptr + 8); + int pDestination = *dram_u32(hle, data_ptr + 12); + int nMovieWidth = *dram_u32(hle, data_ptr + 16); + int nMovieHeight = *dram_u32(hle, data_ptr + 20); +#if 0 /* unused, but keep it for documentation purpose */ + int nRowsPerDMEM = *dram_u32(hle, data_ptr + 24); + int nDMEMPerFrame = *dram_u32(hle, data_ptr + 28); + int nLengthSkipCount = *dram_u32(hle, data_ptr + 32); +#endif + int nScreenDMAIncrement = *dram_u32(hle, data_ptr + 36); + + int i, j; + uint8_t Y, Cb, Cr; + uint32_t pixel; + int pY_1st_row, pY_2nd_row, pDest_1st_row, pDest_2nd_row; + + for (i = 0; i < nMovieHeight; i += 2) + { + pY_1st_row = pLuminance; + pY_2nd_row = pLuminance + nMovieWidth; + pDest_1st_row = pDestination; + pDest_2nd_row = pDestination + (nScreenDMAIncrement >> 1); + + for (j = 0; j < nMovieWidth; j += 2) + { + dram_load_u8(hle, (uint8_t*)&Cb, pCb++, 1); + dram_load_u8(hle, (uint8_t*)&Cr, pCr++, 1); + + /*1st row*/ + dram_load_u8(hle, (uint8_t*)&Y, pY_1st_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + dram_store_u32(hle, &pixel, pDest_1st_row, 1); + pDest_1st_row += 4; + + dram_load_u8(hle, (uint8_t*)&Y, pY_1st_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + dram_store_u32(hle, &pixel, pDest_1st_row, 1); + pDest_1st_row += 4; + + /*2nd row*/ + dram_load_u8(hle, (uint8_t*)&Y, pY_2nd_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + dram_store_u32(hle, &pixel, pDest_2nd_row, 1); + pDest_2nd_row += 4; + + dram_load_u8(hle, (uint8_t*)&Y, pY_2nd_row++, 1); + pixel = YCbCr_to_RGBA(Y, Cb, Cr); + dram_store_u32(hle, &pixel, pDest_2nd_row, 1); + pDest_2nd_row += 4; + } + + pLuminance += (nMovieWidth << 1); + pDestination += nScreenDMAIncrement; + } + + rsp_break(hle, SP_STATUS_TASKDONE); +} + +void fill_video_double_buffer_task(struct hle_t* hle) +{ + int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA); + + int pSrc = *dram_u32(hle, data_ptr); + int pDest = *dram_u32(hle, data_ptr + 0x4); + int width = *dram_u32(hle, data_ptr + 0x8) >> 1; + int height = *dram_u32(hle, data_ptr + 0x10) << 1; + int stride = *dram_u32(hle, data_ptr + 0x1c) >> 1; + + assert((*dram_u32(hle, data_ptr + 0x28) >> 16) == 0x8000); + +#if 0 /* unused, but keep it for documentation purpose */ + int arg3 = *dram_u32(hle, data_ptr + 0xc); + int arg5 = *dram_u32(hle, data_ptr + 0x14); + int arg6 = *dram_u32(hle, data_ptr + 0x18); +#endif + + int i, j; + int r, g, b; + uint32_t pixel, pixel1, pixel2; + + for(i = 0; i < height; i++) + { + for(j = 0; j < width; j=j+4) + { + pixel1 = *dram_u32(hle, pSrc+j); + pixel2 = *dram_u32(hle, pDest+j); + + r = (((pixel1 >> 24) & 0xff) + ((pixel2 >> 24) & 0xff)) >> 1; + g = (((pixel1 >> 16) & 0xff) + ((pixel2 >> 16) & 0xff)) >> 1; + b = (((pixel1 >> 8) & 0xff) + ((pixel2 >> 8) & 0xff)) >> 1; + + pixel = (r << 24) | (g << 16) | (b << 8) | 0; + + dram_store_u32(hle, &pixel, pDest+j, 1); + } + pSrc += stride; + pDest += stride; + } + + rsp_break(hle, SP_STATUS_TASKDONE); } diff --git a/mupen64plus-rsp-hle/src/ucodes.h b/mupen64plus-rsp-hle/src/ucodes.h index 86ea515f..8d12bfb1 100644 --- a/mupen64plus-rsp-hle/src/ucodes.h +++ b/mupen64plus-rsp-hle/src/ucodes.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-rsp-hle - ucodes.h * - * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * @@ -24,8 +24,23 @@ #include +#define CACHED_UCODES_MAX_SIZE 16 + struct hle_t; +typedef void(*ucode_func_t)(struct hle_t* hle); + +struct ucode_info_t { + uint32_t uc_start; + uint32_t uc_dstart; + uint16_t uc_dsize; + ucode_func_t uc_pfunc; +}; + +struct cached_ucodes_t { + struct ucode_info_t infos[CACHED_UCODES_MAX_SIZE]; + int count; +}; /* cic_x105 ucode */ void cicx105_ucode(struct hle_t* hle); @@ -126,7 +141,8 @@ 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); - +void alist_process_nead_mats(struct hle_t* hle); +void alist_process_nead_efz (struct hle_t* hle); /* mp3 ucode */ void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address); @@ -144,6 +160,12 @@ void jpeg_decode_OB(struct hle_t* hle); /* Resident evil 2 ucode */ void resize_bilinear_task(struct hle_t* hle); +void decode_video_frame_task(struct hle_t* hle); +void fill_video_double_buffer_task(struct hle_t* hle); + +/* hvqm2 ucode */ +void hvqm2_decode_sp1_task(struct hle_t* hle); +void hvqm2_decode_sp2_task(struct hle_t* hle); #endif