shithub: psxe

Download patch

ref: 594aa466b7057e4a3b7ff95836169106161a4787
parent: 7f9fc68a99d1056963e74a37e921d449a3c99cca
author: allkern <lisandroaalarcon@gmail.com>
date: Sun Jun 2 20:35:56 EDT 2024

Many fixes and improvements

Fixed CD-XA popping issue
Improved SPU IRQ emulation
Fixed GPU signed draw offsets
Improved CDROM timings (better compatibility)

--- a/build-deps.ps1
+++ b/build-deps.ps1
@@ -5,4 +5,6 @@
 $SDL2_URL = "https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-devel-2.30.3-mingw.zip"
 
 Invoke-WebRequest -URI $SDL2_URL -OutFile "sdl2.zip"
-Expand-Archive "sdl2.zip" -DestinationPath "." -Force
\ No newline at end of file
+Expand-Archive "sdl2.zip" -DestinationPath "." -Force
+
+Remove-Item "sdl2.zip"
\ No newline at end of file
--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -1477,9 +1477,9 @@
     if (i == 3)
         cpu->s_mac3 = value;
 
-    if (value < -0x80000000000) {
+    if (value < -0x80000000000ll) {
         R_FLAG |= 0x8000000 >> (i - 1);
-    } else if (value > 0x7ffffffffff) {
+    } else if (value > 0x7ffffffffffll) {
         R_FLAG |= 0x40000000 >> (i - 1);
     }
 
@@ -1486,6 +1486,14 @@
     return (int32_t)(((value << 20) >> 20) >> cpu->gte_sf);
 }
 
+void gte_check_mac(psx_cpu_t* cpu, int i, int64_t value) {
+    if (value < -0x80000000000ll) {
+        R_FLAG |= 0x8000000 >> (i - 1);
+    } else if (value > 0x7ffffffffffll) {
+        R_FLAG |= 0x40000000 >> (i - 1);
+    }
+}
+
 int32_t gte_clamp_ir0(psx_cpu_t* cpu, int32_t value) {
     if (value < 0) {
         R_FLAG |= 0x1000;
@@ -1841,9 +1849,21 @@
     R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
     R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
     R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
-    R_MAC1 = gte_clamp_mac(cpu, 1, (I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1)) + (I64(R_LR2) * I64(R_IR2)) + (I64(R_LR3) * I64(R_IR3))); \
-    R_MAC2 = gte_clamp_mac(cpu, 2, (I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1)) + (I64(R_LG2) * I64(R_IR2)) + (I64(R_LG3) * I64(R_IR3))); \
-    R_MAC3 = gte_clamp_mac(cpu, 3, (I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1)) + (I64(R_LB2) * I64(R_IR2)) + (I64(R_LB3) * I64(R_IR3))); \
+    gte_check_mac(cpu, 1, ((I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1)))); \
+    gte_check_mac(cpu, 2, ((I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1)))); \
+    gte_check_mac(cpu, 3, ((I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1)))); \
+    gte_check_mac(cpu, 1, I64(R_LR2) * I64(R_IR2)); \
+    gte_check_mac(cpu, 2, I64(R_LG2) * I64(R_IR2)); \
+    gte_check_mac(cpu, 3, I64(R_LB2) * I64(R_IR2)); \
+    gte_check_mac(cpu, 1, I64(R_LR3) * I64(R_IR3)); \
+    gte_check_mac(cpu, 2, I64(R_LG3) * I64(R_IR3)); \
+    gte_check_mac(cpu, 3, I64(R_LB3) * I64(R_IR3)); \
+    R_MAC1 = gte_clamp_mac(cpu, 1, ((I64(R_RBK) << 12) + (I64(R_LR1) * I64(R_IR1))) + (I64(R_LR2) * I64(R_IR2)) + (I64(R_LR3) * I64(R_IR3))); \
+    R_MAC2 = gte_clamp_mac(cpu, 2, ((I64(R_GBK) << 12) + (I64(R_LG1) * I64(R_IR1))) + (I64(R_LG2) * I64(R_IR2)) + (I64(R_LG3) * I64(R_IR3))); \
+    R_MAC3 = gte_clamp_mac(cpu, 3, ((I64(R_BBK) << 12) + (I64(R_LB1) * I64(R_IR1))) + (I64(R_LB2) * I64(R_IR2)) + (I64(R_LB3) * I64(R_IR3))); \
+    /* R_MAC1 = gte_clamp_mac(cpu, 1, () + () + ()); */ \
+    /* R_MAC2 = gte_clamp_mac(cpu, 2, () + () + ()); */ \
+    /* R_MAC3 = gte_clamp_mac(cpu, 3, () + () + ()); */ \
     R_IR1 = gte_clamp_ir(cpu, 1, R_MAC1, cpu->gte_lm); \
     R_IR2 = gte_clamp_ir(cpu, 2, R_MAC2, cpu->gte_lm); \
     R_IR3 = gte_clamp_ir(cpu, 3, R_MAC3, cpu->gte_lm); \
