Merge pull request #123 from gameblabla/diablofix_hack
[pcsx_rearmed.git] / plugins / dfsound / spu_c64x.c
index 200ab38..e0aa0da 100644 (file)
@@ -43,8 +43,29 @@ static struct {
 
  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;
@@ -63,7 +84,7 @@ static void thread_work_start(void)
 
  // to start the DSP, dsp_rpc_send() must be used,
  // but before that, previous request must be finished
- if (worker->req_sent) {
+ if (f.req_sent) {
   if (worker->boot_cnt == worker->last_boot_cnt) {
    // hopefully still booting
    //printf("booting?\n");
@@ -74,7 +95,7 @@ static void thread_work_start(void)
   if (ret != 0) {
    fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret);
    f.dsp_logbuf_print();
-   worker->req_sent = 0;
+   f.req_sent = 0;
    spu_config.iUseThread = 0;
    return;
   }
@@ -82,9 +103,11 @@ static void thread_work_start(void)
 
  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->spu_config, &spu_config, sizeof(mem->spu_config));
+ 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);
@@ -94,7 +117,12 @@ static void thread_work_start(void)
   spu_config.iUseThread = 0;
   return;
  }
- worker->req_sent = 1;
+ f.req_sent = 1;
+
+#if 0
+ f.dsp_rpc_recv(&msg);
+ f.req_sent = 0;
+#endif
 }
 
 static int thread_get_i_done(void)
@@ -108,14 +136,18 @@ static void thread_work_wait_sync(struct work_item *work, int force)
  int limit = 1000;
  int ns_to;
 
- ns_to = work->ns_to;
- f.dsp_cache_inv_virt(work->RVB, sizeof(work->RVB[0]) * 2 * ns_to);
- f.dsp_cache_inv_virt(work->SSumLR, sizeof(work->SSumLR[0]) * 2 * ns_to);
- __builtin_prefetch(work->RVB);
- __builtin_prefetch(work->SSumLR);
+ if ((unsigned int)(worker->i_done - worker->i_reaped) > WORK_MAXCNT) {
+  dsp_fault();
+  return;
+ }
 
  while (worker->i_done == worker->i_reaped && limit-- > 0) {
-  if (!worker->active) {
+  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;
@@ -125,6 +157,13 @@ static void thread_work_wait_sync(struct work_item *work, int force)
   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");
 
@@ -132,7 +171,7 @@ static void thread_work_wait_sync(struct work_item *work, int force)
  if (worker->i_reaped != worker->i_done - 1)
   return;
 
- if (worker->req_sent && (force || worker->i_done == worker->i_ready)) {
+ if (f.req_sent && (force || worker->i_done == worker->i_ready)) {
   dsp_msg_t msg;
   int ret;
 
@@ -142,12 +181,20 @@ static void thread_work_wait_sync(struct work_item *work, int force)
    f.dsp_logbuf_print();
    spu_config.iUseThread = 0;
   }
-  worker->req_sent = 0;
+  f.req_sent = 0;
  }
+}
 
- if (force) {
+static void thread_sync_caches(void)
+{
+ 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);
+  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;
  }
 }
 
@@ -206,7 +253,7 @@ static void init_spu_thread(void)
  }
  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, f.compid, CCMD_INIT, f.region.phys_addr, 0);
  ret = f.dsp_rpc(&init_msg, &msg_in);
@@ -220,9 +267,9 @@ 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_spos_3_20 != offsetof(typeof(*mem), worker.i[3].ch[20])) {
@@ -237,7 +284,9 @@ static void init_spu_thread(void)
  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)f.compid);
@@ -267,8 +316,10 @@ static void exit_spu_thread(void)
  if (worker == NULL)
   return;
 
- if (worker->req_sent)
+ if (f.req_sent) {
   f.dsp_rpc_recv(&msg);
+  f.req_sent = 0;
+ }
 
  f.dsp_logbuf_print();
  f.dsp_shm_free(f.region);
@@ -277,7 +328,27 @@ static void exit_spu_thread(void)
  spu.spuMemC = 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