diff --git a/config_spec.yml b/config_spec.yml index dc8a449eba..35cfd1553c 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -314,6 +314,9 @@ audio: type: integer default: 0 # 0 = auto use_dsp: bool + use_dsp_jit: + type: bool + default: true hrtf: type: bool default: true diff --git a/hw/xbox/mcpx/apu/apu.c b/hw/xbox/mcpx/apu/apu.c index 86ed7139ff..bd4b90a75b 100644 --- a/hw/xbox/mcpx/apu/apu.c +++ b/hw/xbox/mcpx/apu/apu.c @@ -214,8 +214,6 @@ static void throttle(MCPXAPUState *d) d->next_frame_time_us += (queued_bytes > mid) - (queued_bytes < mid); } } - - d->sleep_acc_us += qemu_clock_get_us(QEMU_CLOCK_REALTIME) - start_us; } static void se_frame(MCPXAPUState *d) @@ -225,22 +223,21 @@ static void se_frame(MCPXAPUState *d) g_dbg.gp_realtime = d->gp.realtime; g_dbg.ep_realtime = d->ep.realtime; - int64_t now_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - int64_t elapsed_ms = now_ms - d->frame_count_time_ms; - if (elapsed_ms >= 1000) { + int64_t start_us = qemu_clock_get_us(QEMU_CLOCK_REALTIME); + int64_t elapsed_us = start_us - d->frame_count_time_us; + if (elapsed_us >= 1000000) { /* A rudimentary calculation to determine approximately how taxed the APU - * thread is, by measuring how much time we spend waiting for buffer to drain - * versus working on building frames. + * thread is, by measuring how much time we spend building frames. * =1: thread is not sleeping and likely falling behind realtime * <1: thread is able to complete work on time */ - g_dbg.utilization = 1.0 - d->sleep_acc_us / (elapsed_ms * 1000.0); - g_dbg.frames_processed = (int)(d->frame_count * 1000.0 / elapsed_ms + 0.5); + g_dbg.utilization = (double)d->frame_work_acc_us / (double)elapsed_us; + g_dbg.frames_processed = (int)(d->frame_count * 1000000.0 / elapsed_us + 0.5); throttle_publish_debug(d); - d->frame_count_time_ms = now_ms; + d->frame_count_time_us = start_us; d->frame_count = 0; - d->sleep_acc_us = 0; + d->frame_work_acc_us = 0; } d->frame_count++; @@ -252,6 +249,7 @@ static void se_frame(MCPXAPUState *d) mcpx_apu_monitor_frame(d); d->ep_frame_div++; + d->frame_work_acc_us += qemu_clock_get_us(QEMU_CLOCK_REALTIME) - start_us; mcpx_debug_end_frame(); } @@ -326,10 +324,8 @@ static void mcpx_apu_reset_locked(MCPXAPUState *d) mcpx_apu_vp_reset(d); // FIXME: Reset DSP state - memset(d->gp.dsp->core.pram_opcache, 0, - sizeof(d->gp.dsp->core.pram_opcache)); - memset(d->ep.dsp->core.pram_opcache, 0, - sizeof(d->ep.dsp->core.pram_opcache)); + dsp_invalidate_opcache(d->gp.dsp); + dsp_invalidate_opcache(d->ep.dsp); d->set_irq = false; } @@ -357,10 +353,22 @@ static void mcpx_apu_vm_state_change(void *opaque, bool running, RunState state) bql_unlock(); qemu_mutex_lock(&d->lock); mcpx_apu_wait_for_idle(d); + if (d->gp.dsp) { + dsp_sync_to_vm(d->gp.dsp); + } + if (d->ep.dsp) { + dsp_sync_to_vm(d->ep.dsp); + } qemu_mutex_unlock(&d->lock); bql_lock(); } else { qemu_mutex_lock(&d->lock); + if (d->gp.dsp) { + dsp_sync_from_vm(d->gp.dsp); + } + if (d->ep.dsp) { + dsp_sync_from_vm(d->ep.dsp); + } mcpx_apu_resume(d); qemu_mutex_unlock(&d->lock); } @@ -440,6 +448,23 @@ static void mcpx_apu_exitfn(PCIDevice *dev) mcpx_apu_monitor_finalize(d); } +static bool vp_dsp_dma_read_count_needed(void *opaque) +{ + DSPDMAState *s = opaque; + return s->dma_read_count != 0; +} + +static const VMStateDescription vmstate_vp_dsp_dma_read_count = { + .name = "mcpx-apu/dsp-state/dma/dma_read_count", + .version_id = 1, + .minimum_version_id = 1, + .needed = vp_dsp_dma_read_count_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(dma_read_count, DSPDMAState), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_vp_dsp_dma_state = { .name = "mcpx-apu/dsp-state/dma", .version_id = 1, @@ -452,6 +477,10 @@ const VMStateDescription vmstate_vp_dsp_dma_state = { VMSTATE_BOOL(error, DSPDMAState), VMSTATE_BOOL(eol, DSPDMAState), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * const []) { + &vmstate_vp_dsp_dma_read_count, + NULL } }; @@ -460,37 +489,33 @@ const VMStateDescription vmstate_vp_dsp_core_state = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - // FIXME: Remove unnecessary fields - VMSTATE_UINT16(instr_cycle, dsp_core_t), - VMSTATE_UINT32(pc, dsp_core_t), - VMSTATE_UINT32_ARRAY(registers, dsp_core_t, DSP_REG_MAX), - VMSTATE_UINT32_2DARRAY(stack, dsp_core_t, 2, 16), - VMSTATE_UINT32_ARRAY(xram, dsp_core_t, DSP_XRAM_SIZE), - VMSTATE_UINT32_ARRAY(yram, dsp_core_t, DSP_YRAM_SIZE), - VMSTATE_UINT32_ARRAY(pram, dsp_core_t, DSP_PRAM_SIZE), - VMSTATE_UINT32_ARRAY(mixbuffer, dsp_core_t, DSP_MIXBUFFER_SIZE), - VMSTATE_UINT32_ARRAY(periph, dsp_core_t, DSP_PERIPH_SIZE), - VMSTATE_UINT32(loop_rep, dsp_core_t), - VMSTATE_UINT32(pc_on_rep, dsp_core_t), - VMSTATE_UINT16(interrupt_state, dsp_core_t), - VMSTATE_UINT16(interrupt_instr_fetch, dsp_core_t), - VMSTATE_UINT16(interrupt_save_pc, dsp_core_t), - VMSTATE_UINT16(interrupt_counter, dsp_core_t), - VMSTATE_UINT16(interrupt_ipl_to_raise, dsp_core_t), - VMSTATE_UINT16(interrupt_pipeline_count, dsp_core_t), - VMSTATE_INT16_ARRAY(interrupt_ipl, dsp_core_t, 12), - VMSTATE_UINT16_ARRAY(interrupt_is_pending, dsp_core_t, 12), - VMSTATE_UINT32(num_inst, dsp_core_t), - VMSTATE_UINT32(cur_inst_len, dsp_core_t), - VMSTATE_UINT32(cur_inst, dsp_core_t), - VMSTATE_UNUSED(1), - VMSTATE_UINT32(disasm_memory_ptr, dsp_core_t), - VMSTATE_BOOL(exception_debugging, dsp_core_t), - VMSTATE_UINT32(disasm_prev_inst_pc, dsp_core_t), - VMSTATE_BOOL(disasm_is_looping, dsp_core_t), - VMSTATE_UINT32(disasm_cur_inst, dsp_core_t), - VMSTATE_UINT16(disasm_cur_inst_len, dsp_core_t), - VMSTATE_UINT32_ARRAY(disasm_registers_save, dsp_core_t, 64), + VMSTATE_UINT16(instr_cycle, DspCoreState), + VMSTATE_UINT32(pc, DspCoreState), + VMSTATE_UINT32_ARRAY(registers, DspCoreState, DSP_REG_MAX), + VMSTATE_UINT32_2DARRAY(stack, DspCoreState, 2, 16), + VMSTATE_UINT32_ARRAY(xram, DspCoreState, DSP_XRAM_SIZE), + VMSTATE_UINT32_ARRAY(yram, DspCoreState, DSP_YRAM_SIZE), + VMSTATE_UINT32_ARRAY(pram, DspCoreState, DSP_PRAM_SIZE), + VMSTATE_UINT32_ARRAY(mixbuffer, DspCoreState, DSP_MIXBUFFER_SIZE), + VMSTATE_UINT32_ARRAY(periph, DspCoreState, DSP_PERIPH_SIZE), + VMSTATE_UINT32(loop_rep, DspCoreState), + VMSTATE_UINT32(pc_on_rep, DspCoreState), + VMSTATE_UINT16(interrupt_state, DspCoreState), + VMSTATE_UINT16(interrupt_instr_fetch, DspCoreState), + VMSTATE_UINT16(interrupt_save_pc, DspCoreState), + VMSTATE_UINT16(interrupt_counter, DspCoreState), + VMSTATE_UINT16(interrupt_ipl_to_raise, DspCoreState), + VMSTATE_UINT16(interrupt_pipeline_count, DspCoreState), + VMSTATE_INT16_ARRAY(interrupt_ipl, DspCoreState, 12), + VMSTATE_UINT16_ARRAY(interrupt_is_pending, DspCoreState, 12), + VMSTATE_UNUSED(4), /* was num_inst */ + VMSTATE_UINT32(cur_inst_len, DspCoreState), + VMSTATE_UINT32(cur_inst, DspCoreState), + VMSTATE_UNUSED(273), /* was: unused(1) + disasm_memory_ptr(4) + + * exception_debugging(1) + disasm_prev_inst_pc(4) + + * disasm_is_looping(1) + disasm_cur_inst(4) + + * disasm_cur_inst_len(2) + + * disasm_registers_save(256) */ VMSTATE_END_OF_LIST() } }; @@ -500,7 +525,7 @@ const VMStateDescription vmstate_vp_dsp_state = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_STRUCT(core, DSPState, 1, vmstate_vp_dsp_core_state, dsp_core_t), + VMSTATE_STRUCT(core, DSPState, 1, vmstate_vp_dsp_core_state, DspCoreState), VMSTATE_STRUCT(dma, DSPState, 1, vmstate_vp_dsp_dma_state, DSPDMAState), VMSTATE_INT32(save_cycles, DSPState), VMSTATE_UINT32(interrupts, DSPState), diff --git a/hw/xbox/mcpx/apu/apu_int.h b/hw/xbox/mcpx/apu/apu_int.h index 1e81605590..ff13d42994 100644 --- a/hw/xbox/mcpx/apu/apu_int.h +++ b/hw/xbox/mcpx/apu/apu_int.h @@ -96,9 +96,9 @@ typedef struct MCPXAPUState { uint32_t regs[0x20000]; int ep_frame_div; - int sleep_acc_us; + int frame_work_acc_us; int frame_count; - int64_t frame_count_time_ms; + int64_t frame_count_time_us; int64_t next_frame_time_us; struct { diff --git a/hw/xbox/mcpx/apu/dsp/debug.c b/hw/xbox/mcpx/apu/dsp/debug.c deleted file mode 100644 index e41a222bf9..0000000000 --- a/hw/xbox/mcpx/apu/dsp/debug.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * MCPX DSP emulator - * - * Copyright (c) 2015 espes - * Copyright (c) 2020-2025 Matt Borgerson - * - * Adapted from Hatari DSP M56001 emulation - * (C) 2001-2008 ARAnyM developer team - * Adaption to Hatari (C) 2008 by Thomas Huth - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "qemu/osdep.h" - -#include -#include -#include -#include - -#include "dsp_cpu.h" -#include "dsp_dma.h" -#include "dsp_state.h" - -#include "dsp.h" -#include "debug.h" - -#if DEBUG_DSP -#define BITMASK(x) ((1<<(x))-1) - -/** - * Output memory values between given addresses in given DSP address space. - * Return next DSP address value. - */ -uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space) -{ - uint32_t mem, value; - - for (mem = dsp_memdump_addr; mem <= dsp_memdump_upper; mem++) { - value = dsp_read_memory(dsp, space, mem); - printf("%04x %06x\n", mem, value); - } - return dsp_memdump_upper+1; -} - -/** - * Show information on DSP core state which isn't - * shown by any of the other commands (dd, dm, dr). - */ -void dsp_info(DSPState* dsp) -{ - int i, j; - const char *stackname[] = { "SSH", "SSL" }; - - printf("DSP core information:\n"); - - for (i = 0; i < ARRAY_SIZE(stackname); i++) { - printf("- %s stack:", stackname[i]); - for (j = 0; j < ARRAY_SIZE(dsp->core.stack[0]); j++) { - printf(" %04x", dsp->core.stack[i][j]); - } - printf("\n"); - } - - printf("- Interrupt IPL:"); - for (i = 0; i < ARRAY_SIZE(dsp->core.interrupt_ipl); i++) { - printf(" %04x", dsp->core.interrupt_ipl[i]); - } - printf("\n"); - - printf("- Pending ints: "); - for (i = 0; i < ARRAY_SIZE(dsp->core.interrupt_is_pending); i++) { - printf(" %04hx", dsp->core.interrupt_is_pending[i]); - } - printf("\n"); -} - -/** - * Show DSP register contents - */ -void dsp_print_registers(DSPState* dsp) -{ - uint32_t i; - - printf("A: A2: %02x A1: %06x A0: %06x\n", - dsp->core.registers[DSP_REG_A2], dsp->core.registers[DSP_REG_A1], dsp->core.registers[DSP_REG_A0]); - printf("B: B2: %02x B1: %06x B0: %06x\n", - dsp->core.registers[DSP_REG_B2], dsp->core.registers[DSP_REG_B1], dsp->core.registers[DSP_REG_B0]); - - printf("X: X1: %06x X0: %06x\n", dsp->core.registers[DSP_REG_X1], dsp->core.registers[DSP_REG_X0]); - printf("Y: Y1: %06x Y0: %06x\n", dsp->core.registers[DSP_REG_Y1], dsp->core.registers[DSP_REG_Y0]); - - for (i=0; i<8; i++) { - printf("R%01x: %04x N%01x: %04x M%01x: %04x\n", - i, dsp->core.registers[DSP_REG_R0+i], - i, dsp->core.registers[DSP_REG_N0+i], - i, dsp->core.registers[DSP_REG_M0+i]); - } - - printf("LA: %04x LC: %04x PC: %04x\n", dsp->core.registers[DSP_REG_LA], dsp->core.registers[DSP_REG_LC], dsp->core.pc); - printf("SR: %04x OMR: %02x\n", dsp->core.registers[DSP_REG_SR], dsp->core.registers[DSP_REG_OMR]); - printf("SP: %02x SSH: %04x SSL: %04x\n", - dsp->core.registers[DSP_REG_SP], dsp->core.registers[DSP_REG_SSH], dsp->core.registers[DSP_REG_SSL]); -} - - -/** - * Get given DSP register address and required bit mask. - * Works for A0-2, B0-2, LA, LC, M0-7, N0-7, R0-7, X0-1, Y0-1, PC, SR, SP, - * OMR, SSH & SSL registers, but note that the SP, SSH & SSL registers - * need special handling (in DSP*SetRegister()) when they are set. - * Return the register width in bits or zero for an error. - */ -int dsp_get_register_address(DSPState* dsp, const char *regname, uint32_t **addr, uint32_t *mask) -{ -#define MAX_REGNAME_LEN 4 - typedef struct { - const char name[MAX_REGNAME_LEN]; - uint32_t *addr; - size_t bits; - uint32_t mask; - } reg_addr_t; - - /* sorted by name so that this can be bisected */ - const reg_addr_t registers[] = { - - /* 56-bit A register */ - { "A0", &dsp->core.registers[DSP_REG_A0], 32, BITMASK(24) }, - { "A1", &dsp->core.registers[DSP_REG_A1], 32, BITMASK(24) }, - { "A2", &dsp->core.registers[DSP_REG_A2], 32, BITMASK(8) }, - - /* 56-bit B register */ - { "B0", &dsp->core.registers[DSP_REG_B0], 32, BITMASK(24) }, - { "B1", &dsp->core.registers[DSP_REG_B1], 32, BITMASK(24) }, - { "B2", &dsp->core.registers[DSP_REG_B2], 32, BITMASK(8) }, - - /* 16-bit LA & LC registers */ - { "LA", &dsp->core.registers[DSP_REG_LA], 32, BITMASK(16) }, - { "LC", &dsp->core.registers[DSP_REG_LC], 32, BITMASK(16) }, - - /* 16-bit M registers */ - { "M0", &dsp->core.registers[DSP_REG_M0], 32, BITMASK(16) }, - { "M1", &dsp->core.registers[DSP_REG_M1], 32, BITMASK(16) }, - { "M2", &dsp->core.registers[DSP_REG_M2], 32, BITMASK(16) }, - { "M3", &dsp->core.registers[DSP_REG_M3], 32, BITMASK(16) }, - { "M4", &dsp->core.registers[DSP_REG_M4], 32, BITMASK(16) }, - { "M5", &dsp->core.registers[DSP_REG_M5], 32, BITMASK(16) }, - { "M6", &dsp->core.registers[DSP_REG_M6], 32, BITMASK(16) }, - { "M7", &dsp->core.registers[DSP_REG_M7], 32, BITMASK(16) }, - - /* 16-bit N registers */ - { "N0", &dsp->core.registers[DSP_REG_N0], 32, BITMASK(16) }, - { "N1", &dsp->core.registers[DSP_REG_N1], 32, BITMASK(16) }, - { "N2", &dsp->core.registers[DSP_REG_N2], 32, BITMASK(16) }, - { "N3", &dsp->core.registers[DSP_REG_N3], 32, BITMASK(16) }, - { "N4", &dsp->core.registers[DSP_REG_N4], 32, BITMASK(16) }, - { "N5", &dsp->core.registers[DSP_REG_N5], 32, BITMASK(16) }, - { "N6", &dsp->core.registers[DSP_REG_N6], 32, BITMASK(16) }, - { "N7", &dsp->core.registers[DSP_REG_N7], 32, BITMASK(16) }, - - { "OMR", &dsp->core.registers[DSP_REG_OMR], 32, 0x5f }, - - /* 16-bit program counter */ - { "PC", (uint32_t*)(&dsp->core.pc), 24, BITMASK(24) }, - - /* 16-bit DSP R (address) registers */ - { "R0", &dsp->core.registers[DSP_REG_R0], 32, BITMASK(16) }, - { "R1", &dsp->core.registers[DSP_REG_R1], 32, BITMASK(16) }, - { "R2", &dsp->core.registers[DSP_REG_R2], 32, BITMASK(16) }, - { "R3", &dsp->core.registers[DSP_REG_R3], 32, BITMASK(16) }, - { "R4", &dsp->core.registers[DSP_REG_R4], 32, BITMASK(16) }, - { "R5", &dsp->core.registers[DSP_REG_R5], 32, BITMASK(16) }, - { "R6", &dsp->core.registers[DSP_REG_R6], 32, BITMASK(16) }, - { "R7", &dsp->core.registers[DSP_REG_R7], 32, BITMASK(16) }, - - { "SSH", &dsp->core.registers[DSP_REG_SSH], 32, BITMASK(16) }, - { "SSL", &dsp->core.registers[DSP_REG_SSL], 32, BITMASK(16) }, - { "SP", &dsp->core.registers[DSP_REG_SP], 32, BITMASK(6) }, - - /* 16-bit status register */ - { "SR", &dsp->core.registers[DSP_REG_SR], 32, 0xefff }, - - /* 48-bit X register */ - { "X0", &dsp->core.registers[DSP_REG_X0], 32, BITMASK(24) }, - { "X1", &dsp->core.registers[DSP_REG_X1], 32, BITMASK(24) }, - - /* 48-bit Y register */ - { "Y0", &dsp->core.registers[DSP_REG_Y0], 32, BITMASK(24) }, - { "Y1", &dsp->core.registers[DSP_REG_Y1], 32, BITMASK(24) } - }; - /* left, right, middle, direction */ - int l, r, m, dir = 0; - unsigned int i, len; - char reg[MAX_REGNAME_LEN]; - - for (i = 0; i < sizeof(reg) && regname[i]; i++) { - reg[i] = toupper(regname[i]); - } - if (i < 2 || regname[i]) { - /* too short or longer than any of the names */ - return 0; - } - len = i; - - /* bisect */ - l = 0; - r = ARRAY_SIZE(registers) - 1; - do { - m = (l+r) >> 1; - for (i = 0; i < len; i++) { - dir = (int)reg[i] - registers[m].name[i]; - if (dir) { - break; - } - } - if (dir == 0) { - *addr = registers[m].addr; - *mask = registers[m].mask; - return registers[m].bits; - } - if (dir < 0) { - r = m-1; - } else { - l = m+1; - } - } while (l <= r); -#undef MAX_REGNAME_LEN - return 0; -} - - -/** - * Set given DSP register value, return false if unknown register given - */ -bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value) -{ - uint32_t *addr, mask, sp_value; - int bits; - - /* first check registers needing special handling... */ - if (arg[0]=='S' || arg[0]=='s') { - if (arg[1]=='P' || arg[1]=='p') { - dsp->core.registers[DSP_REG_SP] = value & BITMASK(6); - value &= BITMASK(4); - dsp->core.registers[DSP_REG_SSH] = dsp->core.stack[0][value]; - dsp->core.registers[DSP_REG_SSL] = dsp->core.stack[1][value]; - return true; - } - if (arg[1]=='S' || arg[1]=='s') { - sp_value = dsp->core.registers[DSP_REG_SP] & BITMASK(4); - if (arg[2]=='H' || arg[2]=='h') { - if (sp_value == 0) { - dsp->core.registers[DSP_REG_SSH] = 0; - dsp->core.stack[0][sp_value] = 0; - } else { - dsp->core.registers[DSP_REG_SSH] = value & BITMASK(16); - dsp->core.stack[0][sp_value] = value & BITMASK(16); - } - return true; - } - if (arg[2]=='L' || arg[2]=='l') { - if (sp_value == 0) { - dsp->core.registers[DSP_REG_SSL] = 0; - dsp->core.stack[1][sp_value] = 0; - } else { - dsp->core.registers[DSP_REG_SSL] = value & BITMASK(16); - dsp->core.stack[1][sp_value] = value & BITMASK(16); - } - return true; - } - } - } - - /* ...then registers where address & mask are enough */ - bits = dsp_get_register_address(dsp, arg, &addr, &mask); - switch (bits) { - case 32: - *addr = value & mask; - return true; - case 16: - *(uint16_t*)addr = value & mask; - return true; - } - return false; -} - -#endif diff --git a/hw/xbox/mcpx/apu/dsp/debug.h b/hw/xbox/mcpx/apu/dsp/debug.h index befef229b1..5507c01f85 100644 --- a/hw/xbox/mcpx/apu/dsp/debug.h +++ b/hw/xbox/mcpx/apu/dsp/debug.h @@ -25,10 +25,6 @@ #define DEBUG_DSP 0 #endif -#define TRACE_DSP_DISASM 0 -#define TRACE_DSP_DISASM_REG 0 -#define TRACE_DSP_DISASM_MEM 0 - #define DPRINTF(fmt, ...) \ do { \ if (DEBUG_DSP) fprintf(stderr, fmt, ## __VA_ARGS__); \ diff --git a/hw/xbox/mcpx/apu/dsp/dsp.c b/hw/xbox/mcpx/apu/dsp/dsp.c index 00556b872a..0d844af07d 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp.c +++ b/hw/xbox/mcpx/apu/dsp/dsp.c @@ -24,61 +24,27 @@ */ #include "qemu/osdep.h" -#include "dsp_cpu.h" -#include "dsp_dma.h" -#include "dsp_state.h" -#include "dsp.h" -#include "debug.h" +#include "dsp_internal.h" #include "trace.h" +#include "ui/xemu-settings.h" /* Defines */ -#define BITMASK(x) ((1<<(x))-1) +#define BITMASK(x) ((1 << (x)) - 1) #define INTERRUPT_ABORT_FRAME (1 << 0) #define INTERRUPT_START_FRAME (1 << 1) #define INTERRUPT_DMA_EOL (1 << 7) -static uint32_t read_peripheral(dsp_core_t* core, uint32_t address); -static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value); +static int g_gp_frame_count = 0; -DSPState *dsp_init(void *rw_opaque, - dsp_scratch_rw_func scratch_rw, - dsp_fifo_rw_func fifo_rw) +/* + * Shared peripheral I/O helpers, used by both backends via callbacks. + */ + +uint32_t read_peripheral(DSPState *dsp, uint32_t address) { - DPRINTF("dsp_init\n"); - - DSPState* dsp = (DSPState*)malloc(sizeof(DSPState)); - memset(dsp, 0, sizeof(*dsp)); - - dsp->core.read_peripheral = read_peripheral; - dsp->core.write_peripheral = write_peripheral; - - dsp->dma.core = &dsp->core; - dsp->dma.rw_opaque = rw_opaque; - dsp->dma.scratch_rw = scratch_rw; - dsp->dma.fifo_rw = fifo_rw; - - dsp_reset(dsp); - - return dsp; -} - -void dsp_reset(DSPState* dsp) -{ - dsp56k_reset_cpu(&dsp->core); - dsp->save_cycles = 0; -} - -void dsp_destroy(DSPState* dsp) -{ - free(dsp); -} - -static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) { - DSPState* dsp = container_of(core, DSPState, core); - uint32_t v = 0xababa; - switch(address) { + switch (address) { case 0xFFFFB3: v = 0; // core->num_inst; // ?? break; @@ -106,13 +72,12 @@ static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) { return v; } -static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) { - DSPState* dsp = container_of(core, DSPState, core); - - switch(address) { +void write_peripheral(DSPState *dsp, uint32_t address, uint32_t value) +{ + switch (address) { case 0xFFFFC4: if (value & 1) { - core->is_idle = true; + dsp_set_halt_requested(dsp, true); } break; case 0xFFFFC5: @@ -138,105 +103,128 @@ static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) trace_dsp_write_peripheral(address, value); } - -void dsp_step(DSPState* dsp) -{ - dsp56k_execute_instruction(&dsp->core); -} - -void dsp_run(DSPState* dsp, int cycles) -{ - dsp->save_cycles += cycles; - - if (dsp->save_cycles <= 0) return; - - int dma_timer = 0; - - while (dsp->save_cycles > 0) - { - dsp56k_execute_instruction(&dsp->core); - dsp->save_cycles -= dsp->core.instr_cycle; - dsp->core.cycle_count++; - - if (dsp->dma.control & DMA_CONTROL_RUNNING) { - dma_timer++; - } - - if (dma_timer > 2) { - dma_timer = 0; - dsp->dma.control &= ~DMA_CONTROL_RUNNING; - dsp->dma.control |= DMA_CONTROL_STOPPED; - } - - if (dsp->core.is_idle) break; - } - - /* FIXME: DMA timing be done cleaner. Xbox enables running - * then polls to make sure its running. But we complete DMA instantaneously, - * so when is it supposed to be signaled that it stopped? Maybe just wait at - * least one cycle? How long does hardware wait? - */ -} - -void dsp_bootstrap(DSPState* dsp) -{ - // scratch memory is dma'd in to pram by the bootrom - dsp->dma.scratch_rw(dsp->dma.rw_opaque, - (uint8_t*)dsp->core.pram, 0, 0x800*4, false); - for (int i = 0; i < 0x800; i++) { - if (dsp->core.pram[i] & 0xff000000) { - DPRINTF("Bootstrap %04x: %08x\n", i, dsp->core.pram[i]); - dsp->core.pram[i] &= 0x00ffffff; - } - } - memset(dsp->core.pram_opcache, 0, sizeof(dsp->core.pram_opcache)); -} - -void dsp_start_frame(DSPState* dsp) +void dsp_start_frame_impl(DSPState *dsp) { dsp->interrupts |= INTERRUPT_START_FRAME; } -uint32_t dsp_read_memory(DSPState* dsp, char space, uint32_t address) +DSPState *dsp_init(void *rw_opaque, dsp_scratch_rw_func scratch_rw, + dsp_fifo_rw_func fifo_rw, bool is_gp) { - int space_id; + DSPState *dsp = g_new0(DSPState, 1); + dsp->is_gp = is_gp; + dsp->core.is_gp = is_gp; - switch (space) { - case 'X': - space_id = DSP_SPACE_X; - break; - case 'Y': - space_id = DSP_SPACE_Y; - break; - case 'P': - space_id = DSP_SPACE_P; - break; - default: - assert(!"Invalid dsp space when reading from memory"); - return 0; + dsp->dma.rw_opaque = rw_opaque; + dsp->dma.scratch_rw = scratch_rw; + dsp->dma.fifo_rw = fifo_rw; + + if (g_config.audio.use_dsp_jit) { + dsp_jit_init(dsp); + } else { + dsp_c_init(dsp); } - return dsp56k_read_memory(&dsp->core, space_id, address); + dsp_reset(dsp); + + return dsp; } -void dsp_write_memory(DSPState* dsp, char space, uint32_t address, uint32_t value) +void dsp_destroy(DSPState *dsp) { - int space_id; + dsp->ops->finalize(dsp); + g_free(dsp); +} - switch (space) { - case 'X': - space_id = DSP_SPACE_X; - break; - case 'Y': - space_id = DSP_SPACE_Y; - break; - case 'P': - space_id = DSP_SPACE_P; - break; - default: - assert(!"Invalid dsp space when writing to memory"); +void dsp_reset(DSPState *dsp) +{ + dsp->ops->reset(dsp); +} + +void dsp_step(DSPState *dsp) +{ + dsp->ops->step(dsp); +} + +void dsp_run(DSPState *dsp, int cycles) +{ + dsp->ops->run(dsp, cycles); +} + +void dsp_bootstrap(DSPState *dsp) +{ + dsp->ops->bootstrap(dsp); +} + +void dsp_start_frame(DSPState *dsp) +{ + if (dsp->is_gp) { + g_gp_frame_count++; + } + dsp->ops->start_frame(dsp); +} + +uint32_t dsp_read_memory(DSPState *dsp, char space, uint32_t address) +{ + return dsp->ops->read_memory(dsp, space, address); +} + +void dsp_write_memory(DSPState *dsp, char space, uint32_t address, + uint32_t value) +{ + dsp->ops->write_memory(dsp, space, address, value); +} + +bool dsp_get_halt_requested(DSPState *dsp) +{ + return dsp->ops->get_halt_requested(dsp); +} + +void dsp_set_halt_requested(DSPState *dsp, bool idle) +{ + dsp->ops->set_halt_requested(dsp, idle); +} + +uint32_t dsp_get_cycle_count(DSPState *dsp) +{ + return dsp->ops->get_cycle_count(dsp); +} + +void dsp_set_cycle_count(DSPState *dsp, uint32_t count) +{ + dsp->ops->set_cycle_count(dsp, count); +} + +void dsp_invalidate_opcache(DSPState *dsp) +{ + dsp->ops->invalidate_opcache(dsp); +} + +void dsp_sync_to_vm(DSPState *dsp) +{ + dsp->ops->sync_to_vm(dsp); +} + +void dsp_sync_from_vm(DSPState *dsp) +{ + dsp->ops->sync_from_vm(dsp); +} + +void dsp_set_engine(DSPState *dsp, bool use_jit) +{ + bool currently_jit = (dsp->ops == &jit_dsp_ops); + if (use_jit == currently_jit) { return; } - dsp56k_write_memory(&dsp->core, space_id, address, value); + dsp_sync_to_vm(dsp); + dsp->ops->finalize(dsp); + + if (use_jit) { + dsp_jit_init(dsp); + } else { + dsp_c_init(dsp); + } + + dsp_sync_from_vm(dsp); } diff --git a/hw/xbox/mcpx/apu/dsp/dsp.h b/hw/xbox/mcpx/apu/dsp/dsp.h index d85e03d55e..8ed345397e 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp.h +++ b/hw/xbox/mcpx/apu/dsp/dsp.h @@ -1,22 +1,22 @@ /* * MCPX DSP emulator - + * * Copyright (c) 2015 espes - + * * Adapted from Hatari DSP M56001 emulation * (C) 2001-2008 ARAnyM developer team * Adaption to Hatari (C) 2008 by Thomas Huth - + * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -27,35 +27,113 @@ #include #include -#include + +#include "interp/dsp_cpu_regs.h" +#include "dsp_dma.h" typedef struct DSPState DSPState; -typedef void (*dsp_scratch_rw_func)( - void *opaque, uint8_t *ptr, uint32_t addr, size_t len, bool dir); -typedef void (*dsp_fifo_rw_func)( - void *opaque, uint8_t *ptr, unsigned int index, size_t len, bool dir); +typedef struct DSPOps { + void (*finalize)(DSPState *dsp); + void (*reset)(DSPState *dsp); + void (*step)(DSPState *dsp); + void (*run)(DSPState *dsp, int cycles); + void (*bootstrap)(DSPState *dsp); + void (*start_frame)(DSPState *dsp); + uint32_t (*read_memory)(DSPState *dsp, char space, uint32_t addr); + void (*write_memory)(DSPState *dsp, char space, uint32_t addr, + uint32_t value); + bool (*get_halt_requested)(DSPState *dsp); + void (*set_halt_requested)(DSPState *dsp, bool idle); + uint32_t (*get_cycle_count)(DSPState *dsp); + void (*set_cycle_count)(DSPState *dsp, uint32_t count); + void (*invalidate_opcache)(DSPState *dsp); + void (*sync_to_vm)(DSPState *dsp); + void (*sync_from_vm)(DSPState *dsp); +} DSPOps; -DSPState *dsp_init(void *rw_opaque, - dsp_scratch_rw_func scratch_rw, - dsp_fifo_rw_func fifo_rw); -void dsp_destroy(DSPState* dsp); -void dsp_reset(DSPState* dsp); +/* + * Shared VM state for save/load and backend synchronization. + * Both the C interpreter and JIT backends sync to/from this struct. + * + * TODO: This struct mirrors the old C interpreter's dsp_core_t layout for + * snapshot compatibility. It uses 16-bit interrupt fields and only 4 interrupt + * slots, losing fidelity when saving JIT state (which has 24-bit addresses and + * 128 IVT slots). Once the C interpreter is removed, simplify this to match + * the JIT's native state and bump the vmstate version. + */ +typedef struct DspCoreState { + uint32_t pc; + uint32_t registers[DSP_REG_MAX]; + uint32_t stack[2][16]; -void dsp_step(DSPState* dsp); -void dsp_run(DSPState* dsp, int cycles); + uint32_t xram[DSP_XRAM_SIZE]; + uint32_t yram[DSP_YRAM_SIZE]; + uint32_t pram[DSP_PRAM_SIZE]; + uint32_t mixbuffer[DSP_MIXBUFFER_SIZE]; + uint32_t periph[DSP_PERIPH_SIZE]; -void dsp_bootstrap(DSPState* dsp); -void dsp_start_frame(DSPState* dsp); + uint32_t cycle_count; + uint16_t instr_cycle; + bool halt_requested; + bool is_gp; -uint32_t dsp_read_memory(DSPState* dsp, char space, uint32_t addr); -void dsp_write_memory(DSPState* dsp, char space, uint32_t address, uint32_t value); + uint32_t loop_rep; + uint32_t pc_on_rep; + uint32_t cur_inst; + uint32_t cur_inst_len; -void dsp_info(DSPState* dsp); -void dsp_print_registers(DSPState* dsp); -int dsp_get_register_address(DSPState* dsp, const char *arg, uint32_t **addr, uint32_t *mask); -uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space); -uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr); -bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value); + uint16_t interrupt_state; + uint16_t interrupt_instr_fetch; + uint16_t interrupt_save_pc; + uint16_t interrupt_counter; + uint16_t interrupt_ipl_to_raise; + uint16_t interrupt_pipeline_count; + int16_t interrupt_ipl[12]; /* only [0..3] used; size 12 for snapshot compat */ + uint16_t interrupt_is_pending[12]; /* only [0..3] used; size 12 for snapshot compat */ +} DspCoreState; + +struct DSPState { + const DSPOps *ops; + + DspCoreState core; + DSPDMAState dma; + int save_cycles; + + uint32_t interrupts; + + bool is_gp; + + void *backend; +}; + +DSPState *dsp_init(void *rw_opaque, dsp_scratch_rw_func scratch_rw, + dsp_fifo_rw_func fifo_rw, bool is_gp); +void dsp_destroy(DSPState *dsp); +void dsp_reset(DSPState *dsp); + +void dsp_step(DSPState *dsp); +void dsp_run(DSPState *dsp, int cycles); + +void dsp_bootstrap(DSPState *dsp); +void dsp_start_frame(DSPState *dsp); + +uint32_t dsp_read_memory(DSPState *dsp, char space, uint32_t addr); +void dsp_write_memory(DSPState *dsp, char space, uint32_t address, + uint32_t value); + +/* Accessor functions for backend-independent state access */ +bool dsp_get_halt_requested(DSPState *dsp); +void dsp_set_halt_requested(DSPState *dsp, bool idle); +uint32_t dsp_get_cycle_count(DSPState *dsp); +void dsp_set_cycle_count(DSPState *dsp, uint32_t count); +void dsp_invalidate_opcache(DSPState *dsp); + +/* Backend synchronization - sync backend state to/from DspCoreState */ +void dsp_sync_to_vm(DSPState *dsp); +void dsp_sync_from_vm(DSPState *dsp); + +/* Engine switching */ +void dsp_set_engine(DSPState *dsp, bool use_jit); #endif /* DSP_H */ diff --git a/hw/xbox/mcpx/apu/dsp/dsp_c.c b/hw/xbox/mcpx/apu/dsp/dsp_c.c new file mode 100644 index 0000000000..13b3710c68 --- /dev/null +++ b/hw/xbox/mcpx/apu/dsp/dsp_c.c @@ -0,0 +1,299 @@ +/* + * MCPX DSP emulator - C interpreter backend + * + * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson + * + * Adapted from Hatari DSP M56001 emulation + * (C) 2001-2008 ARAnyM developer team + * Adaption to Hatari (C) 2008 by Thomas Huth + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "qemu/osdep.h" +#include "dsp_internal.h" +#include "interp/dsp_cpu.h" +#include "debug.h" + +static dsp_core_t *c_core(DSPState *dsp) +{ + return (dsp_core_t *)dsp->backend; +} + +static uint32_t c_dma_mem_read(void *opaque, int space, uint32_t addr) +{ + return dsp56k_read_memory((dsp_core_t *)opaque, space, addr); +} + +static void c_dma_mem_write(void *opaque, int space, uint32_t addr, + uint32_t value) +{ + dsp56k_write_memory((dsp_core_t *)opaque, space, addr, value); +} + +static uint32_t c_read_peripheral(dsp_core_t *core, uint32_t address) +{ + return read_peripheral((DSPState *)core->opaque, address); +} + +static void c_write_peripheral(dsp_core_t *core, uint32_t address, + uint32_t value) +{ + write_peripheral((DSPState *)core->opaque, address, value); +} + +static void dsp_c_reset(DSPState *dsp) +{ + dsp56k_reset_cpu(c_core(dsp)); + dsp->save_cycles = 0; +} + +static void dsp_c_step(DSPState *dsp) +{ + dsp56k_execute_instruction(c_core(dsp)); +} + +static void dsp_c_run(DSPState *dsp, int cycles) +{ + dsp_core_t *core = c_core(dsp); + + dsp->save_cycles += cycles; + + if (dsp->save_cycles <= 0) + return; + + while (dsp->save_cycles > 0) { + dsp56k_execute_instruction(core); + dsp->save_cycles -= core->instr_cycle; + core->cycle_count += core->instr_cycle; + + if (core->is_idle) { + break; + } + } +} + +static void dsp_c_bootstrap(DSPState *dsp) +{ + dsp_core_t *core = c_core(dsp); + + // scratch memory is dma'd in to pram by the bootrom + dsp->dma.scratch_rw(dsp->dma.rw_opaque, (uint8_t *)core->pram, 0, 0x800 * 4, + false); + for (int i = 0; i < 0x800; i++) { + if (core->pram[i] & 0xff000000) { + DPRINTF("Bootstrap %04x: %08x\n", i, core->pram[i]); + core->pram[i] &= 0x00ffffff; + } + } + memset(core->pram_opcache, 0, sizeof(core->pram_opcache)); +} + +static uint32_t dsp_c_read_memory(DSPState *dsp, char space, uint32_t address) +{ + int space_id; + + switch (space) { + case 'X': + space_id = DSP_SPACE_X; + break; + case 'Y': + space_id = DSP_SPACE_Y; + break; + case 'P': + space_id = DSP_SPACE_P; + break; + default: + assert(!"Invalid dsp space when reading from memory"); + return 0; + } + + return dsp56k_read_memory(c_core(dsp), space_id, address); +} + +static void dsp_c_write_memory(DSPState *dsp, char space, uint32_t address, + uint32_t value) +{ + int space_id; + + switch (space) { + case 'X': + space_id = DSP_SPACE_X; + break; + case 'Y': + space_id = DSP_SPACE_Y; + break; + case 'P': + space_id = DSP_SPACE_P; + break; + default: + assert(!"Invalid dsp space when writing to memory"); + return; + } + + dsp56k_write_memory(c_core(dsp), space_id, address, value); +} + +static bool dsp_c_get_halt_requested(DSPState *dsp) +{ + return c_core(dsp)->is_idle; +} + +static void dsp_c_set_halt_requested(DSPState *dsp, bool halt) +{ + c_core(dsp)->is_idle = halt; +} + +static uint32_t dsp_c_get_cycle_count(DSPState *dsp) +{ + return c_core(dsp)->cycle_count; +} + +static void dsp_c_set_cycle_count(DSPState *dsp, uint32_t count) +{ + c_core(dsp)->cycle_count = count; +} + +static void dsp_c_invalidate_opcache(DSPState *dsp) +{ + memset(c_core(dsp)->pram_opcache, 0, sizeof(c_core(dsp)->pram_opcache)); +} + +/* + * Sync: C interpreter -> DspCoreState (before VM save / debug) + */ +static void dsp_c_sync_to_vm(DSPState *dsp) +{ + dsp_core_t *core = c_core(dsp); + DspCoreState *vm = &dsp->core; + + vm->pc = core->pc; + vm->cycle_count = core->cycle_count; + vm->instr_cycle = core->instr_cycle; + vm->halt_requested = core->is_idle; + vm->is_gp = core->is_gp; + vm->loop_rep = core->loop_rep; + vm->pc_on_rep = core->pc_on_rep; + vm->cur_inst = core->cur_inst; + vm->cur_inst_len = core->cur_inst_len; + + memcpy(vm->registers, core->registers, sizeof(vm->registers)); + memcpy(vm->stack, core->stack, sizeof(vm->stack)); + memcpy(vm->xram, core->xram, sizeof(vm->xram)); + memcpy(vm->yram, core->yram, sizeof(vm->yram)); + memcpy(vm->pram, core->pram, sizeof(vm->pram)); + memcpy(vm->mixbuffer, core->mixbuffer, sizeof(vm->mixbuffer)); + memcpy(vm->periph, core->periph, sizeof(vm->periph)); + + vm->interrupt_state = core->interrupt_state; + vm->interrupt_instr_fetch = core->interrupt_instr_fetch; + vm->interrupt_save_pc = core->interrupt_save_pc; + vm->interrupt_counter = core->interrupt_counter; + vm->interrupt_ipl_to_raise = core->interrupt_ipl_to_raise; + vm->interrupt_pipeline_count = core->interrupt_pipeline_count; + memcpy(vm->interrupt_ipl, core->interrupt_ipl, sizeof(core->interrupt_ipl)); + memcpy(vm->interrupt_is_pending, core->interrupt_is_pending, + sizeof(core->interrupt_is_pending)); +} + +/* + * Sync: DspCoreState -> C interpreter (after VM load / engine switch) + */ +static void dsp_c_sync_from_vm(DSPState *dsp) +{ + dsp_core_t *core = c_core(dsp); + DspCoreState *vm = &dsp->core; + + core->pc = vm->pc; + core->cycle_count = vm->cycle_count; + core->instr_cycle = vm->instr_cycle; + core->is_idle = vm->halt_requested; + core->is_gp = vm->is_gp; + core->loop_rep = vm->loop_rep; + core->pc_on_rep = vm->pc_on_rep; + core->cur_inst = vm->cur_inst; + core->cur_inst_len = vm->cur_inst_len; + + memcpy(core->registers, vm->registers, sizeof(vm->registers)); + memcpy(core->stack, vm->stack, sizeof(vm->stack)); + memcpy(core->xram, vm->xram, sizeof(vm->xram)); + memcpy(core->yram, vm->yram, sizeof(vm->yram)); + memcpy(core->pram, vm->pram, sizeof(vm->pram)); + memcpy(core->mixbuffer, vm->mixbuffer, sizeof(vm->mixbuffer)); + memcpy(core->periph, vm->periph, sizeof(vm->periph)); + + core->interrupt_state = vm->interrupt_state; + core->interrupt_instr_fetch = vm->interrupt_instr_fetch; + core->interrupt_save_pc = vm->interrupt_save_pc; + core->interrupt_counter = vm->interrupt_counter; + core->interrupt_ipl_to_raise = vm->interrupt_ipl_to_raise; + core->interrupt_pipeline_count = vm->interrupt_pipeline_count; + memcpy(core->interrupt_ipl, vm->interrupt_ipl, sizeof(core->interrupt_ipl)); + memcpy(core->interrupt_is_pending, vm->interrupt_is_pending, + sizeof(core->interrupt_is_pending)); + + memset(core->pram_opcache, 0, sizeof(core->pram_opcache)); +} + +void dsp_c_init(DSPState *dsp) +{ + dsp_core_t *core = g_new0(dsp_core_t, 1); + core->opaque = dsp; + core->read_peripheral = c_read_peripheral; + core->write_peripheral = c_write_peripheral; + + dsp->backend = core; + dsp->ops = &c_dsp_ops; + + dsp->dma.mem_opaque = core; + dsp->dma.mem_read = c_dma_mem_read; + dsp->dma.mem_write = c_dma_mem_write; + + /* Ensure the interpreter's opcode decoder tables are initialized. + * dsp56k_reset_cpu populates the static nonparallel_matches[] array + * on first call. The runtime state it writes (registers, PC, etc.) + * will be overwritten by the subsequent sync_from_vm. */ + dsp56k_reset_cpu(core); + + memset(core->pram, 0xCA, DSP_PRAM_SIZE * sizeof(uint32_t)); + memset(core->xram, 0xCA, DSP_XRAM_SIZE * sizeof(uint32_t)); + memset(core->yram, 0xCA, DSP_YRAM_SIZE * sizeof(uint32_t)); + dsp->ops->invalidate_opcache(dsp); +} + +static void dsp_c_finalize(DSPState *dsp) +{ + g_free(dsp->backend); + dsp->backend = NULL; +} + +const DSPOps c_dsp_ops = { + .bootstrap = dsp_c_bootstrap, + .finalize = dsp_c_finalize, + .get_cycle_count = dsp_c_get_cycle_count, + .get_halt_requested = dsp_c_get_halt_requested, + .invalidate_opcache = dsp_c_invalidate_opcache, + .read_memory = dsp_c_read_memory, + .reset = dsp_c_reset, + .run = dsp_c_run, + .set_cycle_count = dsp_c_set_cycle_count, + .set_halt_requested = dsp_c_set_halt_requested, + .start_frame = dsp_start_frame_impl, + .step = dsp_c_step, + .sync_from_vm = dsp_c_sync_from_vm, + .sync_to_vm = dsp_c_sync_to_vm, + .write_memory = dsp_c_write_memory, +}; diff --git a/hw/xbox/mcpx/apu/dsp/dsp_dma.c b/hw/xbox/mcpx/apu/dsp/dsp_dma.c index b9274bcb80..ba512f031e 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp_dma.c +++ b/hw/xbox/mcpx/apu/dsp/dsp_dma.c @@ -20,9 +20,10 @@ #include "qemu/osdep.h" #include "qemu/compiler.h" +#include "debug.h" #include "dsp_dma.h" #include "dsp_dma_regs.h" -#include "dsp_state.h" +#include "interp/dsp_cpu_regs.h" #ifdef DEBUG @@ -127,13 +128,14 @@ static void dsp_dma_run(DSPDMAState *s) assert(!"Dsp dma space address out of range"); } - uint32_t next_block = dsp56k_read_memory(s->core, block_space, block_addr); - uint32_t control = dsp56k_read_memory(s->core, block_space, block_addr+1); - uint32_t count = dsp56k_read_memory(s->core, block_space, block_addr+2); - uint32_t dsp_offset = dsp56k_read_memory(s->core, block_space, block_addr+3); - uint32_t scratch_offset = dsp56k_read_memory(s->core, block_space, block_addr+4); - uint32_t scratch_base = dsp56k_read_memory(s->core, block_space, block_addr+5); - uint32_t scratch_size = dsp56k_read_memory(s->core, block_space, block_addr+6)+1; + uint32_t next_block = s->mem_read(s->mem_opaque, block_space, block_addr); + uint32_t control = s->mem_read(s->mem_opaque, block_space, block_addr+1); + uint32_t count = s->mem_read(s->mem_opaque, block_space, block_addr+2); + + uint32_t dsp_offset = s->mem_read(s->mem_opaque, block_space, block_addr+3); + uint32_t scratch_offset = s->mem_read(s->mem_opaque, block_space, block_addr+4); + uint32_t scratch_base = s->mem_read(s->mem_opaque, block_space, block_addr+5); + uint32_t scratch_size = s->mem_read(s->mem_opaque, block_space, block_addr+6)+1; s->next_block = next_block; if (s->next_block & NODE_POINTER_EOL) { @@ -164,6 +166,10 @@ static void dsp_dma_run(DSPDMAState *s) // bool lsb = (format == 6); // FIXME switch(format) { + case 0: + item_size = 1; + item_mask = 0x000000ff; + break; case 1: item_size = 2; item_mask = 0x0000ffff; @@ -219,7 +225,7 @@ static void dsp_dma_run(DSPDMAState *s) // Interleave samples for (int i = 0; i < block_count; i++) { for (int ch = 0; ch < channel_count; ch++) { - uint32_t v = dsp56k_read_memory(s->core, + uint32_t v = s->mem_read(s->mem_opaque, mem_space, mem_address+ch*block_count+i); switch(item_size) { case 2: @@ -236,7 +242,7 @@ static void dsp_dma_run(DSPDMAState *s) } } else { for (int i = 0; i < count; i++) { - uint32_t v = dsp56k_read_memory(s->core, mem_space, mem_address+i); + uint32_t v = s->mem_read(s->mem_opaque, mem_space, mem_address+i); switch(item_size) { case 2: *(uint16_t*)(scratch_buf + i*2) = v >> 8; @@ -298,12 +304,12 @@ static void dsp_dma_run(DSPDMAState *s) break; } - dsp56k_write_memory(s->core, mem_space, mem_address+i, v); + s->mem_write(s->mem_opaque, mem_space, mem_address+i, v); } } if (buffer_offset_writeback) { - dsp56k_write_memory(s->core, block_space, block_addr+4, scratch_offset); + s->mem_write(s->mem_opaque, block_space, block_addr+4, scratch_offset); } } @@ -315,6 +321,14 @@ uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg) case DMA_CONFIGURATION: return s->configuration; case DMA_CONTROL: + if (s->control & DMA_CONTROL_RUNNING) { + s->dma_read_count++; + if (s->dma_read_count > 2) { + s->control &= ~DMA_CONTROL_RUNNING; + s->control |= DMA_CONTROL_STOPPED; + s->dma_read_count = 0; + } + } return s->control; case DMA_START_BLOCK: return s->start_block; @@ -337,6 +351,7 @@ void dsp_dma_write(DSPDMAState *s, DSPDMARegister reg, uint32_t v) case DMA_CONTROL_ACTION_START: s->control |= DMA_CONTROL_RUNNING; s->control &= ~DMA_CONTROL_STOPPED; + s->dma_read_count = 0; break; case DMA_CONTROL_ACTION_STOP: s->control |= DMA_CONTROL_STOPPED; diff --git a/hw/xbox/mcpx/apu/dsp/dsp_dma.h b/hw/xbox/mcpx/apu/dsp/dsp_dma.h index 7ec300d31d..cbfa114cfa 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp_dma.h +++ b/hw/xbox/mcpx/apu/dsp/dsp_dma.h @@ -22,9 +22,12 @@ #include #include +#include -#include "dsp.h" -#include "dsp_cpu.h" +typedef void (*dsp_scratch_rw_func)( + void *opaque, uint8_t *ptr, uint32_t addr, size_t len, bool dir); +typedef void (*dsp_fifo_rw_func)( + void *opaque, uint8_t *ptr, unsigned int index, size_t len, bool dir); #define DMA_CONTROL_RUNNING (1 << 4) #define DMA_CONTROL_STOPPED (1 << 5) @@ -36,9 +39,17 @@ typedef enum DSPDMARegister { DMA_NEXT_BLOCK, } DSPDMARegister; -typedef struct DSPDMAState { - dsp_core_t* core; +/* Memory access callbacks for backend-agnostic DMA */ +typedef uint32_t (*dsp_dma_mem_read_func)(void *opaque, int space, uint32_t addr); +typedef void (*dsp_dma_mem_write_func)(void *opaque, int space, uint32_t addr, uint32_t value); +typedef struct DSPDMAState { + /* DSP memory access (backend-agnostic) */ + void *mem_opaque; + dsp_dma_mem_read_func mem_read; + dsp_dma_mem_write_func mem_write; + + /* System memory access */ void *rw_opaque; dsp_scratch_rw_func scratch_rw; dsp_fifo_rw_func fifo_rw; @@ -50,6 +61,10 @@ typedef struct DSPDMAState { bool error; bool eol; + + /* DMA completion timer: counts reads of DMA_CONTROL while RUNNING. + * After 3 reads, transitions RUNNING -> STOPPED. */ + uint32_t dma_read_count; } DSPDMAState; uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg); diff --git a/hw/xbox/mcpx/apu/dsp/dsp_internal.h b/hw/xbox/mcpx/apu/dsp/dsp_internal.h new file mode 100644 index 0000000000..e9ea57c16e --- /dev/null +++ b/hw/xbox/mcpx/apu/dsp/dsp_internal.h @@ -0,0 +1,28 @@ +/* + * MCPX DSP emulator - internal declarations + * + * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson + * + * 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. + */ + +#ifndef DSP_INTERNAL_H +#define DSP_INTERNAL_H + +#include "dsp.h" + +uint32_t read_peripheral(DSPState *dsp, uint32_t address); +void write_peripheral(DSPState *dsp, uint32_t address, uint32_t value); +void dsp_start_frame_impl(DSPState *dsp); + +extern const DSPOps c_dsp_ops; +void dsp_c_init(DSPState *dsp); + +extern const DSPOps jit_dsp_ops; +void dsp_jit_init(DSPState *dsp); + +#endif /* DSP_INTERNAL_H */ diff --git a/hw/xbox/mcpx/apu/dsp/dsp_jit.c b/hw/xbox/mcpx/apu/dsp/dsp_jit.c new file mode 100644 index 0000000000..ec89f14b9f --- /dev/null +++ b/hw/xbox/mcpx/apu/dsp/dsp_jit.c @@ -0,0 +1,362 @@ +/* + * MCPX DSP emulator - Rust JIT backend + * + * Copyright (c) 2026 Matt Borgerson + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "qemu/osdep.h" +#include "dsp_internal.h" +#include "debug.h" + +#include + +/* Map C interpreter interrupt indices to architectural IVT slots. + * Architectural slot = vectorAddr / 2 (per DSP56300FM Table 2-2). */ +static const int cinterp_to_arch[4] = { + 0, /* RESET: vec $00, slot 0 */ + 2, /* ILLEGAL: vec $04, slot 2 */ + 1, /* STACK_ERROR: vec $02, slot 1 */ + 4, /* TRAP: vec $08, slot 4 */ +}; + +typedef struct JitBackend { + Dsp56300Jit *jit; + uint32_t *xram; + uint32_t *yram; + uint32_t *pram; +} JitBackend; + +static JitBackend *jit_be(DSPState *dsp) +{ + return (JitBackend *)dsp->backend; +} + +static uint32_t jit_dma_mem_read(void *opaque, int space, uint32_t addr) +{ + return dsp56300_read_memory((const Dsp56300Jit *)opaque, + (Dsp56300MemSpace)space, addr); +} + +static void jit_dma_mem_write(void *opaque, int space, uint32_t addr, + uint32_t value) +{ + dsp56300_write_memory((Dsp56300Jit *)opaque, (Dsp56300MemSpace)space, addr, + value); +} + +static uint32_t jit_read_peripheral(void *opaque, uint32_t address) +{ + return read_peripheral((DSPState *)opaque, address); +} + +static void jit_write_peripheral(void *opaque, uint32_t address, uint32_t value) +{ + write_peripheral((DSPState *)opaque, address, value); +} + +static void dsp_jit_reset(DSPState *dsp) +{ + dsp56300_reset(jit_be(dsp)->jit); +} + +static void dsp_jit_step(DSPState *dsp) +{ + dsp56300_step(jit_be(dsp)->jit); +} + +static void dsp_jit_run(DSPState *dsp, int cycles) +{ + dsp56300_run(jit_be(dsp)->jit, cycles); +} + +static void dsp_jit_bootstrap(DSPState *dsp) +{ + JitBackend *be = jit_be(dsp); + + /* Load scratch memory into PRAM (C-side owned buffer) */ + dsp->dma.scratch_rw(dsp->dma.rw_opaque, (uint8_t *)be->pram, 0, 0x800 * 4, + false); + for (int i = 0; i < 0x800; i++) { + if (be->pram[i] & 0xff000000) { + DPRINTF("Bootstrap %04x: %08x\n", i, be->pram[i]); + be->pram[i] &= 0x00ffffff; + } + } + dsp56300_invalidate_cache(be->jit); +} + +static uint32_t dsp_jit_read_memory(DSPState *dsp, char space, uint32_t addr) +{ + Dsp56300MemSpace space_id = (space == 'X') ? DSP56300_MEM_SPACE_X : + (space == 'Y') ? DSP56300_MEM_SPACE_Y : + DSP56300_MEM_SPACE_P; + return dsp56300_read_memory(jit_be(dsp)->jit, space_id, addr); +} + +static void dsp_jit_write_memory(DSPState *dsp, char space, uint32_t addr, + uint32_t value) +{ + Dsp56300MemSpace space_id = (space == 'X') ? DSP56300_MEM_SPACE_X : + (space == 'Y') ? DSP56300_MEM_SPACE_Y : + DSP56300_MEM_SPACE_P; + dsp56300_write_memory(jit_be(dsp)->jit, space_id, addr, value); +} + +static bool dsp_jit_get_halt_requested(DSPState *dsp) +{ + return dsp56300_halt_requested(jit_be(dsp)->jit); +} + +static void dsp_jit_set_halt_requested(DSPState *dsp, bool idle) +{ + dsp56300_set_halt_requested(jit_be(dsp)->jit, idle); +} + +static uint32_t dsp_jit_get_cycle_count(DSPState *dsp) +{ + return dsp56300_cycle_count(jit_be(dsp)->jit); +} + +static void dsp_jit_set_cycle_count(DSPState *dsp, uint32_t count) +{ + dsp56300_set_cycle_count(jit_be(dsp)->jit, count); +} + +static void dsp_jit_invalidate_opcache(DSPState *dsp) +{ + dsp56300_invalidate_cache(jit_be(dsp)->jit); +} + +/* + * Sync: JIT -> DspCoreState (before VM save / debug) + */ +static void dsp_jit_sync_to_vm(DSPState *dsp) +{ + JitBackend *be = jit_be(dsp); + Dsp56300Jit *jit = be->jit; + DspCoreState *vm = &dsp->core; + + /* Scalar state via bulk struct */ + Dsp56300State ss; + dsp56300_get_state(jit, &ss); + vm->pc = ss.pc; + vm->cur_inst_len = ss.pc_advance; + vm->loop_rep = (uint32_t)ss.loop_rep; + vm->pc_on_rep = (uint32_t)ss.pc_on_rep; + vm->cycle_count = ss.cycle_count; + vm->halt_requested = ss.halt_requested; + vm->interrupt_state = ss.interrupts.state; + vm->interrupt_instr_fetch = (uint16_t)ss.interrupts.vector_addr; + vm->interrupt_save_pc = (uint16_t)ss.interrupts.saved_pc; + vm->interrupt_ipl_to_raise = ss.interrupts.ipl_to_raise; + vm->interrupt_pipeline_count = ss.interrupts.pipeline_stage; + vm->interrupt_counter = 0; + for (int i = 0; i < 4; i++) { + int slot = cinterp_to_arch[i]; + vm->interrupt_ipl[i] = (int16_t)ss.interrupts.ipl[slot]; + vm->interrupt_is_pending[i] = (ss.interrupts.pending_bits[slot / 64] >> (slot % 64)) & 1; + vm->interrupt_counter += vm->interrupt_is_pending[i]; + } + dsp->save_cycles = ss.cycle_budget; + + /* Register/stack arrays from bulk state */ + memcpy(vm->registers, ss.registers, DSP_REG_MAX * sizeof(uint32_t)); + memcpy(vm->stack[0], ss.stack[0], 16 * sizeof(uint32_t)); + memcpy(vm->stack[1], ss.stack[1], 16 * sizeof(uint32_t)); + + /* Memory arrays from C-side owned buffers */ + memcpy(vm->pram, be->pram, DSP_PRAM_SIZE * sizeof(uint32_t)); + memcpy(vm->xram, be->xram, DSP_XRAM_SIZE * sizeof(uint32_t)); + memcpy(vm->yram, be->yram, DSP_YRAM_SIZE * sizeof(uint32_t)); + /* Mixbuffer is aliased at xram[0xC00] */ + memcpy(vm->mixbuffer, be->xram + 0xC00, + DSP_MIXBUFFER_SIZE * sizeof(uint32_t)); + /* Peripheral state: read current values via callbacks */ + for (int i = 0; i < DSP_PERIPH_SIZE; i++) { + vm->periph[i] = + dsp56300_read_memory(jit, DSP56300_MEM_SPACE_X, 0xFFFF80 + i); + } +} + +/* + * Sync: DspCoreState -> JIT (after VM load / engine switch) + */ +static void dsp_jit_sync_from_vm(DSPState *dsp) +{ + JitBackend *be = jit_be(dsp); + Dsp56300Jit *jit = be->jit; + DspCoreState *vm = &dsp->core; + + /* Memory arrays into C-side owned buffers */ + memcpy(be->pram, vm->pram, DSP_PRAM_SIZE * sizeof(uint32_t)); + memcpy(be->xram, vm->xram, DSP_XRAM_SIZE * sizeof(uint32_t)); + memcpy(be->yram, vm->yram, DSP_YRAM_SIZE * sizeof(uint32_t)); + /* Mixbuffer is aliased at xram[0xC00] */ + memcpy(be->xram + 0xC00, vm->mixbuffer, + DSP_MIXBUFFER_SIZE * sizeof(uint32_t)); + + /* Scalar state via bulk struct */ + Dsp56300State ss = { + .pc = vm->pc, + .pc_advance = vm->cur_inst_len, + .pc_on_rep = (bool)vm->pc_on_rep, + .cycle_count = vm->cycle_count, + .cycle_budget = dsp->save_cycles, + .loop_rep = (bool)vm->loop_rep, + .halt_requested = vm->halt_requested, + .power_state = 0, + .registers = {0}, + .stack = {{0}}, + .interrupts = { + .state = (uint8_t)vm->interrupt_state, + .vector_addr = vm->interrupt_instr_fetch, + .saved_pc = vm->interrupt_save_pc, + .ipl_to_raise = (uint8_t)vm->interrupt_ipl_to_raise, + .pipeline_stage = (uint8_t)vm->interrupt_pipeline_count, + }, + }; + ss.interrupts.pending_bits[0] = 0; + ss.interrupts.pending_bits[1] = 0; + for (int i = 0; i < 4; i++) { + int slot = cinterp_to_arch[i]; + ss.interrupts.ipl[slot] = (int8_t)vm->interrupt_ipl[i]; + ss.interrupts.pending_bits[slot / 64] |= + (uint64_t)(vm->interrupt_is_pending[i] != 0) << (slot % 64); + } + memcpy(ss.registers, vm->registers, DSP_REG_MAX * sizeof(uint32_t)); + memcpy(ss.stack[0], vm->stack[0], 16 * sizeof(uint32_t)); + memcpy(ss.stack[1], vm->stack[1], 16 * sizeof(uint32_t)); + + /* Widen legacy 16-bit register values from old snapshots. + * The C interpreter used 16-bit R/N/M/SSH/SSL/LA/LC registers. + * M: $FFFF meant linear addressing at 16-bit; JIT needs $FFFFFF. + * N: Signed offsets need sign extension from 16-bit to 24-bit. + */ + for (int i = 0; i < 8; i++) { + if (ss.registers[DSP_REG_M0 + i] == 0x00FFFF) { + ss.registers[DSP_REG_M0 + i] = 0x00FFFFFF; + } + if (ss.registers[DSP_REG_N0 + i] & 0x8000) { + ss.registers[DSP_REG_N0 + i] |= 0xFF0000; + } + } + + dsp56300_set_state(jit, &ss); + + dsp56300_invalidate_cache(jit); +} + +static JitBackend *dsp_create_jit_backend(DSPState *dsp) +{ + JitBackend *be = g_new0(JitBackend, 1); + + /* Allocate memory buffers owned by the C side */ + be->xram = g_new(uint32_t, DSP_XRAM_SIZE); + memset(be->xram, 0xCA, DSP_XRAM_SIZE * sizeof(uint32_t)); + be->yram = g_new(uint32_t, DSP_YRAM_SIZE); + memset(be->yram, 0xCA, DSP_YRAM_SIZE * sizeof(uint32_t)); + be->pram = g_new(uint32_t, DSP_PRAM_SIZE); + memset(be->pram, 0xCA, DSP_PRAM_SIZE * sizeof(uint32_t)); + + /* X-space: XRAM [0, 0x1000), mixbuf alias [0x1400, 0x1800), peripherals */ + Dsp56300MemoryRegion x_regions[3] = { + { .start = 0x0000, + .end = 0x1000, + .kind = DSP56300_REGION_BUFFER, + .data = { .buffer = { .base = be->xram, .offset = 0 } } }, + { .start = 0x1400, + .end = 0x1800, + .kind = DSP56300_REGION_BUFFER, + .data = { .buffer = { .base = be->xram, .offset = 0xC00 } } }, + { .start = 0xFFFF80, + .end = 0x1000000, + .kind = DSP56300_REGION_CALLBACK, + .data = { .callback = { .opaque = dsp, + .read = jit_read_peripheral, + .write = jit_write_peripheral } } }, + }; + + /* Y-space: YRAM [0, 0x800) */ + Dsp56300MemoryRegion y_regions[1] = { + { .start = 0x0000, + .end = 0x0800, + .kind = DSP56300_REGION_BUFFER, + .data = { .buffer = { .base = be->yram, .offset = 0 } } }, + }; + + /* P-space: PRAM [0, 0x1000) */ + Dsp56300MemoryRegion p_regions[1] = { + { .start = 0x0000, + .end = 0x1000, + .kind = DSP56300_REGION_BUFFER, + .data = { .buffer = { .base = be->pram, .offset = 0 } } }, + }; + + Dsp56300CreateInfo info = { + .memory_map = { + .x_regions = x_regions, + .x_count = ARRAY_SIZE(x_regions), + .y_regions = y_regions, + .y_count = ARRAY_SIZE(y_regions), + .p_regions = p_regions, + .p_count = ARRAY_SIZE(p_regions), + }, + }; + + be->jit = dsp56300_create(&info); + return be; +} + +void dsp_jit_init(DSPState *dsp) +{ + JitBackend *be = dsp_create_jit_backend(dsp); + dsp->backend = be; + dsp->ops = &jit_dsp_ops; + + dsp->dma.mem_opaque = be->jit; + dsp->dma.mem_read = jit_dma_mem_read; + dsp->dma.mem_write = jit_dma_mem_write; +} + +static void dsp_jit_finalize(DSPState *dsp) +{ + JitBackend *be = jit_be(dsp); + dsp56300_destroy(be->jit); + g_free(be->xram); + g_free(be->yram); + g_free(be->pram); + g_free(be); + dsp->backend = NULL; +} + +const DSPOps jit_dsp_ops = { + .finalize = dsp_jit_finalize, + .reset = dsp_jit_reset, + .step = dsp_jit_step, + .run = dsp_jit_run, + .bootstrap = dsp_jit_bootstrap, + .start_frame = dsp_start_frame_impl, + .read_memory = dsp_jit_read_memory, + .write_memory = dsp_jit_write_memory, + .get_halt_requested = dsp_jit_get_halt_requested, + .set_halt_requested = dsp_jit_set_halt_requested, + .get_cycle_count = dsp_jit_get_cycle_count, + .set_cycle_count = dsp_jit_set_cycle_count, + .invalidate_opcache = dsp_jit_invalidate_opcache, + .sync_to_vm = dsp_jit_sync_to_vm, + .sync_from_vm = dsp_jit_sync_from_vm, +}; diff --git a/hw/xbox/mcpx/apu/dsp/dsp_state.h b/hw/xbox/mcpx/apu/dsp/dsp_state.h deleted file mode 100644 index 899ac0740c..0000000000 --- a/hw/xbox/mcpx/apu/dsp/dsp_state.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * MCPX DSP emulator - - * Copyright (c) 2015 espes - - * Adapted from Hatari DSP M56001 emulation - * (C) 2001-2008 ARAnyM developer team - * Adaption to Hatari (C) 2008 by Thomas Huth - - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DSP_STATE_H -#define DSP_STATE_H - -#include "dsp_cpu.h" -#include "dsp_dma.h" - -struct DSPState { - dsp_core_t core; - DSPDMAState dma; - int save_cycles; - - uint32_t interrupts; - - bool is_gp; -}; - -#endif /* DSP_STATE_H */ diff --git a/hw/xbox/mcpx/apu/dsp/gp_ep.c b/hw/xbox/mcpx/apu/dsp/gp_ep.c index 7cd38fdd9a..a1212acb05 100644 --- a/hw/xbox/mcpx/apu/dsp/gp_ep.c +++ b/hw/xbox/mcpx/apu/dsp/gp_ep.c @@ -25,23 +25,27 @@ static const int16_t ep_silence[256][2] = { 0 }; void mcpx_apu_update_dsp_preference(MCPXAPUState *d) { - static int last_known_preference = -1; + static int last_known_dsp_pref = -1; + static int last_known_jit_pref = -1; - if (last_known_preference == (int)g_config.audio.use_dsp) { - return; + if (last_known_dsp_pref != (int)g_config.audio.use_dsp) { + if (g_config.audio.use_dsp) { + d->monitor.point = MCPX_APU_DEBUG_MON_GP_OR_EP; + d->gp.realtime = true; + d->ep.realtime = true; + } else { + d->monitor.point = MCPX_APU_DEBUG_MON_VP; + d->gp.realtime = false; + d->ep.realtime = false; + } + last_known_dsp_pref = g_config.audio.use_dsp; } - if (g_config.audio.use_dsp) { - d->monitor.point = MCPX_APU_DEBUG_MON_GP_OR_EP; - d->gp.realtime = true; - d->ep.realtime = true; - } else { - d->monitor.point = MCPX_APU_DEBUG_MON_VP; - d->gp.realtime = false; - d->ep.realtime = false; + if (last_known_jit_pref != (int)g_config.audio.use_dsp_jit) { + dsp_set_engine(d->gp.dsp, g_config.audio.use_dsp_jit); + dsp_set_engine(d->ep.dsp, g_config.audio.use_dsp_jit); + last_known_jit_pref = g_config.audio.use_dsp_jit; } - - last_known_preference = g_config.audio.use_dsp; } static void scatter_gather_rw(MCPXAPUState *d, hwaddr sge_base, @@ -454,12 +458,12 @@ void mcpx_apu_dsp_frame(MCPXAPUState *d, float mixbins[NUM_MIXBINS][NUM_SAMPLES_ if ((d->gp.regs[NV_PAPU_GPRST] & NV_PAPU_GPRST_GPRST) && (d->gp.regs[NV_PAPU_GPRST] & NV_PAPU_GPRST_GPDSPRST)) { dsp_start_frame(d->gp.dsp); - d->gp.dsp->core.is_idle = false; - d->gp.dsp->core.cycle_count = 0; + dsp_set_halt_requested(d->gp.dsp, false); + dsp_set_cycle_count(d->gp.dsp, 0); do { dsp_run(d->gp.dsp, 1000); - } while (!d->gp.dsp->core.is_idle && d->gp.realtime); - g_dbg.gp.cycles = d->gp.dsp->core.cycle_count; + } while (!dsp_get_halt_requested(d->gp.dsp) && d->gp.realtime); + g_dbg.gp.cycles = dsp_get_cycle_count(d->gp.dsp); if ((d->monitor.point == MCPX_APU_DEBUG_MON_GP) || (d->monitor.point == MCPX_APU_DEBUG_MON_GP_OR_EP && !ep_enabled)) { @@ -479,45 +483,25 @@ void mcpx_apu_dsp_frame(MCPXAPUState *d, float mixbins[NUM_MIXBINS][NUM_SAMPLES_ (d->ep.regs[NV_PAPU_EPRST] & NV_PAPU_GPRST_GPDSPRST)) { if (d->ep_frame_div % 8 == 0) { dsp_start_frame(d->ep.dsp); - d->ep.dsp->core.is_idle = false; - d->ep.dsp->core.cycle_count = 0; + dsp_set_halt_requested(d->ep.dsp, false); + dsp_set_cycle_count(d->ep.dsp, 0); do { dsp_run(d->ep.dsp, 1000); - } while (!d->ep.dsp->core.is_idle && d->ep.realtime); - g_dbg.ep.cycles = d->ep.dsp->core.cycle_count; + } while (!dsp_get_halt_requested(d->ep.dsp) && d->ep.realtime); + g_dbg.ep.cycles = dsp_get_cycle_count(d->ep.dsp); } } } void mcpx_apu_dsp_init(MCPXAPUState *d) { - d->gp.dsp = dsp_init(d, gp_scratch_rw, gp_fifo_rw); - for (int i = 0; i < DSP_PRAM_SIZE; i++) { - d->gp.dsp->core.pram[i] = 0xCACACACA; - } - memset(d->gp.dsp->core.pram_opcache, 0, - sizeof(d->gp.dsp->core.pram_opcache)); - d->gp.dsp->is_gp = true; - d->gp.dsp->core.is_gp = true; - d->gp.dsp->core.is_idle = false; - d->gp.dsp->core.cycle_count = 0; + d->gp.dsp = dsp_init(d, gp_scratch_rw, gp_fifo_rw, true); + dsp_set_halt_requested(d->gp.dsp, false); + dsp_set_cycle_count(d->gp.dsp, 0); - d->ep.dsp = dsp_init(d, ep_scratch_rw, ep_fifo_rw); - for (int i = 0; i < DSP_PRAM_SIZE; i++) { - d->ep.dsp->core.pram[i] = 0xCACACACA; - } - memset(d->ep.dsp->core.pram_opcache, 0, - sizeof(d->ep.dsp->core.pram_opcache)); - for (int i = 0; i < DSP_XRAM_SIZE; i++) { - d->ep.dsp->core.xram[i] = 0xCACACACA; - } - for (int i = 0; i < DSP_YRAM_SIZE; i++) { - d->ep.dsp->core.yram[i] = 0xCACACACA; - } - d->ep.dsp->is_gp = false; - d->ep.dsp->core.is_gp = false; - d->ep.dsp->core.is_idle = false; - d->ep.dsp->core.cycle_count = 0; + d->ep.dsp = dsp_init(d, ep_scratch_rw, ep_fifo_rw, false); + dsp_set_halt_requested(d->ep.dsp, false); + dsp_set_cycle_count(d->ep.dsp, 0); /* Until DSP is more performant, a switch to decide whether or not we should * use the full audio pipeline or not. diff --git a/hw/xbox/mcpx/apu/dsp/gp_ep.h b/hw/xbox/mcpx/apu/dsp/gp_ep.h index c1250373ca..64fb0fade8 100644 --- a/hw/xbox/mcpx/apu/dsp/gp_ep.h +++ b/hw/xbox/mcpx/apu/dsp/gp_ep.h @@ -27,9 +27,6 @@ #include "hw/xbox/mcpx/apu/apu_regs.h" #include "dsp.h" -#include "dsp_dma.h" -#include "dsp_cpu.h" -#include "dsp_state.h" typedef struct MCPXAPUState MCPXAPUState; diff --git a/hw/xbox/mcpx/apu/dsp/interp/debug.c b/hw/xbox/mcpx/apu/dsp/interp/debug.c new file mode 100644 index 0000000000..eb7f81c64c --- /dev/null +++ b/hw/xbox/mcpx/apu/dsp/interp/debug.c @@ -0,0 +1,293 @@ +/* + * MCPX DSP emulator + * + * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson + * + * Adapted from Hatari DSP M56001 emulation + * (C) 2001-2008 ARAnyM developer team + * Adaption to Hatari (C) 2008 by Thomas Huth + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "dsp_cpu.h" +#include "debug.h" + +#if DEBUG_DSP +#define BITMASK(x) ((1<<(x))-1) + +/** + * Output memory values between given addresses in given DSP address space. + * Return next DSP address value. + */ +uint32_t dsp_disasm_memory(dsp_core_t* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, int space) +{ + uint32_t mem, value; + + for (mem = dsp_memdump_addr; mem <= dsp_memdump_upper; mem++) { + value = dsp56k_read_memory(dsp, space, mem); + printf("%04x %06x\n", mem, value); + } + return dsp_memdump_upper+1; +} + +/** + * Show information on DSP core state which isn't + * shown by any of the other commands (dd, dm, dr). + */ +void dsp_info(dsp_core_t* dsp) +{ + int i, j; + const char *stackname[] = { "SSH", "SSL" }; + + printf("DSP core information:\n"); + + for (i = 0; i < ARRAY_SIZE(stackname); i++) { + printf("- %s stack:", stackname[i]); + for (j = 0; j < ARRAY_SIZE(dsp->stack[0]); j++) { + printf(" %04x", dsp->stack[i][j]); + } + printf("\n"); + } + + printf("- Interrupt IPL:"); + for (i = 0; i < ARRAY_SIZE(dsp->interrupt_ipl); i++) { + printf(" %04x", dsp->interrupt_ipl[i]); + } + printf("\n"); + + printf("- Pending ints: "); + for (i = 0; i < ARRAY_SIZE(dsp->interrupt_is_pending); i++) { + printf(" %04hx", dsp->interrupt_is_pending[i]); + } + printf("\n"); +} + +/** + * Show DSP register contents + */ +void dsp_print_registers(dsp_core_t* dsp) +{ + uint32_t i; + + printf("A: A2: %02x A1: %06x A0: %06x\n", + dsp->registers[DSP_REG_A2], dsp->registers[DSP_REG_A1], dsp->registers[DSP_REG_A0]); + printf("B: B2: %02x B1: %06x B0: %06x\n", + dsp->registers[DSP_REG_B2], dsp->registers[DSP_REG_B1], dsp->registers[DSP_REG_B0]); + + printf("X: X1: %06x X0: %06x\n", dsp->registers[DSP_REG_X1], dsp->registers[DSP_REG_X0]); + printf("Y: Y1: %06x Y0: %06x\n", dsp->registers[DSP_REG_Y1], dsp->registers[DSP_REG_Y0]); + + for (i=0; i<8; i++) { + printf("R%01x: %04x N%01x: %04x M%01x: %04x\n", + i, dsp->registers[DSP_REG_R0+i], + i, dsp->registers[DSP_REG_N0+i], + i, dsp->registers[DSP_REG_M0+i]); + } + + printf("LA: %04x LC: %04x PC: %04x\n", dsp->registers[DSP_REG_LA], dsp->registers[DSP_REG_LC], dsp->pc); + printf("SR: %04x OMR: %02x\n", dsp->registers[DSP_REG_SR], dsp->registers[DSP_REG_OMR]); + printf("SP: %02x SSH: %04x SSL: %04x\n", + dsp->registers[DSP_REG_SP], dsp->registers[DSP_REG_SSH], dsp->registers[DSP_REG_SSL]); +} + + +/** + * Get given DSP register address and required bit mask. + * Works for A0-2, B0-2, LA, LC, M0-7, N0-7, R0-7, X0-1, Y0-1, PC, SR, SP, + * OMR, SSH & SSL registers, but note that the SP, SSH & SSL registers + * need special handling (in DSP*SetRegister()) when they are set. + * Return the register width in bits or zero for an error. + */ +int dsp_get_register_address(dsp_core_t* dsp, const char *regname, uint32_t **addr, uint32_t *mask) +{ +#define MAX_REGNAME_LEN 4 + typedef struct { + const char name[MAX_REGNAME_LEN]; + uint32_t *addr; + size_t bits; + uint32_t mask; + } reg_addr_t; + + /* sorted by name so that this can be bisected */ + const reg_addr_t registers[] = { + + /* 56-bit A register */ + { "A0", &dsp->registers[DSP_REG_A0], 32, BITMASK(24) }, + { "A1", &dsp->registers[DSP_REG_A1], 32, BITMASK(24) }, + { "A2", &dsp->registers[DSP_REG_A2], 32, BITMASK(8) }, + + /* 56-bit B register */ + { "B0", &dsp->registers[DSP_REG_B0], 32, BITMASK(24) }, + { "B1", &dsp->registers[DSP_REG_B1], 32, BITMASK(24) }, + { "B2", &dsp->registers[DSP_REG_B2], 32, BITMASK(8) }, + + /* 16-bit LA & LC registers */ + { "LA", &dsp->registers[DSP_REG_LA], 32, BITMASK(16) }, + { "LC", &dsp->registers[DSP_REG_LC], 32, BITMASK(16) }, + + /* 16-bit M registers */ + { "M0", &dsp->registers[DSP_REG_M0], 32, BITMASK(16) }, + { "M1", &dsp->registers[DSP_REG_M1], 32, BITMASK(16) }, + { "M2", &dsp->registers[DSP_REG_M2], 32, BITMASK(16) }, + { "M3", &dsp->registers[DSP_REG_M3], 32, BITMASK(16) }, + { "M4", &dsp->registers[DSP_REG_M4], 32, BITMASK(16) }, + { "M5", &dsp->registers[DSP_REG_M5], 32, BITMASK(16) }, + { "M6", &dsp->registers[DSP_REG_M6], 32, BITMASK(16) }, + { "M7", &dsp->registers[DSP_REG_M7], 32, BITMASK(16) }, + + /* 16-bit N registers */ + { "N0", &dsp->registers[DSP_REG_N0], 32, BITMASK(16) }, + { "N1", &dsp->registers[DSP_REG_N1], 32, BITMASK(16) }, + { "N2", &dsp->registers[DSP_REG_N2], 32, BITMASK(16) }, + { "N3", &dsp->registers[DSP_REG_N3], 32, BITMASK(16) }, + { "N4", &dsp->registers[DSP_REG_N4], 32, BITMASK(16) }, + { "N5", &dsp->registers[DSP_REG_N5], 32, BITMASK(16) }, + { "N6", &dsp->registers[DSP_REG_N6], 32, BITMASK(16) }, + { "N7", &dsp->registers[DSP_REG_N7], 32, BITMASK(16) }, + + { "OMR", &dsp->registers[DSP_REG_OMR], 32, 0x5f }, + + /* 16-bit program counter */ + { "PC", (uint32_t*)(&dsp->pc), 24, BITMASK(24) }, + + /* 16-bit DSP R (address) registers */ + { "R0", &dsp->registers[DSP_REG_R0], 32, BITMASK(16) }, + { "R1", &dsp->registers[DSP_REG_R1], 32, BITMASK(16) }, + { "R2", &dsp->registers[DSP_REG_R2], 32, BITMASK(16) }, + { "R3", &dsp->registers[DSP_REG_R3], 32, BITMASK(16) }, + { "R4", &dsp->registers[DSP_REG_R4], 32, BITMASK(16) }, + { "R5", &dsp->registers[DSP_REG_R5], 32, BITMASK(16) }, + { "R6", &dsp->registers[DSP_REG_R6], 32, BITMASK(16) }, + { "R7", &dsp->registers[DSP_REG_R7], 32, BITMASK(16) }, + + { "SSH", &dsp->registers[DSP_REG_SSH], 32, BITMASK(16) }, + { "SSL", &dsp->registers[DSP_REG_SSL], 32, BITMASK(16) }, + { "SP", &dsp->registers[DSP_REG_SP], 32, BITMASK(6) }, + + /* 16-bit status register */ + { "SR", &dsp->registers[DSP_REG_SR], 32, 0xefff }, + + /* 48-bit X register */ + { "X0", &dsp->registers[DSP_REG_X0], 32, BITMASK(24) }, + { "X1", &dsp->registers[DSP_REG_X1], 32, BITMASK(24) }, + + /* 48-bit Y register */ + { "Y0", &dsp->registers[DSP_REG_Y0], 32, BITMASK(24) }, + { "Y1", &dsp->registers[DSP_REG_Y1], 32, BITMASK(24) } + }; + /* left, right, middle, direction */ + int l, r, m, dir = 0; + unsigned int i, len; + char reg[MAX_REGNAME_LEN]; + + for (i = 0; i < sizeof(reg) && regname[i]; i++) { + reg[i] = toupper(regname[i]); + } + if (i < 2 || regname[i]) { + /* too short or longer than any of the names */ + return 0; + } + len = i; + + /* bisect */ + l = 0; + r = ARRAY_SIZE(registers) - 1; + do { + m = (l+r) >> 1; + for (i = 0; i < len; i++) { + dir = (int)reg[i] - registers[m].name[i]; + if (dir) { + break; + } + } + if (dir == 0) { + *addr = registers[m].addr; + *mask = registers[m].mask; + return registers[m].bits; + } + if (dir < 0) { + r = m-1; + } else { + l = m+1; + } + } while (l <= r); +#undef MAX_REGNAME_LEN + return 0; +} + + +/** + * Set given DSP register value, return false if unknown register given + */ +bool dsp_disasm_set_register(dsp_core_t* dsp, const char *arg, uint32_t value) +{ + uint32_t *addr, mask, sp_value; + int bits; + + /* first check registers needing special handling... */ + if (arg[0]=='S' || arg[0]=='s') { + if (arg[1]=='P' || arg[1]=='p') { + dsp->registers[DSP_REG_SP] = value & BITMASK(6); + value &= BITMASK(4); + dsp->registers[DSP_REG_SSH] = dsp->stack[0][value]; + dsp->registers[DSP_REG_SSL] = dsp->stack[1][value]; + return true; + } + if (arg[1]=='S' || arg[1]=='s') { + sp_value = dsp->registers[DSP_REG_SP] & BITMASK(4); + if (arg[2]=='H' || arg[2]=='h') { + if (sp_value == 0) { + dsp->registers[DSP_REG_SSH] = 0; + dsp->stack[0][sp_value] = 0; + } else { + dsp->registers[DSP_REG_SSH] = value & BITMASK(16); + dsp->stack[0][sp_value] = value & BITMASK(16); + } + return true; + } + if (arg[2]=='L' || arg[2]=='l') { + if (sp_value == 0) { + dsp->registers[DSP_REG_SSL] = 0; + dsp->stack[1][sp_value] = 0; + } else { + dsp->registers[DSP_REG_SSL] = value & BITMASK(16); + dsp->stack[1][sp_value] = value & BITMASK(16); + } + return true; + } + } + } + + /* ...then registers where address & mask are enough */ + bits = dsp_get_register_address(dsp, arg, &addr, &mask); + switch (bits) { + case 32: + *addr = value & mask; + return true; + case 16: + *(uint16_t*)addr = value & mask; + return true; + } + return false; +} + +#endif diff --git a/hw/xbox/mcpx/apu/dsp/dsp_cpu.c b/hw/xbox/mcpx/apu/dsp/interp/dsp_cpu.c similarity index 96% rename from hw/xbox/mcpx/apu/dsp/dsp_cpu.c rename to hw/xbox/mcpx/apu/dsp/interp/dsp_cpu.c index 7a5486ca12..9e4b695bd7 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/apu/dsp/interp/dsp_cpu.c @@ -31,6 +31,10 @@ #define BITMASK(x) ((1<<(x))-1) +#define TRACE_DSP_DISASM 0 +#define TRACE_DSP_DISASM_REG 0 +#define TRACE_DSP_DISASM_MEM 0 + // #define DSP_COUNT_IPS /* Count instruction per seconds */ @@ -70,19 +74,12 @@ static void dsp_mul56(uint32_t source1, uint32_t source2, uint32_t *dest, uint8_ static void dsp_rnd56(dsp_core_t* dsp, uint32_t *dest); static uint32_t dsp_signextend(int bits, uint32_t v); -static const dsp_interrupt_t dsp_interrupt[12] = { +/* Vector addresses per DSP56300FM Table 2-2, indexed by DSP_INTER_* */ +static const dsp_interrupt_t dsp_interrupt[4] = { { DSP_INTER_RESET, 0x00, 0, "Reset" }, - { DSP_INTER_ILLEGAL, 0x3e, 0, "Illegal" }, + { DSP_INTER_ILLEGAL, 0x04, 0, "Illegal" }, { DSP_INTER_STACK_ERROR, 0x02, 0, "Stack Error" }, - { DSP_INTER_TRACE, 0x04, 0, "Trace" }, - { DSP_INTER_SWI, 0x06, 0, "Swi" }, - { DSP_INTER_HOST_COMMAND, 0xff, 1, "Host Command" }, - { DSP_INTER_HOST_RCV_DATA, 0x20, 1, "Host receive" }, - { DSP_INTER_HOST_TRX_DATA, 0x22, 1, "Host transmit" }, - { DSP_INTER_SSI_RCV_DATA_E, 0x0e, 2, "SSI receive with exception" }, - { DSP_INTER_SSI_RCV_DATA, 0x0c, 2, "SSI receive" }, - { DSP_INTER_SSI_TRX_DATA_E, 0x12, 2, "SSI transmit with exception" }, - { DSP_INTER_SSI_TRX_DATA, 0x10, 2, "SSI transmit" } + { DSP_INTER_TRAP, 0x08, 0, "Trap" }, }; static const int registers_tcc[16][2] = { @@ -392,12 +389,9 @@ void dsp56k_reset_cpu(dsp_core_t* dsp) dsp->interrupt_save_pc = -1; dsp->interrupt_counter = 0; dsp->interrupt_pipeline_count = 0; - for (i=0;i<5;i++) { + for (i=0;i<4;i++) { dsp->interrupt_ipl[i] = 3; } - for (i=5;i<12;i++) { - dsp->interrupt_ipl[i] = -1; - } /* Misc */ dsp->loop_rep = 0; @@ -783,7 +777,7 @@ static void dsp_postexecute_interrupts(dsp_core_t* dsp) if ( ((instr & 0xfff000) == 0x0d0000) || ((instr & 0xffc0ff) == 0x0bc080) ) { dsp->interrupt_state = DSP_INTERRUPT_LONG; dsp_stack_push(dsp, dsp->interrupt_save_pc, dsp->registers[DSP_REG_SR], 0); - dsp->registers[DSP_REG_SR] &= BITMASK(16)-((1<registers[DSP_REG_SR] &= BITMASK(16)-((1<registers[DSP_REG_SR] |= dsp->interrupt_ipl_to_raise<interrupt_state = DSP_INTERRUPT_LONG; dsp_stack_push(dsp, dsp->interrupt_save_pc, dsp->registers[DSP_REG_SR], 0); - dsp->registers[DSP_REG_SR] &= BITMASK(16)-((1<registers[DSP_REG_SR] &= BITMASK(16)-((1<registers[DSP_REG_SR] |= dsp->interrupt_ipl_to_raise<registers[DSP_REG_SR] & (1<interrupt_counter == 0) { return; @@ -845,7 +834,7 @@ static void dsp_postexecute_interrupts(dsp_core_t* dsp) ipl_to_raise = -1; /* Arbitrate between all pending interrupts */ - for (i=0; i<12; i++) { + for (i=0; i<4; i++) { if (dsp->interrupt_is_pending[i] == 1) { /* level 3 interrupt ? */ @@ -890,29 +879,6 @@ static void dsp_postexecute_interrupts(dsp_core_t* dsp) dsp->interrupt_ipl_to_raise = ipl_to_raise; DPRINTF("Dsp interrupt: %s\n", dsp_interrupt[index].name); - - /* SSI receive data with exception ? */ - if (dsp->interrupt_instr_fetch == 0xe) { - // dsp->periph[DSP_SPACE_X][DSP_SSI_SR] &= 0xff-(1<interrupt_instr_fetch == 0x12) { - // dsp->periph[DSP_SPACE_X][DSP_SSI_SR] &= 0xff-(1<interrupt_instr_fetch == 0xff) { - /* Clear HC and HCP interrupt */ - // dsp->periph[DSP_SPACE_X][DSP_HOST_HSR] &= 0xff - (1<hostport[CPU_HOST_CVR] &= 0xff - (1<interrupt_instr_fetch = dsp->hostport[CPU_HOST_CVR] & BITMASK(5); - // dsp->interrupt_instr_fetch *= 2; - assert(!"Host command failure"); - } } /********************************** diff --git a/hw/xbox/mcpx/apu/dsp/dsp_cpu.h b/hw/xbox/mcpx/apu/dsp/interp/dsp_cpu.h similarity index 96% rename from hw/xbox/mcpx/apu/dsp/dsp_cpu.h rename to hw/xbox/mcpx/apu/dsp/interp/dsp_cpu.h index 4cffd2631d..d9ee16368d 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp_cpu.h +++ b/hw/xbox/mcpx/apu/dsp/interp/dsp_cpu.h @@ -81,8 +81,11 @@ struct dsp_core_s { uint16_t interrupt_counter; /* count number of pending interrupts */ uint16_t interrupt_ipl_to_raise; /* save the IPL level to save in the SR register */ uint16_t interrupt_pipeline_count; /* used to prefetch correctly the 2 inter instructions */ - int16_t interrupt_ipl[12]; /* store the current IPL for each interrupt */ - uint16_t interrupt_is_pending[12]; /* store if interrupt is pending for each interrupt */ + int16_t interrupt_ipl[4]; + uint16_t interrupt_is_pending[4]; + + /* Back-pointer to owning DSPState (set by dsp_c.c) */ + void *opaque; /* callbacks */ uint32_t (*read_peripheral)(dsp_core_t* core, uint32_t address); diff --git a/hw/xbox/mcpx/apu/dsp/dsp_cpu_regs.h b/hw/xbox/mcpx/apu/dsp/interp/dsp_cpu_regs.h similarity index 86% rename from hw/xbox/mcpx/apu/dsp/dsp_cpu_regs.h rename to hw/xbox/mcpx/apu/dsp/interp/dsp_cpu_regs.h index 75b2009b2f..0fc33d13cc 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp_cpu_regs.h +++ b/hw/xbox/mcpx/apu/dsp/interp/dsp_cpu_regs.h @@ -43,8 +43,10 @@ #define DSP_SR_I1 0x09 #define DSP_SR_S0 0x0a #define DSP_SR_S1 0x0b -#define DSP_SR_T 0x0d +#define DSP_SR_SC 0x0d +#define DSP_SR_DM 0x0e #define DSP_SR_LF 0x0f +#define DSP_SR_FV 0x10 #define DSP_SP_SE 0x04 #define DSP_SP_UF 0x05 @@ -122,17 +124,9 @@ #define DSP_INTERRUPT_DISABLED 0x1 #define DSP_INTERRUPT_LONG 0x2 -#define DSP_INTER_RESET 0x0 -#define DSP_INTER_ILLEGAL 0x1 -#define DSP_INTER_STACK_ERROR 0x2 -#define DSP_INTER_TRACE 0x3 -#define DSP_INTER_SWI 0x4 -#define DSP_INTER_HOST_COMMAND 0x5 -#define DSP_INTER_HOST_RCV_DATA 0x6 -#define DSP_INTER_HOST_TRX_DATA 0x7 -#define DSP_INTER_SSI_RCV_DATA_E 0x8 -#define DSP_INTER_SSI_RCV_DATA 0x9 -#define DSP_INTER_SSI_TRX_DATA_E 0xa -#define DSP_INTER_SSI_TRX_DATA 0xb +#define DSP_INTER_RESET 0 +#define DSP_INTER_ILLEGAL 1 +#define DSP_INTER_STACK_ERROR 2 +#define DSP_INTER_TRAP 3 #endif diff --git a/hw/xbox/mcpx/apu/dsp/dsp_dis.c.inc b/hw/xbox/mcpx/apu/dsp/interp/dsp_dis.c.inc similarity index 99% rename from hw/xbox/mcpx/apu/dsp/dsp_dis.c.inc rename to hw/xbox/mcpx/apu/dsp/interp/dsp_dis.c.inc index 0cc0a98a20..f8350513a4 100644 --- a/hw/xbox/mcpx/apu/dsp/dsp_dis.c.inc +++ b/hw/xbox/mcpx/apu/dsp/interp/dsp_dis.c.inc @@ -1331,7 +1331,7 @@ static void dis_lua(dsp_core_t* dsp) char addr_name[12]; dis_calc_ea(dsp, (dsp->disasm_cur_inst>>8) & BITMASK(5), addr_name); - uint32_t numreg = dsp->disasm_cur_inst & BITMASK(4); + uint32_t numreg = dsp->disasm_cur_inst & BITMASK(5); sprintf(dsp->disasm_str_instr,"lua %s,%s", addr_name, registers_name[numreg]); } diff --git a/hw/xbox/mcpx/apu/dsp/dsp_emu.c.inc b/hw/xbox/mcpx/apu/dsp/interp/dsp_emu.c.inc similarity index 100% rename from hw/xbox/mcpx/apu/dsp/dsp_emu.c.inc rename to hw/xbox/mcpx/apu/dsp/interp/dsp_emu.c.inc diff --git a/hw/xbox/mcpx/apu/dsp/interp/meson.build b/hw/xbox/mcpx/apu/dsp/interp/meson.build new file mode 100644 index 0000000000..d2fb253222 --- /dev/null +++ b/hw/xbox/mcpx/apu/dsp/interp/meson.build @@ -0,0 +1,5 @@ +libdsp_cpu_interp = static_library( + 'dsp_cpu_interp', + files(['dsp_cpu.c', 'debug.c']) + genh, + include_directories: include_directories('..'), +) diff --git a/hw/xbox/mcpx/apu/dsp/meson.build b/hw/xbox/mcpx/apu/dsp/meson.build index 4d973c6797..3429547e24 100644 --- a/hw/xbox/mcpx/apu/dsp/meson.build +++ b/hw/xbox/mcpx/apu/dsp/meson.build @@ -1,4 +1,19 @@ -libdsp = static_library('dsp', files(['debug.c', 'dsp.c', 'dsp_cpu.c', 'dsp_dma.c']) + genh) -dsp = declare_dependency(objects: libdsp.extract_all_objects(recursive: false)) +dsp56300_emu_ffi = dependency('dsp56300-emu-ffi', fallback: ['dsp56300', 'dsp56300_dep']) + +subdir('interp') + +libdsp = static_library( + 'dsp', + files(['dsp.c', 'dsp_c.c', 'dsp_jit.c', 'dsp_dma.c']) + genh, + dependencies: [dsp56300_emu_ffi], +) + +dsp = declare_dependency( + objects: [ + libdsp.extract_all_objects(recursive: false), + libdsp_cpu_interp.extract_all_objects(recursive: false), + ], + dependencies: [dsp56300_emu_ffi], +) mcpx_ss.add(dsp, files('gp_ep.c')) diff --git a/licenses/dsp56300.license.txt b/licenses/dsp56300.license.txt new file mode 100644 index 0000000000..caf7d555ba --- /dev/null +++ b/licenses/dsp56300.license.txt @@ -0,0 +1,1157 @@ +MIT License + +Copyright (c) 2026 Matt Borgerson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +Third-Party Licenses +==================== + +This file lists the licenses of third-party libraries used by this software. + +------------------------------------------------------------------------------- +Apache License 2.0 + - cranelift-bforest 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-codegen-shared 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-codegen 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-control 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-entity 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-frontend 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-jit 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-module 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - cranelift-native 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - regalloc2 0.15.0 (https://github.com/bytecodealliance/regalloc2) + - target-lexicon 0.13.5 (https://github.com/bytecodealliance/target-lexicon) + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + + +------------------------------------------------------------------------------- +Apache License 2.0 + - windows-link 0.2.1 (https://github.com/microsoft/windows-rs) + - windows-sys 0.52.0 (https://github.com/microsoft/windows-rs) + - windows-sys 0.61.2 (https://github.com/microsoft/windows-rs) + - windows-targets 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_aarch64_gnullvm 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_aarch64_msvc 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_i686_gnu 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_i686_gnullvm 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_i686_msvc 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_x86_64_gnu 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_x86_64_gnullvm 0.52.6 (https://github.com/microsoft/windows-rs) + - windows_x86_64_msvc 0.52.6 (https://github.com/microsoft/windows-rs) + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) Microsoft Corporation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +Apache License 2.0 + - anstream 1.0.0 (https://github.com/rust-cli/anstyle.git) + - anstyle-parse 1.0.0 (https://github.com/rust-cli/anstyle.git) + - anstyle-query 1.1.5 (https://github.com/rust-cli/anstyle.git) + - anstyle-wincon 3.0.11 (https://github.com/rust-cli/anstyle.git) + - anstyle 1.0.13 (https://github.com/rust-cli/anstyle.git) + - clap 4.6.0 (https://github.com/clap-rs/clap) + - clap_builder 4.6.0 (https://github.com/clap-rs/clap) + - clap_derive 4.6.0 (https://github.com/clap-rs/clap) + - clap_lex 1.0.0 (https://github.com/clap-rs/clap) + - colorchoice 1.0.4 (https://github.com/rust-cli/anstyle.git) + - is_terminal_polyfill 1.70.2 (https://github.com/polyfill-rs/is_terminal_polyfill) + - once_cell_polyfill 1.70.2 (https://github.com/polyfill-rs/once_cell_polyfill) + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +------------------------------------------------------------------------------- +Apache License 2.0 + - arbitrary 1.4.2 (https://github.com/rust-fuzz/arbitrary/) + - bitflags 1.3.2 (https://github.com/bitflags/bitflags) + - bumpalo 3.20.2 (https://github.com/fitzgen/bumpalo) + - cfg-if 1.0.4 (https://github.com/rust-lang/cfg-if) + - equivalent 1.0.2 (https://github.com/indexmap-rs/equivalent) + - fnv 1.0.7 (https://github.com/servo/rust-fnv) + - gimli 0.33.0 (https://github.com/gimli-rs/gimli) + - hashbrown 0.15.5 (https://github.com/rust-lang/hashbrown) + - hashbrown 0.16.1 (https://github.com/rust-lang/hashbrown) + - heck 0.5.0 (https://github.com/withoutboats/heck) + - indexmap 2.13.0 (https://github.com/indexmap-rs/indexmap) + - log 0.4.29 (https://github.com/rust-lang/log) + - smallvec 1.15.1 (https://github.com/servo/rust-smallvec) + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +Apache License 2.0 + - allocator-api2 0.2.21 (https://github.com/zakarumych/allocator-api2) + - anyhow 1.0.101 (https://github.com/dtolnay/anyhow) + - cranelift-assembler-x64 0.130.0 + - cranelift-bitset 0.130.0 (https://github.com/bytecodealliance/wasmtime) + - libc 0.2.182 (https://github.com/rust-lang/libc) + - mach2 0.4.3 (https://github.com/JohnTitor/mach2) + - proc-macro2 1.0.106 (https://github.com/dtolnay/proc-macro2) + - quote 1.0.45 (https://github.com/dtolnay/quote) + - rustc-hash 2.1.1 (https://github.com/rust-lang/rustc-hash) + - syn 2.0.117 (https://github.com/dtolnay/syn) + - unicode-ident 1.0.24 (https://github.com/dtolnay/unicode-ident) + - utf8parse 0.2.2 (https://github.com/alacritty/vte) + - wasmtime-internal-core 43.0.0 + - wasmtime-internal-jit-icache-coherence 43.0.0 (https://github.com/bytecodealliance/wasmtime) + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +MIT License + - region 3.0.2 (https://github.com/darfink/region-rs) + +Copyright (c) 2016 Elliott Linder + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +MIT License + - dsp56300-core 0.1.1 (https://github.com/mborgerson/dsp56300) + - dsp56300-emu 0.1.1 (https://github.com/mborgerson/dsp56300) + - libm 0.2.16 (https://github.com/rust-lang/compiler-builtins) + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +MIT License + - strsim 0.11.1 (https://github.com/rapidfuzz/strsim-rs) + +The MIT License (MIT) + +Copyright (c) 2015 Danny Guo +Copyright (c) 2016 Titus Wormer +Copyright (c) 2018 Akash Kurdekar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +Unicode License v3 + - unicode-ident 1.0.24 (https://github.com/dtolnay/unicode-ident) + +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2023 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +------------------------------------------------------------------------------- +zlib License + - foldhash 0.2.0 (https://github.com/orlp/foldhash) + +Copyright (c) 2024 Orson Peters + +This software is provided 'as-is', without any express or implied warranty. In +no event will the authors be held liable for any damages arising from the use of +this software. + +Permission is granted to anyone to use this software for any purpose, including +commercial applications, and to alter it and redistribute it freely, subject to +the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim + that you wrote the original software. If you use this software in a product, + an acknowledgment in the product documentation would be appreciated but is + not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index f9aaa959cb..264fa016ae 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -122,4 +122,15 @@ for sp in "${subprojects[@]}"; do tar --append --file "$tar_file" --exclude=.git --transform "s,^./,$tar_prefix," ./subprojects/"$(subproject_dir $sp)" test $? -ne 0 && error "failed to append subproject $sp to $tar_file" done + +# Pre-download dsp56300 pre-built libraries for offline builds (e.g. PPA). +dsp56300_version=$(sed -n "s/^project.*version: *'\([^']*\)'.*/\1/p" subprojects/dsp56300/meson.build) +for target in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do + archive="dsp56300-${dsp56300_version}-${target}.tar.gz" + curl -fsSL "https://github.com/mborgerson/dsp56300/releases/download/v${dsp56300_version}/${archive}" \ + -o "subprojects/dsp56300/${archive}" + tar --append --file "$tar_file" --transform "s,^./,$tar_prefix," "./subprojects/dsp56300/${archive}" + rm "subprojects/dsp56300/${archive}" +done + exit 0 diff --git a/scripts/gen-license.py b/scripts/gen-license.py index c4697d3ca6..aec974ffc3 100755 --- a/scripts/gen-license.py +++ b/scripts/gen-license.py @@ -510,6 +510,17 @@ LIBS = [ platform={windows}, submodule=Submodule("subprojects/curl.wrap"), ), + Lib( + "dsp56300", + "https://github.com/mborgerson/dsp56300", + mit, + # Note: This URL points to the dsp56300 license, but the distributed library includes + # additional dependencies. The license file at licenses/dsp56300.license.txt contains + # the dsp56300 license as well as its dependencies. + "https://raw.githubusercontent.com/mborgerson/dsp56300/refs/heads/main/LICENSE", + ships_static=all_platforms, + version="0.1.3", + ), ] diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 662a34f4bd..2d61cdf376 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -39,3 +39,5 @@ genconfig curl-* json-* SDL3-* +/dsp56300/* +!/dsp56300/meson.build diff --git a/subprojects/dsp56300/meson.build b/subprojects/dsp56300/meson.build new file mode 100644 index 0000000000..808b1716d8 --- /dev/null +++ b/subprojects/dsp56300/meson.build @@ -0,0 +1,48 @@ +project('dsp56300', version: '0.1.3') + +fs = import('fs') + +host_cpu = host_machine.cpu_family() +host_os = host_machine.system() + +if host_os == 'darwin' + os_suffix = 'apple-darwin' +elif host_os == 'windows' + os_suffix = (host_cpu == 'aarch64') ? 'pc-windows-gnullvm' : 'pc-windows-gnu' +elif host_os == 'linux' + os_suffix = 'unknown-linux-gnu' +else + error('Unsupported host OS: ' + host_os) +endif +rust_target = host_cpu + '-' + os_suffix + +ver = meson.project_version() +prefix = 'dsp56300-@0@-@1@'.format(ver, rust_target) +archive = '@0@.tar.gz'.format(prefix) +url = 'https://github.com/mborgerson/dsp56300/releases/download/v@0@/@1@'.format(ver, archive) +lib = meson.current_build_dir() / prefix / 'lib' / 'libdsp56300_emu_ffi.a' + +if not fs.exists(lib) + src_archive = meson.current_source_dir() / archive + if not fs.exists(src_archive) + message('Downloading dsp56300 @0@ for @1@...'.format(ver, rust_target)) + run_command(find_program('curl'), '-fsSL', url, '-o', src_archive, check: true) + endif + run_command('tar', 'xzf', src_archive, '-C', meson.current_build_dir(), check: true) +endif + +link_args = [] +if host_os == 'linux' + link_args = ['-lpthread', '-ldl', '-lm'] +elif host_os == 'windows' + link_args = ['-lbcrypt', '-lntdll', '-luserenv', '-lws2_32'] +elif host_os == 'darwin' + link_args = ['-lpthread', '-lm', '-framework', 'Security'] +endif + +dsp56300_dep = declare_dependency( + link_args: [lib] + link_args, + include_directories: include_directories(prefix / 'include'), +) + +meson.override_dependency('dsp56300-emu-ffi', dsp56300_dep) diff --git a/ui/xui/debug.cc b/ui/xui/debug.cc index 6c98ede711..b6ad33c38d 100644 --- a/ui/xui/debug.cc +++ b/ui/xui/debug.cc @@ -207,6 +207,8 @@ void DebugApuWindow::Draw() mcpx_apu_debug_set_monitor((McpxApuDebugMonitorPoint)mon); } + ImGui::Checkbox("JIT Engine\n", &g_config.audio.use_dsp_jit); + static bool gp_realtime; gp_realtime = dbg->gp_realtime; if (ImGui::Checkbox("GP Realtime\n", &gp_realtime)) { diff --git a/ui/xui/main-menu.cc b/ui/xui/main-menu.cc index 0cb8257e53..85997c1a5e 100644 --- a/ui/xui/main-menu.cc +++ b/ui/xui/main-menu.cc @@ -846,6 +846,8 @@ void MainMenuAudioView::Draw() SectionTitle("Quality"); Toggle("Real-time DSP processing", &g_config.audio.use_dsp, "Enable improved audio accuracy (experimental)"); + Toggle("DSP JIT engine", &g_config.audio.use_dsp_jit, + "Use DSP JIT engine"); }