shithub: psxe

Download patch

ref: 4c91f5854dce4ce995d6978ce6989a7f0df9404b
parent: 23f12a941b9d8e82951288842302344ecba9ace8
author: allkern <lisandroaalarcon@gmail.com>
date: Tue Oct 3 19:18:25 EDT 2023

Various fixes

Fixed memory card support (only one for now)
Implemented GP1(00h) and fixed lines
Working on ADSR
Improved timer 2

--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -172,6 +172,320 @@
 
 //#define CPU_TRACE
 
+static const char* g_psx_cpu_a_kcall_symtable[] = {
+    "open(filename=%08x,accessmode=%08x)",
+    "lseek(fd=%08x,offset=%08x,seektype=%08x)",
+    "read(fd=%08x,dst=%08x,length=%08x)",
+    "write(fd=%08x,src=%08x,length=%08x)",
+    "close(fd=%08x)",
+    "ioctl(fd=%08x,cmd=%08x,arg=%08x)",
+    "exit(exitcode=%08x)",
+    "isatty(fd=%08x)",
+    "getc(fd=%08x)",
+    "putc(char=%08x,fd=%08x)",
+    "todigit(char=%08x)",
+    "atof(src=%08x)",
+    "strtoul(src=%08x,src_end=%08x,base=%08x)",
+    "strtol(src=%08x,src_end=%08x,base=%08x)",
+    "abs(val=%08x)",
+    "labs(val=%08x)",
+    "atoi(src=%08x)",
+    "atol(src=%08x)",
+    "atob(src=%08x,num_dst=%08x)",
+    "setjmp(buf=%08x)",
+    "longjmp(buf=%08x,param=%08x)",
+    "strcat(dst=%08x,src=%08x)",
+    "strncat(dst=%08x,src=%08x,maxlen=%08x)",
+    "strcmp(str1=%08x,str2=%08x)",
+    "strncmp(str1=%08x,str2=%08x,maxlen=%08x)",
+    "strcpy(dst=%08x,src=%08x)",
+    "strncpy(dst=%08x,src=%08x,maxlen=%08x)",
+    "strlen(src=%08x)",
+    "index(src=%08x,char=%08x)",
+    "rindex(src=%08x,char=%08x)",
+    "strchr(src=%08x,char=%08x)",
+    "strrchr(src=%08x,char=%08x)",
+    "strpbrk(src=%08x,list=%08x)",
+    "strspn(src=%08x,list=%08x)",
+    "strcspn(src=%08x,list=%08x)",
+    "strtok(src=%08x,list=%08x)",
+    "strstr(str=%08x,substr=%08x)",
+    "toupper(char=%08x)",
+    "tolower(char=%08x)",
+    "bcopy(src=%08x,dst=%08x,len=%08x)",
+    "bzero(dst=%08x,len=%08x)",
+    "bcmp(ptr1=%08x,ptr2=%08x,len=%08x)",
+    "memcpy(dst=%08x,src=%08x,len=%08x)",
+    "memset(dst=%08x,fillbyte=%08x,len=%08x)",
+    "memmove(dst=%08x,src=%08x,len=%08x)",
+    "memcmp(src1=%08x,src2=%08x,len=%08x)",
+    "memchr(src=%08x,scanbyte=%08x,len=%08x)",
+    "rand()",
+    "srand(seed=%08x)",
+    "qsort(base=%08x,nel=%08x,width=%08x,callback=%08x)",
+    "strtod(src=%08x,src_end=%08x)",
+    "malloc(size=%08x)",
+    "free(buf=%08x)",
+    "lsearch(key=%08x,base=%08x,nel=%08x,width=%08x,callback=%08x)",
+    "bsearch(key=%08x,base=%08x,nel=%08x,width=%08x,callback=%08x)",
+    "calloc(sizx=%08x,sizy=%08x)",
+    "realloc(old_buf=%08x,new_siz=%08x)",
+    "InitHeap(addr=%08x,size=%08x)",
+    "_exit(exitcode=%08x)",
+    "getchar()",
+    "putchar(char=%08x)",
+    "gets(dst=%08x)",
+    "puts(src=%08x)",
+    "printf(txt=%08x,param1=%08x,param2=%08x,etc.=%08x)",
+    "SystemErrorUnresolvedException()",
+    "LoadTest(filename=%08x,headerbuf=%08x)",
+    "Load(filename=%08x,headerbuf=%08x)",
+    "Exec(headerbuf=%08x,param1=%08x,param2=%08x)",
+    "FlushCache()",
+    "init_a0_b0_c0_vectors()",
+    "GPU_dw(Xdst=%08x,Ydst=%08x,Xsiz=%08x,Ysiz=%08x,src=%08x)",
+    "gpu_send_dma(Xdst=%08x,Ydst=%08x,Xsiz=%08x,Ysiz=%08x,src=%08x)",
+    "SendGP1Command(gp1cmd=%08x)",
+    "GPU_cw(gp0cmd=%08x)",
+    "GPU_cwp(src=%08x,num=%08x)",
+    "send_gpu_linked_list(src=%08x)",
+    "gpu_abort_dma()",
+    "GetGPUStatus()",
+    "gpu_sync()",
+    "SystemError()",
+    "SystemError()",
+    "LoadExec(filename=%08x,stackbase=%08x,stackoffset=%08x)",
+    "GetSysSp()",
+    "SystemError()",
+    "_96_init()",
+    "_bu_init()",
+    "_96_remove()",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "dev_tty_init()",
+    "dev_tty_open(fcb=%08x, (unused)path=%08x,accessmode=%08x)",
+    "dev_tty_in_out(fcb=%08x,cmd=%08x)",
+    "dev_tty_ioctl(fcb=%08x,cmd=%08x,arg=%08x)",
+    "dev_cd_open(fcb=%08x,path=%08x,accessmode=%08x)",
+    "dev_cd_read(fcb=%08x,dst=%08x,len=%08x)",
+    "dev_cd_close(fcb=%08x)",
+    "dev_cd_firstfile(fcb=%08x,path=%08x,direntry=%08x)",
+    "dev_cd_nextfile(fcb=%08x,direntry=%08x)",
+    "dev_cd_chdir(fcb=%08x,path=%08x)",
+    "dev_card_open(fcb=%08x,path=%08x,accessmode=%08x)",
+    "dev_card_read(fcb=%08x,dst=%08x,len=%08x)",
+    "dev_card_write(fcb=%08x,src=%08x,len=%08x)",
+    "dev_card_close(fcb=%08x)",
+    "dev_card_firstfile(fcb=%08x,path=%08x,direntry=%08x)",
+    "dev_card_nextfile(fcb=%08x,direntry=%08x)",
+    "dev_card_erase(fcb=%08x,path=%08x)",
+    "dev_card_undelete(fcb=%08x,path=%08x)",
+    "dev_card_format(fcb=%08x)",
+    "dev_card_rename(fcb1=%08x,path=%08x)",
+    "card_clear_error(fcb=%08x) (?)",
+    "_bu_init()",
+    "_96_init()",
+    "_96_remove()",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "CdAsyncSeekL(src=%08x)",
+    "return 0",
+    "return 0",
+    "return 0",
+    "CdAsyncGetStatus(dst=%08x)",
+    "return 0",
+    "CdAsyncReadSector(count=%08x,dst=%08x,mode=%08x)",
+    "return 0",
+    "return 0",
+    "CdAsyncSetMode(mode=%08x)",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "CdromIoIrqFunc1()",
+    "CdromDmaIrqFunc1()",
+    "CdromIoIrqFunc2()",
+    "CdromDmaIrqFunc2()",
+    "CdromGetInt5errCode(dst1=%08x,dst2=%08x)",
+    "CdInitSubFunc()",
+    "AddCDROMDevice()",
+    "AddMemCardDevice()",
+    "AddDuartTtyDevice()",
+    "add_nullcon_driver()",
+    "SystemError()",
+    "SystemError()",
+    "SetConf(num_EvCB=%08x,num_TCB=%08x,stacktop=%08x)",
+    "GetConf(num_EvCB_dst=%08x,num_TCB_dst=%08x,stacktop_dst=%08x)",
+    "SetCdromIrqAutoAbort(type=%08x,flag=%08x)",
+    "SetMem(megabytes=%08x)",
+    "_boot()",
+    "SystemError(type=%08x,errorcode=%08x)",
+    "EnqueueCdIntr()",
+    "DequeueCdIntr()",
+    "CdGetLbn(filename=%08x)",
+    "CdReadSector(count=%08x,sector=%08x,buffer=%08x)",
+    "CdGetStatus()",
+    "bufs_cb_0()",
+    "bufs_cb_1()",
+    "bufs_cb_2()",
+    "bufs_cb_3()",
+    "_card_info(port=%08x)",
+    "_card_load(port=%08x)",
+    "_card_auto(flag=%08x)",
+    "bufs_cb_4()",
+    "card_write_test(port=%08x)",
+    "return 0",
+    "return 0",
+    "ioabort_raw(param=%08x)",
+    "return 0",
+    "GetSystemInfo(index=%08x)"
+};
+
+static const char* g_psx_cpu_b_kcall_symtable[] = {
+    "alloc_kernel_memory(size=%08x)",
+    "free_kernel_memory(buf=%08x)",
+    "init_timer(t=%08x,reload=%08x,flags=%08x)",
+    "get_timer(t=%08x)",
+    "enable_timer_irq(t=%08x)",
+    "disable_timer_irq(t=%08x)",
+    "restart_timer(t=%08x)",
+    "DeliverEvent(class=%08x, spec=%08x)",
+    "OpenEvent(class=%08x,spec=%08x,mode=%08x,func=%08x)",
+    "CloseEvent(event=%08x)",
+    "WaitEvent(event=%08x)",
+    "TestEvent(event=%08x)",
+    "EnableEvent(event=%08x)",
+    "DisableEvent(event=%08x)",
+    "OpenTh(reg_PC=%08x,reg_SP_FP=%08x,reg_GP=%08x)",
+    "CloseTh(handle=%08x)",
+    "ChangeTh(handle=%08x)",
+    "jump_to_00000000h()",
+    "InitPAD2(buf1=%08x,siz1=%08x,buf2=%08x,siz2=%08x)",
+    "StartPAD2()",
+    "StopPAD2()",
+    "PAD_init2(type=%08x,button_dest=%08x,unused=%08x,unused=%08x)",
+    "PAD_dr()",
+    "ReturnFromException()",
+    "ResetEntryInt()",
+    "HookEntryInt(addr=%08x)",
+    "SystemError()",
+    "SystemError()",
+    "SystemError()",
+    "SystemError()",
+    "SystemError()",
+    "SystemError()",
+    "UnDeliverEvent(class=%08x,spec=%08x)",
+    "SystemError()",
+    "SystemError()",
+    "SystemError()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "SystemError()",
+    "SystemError()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "jump_to_00000000h()",
+    "open(filename=%08x,accessmode=%08x)",
+    "lseek(fd=%08x,offset=%08x,seektype=%08x)",
+    "read(fd=%08x,dst=%08x,length=%08x)",
+    "write(fd=%08x,src=%08x,length=%08x)",
+    "close(fd=%08x)",
+    "ioctl(fd=%08x,cmd=%08x,arg=%08x)",
+    "exit(exitcode=%08x)",
+    "isatty(fd=%08x)",
+    "getc(fd=%08x)",
+    "putc(char=%08x,fd=%08x)",
+    "getchar()",
+    "putchar(char=%08x)",
+    "gets(dst=%08x)",
+    "puts(src=%08x)",
+    "cd(name=%08x)",
+    "format(devicename=%08x)",
+    "firstfile2(filename=%08x,direntry=%08x)",
+    "nextfile(direntry=%08x)",
+    "rename(old_filename=%08x,new_filename=%08x)",
+    "erase(filename=%08x)",
+    "undelete(filename=%08x)",
+    "AddDrv(device_info=%08x)",
+    "DelDrv(device_name_lowercase=%08x)",
+    "PrintInstalledDevices()",
+    "InitCARD2(pad_enable=%08x)",
+    "StartCARD2()",
+    "StopCARD2()",
+    "_card_info_subfunc(port=%08x)",
+    "_card_write(port=%08x,sector=%08x,src=%08x)",
+    "_card_read(port=%08x,sector=%08x,dst=%08x)",
+    "_new_card()",
+    "Krom2RawAdd(shiftjis_code=%08x)",
+    "SystemError()",
+    "Krom2Offset(shiftjis_code=%08x)",
+    "_get_errno()",
+    "_get_error(fd=%08x)",
+    "GetC0Table()",
+    "GetB0Table()",
+    "_card_chan()",
+    "testdevice(devicename=%08x)",
+    "SystemError()",
+    "ChangeClearPAD(int=%08x)",
+    "_card_status(slot=%08x)",
+    "_card_wait(slot=%08x)"
+};
+
+static const char* g_psx_cpu_c_kcall_symtable[] = {
+    "EnqueueTimerAndVblankIrqs(priority=%08x)",
+    "EnqueueSyscallHandler(priority=%08x)",
+    "SysEnqIntRP(priority=%08x,struc=%08x)",
+    "SysDeqIntRP(priority=%08x,struc=%08x)",
+    "get_free_EvCB_slot()",
+    "get_free_TCB_slot()",
+    "ExceptionHandler()",
+    "InstallExceptionHandlers()",
+    "SysInitMemory(addr=%08x,size=%08x)",
+    "SysInitKernelVariables()",
+    "ChangeClearRCnt(t=%08x,flag=%08x)",
+    "SystemError()",
+    "InitDefInt(priority=%08x)",
+    "SetIrqAutoAck(irq=%08x,flag=%08x)",
+    "return 0",
+    "return 0",
+    "return 0",
+    "return 0",
+    "InstallDevices(ttyflag=%08x)",
+    "FlushStdInOutPut()",
+    "return 0",
+    "_cdevinput(circ=%08x,char=%08x)",
+    "_cdevscan()",
+    "_circgetc(circ=%08x)",
+    "_circputc(char=%08x,circ=%08x)",
+    "_ioabort(txt1=%08x,txt2=%08x)",
+    "set_card_find_mode(mode=%08x)",
+    "KernelRedirect(ttyflag=%08x)",
+    "AdjustA0Table()",
+    "get_card_find_mode()"
+};
+
 #ifdef CPU_TRACE
 #define TRACE_M(m) \
     log_trace("%08x: %-7s $%s, %+i($%s)", cpu->pc-8, m, g_mips_cc_register_names[T], IMM16S, g_mips_cc_register_names[S])
