dma: add optional slow linked list walking
[pcsx_rearmed.git] / plugins / gpulib / gpu.c
index d0bb526..f468cf8 100644 (file)
@@ -126,17 +126,16 @@ static noinline void get_gpu_info(uint32_t data)
     case 0x02:
     case 0x03:
     case 0x04:
-    case 0x05:
       gpu.gp0 = gpu.ex_regs[data & 7] & 0xfffff;
       break;
-    case 0x06:
-      gpu.gp0 = gpu.ex_regs[5] & 0xfffff;
+    case 0x05:
+      gpu.gp0 = gpu.ex_regs[5] & 0x3fffff;
       break;
     case 0x07:
       gpu.gp0 = 2;
       break;
     default:
-      gpu.gp0 = 0;
+      // gpu.gp0 unchanged
       break;
   }
 }
@@ -360,7 +359,7 @@ static void start_vram_transfer(uint32_t pos_word, uint32_t size_word, int is_re
   if (is_read) {
     gpu.status |= PSX_GPU_STATUS_IMG;
     // XXX: wrong for width 1
-    memcpy(&gpu.gp0, VRAM_MEM_XY(gpu.dma.x, gpu.dma.y), 4);
+    gpu.gp0 = LE32TOH(*(uint32_t *) VRAM_MEM_XY(gpu.dma.x, gpu.dma.y));
     gpu.state.last_vram_read_frame = *gpu.state.frame_count;
   }
 
@@ -386,12 +385,12 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
 
   while (pos < count && skip) {
     uint32_t *list = data + pos;
-    cmd = list[0] >> 24;
+    cmd = LE32TOH(list[0]) >> 24;
     len = 1 + cmd_lengths[cmd];
 
     switch (cmd) {
       case 0x02:
-        if ((list[2] & 0x3ff) > gpu.screen.w || ((list[2] >> 16) & 0x1ff) > gpu.screen.h)
+        if ((LE32TOH(list[2]) & 0x3ff) > gpu.screen.w || ((LE32TOH(list[2]) >> 16) & 0x1ff) > gpu.screen.h)
           // clearing something large, don't skip
           do_cmd_list(list, 3, &dummy);
         else
@@ -402,12 +401,12 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
       case 0x34 ... 0x37:
       case 0x3c ... 0x3f:
         gpu.ex_regs[1] &= ~0x1ff;
-        gpu.ex_regs[1] |= list[4 + ((cmd >> 4) & 1)] & 0x1ff;
+        gpu.ex_regs[1] |= LE32TOH(list[4 + ((cmd >> 4) & 1)]) & 0x1ff;
         break;
       case 0x48 ... 0x4F:
         for (v = 3; pos + v < count; v++)
         {
-          if ((list[v] & 0xf000f000) == 0x50005000)
+          if ((list[v] & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
             break;
         }
         len += v - 3;
@@ -415,16 +414,16 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
       case 0x58 ... 0x5F:
         for (v = 4; pos + v < count; v += 2)
         {
-          if ((list[v] & 0xf000f000) == 0x50005000)
+          if ((list[v] & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
             break;
         }
         len += v - 4;
         break;
       default:
         if (cmd == 0xe3)
-          skip = decide_frameskip_allow(list[0]);
+          skip = decide_frameskip_allow(LE32TOH(list[0]));
         if ((cmd & 0xf8) == 0xe0)
-          gpu.ex_regs[cmd & 7] = list[0];
+          gpu.ex_regs[cmd & 7] = LE32TOH(list[0]);
         break;
     }
 
@@ -459,7 +458,7 @@ static noinline int do_cmd_buffer(uint32_t *data, int count)
         break;
     }
 
-    cmd = data[pos] >> 24;
+    cmd = LE32TOH(data[pos]) >> 24;
     if (0xa0 <= cmd && cmd <= 0xdf) {
       if (unlikely((pos+2) >= count)) {
         // incomplete vram write/read cmd, can't consume yet
@@ -468,13 +467,13 @@ static noinline int do_cmd_buffer(uint32_t *data, int count)
       }
 
       // consume vram write/read cmd
-      start_vram_transfer(data[pos + 1], data[pos + 2], (cmd & 0xe0) == 0xc0);
+      start_vram_transfer(LE32TOH(data[pos + 1]), LE32TOH(data[pos + 2]), (cmd & 0xe0) == 0xc0);
       pos += 3;
       continue;
     }
 
     // 0xex cmds might affect frameskip.allow, so pass to do_cmd_list_skip
-    if (gpu.frameskip.active && (gpu.frameskip.allow || ((data[pos] >> 24) & 0xf0) == 0xe0))
+    if (gpu.frameskip.active && (gpu.frameskip.allow || ((LE32TOH(data[pos]) >> 24) & 0xf0) == 0xe0))
       pos += do_cmd_list_skip(data + pos, count - pos, &cmd);
     else {
       pos += do_cmd_list(data + pos, count - pos, &cmd);
@@ -523,12 +522,12 @@ void GPUwriteDataMem(uint32_t *mem, int count)
 void GPUwriteData(uint32_t data)
 {
   log_io("gpu_write %08x\n", data);
-  gpu.cmd_buffer[gpu.cmd_len++] = data;
+  gpu.cmd_buffer[gpu.cmd_len++] = HTOLE32(data);
   if (gpu.cmd_len >= CMD_BUFFER_LEN)
     flush_cmd_buffer();
 }
 
-long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
+long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr)
 {
   uint32_t addr, *list, ld_addr = 0;
   int len, left, count;
@@ -544,8 +543,8 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
   for (count = 0; (addr & 0x800000) == 0; count++)
   {
     list = rambase + (addr & 0x1fffff) / 4;
-    len = list[0] >> 24;
-    addr = list[0] & 0xffffff;
+    len = LE32TOH(list[0]) >> 24;
+    addr = LE32TOH(list[0]) & 0xffffff;
     preload(rambase + (addr & 0x1fffff) / 4);
 
     cpu_cycles += 10;
@@ -560,6 +559,10 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
         log_anomaly("GPUdmaChain: discarded %d/%d words\n", left, len);
     }
 
+    if (progress_addr) {
+      *progress_addr = addr;
+      break;
+    }
     #define LD_THRESHOLD (8*1024)
     if (count >= LD_THRESHOLD) {
       if (count == LD_THRESHOLD) {
@@ -570,7 +573,7 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
       // loop detection marker
       // (bit23 set causes DMA error on real machine, so
       //  unlikely to be ever set by the game)
-      list[0] |= 0x800000;
+      list[0] |= HTOLE32(0x800000);
     }
   }
 
@@ -580,8 +583,8 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
     addr = ld_addr & 0x1fffff;
     while (count-- > 0) {
       list = rambase + addr / 4;
-      addr = list[0] & 0x1fffff;
-      list[0] &= ~0x800000;
+      addr = LE32TOH(list[0]) & 0x1fffff;
+      list[0] &= HTOLE32(~0x800000);
     }
   }
 
@@ -612,8 +615,11 @@ uint32_t GPUreadData(void)
     flush_cmd_buffer();
 
   ret = gpu.gp0;
-  if (gpu.dma.h)
+  if (gpu.dma.h) {
+    ret = HTOLE32(ret);
     do_vram_io(&ret, 1, 1);
+    ret = LE32TOH(ret);
+  }
 
   log_io("gpu_read %08x\n", ret);
   return ret;