forked from kode54/libupse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathupse_r3000_abstract.c
135 lines (107 loc) · 3.28 KB
/
upse_r3000_abstract.c
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
/*
* UPSE: the unix playstation sound emulator.
*
* Filename: upse_r3000_abstract.c
* Purpose: libupse: r3K abstract implementation factory
*
* Copyright (c) 2007 William Pitcock <[email protected]>
* Portions copyright (c) 1999-2002 Pcsx Team
* Portions copyright (c) 2004 "Xodnizel"
*
* UPSE is free software, released under the GNU General Public License,
* version 2.
*
* A copy of the GNU General Public License, version 2, is included in
* the UPSE source kit as COPYING.
*
* UPSE is offered without any warranty of any kind, explicit or implicit.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "upse-internal.h"
int upse_ps1_init(upse_module_instance_t *ins)
{
int ret;
if (upse_ps1_memory_init(ins) == -1)
return -1;
ret = upse_r3000_cpu_init(ins);
return ret;
}
void upse_ps1_reset(upse_module_instance_t *ins, upse_psx_revision_t rev)
{
upse_r3000_cpu_reset(ins);
upse_ps1_memory_reset(ins);
ins->spu = upse_ps1_spu_open(ins);
memset(&ins->cpustate, 0, sizeof(ins->cpustate));
ins->cpustate.pc = 0xbfc00000; // Start in bootstrap
ins->cpustate.CP0.r[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
switch (rev)
{
case UPSE_PSX_REV_PS2_IOP:
ins->cpustate.CP0.r[15] = 0x00000010; // PRevID = Revision ID, same as IOP
break;
case UPSE_PSX_REV_PS1:
ins->cpustate.CP0.r[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
break;
}
upse_ps1_hal_reset(ins);
upse_ps1_bios_init(ins);
/* start up the bios */
if (upse_has_custom_bios())
upse_ps1_execute_bios(ins);
}
void upse_ps1_shutdown(upse_module_instance_t *ins)
{
upse_ps1_memory_shutdown(ins);
upse_ps1_bios_shutdown(ins);
upse_r3000_cpu_shutdown(ins);
upse_ps1_spu_close(ins->spu);
ins->spu = NULL;
}
void upse_ps1_exception(upse_module_instance_t *ins, u32 code, u32 bd)
{
_DEBUG("exception, code %d bd %d.", code, bd);
// Set the Cause
ins->cpustate.CP0.n.Cause = code;
#ifdef PSXCPU_LOG
if (bd)
PSXCPU_LOG("bd set\n");
#endif
// Set the EPC & PC
if (bd)
{
ins->cpustate.CP0.n.Cause |= 0x80000000;
ins->cpustate.CP0.n.EPC = (ins->cpustate.pc - 4);
}
else
ins->cpustate.CP0.n.EPC = (ins->cpustate.pc);
if (ins->cpustate.CP0.n.Status & 0x400000)
ins->cpustate.pc = 0xbfc00180;
else
ins->cpustate.pc = 0x80000080;
// Set the Status
ins->cpustate.CP0.n.Status = (ins->cpustate.CP0.n.Status & ~0x3f) | ((ins->cpustate.CP0.n.Status & 0xf) << 2);
if (!upse_has_custom_bios())
upse_ps1_bios_exception(ins);
}
void upse_ps1_branch_test(upse_module_instance_t *ins)
{
upse_psx_counter_state_t *ctrstate = ins->ctrstate;
_ENTER;
if ((ins->cpustate.cycle - ctrstate->psxNextsCounter) >= ctrstate->psxNextCounter)
upse_ps1_counter_update(ins);
if (psxHu32(ins, 0x1070) & psxHu32(ins, 0x1074))
{
if ((ins->cpustate.CP0.n.Status & 0x401) == 0x401)
{
upse_ps1_exception(ins, 0x400, 0);
}
}
_LEAVE;
}
void upse_ps1_execute_bios(upse_module_instance_t *ins)
{
while (ins->cpustate.pc != 0x80030000)
upse_r3000_cpu_execute_block(ins);
}