@@ -388,8 +702,57 @@
 }
 
 void psx_cpu_cycle(psx_cpu_t* cpu) {
-    if ((cpu->pc & 0x3fffffff) == 0x000000b4)
+    // if ((cpu->pc & 0x3fffffff) == 0x000000a4) {
+    //     if (cpu->r[9] == 0x2f)
+    //         goto no_putchar;
+
+    //     char buf[256];
+    
+    //     sprintf(buf, g_psx_cpu_a_kcall_symtable[cpu->r[9]],
+    //         cpu->r[4],
+    //         cpu->r[5],
+    //         cpu->r[6],
+    //         cpu->r[7]
+    //     );
+    //     log_set_quiet(0);
+    //     log_fatal("A(%02x) %s", cpu->r[9], buf);
+    //     log_set_quiet(1);
+    // }
+
+    if ((cpu->pc & 0x3fffffff) == 0x000000b4) {
         if (cpu->b_function_hook) cpu->b_function_hook(cpu);
+
+        if ((cpu->r[9] == 0x3b) || (cpu->r[9] == 0x3d) || (cpu->r[9] == 0x3f) || (cpu->r[9] == 0x0b))
+            goto no_putchar;
+        
+        // char buf[256];
+
+        // sprintf(buf, g_psx_cpu_b_kcall_symtable[cpu->r[9]],
+        //     cpu->r[4],
+        //     cpu->r[5],
+        //     cpu->r[6],
+        //     cpu->r[7]
+        // );
+        // log_set_quiet(0);
+        // log_fatal("B(%02x) %s", cpu->r[9], buf);
+        // log_set_quiet(1);
+    }
+
+    no_putchar:
+
+    // if ((cpu->pc & 0x3fffffff) == 0x000000c4) {
+    //     char buf[256];
+
+    //     sprintf(buf, g_psx_cpu_c_kcall_symtable[cpu->r[9]],
+    //         cpu->r[4],
+    //         cpu->r[5],
+    //         cpu->r[6],
+    //         cpu->r[7]
+    //     );
+    //     log_set_quiet(0);
+    //     log_fatal("C(%02x) %s", cpu->r[9], buf);
+    //     log_set_quiet(1);
+    // }
 
     cpu->saved_pc = cpu->pc;
     cpu->delay_slot = cpu->branch;
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -104,7 +104,7 @@
 
             return data;
         } break;
