summaryrefslogtreecommitdiff
path: root/libpsx/src/cop.c
blob: 04b49f593e2ec9384c52aa6d65a5b59eeaa0ed8b (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
#include <psx.h>

unsigned int get_cop_register(unsigned char cop_num,
							unsigned char register_num)
{
// Workaround for MIPS' simplicistic instruction set...	
	
	unsigned int instr[] =
		{0x40020000, // cfc $v0, 0
		  0x03E00008, // jr $ra
		  0x00000000, // nop
                  0x00000000}; // nop

	int (*rawFunc)() = (void*)instr;

// Write coprocessor register number inside instruction		  
	instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );

// Execute modified instruction
	return rawFunc();
}

unsigned int get_cop_ctrl_register(unsigned char cop_num,
							unsigned char register_num)
{
// Workaround for MIPS' simplicistic instruction set...	
	unsigned int instr[] =
		{0x40420000, // mfc $v0, 0
		  0x03E00008, // jr $ra
		  0x00000000, // nop
                  0x00000000}; // nop

	int (*rawFunc)() = (void*)instr;

// Write coprocessor register number inside instruction		  
	instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );

// Execute modified instruction
	return rawFunc();
}

unsigned int get_cop0_register(unsigned char register_num)
{
	return get_cop_register(0, register_num);
}

void set_cop_register(unsigned char cop_num,
					unsigned char register_num,
					unsigned int value)
{
// Workaround for MIPS' simplicistic instruction set...	
	unsigned int instr[] =
		{0x40840000, // mtc $a0, 0
		  0x03E00008, // jr $ra
		  0x00000000, // nop
                  0x00000000}; // nop
		  
	void (*rawFunc)(int value) = (void*)instr;

// Write coprocessor register number inside instruction
	instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );	 

// Execute modified instruction
	rawFunc(value);
}

void set_cop_ctrl_register(unsigned char cop_num,
					unsigned char register_num,
					unsigned int value)
{
// Workaround for MIPS' simplicistic instruction set...	
	unsigned int instr[] =
		{0x40C40000, // ctc $a0, 0
		  0x03E00008, // jr $ra
		  0x00000000, // nop
                  0x00000000}; // nop
		  
	void (*rawFunc)(int value) = (void*)instr;

// Write coprocessor register number inside instruction
	instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 );	 

// Execute modified instruction
	rawFunc(value);
}

void set_cop0_register(unsigned char register_num,
							unsigned int value)
{
	set_cop_register(0, register_num, value);
}

void run_cop_instruction(unsigned char cop_num,
						unsigned int operation)
{
// Workaround for MIPS' simplicistic instruction set...	
	unsigned int instr[] =
		{0x42000000, // cop 0
		  0x03E00008, // jr $ra
		  0x00000000, // nop
                  0x00000000}; // nop
		  
	void (*rawFunc)(void) = (void*)instr;

// Write coprocessor register number inside instruction
	instr[0] |= ( (cop_num & 3) << 26 ) |  (operation & 0x1ffffff);	 

// Execute modified instruction
	rawFunc();
}