Update to most recent HLE RSP.

This commit is contained in:
mudlord 2022-05-07 16:49:40 +10:00
parent b804ab1a19
commit 64c2a5023d
24 changed files with 2918 additions and 1972 deletions

View File

@ -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

View File

@ -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 <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <boolean.h>
#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;
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);
uint32_t w1, w2;
unsigned int acmd;
const uint32_t *alist = dram_u32(hle, *dmem_u32(hle, TASK_DATA_PTR));
const uint32_t *const alist_end = alist + (*dmem_u32(hle, TASK_DATA_SIZE) >> 2);
while (alist != alist_end)
{
uint32_t w1 = *(alist++);
uint32_t w2 = *(alist++);
uint32_t acmd = (w1 >> 24) & 0x7f;
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,8 +172,7 @@ 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)
{
while (count != 0) {
*alist_u8(hle, dmemo++) = *alist_u8(hle, dmemi++);
--count;
}
@ -157,8 +180,7 @@ void alist_move(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t coun
void alist_copy_every_other_sample(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count)
{
while (count)
{
while (count != 0) {
*alist_s16(hle, dmemo) = *alist_s16(hle, dmemi);
dmemo += 2;
dmemi += 4;
@ -172,8 +194,7 @@ void alist_repeat64(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint8_t c
memcpy(buffer, hle->alist_buffer + dmemi, 128);
while(count)
{
while(count != 0) {
memcpy(hle->alist_buffer + dmemo, buffer, 128);
dmemo += 128;
--count;
@ -210,14 +231,13 @@ void alist_interleave(struct hle_t* hle, uint16_t dmemo, uint16_t left, uint16_t
count >>= 2;
while(count)
{
while(count != 0) {
uint16_t l1 = *(srcL++);
uint16_t l2 = *(srcL++);
uint16_t r1 = *(srcR++);
uint16_t r2 = *(srcR++);
#ifdef MSB_FIRST
#if M64P_BIG_ENDIAN
*(dst++) = l1;
*(dst++) = r1;
*(dst++) = l2;
@ -246,10 +266,6 @@ void alist_envmix_exp(
const int32_t *rate,
uint32_t address)
{
struct ramp_t ramps[2];
int32_t exp_seq[2];
int32_t exp_rates[2];
int x, y;
size_t n = (aux) ? 4 : 2;
const int16_t* const in = (int16_t*)(hle->alist_buffer + dmemi);
@ -257,11 +273,17 @@ void alist_envmix_exp(
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)
{
struct ramp_t ramps[2];
int32_t exp_seq[2];
int32_t exp_rates[2];
uint32_t ptr = 0;
int x, y;
short save_buffer[40];
memcpy((uint8_t *)save_buffer, (hle->dram + address), sizeof(save_buffer));
if (init) {
ramps[0].value = (vol[0] << 16);
ramps[1].value = (vol[1] << 16);
ramps[0].target = (target[0] << 16);
@ -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,22 +309,21 @@ 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)
for (y = 0; y < count; y += 16) {
if (ramps[0].step != 0)
{
exp_seq[0] = ((int64_t)exp_seq[0]*(int64_t)exp_rates[0]) >> 16;
ramps[0].step = (exp_seq[0] - ramps[0].value) >> 3;
}
if (ramps[1].step)
if (ramps[1].step != 0)
{
exp_seq[1] = ((int64_t)exp_seq[1]*(int64_t)exp_rates[1]) >> 16;
ramps[1].step = (exp_seq[1] - ramps[1].value) >> 3;
}
for (x = 0; x < 8; ++x)
{
for (x = 0; x < 8; ++x) {
int16_t gains[4];
int16_t* buffers[4];
int16_t l_vol = ramp_step(&ramps[0]);
@ -335,6 +354,7 @@ void alist_envmix_exp(
*(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,7 +371,6 @@ void alist_envmix_ge(
uint32_t address)
{
unsigned k;
struct ramp_t ramps[2];
size_t n = (aux) ? 4 : 2;
const int16_t* const in = (int16_t*)(hle->alist_buffer + dmemi);
@ -359,19 +378,19 @@ void alist_envmix_ge(
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);
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,8 +404,7 @@ void alist_envmix_ge(
}
count >>= 1;
for (k = 0; k < count; ++k)
{
for (k = 0; k < count; ++k) {
int16_t gains[4];
int16_t* buffers[4];
int16_t l_vol = ramp_step(&ramps[0]);
@ -411,10 +429,11 @@ void alist_envmix_ge(
*(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 + 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 */
@ -482,12 +500,13 @@ void alist_envmix_lin(
*(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 */
*(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,12 +534,9 @@ void alist_envmix_nead(
if (swap_wet_LR)
swap(&wl, &wr);
while (count)
{
while (count != 0) {
size_t i;
for(i = 0; i < 8; ++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];
@ -553,9 +569,8 @@ void alist_mix(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count
count >>= 1;
while(count)
{
*dst = sample_mix(dst, *src, gain);
while(count != 0) {
sample_mix(dst, *src, gain);
++dst;
++src;
@ -569,8 +584,7 @@ void alist_multQ44(struct hle_t* hle, uint16_t dmem, uint16_t count, int8_t gain
count >>= 1;
while(count)
{
while(count != 0) {
*dst = clamp_s16(*dst * gain >> 4);
++dst;
@ -585,8 +599,7 @@ void alist_add(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count
count >>= 1;
while(count)
{
while(count != 0) {
*dst = clamp_s16(*dst + *src);
++dst;
@ -605,8 +618,7 @@ static void alist_resample_reset(struct hle_t* hle, uint16_t pos, uint32_t* pitc
*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);
@ -638,23 +649,21 @@ void alist_resample(
uint32_t address)
{
uint32_t pitch_accu;
uint16_t ipos = (dmemi >> 1) - 4;
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 (init)
alist_resample_reset(hle, ipos, &pitch_accu);
else
alist_resample_load(hle, address, ipos, &pitch_accu);
while (count)
{
while (count != 0) {
const int16_t* lut = RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8);
*sample(hle, opos++) = clamp_s16( (
@ -684,8 +693,8 @@ void alist_resample_zoh(
uint16_t opos = dmemo >> 1;
count >>= 1;
while(count)
{
while(count != 0) {
*sample(hle, opos++) = *sample(hle, ipos);
pitch_accu += pitch;
@ -704,8 +713,7 @@ static unsigned int adpcm_predict_frame_4bits(struct hle_t* hle,
unsigned int i;
unsigned int rshift = (scale < 12) ? 12 - scale : 0;
for(i = 0; i < 8; ++i)
{
for(i = 0; i < 8; ++i) {
uint8_t byte = *alist_u8(hle, dmemi++);
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
@ -721,8 +729,7 @@ static unsigned int adpcm_predict_frame_2bits(struct hle_t* hle,
unsigned int i;
unsigned int rshift = (scale < 14) ? 14 - scale : 0;
for(i = 0; i < 4; ++i)
{
for(i = 0; i < 4; ++i) {
uint8_t byte = *alist_u8(hle, dmemi++);
*(dst++) = adpcm_predict_sample(byte, 0xc0, 8, rshift);
@ -748,30 +755,22 @@ void alist_adpcm(
{
int16_t last_frame[16];
size_t i;
adpcm_predict_frame_t predict_frame;
if (!hle || !codebook)
return;
predict_frame = (two_bit_per_sample)
adpcm_predict_frame_t predict_frame = (two_bit_per_sample)
? adpcm_predict_frame_2bits
: adpcm_predict_frame_4bits;
assert((count & 0x1f) == 0);
if (init)
{
for (i = 0; i < 16; i++)
last_frame[i] = 0;
}
memset(last_frame, 0, 16*sizeof(last_frame[0]));
else
dram_load_u16(hle, (uint16_t*)last_frame, (loop) ? loop_address : last_frame_address, 16);
for(i = 0; i < 16; ++i, dmemo += 2)
*alist_s16(hle, dmemo) = last_frame[i];
while (count)
{
while (count != 0) {
int16_t frame[16];
uint8_t code = *alist_u8(hle, dmemi++);
unsigned char scale = (code & 0xf0) >> 4;
@ -809,14 +808,13 @@ void alist_filter(
int16_t* in1 = (int16_t*)(hle->dram + address);
int16_t* in2 = (int16_t*)(hle->alist_buffer + dmem);
for (x = 0; x < 8; ++x)
{
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)
{
for (x = 0; x < count; x += 16) {
int32_t v[8];
v[1] = in1[0] * lutt6[6];
@ -918,24 +916,27 @@ 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;
unsigned i;
int16_t l1, l2;
int16_t h2_before[8];
count = align(count, 16);
if (!init)
{
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)
{
for(i = 0; i < 8; ++i) {
h2_before[i] = h2[i];
h2[i] = (((int32_t)h2[i] * gain) >> 14);
}
@ -947,10 +948,9 @@ void alist_polef(
for(i = 0; i < 8; ++i, dmemi += 2)
frame[i] = *alist_s16(hle, dmemi);
for(i = 0; i < 8; ++i)
{
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);
accu += h1[i]*l1 + h2_before[i]*l2 + rdot(i, h2, frame);
dst[i^S] = clamp_s16(accu >> 14);
}
@ -959,7 +959,7 @@ void alist_polef(
dst += 8;
count -= 16;
}while(count);
} while (count != 0);
dram_store_u32(hle, (uint32_t*)(dst - 4), address, 2);
}
@ -973,11 +973,13 @@ void alist_iirf(
int16_t* table,
uint32_t address)
{
int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo);
int32_t i, prev;
int16_t frame[8];
int16_t ibuf[4];
uint16_t index = 7;
int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo);
count = align(count, 16);
if(init)
@ -996,30 +998,41 @@ void alist_iirf(
}
prev = vmulf(table[9], frame[6]) * 2;
do
{
for(i = 0; i < 8; ++i)
{
int32_t accu;
ibuf[index&3] = *alist_s16(hle, dmemi);
accu = prev
+ vmulf(table[0], ibuf[index&3])
+ vmulf(table[1], ibuf[(index-1)&3])
+ vmulf(table[0], ibuf[(index-2)&3]);
accu = prev + vmulf(table[0], ibuf[index&3]) + vmulf(table[1], ibuf[(index-1)&3]) + vmulf(table[0], ibuf[(index-2)&3]);
accu += vmulf(table[8], frame[index]) * 2;
prev = vmulf(table[9], frame[index]) * 2;
dst[i^S] = frame[i] = accu;
index = (index+1)&7;
index=(index+1)&7;
dmemi += 2;
}
dst += 8;
count -= 0x10;
} while (count > 0);
dram_store_u16(hle, (uint16_t*)&frame[6], address + 4, 4);
dram_store_u16(hle, (uint16_t*)&ibuf[(index-2)&3], address+8, 2);
dram_store_u16(hle, (uint16_t*)&ibuf[(index-1)&3], address+10, 2);
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 --;
}
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <boolean.h>
#include <stdint.h>
struct hle_t;
@ -149,6 +149,14 @@ void alist_iirf(
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
*/

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <boolean.h>
#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))
@ -67,7 +59,9 @@ static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
uint16_t dmem = w1 + DMEM_BASE;
uint16_t count = w2 & 0xfff;
if (count != 0)
if (count == 0)
return;
alist_clear(hle, dmem, align(count, 16));
}
@ -117,7 +111,7 @@ static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
alist_resample(
hle,
flags & 0x1,
flags & A_INIT,
flags & 0x2,
hle->alist_audio.out,
hle->alist_audio.in,
@ -128,35 +122,26 @@ static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
unsigned lr;
uint8_t flags = (w1 >> 16);
if (!hle)
return;
if (flags & A_AUX)
{
if (flags & A_AUX) {
hle->alist_audio.dry = w1;
hle->alist_audio.wet = w2;
return;
}
lr = (flags & A_LEFT) ? 0 : 1;
else {
unsigned lr = (flags & A_LEFT) ? 0 : 1;
if (flags & A_VOL)
hle->alist_audio.vol[lr] = w1;
else
{
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);
}
@ -165,13 +150,10 @@ 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);
if (!hle)
return;
alist_adpcm(
hle,
flags & 0x1,
flags & 0x2,
flags & A_INIT,
flags & A_LOOP,
false, /* unsupported in this ucode */
hle->alist_audio.out,
hle->alist_audio.in,
@ -185,7 +167,9 @@ static void LOADBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
uint32_t address = get_address(hle, w2);
if (hle->alist_audio.count != 0)
if (hle->alist_audio.count == 0)
return;
alist_load(hle, hle->alist_audio.in, address, hle->alist_audio.count);
}
@ -193,7 +177,9 @@ static void SAVEBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
uint32_t address = get_address(hle, w2);
if (hle->alist_audio.count != 0)
if (hle->alist_audio.count == 0)
return;
alist_save(hle, hle->alist_audio.out, address, hle->alist_audio.count);
}
@ -201,26 +187,26 @@ 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 dmemo = (w2 >> 16) + DMEM_BASE;
uint16_t count = w2;
if (count == 0)
return;
if (count != 0)
alist_move(hle, dmemo, dmemi, align(count, 16));
}
@ -229,9 +215,6 @@ static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t 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);
}
@ -240,9 +223,10 @@ static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
uint16_t left = (w2 >> 16) + DMEM_BASE;
uint16_t right = w2 + DMEM_BASE;
if (hle->alist_audio.count != 0)
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)
@ -251,7 +235,9 @@ static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
uint16_t dmemi = (w2 >> 16) + DMEM_BASE;
uint16_t dmemo = w2 + DMEM_BASE;
if (hle->alist_audio.count != 0)
if (hle->alist_audio.count == 0)
return;
alist_mix(hle, dmemo, dmemi, align(hle->alist_audio.count, 32), gain);
}
@ -266,7 +252,9 @@ static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
uint16_t gain = w1;
uint32_t address = get_address(hle, w2);
if (hle->alist_audio.count != 0)
if (hle->alist_audio.count == 0)
return;
alist_polef(
hle,
flags & A_INIT,
@ -290,6 +278,7 @@ void alist_process_audio(struct hle_t* hle)
clear_segments(hle);
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_audio_ge(struct hle_t* hle)
@ -303,6 +292,7 @@ void alist_process_audio_ge(struct hle_t* hle)
clear_segments(hle);
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_audio_bc(struct hle_t* hle)
@ -316,4 +306,5 @@ void alist_process_audio_bc(struct hle_t* hle)
clear_segments(hle);
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <boolean.h>
#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,6 +41,7 @@ enum
NAUDIO_WET_RIGHT = 0xe20
};
/* audio commands definition */
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
@ -58,13 +53,11 @@ static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t 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);
@ -85,10 +76,10 @@ static void NAUDIO_14(struct hle_t* hle, uint32_t w1, uint32_t w2)
uint16_t gain = w1;
uint8_t select_main = (w2 >> 24);
uint32_t address = (w2 & 0xffffff);
uint16_t dmem = (select_main == 0) ? NAUDIO_MAIN : NAUDIO_MAIN2;
if (hle->alist_naudio.table[0] == 0 && hle->alist_naudio.table[1] == 0)
{
if (hle->alist_naudio.table[0] == 0 && hle->alist_naudio.table[1] == 0) {
alist_polef(
hle,
flags & A_INIT,
@ -98,9 +89,9 @@ static void NAUDIO_14(struct hle_t* hle, uint32_t w1, uint32_t w2)
gain,
hle->alist_naudio.table,
address);
return;
}
else
{
alist_iirf(
hle,
flags & A_INIT,
@ -109,30 +100,29 @@ static void NAUDIO_14(struct hle_t* hle, uint32_t w1, uint32_t w2)
NAUDIO_COUNT,
hle->alist_naudio.table,
address);
}
}
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
if (flags & 0x4)
{
if (flags & 0x2)
{
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
{
else { /* A_RIGHT */
hle->alist_naudio.target[1] = w1;
hle->alist_naudio.rate[1] = w2;
}
return;
}
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)
@ -144,7 +134,7 @@ static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
alist_envmix_lin(
hle,
flags & 0x1,
flags & A_INIT,
NAUDIO_DRY_LEFT,
NAUDIO_DRY_RIGHT,
NAUDIO_WET_LEFT,
@ -194,14 +184,11 @@ static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
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);
if (!hle)
return;
dram_load_u16(hle, (uint16_t*)hle->alist_naudio.table, address, count >> 1);
}
@ -229,8 +216,8 @@ static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
alist_adpcm(
hle,
flags & 0x1,
flags & 0x2,
flags & A_INIT,
flags & A_LOOP,
false, /* unsuported by this ucode */
dmemo,
dmemi,
@ -250,7 +237,7 @@ static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
alist_resample(
hle,
flags & 0x1,
flags & A_INIT,
false, /* TODO: check which ABI supports it */
dmemo,
dmemi,
@ -276,17 +263,28 @@ static void MP3(struct hle_t* hle, uint32_t w1, uint32_t w2)
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 */
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);
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <boolean.h>
#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
@ -51,14 +51,11 @@ 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);
if (!hle)
return;
dram_load_u16(hle, (uint16_t*)hle->alist_nead.table, address, count >> 1);
}
@ -97,7 +94,9 @@ static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
uint16_t dmem = w1;
uint16_t count = w2 & 0xfff;
if (count != 0)
if (count == 0)
return;
alist_clear(hle, dmem, count);
}
@ -161,12 +160,15 @@ static void RESAMPLE_ZOH(struct hle_t* hle, uint32_t w1, uint32_t w2)
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 dmemo = (w2 >> 16);
uint16_t count = w2;
if (count == 0)
return;
if (count != 0)
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
}
@ -270,7 +272,9 @@ static void INTERLEAVE_MK(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
uint16_t left = (w2 >> 16);
uint16_t right = w2;
if (hle->alist_nead.count != 0)
if (hle->alist_nead.count == 0)
return;
alist_interleave(hle, hle->alist_nead.out, left, right, hle->alist_nead.count);
}
@ -304,24 +308,22 @@ static void HILOGAIN(struct hle_t* hle, uint32_t w1, uint32_t w2)
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);
if (flags > 1)
{
if (flags > 1) {
hle->alist_nead.filter_count = w1;
hle->alist_nead.filter_lut_address[0] = address; /* t6 */
return;
}
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);
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))
{
}
@ -341,7 +343,9 @@ static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
uint16_t gain = w1;
uint32_t address = (w2 & 0xffffff);
if (hle->alist_nead.count != 0)
if (hle->alist_nead.count == 0)
return;
alist_polef(
hle,
flags & A_INIT,
@ -359,7 +363,7 @@ 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,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1_MK, ENVMIXER_MK,
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
@ -368,6 +372,7 @@ void alist_process_nead_mk(struct hle_t* hle)
};
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_sf(struct hle_t* hle)
@ -375,7 +380,7 @@ 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,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
@ -384,6 +389,7 @@ void alist_process_nead_sf(struct hle_t* hle)
};
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_sfj(struct hle_t* hle)
@ -391,7 +397,7 @@ 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,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
@ -400,6 +406,7 @@ void alist_process_nead_sfj(struct hle_t* hle)
};
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_fz(struct hle_t* hle)
@ -407,7 +414,7 @@ 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,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
@ -416,6 +423,7 @@ void alist_process_nead_fz(struct hle_t* hle)
};
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_wrjb(struct hle_t* hle)
@ -423,7 +431,7 @@ 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,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
@ -432,6 +440,7 @@ void alist_process_nead_wrjb(struct hle_t* hle)
};
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_ys(struct hle_t* hle)
@ -439,13 +448,14 @@ 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,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_1080(struct hle_t* hle)
@ -453,13 +463,14 @@ 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,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_oot(struct hle_t* hle)
@ -467,13 +478,14 @@ 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,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mm(struct hle_t* hle)
@ -481,13 +493,14 @@ 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,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mmb(struct hle_t* hle)
@ -495,13 +508,14 @@ 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,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_ac(struct hle_t* hle)
@ -509,11 +523,34 @@ 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,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
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);
}
}

View File

@ -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 <retro_inline.h>
#include <stdint.h>
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,7 +34,7 @@ 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;
}

View File

@ -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 *
@ -96,8 +96,12 @@ int32_t rdot(size_t n, const int16_t *x, const int16_t *y)
{
int32_t accu = 0;
while (n-- != 0)
y += n;
while (n != 0) {
accu += *(x++) * *(--y);
--n;
}
return accu;
}
@ -105,17 +109,19 @@ int32_t rdot(size_t n, const int16_t *x, const int16_t *y)
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 l1 = last_samples[0];
const int16_t l2 = last_samples[1];
for(i = 0; i < count; ++i)
{
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 + i);
accu += book1[i]*l1 + book2[i]*l2 + rdot(i, book2, src);
dst[i] = clamp_s16(accu >> 11);
}
}

View File

@ -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 <stddef.h>
#include <stdint.h>
#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);

View File

@ -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 *
@ -44,11 +44,13 @@ void cicx105_ucode(struct hle_t* hle)
memcpy(hle->imem + 0x120, hle->dram + 0x1e8, 0x1f0);
/* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */
for (i = 0; i < 24; ++i)
{
for (i = 0; i < 24; ++i) {
memcpy(dst, src, 8);
dst += 0xff0;
src += 0x8;
}
rsp_break(hle, 0);
}

View File

@ -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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <boolean.h>
#ifdef ENABLE_TASK_DUMP
#include <stdio.h>
#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))
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);
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 (!try_fast_task_dispatching(hle))
normal_task_dispatching(hle);
rsp_break(hle, SP_STATUS_TASKDONE);
return;
if (info->uc_start == uc_start && info->uc_dstart == uc_dstart && info->uc_dsize == uc_dsize)
{
match = true;
break;
}
info--;
}
non_task_dispatching(hle);
rsp_break(hle, 0);
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;
}
/**
* Try to figure if the RSP was launched using osSpTask* functions
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
*
* Previously, the ucode_size field was used to determine this,
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
*
* Using ucode_boot_size should be more robust in this regard.
**/
static bool is_task(struct hle_t* hle)
{
return (*dmem_u32(hle, TASK_UCODE_BOOT_SIZE) <= 0x1000);
}
static void rsp_break(struct hle_t* hle, unsigned int setbits)
void rsp_break(struct hle_t* hle, unsigned int setbits)
{
*hle->sp_status |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT;
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK))
{
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK)) {
*hle->mi_intr |= MI_INTR_SP;
if (rsp_info.CheckInterrupts)
rsp_info.CheckInterrupts();
HleCheckInterrupts(hle->user_defined);
}
}
static void forward_gfx_task(struct hle_t* hle)
static void send_alist_to_audio_plugin(struct hle_t* hle)
{
if (rsp_info.ProcessDlistList)
rsp_info.ProcessDlistList();
HleProcessAlistList(hle->user_defined);
rsp_break(hle, SP_STATUS_TASKDONE);
}
static bool try_fast_audio_dispatching(struct hle_t* hle)
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)
{
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;
return &alist_process_audio;
case 0x1dc8138c: /* GoldenEye */
alist_process_audio_ge(hle); return true;
return &alist_process_audio_ge;
case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */
alist_process_audio_bc(hle); return true;
return &alist_process_audio_bc;
default:
HleWarnMessage(hle->user_defined, "ABI1 identification regression: v=%08x", v);
}
}
else
{
} else {
v = *dram_u32(hle, ucode_data + 0x10);
switch(v)
{
case 0x11181350: /* MarioKart, WaveRace (E) */
alist_process_nead_mk(hle); return true;
return &alist_process_nead_mk;
case 0x111812e0: /* StarFox (J) */
alist_process_nead_sfj(hle); return true;
return &alist_process_nead_sfj;
case 0x110412ac: /* WaveRace (J RevB) */
alist_process_nead_wrjb(hle); return true;
return &alist_process_nead_wrjb;
case 0x110412cc: /* StarFox/LylatWars (except J) */
alist_process_nead_sf(hle); return true;
return &alist_process_nead_sf;
case 0x1cd01250: /* FZeroX */
alist_process_nead_fz(hle); return true;
return &alist_process_nead_fz;
case 0x1f08122c: /* YoshisStory */
alist_process_nead_ys(hle); return true;
return &alist_process_nead_ys;
case 0x1f38122c: /* 1080° Snowboarding */
alist_process_nead_1080(hle); return true;
return &alist_process_nead_1080;
case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */
alist_process_nead_oot(hle); return true;
return &alist_process_nead_oot;
case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */
alist_process_nead_mm(hle); return true;
return &alist_process_nead_mm;
case 0x109411f8: /* Zelda MM (E Beta) */
alist_process_nead_mmb(hle); return true;
return &alist_process_nead_mmb;
case 0x1eac11b8: /* AnimalCrossing */
alist_process_nead_ac(hle); return true;
return &alist_process_nead_ac;
case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */
musyx_v2_task(hle); return true;
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)
{
/* -- 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;
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, "ABI3 identification regression: v=%08x", v);
}
}
return false;
return NULL;
}
static bool try_fast_task_dispatching(struct hle_t* hle)
static ucode_func_t try_normal_task_detection(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;
unsigned int sum =
sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), min(*dmem_u32(hle, TASK_UCODE_SIZE), 0xf80) >> 1);
if (FORWARD_GFX)
{
forward_gfx_task(hle);
return true;
}
break;
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;
}
return false;
}
static void normal_task_dispatching(struct hle_t* hle)
{
const unsigned int sum =
sum_bytes((void*)dram_u32(hle,
*dmem_u32(hle, TASK_UCODE)),
min(*dmem_u32(hle, TASK_UCODE_SIZE), 0xf80) >> 1);
switch (sum)
{
switch (sum) {
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
case 0x278:
/* Nothing to emulate */
return;
return &task_done;
/* GFX: Twintris [misleading task->type == 0] */
case 0x212ee:
if (FORWARD_GFX)
{
forward_gfx_task(hle);
return;
if (hle->hle_gfx) {
return &send_dlist_to_gfx_plugin;
}
break;
return NULL;
/* JPEG: found in Pokemon Stadium J */
case 0x2c85a:
jpeg_decode_PS0(hle);
return;
return &jpeg_decode_PS0;
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
case 0x2caa6:
jpeg_decode_PS(hle);
return;
return &jpeg_decode_PS;
/* 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;
return &jpeg_decode_OB;
}
HleWarnMessage(hle->user_defined, "unknown OSTask: sum: %x PC:%x", sum, *hle->sp_pc);
/* Resident Evil 2 */
sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 256);
switch (sum) {
case 0x450f:
return &resize_bilinear_task;
case 0x3b44:
return &decode_video_frame_task;
case 0x3d84:
return &fill_video_double_buffer_task;
}
/* 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 non_task_dispatching(struct hle_t* hle)
static ucode_func_t non_task_detection(struct hle_t* hle)
{
const unsigned int sum = sum_bytes(hle->imem, 44);
if (sum == 0x9e2)
{
/* CIC x105 ucode (used during boot of CIC x105 games) */
cicx105_ucode(hle);
return;
return &cicx105_ucode;
}
HleWarnMessage(hle->user_defined, "unknown RSP code: sum: %x PC:%x", sum, *hle->sp_pc);
return &unknown_ucode;
}
static ucode_func_t task_detection(struct hle_t* hle)
{
if (is_task(hle)) {
ucode_func_t uc_pfunc;
uint32_t type = *dmem_u32(hle, TASK_TYPE);
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;
}
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

View File

@ -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 *

View File

@ -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

View File

@ -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

View File

@ -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,8 +26,7 @@
/* Global functions */
void load_u8(uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count)
{
while (count)
{
while (count != 0) {
*(dst++) = *u8(buffer, address);
address += 1;
--count;
@ -36,20 +35,40 @@ void load_u8(uint8_t* dst, const unsigned char* buffer, unsigned address, size_t
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count)
{
while (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)
{
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));
}

View File

@ -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 <stdarg.h>
#include <stdio.h>
#include <string.h>
#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];
l_PluginInit = 1;
if (l_DebugCallback == NULL)
return;
vsprintf(msgbuf, message, args);
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
}
unsigned int hleDoRspCycles(unsigned int Cycles)
/* 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;
}
EXPORT m64p_error CALL hlePluginShutdown(void)
{
if (!l_PluginInit)
hleInitiateRSP(rsp_info, NULL);
return M64ERR_NOT_INIT;
/* reset some local variable */
l_DebugCallback = NULL;
l_DebugCallContext = NULL;
l_PluginInit = 0;
return M64ERR_SUCCESS;
}
EXPORT unsigned int CALL hleDoRspCycles(unsigned int Cycles)
{
hle_execute(&g_hle);
return Cycles;
}
void hleRomClosed(void)
EXPORT void CALL hleInitiateRSP(RSP_INFO Rsp_Info, unsigned int* CycleCount)
{
/* do nothing */
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();
}*/
}

View File

@ -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 <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#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);
}

View File

@ -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]];

View File

@ -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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <retro_inline.h>
#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;
}
#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

View File

@ -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 <string.h>
#include <stdint.h>
#include <string.h>
#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,15 +227,12 @@ 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;
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 -------------------- */
/* --------------- Inner Loop Start -------------------- */
for (cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) {
t6 &= 0xFFE0;
t5 &= 0xFFE0;
@ -248,7 +246,7 @@ void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address)
inPtr += 0x40;
outPtr += 0x40;
}
/* --------------- Inner Loop End -------------------- */
/* --------------- 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,10 +661,9 @@ static void InnerLoop(struct hle_t* hle,
hi0 = (int)hi0 >> 0x10;
hi1 = (int)hi1 >> 0x10;
for (i = 0; i < 8; i++)
{
for (i = 0; i < 8; i++) {
/* v0 */
int32_t vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0);
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x40)^S16)) = clamp_s16(vt);
/* v17 */

View File

@ -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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include <boolean.h>
#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,11 +379,9 @@ 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)
{
if (voice_mask != 0) {
for (i = 0, mask = 1; i < MAX_VOICES;
++i, mask <<= 1, last_sample_ptr += 8)
{
++i, mask <<= 1, last_sample_ptr += 8) {
if ((voice_mask & mask) == 0)
continue;
@ -389,11 +391,9 @@ static void update_base_vol(struct hle_t* hle, int32_t *base_vol,
}
/* optim: skip contributions entirely if mask_15 is empty */
if (mask_15 != 0)
{
if (mask_15 != 0) {
for(i = 0, mask = 1; i < 4;
++i, mask <<= 1, ptr_24 += 8)
{
++i, mask <<= 1, ptr_24 += 8) {
if ((mask_15 & mask) == 0)
continue;
@ -448,8 +448,8 @@ static void init_subframes_v2(musyx_t *musyx)
subframes[2] = musyx->cc0;
subframes[3] = musyx->e50;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
for (i = 0; i < SUBFRAME_SIZE; ++i) {
for(k = 0; k < 4; ++k)
*(subframes[k]++) = values[k];
}
@ -460,20 +460,15 @@ 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)
{
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;
} else {
/* otherwise process voices until a non null output_ptr is encountered */
for (;;)
{
for (;;) {
/* load voice samples (PCM16 or APDCM) */
int16_t samples[SAMPLE_BUFFER_SIZE];
unsigned segbase;
@ -523,7 +518,9 @@ static void dma_cat8(struct hle_t* hle, uint8_t *dst, uint32_t catsrc_ptr)
dram_load_u8(hle, dst, ptr1, count1);
if (size2 != 0)
if (size2 == 0)
return;
dram_load_u8(hle, dst + count1, ptr2, count2);
}
@ -546,13 +543,16 @@ 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)
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);
@ -598,11 +598,10 @@ static void load_samples_ADPCM(struct hle_t* hle, uint32_t voice_ptr, int16_t *s
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;
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,25 +609,24 @@ 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;
unsigned i;
bool jump_gap = false;
HleVerboseMessage(hle->user_defined,
"ADPCM decode: count=%d, skip=%d",
count, skip_samples);
if (skip_samples >= 32)
{
if (skip_samples >= 32) {
jump_gap = true;
nibbles += 16;
src += 4;
}
for (i = 0; i < count; ++i)
{
for (i = 0; i < count; ++i) {
uint8_t c2 = nibbles[0];
const int16_t *book = (c2 & 0xf0) + table;
unsigned int rshift = (c2 & 0x0f);
@ -640,8 +638,7 @@ static void adpcm_decode_frames(struct hle_t* hle,
adpcm_compute_residuals(dst + 16, frame + 16, book, dst + 14, 8);
adpcm_compute_residuals(dst + 24, frame + 24, book, dst + 22, 8);
if (jump_gap)
{
if (jump_gap) {
nibbles += 8;
src += 32;
}
@ -654,15 +651,15 @@ static void adpcm_decode_frames(struct hle_t* hle,
}
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;
*(dst++) = (src[0] << 8) | src[1];
*(dst++) = (src[2] << 8) | src[3];
for (i = 1; i < 16; ++i)
{
for (i = 1; i < 16; ++i) {
uint8_t byte = nibbles[i];
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
@ -675,10 +672,6 @@ static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
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];
/* parse VOICE structure */
const uint16_t pitch_q16 = *dram_u16(hle, voice_ptr + VOICE_PITCH_Q16);
@ -695,9 +688,15 @@ static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
const int16_t *const sample_restart = samples + (restart_point & 0x7fff) +
(((restart_point & 0x8000) != 0) ? 0x000 : segbase);
uint32_t pitch_accu = pitch_q16;
uint32_t pitch_step = pitch_shift << 4;
int32_t v4_env[4];
int32_t v4_env_step[4];
int16_t *v4_dst[4];
int16_t v4[4];
dram_load_u32(hle, (uint32_t *)v4_env, voice_ptr + VOICE_ENV_BEGIN, 4);
dram_load_u32(hle, (uint32_t *)v4_env_step, voice_ptr + VOICE_ENV_STEP, 4);
@ -720,12 +719,11 @@ static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
v4_env[0], v4_env[1], v4_env[2], v4_env[3],
v4_env_step[0], v4_env_step[1], v4_env_step[2], v4_env_step[3]);
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
int dist;
int16_t v;
for (i = 0; i < SUBFRAME_SIZE; ++i) {
/* update sample and lut pointers and then pitch_accu */
const int16_t *lut = (RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8));
int dist;
int16_t v;
sample += (pitch_accu >> 16);
pitch_accu &= 0xffff;
@ -739,8 +737,7 @@ static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
/* apply resample filter */
v = clamp_s16(dot4(sample, lut));
for (k = 0; k < 4; ++k)
{
for (k = 0; k < 4; ++k) {
/* envmix */
int32_t accu = (v * (v4_env[k] >> 16)) >> 15;
v4[k] = clamp_s16(accu);
@ -764,23 +761,26 @@ static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
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;
int16_t buffer[SUBFRAME_SIZE + 4];
int16_t *subframe = buffer + 4;
uint32_t tap_delays[8];
int16_t tap_gains[8];
int16_t fir4_hcoeffs[4];
int16_t delayed[SUBFRAME_SIZE];
int dpos, dlength;
int16_t *subframe = buffer + 4;
const uint32_t pos = idx * SUBFRAME_SIZE;
uint32_t cbuffer_ptr;
uint32_t cbuffer_length;
uint16_t tap_count;
int16_t fir4_hgain;
uint16_t sfx_gains[2];
HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx);
if (sfx_ptr == 0)
@ -824,10 +824,9 @@ static void sfx_stage(struct hle_t* hle, mix_sfx_with_main_subframes_t mix_sfx_w
/* 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];
for (i = 0; i < tap_count; ++i) {
dpos = pos - tap_delays[i];
if (dpos <= 0)
dpos += cbuffer_length;
dlength = SUBFRAME_SIZE;
@ -857,8 +856,7 @@ static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subfra
{
unsigned i;
for (i = 0; i < SUBFRAME_SIZE; ++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);
@ -870,8 +868,7 @@ static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subfra
{
unsigned i;
for (i = 0; i < SUBFRAME_SIZE; ++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;
@ -882,14 +879,17 @@ static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subfra
}
}
#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)
@ -902,8 +902,7 @@ static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t
h[2] = (hgain * hcoeffs[2]) >> 15;
h[3] = (hgain * hcoeffs[3]) >> 15;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
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);
}
@ -912,18 +911,24 @@ static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t
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);
#ifndef NDEBUG
int16_t base_left;
int16_t base_right;
int16_t *left;
int16_t *right;
uint32_t *dst;
HleVerboseMessage(hle->user_defined, "interleave: %08x", output_ptr);
#endif
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
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);
@ -940,24 +945,20 @@ static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
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
/* 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)
{
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)
{
for (k = 0, mask = 1; k < 8; ++k, mask <<= 1, ptr_18 += 8) {
int16_t hgain;
uint32_t address;
@ -967,19 +968,16 @@ static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
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);
for(i = 0; i < SUBFRAME_SIZE; ++i)
{
for(i = 0; i < SUBFRAME_SIZE; ++i) {
uint16_t l = musyx->left[i];
uint16_t r = musyx->right[i];
*(dst++) = (l << 16) | r;

View File

@ -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);
}

View File

@ -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 <stdint.h>
#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