X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu_c64x.c;h=e0aa0da224926608ef9f795d2537cbc946a3a813;hp=d829d29757419c3e27fa91c1676f6c2e7ff7d08d;hb=8a55ebcc07d4f860633db8c77bb9e16bcfa03313;hpb=de4a0279efefdd2e4595c8fc27f1564f4bff9341 diff --git a/plugins/dfsound/spu_c64x.c b/plugins/dfsound/spu_c64x.c index d829d297..e0aa0da2 100644 --- a/plugins/dfsound/spu_c64x.c +++ b/plugins/dfsound/spu_c64x.c @@ -23,13 +23,11 @@ #include #include +#include #include #include "spu_c64x.h" -static dsp_mem_region_t region; -static dsp_component_id_t compid; - static struct { void *handle; int (*dsp_open)(void); @@ -42,49 +40,161 @@ static struct { int (*dsp_rpc_recv)(dsp_msg_t *_msgFrom); int (*dsp_rpc)(const dsp_msg_t *_msgTo, dsp_msg_t *_msgFrom); void (*dsp_logbuf_print)(void); + + dsp_mem_region_t region; + dsp_component_id_t compid; + unsigned int stale_caches:1; + unsigned int req_sent:1; } f; +static noinline void dsp_fault(void) +{ + dsp_msg_t msg; + + f.dsp_cache_inv_virt(worker, sizeof(*worker)); + printf("dsp crash/fault/corruption:\n"); + printf("state rdy/reap/done: %u %u %u\n", + worker->i_ready, worker->i_reaped, worker->i_done); + printf("active/boot: %u %u\n", + worker->active, worker->boot_cnt); + + if (f.req_sent) { + f.dsp_rpc_recv(&msg); + f.req_sent = 0; + } + f.dsp_logbuf_print(); + spu_config.iUseThread = 0; +} + static void thread_work_start(void) { + struct region_mem *mem; dsp_msg_t msg; int ret; - DSP_MSG_INIT(&msg, compid, CCMD_DOIT, 0, 0); + // make sure new work is written out + __sync_synchronize(); + + // this should be safe, as dsp checks for new work even + // after it decrements ->active + // cacheline: i_done, active + f.dsp_cache_inv_virt(&worker->i_done, 64); + if (worker->active == ACTIVE_CNT) + return; + + // to start the DSP, dsp_rpc_send() must be used, + // but before that, previous request must be finished + if (f.req_sent) { + if (worker->boot_cnt == worker->last_boot_cnt) { + // hopefully still booting + //printf("booting?\n"); + return; + } + + ret = f.dsp_rpc_recv(&msg); + if (ret != 0) { + fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret); + f.dsp_logbuf_print(); + f.req_sent = 0; + spu_config.iUseThread = 0; + return; + } + } + + f.dsp_cache_inv_virt(&worker->i_done, 64); + worker->last_boot_cnt = worker->boot_cnt; + worker->ram_dirty = spu.bMemDirty; + spu.bMemDirty = 0; + + mem = (void *)f.region.virt_addr; + memcpy(&mem->in.spu_config, &spu_config, sizeof(mem->in.spu_config)); + + DSP_MSG_INIT(&msg, f.compid, CCMD_DOIT, f.region.phys_addr, 0); ret = f.dsp_rpc_send(&msg); if (ret != 0) { fprintf(stderr, "dsp_rpc_send failed: %d\n", ret); f.dsp_logbuf_print(); - // maybe stop using the DSP? + spu_config.iUseThread = 0; + return; } + f.req_sent = 1; + +#if 0 + f.dsp_rpc_recv(&msg); + f.req_sent = 0; +#endif } -static void thread_work_wait_sync(void) +static int thread_get_i_done(void) { - dsp_msg_t msg; + f.dsp_cache_inv_virt(&worker->i_done, sizeof(worker->i_done)); + return worker->i_done; +} + +static void thread_work_wait_sync(struct work_item *work, int force) +{ + int limit = 1000; int ns_to; - int ret; - ns_to = worker->ns_to; - f.dsp_cache_inv_virt(spu.sRVBStart, sizeof(spu.sRVBStart[0]) * 2 * ns_to); - f.dsp_cache_inv_virt(SSumLR, sizeof(SSumLR[0]) * 2 * ns_to); - f.dsp_cache_inv_virt(&worker->r, sizeof(worker->r)); - worker->stale_cache = 1; // SB, ram + if ((unsigned int)(worker->i_done - worker->i_reaped) > WORK_MAXCNT) { + dsp_fault(); + return; + } - ret = f.dsp_rpc_recv(&msg); - if (ret != 0) { - fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret); - f.dsp_logbuf_print(); + while (worker->i_done == worker->i_reaped && limit-- > 0) { + if (!f.req_sent) { + printf("dsp: req not sent?\n"); + break; + } + + if (worker->boot_cnt != worker->last_boot_cnt && !worker->active) { + printf("dsp: broken sync\n"); + worker->last_boot_cnt = ~0; + break; + } + + usleep(500); + f.dsp_cache_inv_virt(&worker->i_done, 64); + } + + ns_to = work->ns_to; + f.dsp_cache_inv_virt(work->SSumLR, sizeof(work->SSumLR[0]) * 2 * ns_to); + preload(work->SSumLR); + preload(work->SSumLR + 64/4); + + f.stale_caches = 1; // SB, spuMem + + if (limit == 0) + printf("dsp: wait timeout\n"); + + // still in results loop? + if (worker->i_reaped != worker->i_done - 1) + return; + + if (f.req_sent && (force || worker->i_done == worker->i_ready)) { + dsp_msg_t msg; + int ret; + + ret = f.dsp_rpc_recv(&msg); + if (ret != 0) { + fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret); + f.dsp_logbuf_print(); + spu_config.iUseThread = 0; + } + f.req_sent = 0; } - //f.dsp_logbuf_print(); } -// called before ARM decides to do SPU mixing itself static void thread_sync_caches(void) { - if (worker->stale_cache) { + if (f.stale_caches) { f.dsp_cache_inv_virt(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24); f.dsp_cache_inv_virt(spu.spuMemC + 0x800, 0x800); - worker->stale_cache = 0; + if (spu.rvb->StartAddr) { + int left = 0x40000 - spu.rvb->StartAddr; + f.dsp_cache_inv_virt(spu.spuMem + spu.rvb->StartAddr, left * 2); + } + f.stale_caches = 0; } } @@ -101,7 +211,7 @@ static void init_spu_thread(void) f.handle = dlopen(lib, RTLD_NOW); if (f.handle == NULL) { fprintf(stderr, "can't load %s: %s\n", lib, dlerror()); - return; + goto fail_open; } #define LDS(name) \ failed |= (f.name = dlsym(f.handle, #name)) == NULL @@ -120,32 +230,32 @@ static void init_spu_thread(void) fprintf(stderr, "missing symbol(s) in %s\n", lib); dlclose(f.handle); f.handle = NULL; - return; + goto fail_open; } } ret = f.dsp_open(); if (ret != 0) { fprintf(stderr, "dsp_open failed: %d\n", ret); - return; + goto fail_open; } - ret = f.dsp_component_load(NULL, COMPONENT_NAME, &compid); + ret = f.dsp_component_load(NULL, COMPONENT_NAME, &f.compid); if (ret != 0) { fprintf(stderr, "dsp_component_load failed: %d\n", ret); goto fail_cload; } - region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough - if (region.size < sizeof(*mem) || region.virt_addr == 0) { + f.region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough + if (f.region.size < sizeof(*mem) || f.region.virt_addr == 0) { fprintf(stderr, "dsp_shm_alloc failed\n"); goto fail_mem; } - mem = (void *)region.virt_addr; + mem = (void *)f.region.virt_addr; - memcpy(&mem->spu_config, &spu_config, sizeof(mem->spu_config)); + memcpy(&mem->in.spu_config, &spu_config, sizeof(mem->in.spu_config)); - DSP_MSG_INIT(&init_msg, compid, CCMD_INIT, region.phys_addr, 0); + DSP_MSG_INIT(&init_msg, f.compid, CCMD_INIT, f.region.phys_addr, 0); ret = f.dsp_rpc(&init_msg, &msg_in); if (ret != 0) { fprintf(stderr, "dsp_rpc failed: %d\n", ret); @@ -157,64 +267,88 @@ static void init_spu_thread(void) mem->sizeof_region_mem, sizeof(*mem)); goto fail_init; } - if (mem->offsetof_s_chan1 != offsetof(typeof(*mem), s_chan[1])) { + if (mem->offsetof_s_chan1 != offsetof(typeof(*mem), in.s_chan[1])) { fprintf(stderr, "error: size mismatch 2: %d vs %zd\n", - mem->offsetof_s_chan1, offsetof(typeof(*mem), s_chan[1])); + mem->offsetof_s_chan1, offsetof(typeof(*mem), in.s_chan[1])); goto fail_init; } - if (mem->offsetof_worker_ram != offsetof(typeof(*mem), worker.ch[1])) { + if (mem->offsetof_spos_3_20 != offsetof(typeof(*mem), worker.i[3].ch[20])) { fprintf(stderr, "error: size mismatch 3: %d vs %zd\n", - mem->offsetof_worker_ram, offsetof(typeof(*mem), worker.ch[1])); + mem->offsetof_spos_3_20, offsetof(typeof(*mem), worker.i[3].ch[20])); goto fail_init; } // override default allocations free(spu.spuMemC); spu.spuMemC = mem->spu_ram; - free(spu.sRVBStart); - spu.sRVBStart = mem->RVB; - free(SSumLR); - SSumLR = mem->SSumLR; free(spu.SB); spu.SB = mem->SB; free(spu.s_chan); - spu.s_chan = mem->s_chan; + spu.s_chan = mem->in.s_chan; + free(spu.rvb); + spu.rvb = &mem->in.rvb; worker = &mem->worker; - printf("spu: C64x DSP ready (id=%d).\n", (int)compid); + printf("spu: C64x DSP ready (id=%d).\n", (int)f.compid); f.dsp_logbuf_print(); -pcnt_init(); + spu_config.iThreadAvail = 1; (void)do_channel_work; // used by DSP instead return; fail_init: - f.dsp_shm_free(region); + f.dsp_shm_free(f.region); fail_mem: // no component unload func? fail_cload: - printf("spu: C64x DSP init failed.\n"); f.dsp_logbuf_print(); f.dsp_close(); +fail_open: + printf("spu: C64x DSP init failed.\n"); + spu_config.iUseThread = spu_config.iThreadAvail = 0; worker = NULL; } static void exit_spu_thread(void) { + dsp_msg_t msg; + if (worker == NULL) return; - if (worker->pending) - thread_work_wait_sync(); - f.dsp_shm_free(region); + if (f.req_sent) { + f.dsp_rpc_recv(&msg); + f.req_sent = 0; + } + + f.dsp_logbuf_print(); + f.dsp_shm_free(f.region); f.dsp_close(); spu.spuMemC = NULL; - spu.sRVBStart = NULL; - SSumLR = NULL; spu.SB = NULL; spu.s_chan = NULL; + spu.rvb = NULL; worker = NULL; } +/* debug: "access" shared mem from gdb */ +#if 0 +struct region_mem *dbg_dsp_mem; + +void dbg_dsp_mem_update(void) +{ + struct region_mem *mem; + + if (dbg_dsp_mem == NULL) + dbg_dsp_mem = malloc(sizeof(*dbg_dsp_mem)); + if (dbg_dsp_mem == NULL) + return; + + mem = (void *)f.region.virt_addr; + f.dsp_cache_inv_virt(mem, sizeof(*mem)); + memcpy(dbg_dsp_mem, mem, sizeof(*dbg_dsp_mem)); +} +#endif + // vim:shiftwidth=1:expandtab