Bug Summary

File:Source/Core/Core/Src/HW/SI.cpp
Location:line 635, column 6
Description:Value stored to 'numOutput' during its initialization is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "Common.h"
6#include "ChunkFile.h"
7#include "../ConfigManager.h"
8#include "../CoreTiming.h"
9#include "../Movie.h"
10#include "../NetPlayClient.h"
11
12#include "SystemTimers.h"
13#include "ProcessorInterface.h"
14#include "VideoInterface.h"
15
16#include "SI.h"
17#include "SI_DeviceGBA.h"
18
19namespace SerialInterface
20{
21
22static int changeDevice;
23
24void RunSIBuffer();
25void UpdateInterrupts();
26
27// SI Interrupt Types
28enum SIInterruptType
29{
30 INT_RDSTINT = 0,
31 INT_TCINT = 1,
32};
33static void GenerateSIInterrupt(SIInterruptType _SIInterrupt);
34
35// SI number of channels
36enum
37{
38 NUMBER_OF_CHANNELS = 0x04
39};
40
41// SI Internal Hardware Addresses
42enum
43{
44 SI_CHANNEL_0_OUT = 0x00,
45 SI_CHANNEL_0_IN_HI = 0x04,
46 SI_CHANNEL_0_IN_LO = 0x08,
47 SI_CHANNEL_1_OUT = 0x0C,
48 SI_CHANNEL_1_IN_HI = 0x10,
49 SI_CHANNEL_1_IN_LO = 0x14,
50 SI_CHANNEL_2_OUT = 0x18,
51 SI_CHANNEL_2_IN_HI = 0x1C,
52 SI_CHANNEL_2_IN_LO = 0x20,
53 SI_CHANNEL_3_OUT = 0x24,
54 SI_CHANNEL_3_IN_HI = 0x28,
55 SI_CHANNEL_3_IN_LO = 0x2C,
56 SI_POLL = 0x30,
57 SI_COM_CSR = 0x34,
58 SI_STATUS_REG = 0x38,
59 SI_EXI_CLOCK_COUNT = 0x3C,
60};
61
62// SI Channel Output
63union USIChannelOut
64{
65 u32 Hex;
66 struct
67 {
68 u32 OUTPUT1 : 8;
69 u32 OUTPUT0 : 8;
70 u32 CMD : 8;
71 u32 : 8;
72 };
73};
74
75// SI Channel Input High u32
76union USIChannelIn_Hi
77{
78 u32 Hex;
79 struct
80 {
81 u32 INPUT3 : 8;
82 u32 INPUT2 : 8;
83 u32 INPUT1 : 8;
84 u32 INPUT0 : 6;
85 u32 ERRLATCH : 1; // 0: no error 1: Error latched. Check SISR.
86 u32 ERRSTAT : 1; // 0: no error 1: error on last transfer
87 };
88};
89
90// SI Channel Input Low u32
91union USIChannelIn_Lo
92{
93 u32 Hex;
94 struct
95 {
96 u32 INPUT7 : 8;
97 u32 INPUT6 : 8;
98 u32 INPUT5 : 8;
99 u32 INPUT4 : 8;
100 };
101};
102
103// SI Channel
104struct SSIChannel
105{
106 USIChannelOut m_Out;
107 USIChannelIn_Hi m_InHi;
108 USIChannelIn_Lo m_InLo;
109 ISIDevice* m_pDevice;
110};
111
112// SI Poll: Controls how often a device is polled
113union USIPoll
114{
115 u32 Hex;
116 struct
117 {
118 u32 VBCPY3 : 1; // 1: write to output buffer only on vblank
119 u32 VBCPY2 : 1;
120 u32 VBCPY1 : 1;
121 u32 VBCPY0 : 1;
122 u32 EN3 : 1; // Enable polling of channel
123 u32 EN2 : 1; // does not affect communication RAM transfers
124 u32 EN1 : 1;
125 u32 EN0 : 1;
126 u32 Y : 8; // Polls per frame
127 u32 X : 10; // Polls per X lines. begins at vsync, min 7, max depends on video mode
128 u32 : 6;
129 };
130};
131
132// SI Communication Control Status Register
133union USIComCSR
134{
135 u32 Hex;
136 struct
137 {
138 u32 TSTART : 1; // write: start transfer read: transfer status
139 u32 CHANNEL : 2; // determines which SI channel will be used on the communication interface.
140 u32 : 3;
141 u32 CALLBEN : 1; // Callback enable
142 u32 CMDEN : 1; // Command enable?
143 u32 INLNGTH : 7;
144 u32 : 1;
145 u32 OUTLNGTH : 7; // Communication Channel Output Length in bytes
146 u32 : 1;
147 u32 CHANEN : 1; // Channel enable?
148 u32 CHANNUM : 2; // Channel number?
149 u32 RDSTINTMSK : 1; // Read Status Interrupt Status Mask
150 u32 RDSTINT : 1; // Read Status Interrupt Status
151 u32 COMERR : 1; // Communication Error (set 0)
152 u32 TCINTMSK : 1; // Transfer Complete Interrupt Mask
153 u32 TCINT : 1; // Transfer Complete Interrupt
154 };
155 USIComCSR() {Hex = 0;}
156 USIComCSR(u32 _hex) {Hex = _hex;}
157};
158
159// SI Status Register
160union USIStatusReg
161{
162 u32 Hex;
163 struct
164 {
165 u32 UNRUN3 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error
166 u32 OVRUN3 : 1; // (RWC) write 1: bit cleared read 1: overrun error
167 u32 COLL3 : 1; // (RWC) write 1: bit cleared read 1: collision error
168 u32 NOREP3 : 1; // (RWC) write 1: bit cleared read 1: response error
169 u32 WRST3 : 1; // (R) 1: buffer channel0 not copied
170 u32 RDST3 : 1; // (R) 1: new Data available
171 u32 : 2; // 7:6
172 u32 UNRUN2 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error
173 u32 OVRUN2 : 1; // (RWC) write 1: bit cleared read 1: overrun error
174 u32 COLL2 : 1; // (RWC) write 1: bit cleared read 1: collision error
175 u32 NOREP2 : 1; // (RWC) write 1: bit cleared read 1: response error
176 u32 WRST2 : 1; // (R) 1: buffer channel0 not copied
177 u32 RDST2 : 1; // (R) 1: new Data available
178 u32 : 2; // 15:14
179 u32 UNRUN1 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error
180 u32 OVRUN1 : 1; // (RWC) write 1: bit cleared read 1: overrun error
181 u32 COLL1 : 1; // (RWC) write 1: bit cleared read 1: collision error
182 u32 NOREP1 : 1; // (RWC) write 1: bit cleared read 1: response error
183 u32 WRST1 : 1; // (R) 1: buffer channel0 not copied
184 u32 RDST1 : 1; // (R) 1: new Data available
185 u32 : 2; // 23:22
186 u32 UNRUN0 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error
187 u32 OVRUN0 : 1; // (RWC) write 1: bit cleared read 1: overrun error
188 u32 COLL0 : 1; // (RWC) write 1: bit cleared read 1: collision error
189 u32 NOREP0 : 1; // (RWC) write 1: bit cleared read 1: response error
190 u32 WRST0 : 1; // (R) 1: buffer channel0 not copied
191 u32 RDST0 : 1; // (R) 1: new Data available
192 u32 : 1;
193 u32 WR : 1; // (RW) write 1 start copy, read 0 copy done
194 };
195 USIStatusReg() {Hex = 0;}
196 USIStatusReg(u32 _hex) {Hex = _hex;}
197};
198
199// SI EXI Clock Count
200union USIEXIClockCount
201{
202 u32 Hex;
203 struct
204 {
205 u32 LOCK : 1; // 1: prevents CPU from setting EXI clock to 32MHz
206 u32 : 0;
207 };
208};
209
210// STATE_TO_SAVE
211static SSIChannel g_Channel[NUMBER_OF_CHANNELS];
212static USIPoll g_Poll;
213static USIComCSR g_ComCSR;
214static USIStatusReg g_StatusReg;
215static USIEXIClockCount g_EXIClockCount;
216static u8 g_SIBuffer[128];
217
218void DoState(PointerWrap &p)
219{
220 for(int i = 0; i < NUMBER_OF_CHANNELS; i++)
221 {
222 p.Do(g_Channel[i].m_InHi.Hex);
223 p.Do(g_Channel[i].m_InLo.Hex);
224 p.Do(g_Channel[i].m_Out.Hex);
225
226 ISIDevice* pDevice = g_Channel[i].m_pDevice;
227 SIDevices type = pDevice->GetDeviceType();
228 p.Do(type);
229 ISIDevice* pSaveDevice = (type == pDevice->GetDeviceType()) ? pDevice : SIDevice_Create(type, i);
230 pSaveDevice->DoState(p);
231 if(pSaveDevice != pDevice)
232 {
233 // if we had to create a temporary device, discard it if we're not loading.
234 // also, if no movie is active, we'll assume the user wants to keep their current devices
235 // instead of the ones they had when the savestate was created.
236 if(p.GetMode() != PointerWrap::MODE_READ ||
237 (!Movie::IsRecordingInput() && !Movie::IsPlayingInput()))
238 {
239 delete pSaveDevice;
240 }
241 else
242 {
243 AddDevice(pSaveDevice);
244 }
245 }
246 }
247 p.Do(g_Poll);
248 p.DoPOD(g_ComCSR);
249 p.DoPOD(g_StatusReg);
250 p.Do(g_EXIClockCount);
251 p.Do(g_SIBuffer);
252}
253
254
255void Init()
256{
257 for (int i = 0; i < NUMBER_OF_CHANNELS; i++)
258 {
259 g_Channel[i].m_Out.Hex = 0;
260 g_Channel[i].m_InHi.Hex = 0;
261 g_Channel[i].m_InLo.Hex = 0;
262
263 if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
264 AddDevice(Movie::IsUsingPad(i) ? (Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i);
265 else if (NetPlay::IsNetPlayRunning())
266 AddDevice((SIDevices) g_NetPlaySettings.m_Controllers[i], i);
267 else
268 AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
269 }
270
271 g_Poll.Hex = 0;
272 g_Poll.X = 7;
273
274 g_ComCSR.Hex = 0;
275
276 g_StatusReg.Hex = 0;
277
278 g_EXIClockCount.Hex = 0;
279 //g_EXIClockCount.LOCK = 1; // Supposedly set on reset, but logs from real wii don't look like it is...
280 memset(g_SIBuffer, 0, 128);
281
282 changeDevice = CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
283}
284
285void Shutdown()
286{
287 for (int i = 0; i < NUMBER_OF_CHANNELS; i++)
288 RemoveDevice(i);
289 GBAConnectionWaiter_Shutdown();
290}
291
292void Read32(u32& _uReturnValue, const u32 _iAddress)
293{
294 // SIBuffer
295 if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) ||
296 (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500))
297 {
298 _uReturnValue = *(u32*)&g_SIBuffer[_iAddress & 0x7F];
299 return;
300 }
301
302 // error if not changed in the switch
303 _uReturnValue = 0xdeadbeef;
304
305 // registers
306 switch (_iAddress & 0x3FF)
307 {
308 //////////////////////////////////////////////////////////////////////////
309 // Channel 0
310 //////////////////////////////////////////////////////////////////////////
311 case SI_CHANNEL_0_OUT:
312 _uReturnValue = g_Channel[0].m_Out.Hex;
313 break;
314
315 case SI_CHANNEL_0_IN_HI:
316 g_StatusReg.RDST0 = 0;
317 UpdateInterrupts();
318 _uReturnValue = g_Channel[0].m_InHi.Hex;
319 break;
320
321 case SI_CHANNEL_0_IN_LO:
322 g_StatusReg.RDST0 = 0;
323 UpdateInterrupts();
324 _uReturnValue = g_Channel[0].m_InLo.Hex;
325 break;
326
327 //////////////////////////////////////////////////////////////////////////
328 // Channel 1
329 //////////////////////////////////////////////////////////////////////////
330 case SI_CHANNEL_1_OUT:
331 _uReturnValue = g_Channel[1].m_Out.Hex;
332 break;
333
334 case SI_CHANNEL_1_IN_HI:
335 g_StatusReg.RDST1 = 0;
336 UpdateInterrupts();
337 _uReturnValue = g_Channel[1].m_InHi.Hex;
338 break;
339
340 case SI_CHANNEL_1_IN_LO:
341 g_StatusReg.RDST1 = 0;
342 UpdateInterrupts();
343 _uReturnValue = g_Channel[1].m_InLo.Hex;
344 break;
345
346 //////////////////////////////////////////////////////////////////////////
347 // Channel 2
348 //////////////////////////////////////////////////////////////////////////
349 case SI_CHANNEL_2_OUT:
350 _uReturnValue = g_Channel[2].m_Out.Hex;
351 break;
352
353 case SI_CHANNEL_2_IN_HI:
354 g_StatusReg.RDST2 = 0;
355 UpdateInterrupts();
356 _uReturnValue = g_Channel[2].m_InHi.Hex;
357 break;
358
359 case SI_CHANNEL_2_IN_LO:
360 g_StatusReg.RDST2 = 0;
361 UpdateInterrupts();
362 _uReturnValue = g_Channel[2].m_InLo.Hex;
363 break;
364
365 //////////////////////////////////////////////////////////////////////////
366 // Channel 3
367 //////////////////////////////////////////////////////////////////////////
368 case SI_CHANNEL_3_OUT:
369 _uReturnValue = g_Channel[3].m_Out.Hex;
370 break;
371
372 case SI_CHANNEL_3_IN_HI:
373 g_StatusReg.RDST3 = 0;
374 UpdateInterrupts();
375 _uReturnValue = g_Channel[3].m_InHi.Hex;
376 break;
377
378 case SI_CHANNEL_3_IN_LO:
379 g_StatusReg.RDST3 = 0;
380 UpdateInterrupts();
381 _uReturnValue = g_Channel[3].m_InLo.Hex;
382 break;
383
384 //////////////////////////////////////////////////////////////////////////
385 // Other
386 //////////////////////////////////////////////////////////////////////////
387 case SI_POLL: _uReturnValue = g_Poll.Hex; break;
388 case SI_COM_CSR: _uReturnValue = g_ComCSR.Hex; break;
389 case SI_STATUS_REG: _uReturnValue = g_StatusReg.Hex; break;
390
391 case SI_EXI_CLOCK_COUNT: _uReturnValue = g_EXIClockCount.Hex; break;
392
393 default:
394 INFO_LOG(SERIALINTERFACE, "(r32-unk): 0x%08x", _iAddress)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 394, "(r32-unk): 0x%08x", _iAddress); } } while (0)
;
395 _dbg_assert_(SERIALINTERFACE,0){};
396 break;
397 }
398
399 DEBUG_LOG(SERIALINTERFACE, "(r32) 0x%08x - 0x%08x", _iAddress, _uReturnValue)do { { if (LogTypes::LDEBUG <= 3) GenericLog(LogTypes::LDEBUG
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 399, "(r32) 0x%08x - 0x%08x", _iAddress, _uReturnValue); } }
while (0)
;
400}
401
402void Write32(const u32 _iValue, const u32 _iAddress)
403{
404 DEBUG_LOG(SERIALINTERFACE, "(w32) 0x%08x @ 0x%08x", _iValue, _iAddress)do { { if (LogTypes::LDEBUG <= 3) GenericLog(LogTypes::LDEBUG
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 404, "(w32) 0x%08x @ 0x%08x", _iValue, _iAddress); } } while
(0)
;
405
406 // SIBuffer
407 if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) ||
408 (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500))
409 {
410 *(u32*)&g_SIBuffer[_iAddress & 0x7F] = _iValue;
411 return;
412 }
413
414 // registers
415 switch (_iAddress & 0x3FF)
416 {
417 case SI_CHANNEL_0_OUT: g_Channel[0].m_Out.Hex = _iValue; break;
418 case SI_CHANNEL_0_IN_HI: g_Channel[0].m_InHi.Hex = _iValue; break;
419 case SI_CHANNEL_0_IN_LO: g_Channel[0].m_InLo.Hex = _iValue; break;
420 case SI_CHANNEL_1_OUT: g_Channel[1].m_Out.Hex = _iValue; break;
421 case SI_CHANNEL_1_IN_HI: g_Channel[1].m_InHi.Hex = _iValue; break;
422 case SI_CHANNEL_1_IN_LO: g_Channel[1].m_InLo.Hex = _iValue; break;
423 case SI_CHANNEL_2_OUT: g_Channel[2].m_Out.Hex = _iValue; break;
424 case SI_CHANNEL_2_IN_HI: g_Channel[2].m_InHi.Hex = _iValue; break;
425 case SI_CHANNEL_2_IN_LO: g_Channel[2].m_InLo.Hex = _iValue; break;
426 case SI_CHANNEL_3_OUT: g_Channel[3].m_Out.Hex = _iValue; break;
427 case SI_CHANNEL_3_IN_HI: g_Channel[3].m_InHi.Hex = _iValue; break;
428 case SI_CHANNEL_3_IN_LO: g_Channel[3].m_InLo.Hex = _iValue; break;
429
430 case SI_POLL:
431 INFO_LOG(SERIALINTERFACE, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 436, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s", g_Poll.X
, g_Poll.Y, g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",
g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ", g_Poll.VBCPY0
? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ", g_Poll.VBCPY2
? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" "); } } while (
0)
432 g_Poll.X, g_Poll.Y,do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 436, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s", g_Poll.X
, g_Poll.Y, g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",
g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ", g_Poll.VBCPY0
? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ", g_Poll.VBCPY2
? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" "); } } while (
0)
433 g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 436, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s", g_Poll.X
, g_Poll.Y, g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",
g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ", g_Poll.VBCPY0
? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ", g_Poll.VBCPY2
? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" "); } } while (
0)
434 g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 436, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s", g_Poll.X
, g_Poll.Y, g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",
g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ", g_Poll.VBCPY0
? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ", g_Poll.VBCPY2
? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" "); } } while (
0)
435 g_Poll.VBCPY0 ? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ",do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 436, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s", g_Poll.X
, g_Poll.Y, g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",
g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ", g_Poll.VBCPY0
? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ", g_Poll.VBCPY2
? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" "); } } while (
0)
436 g_Poll.VBCPY2 ? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" ")do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 436, "Wrote Poll: X=%03d Y=%03d %s%s%s%s%s%s%s%s", g_Poll.X
, g_Poll.Y, g_Poll.EN0 ? "EN0 ":" ", g_Poll.EN1 ? "EN1 ":" ",
g_Poll.EN2 ? "EN2 ":" ", g_Poll.EN3 ? "EN3 ":" ", g_Poll.VBCPY0
? "VBCPY0 ":" ", g_Poll.VBCPY1 ? "VBCPY1 ":" ", g_Poll.VBCPY2
? "VBCPY2 ":" ", g_Poll.VBCPY3 ? "VBCPY3 ":" "); } } while (
0)
;
437 g_Poll.Hex = _iValue;
438 break;
439
440 case SI_COM_CSR:
441 {
442 USIComCSR tmpComCSR(_iValue);
443
444 g_ComCSR.CHANNEL = tmpComCSR.CHANNEL;
445 g_ComCSR.INLNGTH = tmpComCSR.INLNGTH;
446 g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH;
447 g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK;
448 g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK;
449
450 g_ComCSR.COMERR = 0;
451
452 if (tmpComCSR.RDSTINT) g_ComCSR.RDSTINT = 0;
453 if (tmpComCSR.TCINT) g_ComCSR.TCINT = 0;
454
455 // be careful: run si-buffer after updating the INT flags
456 if (tmpComCSR.TSTART) RunSIBuffer();
457 UpdateInterrupts();
458 }
459 break;
460
461 case SI_STATUS_REG:
462 {
463 USIStatusReg tmpStatus(_iValue);
464
465 // clear bits ( if(tmp.bit) SISR.bit=0 )
466 if (tmpStatus.NOREP0) g_StatusReg.NOREP0 = 0;
467 if (tmpStatus.COLL0) g_StatusReg.COLL0 = 0;
468 if (tmpStatus.OVRUN0) g_StatusReg.OVRUN0 = 0;
469 if (tmpStatus.UNRUN0) g_StatusReg.UNRUN0 = 0;
470
471 if (tmpStatus.NOREP1) g_StatusReg.NOREP1 = 0;
472 if (tmpStatus.COLL1) g_StatusReg.COLL1 = 0;
473 if (tmpStatus.OVRUN1) g_StatusReg.OVRUN1 = 0;
474 if (tmpStatus.UNRUN1) g_StatusReg.UNRUN1 = 0;
475
476 if (tmpStatus.NOREP2) g_StatusReg.NOREP2 = 0;
477 if (tmpStatus.COLL2) g_StatusReg.COLL2 = 0;
478 if (tmpStatus.OVRUN2) g_StatusReg.OVRUN2 = 0;
479 if (tmpStatus.UNRUN2) g_StatusReg.UNRUN2 = 0;
480
481 if (tmpStatus.NOREP3) g_StatusReg.NOREP3 = 0;
482 if (tmpStatus.COLL3) g_StatusReg.COLL3 = 0;
483 if (tmpStatus.OVRUN3) g_StatusReg.OVRUN3 = 0;
484 if (tmpStatus.UNRUN3) g_StatusReg.UNRUN3 = 0;
485
486 // send command to devices
487 if (tmpStatus.WR)
488 {
489 g_Channel[0].m_pDevice->SendCommand(g_Channel[0].m_Out.Hex, g_Poll.EN0);
490 g_Channel[1].m_pDevice->SendCommand(g_Channel[1].m_Out.Hex, g_Poll.EN1);
491 g_Channel[2].m_pDevice->SendCommand(g_Channel[2].m_Out.Hex, g_Poll.EN2);
492 g_Channel[3].m_pDevice->SendCommand(g_Channel[3].m_Out.Hex, g_Poll.EN3);
493
494 g_StatusReg.WR = 0;
495 g_StatusReg.WRST0 = 0;
496 g_StatusReg.WRST1 = 0;
497 g_StatusReg.WRST2 = 0;
498 g_StatusReg.WRST3 = 0;
499 }
500 }
501 break;
502
503 case SI_EXI_CLOCK_COUNT:
504 g_EXIClockCount.Hex = _iValue;
505 break;
506
507 case 0x80: // Bogus? never seen it with ma own eyes
508 INFO_LOG(SERIALINTERFACE, "WII something at 0xCD006480")do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 508, "WII something at 0xCD006480"); } } while (0)
;
509 break;
510
511 default:
512 _dbg_assert_(SERIALINTERFACE, 0){};
513 break;
514 }
515}
516
517void UpdateInterrupts()
518{
519 // check if we have to update the RDSTINT flag
520 if (g_StatusReg.RDST0 || g_StatusReg.RDST1 ||
521 g_StatusReg.RDST2 || g_StatusReg.RDST3)
522 g_ComCSR.RDSTINT = 1;
523 else
524 g_ComCSR.RDSTINT = 0;
525
526 // check if we have to generate an interrupt
527 if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) ||
528 (g_ComCSR.TCINT & g_ComCSR.TCINTMSK))
529 {
530 ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, true);
531 }
532 else
533 {
534 ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, false);
535 }
536}
537
538void GenerateSIInterrupt(SIInterruptType _SIInterrupt)
539{
540 switch(_SIInterrupt)
541 {
542 case INT_RDSTINT: g_ComCSR.RDSTINT = 1; break;
543 case INT_TCINT: g_ComCSR.TCINT = 1; break;
544 }
545
546 UpdateInterrupts();
547}
548
549void RemoveDevice(int _iDeviceNumber)
550{
551 delete g_Channel[_iDeviceNumber].m_pDevice;
552 g_Channel[_iDeviceNumber].m_pDevice = NULL__null;
553}
554
555void AddDevice(ISIDevice* pDevice)
556{
557 int _iDeviceNumber = pDevice->GetDeviceNumber();
558
559 //_dbg_assert_(SERIALINTERFACE, _iDeviceNumber < NUMBER_OF_CHANNELS);
560
561 // delete the old device
562 RemoveDevice(_iDeviceNumber);
563
564 // create the new one
565 g_Channel[_iDeviceNumber].m_pDevice = pDevice;
566}
567
568void AddDevice(const SIDevices _device, int _iDeviceNumber)
569{
570 ISIDevice* pDevice = SIDevice_Create(_device, _iDeviceNumber);
571 AddDevice(pDevice);
572}
573
574void SetNoResponse(u32 channel)
575{
576 // raise the NO RESPONSE error
577 switch (channel)
578 {
579 case 0: g_StatusReg.NOREP0 = 1; break;
580 case 1: g_StatusReg.NOREP1 = 1; break;
581 case 2: g_StatusReg.NOREP2 = 1; break;
582 case 3: g_StatusReg.NOREP3 = 1; break;
583 }
584 g_ComCSR.COMERR = 1;
585}
586
587void ChangeDeviceCallback(u64 userdata, int cyclesLate)
588{
589 u8 channel = (u8)(userdata >> 32);
590
591 g_Channel[channel].m_Out.Hex = 0;
592 g_Channel[channel].m_InHi.Hex = 0;
593 g_Channel[channel].m_InLo.Hex = 0;
594
595 SetNoResponse(channel);
596
597 AddDevice((SIDevices)(u32)userdata, channel);
598}
599
600void ChangeDevice(SIDevices device, int channel)
601{
602 // Called from GUI, so we need to make it thread safe.
603 // Let the hardware see no device for .5b cycles
604 CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE);
605 CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device);
606}
607
608void UpdateDevices()
609{
610 // Update channels and set the status bit if there's new data
611 g_StatusReg.RDST0 = !!g_Channel[0].m_pDevice->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex);
612 g_StatusReg.RDST1 = !!g_Channel[1].m_pDevice->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex);
613 g_StatusReg.RDST2 = !!g_Channel[2].m_pDevice->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex);
614 g_StatusReg.RDST3 = !!g_Channel[3].m_pDevice->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex);
615
616 UpdateInterrupts();
617}
618
619void RunSIBuffer()
620{
621 // Math inLength
622 int inLength = g_ComCSR.INLNGTH;
623 if (inLength == 0)
624 inLength = 128;
625 else
626 inLength++;
627
628 // Math outLength
629 int outLength = g_ComCSR.OUTLNGTH;
630 if (outLength == 0)
631 outLength = 128;
632 else
633 outLength++;
634
635 int numOutput = g_Channel[g_ComCSR.CHANNEL].m_pDevice->RunBuffer(g_SIBuffer, inLength);
Value stored to 'numOutput' during its initialization is never read
636
637 DEBUG_LOG(SERIALINTERFACE, "RunSIBuffer (intLen: %i outLen: %i) (processed: %i)", inLength, outLength, numOutput)do { { if (LogTypes::LDEBUG <= 3) GenericLog(LogTypes::LDEBUG
, LogTypes::SERIALINTERFACE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp"
, 637, "RunSIBuffer (intLen: %i outLen: %i) (processed: %i)"
, inLength, outLength, numOutput); } } while (0)
;
638
639 // Transfer completed
640 GenerateSIInterrupt(INT_TCINT);
641 g_ComCSR.TSTART = 0;
642}
643
644int GetTicksToNextSIPoll()
645{
646 // Poll for input at regular intervals (once per frame) when playing or recording a movie
647 if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
648 {
649 return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
650 }
651 if (NetPlay::IsNetPlayRunning())
652 return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2;
653
654 if (!g_Poll.Y && g_Poll.X)
655 return VideoInterface::GetTicksPerLine() * g_Poll.X;
656 else if (!g_Poll.Y)
657 return SystemTimers::GetTicksPerSecond() / 60;
658
659 return min(VideoInterface::GetTicksPerFrame() / g_Poll.Y, VideoInterface::GetTicksPerLine() * g_Poll.X);
660}
661
662} // end of namespace SerialInterface