shithub: psxe

Download patch

ref: 364d8222cea403a2a6109640e26cc7131bcb465f
parent: baa9e6a32f5eb94d1c0d2314fa3ad69ad6567945
author: allkern <lisandroaalarcon@gmail.com>
date: Wed Jun 28 19:35:54 EDT 2023

Fix undocumented BXX dupes

Fix scaling on 512x240
Improve GPU timings and accuracy

--- a/build-win64.ps1
+++ b/build-win64.ps1
@@ -22,6 +22,6 @@
     -L"`"$($SDL2_DIR)\lib`"" `
     -m64 -lSDL2main -lSDL2 -Wno-overflow `
     -Wall -pedantic -DLOG_USE_COLOR `
-    -ffast-math -Ofast
+    -ffast-math -Ofast -g
 
 Copy-Item -Path "sdl2-win64/SDL2.dll" -Destination "bin"
\ No newline at end of file
--- a/frontend/screen.c
+++ b/frontend/screen.c
@@ -93,8 +93,10 @@
 void psxe_screen_set_scale(psxe_screen_t* screen, unsigned int scale) {
 #ifdef PSXE_SCREEN_DEBUG
     screen->scale = 1;
+    screen->saved_scale = 1;
 #else
     screen->scale = scale;
+    screen->saved_scale = scale;
 #endif
 }
 
@@ -119,7 +121,7 @@
     screen->height = psx_get_display_height(screen->psx);
 #endif
     
-    if (screen->width >= 512) {
+    if (screen->width > 512) {
         screen->saved_scale = screen->scale;
         screen->scale = 1;
     } else {
--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -126,10 +126,10 @@
     psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
     psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
     psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
-    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
-    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
-    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
-    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal
+    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez
 };
 
 #define OP ((cpu->buf[1] >> 26) & 0x3f)
@@ -320,6 +320,12 @@
 
     cpu->buf[1] = cpu->buf[0];
 
+    if (cpu->pc & 0x3) {
+        psx_cpu_exception(cpu, CAUSE_ADEL);
+
+        return;
+    }
+
     psx_cpu_fetch(cpu);
 
     cpu->delay_slot = cpu->branch;
@@ -731,6 +737,8 @@
 
     uint32_t aligned = psx_bus_read32(cpu->bus, addr & ~0x3);
 
+    cpu->load_v = cpu->r[T];
+
     switch (addr & 0x3) {
         case 0: cpu->load_v =                               aligned       ; break;
         case 1: cpu->load_v = (cpu->load_v & 0xff000000) | (aligned >> 8 ); break;
@@ -1255,6 +1263,10 @@
         case 9: cpu->cop0_bdam = t; break;
         case 11: cpu->cop0_bpcm = t; break;
         case 12: cpu->cop0_sr = t; break;
+    }
+
+    if ((cpu->cop0_sr & SR_IEC) && (cpu->cop0_cause & cpu->cop0_sr & SR_IM2)) {
+        psx_cpu_exception(cpu, CAUSE_INT);
     }
 }
 
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -38,15 +38,7 @@
 uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) {
     switch (offset) {
         case 0x00: return gpu->gpuread; // GPUREAD
-        case 0x04: {
-            if (gpu->gpustat & 0x80000000) {
-                gpu->gpustat &= ~0x80000000;
-            } else {
-                gpu->gpustat |= 0x80000000;
-            }
-
-            return (gpu->gpustat & ~0x00080000) | 0x1c000000; // GPUSTAT
-        }
+        case 0x04: return gpu->gpustat | 0x1c000000;
     }
 
     log_warn("Unhandled 32-bit GPU read at offset %08x", offset);
@@ -56,8 +48,8 @@
 
 uint16_t psx_gpu_read16(psx_gpu_t* gpu, uint32_t offset) {
     switch (offset) {
-        case 0x00: return 0x00000000; // GPUREAD
-        case 0x04: return 0x1c000000; // GPUSTAT
+        case 0x00: return gpu->gpuread;
+        case 0x04: return gpu->gpustat;
     }
 
     log_warn("Unhandled 16-bit GPU read at offset %08x", offset);
@@ -67,8 +59,8 @@
 
 uint8_t psx_gpu_read8(psx_gpu_t* gpu, uint32_t offset) {
     switch (offset) {
-        case 0x00: return 0x00000000; // GPUREAD
-        case 0x04: return 0x1c000000; // GPUSTAT
+        case 0x00: return gpu->gpuread;
+        case 0x04: return gpu->gpustat;
     }
 
     log_warn("Unhandled 8-bit GPU read at offset %08x", offset);
@@ -114,6 +106,24 @@
     }
 }
 
+void gpu_render_flat_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint32_t color) {
+    /* Offset coordinates */
+    v.x += gpu->off_x;
+    v.y += gpu->off_y;
+
+    /* Calculate bounding box */
+    int xmin = max(v.x, gpu->draw_x1);
+    int ymin = max(v.y, gpu->draw_y1);
+    int xmax = min(xmin + w, gpu->draw_x2);
+    int ymax = min(ymin + h, gpu->draw_y2);
+
+    for (uint32_t y = ymin; y < ymax; y++) {
+        for (uint32_t x = xmin; x < xmax; x++) {
+            gpu->vram[x + (y * 1024)] = gpu_to_bgr555(color);
+        }
+    }
+}
+
 void gpu_render_textured_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint32_t tpx, uint32_t tpy) {
     vertex_t a = v;
 
@@ -571,6 +581,29 @@
     }
 }
 