-        case 0x04: return gpu->gpustat | 0x1c000000;
+        case 0x04: return gpu->gpustat | 0x1e000000;
     }
 
     log_warn("Unhandled 32-bit GPU read at offset %08x", offset);
@@ -1537,7 +1537,7 @@
         // case 0x38: gpu_cmd_38(gpu); break;
         // case 0x3c: gpu_cmd_3c(gpu); break;
         // case 0x3e: gpu_cmd_3c(gpu); break;
-        // case 0x40: gpu_cmd_40(gpu); break;
+        case 0x40: gpu_cmd_40(gpu); break;
         // case 0x60: gpu_cmd_60(gpu); break;
         // case 0x62: gpu_cmd_60(gpu); break;
         // case 0x64: gpu_cmd_64(gpu); break;
@@ -1628,6 +1628,33 @@
             uint8_t cmd = value >> 24;
 
             switch (cmd) {
+                case 0x00: {
+                    gpu->gpustat = 0x14802000;
+
+                    /*
+                        GP1(01h)      ;clear fifo
+                        GP1(02h)      ;ack irq (0)
+                        GP1(03h)      ;display off (1)
+                        GP1(04h)      ;dma off (0)
+                        GP1(05h)      ;display address (0)
+                        GP1(06h)      ;display x1,x2 (x1=200h, x2=200h+256*10)
+                        GP1(07h)      ;display y1,y2 (y1=010h, y2=010h+240)
+                        GP1(08h)      ;display mode 320x200 NTSC (0)
+                        GP0(E1h..E6h) ;rendering attributes (0)
+                    */
+
+                    gpu->disp_x1 = 0x200;
+                    gpu->disp_x2 = 0xc00;
+                    gpu->disp_y1 = 0x010;
+                    gpu->disp_y2 = 0x100;
+                    gpu->display_mode = 0;
+
+                    gpu->disp_x = 0;
+                    gpu->disp_y = 0;
+
+                    if (gpu->event_cb_table[GPU_EVENT_DMODE])
+                        gpu->event_cb_table[GPU_EVENT_DMODE](gpu);
+                } break;
                 case 0x04: {
                 } break;
                 case 0x05: {
--- a/psx/dev/mcd.c
+++ b/psx/dev/mcd.c
@@ -31,7 +31,7 @@
 uint8_t psx_mcd_read(psx_mcd_t* mcd) {
     switch (mcd->state) {
         case MCD_STATE_TX_HIZ: mcd->tx_data = 0xff; break;
-        case MCD_STATE_TX_FLG: mcd->tx_data = mcd->flag; break;
+        case MCD_STATE_TX_FLG: mcd->tx_data = mcd->flag; mcd->flag = 0x00; break;
         case MCD_STATE_TX_ID1: mcd->tx_data = 0x5a; break;
         case MCD_STATE_TX_ID2: {
             mcd->tx_data_ready = 1;
@@ -43,6 +43,10 @@
                 case 'S': mcd->state = MCD_S_STATE_TX_ACK1; break;
             }
 
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", mcd->tx_data);
+            // log_set_quiet(1);
+
             return mcd->tx_data;
         } break;
 
@@ -67,6 +71,10 @@
                 break;
             }
 
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", data);
+            // log_set_quiet(1);
+
             return data;
         } break;
         case MCD_R_STATE_TX_CHK: mcd->tx_data = mcd->checksum; break;
@@ -74,17 +82,64 @@
             mcd->tx_data_ready = 0;
             mcd->state = MCD_STATE_TX_HIZ;
 
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", 'G');
+            // log_set_quiet(1);
+
             return 'G';
         } break;
