mirror of
https://github.com/libretro/parallel-n64.git
synced 2024-11-23 08:09:50 +00:00
Update to most recent HLE RSP.
This commit is contained in:
parent
b804ab1a19
commit
64c2a5023d
@ -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
|
||||
|
@ -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 --;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 *
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}*/
|
||||
}
|
||||
|
354
mupen64plus-rsp-hle/src/hvqm.c
Normal file
354
mupen64plus-rsp-hle/src/hvqm.c
Normal 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);
|
||||
}
|
@ -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]];
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user