--- a/psx/dev/cdrom.c
+++ b/psx/dev/cdrom.c
@@ -253,7 +253,7 @@
                 return;
             }
 
-            cdrom->irq_delay = DELAY_1MS;
+            cdrom->irq_delay = DELAY_1MS * 2;
             cdrom->state = CD_STATE_SEND_RESP1;
             cdrom->delayed_command = CDL_GETSTAT;
         } break;
@@ -262,7 +262,7 @@
             SET_BITS(ifr, IFR_INT, IFR_INT3);
             RESP_PUSH(
                 GETSTAT_MOTOR |
-                ((cdrom->cdda_playing || cdrom->xa_playing) ? GETSTAT_PLAY : 0) |
+                (cdrom->cdda_playing ? GETSTAT_PLAY : 0) |
                 (cdrom->ongoing_read_command ? GETSTAT_READ : 0) |
                 (cdrom->disc ? 0 : GETSTAT_TRAYOPEN)
             );
@@ -271,7 +271,7 @@
                 // printf("getstat command=%02x\n", cdrom->ongoing_read_command);
                 cdrom->state = CD_STATE_SEND_RESP2;
                 cdrom->delayed_command = cdrom->ongoing_read_command;
-                cdrom->irq_delay = DELAY_1MS;
+                cdrom->irq_delay = DELAY_1MS * 2;
             } else {
                 cdrom->delayed_command = CDL_NONE;
                 cdrom->state = CD_STATE_RECV_CMD;
@@ -379,15 +379,15 @@
         case CD_STATE_RECV_CMD: {
             int track = 0;
 
-            if (cdrom->cdda_playing) {
-                cdrom->pfifo_index = 0;
+            // if (cdrom->cdda_playing) {
+            //     cdrom->pfifo_index = 0;
 
-                cdrom->irq_delay = DELAY_1MS;
-                cdrom->state = CD_STATE_SEND_RESP1;
-                cdrom->delayed_command = CDL_PLAY;
+            //     cdrom->irq_delay = DELAY_1MS;
+            //     cdrom->state = CD_STATE_SEND_RESP1;
+            //     cdrom->delayed_command = CDL_PLAY;
 
-                return;
-            }
+            //     return;
+            // }
 
             // Optional track number parameter
             if (cdrom->pfifo_index)
@@ -461,6 +461,7 @@
 
             if (cdrom->mode & MODE_XA_ADPCM) {
                 cdrom->xa_msf = cdrom->seek_msf;
+                cdrom->xa_current_msf = cdrom->xa_msf;
                 cdrom->xa_playing = 1;
                 cdrom->xa_remaining_samples = 0;
 
@@ -883,7 +884,7 @@
 void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) {
     switch (cdrom->state) {
         case CD_STATE_RECV_CMD: {
-            cdrom->irq_delay = DELAY_1MS;
+            cdrom->irq_delay = DELAY_1MS * 4;
             cdrom->delayed_command = CDL_GETLOCL;
             cdrom->state = CD_STATE_SEND_RESP1;
         } break;
@@ -903,7 +904,7 @@
                 // printf("command=%02x\n", cdrom->ongoing_read_command);
                 cdrom->state = CD_STATE_SEND_RESP2;
                 cdrom->delayed_command = cdrom->ongoing_read_command;
-                cdrom->irq_delay = DELAY_1MS;
+                cdrom->irq_delay = DELAY_1MS * 4;
             } else {
                 cdrom->delayed_command = CDL_NONE;
                 cdrom->state = CD_STATE_RECV_CMD;
@@ -914,7 +915,7 @@
 void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) {
     switch (cdrom->state) {
         case CD_STATE_RECV_CMD: {
-            cdrom->irq_delay = DELAY_1MS;
+            cdrom->irq_delay = DELAY_1MS * 8;
             cdrom->delayed_command = CDL_GETLOCP;
             cdrom->state = CD_STATE_SEND_RESP1;
         } break;
@@ -968,7 +969,7 @@
                 printf("getlocp command=%02x\n", cdrom->ongoing_read_command);
                 cdrom->state = CD_STATE_SEND_RESP2;
                 cdrom->delayed_command = cdrom->ongoing_read_command;
-                cdrom->irq_delay = DELAY_1MS;
+                cdrom->irq_delay = DELAY_1MS * 8;
             } else {
                 cdrom->delayed_command = CDL_NONE;
                 cdrom->state = CD_STATE_RECV_CMD;
@@ -1234,10 +1235,10 @@
 
             // 95h,05h,16h,C1h
             SET_BITS(ifr, IFR_INT, IFR_INT3);
-            RESP_PUSH(0xc1);
-            RESP_PUSH(0x16);
-            RESP_PUSH(0x05);
-            RESP_PUSH(0x95);
+            RESP_PUSH(0xc0);
+            RESP_PUSH(0x19);
+            RESP_PUSH(0x09);
+            RESP_PUSH(0x94);
 
             cdrom->state = CD_STATE_RECV_CMD;
         } break;
@@ -1327,6 +1328,7 @@
 
             if (cdrom->mode & MODE_XA_ADPCM) {
                 cdrom->xa_msf = cdrom->seek_msf;
+                cdrom->xa_current_msf = cdrom->xa_msf;
                 cdrom->xa_playing = 1;
                 cdrom->xa_remaining_samples = 0;
 
@@ -2086,8 +2088,6 @@
 
     int16_t left[28];
     int16_t right[28];
-    int16_t left_h[2] = { 0, 0 };
-    int16_t right_h[2] = { 0, 0 };
 
     int16_t* left_ptr = cdrom->xa_left_buf;
     int16_t* right_ptr = cdrom->xa_right_buf;
@@ -2096,8 +2096,8 @@
     for (int i = 0; i < 18; i++) {
         for (int blk = 0; blk < 4; blk++) {
             if (cdrom->xa_sector_buf[0x13] & 1) {
-                cdrom_decode_xa_block(cdrom, src, blk, 0, left, left_h);
-                cdrom_decode_xa_block(cdrom, src, blk, 1, right, right_h);
+                cdrom_decode_xa_block(cdrom, src, blk, 0, left, cdrom->xa_left_h);
+                cdrom_decode_xa_block(cdrom, src, blk, 1, right, cdrom->xa_right_h);
 
                 for (int i = 0; i < 28; i++) {
                     *left_ptr++ = left[i];
@@ -2104,12 +2104,12 @@
                     *right_ptr++ = right[i];
                 }
             } else {
-                cdrom_decode_xa_block(cdrom, src, blk, 0, left, left_h);
+                cdrom_decode_xa_block(cdrom, src, blk, 0, left, cdrom->xa_left_h);
 
                 for (int i = 0; i < 28; i++)
                     *mono_ptr++ = left[i];
 
-                cdrom_decode_xa_block(cdrom, src, blk, 1, left, left_h);
+                cdrom_decode_xa_block(cdrom, src, blk, 1, left, cdrom->xa_left_h);
 
                 for (int i = 0; i < 28; i++)
                     *mono_ptr++ = left[i];
@@ -2124,6 +2124,7 @@
     while (true) {
         if (psx_disc_seek(cdrom->disc, cdrom->xa_msf)) {
             cdrom->xa_playing = 0;
+            cdrom->xa_remaining_samples = 0;
 
             return;
         }
@@ -2132,12 +2133,12 @@
 
         msf_add_f(&cdrom->xa_msf, 1);
 
-        // Check for EOR, EOF bits
-        if (cdrom->xa_sector_buf[0x12] & 0x80)
+        // Check for EOR bit
+        if (cdrom->xa_sector_buf[0x12] & 1)
             return;
 
-        // Check RT and Audio bit
-        if ((cdrom->xa_sector_buf[0x12] & 4) != 4)
+        // Check Audio bit
+        if (!(cdrom->xa_sector_buf[0x12] & 4))
             continue;
 
         // If we get here it means this is a real-time audio sector.
@@ -2185,14 +2186,18 @@
             if (!cdrom->xa_remaining_samples) {
                 cdrom_fetch_xa_sector(cdrom);
 
-                if (cdrom->xa_sector_buf[0x12] & 0x80) {
+                if (cdrom->xa_sector_buf[0x12] & 0x01) {
                     SET_BITS(status, STAT_ADPBUSY_MASK, 0);
 
+                    printf("Pausing XA-ADPCM playback\n");
+
                     cdrom->xa_playing = 0;
                     cdrom->xa_remaining_samples = 0;
 
                     return;
                 }
+
+                msf_add_f(&cdrom->xa_current_msf, 1);
 
                 stereo = (cdrom->xa_sector_buf[0x13] & 1) == 1;
 
--- a/psx/dev/cdrom.h
+++ b/psx/dev/cdrom.h
@@ -11,10 +11,10 @@
 #include "../msf.h"
 #include "spu.h"
 
-// #define DELAY_1MS (0xc4e1)
+#define DELAY_1MS (0xc4e1)
 // #define READ_SINGLE_DELAY (0x6e1cd)
 // #define READ_DOUBLE_DELAY (0x36cd2)
-#define DELAY_1MS (PSX_CPU_CPS / 1000)
+// #define DELAY_1MS (PSX_CPU_CPS / 1000)
 #define READ_SINGLE_DELAY (PSX_CPU_CPS / 75)
 #define READ_DOUBLE_DELAY (PSX_CPU_CPS / (2 * 75))
 
@@ -210,11 +210,14 @@
     // XA-ADPCM
     uint8_t* xa_sector_buf;
     msf_t xa_msf;
+    msf_t xa_current_msf;
     int xa_playing;
     int xa_mute;
     uint8_t xa_file;
     uint8_t xa_channel;
     uint8_t xa_coding;
+    int16_t xa_left_h[2];
+    int16_t xa_right_h[2];
     int16_t* xa_left_buf;
     int16_t* xa_right_buf;
     int16_t* xa_mono_buf;
--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -345,14 +345,10 @@
 
     uint32_t size = BCR_SIZE(cdrom);
 
-    if (!size) {
+    if (!size)
         printf("0 sized CDROM DMA\n");
 
-        return;
-        exit(1);
-    }
-
-    dma->cdrom_irq_delay = size * 24;
+    dma->cdrom_irq_delay = 1;
 
     if (!CHCR_TDIR(cdrom)) {
         for (int i = 0; i < size; i++) {
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -825,6 +825,8 @@
     }
 }
 
+#define I32(v, b) (((int32_t)((v) << (31-b))) >> (31-b))
+
 void gpu_rect(psx_gpu_t* gpu) {
     switch (gpu->state) {
         case GPU_STATE_RECV_CMD: {
@@ -1516,8 +1518,8 @@
                 //     gpu->ysiz
                 // );
 
-                for (uint32_t y = gpu->v0.y; y < (gpu->v0.y + gpu->ysiz); y++) {
-                    for (uint32_t x = gpu->v0.x; x < (gpu->v0.x + gpu->xsiz); x++) {
+                for (int y = gpu->v0.y; y < (gpu->v0.y + gpu->ysiz); y++) {
+                    for (int x = gpu->v0.x; x < (gpu->v0.x + gpu->xsiz); x++) {
                         // This shouldn't be needed
                         int bc = (x >= gpu->draw_x1) && (x <= gpu->draw_x2) &&
                                  (y >= gpu->draw_y1) && (y <= gpu->draw_y2);
@@ -1645,8 +1647,8 @@
             gpu->draw_y2 = (gpu->buf[0] >> 10) & 0x1ff;
         } break;
         case 0xe5: {
-            gpu->off_x = (gpu->buf[0] >> 0 ) & 0x7ff;
-            gpu->off_y = (gpu->buf[0] >> 11) & 0x7ff;
+            gpu->off_x = ((int32_t)((gpu->buf[0] >> 0 ) & 0x7ff) << 21) >> 21;
+            gpu->off_y = ((int32_t)((gpu->buf[0] >> 11) & 0x7ff) << 21) >> 21;
         } break;
         case 0xe6: {
             /* To-do: Implement mask bit thing */
@@ -1791,8 +1793,9 @@
         // Player Select. It probably uses T2 IRQs to time
         // GetlocP commands, if the timer is too slow it will
         // break.
-        if (!(gpu->line & 7))
-            psx_ic_irq(gpu->ic, IC_TIMER2);
+        // if (!(gpu->line & 7))
+            // psx_ic_irq(gpu->ic, IC_TIMER2);
+            // psx_ic_irq(gpu->ic, IC_SPU);
     } else {
         gpu->gpustat &= ~(1 << 31);
     }
@@ -1807,8 +1810,6 @@
     } else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
         if (gpu->event_cb_table[GPU_EVENT_VBLANK_END])
             gpu->event_cb_table[GPU_EVENT_VBLANK_END](gpu);
-
-        psx_ic_irq(gpu->ic, IC_SPU);
 
         gpu->line = 0;
     }
--- a/psx/dev/gpu.h
+++ b/psx/dev/gpu.h
@@ -130,7 +130,7 @@
     uint32_t draw_x2, draw_y2;
 
     // Drawing offset
-    uint32_t off_x, off_y;
+    int32_t off_x, off_y;
 
     // Texture Window
     uint32_t texw_mx, texw_my;
--- a/psx/dev/spu.c
+++ b/psx/dev/spu.c
@@ -89,12 +89,13 @@
     return (psx_spu_t*)malloc(sizeof(psx_spu_t));
 }
 
-void psx_spu_init(psx_spu_t* spu) {
+void psx_spu_init(psx_spu_t* spu, psx_ic_t* ic) {
     memset(spu, 0, sizeof(psx_spu_t));
 
     spu->io_base = PSX_SPU_BEGIN;
     spu->io_size = PSX_SPU_SIZE;
 
+    spu->ic = ic;
     spu->ram = (uint8_t*)malloc(SPU_RAM_SIZE);
 
     memset(spu->ram, 0, SPU_RAM_SIZE);
@@ -141,6 +142,9 @@
     int32_t f0 = g_spu_pos_adpcm_table[filter];
     int32_t f1 = g_spu_neg_adpcm_table[filter];
 
+    if ((spu->irq9addr << 3) == addr)
+        psx_ic_irq(spu->ic, IC_SPU);
+
     for (int j = 0; j < 28; j++) {
         uint16_t n = (spu->ram[addr + 2 + (j >> 1)] >> ((j & 1) * 4)) & 0xf;
 
@@ -356,6 +360,10 @@
 
             spu_kon(spu, value << (16 * high));
         } return 1;
+
+        // case SPUR_SPUIRQA: {
+        //     spu->irq9addr = value << 3;
+        // } return 1;
 
         case SPUR_KOFFL: case SPUR_KOFFH: {
             int high = (offset & 2) != 0;
--- a/psx/dev/spu.h
+++ b/psx/dev/spu.h
@@ -3,6 +3,8 @@
 
 #include <stdint.h>
 
+#include "ic.h"
+
 #define PSX_SPU_BEGIN 0x1f801c00
 #define PSX_SPU_SIZE  0x400
 #define PSX_SPU_END   0x1f801fff
@@ -32,11 +34,13 @@
 #define SPUR_TCTRL   0x1ac
 #define SPUR_SPUSTAT 0x1ae
 #define SPUR_MBASE   0x1a2
+#define SPUR_SPUIRQA 0x1a4
 
 typedef struct __attribute__((__packed__)) {
     uint32_t bus_delay;
     uint32_t io_base, io_size;
 
+    psx_ic_t* ic;
     uint8_t* ram;
 
     struct __attribute__((__packed__)) {
@@ -166,7 +170,7 @@
 } psx_spu_t;
 
 psx_spu_t* psx_spu_create(void);
-void psx_spu_init(psx_spu_t*);
+void psx_spu_init(psx_spu_t*, psx_ic_t*);
 uint32_t psx_spu_read32(psx_spu_t*, uint32_t);
 uint16_t psx_spu_read16(psx_spu_t*, uint32_t);
 uint8_t psx_spu_read8(psx_spu_t*, uint32_t);
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -91,8 +91,32 @@
     timer->timer[index].blank_once = 0;
     timer->timer[index].paused = 0;
 
-    if (index == 2)
-        printf("timer_set_mode %u %04x\n", index, value);
+    // printf(
+    //     "timer_set_mode %u %04x\n"
+    //     "sync_enable    %u\n"
+    //     "sync_mode      %u\n"
+    //     "reset_target   %u\n"
+    //     "irq_target     %u\n"
+    //     "irq_max        %u\n"
+    //     "irq_repeat     %u\n"
+    //     "irq_toggle     %u\n"
+    //     "clk_source     %u\n"
+    //     "target_reached %u\n"
+    //     "max_reached    %u\n"
+    //     "target         %04x\n",
+    //     index, value,
+    //     timer->timer[index].sync_enable,
+    //     timer->timer[index].sync_mode,
+    //     timer->timer[index].reset_target,
+    //     timer->timer[index].irq_target,
+    //     timer->timer[index].irq_max,
+    //     timer->timer[index].irq_repeat,
+    //     timer->timer[index].irq_toggle,
+    //     timer->timer[index].clk_source,
+    //     timer->timer[index].target_reached,
+    //     timer->timer[index].max_reached,
+    //     timer->timer[index].target
+    // );
 
     switch (index) {
         case 0: {
@@ -209,8 +233,6 @@
 void timer_handle_irq(psx_timer_t* timer, int i) {
     int irq = 0;
 
-    int prev_target_reached = timer->timer[i].target_reached;
-    int prev_max_reached = timer->timer[i].max_reached;
     int target_reached = timer->timer[i].counter > timer->timer[i].target;
     int max_reached = timer->timer[i].counter > 65535.0f;
 
@@ -217,12 +239,13 @@
     if (target_reached) {
         timer->timer[i].target_reached = 1;
 
-        if (timer->timer[i].reset_target) {
+        // if ((i == 2) && (T2_CLKSRC == 2))
+        //     printf("target %04x (%f) reached\n", timer->timer[i].target, timer->timer[i].counter);
+
+        if (timer->timer[i].reset_target)
             timer->timer[i].counter = 0;
-            timer->timer[i].div_counter = 0;
-        }
 
-        if (timer->timer[i].irq_target && !prev_target_reached)
+        if (timer->timer[i].irq_target)
             irq = 1;
     }
 
@@ -230,12 +253,10 @@
         timer->timer[i].counter -= 65536.0f;
         timer->timer[i].max_reached = 1;
 
-        if (timer->timer[i].irq_max && !prev_max_reached)
+        if (timer->timer[i].irq_max)
             irq = 1;
     }
 
-    timer->timer[i].div_counter &= 0xffff;
-
     if (!irq)
         return;
 
@@ -258,8 +279,9 @@
     timer->timer[i].irq = 1;
 
     if (trigger) {
-        // printf("timer %u irq fire\n", i);
-   
+        // if ((i == 1))
+        //     printf("timer 1 irq fire\n");
+
         psx_ic_irq(timer->ic, 16 << i);
     }
 }
@@ -308,10 +330,9 @@
         return;
 
     if (T2_CLKSRC <= 1) {
-        T2_COUNTER += cyc;
+        T2_COUNTER += (float)cyc;
     } else {
-        T2_COUNTER += ((float)cyc) * (1.0f / 8.0f);
-        // T2_COUNTER = T2_DIV_COUNTER >> 3;
+        T2_COUNTER += ((float)cyc) / 8.0f;
     }
 
     timer_handle_irq(timer, 2);
@@ -331,8 +352,11 @@
 
     timer->hblank = 1;
 
-    if ((T1_CLKSRC & 1) && !T1_PAUSED)
+    if ((T1_CLKSRC & 1) && !T1_PAUSED) {
         ++T1_COUNTER;
+
+        timer_handle_irq(timer, 1);
+    }
 
     if (!T0_SYNC_EN)
         return;
--- a/psx/msf.c
+++ b/psx/msf.c
@@ -23,7 +23,7 @@
         msf->f -= CD_SECTORS_PS * s;
     }
 
-    if (msf->s > 60) {
+    if (msf->s >= 60) {
         int m = msf->s / 60;
 
         msf->m += m;
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -174,7 +174,7 @@
     psx_ic_init(psx->ic, psx->cpu);
     psx_scratchpad_init(psx->scratchpad);
     psx_gpu_init(psx->gpu, psx->ic);
-    psx_spu_init(psx->spu);
+    psx_spu_init(psx->spu, psx->ic);
     psx_timer_init(psx->timer, psx->ic, psx->gpu);
     psx_cdrom_init(psx->cdrom, psx->ic);
     psx_pad_init(psx->pad, psx->ic);
--