+
+        /* Write states */
+        case MCD_W_STATE_RX_MSB: mcd->tx_data = 0x00; break;
+        case MCD_W_STATE_RX_LSB: mcd->tx_data = mcd->msb;
+                                 mcd->pending_bytes = 127; break;
+        case MCD_W_STATE_RX_DATA: {
+             --mcd->pending_bytes;
+
+            mcd->buf[mcd->addr++] = mcd->rx_data;
+
+            if (!mcd->pending_bytes) {
+                mcd->tx_data = mcd->rx_data;
+
+                break;
+            }
+
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", mcd->rx_data);
+            // log_set_quiet(1);
+
+            return mcd->rx_data;
+        } break;
+        case MCD_W_STATE_RX_CHK: mcd->tx_data = mcd->rx_data; break;
+        case MCD_W_STATE_TX_ACK1: mcd->tx_data = 0x5c; break;
+        case MCD_W_STATE_TX_ACK2: mcd->tx_data = 0x5d; break;
+        case MCD_W_STATE_TX_MEB: {
+            mcd->tx_data_ready = 0;
+            mcd->state = MCD_STATE_TX_HIZ;
+
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", 'G');
+            // log_set_quiet(1);
+
+            return 'G';
+        } break;
     }
 
     mcd->tx_data_ready = 1;
     mcd->state++;
 
