mirror of https://github.com/xemu-project/xemu.git
Merge 6c447c3d70
into a143f66ce4
This commit is contained in:
commit
5319b7577c
|
@ -2571,7 +2571,7 @@ const VMStateDescription vmstate_vp_dsp_core_state = {
|
|||
VMSTATE_UINT32(num_inst, dsp_core_t),
|
||||
VMSTATE_UINT32(cur_inst_len, dsp_core_t),
|
||||
VMSTATE_UINT32(cur_inst, dsp_core_t),
|
||||
VMSTATE_BOOL(executing_for_disasm, 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),
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MCPX DSP emulator
|
||||
|
||||
* Copyright (c) 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.
|
||||
|
||||
* 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 HW_XBOX_MCPX_DSP_DEBUG_H
|
||||
#define HW_XBOX_MCPX_DSP_DEBUG_H
|
||||
|
||||
#ifndef DEBUG_DSP
|
||||
#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__); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
|
@ -2,6 +2,7 @@
|
|||
* 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
|
||||
|
@ -23,17 +24,12 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dsp_cpu.h"
|
||||
#include "dsp_dma.h"
|
||||
#include "dsp_state.h"
|
||||
|
||||
#include "dsp.h"
|
||||
#include "debug.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* Defines */
|
||||
#define BITMASK(x) ((1<<(x))-1)
|
||||
|
@ -42,16 +38,6 @@
|
|||
#define INTERRUPT_START_FRAME (1 << 1)
|
||||
#define INTERRUPT_DMA_EOL (1 << 7)
|
||||
|
||||
// #define DEBUG_DSP
|
||||
|
||||
#ifdef DEBUG_DSP
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
|
@ -91,8 +77,6 @@ void dsp_destroy(DSPState* dsp)
|
|||
static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) {
|
||||
DSPState* dsp = container_of(core, DSPState, core);
|
||||
|
||||
DPRINTF("read_peripheral 0x%06x", address);
|
||||
|
||||
uint32_t v = 0xababa;
|
||||
switch(address) {
|
||||
case 0xFFFFB3:
|
||||
|
@ -118,15 +102,13 @@ static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) {
|
|||
break;
|
||||
}
|
||||
|
||||
DPRINTF(" -> 0x%06x\n", v);
|
||||
trace_dsp_read_peripheral(address, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) {
|
||||
DSPState* dsp = container_of(core, DSPState, core);
|
||||
|
||||
DPRINTF("write_peripheral [0x%06x] = 0x%06x\n", address, value);
|
||||
|
||||
switch(address) {
|
||||
case 0xFFFFC4:
|
||||
if (value & 1) {
|
||||
|
@ -152,6 +134,8 @@ static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value)
|
|||
dsp_dma_write(&dsp->dma, DMA_CONFIGURATION, value);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_dsp_write_peripheral(address, value);
|
||||
}
|
||||
|
||||
|
||||
|
@ -201,7 +185,7 @@ void dsp_bootstrap(DSPState* dsp)
|
|||
(uint8_t*)dsp->core.pram, 0, 0x800*4, false);
|
||||
for (int i = 0; i < 0x800; i++) {
|
||||
if (dsp->core.pram[i] & 0xff000000) {
|
||||
DPRINTF(stderr, "Bootstrap %04x: %08x\n", i, dsp->core.pram[i]);
|
||||
DPRINTF("Bootstrap %04x: %08x\n", i, dsp->core.pram[i]);
|
||||
dsp->core.pram[i] &= 0x00ffffff;
|
||||
}
|
||||
}
|
||||
|
@ -213,19 +197,6 @@ void dsp_start_frame(DSPState* dsp)
|
|||
dsp->interrupts |= INTERRUPT_START_FRAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassemble DSP code between given addresses, return next PC address
|
||||
*/
|
||||
uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr)
|
||||
{
|
||||
uint32_t dsp_pc;
|
||||
|
||||
for (dsp_pc=lowerAdr; dsp_pc<=UpperAdr; dsp_pc++) {
|
||||
dsp_pc += dsp56k_execute_one_disasm_instruction(&dsp->core, out, dsp_pc);
|
||||
}
|
||||
return dsp_pc;
|
||||
}
|
||||
|
||||
uint32_t dsp_read_memory(DSPState* dsp, char space, uint32_t address)
|
||||
{
|
||||
int space_id;
|
||||
|
@ -269,259 +240,3 @@ void dsp_write_memory(DSPState* dsp, char space, uint32_t address, uint32_t valu
|
|||
|
||||
dsp56k_write_memory(&dsp->core, space_id, address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ typedef void (*dsp_scratch_rw_func)(
|
|||
typedef void (*dsp_fifo_rw_func)(
|
||||
void *opaque, uint8_t *ptr, unsigned int index, size_t len, bool dir);
|
||||
|
||||
/* Dsp commands */
|
||||
DSPState *dsp_init(void *rw_opaque,
|
||||
dsp_scratch_rw_func scratch_rw,
|
||||
dsp_fifo_rw_func fifo_rw);
|
||||
|
@ -49,16 +48,14 @@ void dsp_run(DSPState* dsp, int cycles);
|
|||
void dsp_bootstrap(DSPState* dsp);
|
||||
void dsp_start_frame(DSPState* dsp);
|
||||
|
||||
|
||||
/* Dsp Debugger commands */
|
||||
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 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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
#endif /* DSP_H */
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* DSP56300 emulator
|
||||
*
|
||||
* Copyright (c) 2015 espes
|
||||
* Copyright (c) 2020-2025 Matt Borgerson
|
||||
*
|
||||
* Adapted from Hatari DSP M56001 emulation
|
||||
* (C) 2003-2008 ARAnyM developer team
|
||||
|
@ -23,20 +24,10 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
|
||||
#include "dsp_cpu.h"
|
||||
|
||||
#define TRACE_DSP_DISASM 0
|
||||
#define TRACE_DSP_DISASM_REG 0
|
||||
#define TRACE_DSP_DISASM_MEM 0
|
||||
|
||||
#define DPRINTF(s, ...) printf(s, ## __VA_ARGS__)
|
||||
#include "debug.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define BITMASK(x) ((1<<(x))-1)
|
||||
|
||||
|
@ -415,7 +406,6 @@ void dsp56k_reset_cpu(dsp_core_t* dsp)
|
|||
|
||||
/* runtime shit */
|
||||
|
||||
dsp->executing_for_disasm = false;
|
||||
// start_time = SDL_GetTicks();
|
||||
dsp->num_inst = 0;
|
||||
|
||||
|
@ -462,7 +452,7 @@ static uint16_t disasm_instruction(dsp_core_t* dsp, dsp_trace_disasm_t mode)
|
|||
if (mode == DSP_TRACE_MODE) {
|
||||
if (dsp->disasm_prev_inst_pc == dsp->pc) {
|
||||
if (!dsp->disasm_is_looping) {
|
||||
printf( "Looping on DSP instruction at PC = $%04x\n", dsp->disasm_prev_inst_pc);
|
||||
DPRINTF("Looping on DSP instruction at PC = $%04x\n", dsp->disasm_prev_inst_pc);
|
||||
dsp->disasm_is_looping = true;
|
||||
}
|
||||
return 0;
|
||||
|
@ -520,7 +510,7 @@ static void disasm_reg_compare(dsp_core_t* dsp)
|
|||
case DSP_REG_X1:
|
||||
case DSP_REG_Y0:
|
||||
case DSP_REG_Y1:
|
||||
printf("\tReg: %s $%06x -> $%06x\n",
|
||||
DPRINTF("\tReg: %s $%06x -> $%06x\n",
|
||||
registers_name[i], dsp->disasm_registers_save[i], dsp->registers[i]);
|
||||
break;
|
||||
case DSP_REG_R0:
|
||||
|
@ -550,21 +540,21 @@ static void disasm_reg_compare(dsp_core_t* dsp)
|
|||
case DSP_REG_SR:
|
||||
case DSP_REG_LA:
|
||||
case DSP_REG_LC:
|
||||
printf("\tReg: %s $%04x -> $%04x\n",
|
||||
DPRINTF("\tReg: %s $%04x -> $%04x\n",
|
||||
registers_name[i], dsp->disasm_registers_save[i], dsp->registers[i]);
|
||||
break;
|
||||
case DSP_REG_OMR:
|
||||
case DSP_REG_SP:
|
||||
case DSP_REG_SSH:
|
||||
case DSP_REG_SSL:
|
||||
printf("\tReg: %s $%02x -> $%02x\n",
|
||||
DPRINTF("\tReg: %s $%02x -> $%02x\n",
|
||||
registers_name[i], dsp->disasm_registers_save[i], dsp->registers[i]);
|
||||
break;
|
||||
case DSP_REG_A0:
|
||||
case DSP_REG_A1:
|
||||
case DSP_REG_A2:
|
||||
if (bRegA == false) {
|
||||
printf("\tReg: a $%02x:%06x:%06x -> $%02x:%06x:%06x\n",
|
||||
DPRINTF("\tReg: a $%02x:%06x:%06x -> $%02x:%06x:%06x\n",
|
||||
dsp->disasm_registers_save[DSP_REG_A2], dsp->disasm_registers_save[DSP_REG_A1], dsp->disasm_registers_save[DSP_REG_A0],
|
||||
dsp->registers[DSP_REG_A2], dsp->registers[DSP_REG_A1], dsp->registers[DSP_REG_A0]
|
||||
);
|
||||
|
@ -575,7 +565,7 @@ static void disasm_reg_compare(dsp_core_t* dsp)
|
|||
case DSP_REG_B1:
|
||||
case DSP_REG_B2:
|
||||
if (bRegB == false) {
|
||||
printf("\tReg: b $%02x:%06x:%06x -> $%02x:%06x:%06x\n",
|
||||
DPRINTF("\tReg: b $%02x:%06x:%06x -> $%02x:%06x:%06x\n",
|
||||
dsp->disasm_registers_save[DSP_REG_B2], dsp->disasm_registers_save[DSP_REG_B1], dsp->disasm_registers_save[DSP_REG_B0],
|
||||
dsp->registers[DSP_REG_B2], dsp->registers[DSP_REG_B1], dsp->registers[DSP_REG_B0]
|
||||
);
|
||||
|
@ -587,70 +577,28 @@ static void disasm_reg_compare(dsp_core_t* dsp)
|
|||
|
||||
#ifdef DSP_DISASM_REG_PC
|
||||
if (pc_save != dsp->pc) {
|
||||
printf("\tReg: pc $%04x -> $%04x\n", pc_save, dsp->pc);
|
||||
DPRINTF("\tReg: pc $%04x -> $%04x\n", pc_save, dsp->pc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char* disasm_get_instruction_text(dsp_core_t* dsp)
|
||||
{
|
||||
// const int len = sizeof(dsp->disasm_str_instr);
|
||||
// uint64_t count, cycles;
|
||||
// uint16_t cycle_diff;
|
||||
// float percentage;
|
||||
// int offset;
|
||||
|
||||
if (dsp->disasm_is_looping) {
|
||||
dsp->disasm_str_instr2[0] = 0;
|
||||
}
|
||||
// if (dsp->disasm_cur_inst_len == 1) {
|
||||
// offset = sprintf(dsp->disasm_str_instr2, "p:%04x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, dsp->instr_cycle, len, dsp->disasm_str_instr);
|
||||
// } else {
|
||||
// offset = sprintf(dsp->disasm_str_instr2, "p:%04x %06x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, read_memory_p(dsp, dsp->disasm_prev_inst_pc + 1), dsp->instr_cycle, len, dsp->disasm_str_instr);
|
||||
// }
|
||||
// if (offset > 2 && Profile_DspAddressData(dsp->disasm_prev_inst_pc, &percentage, &count, &cycles, &cycle_diff)) {
|
||||
// offset -= 2;
|
||||
// sprintf(str_instr2+offset, "%5.2f%% (%"PRId64", %"PRId64", %d)\n",
|
||||
// percentage, count, cycles, cycle_diff);
|
||||
// }
|
||||
if (dsp->disasm_cur_inst_len == 1) {
|
||||
snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x (%02d cyc) %s", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, dsp->instr_cycle, dsp->disasm_str_instr);
|
||||
} else {
|
||||
snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x %06x (%02d cyc) %s", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, read_memory_p(dsp, dsp->disasm_prev_inst_pc + 1), dsp->instr_cycle, dsp->disasm_str_instr);
|
||||
}
|
||||
return dsp->disasm_str_instr2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute one instruction in trace mode at a given PC address.
|
||||
* */
|
||||
uint16_t dsp56k_execute_one_disasm_instruction(dsp_core_t* dsp, FILE *out, uint32_t pc)
|
||||
{
|
||||
dsp_core_t dsp_core_save;
|
||||
|
||||
/* Set DSP in disasm mode */
|
||||
dsp->executing_for_disasm = true;
|
||||
|
||||
/* Save DSP context before executing instruction */
|
||||
memcpy(&dsp_core_save, dsp, sizeof(dsp_core_t));
|
||||
|
||||
/* execute and disasm instruction */
|
||||
dsp->pc = pc;
|
||||
|
||||
/* Disasm instruction */
|
||||
uint16_t instruction_length = disasm_instruction(dsp, DSP_DISASM_MODE) - 1;
|
||||
|
||||
/* Execute instruction at address given in parameter to get the number of cycles it takes */
|
||||
dsp56k_execute_instruction(dsp);
|
||||
|
||||
fprintf(out, "%s", disasm_get_instruction_text(dsp));
|
||||
|
||||
/* Restore DSP context after executing instruction */
|
||||
memcpy(dsp, &dsp_core_save, sizeof(dsp_core_t));
|
||||
|
||||
/* Unset DSP in disasm mode */
|
||||
dsp->executing_for_disasm = false;
|
||||
|
||||
return instruction_length;
|
||||
}
|
||||
|
||||
void dsp56k_execute_instruction(dsp_core_t* dsp)
|
||||
{
|
||||
trace_dsp56k_execute_instruction(dsp->is_gp, dsp->pc);
|
||||
|
||||
uint32_t disasm_return = 0;
|
||||
dsp->disasm_memory_ptr = 0;
|
||||
|
||||
|
@ -661,17 +609,18 @@ void dsp56k_execute_instruction(dsp_core_t* dsp)
|
|||
dsp->cur_inst_len = 1;
|
||||
dsp->instr_cycle = 2;
|
||||
|
||||
/* Disasm current instruction ? (trace mode only) */
|
||||
if (TRACE_DSP_DISASM) {
|
||||
/* Call disasm_instruction only when DSP is called in trace mode */
|
||||
if (!dsp->executing_for_disasm) {
|
||||
disasm_return = disasm_instruction(dsp, DSP_TRACE_MODE);
|
||||
bool tracing = TRACE_DSP_DISASM || trace_event_get_state(TRACE_DSP56K_EXECUTE_INSTRUCTION_DISASM);
|
||||
|
||||
if (disasm_return) {
|
||||
printf( "%s", disasm_get_instruction_text(dsp));
|
||||
/* Disasm current instruction ? (trace mode only) */
|
||||
if (tracing) {
|
||||
disasm_return = disasm_instruction(dsp, DSP_TRACE_MODE);
|
||||
if (disasm_return) {
|
||||
const char *text = disasm_get_instruction_text(dsp);
|
||||
trace_dsp56k_execute_instruction_disasm(text);
|
||||
if (TRACE_DSP_DISASM) {
|
||||
DPRINTF("%s\n", text);
|
||||
}
|
||||
if (disasm_return != 0 && TRACE_DSP_DISASM_REG) {
|
||||
/* DSP regs trace enabled only if DSP DISASM is enabled */
|
||||
if (TRACE_DSP_DISASM_REG) {
|
||||
disasm_reg_save(dsp);
|
||||
}
|
||||
}
|
||||
|
@ -686,7 +635,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp)
|
|||
if (op->emu_func) {
|
||||
op->emu_func(dsp);
|
||||
} else {
|
||||
printf("%x - %s\n", dsp->cur_inst, op->name);
|
||||
DPRINTF("%x - %s\n", dsp->cur_inst, op->name);
|
||||
emu_undefined(dsp);
|
||||
}
|
||||
} else {
|
||||
|
@ -695,26 +644,18 @@ void dsp56k_execute_instruction(dsp_core_t* dsp)
|
|||
}
|
||||
|
||||
/* Disasm current instruction ? (trace mode only) */
|
||||
if (TRACE_DSP_DISASM) {
|
||||
/* Display only when DSP is called in trace mode */
|
||||
if (!dsp->executing_for_disasm) {
|
||||
if (disasm_return != 0) {
|
||||
// printf( "%s", disasm_get_instruction_text(dsp));
|
||||
|
||||
/* DSP regs trace enabled only if DSP DISASM is enabled */
|
||||
if (TRACE_DSP_DISASM_REG)
|
||||
disasm_reg_compare(dsp);
|
||||
|
||||
if (TRACE_DSP_DISASM_MEM) {
|
||||
/* 1 memory change to display ? */
|
||||
if (dsp->disasm_memory_ptr == 1)
|
||||
printf( "\t%s\n", dsp->str_disasm_memory[0]);
|
||||
/* 2 memory changes to display ? */
|
||||
else if (dsp->disasm_memory_ptr == 2) {
|
||||
printf( "\t%s\n", dsp->str_disasm_memory[0]);
|
||||
printf( "\t%s\n", dsp->str_disasm_memory[1]);
|
||||
}
|
||||
}
|
||||
if (tracing && disasm_return) {
|
||||
if (TRACE_DSP_DISASM_REG) {
|
||||
disasm_reg_compare(dsp);
|
||||
}
|
||||
if (TRACE_DSP_DISASM_MEM) {
|
||||
/* 1 memory change to display ? */
|
||||
if (dsp->disasm_memory_ptr == 1)
|
||||
DPRINTF("\t%s\n", dsp->str_disasm_memory[0]);
|
||||
/* 2 memory changes to display ? */
|
||||
else if (dsp->disasm_memory_ptr == 2) {
|
||||
DPRINTF("\t%s\n", dsp->str_disasm_memory[0]);
|
||||
DPRINTF("\t%s\n", dsp->str_disasm_memory[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -734,7 +675,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp)
|
|||
/* Evaluate time after <N> instructions have been executed to avoid asking too frequently */
|
||||
uint32_t cur_time = SDL_GetTicks();
|
||||
if (cur_time-start_time>1000) {
|
||||
printf( "Dsp: %d i/s\n", (dsp->num_inst*1000)/(cur_time-start_time));
|
||||
DPRINTF("Dsp: %d i/s\n", (dsp->num_inst*1000)/(cur_time-start_time));
|
||||
start_time=cur_time;
|
||||
dsp->num_inst=0;
|
||||
}
|
||||
|
@ -1122,9 +1063,7 @@ static void dsp_write_reg(dsp_core_t* dsp, uint32_t numreg, uint32_t value)
|
|||
/* Stack underflow or overflow detected, raise interrupt */
|
||||
dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR);
|
||||
dsp->registers[DSP_REG_SP] = value & (3<<DSP_SP_SE);
|
||||
if (!dsp->executing_for_disasm) {
|
||||
printf( "Dsp: Stack Overflow or Underflow\n");
|
||||
}
|
||||
DPRINTF("Dsp: Stack Overflow or Underflow\n");
|
||||
if (dsp->exception_debugging) {
|
||||
assert(false);
|
||||
}
|
||||
|
@ -1167,8 +1106,7 @@ static void dsp_stack_push(dsp_core_t* dsp, uint32_t curpc, uint32_t cursr, uint
|
|||
if ((stack_error==0) && (stack & (1<<DSP_SP_SE))) {
|
||||
/* Stack full, raise interrupt */
|
||||
dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR);
|
||||
if (!dsp->executing_for_disasm)
|
||||
printf("Dsp: Stack Overflow\n");
|
||||
DPRINTF("Dsp: Stack Overflow\n");
|
||||
if (dsp->exception_debugging)
|
||||
assert(false);
|
||||
}
|
||||
|
@ -1204,8 +1142,7 @@ static void dsp_stack_pop(dsp_core_t* dsp, uint32_t *newpc, uint32_t *newsr)
|
|||
if ((stack_error==0) && (stack & (1<<DSP_SP_SE))) {
|
||||
/* Stack empty*/
|
||||
dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR);
|
||||
if (!dsp->executing_for_disasm)
|
||||
printf("Dsp: Stack underflow\n");
|
||||
DPRINTF("Dsp: Stack underflow\n");
|
||||
if (dsp->exception_debugging)
|
||||
assert(false);
|
||||
}
|
||||
|
@ -1458,5 +1395,3 @@ static uint32_t dsp_signextend(int bits, uint32_t v) {
|
|||
assert(shift > 0);
|
||||
return (uint32_t)(((int32_t)v << shift) >> shift);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,115 +29,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DSP_OMR_MA 0x00
|
||||
#define DSP_OMR_MB 0x01
|
||||
#define DSP_OMR_DE 0x02
|
||||
#define DSP_OMR_SD 0x06
|
||||
#define DSP_OMR_EA 0x07
|
||||
|
||||
#define DSP_SR_C 0x00
|
||||
#define DSP_SR_V 0x01
|
||||
#define DSP_SR_Z 0x02
|
||||
#define DSP_SR_N 0x03
|
||||
#define DSP_SR_U 0x04
|
||||
#define DSP_SR_E 0x05
|
||||
#define DSP_SR_L 0x06
|
||||
|
||||
#define DSP_SR_I0 0x08
|
||||
#define DSP_SR_I1 0x09
|
||||
#define DSP_SR_S0 0x0a
|
||||
#define DSP_SR_S1 0x0b
|
||||
#define DSP_SR_T 0x0d
|
||||
#define DSP_SR_LF 0x0f
|
||||
|
||||
#define DSP_SP_SE 0x04
|
||||
#define DSP_SP_UF 0x05
|
||||
|
||||
/* Registers numbers in dsp.registers[] */
|
||||
#define DSP_REG_X0 0x04
|
||||
#define DSP_REG_X1 0x05
|
||||
#define DSP_REG_Y0 0x06
|
||||
#define DSP_REG_Y1 0x07
|
||||
#define DSP_REG_A0 0x08
|
||||
#define DSP_REG_B0 0x09
|
||||
#define DSP_REG_A2 0x0a
|
||||
#define DSP_REG_B2 0x0b
|
||||
#define DSP_REG_A1 0x0c
|
||||
#define DSP_REG_B1 0x0d
|
||||
#define DSP_REG_A 0x0e
|
||||
#define DSP_REG_B 0x0f
|
||||
|
||||
#define DSP_REG_R0 0x10
|
||||
#define DSP_REG_R1 0x11
|
||||
#define DSP_REG_R2 0x12
|
||||
#define DSP_REG_R3 0x13
|
||||
#define DSP_REG_R4 0x14
|
||||
#define DSP_REG_R5 0x15
|
||||
#define DSP_REG_R6 0x16
|
||||
#define DSP_REG_R7 0x17
|
||||
|
||||
#define DSP_REG_N0 0x18
|
||||
#define DSP_REG_N1 0x19
|
||||
#define DSP_REG_N2 0x1a
|
||||
#define DSP_REG_N3 0x1b
|
||||
#define DSP_REG_N4 0x1c
|
||||
#define DSP_REG_N5 0x1d
|
||||
#define DSP_REG_N6 0x1e
|
||||
#define DSP_REG_N7 0x1f
|
||||
|
||||
#define DSP_REG_M0 0x20
|
||||
#define DSP_REG_M1 0x21
|
||||
#define DSP_REG_M2 0x22
|
||||
#define DSP_REG_M3 0x23
|
||||
#define DSP_REG_M4 0x24
|
||||
#define DSP_REG_M5 0x25
|
||||
#define DSP_REG_M6 0x26
|
||||
#define DSP_REG_M7 0x27
|
||||
|
||||
#define DSP_REG_SR 0x39
|
||||
#define DSP_REG_OMR 0x3a
|
||||
#define DSP_REG_SP 0x3b
|
||||
#define DSP_REG_SSH 0x3c
|
||||
#define DSP_REG_SSL 0x3d
|
||||
#define DSP_REG_LA 0x3e
|
||||
#define DSP_REG_LC 0x3f
|
||||
|
||||
#define DSP_REG_NULL 0x00
|
||||
#define DSP_REG_LCSAVE 0x30
|
||||
|
||||
#define DSP_REG_MAX 0x40
|
||||
|
||||
/* Memory spaces for dsp.ram[], dsp.rom[] */
|
||||
#define DSP_SPACE_X 0x00
|
||||
#define DSP_SPACE_Y 0x01
|
||||
#define DSP_SPACE_P 0x02
|
||||
|
||||
#define DSP_XRAM_SIZE 4096
|
||||
#define DSP_YRAM_SIZE 2048
|
||||
#define DSP_PRAM_SIZE 4096
|
||||
|
||||
#define DSP_MIXBUFFER_BASE 0x001400
|
||||
#define DSP_MIXBUFFER_SIZE 1024
|
||||
|
||||
#define DSP_PERIPH_BASE 0xFFFF80
|
||||
#define DSP_PERIPH_SIZE 128
|
||||
|
||||
#define DSP_INTERRUPT_NONE 0x0
|
||||
#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
|
||||
#include "dsp_cpu_regs.h"
|
||||
|
||||
typedef enum {
|
||||
DSP_TRACE_MODE,
|
||||
|
@ -209,10 +101,6 @@ struct dsp_core_s {
|
|||
/* Current instruction */
|
||||
uint32_t cur_inst;
|
||||
|
||||
/* DSP is in disasm mode ? */
|
||||
/* If yes, stack overflow, underflow and illegal instructions messages are not displayed */
|
||||
bool executing_for_disasm;
|
||||
|
||||
char str_disasm_memory[2][50]; /* Buffer for memory change text in disasm mode */
|
||||
uint32_t disasm_memory_ptr; /* Pointer for memory change in disasm mode */
|
||||
|
||||
|
@ -250,7 +138,6 @@ struct dsp_core_s {
|
|||
/* Functions */
|
||||
void dsp56k_reset_cpu(dsp_core_t* dsp); /* Set dsp_core to use */
|
||||
void dsp56k_execute_instruction(dsp_core_t* dsp); /* Execute 1 instruction */
|
||||
uint16_t dsp56k_execute_one_disasm_instruction(dsp_core_t* dsp, FILE *out, uint32_t pc); /* Execute 1 instruction in disasm mode */
|
||||
|
||||
uint32_t dsp56k_read_memory(dsp_core_t* dsp, int space, uint32_t address);
|
||||
void dsp56k_write_memory(dsp_core_t* dsp, int space, uint32_t address, uint32_t value);
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* DSP56300 emulator
|
||||
*
|
||||
* Copyright (c) 2015 espes
|
||||
*
|
||||
* Adapted from Hatari DSP M56001 emulation
|
||||
* (C) 2003-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 HW_XBOX_MCPX_DSP_DSP_CPU_REGS_H
|
||||
#define HW_XBOX_MCPX_DSP_DSP_CPU_REGS_H
|
||||
|
||||
#define DSP_OMR_MA 0x00
|
||||
#define DSP_OMR_MB 0x01
|
||||
#define DSP_OMR_DE 0x02
|
||||
#define DSP_OMR_SD 0x06
|
||||
#define DSP_OMR_EA 0x07
|
||||
|
||||
#define DSP_SR_C 0x00
|
||||
#define DSP_SR_V 0x01
|
||||
#define DSP_SR_Z 0x02
|
||||
#define DSP_SR_N 0x03
|
||||
#define DSP_SR_U 0x04
|
||||
#define DSP_SR_E 0x05
|
||||
#define DSP_SR_L 0x06
|
||||
|
||||
#define DSP_SR_I0 0x08
|
||||
#define DSP_SR_I1 0x09
|
||||
#define DSP_SR_S0 0x0a
|
||||
#define DSP_SR_S1 0x0b
|
||||
#define DSP_SR_T 0x0d
|
||||
#define DSP_SR_LF 0x0f
|
||||
|
||||
#define DSP_SP_SE 0x04
|
||||
#define DSP_SP_UF 0x05
|
||||
|
||||
/* Registers numbers in dsp.registers[] */
|
||||
#define DSP_REG_X0 0x04
|
||||
#define DSP_REG_X1 0x05
|
||||
#define DSP_REG_Y0 0x06
|
||||
#define DSP_REG_Y1 0x07
|
||||
#define DSP_REG_A0 0x08
|
||||
#define DSP_REG_B0 0x09
|
||||
#define DSP_REG_A2 0x0a
|
||||
#define DSP_REG_B2 0x0b
|
||||
#define DSP_REG_A1 0x0c
|
||||
#define DSP_REG_B1 0x0d
|
||||
#define DSP_REG_A 0x0e
|
||||
#define DSP_REG_B 0x0f
|
||||
|
||||
#define DSP_REG_R0 0x10
|
||||
#define DSP_REG_R1 0x11
|
||||
#define DSP_REG_R2 0x12
|
||||
#define DSP_REG_R3 0x13
|
||||
#define DSP_REG_R4 0x14
|
||||
#define DSP_REG_R5 0x15
|
||||
#define DSP_REG_R6 0x16
|
||||
#define DSP_REG_R7 0x17
|
||||
|
||||
#define DSP_REG_N0 0x18
|
||||
#define DSP_REG_N1 0x19
|
||||
#define DSP_REG_N2 0x1a
|
||||
#define DSP_REG_N3 0x1b
|
||||
#define DSP_REG_N4 0x1c
|
||||
#define DSP_REG_N5 0x1d
|
||||
#define DSP_REG_N6 0x1e
|
||||
#define DSP_REG_N7 0x1f
|
||||
|
||||
#define DSP_REG_M0 0x20
|
||||
#define DSP_REG_M1 0x21
|
||||
#define DSP_REG_M2 0x22
|
||||
#define DSP_REG_M3 0x23
|
||||
#define DSP_REG_M4 0x24
|
||||
#define DSP_REG_M5 0x25
|
||||
#define DSP_REG_M6 0x26
|
||||
#define DSP_REG_M7 0x27
|
||||
|
||||
#define DSP_REG_SR 0x39
|
||||
#define DSP_REG_OMR 0x3a
|
||||
#define DSP_REG_SP 0x3b
|
||||
#define DSP_REG_SSH 0x3c
|
||||
#define DSP_REG_SSL 0x3d
|
||||
#define DSP_REG_LA 0x3e
|
||||
#define DSP_REG_LC 0x3f
|
||||
|
||||
#define DSP_REG_NULL 0x00
|
||||
#define DSP_REG_LCSAVE 0x30
|
||||
|
||||
#define DSP_REG_MAX 0x40
|
||||
|
||||
/* Memory spaces for dsp.ram[], dsp.rom[] */
|
||||
#define DSP_SPACE_X 0x00
|
||||
#define DSP_SPACE_Y 0x01
|
||||
#define DSP_SPACE_P 0x02
|
||||
|
||||
#define DSP_XRAM_SIZE 4096
|
||||
#define DSP_YRAM_SIZE 2048
|
||||
#define DSP_PRAM_SIZE 4096
|
||||
|
||||
#define DSP_MIXBUFFER_BASE 0x001400
|
||||
#define DSP_MIXBUFFER_SIZE 1024
|
||||
|
||||
#define DSP_PERIPH_BASE 0xFFFF80
|
||||
#define DSP_PERIPH_SIZE 128
|
||||
|
||||
#define DSP_INTERRUPT_NONE 0x0
|
||||
#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
|
||||
|
||||
#endif
|
|
@ -18,48 +18,14 @@
|
|||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/compiler.h"
|
||||
#include "dsp_dma.h"
|
||||
#include "dsp_dma_regs.h"
|
||||
#include "dsp_state.h"
|
||||
|
||||
|
||||
#define DMA_CONFIGURATION_AUTOSTART (1 << 0)
|
||||
#define DMA_CONFIGURATION_AUTOREADY (1 << 1)
|
||||
#define DMA_CONFIGURATION_IOC_CLEAR (1 << 2)
|
||||
#define DMA_CONFIGURATION_EOL_CLEAR (1 << 3)
|
||||
#define DMA_CONFIGURATION_ERR_CLEAR (1 << 4)
|
||||
|
||||
#define DMA_CONTROL_ACTION 0x7
|
||||
#define DMA_CONTROL_ACTION_NOP 0
|
||||
#define DMA_CONTROL_ACTION_START 1
|
||||
#define DMA_CONTROL_ACTION_STOP 2
|
||||
#define DMA_CONTROL_ACTION_FREEZE 3
|
||||
#define DMA_CONTROL_ACTION_UNFREEZE 4
|
||||
#define DMA_CONTROL_ACTION_ABORT 5
|
||||
#define DMA_CONTROL_FROZEN (1 << 3)
|
||||
#define DMA_CONTROL_RUNNING (1 << 4)
|
||||
#define DMA_CONTROL_STOPPED (1 << 5)
|
||||
|
||||
#define NODE_POINTER_VAL 0x3fff
|
||||
#define NODE_POINTER_EOL (1 << 14)
|
||||
|
||||
#define NODE_CONTROL_DIRECTION (1 << 1)
|
||||
|
||||
|
||||
// #define DEBUG
|
||||
#ifdef DEBUG
|
||||
# define DPRINTF(s, ...) printf(s, ## __VA_ARGS__)
|
||||
#else
|
||||
# define DPRINTF(s, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *buffer_names[] = {
|
||||
"fifo0", /* 0x0 */
|
||||
"fifo1", /* 0x1 */
|
||||
|
@ -98,8 +64,6 @@ const char *space_names[] = {
|
|||
|
||||
#endif
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
static void scratch_circular_copy(
|
||||
DSPDMAState *s,
|
||||
uint32_t scratch_base,
|
||||
|
@ -142,8 +106,6 @@ static void dsp_dma_run(DSPDMAState *s)
|
|||
return;
|
||||
}
|
||||
|
||||
// DSPState *dsp = container_of(s, DSPState, dma);
|
||||
|
||||
while (!(s->next_block & NODE_POINTER_EOL)) {
|
||||
uint32_t addr = s->next_block & NODE_POINTER_VAL;
|
||||
uint32_t block_addr = 0;
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* MCPX DSP DMA
|
||||
*
|
||||
* Copyright (c) 2015 espes
|
||||
* Copyright (c) 2020-2025 Matt Borgerson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_XBOX_MCPX_DSP_DSP_DMA_REGS_H
|
||||
#define HW_XBOX_MCPX_DSP_DSP_DMA_REGS_H
|
||||
|
||||
#define DMA_CONFIGURATION_AUTOSTART (1 << 0)
|
||||
#define DMA_CONFIGURATION_AUTOREADY (1 << 1)
|
||||
#define DMA_CONFIGURATION_IOC_CLEAR (1 << 2)
|
||||
#define DMA_CONFIGURATION_EOL_CLEAR (1 << 3)
|
||||
#define DMA_CONFIGURATION_ERR_CLEAR (1 << 4)
|
||||
|
||||
#define DMA_CONTROL_ACTION 0x7
|
||||
#define DMA_CONTROL_ACTION_NOP 0
|
||||
#define DMA_CONTROL_ACTION_START 1
|
||||
#define DMA_CONTROL_ACTION_STOP 2
|
||||
#define DMA_CONTROL_ACTION_FREEZE 3
|
||||
#define DMA_CONTROL_ACTION_UNFREEZE 4
|
||||
#define DMA_CONTROL_ACTION_ABORT 5
|
||||
#define DMA_CONTROL_FROZEN (1 << 3)
|
||||
#define DMA_CONTROL_RUNNING (1 << 4)
|
||||
#define DMA_CONTROL_STOPPED (1 << 5)
|
||||
|
||||
#define NODE_POINTER_VAL 0x3fff
|
||||
#define NODE_POINTER_EOL (1 << 14)
|
||||
|
||||
#define NODE_CONTROL_DIRECTION (1 << 1)
|
||||
|
||||
#endif
|
|
@ -27,15 +27,10 @@ typedef void (*emu_func_t)(dsp_core_t* dsp);
|
|||
|
||||
static void emu_undefined(dsp_core_t* dsp)
|
||||
{
|
||||
if (!dsp->executing_for_disasm) {
|
||||
dsp->cur_inst_len = 0;
|
||||
printf("Dsp: 0x%04x: 0x%06x Illegal instruction\n",dsp->pc, dsp->cur_inst);
|
||||
/* Add some artificial CPU cycles to avoid being stuck in an infinite loop */
|
||||
dsp->instr_cycle += 100;
|
||||
} else {
|
||||
dsp->cur_inst_len = 1;
|
||||
dsp->instr_cycle = 0;
|
||||
}
|
||||
dsp->cur_inst_len = 0;
|
||||
printf("Dsp: 0x%04x: 0x%06x Illegal instruction\n",dsp->pc, dsp->cur_inst);
|
||||
/* Add some artificial CPU cycles to avoid being stuck in an infinite loop */
|
||||
dsp->instr_cycle += 100;
|
||||
if (dsp->exception_debugging) {
|
||||
assert(false);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
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))
|
|
@ -0,0 +1,9 @@
|
|||
# See docs/devel/tracing.rst for syntax documentation.
|
||||
|
||||
# dsp.c
|
||||
dsp_read_peripheral(uint32_t addr, uint32_t val) "addr 0x%"PRIx32" val 0x%"PRIx64
|
||||
dsp_write_peripheral(uint32_t addr, uint32_t val) "addr 0x%"PRIx32" val 0x%"PRIx64
|
||||
|
||||
# dsp_cpu.c
|
||||
dsp56k_execute_instruction(uint32_t id, uint32_t pc) "[gp=%d]: pc=0x%"PRIx32
|
||||
dsp56k_execute_instruction_disasm(const char *disasm) "%s"
|
|
@ -0,0 +1 @@
|
|||
#include "trace/trace-hw_xbox_mcpx_dsp.h"
|
|
@ -1,10 +1,9 @@
|
|||
subdir('dsp')
|
||||
|
||||
mcpx_ss = ss.source_set()
|
||||
mcpx_ss.add(sdl, libsamplerate, files(
|
||||
mcpx_ss.add(sdl, libsamplerate, dsp, files(
|
||||
'apu.c',
|
||||
'aci.c',
|
||||
'dsp/dsp.c',
|
||||
'dsp/dsp_cpu.c',
|
||||
'dsp/dsp_dma.c',
|
||||
))
|
||||
|
||||
specific_ss.add_all(mcpx_ss)
|
|
@ -3771,6 +3771,7 @@ if have_system
|
|||
'hw/remote',
|
||||
'hw/xbox/nv2a',
|
||||
'hw/xbox/mcpx',
|
||||
'hw/xbox/mcpx/dsp',
|
||||
'hw/xbox',
|
||||
]
|
||||
endif
|
||||
|
|
|
@ -86,3 +86,4 @@ subdir('qapi-schema')
|
|||
subdir('qtest')
|
||||
subdir('migration')
|
||||
subdir('functional')
|
||||
subdir('xbox')
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
all: basic
|
||||
|
||||
%: %.a56
|
||||
a56 -o $@ $<
|
|
@ -0,0 +1,12 @@
|
|||
P 0000 0C0040
|
||||
P 0040 0AF080
|
||||
P 0041 000042
|
||||
P 0042 56F400
|
||||
P 0043 123456
|
||||
P 0044 567000
|
||||
P 0045 000003
|
||||
P 0046 08F484
|
||||
P 0047 000001
|
||||
P 0048 0C0042
|
||||
I 000040 start
|
||||
I 000042 mainloop
|
|
@ -0,0 +1,12 @@
|
|||
org p:$0000
|
||||
jmp <start
|
||||
|
||||
org p:$40
|
||||
start
|
||||
jmp mainloop
|
||||
|
||||
mainloop
|
||||
move #$123456,A
|
||||
move A,X:3
|
||||
movep #$000001,x:$ffffc4
|
||||
jmp <mainloop
|
|
@ -0,0 +1,13 @@
|
|||
test_env = environment()
|
||||
test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
|
||||
test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
|
||||
|
||||
exe = executable('test-dsp',
|
||||
sources: files('test-dsp.c'),
|
||||
dependencies: [dsp, glib])
|
||||
|
||||
test('dsp', exe,
|
||||
env: test_env,
|
||||
args: ['--tap', '-k'],
|
||||
protocol: 'tap',
|
||||
suite: ['dsp'])
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* DSP tests.
|
||||
*
|
||||
* Copyright (c) 2025 Matt Borgerson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xbox/mcpx/dsp/dsp.h"
|
||||
|
||||
static void scratch_rw(void *opaque, uint8_t *ptr, uint32_t addr, size_t len, bool dir)
|
||||
{
|
||||
assert(!"Not implemented");
|
||||
}
|
||||
|
||||
static void fifo_rw(void *opaque, uint8_t *ptr, unsigned int index, size_t len, bool dir)
|
||||
{
|
||||
assert(!"Not implemented");
|
||||
}
|
||||
|
||||
static void load_prog(DSPState *s, const char *path)
|
||||
{
|
||||
FILE *file = fopen(path, "r");
|
||||
assert(file && "Error opening file");
|
||||
|
||||
char type, line[100], arg1[20], arg2[20];
|
||||
int addr, value;
|
||||
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
if (sscanf(line, "%c %s %s", &type, arg1, arg2) >= 2) {
|
||||
switch (type) {
|
||||
case 'P':
|
||||
case 'X':
|
||||
case 'Y': {
|
||||
assert(sscanf(arg1, "%x", &addr) == 1);
|
||||
assert(sscanf(arg2, "%x", &value) == 1);
|
||||
dsp_write_memory(s, type, addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Invalid line: %s\n", line);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
static void test_dsp_basic(void)
|
||||
{
|
||||
g_autofree gchar *path = g_test_build_filename(G_TEST_DIST, "data", "basic", NULL);
|
||||
|
||||
DSPState *s = dsp_init(NULL, scratch_rw, fifo_rw);
|
||||
|
||||
load_prog(s, path);
|
||||
dsp_run(s, 1000);
|
||||
|
||||
uint32_t v = dsp_read_memory(s, 'X', 3);
|
||||
assert(v == 0x123456);
|
||||
|
||||
dsp_destroy(s);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func("/basic", test_dsp_basic);
|
||||
|
||||
return g_test_run();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
subdir('dsp')
|
Loading…
Reference in New Issue