mirror of https://github.com/xemu-project/xemu.git
dma kinda
This commit is contained in:
parent
8f556211d9
commit
7f336a762e
|
@ -27,7 +27,7 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include "qemu-common.h"
|
||||
|
||||
#include "dsp_cpu.h"
|
||||
#include "dsp_dma.h"
|
||||
|
@ -38,12 +38,9 @@
|
|||
#define BITMASK(x) ((1<<(x))-1)
|
||||
#define ARRAYSIZE(x) (int)(sizeof(x)/sizeof(x[0]))
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *) 0)->member) *__mptr = (ptr); \
|
||||
(type *) ((char *) __mptr - offsetof(type, member));})
|
||||
#endif
|
||||
|
||||
#define INTERRUPT_ABORT_FRAME (1 << 0)
|
||||
#define INTERRUPT_START_FRAME (1 << 1)
|
||||
#define INTERRUPT_DMA_EOL (1 << 7)
|
||||
|
||||
#define DPRINTF(s, ...) fprintf(stderr, s, ## __VA_ARGS__)
|
||||
|
||||
|
@ -51,12 +48,14 @@ struct DSPState {
|
|||
dsp_core_t core;
|
||||
DSPDMAState dma;
|
||||
int save_cycles;
|
||||
|
||||
uint32_t interrupts;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
DSPState* dsp_init(void)
|
||||
DSPState* dsp_init(void* scratch_rw_opaque, dsp_scratch_rw_func scratch_rw)
|
||||
{
|
||||
DPRINTF("dsp_init\n");
|
||||
|
||||
|
@ -66,7 +65,12 @@ DSPState* dsp_init(void)
|
|||
dsp->core.read_peripheral = read_peripheral;
|
||||
dsp->core.write_peripheral = write_peripheral;
|
||||
|
||||
dsp->dma.core = &dsp->core;
|
||||
dsp->dma.scratch_rw_opaque = scratch_rw_opaque;
|
||||
dsp->dma.scratch_rw = scratch_rw;
|
||||
|
||||
dsp_reset(dsp);
|
||||
|
||||
return dsp;
|
||||
}
|
||||
|
||||
|
@ -86,13 +90,30 @@ static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) {
|
|||
|
||||
printf("read_peripheral 0x%06x\n", address);
|
||||
|
||||
uint32_t v = 0xababa;
|
||||
switch(address) {
|
||||
// case 0xFFFFC5: // interrupt
|
||||
case 0xFFFFC5:
|
||||
v = dsp->interrupts;
|
||||
if (dsp->dma.eol) {
|
||||
v |= INTERRUPT_DMA_EOL;
|
||||
}
|
||||
break;
|
||||
case 0xFFFFD4:
|
||||
v = dsp_dma_read(&dsp->dma, DMA_NEXT_BLOCK);
|
||||
break;
|
||||
case 0xFFFFD5:
|
||||
v = dsp_dma_read(&dsp->dma, DMA_START_BLOCK);
|
||||
break;
|
||||
case 0xFFFFD6:
|
||||
return dsp_dma_read(&dsp->dma, DMA_CONTROL);
|
||||
v = dsp_dma_read(&dsp->dma, DMA_CONTROL);
|
||||
break;
|
||||
case 0xFFFFD7:
|
||||
v = dsp_dma_read(&dsp->dma, DMA_CONFIGURATION);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xababa;
|
||||
printf(" -> 0x%06x\n", v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) {
|
||||
|
@ -101,9 +122,24 @@ static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value)
|
|||
printf("write_peripheral [0x%06x] = 0x%06x\n", address, value);
|
||||
|
||||
switch(address) {
|
||||
// case 0xFFFFC5: // interrupt
|
||||
case 0xFFFFC5:
|
||||
dsp->interrupts &= ~value;
|
||||
if (value & INTERRUPT_DMA_EOL) {
|
||||
dsp->dma.eol = false;
|
||||
}
|
||||
break;
|
||||
case 0xFFFFD4:
|
||||
dsp_dma_write(&dsp->dma, DMA_NEXT_BLOCK, value);
|
||||
break;
|
||||
case 0xFFFFD5:
|
||||
dsp_dma_write(&dsp->dma, DMA_START_BLOCK, value);
|
||||
break;
|
||||
case 0xFFFFD6:
|
||||
return dsp_dma_write(&dsp->dma, DMA_CONTROL, value);
|
||||
dsp_dma_write(&dsp->dma, DMA_CONTROL, value);
|
||||
break;
|
||||
case 0xFFFFD7:
|
||||
dsp_dma_write(&dsp->dma, DMA_CONFIGURATION, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,6 +178,10 @@ void dsp_bootstrap(DSPState* dsp, const uint32_t* pram, size_t len)
|
|||
memcpy(dsp->core.pram, pram, len);
|
||||
}
|
||||
|
||||
void dsp_start_frame(DSPState* dsp)
|
||||
{
|
||||
dsp->interrupts |= INTERRUPT_START_FRAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassemble DSP code between given addresses, return next PC address
|
||||
|
|
|
@ -31,8 +31,11 @@
|
|||
|
||||
typedef struct DSPState DSPState;
|
||||
|
||||
typedef void (*dsp_scratch_rw_func)(
|
||||
uint8_t* ptr, uint64_t addr, size_t len, bool dir);
|
||||
|
||||
/* Dsp commands */
|
||||
DSPState* dsp_init(void);
|
||||
DSPState* dsp_init(void* scratch_rw_opaque, dsp_scratch_rw_func scratch_rw);
|
||||
void dsp_destroy(DSPState* dsp);
|
||||
void dsp_reset(DSPState* dsp);
|
||||
|
||||
|
@ -40,6 +43,7 @@ void dsp_step(DSPState* dsp);
|
|||
void dsp_run(DSPState* dsp, int cycles);
|
||||
|
||||
void dsp_bootstrap(DSPState* dsp, const uint32_t* pmem, size_t len);
|
||||
void dsp_start_frame(DSPState* dsp);
|
||||
|
||||
|
||||
/* Dsp Debugger commands */
|
||||
|
|
|
@ -1,9 +1,138 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dsp_dma.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)
|
||||
|
||||
static void dsp_dma_run(DSPDMAState *s)
|
||||
{
|
||||
if (!(s->control & DMA_CONTROL_RUNNING)
|
||||
|| (s->control & DMA_CONTROL_FROZEN)) {
|
||||
return;
|
||||
}
|
||||
while (!(s->next_block & NODE_POINTER_EOL)) {
|
||||
uint32_t addr = s->next_block & NODE_POINTER_VAL;
|
||||
assert((addr+6) < sizeof(s->core->xram));
|
||||
|
||||
uint32_t next_block = s->core->xram[addr];
|
||||
uint32_t control = s->core->xram[addr+1];
|
||||
uint32_t count = s->core->xram[addr+2];
|
||||
uint32_t dsp_offset = s->core->xram[addr+3];
|
||||
uint32_t scratch_offset = s->core->xram[addr+4];
|
||||
uint32_t scratch_base = s->core->xram[addr+5];
|
||||
uint32_t scratch_size = s->core->xram[addr+6]+1;
|
||||
|
||||
printf("\n\n\nQQQ DMA addr %x, control %x, count %x, dsp_offset %x, scratch_offset %x, base %x, size %x\n\n\n",
|
||||
addr, control, count, dsp_offset, scratch_offset, scratch_base, scratch_size);
|
||||
|
||||
uint32_t format = (control >> 10) & 7;
|
||||
unsigned int item_size;
|
||||
uint32_t item_mask;
|
||||
switch(format) {
|
||||
case 2: //big-endian?
|
||||
case 6:
|
||||
item_size = 4;
|
||||
item_mask = 0x00FFFFFF;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t buf_id = (control >> 5) & 0xf;
|
||||
|
||||
size_t scratch_addr = scratch_offset;
|
||||
if (buf_id == 0xe) { // 'circular'?
|
||||
assert(scratch_addr == 0);
|
||||
assert(scratch_offset + count * item_size < scratch_size);
|
||||
scratch_addr += scratch_base; //??
|
||||
} else if (buf_id != 0xf) { // 'offset'?
|
||||
assert(false);
|
||||
}
|
||||
|
||||
uint32_t* dsp_ptr;
|
||||
if (dsp_offset < 0x1800) {
|
||||
assert(dsp_offset+count < sizeof(s->core->xram));
|
||||
dsp_ptr = s->core->xram + dsp_offset;
|
||||
} else if (dsp_offset >= 0x1800 && dsp_offset < 0x2000) { //?
|
||||
assert(dsp_offset-0x1800 + count < sizeof(s->core->yram));
|
||||
dsp_ptr = s->core->yram + dsp_offset - 0x1800;
|
||||
} else if (dsp_offset >= 0x2800 && dsp_offset < 0x3800) { //?
|
||||
assert(dsp_offset-0x2800 + count < sizeof(s->core->pram));
|
||||
dsp_ptr = s->core->pram + dsp_offset - 0x2800;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
uint8_t* scratch_buf = calloc(count, item_size);
|
||||
|
||||
assert(s->scratch_rw);
|
||||
|
||||
if (control & NODE_CONTROL_DIRECTION) {
|
||||
int i;
|
||||
for (i=0; i<count; i++) {
|
||||
switch(item_size) {
|
||||
case 4:
|
||||
*(uint32_t*)(scratch_buf + i*4) = dsp_ptr[i];
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write to scratch memory
|
||||
s->scratch_rw(scratch_buf, scratch_addr, count*item_size, 1);
|
||||
} else {
|
||||
// read from scratch memory
|
||||
s->scratch_rw(scratch_buf, scratch_addr, count*item_size, 0);
|
||||
|
||||
int i;
|
||||
for (i=0; i<count; i++) {
|
||||
switch(item_size) {
|
||||
case 4:
|
||||
dsp_ptr[i] = (*(uint32_t*)(scratch_buf + i*4)) & item_mask;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(scratch_buf);
|
||||
|
||||
s->next_block = next_block;
|
||||
|
||||
if (s->next_block & NODE_POINTER_EOL) {
|
||||
s->eol = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg)
|
||||
{
|
||||
switch (reg) {
|
||||
|
@ -20,6 +149,7 @@ uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dsp_dma_write(DSPDMAState *s, DSPDMARegister reg, uint32_t v)
|
||||
{
|
||||
switch (reg) {
|
||||
|
@ -27,7 +157,26 @@ void dsp_dma_write(DSPDMAState *s, DSPDMARegister reg, uint32_t v)
|
|||
s->configuration = v;
|
||||
break;
|
||||
case DMA_CONTROL:
|
||||
s->control = v;
|
||||
switch(v & DMA_CONTROL_ACTION) {
|
||||
case DMA_CONTROL_ACTION_START:
|
||||
s->control |= DMA_CONTROL_RUNNING;
|
||||
s->control &= ~DMA_CONTROL_STOPPED;
|
||||
break;
|
||||
case DMA_CONTROL_ACTION_STOP:
|
||||
s->control |= DMA_CONTROL_STOPPED;
|
||||
s->control &= ~DMA_CONTROL_RUNNING;
|
||||
break;
|
||||
case DMA_CONTROL_ACTION_FREEZE:
|
||||
s->control |= DMA_CONTROL_FROZEN;
|
||||
break;
|
||||
case DMA_CONTROL_ACTION_UNFREEZE:
|
||||
s->control &= ~DMA_CONTROL_FROZEN;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
dsp_dma_run(s);
|
||||
break;
|
||||
case DMA_START_BLOCK:
|
||||
s->start_block = v;
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
#define DSP_DMA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "dsp.h"
|
||||
#include "dsp_cpu.h"
|
||||
|
||||
typedef enum DSPDMARegister {
|
||||
DMA_CONFIGURATION,
|
||||
|
@ -11,10 +15,18 @@ typedef enum DSPDMARegister {
|
|||
} DSPDMARegister;
|
||||
|
||||
typedef struct DSPDMAState {
|
||||
dsp_core_t* core;
|
||||
|
||||
void* scratch_rw_opaque;
|
||||
dsp_scratch_rw_func scratch_rw;
|
||||
|
||||
uint32_t configuration;
|
||||
uint32_t control;
|
||||
uint32_t start_block;
|
||||
uint32_t next_block;
|
||||
|
||||
bool error;
|
||||
bool eol;
|
||||
} DSPDMAState;
|
||||
|
||||
uint32_t dsp_dma_read(DSPDMAState *s, DSPDMARegister reg);
|
||||
|
|
|
@ -7349,10 +7349,16 @@ static void emu_move_x_long(dsp_core_t* dsp) {
|
|||
uint32_t numreg = dsp->cur_inst & BITMASK(6);
|
||||
uint32_t x_addr = (dsp->registers[offreg] + xxxx) & BITMASK(24);
|
||||
|
||||
if (W) {
|
||||
dsp56k_write_memory(dsp, DSP_SPACE_X, x_addr, dsp->registers[numreg]);
|
||||
if (!W) {
|
||||
uint32_t value;
|
||||
if (numreg == DSP_REG_A || numreg == DSP_REG_B) {
|
||||
emu_pm_read_accu24(dsp, numreg, &value);
|
||||
} else {
|
||||
value = dsp->registers[numreg];
|
||||
}
|
||||
dsp56k_write_memory(dsp, DSP_SPACE_X, x_addr, value);
|
||||
} else {
|
||||
dsp->registers[numreg] = dsp56k_read_memory(dsp, DSP_SPACE_X, x_addr);
|
||||
dsp_write_reg(dsp, numreg, dsp56k_read_memory(dsp, DSP_SPACE_X, x_addr));
|
||||
}
|
||||
|
||||
// TODO: cycles
|
||||
|
@ -7367,10 +7373,16 @@ static void emu_move_x_imm(dsp_core_t* dsp) {
|
|||
uint32_t numreg = dsp->disasm_cur_inst & BITMASK(4);
|
||||
uint32_t x_addr = (dsp->registers[offreg] + dsp_signextend(7, xxx)) & BITMASK(24);
|
||||
|
||||
if (W) {
|
||||
dsp56k_write_memory(dsp, DSP_SPACE_X, x_addr, dsp->registers[numreg]);
|
||||
if (!W) {
|
||||
uint32_t value;
|
||||
if (numreg == DSP_REG_A || numreg == DSP_REG_B) {
|
||||
emu_pm_read_accu24(dsp, numreg, &value);
|
||||
} else {
|
||||
value = dsp->registers[numreg];
|
||||
}
|
||||
dsp56k_write_memory(dsp, DSP_SPACE_X, x_addr, value);
|
||||
} else {
|
||||
dsp->registers[numreg] = dsp56k_read_memory(dsp, DSP_SPACE_X, x_addr);
|
||||
dsp_write_reg(dsp, numreg, dsp56k_read_memory(dsp, DSP_SPACE_X, x_addr));
|
||||
}
|
||||
|
||||
// TODO: cycles
|
||||
|
|
Loading…
Reference in New Issue