+    // log_set_quiet(0);
+    // log_fatal("mcd read %02x", mcd->tx_data);
+    // log_set_quiet(1);
+
     return mcd->tx_data;
 }
 
 void psx_mcd_write(psx_mcd_t* mcd, uint8_t data) {
+    // log_set_quiet(0);
+    // log_fatal("mcd write %02x", data);
+    // log_set_quiet(1);
+
     switch (mcd->state) {
         case MCD_STATE_TX_FLG: mcd->mode = data; break;
         case MCD_R_STATE_RX_MSB: mcd->msb = data; break;
@@ -92,11 +147,22 @@
             mcd->lsb = data;
             mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
         } break;
+        case MCD_W_STATE_RX_MSB: mcd->msb = data; break;
+        case MCD_W_STATE_RX_LSB: {
+            mcd->lsb = data;
+            mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
+        } break;
+        case MCD_W_STATE_RX_DATA: mcd->rx_data = data; break;
+        case MCD_W_STATE_RX_CHK: /* Don't care */ break;
     }
 }
 
 int psx_mcd_query(psx_mcd_t* mcd) {
     return mcd->tx_data_ready;
+}
+
+void psx_mcd_reset(psx_mcd_t* mcd) {
+    mcd->state = MCD_STATE_TX_HIZ;
 }
 
 void psx_mcd_destroy(psx_mcd_t* mcd) {
--- a/psx/dev/mcd.h
+++ b/psx/dev/mcd.h
@@ -44,6 +44,7 @@
     uint16_t msb;
     uint16_t lsb;
     uint16_t addr;
+    uint8_t rx_data;
     int pending_bytes;
     char mode;
     int state;
@@ -57,6 +58,7 @@
 uint8_t psx_mcd_read(psx_mcd_t*);
 void psx_mcd_write(psx_mcd_t*, uint8_t);
 int psx_mcd_query(psx_mcd_t*);
+void psx_mcd_reset(psx_mcd_t*);
 void psx_mcd_destroy(psx_mcd_t*);
 
 #endif
\ No newline at end of file
--- a/psx/dev/pad.c
+++ b/psx/dev/pad.c
@@ -44,9 +44,10 @@
 
     if ((!(joy || mcd)) || !(pad->ctrl & CTRL_TXEN))
         return;
-    
-    pad->cycles_until_irq = 512;
 
+    if (pad->ctrl & CTRL_ACIE)
+        pad->cycles_until_irq = 1500;
+
     if (!pad->dest) {
         if ((data == DEST_JOY) || (data == DEST_MCD))
             pad->dest = data;
@@ -84,6 +85,13 @@
 
 void pad_handle_ctrl_write(psx_pad_t* pad, uint32_t value) {
     pad->ctrl = value;
+
+    if (!(pad->ctrl & CTRL_JOUT)) {
+        pad->dest = 0;
+        pad->ctrl &= ~CTRL_SLOT;
+
+        psx_mcd_reset(pad->mcd_slot[(pad->ctrl >> 13) & 1]);
+    }
 }
 
 psx_pad_t* psx_pad_create() {
--- a/psx/dev/pad.h
+++ b/psx/dev/pad.h
@@ -82,12 +82,13 @@
 #define CTRL_UNK3 0x0008
 #define CTRL_ACKN 0x0010
 #define CTRL_UNK5 0x0020
-#define CTRL_NUS7 0x0040
-#define CTRL_RXIM 0x0180
-#define CTRL_TXIE 0x0200
-#define CTRL_RXIE 0x0400
-#define CTRL_ACIE 0x0800
-#define CTRL_SLOT 0x1000
+#define CTRL_REST 0x0040
+#define CTRL_NUS7 0x0080
+#define CTRL_RXIM 0x0300
+#define CTRL_TXIE 0x0400
+#define CTRL_RXIE 0x0800
+#define CTRL_ACIE 0x1000
+#define CTRL_SLOT 0x2000
 
 enum {
     DEST_JOY = 0x01,
--- a/psx/dev/spu.c
+++ b/psx/dev/spu.c
@@ -187,15 +187,6 @@
             SHIFT       = (spu->voice[v].envctl1 >> 10) & 0x1f;
             STEP        = 7 - ((spu->voice[v].envctl1 >> 8) & 3);
             LEVEL       = 0;
-
-            log_fatal("        voice %u KON->Attack e=%u d=%u sh=%u st=%u, l=%04x",
-                v,
-                EXPONENTIAL,
-                DECREASE,
-                SHIFT,
-                STEP,
-                LEVEL
-            );
         } break;
 
         // Attack->Decay
@@ -205,15 +196,6 @@
             SHIFT       = (spu->voice[v].envctl1 >> 4) & 0xf;
             STEP        = -8;
             LEVEL       = 0x7fff;
-
-            log_fatal("        voice %u Attack->Decay e=%u d=%u sh=%u st=%u, l=%04x",
-                v,
-                EXPONENTIAL,
-                DECREASE,
-                SHIFT,
-                STEP,
-                LEVEL
-            );
         } break;
 
         // Decay->Sustain
@@ -225,15 +207,6 @@
             LEVEL       = spu->data[v].adsr_sustain_level;
 
             STEP = DECREASE ? (-8 + STEP) : (7 - STEP);
-
-            log_fatal("        voice %u Decay->Sustain e=%u d=%u sh=%u st=%u, l=%04x",
-                v,
-                EXPONENTIAL,
-                DECREASE,
-                SHIFT,
-                STEP,
-                LEVEL
-            );
         } break;
 
         // Sustain->Release
@@ -243,15 +216,6 @@
             SHIFT       = spu->voice[v].envctl2 & 0x1f;
             STEP        = -8;
             //LEVEL       = spu->data[v].adsr_sustain_level;
-
-            log_fatal("        voice %u Sustain->Release e=%u d=%u sh=%u st=%u, l=%04x",
-                v,
-                EXPONENTIAL,
-                DECREASE,
-                SHIFT,
-                STEP,
-                LEVEL
-            );
         } break;
     }
 