+void gpu_cmd_68(psx_gpu_t* gpu) {
+    switch (gpu->state) {
+        case GPU_STATE_RECV_CMD: {
+            gpu->state = GPU_STATE_RECV_ARGS;
+            gpu->cmd_args_remaining = 1;
+        } break;
+
+        case GPU_STATE_RECV_ARGS: {
+            if (!gpu->cmd_args_remaining) {
+                gpu->state = GPU_STATE_RECV_DATA;
+
+                gpu->color = gpu->buf[0] & 0xffffff;
+                gpu->v0.x  = gpu->buf[1] & 0xffff;
+                gpu->v0.y  = gpu->buf[1] >> 16;
+
+                gpu_render_flat_rectangle(gpu, gpu->v0, 1, 1, gpu->color);
+
+                gpu->state = GPU_STATE_RECV_CMD;
+            }
+        } break;
+    }
+}
+
 void psx_gpu_update_cmd(psx_gpu_t* gpu) {
     switch (gpu->buf[0] >> 24) {
         case 0x00: /* nop */ break;
@@ -580,6 +613,7 @@
         case 0x30: gpu_cmd_30(gpu); break;
         case 0x38: gpu_cmd_38(gpu); break;
         case 0x64: gpu_cmd_64(gpu); break;
+        case 0x68: gpu_cmd_68(gpu); break;
         case 0xa0: gpu_cmd_a0(gpu); break;
         case 0xe1: {
             gpu->gpustat &= 0x7ff;
@@ -698,26 +732,43 @@
     gpu->udata[index] = udata;
 }
 
-#define GPU_CYCLES_PER_SCAN_NTSC 3413
+#define GPU_CYCLES_PER_HDRAW_NTSC 2560
+#define GPU_CYCLES_PER_SCANL_NTSC 3413
+#define GPU_SCANS_PER_VDRAW_NTSC 240
 #define GPU_SCANS_PER_FRAME_NTSC 263
-#define GPU_CYCLES_PER_SCAN_PAL 3406
-#define GPU_SCANS_PER_FRAME_PAL 314
 
+void gpu_scanline_event(psx_gpu_t* gpu) {
+    gpu->line++;
+
+    if (gpu->line < GPU_SCANS_PER_VDRAW_NTSC) {
+        if (gpu->line & 1) {
+            gpu->gpustat |= 1 << 31;
+        } else {
+            gpu->gpustat &= ~(1 << 31);
+        }
+    } else {
+        gpu->gpustat &= ~(1 << 31);
+    }
+
+    if (gpu->line == GPU_SCANS_PER_VDRAW_NTSC) {
+        // Disable Vblank for now
+        // psx_ic_irq(gpu->ic, IC_VBLANK);
+    } else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
+        gpu->line = 0;
+    }
+}
+
 void psx_gpu_update(psx_gpu_t* gpu, int cyc) {
     // Convert CPU (~33.8 MHz) cycles to GPU (~53.7 MHz) cycles
-    gpu->cycles += (float)cyc * (PSX_GPU_CLOCK_FREQ_NTSC / PSX_CPU_CLOCK_FREQ);
+    gpu->cycles += ((float)cyc) * (PSX_GPU_CLOCK_FREQ_PAL / PSX_CPU_CLOCK_FREQ);
 
-    if (gpu->cycles >= (float)GPU_CYCLES_PER_SCAN_NTSC) {
-        gpu->cycles -= (float)GPU_CYCLES_PER_SCAN_NTSC;
-        gpu->line++;
+    //if (gpu->cycles >= (float)GPU_CYCLES_PER_HDRAW_NTSC) {
+        // Tick Hblank timer
 
-        if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
-            // psx_ic_irq(gpu->ic, IC_VBLANK);
+    if (gpu->cycles >= (float)GPU_CYCLES_PER_SCANL_NTSC) {
+        gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC;
 
-            gpu->line = 0;
-        } else {
-            psx_ic_irq(gpu->ic, IC_GPU);
-        }
+        gpu_scanline_event(gpu);
     }
 }
 
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -34,6 +34,21 @@
 }
 
 uint16_t psx_timer_read16(psx_timer_t* timer, uint32_t offset) {
+    if (offset == 0x20) {
+        return 0x000016b0;
+    }
+
+    int t = (offset >> 4) & 0x3;
+    int r = offset & 0xf;
+
+    if (r == 0) {
+        switch (t) {
+            case 0: return timer->t0_stub++;
+            case 1: return timer->t1_stub++;
+            case 2: return timer->t2_stub++;
+        }
+    }
+
     log_fatal("Unhandled 16-bit TIMER read at offset %08x", offset);
 
     return 0x0;
--