summaryrefslogtreecommitdiff
path: root/libpsx/src/exception.c
blob: 6ecabb21eb867a4afc5fd9c5a3ece5675edd1961 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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;
}