diff options
| author | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
|---|---|---|
| committer | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
| commit | 7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch) | |
| tree | c28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/exception.c | |
| parent | a2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff) | |
| download | psxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz | |
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/exception.c')
| -rw-r--r-- | libpsx/src/exception.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/libpsx/src/exception.c b/libpsx/src/exception.c new file mode 100644 index 0000000..6ecabb2 --- /dev/null +++ b/libpsx/src/exception.c @@ -0,0 +1,178 @@ +/** + * exception.c + * + * Exception handling code (part 2) + */ + + #include <stdio.h> + #include <stdlib.h> + #include <psx.h> + +#define DICR *((unsigned int*)0x1f8010f4) +#define IPENDING *((volatile unsigned int*)0x1f801070) +#define IMASK *((volatile unsigned int*)0x1f801074) + +void __psxsdk_exception_manager(); + +void (*_EXC_vblank_handler)(); +void (*_EXC_cdrom_handler)(); +void (*_EXC_sio_handler)(unsigned char *data); +void (*_EXC_dma_handler)(); +unsigned int _EXC_vblank_handler_set; +unsigned int _EXC_cdrom_handler_set; +unsigned int _EXC_sio_handler_set; +unsigned int _EXC_dma_handler_set; + +volatile int __psxsdk_gpu_dma_finished; + +void __psxsdk_real_exception_handler() +{ + unsigned int Cause = get_cop0_register(COP0_CAUSE); + unsigned int Cause_excCode = (Cause >> 2) & 31; + unsigned int Cause_IP = (Cause >> 8) & 255; + unsigned int SR = get_cop0_register(COP0_SR); + unsigned int SR_IM = (SR >> 8) & 255; + int i; +/* unsigned int oldSR = SR; + unsigned int psxIP = IPENDING; + unsigned int psxIM = IMASK; + unsigned int sio_data;*/ + + if(Cause_excCode == 0) // interrupt generated the exception + { + /*for(i = 0; i < 8; i++) + { + if((Cause_IP & (1<<i)) && (SR_IM & (1<<i))) + { + SR ^= 1<<(i+8); + set_cop0_register(COP0_SR, SR); + + switch(i) + { + case 2: // PSX Interrupt controller + // program_vblank_handler(); + break; + } + } + }*/ + + if((Cause_IP & (1<<2)) && (SR_IM & (1<<2))) + { + Cause ^= 1<<10; + set_cop0_register(COP0_CAUSE, Cause); + //SR ^= 1<<10; + //set_cop0_register(COP0_SR, SR); + + //while(IPENDING != 0) + { + for(i = 0; i < 11; i++) + { + if(IPENDING & (1<<i)) + { + // printf("IP = %x\n", IPENDING); +// Very interesting, when reading joypad status the PCSXR emulator sets in IPENDING that IRQ7 is pending even +// if it is not enabled in IMASK! That is insane, but it can be easily worked around. +// So we are going to disable pending bits for IRQs in IPENDING in any case, even if the in IRQ at hand was +// not enabled in IMASK. + + IPENDING ^= 1 << i; + + if(IMASK & (1<<i)) + { + // printf("IM = %x\n", IMASK); + + switch(i) + { + case 0: // VBLANK + // if(!(GPU_CONTROL_PORT & (1<<0x1c))) + // GPU_CONTROL_PORT = 0x02000000; + + // Execute the user-supplied VBlank handler. + if(_EXC_vblank_handler_set) + _EXC_vblank_handler(); + break; + case 2: + /* if(_EXC_cdrom_handler_set) + _EXC_cdrom_handler();*/ + break; + case 3: // DMA + // Execute the user-supplied DMA handler. + if(_EXC_dma_handler_set) + _EXC_dma_handler(); + break; + case 8: + //while(!(SIO_STAT & 2)) + //sio_data = SIO_RX_DATA; + + //_EXC_sio_handler((unsigned char*)&sio_data); + + // SIO_CTRL |= SIOCTRL_ACK; + break; + } + } + } + } + } + } + } +} + +static void __psxsdk_dma_handler() +{ + unsigned int s_dicr = DICR; + unsigned char irq = (s_dicr >> 24) & 127; + + if(irq & (1<<2)) // GPU + __psxsdk_gpu_dma_finished = 1; + + // Acknowledge + DICR = s_dicr; + + // Waste some cycles, so that the acknowledgement is reported +// int x; + +// for(x = 0; x < 1000; x++); +} + +extern void _internal_cdromlib_callback(); + + void __PSX_Init_NoBios() + { + _EXC_vblank_handler = NULL; + _EXC_cdrom_handler = _internal_cdromlib_callback; + _EXC_dma_handler = __psxsdk_dma_handler; + _EXC_sio_handler = NULL; + + _EXC_vblank_handler_set = 0; + _EXC_cdrom_handler_set = 0; + _EXC_dma_handler_set = 1; + _EXC_sio_handler_set = 0; + + IMASK = 0; // Clear Mask + IPENDING = 0; // Clear pending interrupts + +// Disable interrupts + + set_cop0_register(COP0_SR, 0); + +// Change exception vector to point to our exception manager + + *((unsigned int*)0x80000080) = 0x08000000 | ((((unsigned int)__psxsdk_exception_manager)>>2) & 0x3FFFFFF); + *((unsigned int*)0x80000084) = 0; + + +// Enable interrupt generation, and interrupt 2 (PlayStation Interrupt Controller) + set_cop0_register(COP0_SR, (1<<10) | 1); + +// Enable VBlank, CDROM and DMA IRQs (on PlayStation Interrupt Controller) + IMASK = 1 | /* CDROM */ /*4 |*/ 8; + +// Set DMA channel priority + DPCR = 0x07654321; + +// Enable DMA IRQ master, and IRQ generation for DMA channel 2 (GPU) + DICR = (1<<23) | (1<<(16+2)); + +// Setup variables + __psxsdk_gpu_dma_finished = 1; +} |
