Bug Summary

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