/[pcsx2_0.9.7]/trunk/pcsx2/R3000A.cpp
ViewVC logotype

Contents of /trunk/pcsx2/R3000A.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (10 years ago) by william
File size: 7488 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-latest) in ./trunk
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16
17 #include "PrecompiledHeader.h"
18 #include "IopCommon.h"
19
20 #include "Sio.h"
21 #include "Sif.h"
22
23 using namespace R3000A;
24
25 R3000Acpu *psxCpu;
26
27 // used for constant propagation
28 u32 g_psxConstRegs[32];
29 u32 g_psxHasConstReg, g_psxFlushedConstReg;
30
31 // Controls when branch tests are performed.
32 u32 g_iopNextEventCycle = 0;
33
34 // This value is used when the IOP execution is broken to return control to the EE.
35 // (which happens when the IOP throws EE-bound interrupts). It holds the value of
36 // iopCycleEE (which is set to zero to facilitate the code break), so that the unrun
37 // cycles can be accounted for later.
38 s32 iopBreak = 0;
39
40 // tracks the IOP's current sync status with the EE. When it dips below zero,
41 // control is returned to the EE.
42 s32 iopCycleEE = -1;
43
44 // Used to signal to the EE when important actions that need IOP-attention have
45 // happened (hsyncs, vsyncs, IOP exceptions, etc). IOP runs code whenever this
46 // is true, even if it's already running ahead a bit.
47 bool iopEventAction = false;
48
49 bool iopEventTestIsActive = false;
50
51 __aligned16 psxRegisters psxRegs;
52
53 void psxReset()
54 {
55 memzero(psxRegs);
56
57 psxRegs.pc = 0xbfc00000; // Start in bootstrap
58 psxRegs.CP0.n.Status = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
59 psxRegs.CP0.n.PRid = 0x0000001f; // PRevID = Revision ID, same as the IOP R3000A
60
61 iopBreak = 0;
62 iopCycleEE = -1;
63 g_iopNextEventCycle = psxRegs.cycle + 4;
64
65 psxHwReset();
66
67 ioman::reset();
68 }
69
70 void psxShutdown() {
71 //psxCpu->Shutdown();
72 }
73
74 void __fastcall psxException(u32 code, u32 bd)
75 {
76 // PSXCPU_LOG("psxException %x: %x, %x", code, psxHu32(0x1070), psxHu32(0x1074));
77 //Console.WriteLn("!! psxException %x: %x, %x", code, psxHu32(0x1070), psxHu32(0x1074));
78 // Set the Cause
79 psxRegs.CP0.n.Cause &= ~0x7f;
80 psxRegs.CP0.n.Cause |= code;
81
82 // Set the EPC & PC
83 if (bd)
84 {
85 PSXCPU_LOG("bd set");
86 psxRegs.CP0.n.Cause|= 0x80000000;
87 psxRegs.CP0.n.EPC = (psxRegs.pc - 4);
88 }
89 else
90 psxRegs.CP0.n.EPC = (psxRegs.pc);
91
92 if (psxRegs.CP0.n.Status & 0x400000)
93 psxRegs.pc = 0xbfc00180;
94 else
95 psxRegs.pc = 0x80000080;
96
97 // Set the Status
98 psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) |
99 ((psxRegs.CP0.n.Status & 0xf) << 2);
100
101 /*if ((((PSXMu32(psxRegs.CP0.n.EPC) >> 24) & 0xfe) == 0x4a)) {
102 // "hokuto no ken" / "Crash Bandicot 2" ... fix
103 PSXMu32(psxRegs.CP0.n.EPC)&= ~0x02000000;
104 }*/
105
106 /*if (psxRegs.CP0.n.Cause == 0x400 && (!(psxHu32(0x1450) & 0x8))) {
107 hwIntcIrq(INTC_SBUS);
108 }*/
109 }
110
111 __fi void psxSetNextBranch( u32 startCycle, s32 delta )
112 {
113 // typecast the conditional to signed so that things don't blow up
114 // if startCycle is greater than our next branch cycle.
115
116 if( (int)(g_iopNextEventCycle - startCycle) > delta )
117 g_iopNextEventCycle = startCycle + delta;
118 }
119
120 __fi void psxSetNextBranchDelta( s32 delta )
121 {
122 psxSetNextBranch( psxRegs.cycle, delta );
123 }
124
125 __fi int psxTestCycle( u32 startCycle, s32 delta )
126 {
127 // typecast the conditional to signed so that things don't explode
128 // if the startCycle is ahead of our current cpu cycle.
129
130 return (int)(psxRegs.cycle - startCycle) >= delta;
131 }
132
133 __fi void PSX_INT( IopEventId n, s32 ecycle )
134 {
135 // Generally speaking games shouldn't throw ints that haven't been cleared yet.
136 // It's usually indicative of something amiss in our emulation, so uncomment this
137 // code to help trap those sort of things.
138
139 // Exception: IRQ16 - SIO - it drops ints like crazy when handling PAD stuff.
140 if( /*n!=16 &&*/ psxRegs.interrupt & (1<<n) )
141 DevCon.Warning( "***** IOP > Twice-thrown int on IRQ %d", n );
142
143 // 19 is CDVD read int, it's supposed to be high.
144 //if (ecycle > 8192 && n != 19)
145 // DevCon.Warning( "IOP cycles high: %d, n %d", ecycle, n );
146
147 psxRegs.interrupt |= 1 << n;
148
149 psxRegs.sCycle[n] = psxRegs.cycle;
150 psxRegs.eCycle[n] = ecycle;
151
152 psxSetNextBranchDelta( ecycle );
153
154 if( iopCycleEE < 0 )
155 {
156 // The EE called this int, so inform it to branch as needed:
157 // fixme - this doesn't take into account EE/IOP sync (the IOP may be running
158 // ahead or behind the EE as per the EEsCycles value)
159 s32 iopDelta = (g_iopNextEventCycle-psxRegs.cycle)*8;
160 cpuSetNextEventDelta( iopDelta );
161 }
162 }
163
164 static __fi void IopTestEvent( IopEventId n, void (*callback)() )
165 {
166 if( !(psxRegs.interrupt & (1 << n)) ) return;
167
168 if( psxTestCycle( psxRegs.sCycle[n], psxRegs.eCycle[n] ) )
169 {
170 psxRegs.interrupt &= ~(1 << n);
171 callback();
172 }
173 else
174 psxSetNextBranch( psxRegs.sCycle[n], psxRegs.eCycle[n] );
175 }
176
177 static __fi void _psxTestInterrupts()
178 {
179 IopTestEvent(IopEvt_SIF0, sif0Interrupt); // SIF0
180 IopTestEvent(IopEvt_SIF1, sif1Interrupt); // SIF1
181 #ifndef SIO_INLINE_IRQS
182 IopTestEvent(IopEvt_SIO, sioInterrupt);
183 #endif
184 IopTestEvent(IopEvt_CdvdRead, cdvdReadInterrupt);
185
186 // Profile-guided Optimization (sorta)
187 // The following ints are rarely called. Encasing them in a conditional
188 // as follows helps speed up most games.
189
190 if( psxRegs.interrupt & ( (1ul<<5) | (3ul<<11) | (3ul<<20) | (3ul<<17) ) )
191 {
192 IopTestEvent(IopEvt_Cdvd, cdvdActionInterrupt);
193 IopTestEvent(IopEvt_Dma11, psxDMA11Interrupt); // SIO2
194 IopTestEvent(IopEvt_Dma12, psxDMA12Interrupt); // SIO2
195 IopTestEvent(IopEvt_Cdrom, cdrInterrupt);
196 IopTestEvent(IopEvt_CdromRead, cdrReadInterrupt);
197 IopTestEvent(IopEvt_DEV9, dev9Interrupt);
198 IopTestEvent(IopEvt_USB, usbInterrupt);
199 }
200 }
201
202 __ri void iopEventTest()
203 {
204 if( psxTestCycle( psxNextsCounter, psxNextCounter ) )
205 {
206 psxRcntUpdate();
207 iopEventAction = true;
208 }
209 else
210 {
211 // start the next branch at the next counter event by default
212 // the interrupt code below will assign nearer branches if needed.
213 g_iopNextEventCycle = psxNextsCounter+psxNextCounter;
214 }
215
216
217 if (psxRegs.interrupt)
218 {
219 iopEventTestIsActive = true;
220 _psxTestInterrupts();
221 iopEventTestIsActive = false;
222 }
223
224 if( (psxHu32(0x1078) != 0) && ((psxHu32(0x1070) & psxHu32(0x1074)) != 0) )
225 {
226 if( (psxRegs.CP0.n.Status & 0xFE01) >= 0x401 )
227 {
228 PSXCPU_LOG("Interrupt: %x %x", psxHu32(0x1070), psxHu32(0x1074));
229 psxException(0, 0);
230 iopEventAction = true;
231
232 // No need to execute the SIFhack after cpuExceptions, since these by nature break SIF's
233 // thread sleep hangs and allow the IOP to "come back to life."
234 psxRegs.interrupt &= ~IopEvt_SIFhack;
235 }
236 }
237 }
238
239 void iopTestIntc()
240 {
241 if( psxHu32(0x1078) == 0 ) return;
242 if( (psxHu32(0x1070) & psxHu32(0x1074)) == 0 ) return;
243
244 if( !eeEventTestIsActive )
245 {
246 // An iop exception has occurred while the EE is running code.
247 // Inform the EE to branch so the IOP can handle it promptly:
248
249 cpuSetNextEventDelta( 16 );
250 iopEventAction = true;
251 //Console.Error( "** IOP Needs an EE EventText, kthx ** %d", iopCycleEE );
252
253 // Note: No need to set the iop's branch delta here, since the EE
254 // will run an IOP branch test regardless.
255 }
256 else if( !iopEventTestIsActive )
257 psxSetNextBranchDelta( 2 );
258 }
259

  ViewVC Help
Powered by ViewVC 1.1.22