Bug Summary

File:/home/anal/dolphin-emu/Source/Core/Core/Src/HW/SI.cpp
Location:line 633, 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 "../NetPlayProto.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(SConfig::GetInstance().m_SIDevice[i], i);
267 }
268
269 g_Poll.Hex = 0;
270 g_Poll.X = 7;
271
272 g_ComCSR.Hex = 0;
273
274 g_StatusReg.Hex = 0;
275
276 g_EXIClockCount.Hex = 0;
277 //g_EXIClockCount.LOCK = 1; // Supposedly set on reset, but logs from real wii don't look like it is...
278 memset(g_SIBuffer, 0, 128);
279
280 changeDevice = CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
281}
282
283void Shutdown()
284{
285 for (int i = 0; i < NUMBER_OF_CHANNELS; i++)
286 RemoveDevice(i);
287 GBAConnectionWaiter_Shutdown();
288}
289
290void Read32(u32& _uReturnValue, const u32 _iAddress)
291{
292 // SIBuffer
293 if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) ||
294 (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500))
295 {
296 _uReturnValue = *(u32*)&g_SIBuffer[_iAddress & 0x7F];
297 return;
298 }
299
300 // error if not changed in the switch
301 _uReturnValue = 0xdeadbeef;
302
303 // registers
304 switch (_iAddress & 0x3FF)
305 {
306 //////////////////////////////////////////////////////////////////////////
307 // Channel 0
308 //////////////////////////////////////////////////////////////////////////
309 case SI_CHANNEL_0_OUT:
310 _uReturnValue = g_Channel[0].m_Out.Hex;
311 break;
312
313 case SI_CHANNEL_0_IN_HI:
314 g_StatusReg.RDST0 = 0;
315 UpdateInterrupts();
316 _uReturnValue = g_Channel[0].m_InHi.Hex;
317 break;
318
319 case SI_CHANNEL_0_IN_LO:
320 g_StatusReg.RDST0 = 0;
321 UpdateInterrupts();
322 _uReturnValue = g_Channel[0].m_InLo.Hex;
323 break;
324
325 //////////////////////////////////////////////////////////////////////////
326 // Channel 1
327 //////////////////////////////////////////////////////////////////////////
328 case SI_CHANNEL_1_OUT:
329 _uReturnValue = g_Channel[1].m_Out.Hex;
330 break;
331
332 case SI_CHANNEL_1_IN_HI:
333 g_StatusReg.RDST1 = 0;
334 UpdateInterrupts();
335 _uReturnValue = g_Channel[1].m_InHi.Hex;
336 break;
337
338 case SI_CHANNEL_1_IN_LO:
339 g_StatusReg.RDST1 = 0;
340 UpdateInterrupts();
341 _uReturnValue = g_Channel[1].m_InLo.Hex;
342 break;
343
344 //////////////////////////////////////////////////////////////////////////
345 // Channel 2
346 //////////////////////////////////////////////////////////////////////////
347 case SI_CHANNEL_2_OUT:
348 _uReturnValue = g_Channel[2].m_Out.Hex;
349 break;
350
351 case SI_CHANNEL_2_IN_HI:
352 g_StatusReg.RDST2 = 0;
353 UpdateInterrupts();
354 _uReturnValue = g_Channel[2].m_InHi.Hex;
355 break;
356
357 case SI_CHANNEL_2_IN_LO:
358 g_StatusReg.RDST2 = 0;
359 UpdateInterrupts();
360 _uReturnValue = g_Channel[2].m_InLo.Hex;
361 break;
362
363 //////////////////////////////////////////////////////////////////////////
364 // Channel 3
365 //////////////////////////////////////////////////////////////////////////
366 case SI_CHANNEL_3_OUT:
367 _uReturnValue = g_Channel[3].m_Out.Hex;
368 break;
369
370 case SI_CHANNEL_3_IN_HI:
371 g_StatusReg.RDST3 = 0;
372 UpdateInterrupts();
373 _uReturnValue = g_Channel[3].m_InHi.Hex;
374 break;
375
376 case SI_CHANNEL_3_IN_LO:
377 g_StatusReg.RDST3 = 0;
378 UpdateInterrupts();
379 _uReturnValue = g_Channel[3].m_InLo.Hex;
380 break;
381
382 //////////////////////////////////////////////////////////////////////////
383 // Other
384 //////////////////////////////////////////////////////////////////////////
385 case SI_POLL: _uReturnValue = g_Poll.Hex; break;
386 case SI_COM_CSR: _uReturnValue = g_ComCSR.Hex; break;
387 case SI_STATUS_REG: _uReturnValue = g_StatusReg.Hex; break;
388
389 case SI_EXI_CLOCK_COUNT: _uReturnValue = g_EXIClockCount.Hex; break;
390
391 default:
392 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"
, 392, "(r32-unk): 0x%08x", _iAddress); } } while (0)
;
393 _dbg_assert_(SERIALINTERFACE,0){};
394 break;
395 }
396
397 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"
, 397, "(r32) 0x%08x - 0x%08x", _iAddress, _uReturnValue); } }
while (0)
;
398}
399
400void Write32(const u32 _iValue, const u32 _iAddress)
401{
402 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"
, 402, "(w32) 0x%08x @ 0x%08x", _iValue, _iAddress); } } while
(0)
;
403
404 // SIBuffer
405 if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) ||
406 (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500))
407 {
408 *(u32*)&g_SIBuffer[_iAddress & 0x7F] = _iValue;
409 return;
410 }
411
412 // registers
413 switch (_iAddress & 0x3FF)
414 {
415 case SI_CHANNEL_0_OUT: g_Channel[0].m_Out.Hex = _iValue; break;
416 case SI_CHANNEL_0_IN_HI: g_Channel[0].m_InHi.Hex = _iValue; break;
417 case SI_CHANNEL_0_IN_LO: g_Channel[0].m_InLo.Hex = _iValue; break;
418 case SI_CHANNEL_1_OUT: g_Channel[1].m_Out.Hex = _iValue; break;
419 case SI_CHANNEL_1_IN_HI: g_Channel[1].m_InHi.Hex = _iValue; break;
420 case SI_CHANNEL_1_IN_LO: g_Channel[1].m_InLo.Hex = _iValue; break;
421 case SI_CHANNEL_2_OUT: g_Channel[2].m_Out.Hex = _iValue; break;
422 case SI_CHANNEL_2_IN_HI: g_Channel[2].m_InHi.Hex = _iValue; break;
423 case SI_CHANNEL_2_IN_LO: g_Channel[2].m_InLo.Hex = _iValue; break;
424 case SI_CHANNEL_3_OUT: g_Channel[3].m_Out.Hex = _iValue; break;
425 case SI_CHANNEL_3_IN_HI: g_Channel[3].m_InHi.Hex = _iValue; break;
426 case SI_CHANNEL_3_IN_LO: g_Channel[3].m_InLo.Hex = _iValue; break;
427
428 case SI_POLL:
429 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"
, 434, "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)
430 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"
, 434, "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)
431 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"
, 434, "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.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"
, 434, "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.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"
, 434, "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.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"
, 434, "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.Hex = _iValue;
436 break;
437
438 case SI_COM_CSR:
439 {
440 USIComCSR tmpComCSR(_iValue);
441
442 g_ComCSR.CHANNEL = tmpComCSR.CHANNEL;
443 g_ComCSR.INLNGTH = tmpComCSR.INLNGTH;
444 g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH;
445 g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK;
446 g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK;
447
448 g_ComCSR.COMERR = 0;
449
450 if (tmpComCSR.RDSTINT) g_ComCSR.RDSTINT = 0;
451 if (tmpComCSR.TCINT) g_ComCSR.TCINT = 0;
452
453 // be careful: run si-buffer after updating the INT flags
454 if (tmpComCSR.TSTART) RunSIBuffer();
455 UpdateInterrupts();
456 }
457 break;
458
459 case SI_STATUS_REG:
460 {
461 USIStatusReg tmpStatus(_iValue);
462
463 // clear bits ( if(tmp.bit) SISR.bit=0 )
464 if (tmpStatus.NOREP0) g_StatusReg.NOREP0 = 0;
465 if (tmpStatus.COLL0) g_StatusReg.COLL0 = 0;
466 if (tmpStatus.OVRUN0) g_StatusReg.OVRUN0 = 0;
467 if (tmpStatus.UNRUN0) g_StatusReg.UNRUN0 = 0;
468
469 if (tmpStatus.NOREP1) g_StatusReg.NOREP1 = 0;
470 if (tmpStatus.COLL1) g_StatusReg.COLL1 = 0;
471 if (tmpStatus.OVRUN1) g_StatusReg.OVRUN1 = 0;
472 if (tmpStatus.UNRUN1) g_StatusReg.UNRUN1 = 0;
473
474 if (tmpStatus.NOREP2) g_StatusReg.NOREP2 = 0;
475 if (tmpStatus.COLL2) g_StatusReg.COLL2 = 0;
476 if (tmpStatus.OVRUN2) g_StatusReg.OVRUN2 = 0;
477 if (tmpStatus.UNRUN2) g_StatusReg.UNRUN2 = 0;
478
479 if (tmpStatus.NOREP3) g_StatusReg.NOREP3 = 0;
480 if (tmpStatus.COLL3) g_StatusReg.COLL3 = 0;
481 if (tmpStatus.OVRUN3) g_StatusReg.OVRUN3 = 0;
482 if (tmpStatus.UNRUN3) g_StatusReg.UNRUN3 = 0;
483
484 // send command to devices
485 if (tmpStatus.WR)
486 {
487 g_Channel[0].m_pDevice->SendCommand(g_Channel[0].m_Out.Hex, g_Poll.EN0);
488 g_Channel[1].m_pDevice->SendCommand(g_Channel[1].m_Out.Hex, g_Poll.EN1);
489 g_Channel[2].m_pDevice->SendCommand(g_Channel[2].m_Out.Hex, g_Poll.EN2);
490 g_Channel[3].m_pDevice->SendCommand(g_Channel[3].m_Out.Hex, g_Poll.EN3);
491
492 g_StatusReg.WR = 0;
493 g_StatusReg.WRST0 = 0;
494 g_StatusReg.WRST1 = 0;
495 g_StatusReg.WRST2 = 0;
496 g_StatusReg.WRST3 = 0;
497 }
498 }
499 break;
500
501 case SI_EXI_CLOCK_COUNT:
502 g_EXIClockCount.Hex = _iValue;
503 break;
504
505 case 0x80: // Bogus? never seen it with ma own eyes
506 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"
, 506, "WII something at 0xCD006480"); } } while (0)
;
507 break;
508
509 default:
510 _dbg_assert_(SERIALINTERFACE, 0){};
511 break;
512 }
513}
514
515void UpdateInterrupts()
516{
517 // check if we have to update the RDSTINT flag
518 if (g_StatusReg.RDST0 || g_StatusReg.RDST1 ||
519 g_StatusReg.RDST2 || g_StatusReg.RDST3)
520 g_ComCSR.RDSTINT = 1;
521 else
522 g_ComCSR.RDSTINT = 0;
523
524 // check if we have to generate an interrupt
525 if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) ||
526 (g_ComCSR.TCINT & g_ComCSR.TCINTMSK))
527 {
528 ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, true);
529 }
530 else
531 {
532 ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, false);
533 }
534}
535
536void GenerateSIInterrupt(SIInterruptType _SIInterrupt)
537{
538 switch(_SIInterrupt)
539 {
540 case INT_RDSTINT: g_ComCSR.RDSTINT = 1; break;
541 case INT_TCINT: g_ComCSR.TCINT = 1; break;
542 }
543
544 UpdateInterrupts();
545}
546
547void RemoveDevice(int _iDeviceNumber)
548{
549 delete g_Channel[_iDeviceNumber].m_pDevice;
550 g_Channel[_iDeviceNumber].m_pDevice = NULL__null;
551}
552
553void AddDevice(ISIDevice* pDevice)
554{
555 int _iDeviceNumber = pDevice->GetDeviceNumber();
556
557 //_dbg_assert_(SERIALINTERFACE, _iDeviceNumber < NUMBER_OF_CHANNELS);
558
559 // delete the old device
560 RemoveDevice(_iDeviceNumber);
561
562 // create the new one
563 g_Channel[_iDeviceNumber].m_pDevice = pDevice;
564}
565
566void AddDevice(const SIDevices _device, int _iDeviceNumber)
567{
568 ISIDevice *pDevice = SIDevice_Create(_device, _iDeviceNumber);
569 AddDevice(pDevice);
570}
571
572void SetNoResponse(u32 channel)
573{
574 // raise the NO RESPONSE error
575 switch (channel)
576 {
577 case 0: g_StatusReg.NOREP0 = 1; break;
578 case 1: g_StatusReg.NOREP1 = 1; break;
579 case 2: g_StatusReg.NOREP2 = 1; break;
580 case 3: g_StatusReg.NOREP3 = 1; break;
581 }
582 g_ComCSR.COMERR = 1;
583}
584
585void ChangeDeviceCallback(u64 userdata, int cyclesLate)
586{
587 u8 channel = (u8)(userdata >> 32);
588
589 g_Channel[channel].m_Out.Hex = 0;
590 g_Channel[channel].m_InHi.Hex = 0;
591 g_Channel[channel].m_InLo.Hex = 0;
592
593 SetNoResponse(channel);
594
595 AddDevice((SIDevices)(u32)userdata, channel);
596}
597
598void ChangeDevice(SIDevices device, int channel)
599{
600 // Called from GUI, so we need to make it thread safe.
601 // Let the hardware see no device for .5b cycles
602 CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE);
603 CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device);
604}
605
606void UpdateDevices()
607{
608 // Update channels and set the status bit if there's new data
609 g_StatusReg.RDST0 = !!g_Channel[0].m_pDevice->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex);
610 g_StatusReg.RDST1 = !!g_Channel[1].m_pDevice->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex);
611 g_StatusReg.RDST2 = !!g_Channel[2].m_pDevice->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex);
612 g_StatusReg.RDST3 = !!g_Channel[3].m_pDevice->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex);
613
614 UpdateInterrupts();
615}
616
617void RunSIBuffer()
618{
619 // Math inLength
620 int inLength = g_ComCSR.INLNGTH;
621 if (inLength == 0)
622 inLength = 128;
623 else
624 inLength++;
625
626 // Math outLength
627 int outLength = g_ComCSR.OUTLNGTH;
628 if (outLength == 0)
629 outLength = 128;
630 else
631 outLength++;
632
633 int numOutput = g_Channel[g_ComCSR.CHANNEL].m_pDevice->RunBuffer(g_SIBuffer, inLength);
Value stored to 'numOutput' during its initialization is never read
634
635 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"
, 635, "RunSIBuffer (intLen: %i outLen: %i) (processed: %i)"
, inLength, outLength, numOutput); } } while (0)
;
636
637 // Transfer completed
638 GenerateSIInterrupt(INT_TCINT);
639 g_ComCSR.TSTART = 0;
640}
641
642int GetTicksToNextSIPoll()
643{
644 // Poll for input at regular intervals (once per frame) when playing or recording a movie
645 if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
646 {
647 if (Movie::IsNetPlayRecording())
648 return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2;
649 else
650 return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
651 }
652 if (NetPlay::IsNetPlayRunning())
653 return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2;
654
655 if (!g_Poll.Y && g_Poll.X)
656 return VideoInterface::GetTicksPerLine() * g_Poll.X;
657 else if (!g_Poll.Y)
658 return SystemTimers::GetTicksPerSecond() / 60;
659
660 return min(VideoInterface::GetTicksPerFrame() / g_Poll.Y, VideoInterface::GetTicksPerLine() * g_Poll.X);
661}
662
663} // end of namespace SerialInterface