Update to most recent HLE RSP.

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

View File

@ -63,6 +63,7 @@ SOURCES_C += $(RSPDIR)/src/alist.c \
$(RSPDIR)/src/mp3.c \
$(RSPDIR)/src/musyx.c \
$(RSPDIR)/src/re2.c \
$(RSPDIR)/src/hvqm.c \
$(RSPDIR)/src/hle_plugin.c
SOURCES_C += $(CXD4DIR)/rsp.c

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -22,9 +22,9 @@
#ifndef ALIST_INTERNAL_H
#define ALIST_INTERNAL_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <boolean.h>
#include <stdint.h>
struct hle_t;
@ -142,13 +142,21 @@ void alist_polef(
uint32_t address);
void alist_iirf(
struct hle_t* hle,
bool init,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
int16_t* table,
uint32_t address);
struct hle_t* hle,
bool init,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
int16_t* table,
uint32_t address);
void alist_overload(
struct hle_t* hle,
uint16_t dmem,
int16_t count,
int16_t gain,
uint16_t attenuation);
/*
* Audio flags
*/

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist_audio.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -21,41 +21,33 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <boolean.h>
#include "common.h"
#include "alist.h"
#include "common.h"
#include "hle_internal.h"
#include "memory.h"
#include "ucodes.h"
enum
{
DMEM_BASE = 0x5c0
};
enum { DMEM_BASE = 0x5c0 };
/* helper functions */
#define get_address(hle, so) (alist_get_address((hle), (so), (hle)->alist_audio.segments, N_SEGMENTS))
#define set_address(hle, so) alist_set_address((hle), (so), (hle)->alist_audio.segments, N_SEGMENTS)
#define clear_segments(hle) \
(hle)->alist_audio.segments[0] = 0; \
(hle)->alist_audio.segments[1] = 0; \
(hle)->alist_audio.segments[2] = 0; \
(hle)->alist_audio.segments[3] = 0; \
(hle)->alist_audio.segments[4] = 0; \
(hle)->alist_audio.segments[5] = 0; \
(hle)->alist_audio.segments[6] = 0; \
(hle)->alist_audio.segments[7] = 0; \
(hle)->alist_audio.segments[8] = 0; \
(hle)->alist_audio.segments[9] = 0; \
(hle)->alist_audio.segments[10] = 0; \
(hle)->alist_audio.segments[11] = 0; \
(hle)->alist_audio.segments[12] = 0; \
(hle)->alist_audio.segments[13] = 0; \
(hle)->alist_audio.segments[14] = 0; \
(hle)->alist_audio.segments[15] = 0
static uint32_t get_address(struct hle_t* hle, uint32_t so)
{
return alist_get_address(hle, so, hle->alist_audio.segments, N_SEGMENTS);
}
static void set_address(struct hle_t* hle, uint32_t so)
{
alist_set_address(hle, so, hle->alist_audio.segments, N_SEGMENTS);
}
static void clear_segments(struct hle_t* hle)
{
memset(hle->alist_audio.segments, 0, N_SEGMENTS*sizeof(hle->alist_audio.segments[0]));
}
/* audio commands definition */
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
@ -64,195 +56,189 @@ static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUS
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1 + DMEM_BASE;
uint16_t count = w2 & 0xfff;
uint16_t dmem = w1 + DMEM_BASE;
uint16_t count = w2 & 0xfff;
if (count != 0)
alist_clear(hle, dmem, align(count, 16));
if (count == 0)
return;
alist_clear(hle, dmem, align(count, 16));
}
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint32_t address = get_address(hle, w2);
uint8_t flags = (w1 >> 16);
uint32_t address = get_address(hle, w2);
alist_envmix_exp(
hle,
flags & A_INIT,
flags & A_AUX,
hle->alist_audio.out, hle->alist_audio.dry_right,
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
hle->alist_audio.in, hle->alist_audio.count,
hle->alist_audio.dry, hle->alist_audio.wet,
hle->alist_audio.vol,
hle->alist_audio.target,
hle->alist_audio.rate,
address);
alist_envmix_exp(
hle,
flags & A_INIT,
flags & A_AUX,
hle->alist_audio.out, hle->alist_audio.dry_right,
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
hle->alist_audio.in, hle->alist_audio.count,
hle->alist_audio.dry, hle->alist_audio.wet,
hle->alist_audio.vol,
hle->alist_audio.target,
hle->alist_audio.rate,
address);
}
static void ENVMIXER_GE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint32_t address = get_address(hle, w2);
uint8_t flags = (w1 >> 16);
uint32_t address = get_address(hle, w2);
alist_envmix_ge(
hle,
flags & A_INIT,
flags & A_AUX,
hle->alist_audio.out, hle->alist_audio.dry_right,
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
hle->alist_audio.in, hle->alist_audio.count,
hle->alist_audio.dry, hle->alist_audio.wet,
hle->alist_audio.vol,
hle->alist_audio.target,
hle->alist_audio.rate,
address);
alist_envmix_ge(
hle,
flags & A_INIT,
flags & A_AUX,
hle->alist_audio.out, hle->alist_audio.dry_right,
hle->alist_audio.wet_left, hle->alist_audio.wet_right,
hle->alist_audio.in, hle->alist_audio.count,
hle->alist_audio.dry, hle->alist_audio.wet,
hle->alist_audio.vol,
hle->alist_audio.target,
hle->alist_audio.rate,
address);
}
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint16_t pitch = w1;
uint32_t address = get_address(hle, w2);
uint8_t flags = (w1 >> 16);
uint16_t pitch = w1;
uint32_t address = get_address(hle, w2);
alist_resample(
hle,
flags & 0x1,
flags & 0x2,
hle->alist_audio.out,
hle->alist_audio.in,
align(hle->alist_audio.count, 16),
pitch << 1,
address);
alist_resample(
hle,
flags & A_INIT,
flags & 0x2,
hle->alist_audio.out,
hle->alist_audio.in,
align(hle->alist_audio.count, 16),
pitch << 1,
address);
}
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
unsigned lr;
uint8_t flags = (w1 >> 16);
uint8_t flags = (w1 >> 16);
if (!hle)
return;
if (flags & A_AUX) {
hle->alist_audio.dry = w1;
hle->alist_audio.wet = w2;
}
else {
unsigned lr = (flags & A_LEFT) ? 0 : 1;
if (flags & A_AUX)
{
hle->alist_audio.dry = w1;
hle->alist_audio.wet = w2;
return;
}
lr = (flags & A_LEFT) ? 0 : 1;
if (flags & A_VOL)
hle->alist_audio.vol[lr] = w1;
else
{
hle->alist_audio.target[lr] = w1;
hle->alist_audio.rate[lr] = w2;
}
if (flags & A_VOL)
hle->alist_audio.vol[lr] = w1;
else {
hle->alist_audio.target[lr] = w1;
hle->alist_audio.rate[lr] = w2;
}
}
}
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
if (!hle)
return;
hle->alist_audio.loop = get_address(hle, w2);
hle->alist_audio.loop = get_address(hle, w2);
}
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint32_t address = get_address(hle, w2);
uint8_t flags = (w1 >> 16);
uint32_t address = get_address(hle, w2);
if (!hle)
return;
alist_adpcm(
hle,
flags & 0x1,
flags & 0x2,
false, /* unsupported in this ucode */
hle->alist_audio.out,
hle->alist_audio.in,
align(hle->alist_audio.count, 32),
hle->alist_audio.table,
hle->alist_audio.loop,
address);
alist_adpcm(
hle,
flags & A_INIT,
flags & A_LOOP,
false, /* unsupported in this ucode */
hle->alist_audio.out,
hle->alist_audio.in,
align(hle->alist_audio.count, 32),
hle->alist_audio.table,
hle->alist_audio.loop,
address);
}
static void LOADBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
uint32_t address = get_address(hle, w2);
uint32_t address = get_address(hle, w2);
if (hle->alist_audio.count != 0)
alist_load(hle, hle->alist_audio.in, address, hle->alist_audio.count);
if (hle->alist_audio.count == 0)
return;
alist_load(hle, hle->alist_audio.in, address, hle->alist_audio.count);
}
static void SAVEBUFF(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
uint32_t address = get_address(hle, w2);
uint32_t address = get_address(hle, w2);
if (hle->alist_audio.count != 0)
alist_save(hle, hle->alist_audio.out, address, hle->alist_audio.count);
if (hle->alist_audio.count == 0)
return;
alist_save(hle, hle->alist_audio.out, address, hle->alist_audio.count);
}
static void SETBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
if (flags & A_AUX)
{
if (flags & A_AUX) {
hle->alist_audio.dry_right = w1 + DMEM_BASE;
hle->alist_audio.wet_left = (w2 >> 16) + DMEM_BASE;
hle->alist_audio.wet_right = w2 + DMEM_BASE;
}
else
{
} else {
hle->alist_audio.in = w1 + DMEM_BASE;
hle->alist_audio.out = (w2 >> 16) + DMEM_BASE;
hle->alist_audio.count = w2;
}
}
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t count)
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmemi = w1 + DMEM_BASE;
uint16_t dmemo = (count >> 16) + DMEM_BASE;
uint16_t dmemi = w1 + DMEM_BASE;
uint16_t dmemo = (w2 >> 16) + DMEM_BASE;
uint16_t count = w2;
if (count != 0)
alist_move(hle, dmemo, dmemi, align(count, 16));
if (count == 0)
return;
alist_move(hle, dmemo, dmemi, align(count, 16));
}
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = w1;
uint32_t address = get_address(hle, w2);
uint16_t count = w1;
uint32_t address = get_address(hle, w2);
if (!hle)
return;
dram_load_u16(hle, (uint16_t*)hle->alist_audio.table, address, align(count, 8) >> 1);
dram_load_u16(hle, (uint16_t*)hle->alist_audio.table, address, align(count, 8) >> 1);
}
static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
uint16_t left = (w2 >> 16) + DMEM_BASE;
uint16_t right = w2 + DMEM_BASE;
uint16_t left = (w2 >> 16) + DMEM_BASE;
uint16_t right = w2 + DMEM_BASE;
if (hle->alist_audio.count != 0)
alist_interleave(hle, hle->alist_audio.out,
left, right, align(hle->alist_audio.count, 16));
if (hle->alist_audio.count == 0)
return;
alist_interleave(hle, hle->alist_audio.out, left, right, align(hle->alist_audio.count, 16));
}
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
int16_t gain = w1;
uint16_t dmemi = (w2 >> 16) + DMEM_BASE;
uint16_t dmemo = w2 + DMEM_BASE;
int16_t gain = w1;
uint16_t dmemi = (w2 >> 16) + DMEM_BASE;
uint16_t dmemo = w2 + DMEM_BASE;
if (hle->alist_audio.count != 0)
alist_mix(hle, dmemo, dmemi, align(hle->alist_audio.count, 32), gain);
if (hle->alist_audio.count == 0)
return;
alist_mix(hle, dmemo, dmemi, align(hle->alist_audio.count, 32), gain);
}
static void SEGMENT(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
@ -262,12 +248,14 @@ static void SEGMENT(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint16_t gain = w1;
uint32_t address = get_address(hle, w2);
uint8_t flags = (w1 >> 16);
uint16_t gain = w1;
uint32_t address = get_address(hle, w2);
if (hle->alist_audio.count != 0)
alist_polef(
if (hle->alist_audio.count == 0)
return;
alist_polef(
hle,
flags & A_INIT,
hle->alist_audio.out,
@ -281,39 +269,42 @@ static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
/* global functions */
void alist_process_audio(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, POLEF, SETLOOP
};
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, POLEF, SETLOOP
};
clear_segments(hle);
alist_process(hle, ABI, 0x10);
clear_segments(hle);
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_audio_ge(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, POLEF, SETLOOP
};
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, POLEF, SETLOOP
};
clear_segments(hle);
alist_process(hle, ABI, 0x10);
clear_segments(hle);
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_audio_bc(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, POLEF, SETLOOP
};
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM , CLEARBUFF, ENVMIXER_GE,
LOADBUFF, RESAMPLE, SAVEBUFF, SEGMENT,
SETBUFF, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, POLEF, SETLOOP
};
clear_segments(hle);
alist_process(hle, ABI, 0x10);
clear_segments(hle);
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist_naudio.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -21,24 +21,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdbool.h>
#include <stdint.h>
#include <boolean.h>
#include "common.h"
#include "alist.h"
#include "common.h"
#include "hle_external.h"
#include "hle_internal.h"
#include "memory.h"
#include "ucodes.h"
enum
{
NAUDIO_COUNT = 0x170
}; /* ie 184 samples */
enum
{
enum { NAUDIO_COUNT = 0x170 }; /* ie 184 samples */
enum {
NAUDIO_MAIN = 0x4f0,
NAUDIO_MAIN2 = 0x660,
NAUDIO_DRY_LEFT = 0x9d0,
@ -47,24 +41,23 @@ enum
NAUDIO_WET_RIGHT = 0xe20
};
/* audio commands definition */
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t acmd = (w1 >> 24);
uint8_t acmd = (w1 >> 24);
HleWarnMessage(hle->user_defined,
"Unknown audio command %d: %08x %08x",
acmd, w1, w2);
HleWarnMessage(hle->user_defined,
"Unknown audio command %d: %08x %08x",
acmd, w1, w2);
}
static void SPNOOP(struct hle_t* UNUSED(hle),
uint32_t UNUSED(w1), uint32_t UNUSED(w2))
static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
{
}
static void NAUDIO_0000(struct hle_t* hle,
uint32_t w1, uint32_t w2)
static void NAUDIO_0000(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
/* ??? */
UNKNOWN(hle, w1, w2);
@ -72,8 +65,6 @@ static void NAUDIO_0000(struct hle_t* hle,
static void NAUDIO_02B0(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
if (!hle)
return;
/* emulate code at 0x12b0 (inside SETVOL), because PC always execute in IMEM */
hle->alist_naudio.rate[1] &= ~0xffff;
hle->alist_naudio.rate[1] |= (w2 & 0xffff);
@ -81,187 +72,183 @@ static void NAUDIO_02B0(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
static void NAUDIO_14(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint16_t gain = w1;
uint8_t select_main = (w2 >> 24);
uint32_t address = (w2 & 0xffffff);
uint16_t dmem = (select_main == 0) ? NAUDIO_MAIN : NAUDIO_MAIN2;
uint8_t flags = (w1 >> 16);
uint16_t gain = w1;
uint8_t select_main = (w2 >> 24);
uint32_t address = (w2 & 0xffffff);
if (hle->alist_naudio.table[0] == 0 && hle->alist_naudio.table[1] == 0)
{
alist_polef(
hle,
flags & A_INIT,
dmem,
dmem,
NAUDIO_COUNT,
gain,
hle->alist_naudio.table,
address);
return;
}
uint16_t dmem = (select_main == 0) ? NAUDIO_MAIN : NAUDIO_MAIN2;
if (hle->alist_naudio.table[0] == 0 && hle->alist_naudio.table[1] == 0) {
alist_polef(
hle,
flags & A_INIT,
dmem,
dmem,
NAUDIO_COUNT,
gain,
hle->alist_naudio.table,
address);
}
else
{
alist_iirf(
hle,
flags & A_INIT,
dmem,
dmem,
NAUDIO_COUNT,
hle->alist_naudio.table,
address);
}
alist_iirf(
hle,
flags & A_INIT,
dmem,
dmem,
NAUDIO_COUNT,
hle->alist_naudio.table,
address);
}
static void SETVOL(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint8_t flags = (w1 >> 16);
if (flags & 0x4)
{
if (flags & 0x2)
{
hle->alist_naudio.vol[0] = w1;
hle->alist_naudio.dry = (w2 >> 16);
hle->alist_naudio.wet = w2;
}
else
{
hle->alist_naudio.target[1] = w1;
hle->alist_naudio.rate[1] = w2;
}
return;
}
hle->alist_naudio.target[0] = w1;
hle->alist_naudio.rate[0] = w2;
if (flags & A_VOL) {
if (flags & A_LEFT) {
hle->alist_naudio.vol[0] = w1;
hle->alist_naudio.dry = (w2 >> 16);
hle->alist_naudio.wet = w2;
}
else { /* A_RIGHT */
hle->alist_naudio.target[1] = w1;
hle->alist_naudio.rate[1] = w2;
}
}
else { /* A_RATE */
hle->alist_naudio.target[0] = w1;
hle->alist_naudio.rate[0] = w2;
}
}
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint32_t address = (w2 & 0xffffff);
uint8_t flags = (w1 >> 16);
uint32_t address = (w2 & 0xffffff);
hle->alist_naudio.vol[1] = w1;
hle->alist_naudio.vol[1] = w1;
alist_envmix_lin(
hle,
flags & 0x1,
NAUDIO_DRY_LEFT,
NAUDIO_DRY_RIGHT,
NAUDIO_WET_LEFT,
NAUDIO_WET_RIGHT,
NAUDIO_MAIN,
NAUDIO_COUNT,
hle->alist_naudio.dry,
hle->alist_naudio.wet,
hle->alist_naudio.vol,
hle->alist_naudio.target,
hle->alist_naudio.rate,
address);
alist_envmix_lin(
hle,
flags & A_INIT,
NAUDIO_DRY_LEFT,
NAUDIO_DRY_RIGHT,
NAUDIO_WET_LEFT,
NAUDIO_WET_RIGHT,
NAUDIO_MAIN,
NAUDIO_COUNT,
hle->alist_naudio.dry,
hle->alist_naudio.wet,
hle->alist_naudio.vol,
hle->alist_naudio.target,
hle->alist_naudio.rate,
address);
}
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1 + NAUDIO_MAIN;
uint16_t count = w2 & 0xfff;
uint16_t dmem = w1 + NAUDIO_MAIN;
uint16_t count = w2 & 0xfff;
alist_clear(hle, dmem, count);
alist_clear(hle, dmem, count);
}
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
int16_t gain = w1;
uint16_t dmemi = (w2 >> 16) + NAUDIO_MAIN;
uint16_t dmemo = w2 + NAUDIO_MAIN;
int16_t gain = w1;
uint16_t dmemi = (w2 >> 16) + NAUDIO_MAIN;
uint16_t dmemo = w2 + NAUDIO_MAIN;
alist_mix(hle, dmemo, dmemi, NAUDIO_COUNT, gain);
alist_mix(hle, dmemo, dmemi, NAUDIO_COUNT, gain);
}
static void LOADBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
uint32_t address = (w2 & 0xffffff);
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
uint32_t address = (w2 & 0xffffff);
alist_load(hle, dmem, address, count);
alist_load(hle, dmem, address, count);
}
static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
uint32_t address = (w2 & 0xffffff);
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
uint32_t address = (w2 & 0xffffff);
alist_save(hle, dmem, address, count);
alist_save(hle, dmem, address, count);
}
static void NAUDIO_LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = w1;
uint32_t address = (w2 & 0xffffff);
uint16_t count = w1;
uint32_t address = (w2 & 0xffffff);
if (!hle)
return;
dram_load_u16(hle, (uint16_t*)hle->alist_naudio.table, address, count >> 1);
dram_load_u16(hle, (uint16_t*)hle->alist_naudio.table, address, count >> 1);
}
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmemi = w1 + NAUDIO_MAIN;
uint16_t dmemo = (w2 >> 16) + NAUDIO_MAIN;
uint16_t count = w2;
uint16_t dmemi = w1 + NAUDIO_MAIN;
uint16_t dmemo = (w2 >> 16) + NAUDIO_MAIN;
uint16_t count = w2;
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
}
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
hle->alist_naudio.loop = (w2 & 0xffffff);
hle->alist_naudio.loop = (w2 & 0xffffff);
}
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint32_t address = (w1 & 0xffffff);
uint8_t flags = (w2 >> 28);
uint16_t count = (w2 >> 16) & 0xfff;
uint16_t dmemi = ((w2 >> 12) & 0xf) + NAUDIO_MAIN;
uint16_t dmemo = (w2 & 0xfff) + NAUDIO_MAIN;
uint32_t address = (w1 & 0xffffff);
uint8_t flags = (w2 >> 28);
uint16_t count = (w2 >> 16) & 0xfff;
uint16_t dmemi = ((w2 >> 12) & 0xf) + NAUDIO_MAIN;
uint16_t dmemo = (w2 & 0xfff) + NAUDIO_MAIN;
alist_adpcm(
hle,
flags & 0x1,
flags & 0x2,
false, /* unsuported by this ucode */
dmemo,
dmemi,
(count + 0x1f) & ~0x1f,
hle->alist_naudio.table,
hle->alist_naudio.loop,
address);
alist_adpcm(
hle,
flags & A_INIT,
flags & A_LOOP,
false, /* unsuported by this ucode */
dmemo,
dmemi,
(count + 0x1f) & ~0x1f,
hle->alist_naudio.table,
hle->alist_naudio.loop,
address);
}
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint32_t address = (w1 & 0xffffff);
uint8_t flags = (w2 >> 30);
uint16_t pitch = (w2 >> 14);
uint16_t dmemi = ((w2 >> 2) & 0xfff) + NAUDIO_MAIN;
uint16_t dmemo = (w2 & 0x3) ? NAUDIO_MAIN2 : NAUDIO_MAIN;
uint32_t address = (w1 & 0xffffff);
uint8_t flags = (w2 >> 30);
uint16_t pitch = (w2 >> 14);
uint16_t dmemi = ((w2 >> 2) & 0xfff) + NAUDIO_MAIN;
uint16_t dmemo = (w2 & 0x3) ? NAUDIO_MAIN2 : NAUDIO_MAIN;
alist_resample(
hle,
flags & 0x1,
false, /* TODO: check which ABI supports it */
dmemo,
dmemi,
NAUDIO_COUNT,
pitch << 1,
address);
alist_resample(
hle,
flags & A_INIT,
false, /* TODO: check which ABI supports it */
dmemo,
dmemi,
NAUDIO_COUNT,
pitch << 1,
address);
}
static void INTERLEAVE(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t UNUSED(w2))
{
alist_interleave(hle, NAUDIO_MAIN, NAUDIO_DRY_LEFT, NAUDIO_DRY_RIGHT, NAUDIO_COUNT);
alist_interleave(hle, NAUDIO_MAIN, NAUDIO_DRY_LEFT, NAUDIO_DRY_RIGHT, NAUDIO_COUNT);
}
static void MP3ADDY(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
@ -270,10 +257,20 @@ static void MP3ADDY(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNU
static void MP3(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
unsigned index = (w1 & 0x1e);
uint32_t address = (w2 & 0xffffff);
unsigned index = (w1 & 0x1e);
uint32_t address = (w2 & 0xffffff);
mp3_task(hle, index, address);
mp3_task(hle, index, address);
}
static void OVERLOAD(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
/* Overload distortion effect for Conker's Bad Fur Day */
uint16_t dmem = (w1 & 0xfff) + NAUDIO_MAIN;
int16_t gain = (int16_t)(uint16_t)w2;
uint16_t attenuation = w2 >> 16;
alist_overload(hle, dmem, NAUDIO_COUNT, gain, attenuation);
}
/* global functions */
@ -282,11 +279,12 @@ void alist_process_naudio(struct hle_t* hle)
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000,
NAUDIO_0000, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM,
NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
};
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_bk(struct hle_t* hle)
@ -295,11 +293,12 @@ void alist_process_naudio_bk(struct hle_t* hle)
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, NAUDIO_0000,
NAUDIO_0000, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM,
NAUDIO_0000, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
};
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_dk(struct hle_t* hle)
@ -308,34 +307,48 @@ void alist_process_naudio_dk(struct hle_t* hle)
static const acmd_callback_t ABI[0x10] = {
SPNOOP, ADPCM, CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, MIXER,
MIXER, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM,
MIXER, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, NAUDIO_02B0, SETLOOP
};
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_mp3(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x10] = {
UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER,
OVERLOAD, ADPCM, CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, MP3,
MP3ADDY, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM,
MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, NAUDIO_14, SETLOOP
};
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_naudio_cbfd(struct hle_t* hle)
{
/* TODO: see what differs from alist_process_naudio_mp3 */
/* What differs from alist_process_naudio_mp3?
*
* JoshW: It appears that despite being a newer game, CBFD appears to have a slightly older ucode version
* compared to JFG, B.T. et al.
* For naudio_mp3, the functions DMEM parameters have an additional protective AND on them
* (basically dmem & 0xffff).
* But there are minor differences are in the RESAMPLE and ENVMIXER functions.
* I don't think it is making any noticeable difference, as it could be just a simplification of the logic.
*
* bsmiles32: The only difference I could remember between mp3 and cbfd variants is in the MP3ADDY command.
* And the MP3 overlay is also different.
*/
static const acmd_callback_t ABI[0x10] = {
UNKNOWN, ADPCM, CLEARBUFF, ENVMIXER,
OVERLOAD, ADPCM, CLEARBUFF, ENVMIXER,
LOADBUFF, RESAMPLE, SAVEBUFF, MP3,
MP3ADDY, SETVOL, DMEMMOVE, NAUDIO_LOADADPCM,
MP3ADDY, SETVOL, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, NAUDIO_14, SETLOOP
};
alist_process(hle, ABI, 0x10);
rsp_break(hle, SP_STATUS_TASKDONE);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist_nead.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -21,15 +21,15 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdbool.h>
#include <stdint.h>
#include <boolean.h>
#include "common.h"
#include "alist.h"
#include "common.h"
#include "hle_external.h"
#include "hle_internal.h"
#include "memory.h"
#include "ucodes.h"
/* remove windows define to 0x06 */
#ifdef DUPLICATE
@ -39,11 +39,11 @@
/* audio commands definition */
static void UNKNOWN(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t acmd = (w1 >> 24);
uint8_t acmd = (w1 >> 24);
HleWarnMessage(hle->user_defined,
"Unknown audio command %d: %08x %08x",
acmd, w1, w2);
HleWarnMessage(hle->user_defined,
"Unknown audio command %d: %08x %08x",
acmd, w1, w2);
}
@ -51,298 +51,302 @@ static void SPNOOP(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUS
{
}
static void NEAD_LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
static void LOADADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = w1;
uint32_t address = (w2 & 0xffffff);
uint16_t count = w1;
uint32_t address = (w2 & 0xffffff);
if (!hle)
return;
dram_load_u16(hle, (uint16_t*)hle->alist_nead.table, address, count >> 1);
dram_load_u16(hle, (uint16_t*)hle->alist_nead.table, address, count >> 1);
}
static void SETLOOP(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
hle->alist_nead.loop = w2 & 0xffffff;
hle->alist_nead.loop = w2 & 0xffffff;
}
static void SETBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
hle->alist_nead.in = w1;
hle->alist_nead.out = (w2 >> 16);
hle->alist_nead.count = w2;
hle->alist_nead.in = w1;
hle->alist_nead.out = (w2 >> 16);
hle->alist_nead.count = w2;
}
static void ADPCM(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint32_t address = (w2 & 0xffffff);
uint8_t flags = (w1 >> 16);
uint32_t address = (w2 & 0xffffff);
alist_adpcm(
hle,
flags & 0x1,
flags & 0x2,
flags & 0x4,
hle->alist_nead.out,
hle->alist_nead.in,
(hle->alist_nead.count + 0x1f) & ~0x1f,
hle->alist_nead.table,
hle->alist_nead.loop,
address);
alist_adpcm(
hle,
flags & 0x1,
flags & 0x2,
flags & 0x4,
hle->alist_nead.out,
hle->alist_nead.in,
(hle->alist_nead.count + 0x1f) & ~0x1f,
hle->alist_nead.table,
hle->alist_nead.loop,
address);
}
static void CLEARBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1;
uint16_t count = w2 & 0xfff;
uint16_t dmem = w1;
uint16_t count = w2 & 0xfff;
if (count != 0)
alist_clear(hle, dmem, count);
if (count == 0)
return;
alist_clear(hle, dmem, count);
}
static void LOADBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff);
uint32_t address = (w2 & 0xffffff);
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff);
uint32_t address = (w2 & 0xffffff);
alist_load(hle, dmem, address, count);
alist_load(hle, dmem, address, count);
}
static void SAVEBUFF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff);
uint32_t address = (w2 & 0xffffff);
uint16_t count = (w1 >> 12) & 0xfff;
uint16_t dmem = (w1 & 0xfff);
uint32_t address = (w2 & 0xffffff);
alist_save(hle, dmem, address, count);
alist_save(hle, dmem, address, count);
}
static void MIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = (w1 >> 12) & 0xff0;
int16_t gain = w1;
uint16_t dmemi = (w2 >> 16);
uint16_t dmemo = w2;
uint16_t count = (w1 >> 12) & 0xff0;
int16_t gain = w1;
uint16_t dmemi = (w2 >> 16);
uint16_t dmemo = w2;
alist_mix(hle, dmemo, dmemi, count, gain);
alist_mix(hle, dmemo, dmemi, count, gain);
}
static void RESAMPLE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint16_t pitch = w1;
uint32_t address = (w2 & 0xffffff);
uint8_t flags = (w1 >> 16);
uint16_t pitch = w1;
uint32_t address = (w2 & 0xffffff);
alist_resample(
hle,
flags & 0x1,
false, /* TODO: check which ABI supports it */
hle->alist_nead.out,
hle->alist_nead.in,
(hle->alist_nead.count + 0xf) & ~0xf,
pitch << 1,
address);
alist_resample(
hle,
flags & 0x1,
false, /* TODO: check which ABI supports it */
hle->alist_nead.out,
hle->alist_nead.in,
(hle->alist_nead.count + 0xf) & ~0xf,
pitch << 1,
address);
}
static void RESAMPLE_ZOH(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t pitch = w1;
uint16_t pitch_accu = w2;
uint16_t pitch = w1;
uint16_t pitch_accu = w2;
alist_resample_zoh(
hle,
hle->alist_nead.out,
hle->alist_nead.in,
hle->alist_nead.count,
pitch << 1,
pitch_accu);
alist_resample_zoh(
hle,
hle->alist_nead.out,
hle->alist_nead.in,
hle->alist_nead.count,
pitch << 1,
pitch_accu);
}
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t count)
static void DMEMMOVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmemi = w1;
uint16_t dmemo = (count >> 16);
uint16_t dmemi = w1;
uint16_t dmemo = (w2 >> 16);
uint16_t count = w2;
if (count != 0)
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
if (count == 0)
return;
alist_move(hle, dmemo, dmemi, (count + 3) & ~3);
}
static void ENVSETUP1_MK(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
hle->alist_nead.env_steps[2] = 0;
hle->alist_nead.env_steps[0] = (w2 >> 16);
hle->alist_nead.env_steps[1] = w2;
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
hle->alist_nead.env_steps[2] = 0;
hle->alist_nead.env_steps[0] = (w2 >> 16);
hle->alist_nead.env_steps[1] = w2;
}
static void ENVSETUP1(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
hle->alist_nead.env_steps[2] = w1;
hle->alist_nead.env_steps[0] = (w2 >> 16);
hle->alist_nead.env_steps[1] = w2;
hle->alist_nead.env_values[2] = (w1 >> 8) & 0xff00;
hle->alist_nead.env_steps[2] = w1;
hle->alist_nead.env_steps[0] = (w2 >> 16);
hle->alist_nead.env_steps[1] = w2;
}
static void ENVSETUP2(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
hle->alist_nead.env_values[0] = (w2 >> 16);
hle->alist_nead.env_values[1] = w2;
hle->alist_nead.env_values[0] = (w2 >> 16);
hle->alist_nead.env_values[1] = w2;
}
static void ENVMIXER_MK(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
int16_t xors[4];
int16_t xors[4];
uint16_t dmemi = (w1 >> 12) & 0xff0;
uint8_t count = (w1 >> 8) & 0xff;
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
uint16_t dmem_wr = (w2 << 4) & 0xff0;
uint16_t dmemi = (w1 >> 12) & 0xff0;
uint8_t count = (w1 >> 8) & 0xff;
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
uint16_t dmem_wr = (w2 << 4) & 0xff0;
xors[2] = 0; /* unsupported by this ucode */
xors[3] = 0; /* unsupported by this ucode */
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
xors[1] = 0 - (int16_t)((w1 & 0x1) );
xors[2] = 0; /* unsupported by this ucode */
xors[3] = 0; /* unsupported by this ucode */
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
xors[1] = 0 - (int16_t)((w1 & 0x1) );
alist_envmix_nead(
hle,
false, /* unsupported by this ucode */
dmem_dl, dmem_dr,
dmem_wl, dmem_wr,
dmemi, count,
hle->alist_nead.env_values,
hle->alist_nead.env_steps,
xors);
alist_envmix_nead(
hle,
false, /* unsupported by this ucode */
dmem_dl, dmem_dr,
dmem_wl, dmem_wr,
dmemi, count,
hle->alist_nead.env_values,
hle->alist_nead.env_steps,
xors);
}
static void ENVMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
int16_t xors[4];
int16_t xors[4];
uint16_t dmemi = (w1 >> 12) & 0xff0;
uint8_t count = (w1 >> 8) & 0xff;
bool swap_wet_LR = (w1 >> 4) & 0x1;
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
uint16_t dmem_wr = (w2 << 4) & 0xff0;
uint16_t dmemi = (w1 >> 12) & 0xff0;
uint8_t count = (w1 >> 8) & 0xff;
bool swap_wet_LR = (w1 >> 4) & 0x1;
uint16_t dmem_dl = (w2 >> 20) & 0xff0;
uint16_t dmem_dr = (w2 >> 12) & 0xff0;
uint16_t dmem_wl = (w2 >> 4) & 0xff0;
uint16_t dmem_wr = (w2 << 4) & 0xff0;
xors[2] = 0 - (int16_t)((w1 & 0x8) >> 1);
xors[3] = 0 - (int16_t)((w1 & 0x4) >> 1);
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
xors[1] = 0 - (int16_t)((w1 & 0x1) );
xors[2] = 0 - (int16_t)((w1 & 0x8) >> 1);
xors[3] = 0 - (int16_t)((w1 & 0x4) >> 1);
xors[0] = 0 - (int16_t)((w1 & 0x2) >> 1);
xors[1] = 0 - (int16_t)((w1 & 0x1) );
alist_envmix_nead(
hle,
swap_wet_LR,
dmem_dl, dmem_dr,
dmem_wl, dmem_wr,
dmemi, count,
hle->alist_nead.env_values,
hle->alist_nead.env_steps,
xors);
alist_envmix_nead(
hle,
swap_wet_LR,
dmem_dl, dmem_dr,
dmem_wl, dmem_wr,
dmemi, count,
hle->alist_nead.env_values,
hle->alist_nead.env_steps,
xors);
}
static void DUPLICATE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t count = (w1 >> 16);
uint16_t dmemi = w1;
uint16_t dmemo = (w2 >> 16);
uint8_t count = (w1 >> 16);
uint16_t dmemi = w1;
uint16_t dmemo = (w2 >> 16);
alist_repeat64(hle, dmemo, dmemi, count);
alist_repeat64(hle, dmemo, dmemi, count);
}
static void INTERL(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = w1;
uint16_t dmemi = (w2 >> 16);
uint16_t dmemo = w2;
uint16_t count = w1;
uint16_t dmemi = (w2 >> 16);
uint16_t dmemo = w2;
alist_copy_every_other_sample(hle, dmemo, dmemi, count);
alist_copy_every_other_sample(hle, dmemo, dmemi, count);
}
static void INTERLEAVE_MK(struct hle_t* hle, uint32_t UNUSED(w1), uint32_t w2)
{
uint16_t left = (w2 >> 16);
uint16_t right = w2;
uint16_t left = (w2 >> 16);
uint16_t right = w2;
if (hle->alist_nead.count != 0)
alist_interleave(hle, hle->alist_nead.out, left, right, hle->alist_nead.count);
if (hle->alist_nead.count == 0)
return;
alist_interleave(hle, hle->alist_nead.out, left, right, hle->alist_nead.count);
}
static void INTERLEAVE(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = ((w1 >> 12) & 0xff0);
uint16_t dmemo = w1;
uint16_t left = (w2 >> 16);
uint16_t right = w2;
uint16_t count = ((w1 >> 12) & 0xff0);
uint16_t dmemo = w1;
uint16_t left = (w2 >> 16);
uint16_t right = w2;
alist_interleave(hle, dmemo, left, right, count);
alist_interleave(hle, dmemo, left, right, count);
}
static void ADDMIXER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t count = (w1 >> 12) & 0xff0;
uint16_t dmemi = (w2 >> 16);
uint16_t dmemo = w2;
uint16_t count = (w1 >> 12) & 0xff0;
uint16_t dmemi = (w2 >> 16);
uint16_t dmemo = w2;
alist_add(hle, dmemo, dmemi, count);
alist_add(hle, dmemo, dmemi, count);
}
static void HILOGAIN(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
int8_t gain = (w1 >> 16); /* Q4.4 signed */
uint16_t count = w1 & 0xfff;
uint16_t dmem = (w2 >> 16);
int8_t gain = (w1 >> 16); /* Q4.4 signed */
uint16_t count = w1 & 0xfff;
uint16_t dmem = (w2 >> 16);
alist_multQ44(hle, dmem, count, gain);
alist_multQ44(hle, dmem, count, gain);
}
static void FILTER(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint16_t dmem = w1;
uint8_t flags = (w1 >> 16);
uint32_t address = (w2 & 0xffffff);
uint8_t flags = (w1 >> 16);
uint32_t address = (w2 & 0xffffff);
if (flags > 1)
{
hle->alist_nead.filter_count = w1;
hle->alist_nead.filter_lut_address[0] = address; /* t6 */
return;
}
if (flags > 1) {
hle->alist_nead.filter_count = w1;
hle->alist_nead.filter_lut_address[0] = address; /* t6 */
}
else {
uint16_t dmem = w1;
hle->alist_nead.filter_lut_address[1] = address + 0x10; /* t5 */
alist_filter(hle, dmem, hle->alist_nead.filter_count,
address, hle->alist_nead.filter_lut_address);
hle->alist_nead.filter_lut_address[1] = address + 0x10; /* t5 */
alist_filter(hle, dmem, hle->alist_nead.filter_count, address, hle->alist_nead.filter_lut_address);
}
}
static void SEGMENT(struct hle_t* UNUSED(hle),
uint32_t UNUSED(w1), uint32_t UNUSED(w2))
static void SEGMENT(struct hle_t* UNUSED(hle), uint32_t UNUSED(w1), uint32_t UNUSED(w2))
{
}
static void NEAD_16(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t count = (w1 >> 16);
uint16_t dmemi = w1;
uint16_t dmemo = (w2 >> 16);
uint16_t block_size = w2;
uint8_t count = (w1 >> 16);
uint16_t dmemi = w1;
uint16_t dmemo = (w2 >> 16);
uint16_t block_size = w2;
alist_copy_blocks(hle, dmemo, dmemi, block_size, count);
alist_copy_blocks(hle, dmemo, dmemi, block_size, count);
}
static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
{
uint8_t flags = (w1 >> 16);
uint16_t gain = w1;
uint32_t address = (w2 & 0xffffff);
uint8_t flags = (w1 >> 16);
uint16_t gain = w1;
uint32_t address = (w2 & 0xffffff);
if (hle->alist_nead.count != 0)
alist_polef(
if (hle->alist_nead.count == 0)
return;
alist_polef(
hle,
flags & A_INIT,
hle->alist_nead.out,
@ -356,164 +360,197 @@ static void POLEF(struct hle_t* hle, uint32_t w1, uint32_t w2)
void alist_process_nead_mk(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
SPNOOP, RESAMPLE, SPNOOP, SEGMENT,
SETBUFF, SPNOOP, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1_MK, ENVMIXER_MK,
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
SPNOOP, RESAMPLE, SPNOOP, SEGMENT,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1_MK, ENVMIXER_MK,
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
alist_process(hle, ABI, 0x20);
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_sf(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, SPNOOP,
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
alist_process(hle, ABI, 0x20);
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_sfj(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE_MK, POLEF, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
HILOGAIN, UNKNOWN, DUPLICATE, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
alist_process(hle, ABI, 0x20);
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_fz(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x20] = {
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, SPNOOP, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
SPNOOP, UNKNOWN, DUPLICATE, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
static const acmd_callback_t ABI[0x20] = {
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, SPNOOP, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
SPNOOP, UNKNOWN, DUPLICATE, SPNOOP,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
alist_process(hle, ABI, 0x20);
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_wrjb(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
HILOGAIN, UNKNOWN, DUPLICATE, FILTER,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
static const acmd_callback_t ABI[0x20] = {
SPNOOP, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, SPNOOP,
SETBUFF, SPNOOP, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, SPNOOP, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN,
HILOGAIN, UNKNOWN, DUPLICATE, FILTER,
SPNOOP, SPNOOP, SPNOOP, SPNOOP
};
alist_process(hle, ABI, 0x20);
alist_process(hle, ABI, 0x20);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_ys(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_1080(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_oot(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, UNKNOWN,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mm(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mmb(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x18] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
static const acmd_callback_t ABI[0x18] = {
SPNOOP, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_ac(struct hle_t* hle)
{
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, NEAD_LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
static const acmd_callback_t ABI[0x18] = {
UNKNOWN, ADPCM, CLEARBUFF, SPNOOP,
ADDMIXER, RESAMPLE, RESAMPLE_ZOH, FILTER,
SETBUFF, DUPLICATE, DMEMMOVE, LOADADPCM,
MIXER, INTERLEAVE, HILOGAIN, SETLOOP,
NEAD_16, INTERL, ENVSETUP1, ENVMIXER,
LOADBUFF, SAVEBUFF, ENVSETUP2, UNKNOWN
};
alist_process(hle, ABI, 0x18);
alist_process(hle, ABI, 0x18);
rsp_break(hle, SP_STATUS_TASKDONE);
}
void alist_process_nead_mats(struct hle_t* hle)
{
/* FIXME: implement proper ucode
* Forward the task if possible,
* otherwise better to have no sound than garbage sound
*/
if (HleForwardTask(hle->user_defined) != 0) {
rsp_break(hle, SP_STATUS_TASKDONE);
}
}
void alist_process_nead_efz(struct hle_t* hle)
{
/* FIXME: implement proper ucode
* Forward the task if possible,
* otherwise use FZero ucode which should be very similar
*/
if (HleForwardTask(hle->user_defined) != 0) {
alist_process_nead_fz(hle);
}
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - arithmetics.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -22,11 +22,11 @@
#ifndef ARITHMETICS_H
#define ARITHMETICS_H
#include <retro_inline.h>
#include <stdint.h>
static INLINE int16_t clamp_s16(int_fast32_t x)
#include "common.h"
static inline int16_t clamp_s16(int_fast32_t x)
{
x = (x < INT16_MIN) ? INT16_MIN: x;
x = (x > INT16_MAX) ? INT16_MAX: x;
@ -34,9 +34,9 @@ static INLINE int16_t clamp_s16(int_fast32_t x)
return x;
}
static INLINE int32_t vmulf(int16_t x, int16_t y)
static inline int32_t vmulf(int16_t x, int16_t y)
{
return (((int32_t)(x))*((int32_t)(y))+0x4000)>>15;
return (((int32_t)(x))*((int32_t)(y))+0x4000)>>15;
}
#endif

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - audio.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -94,29 +94,35 @@ const int16_t RESAMPLE_LUT[64 * 4] = {
int32_t rdot(size_t n, const int16_t *x, const int16_t *y)
{
int32_t accu = 0;
int32_t accu = 0;
while (n-- != 0)
accu += *(x++) * *(--y);
y += n;
return accu;
while (n != 0) {
accu += *(x++) * *(--y);
--n;
}
return accu;
}
void adpcm_compute_residuals(int16_t* dst, const int16_t* src,
const int16_t* cb_entry, const int16_t* last_samples, size_t count)
{
size_t i;
const int16_t* const book1 = cb_entry;
const int16_t* const book2 = cb_entry + 8;
const int16_t* const book1 = cb_entry;
const int16_t* const book2 = cb_entry + 8;
const int16_t l1 = last_samples[0];
const int16_t l2 = last_samples[1];
const int16_t l1 = last_samples[0];
const int16_t l2 = last_samples[1];
for(i = 0; i < count; ++i)
{
int32_t accu = (int32_t)src[i] << 11;
accu += book1[i]*l1 + book2[i]*l2 + rdot(i, book2, src + i);
dst[i] = clamp_s16(accu >> 11);
size_t i;
assert(count <= 8);
for(i = 0; i < count; ++i) {
int32_t accu = (int32_t)src[i] << 11;
accu += book1[i]*l1 + book2[i]*l2 + rdot(i, book2, src);
dst[i] = clamp_s16(accu >> 11);
}
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - audio.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -25,11 +25,19 @@
#include <stddef.h>
#include <stdint.h>
#include "common.h"
extern const int16_t RESAMPLE_LUT[64 * 4];
int32_t rdot(size_t n, const int16_t *x, const int16_t *y);
#define adpcm_predict_sample(byte, mask, lshift, rshift) (((int16_t)(((uint16_t)((byte) & (mask)) << (lshift))) >> (rshift)))
static inline int16_t adpcm_predict_sample(uint8_t byte, uint8_t mask,
unsigned lshift, unsigned rshift)
{
int16_t sample = (uint16_t)(byte & mask) << lshift;
sample >>= rshift; /* signed */
return sample;
}
void adpcm_compute_residuals(int16_t* dst, const int16_t* src,
const int16_t* cb_entry, const int16_t* last_samples, size_t count);

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - cicx105.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2012 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -35,20 +35,22 @@
**/
void cicx105_ucode(struct hle_t* hle)
{
/* memcpy is okay to use because access constrains are met (alignment, size) */
unsigned int i;
unsigned char *dst = hle->dram + 0x2fb1f0;
unsigned char *src = hle->imem + 0x120;
/* memcpy is okay to use because access constrains are met (alignment, size) */
unsigned int i;
unsigned char *dst = hle->dram + 0x2fb1f0;
unsigned char *src = hle->imem + 0x120;
/* dma_read(0x1120, 0x1e8, 0x1e8) */
memcpy(hle->imem + 0x120, hle->dram + 0x1e8, 0x1f0);
/* dma_read(0x1120, 0x1e8, 0x1e8) */
memcpy(hle->imem + 0x120, hle->dram + 0x1e8, 0x1f0);
/* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */
for (i = 0; i < 24; ++i)
{
memcpy(dst, src, 8);
dst += 0xff0;
src += 0x8;
}
/* dma_write(0x1120, 0x2fb1f0, 0xfe817000) */
for (i = 0; i < 24; ++i) {
memcpy(dst, src, 8);
dst += 0xff0;
src += 0x8;
}
rsp_break(hle, 0);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - common.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -29,5 +29,10 @@
# define UNUSED(x) UNUSED_ ## x
#endif
/* macro for inline keyword */
#ifdef _MSC_VER
#define inline __inline
#endif
#endif

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2012 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -21,44 +21,41 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdbool.h>
#include <stdint.h>
#include <boolean.h>
#ifdef ENABLE_TASK_DUMP
#include <stdio.h>
#endif
#include "hle_external.h"
#include "hle_internal.h"
#include "memory.h"
#include "m64p_plugin.h"
#include "ucodes.h"
#define min(a,b) (((a) < (b)) ? (a) : (b))
/* some rsp status flags */
#define SP_STATUS_HALT 0x1
#define SP_STATUS_BROKE 0x2
#define SP_STATUS_INTR_ON_BREAK 0x40
#define SP_STATUS_TASKDONE 0x200
/* some rdp status flags */
#define DP_STATUS_FREEZE 0x2
/* some mips interface interrupt flags */
#define MI_INTR_SP 0x1
/* helper functions prototypes */
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size);
static void rsp_break(struct hle_t* hle, unsigned int setbits);
static void forward_gfx_task(struct hle_t* hle);
static bool try_fast_audio_dispatching(struct hle_t* hle);
static bool try_fast_task_dispatching(struct hle_t* hle);
static void normal_task_dispatching(struct hle_t* hle);
static void non_task_dispatching(struct hle_t* hle);
static bool is_task(struct hle_t* hle);
static void send_dlist_to_gfx_plugin(struct hle_t* hle);
static ucode_func_t try_audio_task_detection(struct hle_t* hle);
static ucode_func_t try_normal_task_detection(struct hle_t* hle);
static ucode_func_t non_task_detection(struct hle_t* hle);
static ucode_func_t task_detection(struct hle_t* hle);
extern RSP_INFO rsp_info;
/* local variables */
static const bool FORWARD_AUDIO = false, FORWARD_GFX = true;
#ifdef ENABLE_TASK_DUMP
static void dump_binary(struct hle_t* hle, const char *const filename,
const unsigned char *const bytes, unsigned int size);
static void dump_task(struct hle_t* hle, const char *const filename);
static void dump_unknown_task(struct hle_t* hle, unsigned int uc_start);
static void dump_unknown_non_task(struct hle_t* hle, unsigned int uc_start);
#endif
/* Global functions */
void hle_init(struct hle_t* hle,
@ -109,30 +106,40 @@ void hle_init(struct hle_t* hle,
hle->user_defined = user_defined;
}
/**
* Try to figure if the RSP was launched using osSpTask* functions
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
*
* Previously, the ucode_size field was used to determine this,
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
*
* Using ucode_boot_size should be more robust in this regard.
**/
#define is_task(hle) ((*dmem_u32((hle), TASK_UCODE_BOOT_SIZE) <= 0x1000))
void hle_execute(struct hle_t* hle)
{
if (is_task(hle))
{
if (!try_fast_task_dispatching(hle))
normal_task_dispatching(hle);
rsp_break(hle, SP_STATUS_TASKDONE);
return;
}
uint32_t uc_start = *dmem_u32(hle, TASK_UCODE);
uint32_t uc_dstart = *dmem_u32(hle, TASK_UCODE_DATA);
uint32_t uc_dsize = *dmem_u32(hle, TASK_UCODE_DATA_SIZE);
non_task_dispatching(hle);
rsp_break(hle, 0);
bool match = false;
struct cached_ucodes_t * cached_ucodes = &hle->cached_ucodes;
struct ucode_info_t *info = NULL;
if (cached_ucodes->count > 0)
info = &cached_ucodes->infos[cached_ucodes->count-1];
for (int i = 0; i < cached_ucodes->count; i++)
{
if (info->uc_start == uc_start && info->uc_dstart == uc_dstart && info->uc_dsize == uc_dsize)
{
match = true;
break;
}
info--;
}
if (!match)
{
info = &cached_ucodes->infos[cached_ucodes->count];
info->uc_start = uc_start;
info->uc_dstart = uc_dstart;
info->uc_dsize = uc_dsize;
info->uc_pfunc = task_detection(hle);
cached_ucodes->count++;
assert(cached_ucodes->count <= CACHED_UCODES_MAX_SIZE);
assert(info->uc_pfunc != NULL);
}
info->uc_pfunc(hle);
}
/* local functions */
@ -147,233 +154,371 @@ static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size)
return sum;
}
static void rsp_break(struct hle_t* hle, unsigned int setbits)
/**
* Try to figure if the RSP was launched using osSpTask* functions
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
*
* Previously, the ucode_size field was used to determine this,
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
*
* Using ucode_boot_size should be more robust in this regard.
**/
static bool is_task(struct hle_t* hle)
{
*hle->sp_status |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT;
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK))
{
*hle->mi_intr |= MI_INTR_SP;
if (rsp_info.CheckInterrupts)
rsp_info.CheckInterrupts();
}
return (*dmem_u32(hle, TASK_UCODE_BOOT_SIZE) <= 0x1000);
}
static void forward_gfx_task(struct hle_t* hle)
void rsp_break(struct hle_t* hle, unsigned int setbits)
{
if (rsp_info.ProcessDlistList)
rsp_info.ProcessDlistList();
*hle->sp_status |= setbits | SP_STATUS_BROKE | SP_STATUS_HALT;
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK)) {
*hle->mi_intr |= MI_INTR_SP;
HleCheckInterrupts(hle->user_defined);
}
}
static bool try_fast_audio_dispatching(struct hle_t* hle)
static void send_alist_to_audio_plugin(struct hle_t* hle)
{
HleProcessAlistList(hle->user_defined);
rsp_break(hle, SP_STATUS_TASKDONE);
}
static void send_dlist_to_gfx_plugin(struct hle_t* hle)
{
/* Since GFX_INFO version 2, these bits are set before calling the ProcessDlistList function.
* And the GFX plugin is responsible to unset them if needed.
* For GFX_INFO version < 2, the GFX plugin didn't have access to sp_status so
* it doesn't matter if we set these bits before calling ProcessDlistList function.
*/
*hle->sp_status |= SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT;
HleProcessDlistList(hle->user_defined);
if ((*hle->sp_status & SP_STATUS_INTR_ON_BREAK) && (*hle->sp_status & (SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT))) {
*hle->mi_intr |= MI_INTR_SP;
HleCheckInterrupts(hle->user_defined);
}
}
static void task_done(struct hle_t* hle)
{
rsp_break(hle, SP_STATUS_TASKDONE);
}
static void unknown_ucode(struct hle_t* hle)
{
/* Forward task to RSP Fallback.
* If task is not forwarded, use the regular "unknown ucode" path */
if (HleForwardTask(hle->user_defined) != 0) {
uint32_t uc_start = *dmem_u32(hle, TASK_UCODE);
HleWarnMessage(hle->user_defined, "unknown RSP code: uc_start: %x PC:%x", uc_start, *hle->sp_pc);
#ifdef ENABLE_TASK_DUMP
dump_unknown_non_task(hle, uc_start);
#endif
}
}
static void unknown_task(struct hle_t* hle)
{
/* Forward task to RSP Fallback.
* If task is not forwarded, use the regular "unknown task" path */
if (HleForwardTask(hle->user_defined) != 0) {
/* Send task_done signal for unknown ucodes to allow further processings */
rsp_break(hle, SP_STATUS_TASKDONE);
uint32_t uc_start = *dmem_u32(hle, TASK_UCODE);
HleWarnMessage(hle->user_defined, "unknown OSTask: uc_start: %x PC:%x", uc_start, *hle->sp_pc);
#ifdef ENABLE_TASK_DUMP
dump_unknown_task(hle, uc_start);
#endif
}
}
static ucode_func_t try_audio_task_detection(struct hle_t* hle)
{
uint32_t v;
/* identify audio ucode by using the content of ucode_data */
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
uint32_t v;
if (*dram_u32(hle, ucode_data) == 0x00000001)
{
if (*dram_u32(hle, ucode_data + 0x30) == 0xf0000f00)
{
v = *dram_u32(hle, ucode_data + 0x28);
switch(v)
{
case 0x1e24138c: /* audio ABI (most common) */
alist_process_audio(hle); return true;
case 0x1dc8138c: /* GoldenEye */
alist_process_audio_ge(hle); return true;
case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */
alist_process_audio_bc(hle); return true;
default:
HleWarnMessage(hle->user_defined, "ABI1 identification regression: v=%08x", v);
}
if (*dram_u32(hle, ucode_data) == 0x00000001) {
if (*dram_u32(hle, ucode_data + 0x30) == 0xf0000f00) {
v = *dram_u32(hle, ucode_data + 0x28);
switch(v)
{
case 0x1e24138c: /* audio ABI (most common) */
return &alist_process_audio;
case 0x1dc8138c: /* GoldenEye */
return &alist_process_audio_ge;
case 0x1e3c1390: /* BlastCorp, DiddyKongRacing */
return &alist_process_audio_bc;
default:
HleWarnMessage(hle->user_defined, "ABI1 identification regression: v=%08x", v);
}
} else {
v = *dram_u32(hle, ucode_data + 0x10);
switch(v)
{
case 0x11181350: /* MarioKart, WaveRace (E) */
return &alist_process_nead_mk;
case 0x111812e0: /* StarFox (J) */
return &alist_process_nead_sfj;
case 0x110412ac: /* WaveRace (J RevB) */
return &alist_process_nead_wrjb;
case 0x110412cc: /* StarFox/LylatWars (except J) */
return &alist_process_nead_sf;
case 0x1cd01250: /* FZeroX */
return &alist_process_nead_fz;
case 0x1f08122c: /* YoshisStory */
return &alist_process_nead_ys;
case 0x1f38122c: /* 1080° Snowboarding */
return &alist_process_nead_1080;
case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */
return &alist_process_nead_oot;
case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */
return &alist_process_nead_mm;
case 0x109411f8: /* Zelda MM (E Beta) */
return &alist_process_nead_mmb;
case 0x1eac11b8: /* AnimalCrossing */
return &alist_process_nead_ac;
case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */
return &musyx_v2_task;
case 0x1f701238: /* Mario Artist Talent Studio */
return &alist_process_nead_mats;
case 0x1f4c1230: /* FZeroX Expansion */
return &alist_process_nead_efz;
default:
HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v);
}
}
else
} else {
v = *dram_u32(hle, ucode_data + 0x10);
switch(v)
{
v = *dram_u32(hle, ucode_data + 0x10);
switch(v)
{
case 0x11181350: /* MarioKart, WaveRace (E) */
alist_process_nead_mk(hle); return true;
case 0x111812e0: /* StarFox (J) */
alist_process_nead_sfj(hle); return true;
case 0x110412ac: /* WaveRace (J RevB) */
alist_process_nead_wrjb(hle); return true;
case 0x110412cc: /* StarFox/LylatWars (except J) */
alist_process_nead_sf(hle); return true;
case 0x1cd01250: /* FZeroX */
alist_process_nead_fz(hle); return true;
case 0x1f08122c: /* YoshisStory */
alist_process_nead_ys(hle); return true;
case 0x1f38122c: /* 1080° Snowboarding */
alist_process_nead_1080(hle); return true;
case 0x1f681230: /* Zelda OoT / Zelda MM (J, J RevA) */
alist_process_nead_oot(hle); return true;
case 0x1f801250: /* Zelda MM (except J, J RevA, E Beta), PokemonStadium 2 */
alist_process_nead_mm(hle); return true;
case 0x109411f8: /* Zelda MM (E Beta) */
alist_process_nead_mmb(hle); return true;
case 0x1eac11b8: /* AnimalCrossing */
alist_process_nead_ac(hle); return true;
case 0x00010010: /* MusyX v2 (IndianaJones, BattleForNaboo) */
musyx_v2_task(hle); return true;
case 0x00000001: /* MusyX v1
RogueSquadron, ResidentEvil2, PolarisSnoCross,
TheWorldIsNotEnough, RugratsInParis, NBAShowTime,
HydroThunder, Tarzan, GauntletLegend, Rush2049 */
return &musyx_v1_task;
case 0x0000127c: /* naudio (many games) */
return &alist_process_naudio;
case 0x00001280: /* BanjoKazooie */
return &alist_process_naudio_bk;
case 0x1c58126c: /* DonkeyKong */
return &alist_process_naudio_dk;
case 0x1ae8143c: /* BanjoTooie, JetForceGemini, MickeySpeedWayUSA, PerfectDark */
return &alist_process_naudio_mp3;
case 0x1ab0140c: /* ConkerBadFurDay */
return &alist_process_naudio_cbfd;
default:
HleWarnMessage(hle->user_defined, "ABI2 identification regression: v=%08x", v);
}
default:
HleWarnMessage(hle->user_defined, "ABI3 identification regression: v=%08x", v);
}
}
else
{
v = *dram_u32(hle, ucode_data + 0x10);
switch(v)
{
/* -- MusyX v1 --
Star Wars: Rogue Squadron
Resident Evil 2
Polaris SnoCross
007: The World Is Not Enough
Rugrats In Paris
NBA ShowTime
Hydro Thunder
Tarzan
Gauntlet Legends
Rush 2049
*/
case 0x00000001:
musyx_v1_task(hle);
return true;
/* NAUDIO (many games) */
case 0x0000127c:
alist_process_naudio(hle);
return true;
/* Banjo Kazooie */
case 0x00001280:
alist_process_naudio_bk(hle);
return true;
/* Donkey Kong 64 */
case 0x1c58126c:
alist_process_naudio_dk(hle);
return true;
/* Banjo Tooie
* Jet Force Gemini
* Mickey's SpeedWay USA
* Perfect Dark */
case 0x1ae8143c:
alist_process_naudio_mp3(hle);
return true;
case 0x1ab0140c:
/* Conker's Bad Fur Day */
alist_process_naudio_cbfd(hle);
return true;
default:
HleWarnMessage(hle->user_defined, "ABI3 identification regression: v=%08x", v);
}
return NULL;
}
static ucode_func_t try_normal_task_detection(struct hle_t* hle)
{
unsigned int sum =
sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), min(*dmem_u32(hle, TASK_UCODE_SIZE), 0xf80) >> 1);
switch (sum) {
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
case 0x278:
/* Nothing to emulate */
return &task_done;
/* GFX: Twintris [misleading task->type == 0] */
case 0x212ee:
if (hle->hle_gfx) {
return &send_dlist_to_gfx_plugin;
}
return NULL;
/* JPEG: found in Pokemon Stadium J */
case 0x2c85a:
return &jpeg_decode_PS0;
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
case 0x2caa6:
return &jpeg_decode_PS;
/* JPEG: found in Ogre Battle, Bottom of the 9th */
case 0x130de:
case 0x278b0:
return &jpeg_decode_OB;
}
return false;
}
/* Resident Evil 2 */
sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 256);
switch (sum) {
static bool try_fast_task_dispatching(struct hle_t* hle)
{
/* identify task ucode by its type */
switch (*dmem_u32(hle, TASK_TYPE))
{
case 1:
/* Resident evil 2 */
if (*dmem_u32(hle, TASK_DATA_PTR) == 0)
return false;
case 0x450f:
return &resize_bilinear_task;
if (FORWARD_GFX)
{
forward_gfx_task(hle);
return true;
}
break;
case 0x3b44:
return &decode_video_frame_task;
case 2:
if (FORWARD_AUDIO)
{
if (rsp_info.ProcessAlistList)
rsp_info.ProcessAlistList();
return true;
}
if (try_fast_audio_dispatching(hle))
return true;
break;
case 7:
if (rsp_info.ShowCFB)
rsp_info.ShowCFB();
return true;
case 0x3d84:
return &fill_video_double_buffer_task;
}
return false;
/* HVQM */
sum = sum_bytes((void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE)), 1488);
switch (sum) {
case 0x19495:
return &hvqm2_decode_sp1_task;
case 0x19728:
return &hvqm2_decode_sp2_task;
}
return NULL;
}
static void normal_task_dispatching(struct hle_t* hle)
static ucode_func_t non_task_detection(struct hle_t* hle)
{
const unsigned int sum =
sum_bytes((void*)dram_u32(hle,
*dmem_u32(hle, TASK_UCODE)),
min(*dmem_u32(hle, TASK_UCODE_SIZE), 0xf80) >> 1);
const unsigned int sum = sum_bytes(hle->imem, 44);
switch (sum)
{
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
case 0x278:
/* Nothing to emulate */
return;
/* GFX: Twintris [misleading task->type == 0] */
case 0x212ee:
if (FORWARD_GFX)
{
forward_gfx_task(hle);
return;
}
break;
/* JPEG: found in Pokemon Stadium J */
case 0x2c85a:
jpeg_decode_PS0(hle);
return;
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
case 0x2caa6:
jpeg_decode_PS(hle);
return;
/* JPEG: found in Ogre Battle, Bottom of the 9th */
case 0x130de:
case 0x278b0:
jpeg_decode_OB(hle);
return;
/* Resident evil 2 */
case 0x29a20: /* USA */
case 0x298c5: /* Europe */
case 0x298b8: /* USA Rev A */
case 0x296d9: /* J */
resize_bilinear_task(hle);
return;
}
HleWarnMessage(hle->user_defined, "unknown OSTask: sum: %x PC:%x", sum, *hle->sp_pc);
if (sum == 0x9e2)
{
/* CIC x105 ucode (used during boot of CIC x105 games) */
return &cicx105_ucode;
}
return &unknown_ucode;
}
static void non_task_dispatching(struct hle_t* hle)
static ucode_func_t task_detection(struct hle_t* hle)
{
const unsigned int sum = sum_bytes(hle->imem, 44);
if (is_task(hle)) {
ucode_func_t uc_pfunc;
uint32_t type = *dmem_u32(hle, TASK_TYPE);
if (sum == 0x9e2)
{
/* CIC x105 ucode (used during boot of CIC x105 games) */
cicx105_ucode(hle);
return;
}
if (type == 2) {
if (hle->hle_aud) {
return &send_alist_to_audio_plugin;
}
uc_pfunc = try_audio_task_detection(hle);
if (uc_pfunc)
return uc_pfunc;
}
HleWarnMessage(hle->user_defined, "unknown RSP code: sum: %x PC:%x", sum, *hle->sp_pc);
uc_pfunc = try_normal_task_detection(hle);
if (uc_pfunc)
return uc_pfunc;
if (type == 1) {
if (hle->hle_gfx) {
return &send_dlist_to_gfx_plugin;
}
}
return &unknown_task;
}
else {
return non_task_detection(hle);
}
}
#ifdef ENABLE_TASK_DUMP
static void dump_unknown_task(struct hle_t* hle, unsigned int uc_start)
{
char filename[256];
uint32_t ucode = *dmem_u32(hle, TASK_UCODE);
uint32_t ucode_data = *dmem_u32(hle, TASK_UCODE_DATA);
uint32_t data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
sprintf(&filename[0], "task_%x.log", uc_start);
dump_task(hle, filename);
/* dump ucode_boot */
sprintf(&filename[0], "ucode_boot_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, *dmem_u32(hle, TASK_UCODE_BOOT)), *dmem_u32(hle, TASK_UCODE_BOOT_SIZE));
/* dump ucode */
if (ucode != 0) {
sprintf(&filename[0], "ucode_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, ucode), 0xf80);
}
/* dump ucode_data */
if (ucode_data != 0) {
sprintf(&filename[0], "ucode_data_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, ucode_data), *dmem_u32(hle, TASK_UCODE_DATA_SIZE));
}
/* dump data */
if (data_ptr != 0) {
sprintf(&filename[0], "data_%x.bin", uc_start);
dump_binary(hle, filename, (void*)dram_u32(hle, data_ptr), *dmem_u32(hle, TASK_DATA_SIZE));
}
}
static void dump_unknown_non_task(struct hle_t* hle, unsigned int uc_start)
{
char filename[256];
/* dump IMEM & DMEM for further analysis */
sprintf(&filename[0], "imem_%x.bin", uc_start);
dump_binary(hle, filename, hle->imem, 0x1000);
sprintf(&filename[0], "dmem_%x.bin", uc_start);
dump_binary(hle, filename, hle->dmem, 0x1000);
}
static void dump_binary(struct hle_t* hle, const char *const filename,
const unsigned char *const bytes, unsigned int size)
{
FILE *f;
/* if file already exists, do nothing */
f = fopen(filename, "r");
if (f == NULL) {
/* else we write bytes to the file */
f = fopen(filename, "wb");
if (f != NULL) {
if (fwrite(bytes, 1, size, f) != size)
HleErrorMessage(hle->user_defined, "Writing error on %s", filename);
fclose(f);
} else
HleErrorMessage(hle->user_defined, "Couldn't open %s for writing !", filename);
} else
fclose(f);
}
static void dump_task(struct hle_t* hle, const char *const filename)
{
FILE *f;
f = fopen(filename, "r");
if (f == NULL) {
f = fopen(filename, "w");
fprintf(f,
"type = %d\n"
"flags = %d\n"
"ucode_boot = %#08x size = %#x\n"
"ucode = %#08x size = %#x\n"
"ucode_data = %#08x size = %#x\n"
"dram_stack = %#08x size = %#x\n"
"output_buff = %#08x *size = %#x\n"
"data = %#08x size = %#x\n"
"yield_data = %#08x size = %#x\n",
*dmem_u32(hle, TASK_TYPE),
*dmem_u32(hle, TASK_FLAGS),
*dmem_u32(hle, TASK_UCODE_BOOT), *dmem_u32(hle, TASK_UCODE_BOOT_SIZE),
*dmem_u32(hle, TASK_UCODE), *dmem_u32(hle, TASK_UCODE_SIZE),
*dmem_u32(hle, TASK_UCODE_DATA), *dmem_u32(hle, TASK_UCODE_DATA_SIZE),
*dmem_u32(hle, TASK_DRAM_STACK), *dmem_u32(hle, TASK_DRAM_STACK_SIZE),
*dmem_u32(hle, TASK_OUTPUT_BUFF), *dmem_u32(hle, TASK_OUTPUT_BUFF_SIZE),
*dmem_u32(hle, TASK_DATA_PTR), *dmem_u32(hle, TASK_DATA_SIZE),
*dmem_u32(hle, TASK_YIELD_DATA_PTR), *dmem_u32(hle, TASK_YIELD_DATA_SIZE));
fclose(f);
} else
fclose(f);
}
#endif

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle_external.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -22,17 +22,25 @@
#ifndef HLE_EXTERNAL_H
#define HLE_EXTERNAL_H
#if defined(__GNUC__)
#define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos)))
#else
#define ATTR_FMT(fmtpos, attrpos)
#endif
/* users of the hle core are expected to define these functions */
void HleVerboseMessage(void* user_defined, const char *message, ...);
void HleErrorMessage(void* user_defined, const char *message, ...);
void HleWarnMessage(void* user_defined, const char *message, ...);
void HleVerboseMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
void HleInfoMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
void HleErrorMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
void HleWarnMessage(void* user_defined, const char *message, ...) ATTR_FMT(2, 3);
void HleCheckInterrupts(void* user_defined);
void HleProcessDlistList(void* user_defined);
void HleProcessAlistList(void* user_defined);
void HleProcessRdpList(void* user_defined);
void HleShowCFB(void* user_defined);
int HleForwardTask(void* user_defined);
#endif

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hle_internal.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -57,6 +57,9 @@ struct hle_t
/* for user convenience, this will be passed to "external" functions */
void* user_defined;
int hle_gfx;
int hle_aud;
/* alist.c */
uint8_t alist_buffer[0x1000];
@ -71,7 +74,20 @@ struct hle_t
/* mp3.c */
uint8_t mp3_buffer[0x1000];
struct cached_ucodes_t cached_ucodes;
};
/* some mips interface interrupt flags */
#define MI_INTR_SP 0x1
/* some rsp status flags */
#define SP_STATUS_HALT 0x1
#define SP_STATUS_BROKE 0x2
#define SP_STATUS_INTR_ON_BREAK 0x40
#define SP_STATUS_TASKDONE 0x200
void rsp_break(struct hle_t* hle, unsigned int setbits);
#endif

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - memory.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -26,30 +26,49 @@
/* Global functions */
void load_u8(uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count)
{
while (count)
{
*(dst++) = *u8(buffer, address);
address += 1;
--count;
}
while (count != 0) {
*(dst++) = *u8(buffer, address);
address += 1;
--count;
}
}
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count)
{
while (count)
{
*(dst++) = *u16(buffer, address);
address += 2;
--count;
}
while (count != 0) {
*(dst++) = *u16(buffer, address);
address += 2;
--count;
}
}
void load_u32(uint32_t* dst, const unsigned char* buffer, unsigned address, size_t count)
{
/* Optimization for uint32_t */
memcpy(dst, u32(buffer, address), count * sizeof(uint32_t));
}
void store_u8(unsigned char* buffer, unsigned address, const uint8_t* src, size_t count)
{
while (count != 0) {
*u8(buffer, address) = *(src++);
address += 1;
--count;
}
}
void store_u16(unsigned char* buffer, unsigned address, const uint16_t* src, size_t count)
{
while (count)
{
*u16(buffer, address) = *(src++);
address += 2;
--count;
}
while (count != 0) {
*u16(buffer, address) = *(src++);
address += 2;
--count;
}
}
void store_u32(unsigned char* buffer, unsigned address, const uint32_t* src, size_t count)
{
/* Optimization for uint32_t */
memcpy(u32(buffer, address), src, count * sizeof(uint32_t));
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - plugin.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -23,62 +23,39 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "hle.h"
#include "hle_internal.h"
#include "hle_external.h"
#define M64P_PLUGIN_PROTOTYPES 1
#include "m64p_types.h"
#include "m64p_common.h"
#include "m64p_config.h"
#include "m64p_frontend.h"
#include "m64p_plugin.h"
#include "m64p_types.h"
#define RSP_HLE_VERSION 0x020000
#define CONFIG_API_VERSION 0x020100
#define CONFIG_PARAM_VERSION 1.00
#define RSP_API_VERSION 0x20000
#define RSP_HLE_VERSION 0x020509
#define RSP_PLUGIN_API_VERSION 0x020000
/* local variables */
static struct hle_t g_hle;
static void (*l_CheckInterrupts)(void) = NULL;
static void (*l_ProcessDlistList)(void) = NULL;
static void (*l_ProcessAlistList)(void) = NULL;
static void (*l_ProcessRdpList)(void) = NULL;
static void (*l_ShowCFB)(void) = NULL;
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
static void *l_DebugCallContext = NULL;
static int l_PluginInit = 0;
static unsigned l_PluginInit = 0;
/* local function */
static void DebugMessage(int level, const char *message, va_list args)
{
char msgbuf[1024];
vsprintf(msgbuf, message, args);
}
/* Global functions needed by HLE core */
void HleVerboseMessage(void* UNUSED(user_defined), const char *message, ...)
{
va_list args;
va_start(args, message);
DebugMessage(M64MSG_VERBOSE, message, args);
va_end(args);
}
void HleWarnMessage(void* UNUSED(user_defined), const char *message, ...)
{
va_list args;
va_start(args, message);
DebugMessage(M64MSG_WARNING, message, args);
va_end(args);
}
/* DLL-exported functions */
m64p_error hlePluginStartup(m64p_dynlib_handle UNUSED(CoreLibHandle), void *Context, void (*DebugCallback)(void *, int, const char *))
{
l_PluginInit = 1;
return M64ERR_SUCCESS;
}
m64p_error hlePluginShutdown(void)
{
l_PluginInit = 0;
return M64ERR_SUCCESS;
}
m64p_error hlePluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
EXPORT m64p_error CALL hlePluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
{
/* set version info */
if (PluginType != NULL)
@ -99,48 +76,164 @@ m64p_error hlePluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion,
return M64ERR_SUCCESS;
}
extern RSP_INFO rsp_info;
void hleInitiateRSP(RSP_INFO Rsp_Info, unsigned int* UNUSED(CycleCount))
/* local function */
static void DebugMessage(int level, const char *message, va_list args)
{
hle_init(&g_hle,
rsp_info.RDRAM,
rsp_info.DMEM,
rsp_info.IMEM,
rsp_info.MI_INTR_REG,
rsp_info.SP_MEM_ADDR_REG,
rsp_info.SP_DRAM_ADDR_REG,
rsp_info.SP_RD_LEN_REG,
rsp_info.SP_WR_LEN_REG,
rsp_info.SP_STATUS_REG,
rsp_info.SP_DMA_FULL_REG,
rsp_info.SP_DMA_BUSY_REG,
rsp_info.SP_PC_REG,
rsp_info.SP_SEMAPHORE_REG,
rsp_info.DPC_START_REG,
rsp_info.DPC_END_REG,
rsp_info.DPC_CURRENT_REG,
rsp_info.DPC_STATUS_REG,
rsp_info.DPC_CLOCK_REG,
rsp_info.DPC_BUFBUSY_REG,
rsp_info.DPC_PIPEBUSY_REG,
rsp_info.DPC_TMEM_REG,
NULL);
char msgbuf[1024];
if (l_DebugCallback == NULL)
return;
vsprintf(msgbuf, message, args);
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
}
/* Global functions needed by HLE core */
void HleVerboseMessage(void* UNUSED(user_defined), const char *message, ...)
{
}
void HleErrorMessage(void* UNUSED(user_defined), const char *message, ...)
{
}
void HleWarnMessage(void* UNUSED(user_defined), const char *message, ...)
{
}
void HleCheckInterrupts(void* UNUSED(user_defined))
{
if (l_CheckInterrupts == NULL)
return;
(*l_CheckInterrupts)();
}
void HleProcessDlistList(void* UNUSED(user_defined))
{
if (l_ProcessDlistList == NULL)
return;
(*l_ProcessDlistList)();
}
void HleProcessAlistList(void* UNUSED(user_defined))
{
if (l_ProcessAlistList == NULL)
return;
(*l_ProcessAlistList)();
}
void HleProcessRdpList(void* UNUSED(user_defined))
{
if (l_ProcessRdpList == NULL)
return;
(*l_ProcessRdpList)();
}
void HleShowCFB(void* UNUSED(user_defined))
{
if (l_ShowCFB == NULL)
return;
(*l_ShowCFB)();
}
int HleForwardTask(void* user_defined)
{
return -1;
}
/* DLL-exported functions */
EXPORT m64p_error CALL hlePluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
void (*DebugCallback)(void *, int, const char *))
{
if (l_PluginInit)
return M64ERR_ALREADY_INIT;
/* first thing is to set the callback function for debug info */
l_DebugCallback = DebugCallback;
l_DebugCallContext = Context;
/* this plugin doesn't use any Core library functions (ex for Configuration), so no need to keep the CoreLibHandle */
l_PluginInit = 1;
return M64ERR_SUCCESS;
}
unsigned int hleDoRspCycles(unsigned int Cycles)
EXPORT m64p_error CALL hlePluginShutdown(void)
{
if (!l_PluginInit)
hleInitiateRSP(rsp_info, NULL);
if (!l_PluginInit)
return M64ERR_NOT_INIT;
hle_execute(&g_hle);
return Cycles;
/* reset some local variable */
l_DebugCallback = NULL;
l_DebugCallContext = NULL;
l_PluginInit = 0;
return M64ERR_SUCCESS;
}
void hleRomClosed(void)
EXPORT unsigned int CALL hleDoRspCycles(unsigned int Cycles)
{
/* do nothing */
hle_execute(&g_hle);
return Cycles;
}
EXPORT void CALL hleInitiateRSP(RSP_INFO Rsp_Info, unsigned int* CycleCount)
{
hle_init(&g_hle,
Rsp_Info.RDRAM,
Rsp_Info.DMEM,
Rsp_Info.IMEM,
Rsp_Info.MI_INTR_REG,
Rsp_Info.SP_MEM_ADDR_REG,
Rsp_Info.SP_DRAM_ADDR_REG,
Rsp_Info.SP_RD_LEN_REG,
Rsp_Info.SP_WR_LEN_REG,
Rsp_Info.SP_STATUS_REG,
Rsp_Info.SP_DMA_FULL_REG,
Rsp_Info.SP_DMA_BUSY_REG,
Rsp_Info.SP_PC_REG,
Rsp_Info.SP_SEMAPHORE_REG,
Rsp_Info.DPC_START_REG,
Rsp_Info.DPC_END_REG,
Rsp_Info.DPC_CURRENT_REG,
Rsp_Info.DPC_STATUS_REG,
Rsp_Info.DPC_CLOCK_REG,
Rsp_Info.DPC_BUFBUSY_REG,
Rsp_Info.DPC_PIPEBUSY_REG,
Rsp_Info.DPC_TMEM_REG,
NULL);
l_CheckInterrupts = Rsp_Info.CheckInterrupts;
l_ProcessDlistList = Rsp_Info.ProcessDlistList;
l_ProcessAlistList = Rsp_Info.ProcessAlistList;
l_ProcessRdpList = Rsp_Info.ProcessRdpList;
l_ShowCFB = Rsp_Info.ShowCFB;
// Is the DoCommand really needed? It's upstream
m64p_rom_header rom_header;
CoreDoCommand(M64CMD_ROM_GET_HEADER, sizeof(rom_header), &rom_header);
g_hle.hle_gfx = 1;
g_hle.hle_aud = 0;
/* notify fallback plugin */
/*if (l_InitiateRSP) {
l_InitiateRSP(Rsp_Info, CycleCount);
}*/
}
EXPORT void CALL hleRomClosed(void)
{
g_hle.cached_ucodes.count = 0;
/* notify fallback plugin */
/*if (l_RomClosed) {
l_RomClosed();
}*/
}

View File

@ -0,0 +1,354 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - hvqm.c *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2020 Gilles Siberlin *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "hle_external.h"
#include "hle_internal.h"
#include "memory.h"
/* Nest size */
#define HVQM2_NESTSIZE_L 70 /* Number of elements on long side */
#define HVQM2_NESTSIZE_S 38 /* Number of elements on short side */
#define HVQM2_NESTSIZE (HVQM2_NESTSIZE_L * HVQM2_NESTSIZE_S)
struct HVQM2Block {
uint8_t nbase;
uint8_t dc;
uint8_t dc_l;
uint8_t dc_r;
uint8_t dc_u;
uint8_t dc_d;
};
struct HVQM2Basis {
uint8_t sx;
uint8_t sy;
int16_t scale;
uint16_t offset;
uint16_t lineskip;
};
struct HVQM2Arg {
uint32_t info;
uint32_t buf;
uint16_t buf_width;
uint8_t chroma_step_h;
uint8_t chroma_step_v;
uint16_t hmcus;
uint16_t vmcus;
uint8_t alpha;
uint32_t nest;
};
struct RGBA {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
static struct HVQM2Arg arg;
static const int16_t constant[5][16] = {
{0x0006,0x0008,0x0008,0x0006,0x0008,0x000A,0x000A,0x0008,0x0008,0x000A,0x000A,0x0008,0x0006,0x0008,0x0008,0x0006},
{0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF,0x0002,0x0000,0xFFFF,0xFFFF},
{0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002,0xFFFF,0xFFFF,0x0000,0x0002},
{0x0002,0x0002,0x0002,0x0002,0x0000,0x0000,0x0000,0x0000,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF},
{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0000,0x0000,0x0000,0x0002,0x0002,0x0002,0x0002}
};
static int process_info(struct hle_t* hle, uint8_t* base, int16_t* out)
{
struct HVQM2Block block;
uint8_t nbase = *base;
dram_load_u8(hle, (uint8_t*)&block, arg.info, sizeof(struct HVQM2Block));
arg.info += 8;
*base = block.nbase & 0x7;
if ((block.nbase & nbase) != 0)
return 0;
if (block.nbase == 0)
{
//LABEL8
for (int i = 0; i < 16; i++)
{
out[i] = constant[0][i] * block.dc;
out[i] += constant[1][i] * block.dc_l;
out[i] += constant[2][i] * block.dc_r;
out[i] += constant[3][i] * block.dc_u;
out[i] += constant[4][i] * block.dc_d;
out[i] += 4;
out[i] >>= 3;
}
}
else if ((block.nbase & 0xf) == 0)
{
//LABEL7
for (int i = 0; i < 16; i++)
{
out[i] = *dram_u8(hle, arg.info);
arg.info++;
}
}
else if (*base == 0)
{
//LABEL6
for (int i = 0; i < 16; i++)
{
out[i] = *(int8_t*)dram_u8(hle, arg.info) + block.dc;
arg.info++;
}
}
else
{
//LABEL5
struct HVQM2Basis basis;
for (int i = 0; i < 16; i++)
out[i] = block.dc;
for (; *base != 0; (*base)--)
{
basis.sx = *dram_u8(hle, arg.info);
arg.info++;
basis.sy = *dram_u8(hle, arg.info);
arg.info++;
basis.scale = *dram_u16(hle, arg.info);
arg.info += 2;
basis.offset = *dram_u16(hle, arg.info);
arg.info += 2;
basis.lineskip = *dram_u16(hle, arg.info);
arg.info += 2;
int16_t vec[16];
uint32_t addr = arg.nest + basis.offset;
int shift = (basis.sx != 0) ? 1 : 0;
//LABEL9
//LABEL10
for (int i = 0; i < 16; i += 4)
{
vec[i] = *dram_u8(hle, addr);
vec[i + 1] = *dram_u8(hle, addr + (1 << shift));
vec[i + 2] = *dram_u8(hle, addr + (2 << shift));
vec[i + 3] = *dram_u8(hle, addr + (3 << shift));
addr += basis.lineskip;
}
//LABEL11
int16_t sum = 0x8;
for (int i = 0; i < 16; i++)
sum += vec[i];
sum >>= 4;
int16_t max = 0;
for (int i = 0; i < 16; i++)
{
vec[i] -= sum;
max = (abs(vec[i]) > max) ? abs(vec[i]) : max;
}
double dmax = 0.0;
if (max > 0)
dmax = (double)(basis.scale << 2) / (double)max;
for (int i = 0; i < 16; i++)
out[i] += (vec[i] < 0) ? (int16_t)((double)vec[i] * dmax - 0.5) : (int16_t)((double)vec[i] * dmax + 0.5);
block.nbase &= 8;
}
assert(block.nbase == 0);
//if(block.nbase != 0)
// LABEL6
}
return 1;
}
#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255))
static struct RGBA YCbCr_to_RGBA(int16_t Y, int16_t Cb, int16_t Cr, uint8_t alpha)
{
struct RGBA color;
//Format S10.6
int r = (int)(((double)Y + 0.5) + (1.765625 * (double)(Cr - 128)));
int g = (int)(((double)Y + 0.5) - (0.34375 * (double)(Cr - 128)) - (0.71875 * (double)(Cb - 128)));
int b = (int)(((double)Y + 0.5) + (1.40625 * (double)(Cb - 128)));
color.r = SATURATE8(r);
color.g = SATURATE8(g);
color.b = SATURATE8(b);
color.a = alpha;
return color;
}
void store_rgba5551(struct hle_t* hle, struct RGBA color, uint32_t * addr)
{
uint16_t pixel = ((color.b >> 3) << 11) | ((color.g >> 3) << 6) | ((color.r >> 3) << 1) | (color.a & 1);
dram_store_u16(hle, &pixel, *addr, 1);
*addr += 2;
}
void store_rgba8888(struct hle_t* hle, struct RGBA color, uint32_t * addr)
{
uint32_t pixel = (color.b << 24) | (color.g << 16) | (color.r << 8) | color.a;
dram_store_u32(hle, &pixel, *addr, 1);
*addr += 4;
}
typedef void(*store_pixel_t)(struct hle_t* hle, struct RGBA color, uint32_t * addr);
static void hvqm2_decode(struct hle_t* hle, int is32)
{
//uint32_t uc_data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
uint32_t data_ptr = *dmem_u32(hle, TASK_DATA_PTR);
assert((*dmem_u32(hle, TASK_FLAGS) & 0x1) == 0);
/* Fill HVQM2Arg struct */
arg.info = *dram_u32(hle, data_ptr);
data_ptr += 4;
arg.buf = *dram_u32(hle, data_ptr);
data_ptr += 4;
arg.buf_width = *dram_u16(hle, data_ptr);
data_ptr += 2;
arg.chroma_step_h = *dram_u8(hle, data_ptr);
data_ptr++;
arg.chroma_step_v = *dram_u8(hle, data_ptr);
data_ptr++;
arg.hmcus = *dram_u16(hle, data_ptr);
data_ptr += 2;
arg.vmcus = *dram_u16(hle, data_ptr);
data_ptr += 2;
arg.alpha = *dram_u8(hle, data_ptr);
arg.nest = data_ptr + 1;
assert(arg.chroma_step_h == 2);
assert((arg.chroma_step_v == 1) || (arg.chroma_step_v == 2));
assert((*hle->sp_status & 0x80) == 0); //SP_STATUS_YIELD
int length, skip;
store_pixel_t store_pixel;
if (is32)
{
length = 0x20;
skip = arg.buf_width << 2;
arg.buf_width <<= 4;
store_pixel = &store_rgba8888;
}
else
{
length = 0x10;
skip = arg.buf_width << 1;
arg.buf_width <<= 3;
store_pixel = &store_rgba5551;
}
if (arg.chroma_step_v == 2)
arg.buf_width += arg.buf_width;
for (int i = arg.vmcus; i != 0; i--)
{
uint32_t out;
int j;
for (j = arg.hmcus, out = arg.buf; j != 0; j--, out += length)
{
uint8_t base = 0x80;
int16_t Cb[16], Cr[16], Y1[32], Y2[32];
int16_t* pCb = Cb;
int16_t* pCr = Cr;
int16_t* pY1 = Y1;
int16_t* pY2 = Y2;
if (arg.chroma_step_v == 2)
{
if (process_info(hle, &base, pY1) == 0)
continue;
if (process_info(hle, &base, pY2) == 0)
continue;
pY1 = &Y1[16];
pY2 = &Y2[16];
}
if (process_info(hle, &base, pY1) == 0)
continue;
if (process_info(hle, &base, pY2) == 0)
continue;
if (process_info(hle, &base, Cr) == 0)
continue;
if (process_info(hle, &base, Cb) == 0)
continue;
pY1 = Y1;
pY2 = Y2;
uint32_t out_buf = out;
for (int k = 0; k < 4; k++)
{
for (int m = 0; m < arg.chroma_step_v; m++)
{
uint32_t addr = out_buf;
for (int l = 0; l < 4; l++)
{
struct RGBA color = YCbCr_to_RGBA(pY1[l], pCb[l >> 1], pCr[l >> 1], arg.alpha);
store_pixel(hle, color, &addr);
}
for (int l = 0; l < 4; l++)
{
struct RGBA color = YCbCr_to_RGBA(pY2[l], pCb[(l + 4) >> 1], pCr[(l + 4) >> 1], arg.alpha);
store_pixel(hle, color, &addr);
}
out_buf += skip;
pY1 += 4;
pY2 += 4;
}
pCr += 4;
pCb += 4;
}
}
arg.buf += arg.buf_width;
}
rsp_break(hle, SP_STATUS_TASKDONE);
}
void hvqm2_decode_sp1_task(struct hle_t* hle)
{
hvqm2_decode(hle, 0);
}
void hvqm2_decode_sp2_task(struct hle_t* hle)
{
hvqm2_decode(hle, 1);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - jpeg.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2012 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -141,6 +141,7 @@ static const float IDCT_K[10] = {
void jpeg_decode_PS0(struct hle_t* hle)
{
jpeg_decode_std(hle, "PS0", RescaleYSubBlock, RescaleUVSubBlock, EmitYUVTileLine);
rsp_break(hle, SP_STATUS_TASKDONE);
}
/***************************************************************************
@ -150,6 +151,7 @@ void jpeg_decode_PS0(struct hle_t* hle)
void jpeg_decode_PS(struct hle_t* hle)
{
jpeg_decode_std(hle, "PS", NULL, NULL, EmitRGBATileLine);
rsp_break(hle, SP_STATUS_TASKDONE);
}
/***************************************************************************
@ -190,6 +192,7 @@ void jpeg_decode_OB(struct hle_t* hle)
address += (2 * 6 * SUBBLOCK_SIZE);
}
rsp_break(hle, SP_STATUS_TASKDONE);
}
@ -472,7 +475,7 @@ static void ReorderSubBlock(int16_t *dst, const int16_t *src, const unsigned int
unsigned int i;
/* source and destination sublocks cannot overlap */
assert(abs(dst - src) > SUBBLOCK_SIZE);
assert(labs(dst - src) > SUBBLOCK_SIZE);
for (i = 0; i < SUBBLOCK_SIZE; ++i)
dst[i] = src[table[i]];

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - memory.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -25,13 +25,11 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <retro_inline.h>
#include "common.h"
#include "hle_internal.h"
#ifdef MSB_FIRST
#ifdef M64P_BIG_ENDIAN
#define S 0
#define S16 0
#define S8 0
@ -60,47 +58,128 @@ enum {
TASK_YIELD_DATA_SIZE = 0xffc
};
static INLINE unsigned int align(unsigned int x, unsigned amount)
static inline unsigned int align(unsigned int x, unsigned amount)
{
--amount;
return (x + amount) & ~amount;
--amount;
return (x + amount) & ~amount;
}
#define u8(buffer, address) ((uint8_t*)((buffer) + ((address) ^ S8)))
#define u16(buffer, address) ((uint16_t*)((buffer) + ((address) ^ S16)))
#define u32(buffer, address) ((uint32_t*)((buffer) + (address)))
static inline uint8_t* u8(const unsigned char* buffer, unsigned address)
{
return (uint8_t*)(buffer + (address ^ S8));
}
static inline uint16_t* u16(const unsigned char* buffer, unsigned address)
{
assert((address & 1) == 0);
return (uint16_t*)(buffer + (address ^ S16));
}
static inline uint32_t* u32(const unsigned char* buffer, unsigned address)
{
assert((address & 3) == 0);
return (uint32_t*)(buffer + address);
}
void load_u8 (uint8_t* dst, const unsigned char* buffer, unsigned address, size_t count);
void load_u16(uint16_t* dst, const unsigned char* buffer, unsigned address, size_t count);
#define load_u32(dst, buffer, address, count) memcpy((dst), u32((buffer), (address)), (count) * sizeof(uint32_t))
void load_u32(uint32_t* dst, const unsigned char* buffer, unsigned address, size_t count);
void store_u8 (unsigned char* buffer, unsigned address, const uint8_t* src, size_t count);
void store_u16(unsigned char* buffer, unsigned address, const uint16_t* src, size_t count);
void store_u32(unsigned char* buffer, unsigned address, const uint32_t* src, size_t count);
#define store_u32(buffer, address, src, count) memcpy(u32((buffer), (address)), (src), (count) * sizeof(uint32_t))
/* convenient functions for DMEM access */
#define dmem_u8(hle, address) (u8((hle)->dmem, (address) & 0xFFF)
#define dmem_u16(hle, address) (u16((hle)->dmem, (address) & 0xfff);
#define dmem_u32(hle, address) (u32((hle)->dmem, (address) & 0xfff))
#define dmem_load_u8(hle, dst, address, count) load_u8((dst), (hle)->dmem, (address) & 0xfff, (count))
#define dmem_load_u16(hle, dst, address, count) load_u16((dst), (hle)->dmem, (address) & 0xfff, (count))
#define dmem_load_u32(hle, dst, address, count) load_u32((dst), (hle)->dmem, (address) & 0xfff, (count))
#define dmem_store_u16(hle, src, address, count) store_u16((hle)->dmem, (address) & 0xfff, (src), (count))
#define dmem_store_u32(hle, src, address, count) store_u32((hle)->dmem, (address) & 0xfff, (src), (count))
static inline uint8_t* dmem_u8(struct hle_t* hle, uint16_t address)
{
return u8(hle->dmem, address & 0xfff);
}
static inline uint16_t* dmem_u16(struct hle_t* hle, uint16_t address)
{
return u16(hle->dmem, address & 0xfff);
}
static inline uint32_t* dmem_u32(struct hle_t* hle, uint16_t address)
{
return u32(hle->dmem, address & 0xfff);
}
static inline void dmem_load_u8(struct hle_t* hle, uint8_t* dst, uint16_t address, size_t count)
{
load_u8(dst, hle->dmem, address & 0xfff, count);
}
static inline void dmem_load_u16(struct hle_t* hle, uint16_t* dst, uint16_t address, size_t count)
{
load_u16(dst, hle->dmem, address & 0xfff, count);
}
static inline void dmem_load_u32(struct hle_t* hle, uint32_t* dst, uint16_t address, size_t count)
{
load_u32(dst, hle->dmem, address & 0xfff, count);
}
static inline void dmem_store_u8(struct hle_t* hle, const uint8_t* src, uint16_t address, size_t count)
{
store_u8(hle->dmem, address & 0xfff, src, count);
}
static inline void dmem_store_u16(struct hle_t* hle, const uint16_t* src, uint16_t address, size_t count)
{
store_u16(hle->dmem, address & 0xfff, src, count);
}
static inline void dmem_store_u32(struct hle_t* hle, const uint32_t* src, uint16_t address, size_t count)
{
store_u32(hle->dmem, address & 0xfff, src, count);
}
/* convenient functions DRAM access */
#define dram_u8(hle, address) (u8((hle)->dram, (address) & 0xffffff))
#define dram_u16(hle, address) (u16((hle)->dram, (address) & 0xffffff))
#define dram_u32(hle, address) (u32((hle)->dram, (address) & 0xffffff))
static inline uint8_t* dram_u8(struct hle_t* hle, uint32_t address)
{
return u8(hle->dram, address & 0xffffff);
}
#define dram_load_u8(hle, dst, address, count) load_u8((dst), (hle)->dram, (address) & 0xffffff, (count))
#define dram_load_u16(hle, dst, address, count) load_u16((dst), (hle)->dram, (address) & 0xffffff, (count))
#define dram_load_u32(hle, dst, address, count) load_u32((dst), (hle)->dram, (address) & 0xffffff, (count))
#define dram_store_u8(hle, src, address, count) store_u8((hle)->dram, (address) & 0xffffff, (src), (count))
#define dram_store_u16(hle, src, address, count) store_u16((hle)->dram, (address) & 0xffffff, (src), (count))
#define dram_store_u32(hle, src, address, count) store_u32((hle)->dram, (address) & 0xffffff, (src), (count))
static inline uint16_t* dram_u16(struct hle_t* hle, uint32_t address)
{
return u16(hle->dram, address & 0xffffff);
}
static inline uint32_t* dram_u32(struct hle_t* hle, uint32_t address)
{
return u32(hle->dram, address & 0xffffff);
}
static inline void dram_load_u8(struct hle_t* hle, uint8_t* dst, uint32_t address, size_t count)
{
load_u8(dst, hle->dram, address & 0xffffff, count);
}
static inline void dram_load_u16(struct hle_t* hle, uint16_t* dst, uint32_t address, size_t count)
{
load_u16(dst, hle->dram, address & 0xffffff, count);
}
static inline void dram_load_u32(struct hle_t* hle, uint32_t* dst, uint32_t address, size_t count)
{
load_u32(dst, hle->dram, address & 0xffffff, count);
}
static inline void dram_store_u8(struct hle_t* hle, const uint8_t* src, uint32_t address, size_t count)
{
store_u8(hle->dram, address & 0xffffff, src, count);
}
static inline void dram_store_u16(struct hle_t* hle, const uint16_t* src, uint32_t address, size_t count)
{
store_u16(hle->dram, address & 0xffffff, src, count);
}
static inline void dram_store_u32(struct hle_t* hle, const uint32_t* src, uint32_t address, size_t count)
{
store_u32(hle->dram, address & 0xffffff, src, count);
}
#endif

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - mp3.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
@ -21,8 +21,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <string.h>
#include <stdint.h>
#include <string.h>
#include "arithmetics.h"
#include "hle_internal.h"
@ -205,6 +205,7 @@ static void MP3AB0(int32_t* v)
void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address)
{
uint32_t inPtr, outPtr;
uint32_t t6;/* = 0x08A0; - I think these are temporary storage buffers */
uint32_t t5;/* = 0x0AC0; */
uint32_t t4;/* = (w1 & 0x1E); */
@ -226,32 +227,29 @@ void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address)
/* This must be a header byte or whatnot */
readPtr += 8;
for (cnt = 0; cnt < 0x480; cnt += 0x180)
{
uint32_t inPtr, outPtr;
/* DMA: 0xCF0 <- RDRAM[s5] : 0x180 */
memcpy(hle->mp3_buffer + 0xCF0, hle->dram + readPtr, 0x180);
inPtr = 0xCF0; /* s7 */
outPtr = 0xE70; /* s3 */
/* --------------- Inner Loop Start -------------------- */
for (cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) {
t6 &= 0xFFE0;
t5 &= 0xFFE0;
t6 |= t4;
t5 |= t4;
InnerLoop(hle, outPtr, inPtr, t6, t5, t4);
t4 = (t4 - 2) & 0x1E;
tmp = t6;
t6 = t5;
t5 = tmp;
inPtr += 0x40;
outPtr += 0x40;
}
/* --------------- Inner Loop End -------------------- */
memcpy(hle->dram + writePtr, hle->mp3_buffer + 0xe70, 0x180);
writePtr += 0x180;
readPtr += 0x180;
for (cnt = 0; cnt < 0x480; cnt += 0x180) {
/* DMA: 0xCF0 <- RDRAM[s5] : 0x180 */
memcpy(hle->mp3_buffer + 0xCF0, hle->dram + readPtr, 0x180);
inPtr = 0xCF0; /* s7 */
outPtr = 0xE70; /* s3 */
/* --------------- Inner Loop Start -------------------- */
for (cnt2 = 0; cnt2 < 0x180; cnt2 += 0x40) {
t6 &= 0xFFE0;
t5 &= 0xFFE0;
t6 |= t4;
t5 |= t4;
InnerLoop(hle, outPtr, inPtr, t6, t5, t4);
t4 = (t4 - 2) & 0x1E;
tmp = t6;
t6 = t5;
t5 = tmp;
inPtr += 0x40;
outPtr += 0x40;
}
/* --------------- Inner Loop End -------------------- */
memcpy(hle->dram + writePtr, hle->mp3_buffer + 0xe70, 0x180);
writePtr += 0x180;
readPtr += 0x180;
}
}
@ -282,6 +280,7 @@ static void InnerLoop(struct hle_t* hle,
int tmp;
int32_t hi0;
int32_t hi1;
int32_t vt;
int32_t v[32];
v[0] = *(int16_t *)(hle->mp3_buffer + inPtr + (0x00 ^ S16));
@ -662,25 +661,24 @@ static void InnerLoop(struct hle_t* hle,
hi0 = (int)hi0 >> 0x10;
hi1 = (int)hi1 >> 0x10;
for (i = 0; i < 8; i++)
{
/* v0 */
int32_t vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x40)^S16)) = clamp_s16(vt);
for (i = 0; i < 8; i++) {
/* v0 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x40)^S16)) * hi0);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x40)^S16)) = clamp_s16(vt);
/* v17 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x30)^S16)) * hi0);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x30)^S16)) = clamp_s16(vt);
/* v17 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x30)^S16)) * hi0);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x30)^S16)) = clamp_s16(vt);
/* v2 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x1E)^S16)) * hi1);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x1E)^S16)) = clamp_s16(vt);
/* v2 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0x1E)^S16)) * hi1);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0x1E)^S16)) = clamp_s16(vt);
/* v4 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0xE)^S16)) * hi1);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0xE)^S16)) = clamp_s16(vt);
/* v4 */
vt = (*(int16_t *)(hle->mp3_buffer + ((tmp - 0xE)^S16)) * hi1);
*(int16_t *)((uint8_t *)hle->mp3_buffer + ((tmp - 0xE)^S16)) = clamp_s16(vt);
tmp += 2;
tmp += 2;
}
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - musyx.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2013 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -19,15 +19,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#include <boolean.h>
#include "common.h"
#include "arithmetics.h"
#include "audio.h"
#include "common.h"
#include "hle_external.h"
#include "hle_internal.h"
#include "memory.h"
@ -175,6 +174,7 @@ static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subfra
static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subframe,
const uint16_t* gains);
static void mix_samples(int16_t *y, int16_t x, int16_t hgain);
static void mix_subframes(int16_t *y, const int16_t *x, int16_t hgain);
static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t *hcoeffs);
@ -256,6 +256,8 @@ void musyx_v1_task(struct hle_t* hle)
dram_store_u16(hle, (uint16_t *)musyx.cc0, state_ptr + STATE_CC0, SUBFRAME_SIZE);
dram_store_u16(hle, (uint16_t *)musyx.subframe_740_last4, state_ptr + STATE_740_LAST4_V1,
4);
rsp_break(hle, SP_STATUS_TASKDONE);
}
/**************************************************************************
@ -333,6 +335,8 @@ void musyx_v2_task(struct hle_t* hle)
sfd_ptr += SFD2_VOICES + MAX_VOICES * VOICE_SIZE;
}
rsp_break(hle, SP_STATUS_TASKDONE);
}
@ -375,31 +379,27 @@ static void update_base_vol(struct hle_t* hle, int32_t *base_vol,
base_vol[0], base_vol[1], base_vol[2], base_vol[3]);
/* optim: skip voices contributions entirely if voice_mask is empty */
if (voice_mask != 0)
{
for (i = 0, mask = 1; i < MAX_VOICES;
++i, mask <<= 1, last_sample_ptr += 8)
{
if ((voice_mask & mask) == 0)
continue;
if (voice_mask != 0) {
for (i = 0, mask = 1; i < MAX_VOICES;
++i, mask <<= 1, last_sample_ptr += 8) {
if ((voice_mask & mask) == 0)
continue;
for (k = 0; k < 4; ++k)
base_vol[k] += (int16_t)*dram_u16(hle, last_sample_ptr + k * 2);
}
for (k = 0; k < 4; ++k)
base_vol[k] += (int16_t)*dram_u16(hle, last_sample_ptr + k * 2);
}
}
/* optim: skip contributions entirely if mask_15 is empty */
if (mask_15 != 0)
{
for(i = 0, mask = 1; i < 4;
++i, mask <<= 1, ptr_24 += 8)
{
if ((mask_15 & mask) == 0)
continue;
if (mask_15 != 0) {
for(i = 0, mask = 1; i < 4;
++i, mask <<= 1, ptr_24 += 8) {
if ((mask_15 & mask) == 0)
continue;
for(k = 0; k < 4; ++k)
base_vol[k] += (int16_t)*dram_u16(hle, ptr_24 + k * 2);
}
for(k = 0; k < 4; ++k)
base_vol[k] += (int16_t)*dram_u16(hle, ptr_24 + k * 2);
}
}
/* apply 3% decay */
@ -448,10 +448,10 @@ static void init_subframes_v2(musyx_t *musyx)
subframes[2] = musyx->cc0;
subframes[3] = musyx->e50;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
for(k = 0; k < 4; ++k)
*(subframes[k]++) = values[k];
for (i = 0; i < SUBFRAME_SIZE; ++i) {
for(k = 0; k < 4; ++k)
*(subframes[k]++) = values[k];
}
}
@ -460,45 +460,40 @@ static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx,
uint32_t voice_ptr, uint32_t last_sample_ptr)
{
uint32_t output_ptr;
int i = 0;
/* voice stage can be skipped if first voice has no samples */
if (*dram_u16(hle, voice_ptr + VOICE_CATSRC_0 + CATSRC_SIZE1) == 0)
{
HleVerboseMessage(hle->user_defined, "Skipping Voice stage");
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
}
else
{
unsigned i = 0;
if (*dram_u16(hle, voice_ptr + VOICE_CATSRC_0 + CATSRC_SIZE1) == 0) {
HleVerboseMessage(hle->user_defined, "Skipping Voice stage");
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
} else {
/* otherwise process voices until a non null output_ptr is encountered */
for (;;) {
/* load voice samples (PCM16 or APDCM) */
int16_t samples[SAMPLE_BUFFER_SIZE];
unsigned segbase;
unsigned offset;
/* otherwise process voices until a non null output_ptr is encountered */
for (;;)
{
/* load voice samples (PCM16 or APDCM) */
int16_t samples[SAMPLE_BUFFER_SIZE];
unsigned segbase;
unsigned offset;
HleVerboseMessage(hle->user_defined, "Processing Voice #%d", i);
HleVerboseMessage(hle->user_defined, "Processing Voice #%d", i);
if (*dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES) == 0)
load_samples_PCM16(hle, voice_ptr, samples, &segbase, &offset);
else
load_samples_ADPCM(hle, voice_ptr, samples, &segbase, &offset);
if (*dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES) == 0)
load_samples_PCM16(hle, voice_ptr, samples, &segbase, &offset);
else
load_samples_ADPCM(hle, voice_ptr, samples, &segbase, &offset);
/* mix them with each internal subframes */
mix_voice_samples(hle, musyx, voice_ptr, samples, segbase, offset,
last_sample_ptr + i * 8);
/* mix them with each internal subframes */
mix_voice_samples(hle, musyx, voice_ptr, samples, segbase, offset,
last_sample_ptr + i * 8);
/* check break condition */
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
if (output_ptr != 0)
break;
/* check break condition */
output_ptr = *dram_u32(hle, voice_ptr + VOICE_INTERLEAVED_PTR);
if (output_ptr != 0)
break;
/* next voice */
++i;
voice_ptr += VOICE_SIZE;
}
/* next voice */
++i;
voice_ptr += VOICE_SIZE;
}
}
return output_ptr;
@ -506,25 +501,27 @@ static uint32_t voice_stage(struct hle_t* hle, musyx_t *musyx,
static void dma_cat8(struct hle_t* hle, uint8_t *dst, uint32_t catsrc_ptr)
{
uint32_t ptr1 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR1);
uint32_t ptr2 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR2);
uint16_t size1 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE1);
uint16_t size2 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE2);
uint32_t ptr1 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR1);
uint32_t ptr2 = *dram_u32(hle, catsrc_ptr + CATSRC_PTR2);
uint16_t size1 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE1);
uint16_t size2 = *dram_u16(hle, catsrc_ptr + CATSRC_SIZE2);
size_t count1 = size1;
size_t count2 = size2;
size_t count1 = size1;
size_t count2 = size2;
HleVerboseMessage(hle->user_defined,
"dma_cat: %08x %08x %04x %04x",
ptr1,
ptr2,
size1,
size2);
HleVerboseMessage(hle->user_defined,
"dma_cat: %08x %08x %04x %04x",
ptr1,
ptr2,
size1,
size2);
dram_load_u8(hle, dst, ptr1, count1);
dram_load_u8(hle, dst, ptr1, count1);
if (size2 != 0)
dram_load_u8(hle, dst + count1, ptr2, count2);
if (size2 == 0)
return;
dram_load_u8(hle, dst + count1, ptr2, count2);
}
static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr)
@ -546,63 +543,65 @@ static void dma_cat16(struct hle_t* hle, uint16_t *dst, uint32_t catsrc_ptr)
dram_load_u16(hle, dst, ptr1, count1);
if (size2 != 0)
dram_load_u16(hle, dst + count1, ptr2, count2);
if (size2 == 0)
return;
dram_load_u16(hle, dst + count1, ptr2, count2);
}
static void load_samples_PCM16(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
unsigned *segbase, unsigned *offset)
{
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES);
uint16_t u16_40 = *dram_u16(hle, voice_ptr + VOICE_U16_40);
uint16_t u16_42 = *dram_u16(hle, voice_ptr + VOICE_U16_42);
unsigned count = align(u16_40 + u8_3e, 4);
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES);
uint16_t u16_40 = *dram_u16(hle, voice_ptr + VOICE_U16_40);
uint16_t u16_42 = *dram_u16(hle, voice_ptr + VOICE_U16_42);
HleVerboseMessage(hle->user_defined, "Format: PCM16");
unsigned count = align(u16_40 + u8_3e, 4);
*segbase = SAMPLE_BUFFER_SIZE - count;
*offset = u8_3e;
HleVerboseMessage(hle->user_defined, "Format: PCM16");
dma_cat16(hle, (uint16_t *)samples + *segbase, voice_ptr + VOICE_CATSRC_0);
*segbase = SAMPLE_BUFFER_SIZE - count;
*offset = u8_3e;
if (u16_42 != 0)
dma_cat16(hle, (uint16_t *)samples, voice_ptr + VOICE_CATSRC_1);
dma_cat16(hle, (uint16_t *)samples + *segbase, voice_ptr + VOICE_CATSRC_0);
if (u16_42 != 0)
dma_cat16(hle, (uint16_t *)samples, voice_ptr + VOICE_CATSRC_1);
}
static void load_samples_ADPCM(struct hle_t* hle, uint32_t voice_ptr, int16_t *samples,
unsigned *segbase, unsigned *offset)
{
/* decompressed samples cannot exceed 0x400 bytes;
* ADPCM has a compression ratio of 5/16 */
uint8_t buffer[SAMPLE_BUFFER_SIZE * 2 * 5 / 16];
int16_t adpcm_table[128];
/* decompressed samples cannot exceed 0x400 bytes;
* ADPCM has a compression ratio of 5/16 */
uint8_t buffer[SAMPLE_BUFFER_SIZE * 2 * 5 / 16];
int16_t adpcm_table[128];
uint8_t u8_3c = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES );
uint8_t u8_3d = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES + 1);
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES );
uint8_t u8_3f = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES + 1);
uint32_t adpcm_table_ptr = *dram_u32(hle, voice_ptr + VOICE_ADPCM_TABLE_PTR);
unsigned count;
uint8_t u8_3c = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES );
uint8_t u8_3d = *dram_u8(hle, voice_ptr + VOICE_ADPCM_FRAMES + 1);
uint8_t u8_3e = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES );
uint8_t u8_3f = *dram_u8(hle, voice_ptr + VOICE_SKIP_SAMPLES + 1);
uint32_t adpcm_table_ptr = *dram_u32(hle, voice_ptr + VOICE_ADPCM_TABLE_PTR);
unsigned count;
HleVerboseMessage(hle->user_defined, "Format: ADPCM");
HleVerboseMessage(hle->user_defined, "Format: ADPCM");
HleVerboseMessage(hle->user_defined, "Loading ADPCM table: %08x", adpcm_table_ptr);
dram_load_u16(hle, (uint16_t *)adpcm_table, adpcm_table_ptr, 128);
HleVerboseMessage(hle->user_defined, "Loading ADPCM table: %08x", adpcm_table_ptr);
dram_load_u16(hle, (uint16_t *)adpcm_table, adpcm_table_ptr, 128);
count = u8_3c << 5;
count = u8_3c << 5;
*segbase = SAMPLE_BUFFER_SIZE - count;
*offset = u8_3e & 0x1f;
*segbase = SAMPLE_BUFFER_SIZE - count;
*offset = u8_3e & 0x1f;
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_0);
adpcm_decode_frames(hle, samples + *segbase, buffer, adpcm_table, u8_3c, u8_3e);
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_0);
adpcm_decode_frames(hle, samples + *segbase, buffer, adpcm_table, u8_3c, u8_3e);
if (u8_3d == 0)
return;
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_1);
adpcm_decode_frames(hle, samples, buffer, adpcm_table, u8_3d, u8_3f);
if (u8_3d != 0) {
dma_cat8(hle, buffer, voice_ptr + VOICE_CATSRC_1);
adpcm_decode_frames(hle, samples, buffer, adpcm_table, u8_3d, u8_3f);
}
}
static void adpcm_decode_frames(struct hle_t* hle,
@ -610,381 +609,380 @@ static void adpcm_decode_frames(struct hle_t* hle,
const int16_t *table, uint8_t count,
uint8_t skip_samples)
{
unsigned i;
int16_t frame[32];
const uint8_t *nibbles = src + 8;
bool jump_gap = false;
int16_t frame[32];
const uint8_t *nibbles = src + 8;
unsigned i;
bool jump_gap = false;
HleVerboseMessage(hle->user_defined,
"ADPCM decode: count=%d, skip=%d",
count, skip_samples);
HleVerboseMessage(hle->user_defined,
"ADPCM decode: count=%d, skip=%d",
count, skip_samples);
if (skip_samples >= 32)
{
jump_gap = true;
nibbles += 16;
src += 4;
}
if (skip_samples >= 32) {
jump_gap = true;
nibbles += 16;
src += 4;
}
for (i = 0; i < count; ++i)
{
uint8_t c2 = nibbles[0];
const int16_t *book = (c2 & 0xf0) + table;
unsigned int rshift = (c2 & 0x0f);
for (i = 0; i < count; ++i) {
uint8_t c2 = nibbles[0];
adpcm_predict_frame(frame, src, nibbles, rshift);
const int16_t *book = (c2 & 0xf0) + table;
unsigned int rshift = (c2 & 0x0f);
memcpy(dst, frame, 2 * sizeof(frame[0]));
adpcm_compute_residuals(dst + 2, frame + 2, book, dst , 6);
adpcm_compute_residuals(dst + 8, frame + 8, book, dst + 6, 8);
adpcm_compute_residuals(dst + 16, frame + 16, book, dst + 14, 8);
adpcm_compute_residuals(dst + 24, frame + 24, book, dst + 22, 8);
adpcm_predict_frame(frame, src, nibbles, rshift);
if (jump_gap)
{
nibbles += 8;
src += 32;
}
memcpy(dst, frame, 2 * sizeof(frame[0]));
adpcm_compute_residuals(dst + 2, frame + 2, book, dst , 6);
adpcm_compute_residuals(dst + 8, frame + 8, book, dst + 6, 8);
adpcm_compute_residuals(dst + 16, frame + 16, book, dst + 14, 8);
adpcm_compute_residuals(dst + 24, frame + 24, book, dst + 22, 8);
jump_gap = !jump_gap;
nibbles += 16;
src += 4;
dst += 32;
}
if (jump_gap) {
nibbles += 8;
src += 32;
}
jump_gap = !jump_gap;
nibbles += 16;
src += 4;
dst += 32;
}
}
static void adpcm_predict_frame(int16_t *dst, const uint8_t *src,
const uint8_t *nibbles, unsigned int rshift)
const uint8_t *nibbles,
unsigned int rshift)
{
unsigned int i;
unsigned int i;
*(dst++) = (src[0] << 8) | src[1];
*(dst++) = (src[2] << 8) | src[3];
*(dst++) = (src[0] << 8) | src[1];
*(dst++) = (src[2] << 8) | src[3];
for (i = 1; i < 16; ++i)
{
uint8_t byte = nibbles[i];
for (i = 1; i < 16; ++i) {
uint8_t byte = nibbles[i];
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
*(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift);
}
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
*(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift);
}
}
static void mix_voice_samples(struct hle_t* hle, musyx_t *musyx,
uint32_t voice_ptr, const int16_t *samples,
unsigned segbase, unsigned offset, uint32_t last_sample_ptr)
uint32_t voice_ptr, const int16_t *samples,
unsigned segbase, unsigned offset, uint32_t last_sample_ptr)
{
int i, k;
int32_t v4_env[4];
int32_t v4_env_step[4];
int16_t *v4_dst[4];
int16_t v4[4];
int i, k;
/* parse VOICE structure */
const uint16_t pitch_q16 = *dram_u16(hle, voice_ptr + VOICE_PITCH_Q16);
const uint16_t pitch_shift = *dram_u16(hle, voice_ptr + VOICE_PITCH_SHIFT); /* Q4.12 */
/* parse VOICE structure */
const uint16_t pitch_q16 = *dram_u16(hle, voice_ptr + VOICE_PITCH_Q16);
const uint16_t pitch_shift = *dram_u16(hle, voice_ptr + VOICE_PITCH_SHIFT); /* Q4.12 */
const uint16_t end_point = *dram_u16(hle, voice_ptr + VOICE_END_POINT);
const uint16_t restart_point = *dram_u16(hle, voice_ptr + VOICE_RESTART_POINT);
const uint16_t end_point = *dram_u16(hle, voice_ptr + VOICE_END_POINT);
const uint16_t restart_point = *dram_u16(hle, voice_ptr + VOICE_RESTART_POINT);
const uint16_t u16_4e = *dram_u16(hle, voice_ptr + VOICE_U16_4E);
const uint16_t u16_4e = *dram_u16(hle, voice_ptr + VOICE_U16_4E);
/* init values and pointers */
const int16_t *sample = samples + segbase + offset + u16_4e;
const int16_t *const sample_end = samples + segbase + end_point;
const int16_t *const sample_restart = samples + (restart_point & 0x7fff) +
(((restart_point & 0x8000) != 0) ? 0x000 : segbase);
/* init values and pointers */
const int16_t *sample = samples + segbase + offset + u16_4e;
const int16_t *const sample_end = samples + segbase + end_point;
const int16_t *const sample_restart = samples + (restart_point & 0x7fff) +
(((restart_point & 0x8000) != 0) ? 0x000 : segbase);
uint32_t pitch_accu = pitch_q16;
uint32_t pitch_step = pitch_shift << 4;
dram_load_u32(hle, (uint32_t *)v4_env, voice_ptr + VOICE_ENV_BEGIN, 4);
dram_load_u32(hle, (uint32_t *)v4_env_step, voice_ptr + VOICE_ENV_STEP, 4);
uint32_t pitch_accu = pitch_q16;
uint32_t pitch_step = pitch_shift << 4;
v4_dst[0] = musyx->left;
v4_dst[1] = musyx->right;
v4_dst[2] = musyx->cc0;
v4_dst[3] = musyx->e50;
int32_t v4_env[4];
int32_t v4_env_step[4];
int16_t *v4_dst[4];
int16_t v4[4];
HleVerboseMessage(hle->user_defined,
"Voice debug: segbase=%d"
"\tu16_4e=%04x\n"
"\tpitch: frac0=%04x shift=%04x\n"
"\tend_point=%04x restart_point=%04x\n"
"\tenv = %08x %08x %08x %08x\n"
"\tenv_step = %08x %08x %08x %08x\n",
segbase,
u16_4e,
pitch_q16, pitch_shift,
end_point, restart_point,
v4_env[0], v4_env[1], v4_env[2], v4_env[3],
v4_env_step[0], v4_env_step[1], v4_env_step[2], v4_env_step[3]);
dram_load_u32(hle, (uint32_t *)v4_env, voice_ptr + VOICE_ENV_BEGIN, 4);
dram_load_u32(hle, (uint32_t *)v4_env_step, voice_ptr + VOICE_ENV_STEP, 4);
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
int dist;
int16_t v;
/* update sample and lut pointers and then pitch_accu */
const int16_t *lut = (RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8));
v4_dst[0] = musyx->left;
v4_dst[1] = musyx->right;
v4_dst[2] = musyx->cc0;
v4_dst[3] = musyx->e50;
sample += (pitch_accu >> 16);
pitch_accu &= 0xffff;
pitch_accu += pitch_step;
HleVerboseMessage(hle->user_defined,
"Voice debug: segbase=%d"
"\tu16_4e=%04x\n"
"\tpitch: frac0=%04x shift=%04x\n"
"\tend_point=%04x restart_point=%04x\n"
"\tenv = %08x %08x %08x %08x\n"
"\tenv_step = %08x %08x %08x %08x\n",
segbase,
u16_4e,
pitch_q16, pitch_shift,
end_point, restart_point,
v4_env[0], v4_env[1], v4_env[2], v4_env[3],
v4_env_step[0], v4_env_step[1], v4_env_step[2], v4_env_step[3]);
/* handle end/restart points */
dist = sample - sample_end;
if (dist >= 0)
sample = sample_restart + dist;
for (i = 0; i < SUBFRAME_SIZE; ++i) {
/* update sample and lut pointers and then pitch_accu */
const int16_t *lut = (RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8));
int dist;
int16_t v;
/* apply resample filter */
v = clamp_s16(dot4(sample, lut));
sample += (pitch_accu >> 16);
pitch_accu &= 0xffff;
pitch_accu += pitch_step;
for (k = 0; k < 4; ++k)
{
/* envmix */
int32_t accu = (v * (v4_env[k] >> 16)) >> 15;
v4[k] = clamp_s16(accu);
*(v4_dst[k]) = clamp_s16(accu + *(v4_dst[k]));
/* handle end/restart points */
dist = sample - sample_end;
if (dist >= 0)
sample = sample_restart + dist;
/* update envelopes and dst pointers */
++(v4_dst[k]);
v4_env[k] += v4_env_step[k];
}
}
/* apply resample filter */
v = clamp_s16(dot4(sample, lut));
/* save last resampled sample */
dram_store_u16(hle, (uint16_t *)v4, last_sample_ptr, 4);
for (k = 0; k < 4; ++k) {
/* envmix */
int32_t accu = (v * (v4_env[k] >> 16)) >> 15;
v4[k] = clamp_s16(accu);
*(v4_dst[k]) = clamp_s16(accu + *(v4_dst[k]));
HleVerboseMessage(hle->user_defined,
"last_sample = %04x %04x %04x %04x",
v4[0], v4[1], v4[2], v4[3]);
/* update envelopes and dst pointers */
++(v4_dst[k]);
v4_env[k] += v4_env_step[k];
}
}
/* save last resampled sample */
dram_store_u16(hle, (uint16_t *)v4, last_sample_ptr, 4);
HleVerboseMessage(hle->user_defined,
"last_sample = %04x %04x %04x %04x",
v4[0], v4[1], v4[2], v4[3]);
}
static void sfx_stage(struct hle_t* hle, mix_sfx_with_main_subframes_t mix_sfx_with_main_subframes,
musyx_t *musyx, uint32_t sfx_ptr, uint16_t idx)
{
uint32_t cbuffer_ptr;
uint32_t cbuffer_length;
uint16_t tap_count;
int16_t fir4_hgain;
uint16_t sfx_gains[2];
unsigned int i;
unsigned int i;
int16_t buffer[SUBFRAME_SIZE + 4];
uint32_t tap_delays[8];
int16_t tap_gains[8];
int16_t fir4_hcoeffs[4];
int16_t buffer[SUBFRAME_SIZE + 4];
int16_t *subframe = buffer + 4;
int16_t delayed[SUBFRAME_SIZE];
uint32_t tap_delays[8];
int16_t tap_gains[8];
int16_t fir4_hcoeffs[4];
int16_t *subframe = buffer + 4;
const uint32_t pos = idx * SUBFRAME_SIZE;
int16_t delayed[SUBFRAME_SIZE];
int dpos, dlength;
HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx);
const uint32_t pos = idx * SUBFRAME_SIZE;
if (sfx_ptr == 0)
return;
uint32_t cbuffer_ptr;
uint32_t cbuffer_length;
uint16_t tap_count;
int16_t fir4_hgain;
uint16_t sfx_gains[2];
/* load sfx parameters */
cbuffer_ptr = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_PTR);
cbuffer_length = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_LENGTH);
HleVerboseMessage(hle->user_defined, "SFX: %08x, idx=%d", sfx_ptr, idx);
tap_count = *dram_u16(hle, sfx_ptr + SFX_TAP_COUNT);
if (sfx_ptr == 0)
return;
dram_load_u32(hle, tap_delays, sfx_ptr + SFX_TAP_DELAYS, 8);
dram_load_u16(hle, (uint16_t *)tap_gains, sfx_ptr + SFX_TAP_GAINS, 8);
/* load sfx parameters */
cbuffer_ptr = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_PTR);
cbuffer_length = *dram_u32(hle, sfx_ptr + SFX_CBUFFER_LENGTH);
fir4_hgain = *dram_u16(hle, sfx_ptr + SFX_FIR4_HGAIN);
dram_load_u16(hle, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4);
tap_count = *dram_u16(hle, sfx_ptr + SFX_TAP_COUNT);
sfx_gains[0] = *dram_u16(hle, sfx_ptr + SFX_U16_3C);
sfx_gains[1] = *dram_u16(hle, sfx_ptr + SFX_U16_3E);
dram_load_u32(hle, tap_delays, sfx_ptr + SFX_TAP_DELAYS, 8);
dram_load_u16(hle, (uint16_t *)tap_gains, sfx_ptr + SFX_TAP_GAINS, 8);
HleVerboseMessage(hle->user_defined,
"cbuffer: ptr=%08x length=%x", cbuffer_ptr,
cbuffer_length);
fir4_hgain = *dram_u16(hle, sfx_ptr + SFX_FIR4_HGAIN);
dram_load_u16(hle, (uint16_t *)fir4_hcoeffs, sfx_ptr + SFX_FIR4_HCOEFFS, 4);
HleVerboseMessage(hle->user_defined,
"fir4: hgain=%04x hcoeff=%04x %04x %04x %04x",
fir4_hgain,
fir4_hcoeffs[0], fir4_hcoeffs[1], fir4_hcoeffs[2], fir4_hcoeffs[3]);
sfx_gains[0] = *dram_u16(hle, sfx_ptr + SFX_U16_3C);
sfx_gains[1] = *dram_u16(hle, sfx_ptr + SFX_U16_3E);
HleVerboseMessage(hle->user_defined,
"tap count=%d\n"
"delays: %08x %08x %08x %08x %08x %08x %08x %08x\n"
"gains: %04x %04x %04x %04x %04x %04x %04x %04x",
tap_count,
tap_delays[0], tap_delays[1], tap_delays[2], tap_delays[3],
tap_delays[4], tap_delays[5], tap_delays[6], tap_delays[7],
tap_gains[0], tap_gains[1], tap_gains[2], tap_gains[3],
tap_gains[4], tap_gains[5], tap_gains[6], tap_gains[7]);
HleVerboseMessage(hle->user_defined,
"cbuffer: ptr=%08x length=%x", cbuffer_ptr,
cbuffer_length);
HleVerboseMessage(hle->user_defined, "sfx_gains=%04x %04x", sfx_gains[0], sfx_gains[1]);
HleVerboseMessage(hle->user_defined,
"fir4: hgain=%04x hcoeff=%04x %04x %04x %04x",
fir4_hgain,
fir4_hcoeffs[0], fir4_hcoeffs[1], fir4_hcoeffs[2], fir4_hcoeffs[3]);
/* mix up to 8 delayed subframes */
memset(subframe, 0, SUBFRAME_SIZE * sizeof(subframe[0]));
for (i = 0; i < tap_count; ++i)
{
int dlength;
int dpos = pos - tap_delays[i];
if (dpos <= 0)
dpos += cbuffer_length;
dlength = SUBFRAME_SIZE;
HleVerboseMessage(hle->user_defined,
"tap count=%d\n"
"delays: %08x %08x %08x %08x %08x %08x %08x %08x\n"
"gains: %04x %04x %04x %04x %04x %04x %04x %04x",
tap_count,
tap_delays[0], tap_delays[1], tap_delays[2], tap_delays[3],
tap_delays[4], tap_delays[5], tap_delays[6], tap_delays[7],
tap_gains[0], tap_gains[1], tap_gains[2], tap_gains[3],
tap_gains[4], tap_gains[5], tap_gains[6], tap_gains[7]);
if ((uint32_t)(dpos + SUBFRAME_SIZE) > cbuffer_length) {
dlength = cbuffer_length - dpos;
dram_load_u16(hle, (uint16_t *)delayed + dlength, cbuffer_ptr, SUBFRAME_SIZE - dlength);
}
HleVerboseMessage(hle->user_defined, "sfx_gains=%04x %04x", sfx_gains[0], sfx_gains[1]);
dram_load_u16(hle, (uint16_t *)delayed, cbuffer_ptr + dpos * 2, dlength);
/* mix up to 8 delayed subframes */
memset(subframe, 0, SUBFRAME_SIZE * sizeof(subframe[0]));
for (i = 0; i < tap_count; ++i) {
mix_subframes(subframe, delayed, tap_gains[i]);
}
dpos = pos - tap_delays[i];
if (dpos <= 0)
dpos += cbuffer_length;
dlength = SUBFRAME_SIZE;
/* add resulting subframe to main subframes */
mix_sfx_with_main_subframes(musyx, subframe, sfx_gains);
if ((uint32_t)(dpos + SUBFRAME_SIZE) > cbuffer_length) {
dlength = cbuffer_length - dpos;
dram_load_u16(hle, (uint16_t *)delayed + dlength, cbuffer_ptr, SUBFRAME_SIZE - dlength);
}
/* apply FIR4 filter and writeback filtered result */
memcpy(buffer, musyx->subframe_740_last4, 4 * sizeof(int16_t));
memcpy(musyx->subframe_740_last4, subframe + SUBFRAME_SIZE - 4, 4 * sizeof(int16_t));
mix_fir4(musyx->e50, buffer + 1, fir4_hgain, fir4_hcoeffs);
dram_store_u16(hle, (uint16_t *)musyx->e50, cbuffer_ptr + pos * 2, SUBFRAME_SIZE);
dram_load_u16(hle, (uint16_t *)delayed, cbuffer_ptr + dpos * 2, dlength);
mix_subframes(subframe, delayed, tap_gains[i]);
}
/* add resulting subframe to main subframes */
mix_sfx_with_main_subframes(musyx, subframe, sfx_gains);
/* apply FIR4 filter and writeback filtered result */
memcpy(buffer, musyx->subframe_740_last4, 4 * sizeof(int16_t));
memcpy(musyx->subframe_740_last4, subframe + SUBFRAME_SIZE - 4, 4 * sizeof(int16_t));
mix_fir4(musyx->e50, buffer + 1, fir4_hgain, fir4_hcoeffs);
dram_store_u16(hle, (uint16_t *)musyx->e50, cbuffer_ptr + pos * 2, SUBFRAME_SIZE);
}
static void mix_sfx_with_main_subframes_v1(musyx_t *musyx, const int16_t *subframe,
const uint16_t* UNUSED(gains))
{
unsigned i;
unsigned i;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
int16_t v = subframe[i];
musyx->left[i] = clamp_s16(musyx->left[i] + v);
musyx->right[i] = clamp_s16(musyx->right[i] + v);
}
for (i = 0; i < SUBFRAME_SIZE; ++i) {
int16_t v = subframe[i];
musyx->left[i] = clamp_s16(musyx->left[i] + v);
musyx->right[i] = clamp_s16(musyx->right[i] + v);
}
}
static void mix_sfx_with_main_subframes_v2(musyx_t *musyx, const int16_t *subframe,
const uint16_t* gains)
{
unsigned i;
unsigned i;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
int16_t v = subframe[i];
int16_t v1 = (int32_t)(v * gains[0]) >> 16;
int16_t v2 = (int32_t)(v * gains[1]) >> 16;
for (i = 0; i < SUBFRAME_SIZE; ++i) {
int16_t v = subframe[i];
int16_t v1 = (int32_t)(v * gains[0]) >> 16;
int16_t v2 = (int32_t)(v * gains[1]) >> 16;
musyx->left[i] = clamp_s16(musyx->left[i] + v1);
musyx->right[i] = clamp_s16(musyx->right[i] + v1);
musyx->cc0[i] = clamp_s16(musyx->cc0[i] + v2);
}
musyx->left[i] = clamp_s16(musyx->left[i] + v1);
musyx->right[i] = clamp_s16(musyx->right[i] + v1);
musyx->cc0[i] = clamp_s16(musyx->cc0[i] + v2);
}
}
#define mix_samples(y, x, hgain) (clamp_s16(*(y) + (((x) * (hgain) + 0x4000) >> 15)))
static void mix_samples(int16_t *y, int16_t x, int16_t hgain)
{
*y = clamp_s16(*y + ((x * hgain + 0x4000) >> 15));
}
static void mix_subframes(int16_t *y, const int16_t *x, int16_t hgain)
{
unsigned int i;
for (i = 0; i < SUBFRAME_SIZE; ++i)
y[i] = mix_samples(&y[i], x[i], hgain);
mix_samples(&y[i], x[i], hgain);
}
static void mix_fir4(int16_t *y, const int16_t *x, int16_t hgain, const int16_t *hcoeffs)
{
unsigned int i;
int32_t h[4];
unsigned int i;
int32_t h[4];
h[0] = (hgain * hcoeffs[0]) >> 15;
h[1] = (hgain * hcoeffs[1]) >> 15;
h[2] = (hgain * hcoeffs[2]) >> 15;
h[3] = (hgain * hcoeffs[3]) >> 15;
h[0] = (hgain * hcoeffs[0]) >> 15;
h[1] = (hgain * hcoeffs[1]) >> 15;
h[2] = (hgain * hcoeffs[2]) >> 15;
h[3] = (hgain * hcoeffs[3]) >> 15;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
int32_t v = (h[0] * x[i] + h[1] * x[i + 1] + h[2] * x[i + 2] + h[3] * x[i + 3]) >> 15;
y[i] = clamp_s16(y[i] + v);
}
for (i = 0; i < SUBFRAME_SIZE; ++i) {
int32_t v = (h[0] * x[i] + h[1] * x[i + 1] + h[2] * x[i + 2] + h[3] * x[i + 3]) >> 15;
y[i] = clamp_s16(y[i] + v);
}
}
static void interleave_stage_v1(struct hle_t* hle, musyx_t *musyx, uint32_t output_ptr)
{
size_t i;
int16_t base_left = clamp_s16(musyx->base_vol[0]);
int16_t base_right = clamp_s16(musyx->base_vol[1]);
int16_t *left = musyx->left;
int16_t *right = musyx->right;
uint32_t *dst = dram_u32(hle, output_ptr);
size_t i;
#ifndef NDEBUG
HleVerboseMessage(hle->user_defined, "interleave: %08x", output_ptr);
#endif
int16_t base_left;
int16_t base_right;
for (i = 0; i < SUBFRAME_SIZE; ++i)
{
uint16_t l = clamp_s16(*(left++) + base_left);
uint16_t r = clamp_s16(*(right++) + base_right);
int16_t *left;
int16_t *right;
uint32_t *dst;
*(dst++) = (l << 16) | r;
}
HleVerboseMessage(hle->user_defined, "interleave: %08x", output_ptr);
base_left = clamp_s16(musyx->base_vol[0]);
base_right = clamp_s16(musyx->base_vol[1]);
left = musyx->left;
right = musyx->right;
dst = dram_u32(hle, output_ptr);
for (i = 0; i < SUBFRAME_SIZE; ++i) {
uint16_t l = clamp_s16(*(left++) + base_left);
uint16_t r = clamp_s16(*(right++) + base_right);
*(dst++) = (l << 16) | r;
}
}
static void interleave_stage_v2(struct hle_t* hle, musyx_t *musyx,
uint16_t mask_16, uint32_t ptr_18,
uint32_t ptr_1c, uint32_t output_ptr)
uint16_t mask_16, uint32_t ptr_18,
uint32_t ptr_1c, uint32_t output_ptr)
{
unsigned i, k;
int16_t subframe[SUBFRAME_SIZE];
uint32_t *dst;
uint16_t mask;
unsigned i, k;
int16_t subframe[SUBFRAME_SIZE];
uint32_t *dst;
uint16_t mask;
#ifndef NDEBUG
HleVerboseMessage(hle->user_defined,
"mask_16=%04x ptr_18=%08x ptr_1c=%08x output_ptr=%08x",
mask_16, ptr_18, ptr_1c, output_ptr);
#endif
HleVerboseMessage(hle->user_defined,
"mask_16=%04x ptr_18=%08x ptr_1c=%08x output_ptr=%08x",
mask_16, ptr_18, ptr_1c, output_ptr);
/* compute L_total, R_total and update subframe @ptr_1c */
memset(subframe, 0, SUBFRAME_SIZE*sizeof(subframe[0]));
/* compute L_total, R_total and update subframe @ptr_1c */
memset(subframe, 0, SUBFRAME_SIZE*sizeof(subframe[0]));
for(i = 0; i < SUBFRAME_SIZE; ++i)
{
int16_t v = *dram_u16(hle, ptr_1c + i*2);
musyx->left[i] = v;
musyx->right[i] = clamp_s16(-v);
}
for(i = 0; i < SUBFRAME_SIZE; ++i) {
int16_t v = *dram_u16(hle, ptr_1c + i*2);
musyx->left[i] = v;
musyx->right[i] = clamp_s16(-v);
}
for (k = 0, mask = 1; k < 8; ++k, mask <<= 1, ptr_18 += 8)
{
int16_t hgain;
uint32_t address;
for (k = 0, mask = 1; k < 8; ++k, mask <<= 1, ptr_18 += 8) {
int16_t hgain;
uint32_t address;
if ((mask_16 & mask) == 0)
continue;
if ((mask_16 & mask) == 0)
continue;
address = *dram_u32(hle, ptr_18);
hgain = *dram_u16(hle, ptr_18 + 4);
address = *dram_u32(hle, ptr_18);
hgain = *dram_u16(hle, ptr_18 + 4);
for(i = 0; i < SUBFRAME_SIZE; ++i, address += 2)
{
musyx->left[i] = mix_samples(&musyx->left[i], *dram_u16(hle, address), hgain);
musyx->right[i] = mix_samples(&musyx->right[i], *dram_u16(hle, address + 2*SUBFRAME_SIZE), hgain);
subframe[i] = mix_samples(&subframe[i], *dram_u16(hle, address + 4*SUBFRAME_SIZE), hgain);
}
}
for(i = 0; i < SUBFRAME_SIZE; ++i, address += 2) {
mix_samples(&musyx->left[i], *dram_u16(hle, address), hgain);
mix_samples(&musyx->right[i], *dram_u16(hle, address + 2*SUBFRAME_SIZE), hgain);
mix_samples(&subframe[i], *dram_u16(hle, address + 4*SUBFRAME_SIZE), hgain);
}
}
/* interleave L_total and R_total */
dst = dram_u32(hle, output_ptr);
/* interleave L_total and R_total */
dst = dram_u32(hle, output_ptr);
for(i = 0; i < SUBFRAME_SIZE; ++i) {
uint16_t l = musyx->left[i];
uint16_t r = musyx->right[i];
*(dst++) = (l << 16) | r;
}
for(i = 0; i < SUBFRAME_SIZE; ++i)
{
uint16_t l = musyx->left[i];
uint16_t r = musyx->right[i];
*(dst++) = (l << 16) | r;
}
/* writeback subframe @ptr_1c */
dram_store_u16(hle, (uint16_t*)subframe, ptr_1c, SUBFRAME_SIZE);
/* writeback subframe @ptr_1c */
dram_store_u16(hle, (uint16_t*)subframe, ptr_1c, SUBFRAME_SIZE);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - re2.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2016 Gilles Siberlin *
* *
* This program is free software; you can redistribute it and/or modify *
@ -27,8 +27,10 @@
#include "hle_internal.h"
#include "memory.h"
#define SATURATE8(x) ((unsigned int) x <= 255 ? x : (x < 0 ? 0: 255))
/**************************************************************************
* Resident evil 2 ucode
* Resident evil 2 ucodes
**************************************************************************/
void resize_bilinear_task(struct hle_t* hle)
{
@ -94,4 +96,129 @@ void resize_bilinear_task(struct hle_t* hle)
}
y += y_ratio;
}
rsp_break(hle, SP_STATUS_TASKDONE);
}
static uint32_t YCbCr_to_RGBA(uint8_t Y, uint8_t Cb, uint8_t Cr)
{
int r, g, b;
r = (int)(((double)Y * 0.582199097) + (0.701004028 * (double)(Cr - 128)));
g = (int)(((double)Y * 0.582199097) - (0.357070923 * (double)(Cr - 128)) - (0.172073364 * (double)(Cb - 128)));
b = (int)(((double)Y * 0.582199097) + (0.886001587 * (double)(Cb - 128)));
r = SATURATE8(r);
g = SATURATE8(g);
b = SATURATE8(b);
return (r << 24) | (g << 16) | (b << 8) | 0;
}
void decode_video_frame_task(struct hle_t* hle)
{
int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
int pLuminance = *dram_u32(hle, data_ptr);
int pCb = *dram_u32(hle, data_ptr + 4);
int pCr = *dram_u32(hle, data_ptr + 8);
int pDestination = *dram_u32(hle, data_ptr + 12);
int nMovieWidth = *dram_u32(hle, data_ptr + 16);
int nMovieHeight = *dram_u32(hle, data_ptr + 20);
#if 0 /* unused, but keep it for documentation purpose */
int nRowsPerDMEM = *dram_u32(hle, data_ptr + 24);
int nDMEMPerFrame = *dram_u32(hle, data_ptr + 28);
int nLengthSkipCount = *dram_u32(hle, data_ptr + 32);
#endif
int nScreenDMAIncrement = *dram_u32(hle, data_ptr + 36);
int i, j;
uint8_t Y, Cb, Cr;
uint32_t pixel;
int pY_1st_row, pY_2nd_row, pDest_1st_row, pDest_2nd_row;
for (i = 0; i < nMovieHeight; i += 2)
{
pY_1st_row = pLuminance;
pY_2nd_row = pLuminance + nMovieWidth;
pDest_1st_row = pDestination;
pDest_2nd_row = pDestination + (nScreenDMAIncrement >> 1);
for (j = 0; j < nMovieWidth; j += 2)
{
dram_load_u8(hle, (uint8_t*)&Cb, pCb++, 1);
dram_load_u8(hle, (uint8_t*)&Cr, pCr++, 1);
/*1st row*/
dram_load_u8(hle, (uint8_t*)&Y, pY_1st_row++, 1);
pixel = YCbCr_to_RGBA(Y, Cb, Cr);
dram_store_u32(hle, &pixel, pDest_1st_row, 1);
pDest_1st_row += 4;
dram_load_u8(hle, (uint8_t*)&Y, pY_1st_row++, 1);
pixel = YCbCr_to_RGBA(Y, Cb, Cr);
dram_store_u32(hle, &pixel, pDest_1st_row, 1);
pDest_1st_row += 4;
/*2nd row*/
dram_load_u8(hle, (uint8_t*)&Y, pY_2nd_row++, 1);
pixel = YCbCr_to_RGBA(Y, Cb, Cr);
dram_store_u32(hle, &pixel, pDest_2nd_row, 1);
pDest_2nd_row += 4;
dram_load_u8(hle, (uint8_t*)&Y, pY_2nd_row++, 1);
pixel = YCbCr_to_RGBA(Y, Cb, Cr);
dram_store_u32(hle, &pixel, pDest_2nd_row, 1);
pDest_2nd_row += 4;
}
pLuminance += (nMovieWidth << 1);
pDestination += nScreenDMAIncrement;
}
rsp_break(hle, SP_STATUS_TASKDONE);
}
void fill_video_double_buffer_task(struct hle_t* hle)
{
int data_ptr = *dmem_u32(hle, TASK_UCODE_DATA);
int pSrc = *dram_u32(hle, data_ptr);
int pDest = *dram_u32(hle, data_ptr + 0x4);
int width = *dram_u32(hle, data_ptr + 0x8) >> 1;
int height = *dram_u32(hle, data_ptr + 0x10) << 1;
int stride = *dram_u32(hle, data_ptr + 0x1c) >> 1;
assert((*dram_u32(hle, data_ptr + 0x28) >> 16) == 0x8000);
#if 0 /* unused, but keep it for documentation purpose */
int arg3 = *dram_u32(hle, data_ptr + 0xc);
int arg5 = *dram_u32(hle, data_ptr + 0x14);
int arg6 = *dram_u32(hle, data_ptr + 0x18);
#endif
int i, j;
int r, g, b;
uint32_t pixel, pixel1, pixel2;
for(i = 0; i < height; i++)
{
for(j = 0; j < width; j=j+4)
{
pixel1 = *dram_u32(hle, pSrc+j);
pixel2 = *dram_u32(hle, pDest+j);
r = (((pixel1 >> 24) & 0xff) + ((pixel2 >> 24) & 0xff)) >> 1;
g = (((pixel1 >> 16) & 0xff) + ((pixel2 >> 16) & 0xff)) >> 1;
b = (((pixel1 >> 8) & 0xff) + ((pixel2 >> 8) & 0xff)) >> 1;
pixel = (r << 24) | (g << 16) | (b << 8) | 0;
dram_store_u32(hle, &pixel, pDest+j, 1);
}
pSrc += stride;
pDest += stride;
}
rsp_break(hle, SP_STATUS_TASKDONE);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - ucodes.h *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
@ -24,8 +24,23 @@
#include <stdint.h>
#define CACHED_UCODES_MAX_SIZE 16
struct hle_t;
typedef void(*ucode_func_t)(struct hle_t* hle);
struct ucode_info_t {
uint32_t uc_start;
uint32_t uc_dstart;
uint16_t uc_dsize;
ucode_func_t uc_pfunc;
};
struct cached_ucodes_t {
struct ucode_info_t infos[CACHED_UCODES_MAX_SIZE];
int count;
};
/* cic_x105 ucode */
void cicx105_ucode(struct hle_t* hle);
@ -126,7 +141,8 @@ void alist_process_nead_oot (struct hle_t* hle);
void alist_process_nead_mm (struct hle_t* hle);
void alist_process_nead_mmb (struct hle_t* hle);
void alist_process_nead_ac (struct hle_t* hle);
void alist_process_nead_mats(struct hle_t* hle);
void alist_process_nead_efz (struct hle_t* hle);
/* mp3 ucode */
void mp3_task(struct hle_t* hle, unsigned int index, uint32_t address);
@ -144,6 +160,12 @@ void jpeg_decode_OB(struct hle_t* hle);
/* Resident evil 2 ucode */
void resize_bilinear_task(struct hle_t* hle);
void decode_video_frame_task(struct hle_t* hle);
void fill_video_double_buffer_task(struct hle_t* hle);
/* hvqm2 ucode */
void hvqm2_decode_sp1_task(struct hle_t* hle);
void hvqm2_decode_sp2_task(struct hle_t* hle);
#endif