summaryrefslogtreecommitdiff
path: root/libpsx/src/cop.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/cop.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/cop.c')
-rw-r--r--libpsx/src/cop.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/libpsx/src/cop.c b/libpsx/src/cop.c
new file mode 100644
index 0000000..04b49f5
--- /dev/null
+++ b/libpsx/src/cop.c
@@ -0,0 +1,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();
+}
+