diff --git a/hw/xbox/mcpx/apu.c b/hw/xbox/mcpx/apu.c index aa6ba50538..0ab01984b2 100644 --- a/hw/xbox/mcpx/apu.c +++ b/hw/xbox/mcpx/apu.c @@ -19,188 +19,7 @@ * License along with this library; if not, see . */ -#include "qemu/osdep.h" -#include -#include -#include -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "hw/pci/pci_device.h" -#include "cpu.h" -#include "migration/vmstate.h" -#include "qemu/main-loop.h" -#include "qemu/thread.h" -#include "sysemu/runstate.h" -#include "audio/audio.h" -#include "qemu/fifo8.h" -#include "ui/xemu-settings.h" - -#include "trace.h" -#include "dsp/dsp.h" -#include "dsp/dsp_dma.h" -#include "dsp/dsp_cpu.h" -#include "dsp/dsp_state.h" -#include "apu.h" -#include "apu_regs.h" -#include "apu_debug.h" -#include "adpcm.h" -#include "svf.h" -#include "fpconv.h" -#include "hrtf.h" - -#define GET_MASK(v, mask) (((v) & (mask)) >> ctz32(mask)) - -#define SET_MASK(v, mask, val) \ - do { \ - (v) &= ~(mask); \ - (v) |= ((val) << ctz32(mask)) & (mask); \ - } while (0) - -#define CASE_4(v, step) \ - case (v): \ - case (v)+(step): \ - case (v)+(step)*2: \ - case (v)+(step)*3 - -// #define DEBUG_MCPX - -#ifdef DEBUG_MCPX -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - -#define MCPX_APU_DEVICE(obj) \ - OBJECT_CHECK(MCPXAPUState, (obj), "mcpx-apu") - -#define NUM_VOICE_WORKERS 16 - -typedef struct MCPXAPUVPSSLData { - uint32_t base[MCPX_HW_SSLS_PER_VOICE]; - uint8_t count[MCPX_HW_SSLS_PER_VOICE]; - int ssl_index; - int ssl_seg; -} MCPXAPUVPSSLData; - -typedef struct MCPXAPUVoiceFilter { - uint16_t voice; - float resample_buf[NUM_SAMPLES_PER_FRAME * 2]; - SRC_STATE *resampler; - sv_filter svf[2]; - HrtfFilter hrtf; -} MCPXAPUVoiceFilter; - -typedef struct VoiceWorkItem { - int voice; - int list; -} VoiceWorkItem; - -typedef struct VoiceWorker { - QemuThread thread; - float mixbins[NUM_MIXBINS][NUM_SAMPLES_PER_FRAME]; - float sample_buf[NUM_SAMPLES_PER_FRAME][2]; - VoiceWorkItem queue[MCPX_HW_MAX_VOICES]; - int queue_len; -} VoiceWorker; - -typedef struct VoiceWorkDispatch { - QemuMutex lock; - VoiceWorker workers[NUM_VOICE_WORKERS]; - bool workers_should_exit; - QemuCond work_pending; - uint64_t workers_pending; - QemuCond work_finished; - float mixbins[NUM_MIXBINS][NUM_SAMPLES_PER_FRAME]; - VoiceWorkItem queue[MCPX_HW_MAX_VOICES]; - int queue_len; -} VoiceWorkDispatch; - -typedef struct MCPXAPUState { - /*< private >*/ - PCIDevice parent_obj; - /*< public >*/ - - bool exiting; - bool set_irq; - - QemuThread apu_thread; - QemuMutex lock; - QemuCond cond; - - MemoryRegion *ram; - uint8_t *ram_ptr; - MemoryRegion mmio; - - /* Setup Engine */ - struct { - } se; - - /* Voice Processor */ - struct { - MemoryRegion mmio; - VoiceWorkDispatch voice_work_dispatch; - MCPXAPUVoiceFilter filters[MCPX_HW_MAX_VOICES]; - QemuSpin out_buf_lock; - Fifo8 out_buf; - - // FIXME: Where are these stored? - int ssl_base_page; - MCPXAPUVPSSLData ssl[MCPX_HW_MAX_VOICES]; - uint8_t hrtf_headroom; - uint8_t hrtf_submix[4]; - uint8_t submix_headroom[NUM_MIXBINS]; - float sample_buf[NUM_SAMPLES_PER_FRAME][2]; - uint64_t voice_locked[4]; - QemuSpin voice_spinlocks[MCPX_HW_MAX_VOICES]; - - struct { - int current_entry; - // FIXME: Stored in RAM - struct { - float hrir[2][HRTF_NUM_TAPS]; - float itd; - } entries[HRTF_ENTRY_COUNT]; - } hrtf; - } vp; - - /* Global Processor */ - struct { - bool realtime; - MemoryRegion mmio; - DSPState *dsp; - uint32_t regs[0x10000]; - } gp; - - /* Encode Processor */ - struct { - bool realtime; - MemoryRegion mmio; - DSPState *dsp; - uint32_t regs[0x10000]; - } ep; - - uint32_t regs[0x20000]; - - uint32_t inbuf_sge_handle; //FIXME: Where is this stored? - uint32_t outbuf_sge_handle; //FIXME: Where is this stored? - - int mon; - int ep_frame_div; - int sleep_acc; - int frame_count; - int64_t frame_count_time; - int16_t apu_fifo_output[256][2]; // 1 EP frame (0x400 bytes), 8 buffered -} MCPXAPUState; - -static const struct { - hwaddr top, current, next; -} voice_list_regs[] = { - { NV_PAPU_TVL2D, NV_PAPU_CVL2D, NV_PAPU_NVL2D }, // 2D - { NV_PAPU_TVL3D, NV_PAPU_CVL3D, NV_PAPU_NVL3D }, // 3D - { NV_PAPU_TVLMP, NV_PAPU_CVLMP, NV_PAPU_NVLMP }, // MP -}; +#include "apu_int.h" static MCPXAPUState *g_state; // Used via debug handlers static struct McpxApuDebug g_dbg, g_dbg_cache; diff --git a/hw/xbox/mcpx/apu_int.h b/hw/xbox/mcpx/apu_int.h new file mode 100644 index 0000000000..7b812ae9b8 --- /dev/null +++ b/hw/xbox/mcpx/apu_int.h @@ -0,0 +1,207 @@ +/* + * QEMU MCPX Audio Processing Unit implementation + * + * Copyright (c) 2012 espes + * Copyright (c) 2018-2019 Jannik Vogel + * Copyright (c) 2019-2025 Matt Borgerson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef HW_XBOX_MCPX_APU_INT_H +#define HW_XBOX_MCPX_APU_INT_H + +#include "qemu/osdep.h" +#include +#include +#include +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" +#include "cpu.h" +#include "migration/vmstate.h" +#include "qemu/main-loop.h" +#include "qemu/thread.h" +#include "sysemu/runstate.h" +#include "audio/audio.h" +#include "qemu/fifo8.h" +#include "ui/xemu-settings.h" + +#include "trace.h" +#include "dsp/dsp.h" +#include "dsp/dsp_dma.h" +#include "dsp/dsp_cpu.h" +#include "dsp/dsp_state.h" +#include "apu.h" +#include "apu_regs.h" +#include "apu_debug.h" +#include "adpcm.h" +#include "svf.h" +#include "fpconv.h" +#include "hrtf.h" + +#define GET_MASK(v, mask) (((v) & (mask)) >> ctz32(mask)) + +#define SET_MASK(v, mask, val) \ + do { \ + (v) &= ~(mask); \ + (v) |= ((val) << ctz32(mask)) & (mask); \ + } while (0) + +#define CASE_4(v, step) \ + case (v): \ + case (v)+(step): \ + case (v)+(step)*2: \ + case (v)+(step)*3 + +// #define DEBUG_MCPX + +#ifdef DEBUG_MCPX +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +#define MCPX_APU_DEVICE(obj) \ + OBJECT_CHECK(MCPXAPUState, (obj), "mcpx-apu") + +#define NUM_VOICE_WORKERS 16 + +typedef struct MCPXAPUVPSSLData { + uint32_t base[MCPX_HW_SSLS_PER_VOICE]; + uint8_t count[MCPX_HW_SSLS_PER_VOICE]; + int ssl_index; + int ssl_seg; +} MCPXAPUVPSSLData; + +typedef struct MCPXAPUVoiceFilter { + uint16_t voice; + float resample_buf[NUM_SAMPLES_PER_FRAME * 2]; + SRC_STATE *resampler; + sv_filter svf[2]; + HrtfFilter hrtf; +} MCPXAPUVoiceFilter; + +typedef struct VoiceWorkItem { + int voice; + int list; +} VoiceWorkItem; + +typedef struct VoiceWorker { + QemuThread thread; + float mixbins[NUM_MIXBINS][NUM_SAMPLES_PER_FRAME]; + float sample_buf[NUM_SAMPLES_PER_FRAME][2]; + VoiceWorkItem queue[MCPX_HW_MAX_VOICES]; + int queue_len; +} VoiceWorker; + +typedef struct VoiceWorkDispatch { + QemuMutex lock; + VoiceWorker workers[NUM_VOICE_WORKERS]; + bool workers_should_exit; + QemuCond work_pending; + uint64_t workers_pending; + QemuCond work_finished; + float mixbins[NUM_MIXBINS][NUM_SAMPLES_PER_FRAME]; + VoiceWorkItem queue[MCPX_HW_MAX_VOICES]; + int queue_len; +} VoiceWorkDispatch; + +typedef struct MCPXAPUState { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + + bool exiting; + bool set_irq; + + QemuThread apu_thread; + QemuMutex lock; + QemuCond cond; + + MemoryRegion *ram; + uint8_t *ram_ptr; + MemoryRegion mmio; + + /* Setup Engine */ + struct { + } se; + + /* Voice Processor */ + struct { + MemoryRegion mmio; + VoiceWorkDispatch voice_work_dispatch; + MCPXAPUVoiceFilter filters[MCPX_HW_MAX_VOICES]; + QemuSpin out_buf_lock; + Fifo8 out_buf; + + // FIXME: Where are these stored? + int ssl_base_page; + MCPXAPUVPSSLData ssl[MCPX_HW_MAX_VOICES]; + uint8_t hrtf_headroom; + uint8_t hrtf_submix[4]; + uint8_t submix_headroom[NUM_MIXBINS]; + float sample_buf[NUM_SAMPLES_PER_FRAME][2]; + uint64_t voice_locked[4]; + QemuSpin voice_spinlocks[MCPX_HW_MAX_VOICES]; + + struct { + int current_entry; + // FIXME: Stored in RAM + struct { + float hrir[2][HRTF_NUM_TAPS]; + float itd; + } entries[HRTF_ENTRY_COUNT]; + } hrtf; + } vp; + + /* Global Processor */ + struct { + bool realtime; + MemoryRegion mmio; + DSPState *dsp; + uint32_t regs[0x10000]; + } gp; + + /* Encode Processor */ + struct { + bool realtime; + MemoryRegion mmio; + DSPState *dsp; + uint32_t regs[0x10000]; + } ep; + + uint32_t regs[0x20000]; + + uint32_t inbuf_sge_handle; //FIXME: Where is this stored? + uint32_t outbuf_sge_handle; //FIXME: Where is this stored? + + int mon; + int ep_frame_div; + int sleep_acc; + int frame_count; + int64_t frame_count_time; + int16_t apu_fifo_output[256][2]; // 1 EP frame (0x400 bytes), 8 buffered +} MCPXAPUState; + +static const struct { + hwaddr top, current, next; +} voice_list_regs[] = { + { NV_PAPU_TVL2D, NV_PAPU_CVL2D, NV_PAPU_NVL2D }, // 2D + { NV_PAPU_TVL3D, NV_PAPU_CVL3D, NV_PAPU_NVL3D }, // 3D + { NV_PAPU_TVLMP, NV_PAPU_CVLMP, NV_PAPU_NVLMP }, // MP +}; + +#endif