dma kinda

This commit is contained in:
espes 2015-06-13 19:55:48 +10:00
parent 8f556211d9
commit 7f336a762e
5 changed files with 239 additions and 22 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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