@@ -262,10 +226,18 @@
         CYCLES *= 4;
     
     if (EXPONENTIAL && DECREASE)
-        STEP *= LEVEL / 0x8000;
+        LEVEL_STEP *= LEVEL / 0x8000;
+    
+    spu->data[v].adsr_cycles_reload = CYCLES;
+    
+    log_fatal("voice %u ADSR advance %u c=%u, s=%04x, step=%04x, level=%04x",
+        v, spu->data[v].adsr_phase, CYCLES, LEVEL_STEP, STEP, LEVEL
+    );
 }
 
 void spu_handle_adsr(psx_spu_t* spu, int v) {
+    CYCLES = spu->data[v].adsr_cycles_reload;
+
     LEVEL += LEVEL_STEP;
 
     switch (spu->data[v].adsr_phase) {
@@ -353,6 +325,7 @@
             for (int i = 0; i < 24; i++) {
                 if ((value & (1 << i))) {
                     spu->data[i].adsr_phase = 3;
+                    spu->data[i].playing = 0;
 
                     spu_advance_adsr(spu, i);
 
@@ -466,10 +439,12 @@
     int right = 0x0000;
 
     for (int v = 0; v < 24; v++) {
-        --spu->data[v].adsr_cycles;
+        // if (spu->data[v].adsr_cycles) {
+        //     --spu->data[v].adsr_cycles;
 
-        if (!spu->data[v].adsr_cycles)
-            spu_handle_adsr(spu, v);
+        //     if (!spu->data[v].adsr_cycles)
+        //         spu_handle_adsr(spu, v);
+        // }
 
         if (!spu->data[v].playing)
             continue;
@@ -527,8 +502,13 @@
         out += (g2 * spu->data[v].s[1]) >> 15;
         out += (g3 * spu->data[v].s[0]) >> 15;
 
+        //float adsr_vol = (float)spu->voice[v].envcvol / 32767.0f;
+
         left += out * spu->data[v].lvol;
         right += out * spu->data[v].rvol;
+
+        // left *= adsr_vol;
+        // right *= adsr_vol;
 
         uint16_t step = spu->voice[v].adsampr;
 
--- a/psx/dev/spu.h
+++ b/psx/dev/spu.h
@@ -140,6 +140,7 @@
         */
 
         int adsr_phase;
+        int adsr_cycles_reload;
         int adsr_cycles;
         int adsr_mode;
         int adsr_dir;
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -268,7 +268,7 @@
 void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {
     psx_timer_t* timer = gpu->udata[1];
 
-    if (T1_MODE & 0x100)
+    if (T1_MODE & 0x100 && !T1_PAUSED)
         T1_COUNTER++;
 
     if (T0_MODE & MODE_SYNCEN) {
--