Bug Summary

File:Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
Location:line 252, column 5
Description:Value stored to 'addr_hi' 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 "UCode_AX.h"
6#include "../../DSP.h"
7#include "FileUtil.h"
8#include "ConfigManager.h"
9
10#define AX_GC
11#include "UCode_AX_Voice.h"
12
13CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc)
14 : IUCode(dsp_hle, crc)
15 , m_work_available(false)
16 , m_cmdlist_size(0)
17 , m_run_on_thread(SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread)
18{
19 WARN_LOG(DSPHLE, "Instantiating CUCode_AX: crc=%08x", crc)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 19, "Instantiating CUCode_AX: crc=%08x", crc); } } while (0
)
;
20 m_rMailHandler.PushMail(DSP_INIT);
21 DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
22
23 LoadResamplingCoefficients();
24
25 if (m_run_on_thread)
26 m_axthread = std::thread(SpawnAXThread, this);
27}
28
29CUCode_AX::~CUCode_AX()
30{
31 if (m_run_on_thread)
32 {
33 m_cmdlist_size = (u16)-1; // Special value to signal end
34 NotifyAXThread();
35 m_axthread.join();
36 }
37
38 m_rMailHandler.Clear();
39}
40
41void CUCode_AX::LoadResamplingCoefficients()
42{
43 m_coeffs_available = false;
44
45 std::string filenames[] = {
46 File::GetUserPath(D_GCUSER_IDX) + "dsp_coef.bin",
47 File::GetSysDirectory() + "/GC/dsp_coef.bin"
48 };
49
50 size_t fidx;
51 std::string filename;
52 for (fidx = 0; fidx < sizeof (filenames) / sizeof (filenames[0]); ++fidx)
53 {
54 filename = filenames[fidx];
55 if (!File::Exists(filename))
56 continue;
57
58 if (File::GetSize(filename) != 0x1000)
59 continue;
60
61 break;
62 }
63
64 if (fidx >= sizeof (filenames) / sizeof (filenames[0]))
65 return;
66
67 WARN_LOG(DSPHLE, "Loading polyphase resampling coeffs from %s", filename.c_str())do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 67, "Loading polyphase resampling coeffs from %s", filename
.c_str()); } } while (0)
;
68
69 File::IOFile fp(filename, "rb");
70 fp.ReadBytes(m_coeffs, 0x1000);
71
72 for (u32 i = 0; i < 0x800; ++i)
73 m_coeffs[i] = Common::swap16(m_coeffs[i]);
74
75 m_coeffs_available = true;
76}
77
78void CUCode_AX::SpawnAXThread(CUCode_AX* self)
79{
80 self->AXThread();
81}
82
83void CUCode_AX::AXThread()
84{
85 while (true)
86 {
87 {
88 std::unique_lock<std::mutex> lk(m_cmdlist_mutex);
89 while (m_cmdlist_size == 0)
90 m_cmdlist_cv.wait(lk);
91 }
92
93 if (m_cmdlist_size == (u16)-1) // End of thread signal
94 break;
95
96 m_processing.lock();
97 HandleCommandList();
98 m_cmdlist_size = 0;
99 SignalWorkEnd();
100 m_processing.unlock();
101 }
102}
103
104void CUCode_AX::SignalWorkEnd()
105{
106 // Signal end of processing
107 m_rMailHandler.PushMail(DSP_YIELD);
108 DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
109}
110
111void CUCode_AX::NotifyAXThread()
112{
113 std::unique_lock<std::mutex> lk(m_cmdlist_mutex);
114 m_cmdlist_cv.notify_one();
115}
116
117void CUCode_AX::StartWorking()
118{
119 if (m_run_on_thread)
120 NotifyAXThread();
121 else
122 m_work_available = true;
123}
124
125void CUCode_AX::HandleCommandList()
126{
127 // Temp variables for addresses computation
128 u16 addr_hi, addr_lo;
129 u16 addr2_hi, addr2_lo;
130 u16 size;
131
132 u32 pb_addr = 0;
133
134#if 0
135 WARN_LOG(DSPHLE, "Command list:")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 135, "Command list:"); } } while (0)
;
136 for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i)
137 WARN_LOG(DSPHLE, "%04x", m_cmdlist[i])do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 137, "%04x", m_cmdlist[i]); } } while (0)
;
138 WARN_LOG(DSPHLE, "-------------")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 138, "-------------"); } } while (0)
;
139#endif
140
141 u32 curr_idx = 0;
142 bool end = false;
143 while (!end)
144 {
145 u16 cmd = m_cmdlist[curr_idx++];
146
147 switch (cmd)
148 {
149 // Some of these commands are unknown, or unused in this AX HLE.
150 // We still need to skip their arguments using "curr_idx += N".
151
152 case CMD_SETUP:
153 addr_hi = m_cmdlist[curr_idx++];
154 addr_lo = m_cmdlist[curr_idx++];
155 SetupProcessing(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
156 break;
157
158 case CMD_DL_AND_VOL_MIX:
159 {
160 addr_hi = m_cmdlist[curr_idx++];
161 addr_lo = m_cmdlist[curr_idx++];
162 u16 vol_main = m_cmdlist[curr_idx++];
163 u16 vol_auxa = m_cmdlist[curr_idx++];
164 u16 vol_auxb = m_cmdlist[curr_idx++];
165 DownloadAndMixWithVolume(HILO_TO_32(addr)((addr_hi << 16) | addr_lo), vol_main, vol_auxa, vol_auxb);
166 break;
167 }
168
169 case CMD_PB_ADDR:
170 addr_hi = m_cmdlist[curr_idx++];
171 addr_lo = m_cmdlist[curr_idx++];
172 pb_addr = HILO_TO_32(addr)((addr_hi << 16) | addr_lo);
173 break;
174
175 case CMD_PROCESS:
176 ProcessPBList(pb_addr);
177 break;
178
179 case CMD_MIX_AUXA:
180 case CMD_MIX_AUXB:
181 // These two commands are handled almost the same internally.
182 addr_hi = m_cmdlist[curr_idx++];
183 addr_lo = m_cmdlist[curr_idx++];
184 addr2_hi = m_cmdlist[curr_idx++];
185 addr2_lo = m_cmdlist[curr_idx++];
186 MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr)((addr_hi << 16) | addr_lo), HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo));
187 break;
188
189 case CMD_UPLOAD_LRS:
190 addr_hi = m_cmdlist[curr_idx++];
191 addr_lo = m_cmdlist[curr_idx++];
192 UploadLRS(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
193 break;
194
195 case CMD_SET_LR:
196 addr_hi = m_cmdlist[curr_idx++];
197 addr_lo = m_cmdlist[curr_idx++];
198 SetMainLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
199 break;
200
201 case CMD_UNK_08: curr_idx += 10; break; // TODO: check
202
203 case CMD_MIX_AUXB_NOWRITE:
204 addr_hi = m_cmdlist[curr_idx++];
205 addr_lo = m_cmdlist[curr_idx++];
206 MixAUXSamples(false, 0, HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
207 break;
208
209 case CMD_COMPRESSOR_TABLE_ADDR: curr_idx += 2; break;
210 case CMD_UNK_0B: break; // TODO: check other versions
211 case CMD_UNK_0C: break; // TODO: check other versions
212
213 case CMD_MORE:
214 addr_hi = m_cmdlist[curr_idx++];
215 addr_lo = m_cmdlist[curr_idx++];
216 size = m_cmdlist[curr_idx++];
217
218 CopyCmdList(HILO_TO_32(addr)((addr_hi << 16) | addr_lo), size);
219 curr_idx = 0;
220 break;
221
222 case CMD_OUTPUT:
223 addr_hi = m_cmdlist[curr_idx++];
224 addr_lo = m_cmdlist[curr_idx++];
225 addr2_hi = m_cmdlist[curr_idx++];
226 addr2_lo = m_cmdlist[curr_idx++];
227 OutputSamples(HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo), HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
228 break;
229
230 case CMD_END:
231 end = true;
232 break;
233
234 case CMD_MIX_AUXB_LR:
235 addr_hi = m_cmdlist[curr_idx++];
236 addr_lo = m_cmdlist[curr_idx++];
237 addr2_hi = m_cmdlist[curr_idx++];
238 addr2_lo = m_cmdlist[curr_idx++];
239 MixAUXBLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo), HILO_TO_32(addr2)((addr2_hi << 16) | addr2_lo));
240 break;
241
242 case CMD_SET_OPPOSITE_LR:
243 addr_hi = m_cmdlist[curr_idx++];
244 addr_lo = m_cmdlist[curr_idx++];
245 SetOppositeLR(HILO_TO_32(addr)((addr_hi << 16) | addr_lo));
246 break;
247
248 case CMD_UNK_12:
249 {
250 u16 samp_val = m_cmdlist[curr_idx++];
251 u16 idx = m_cmdlist[curr_idx++];
252 addr_hi = m_cmdlist[curr_idx++];
Value stored to 'addr_hi' is never read
253 addr_lo = m_cmdlist[curr_idx++];
254 // TODO
255 // suppress warnings:
256 (void)samp_val; (void)idx;
257 break;
258 }
259
260 // Send the contents of MAIN LRS, AUXA LRS and AUXB S to RAM, and
261 // mix data to MAIN LR and AUXB LR.
262 case CMD_SEND_AUX_AND_MIX:
263 {
264 // Address for Main + AUXA LRS upload
265 u16 main_auxa_up_hi = m_cmdlist[curr_idx++];
266 u16 main_auxa_up_lo = m_cmdlist[curr_idx++];
267
268 // Address for AUXB S upload
269 u16 auxb_s_up_hi = m_cmdlist[curr_idx++];
270 u16 auxb_s_up_lo = m_cmdlist[curr_idx++];
271
272 // Address to read data for Main L
273 u16 main_l_dl_hi = m_cmdlist[curr_idx++];
274 u16 main_l_dl_lo = m_cmdlist[curr_idx++];
275
276 // Address to read data for Main R
277 u16 main_r_dl_hi = m_cmdlist[curr_idx++];
278 u16 main_r_dl_lo = m_cmdlist[curr_idx++];
279
280 // Address to read data for AUXB L
281 u16 auxb_l_dl_hi = m_cmdlist[curr_idx++];
282 u16 auxb_l_dl_lo = m_cmdlist[curr_idx++];
283
284 // Address to read data for AUXB R
285 u16 auxb_r_dl_hi = m_cmdlist[curr_idx++];
286 u16 auxb_r_dl_lo = m_cmdlist[curr_idx++];
287
288 SendAUXAndMix(HILO_TO_32(main_auxa_up)((main_auxa_up_hi << 16) | main_auxa_up_lo), HILO_TO_32(auxb_s_up)((auxb_s_up_hi << 16) | auxb_s_up_lo),
289 HILO_TO_32(main_l_dl)((main_l_dl_hi << 16) | main_l_dl_lo), HILO_TO_32(main_r_dl)((main_r_dl_hi << 16) | main_r_dl_lo),
290 HILO_TO_32(auxb_l_dl)((auxb_l_dl_hi << 16) | auxb_l_dl_lo), HILO_TO_32(auxb_r_dl)((auxb_r_dl_hi << 16) | auxb_r_dl_lo));
291 break;
292 }
293
294 default:
295 ERROR_LOG(DSPHLE, "Unknown command in AX command list: %04x", cmd)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 295, "Unknown command in AX command list: %04x", cmd); } } while
(0)
;
296 end = true;
297 break;
298 }
299 }
300}
301
302void CUCode_AX::ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates)
303{
304 u32 start_idx = 0;
305 for (int i = 0; i < curr_ms; ++i)
306 start_idx += num_updates[i];
307
308 for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i)
309 {
310 u16 update_off = Common::swap16(updates[2 * i]);
311 u16 update_val = Common::swap16(updates[2 * i + 1]);
312
313 pb[update_off] = update_val;
314 }
315}
316
317AXMixControl CUCode_AX::ConvertMixerControl(u32 mixer_control)
318{
319 u32 ret = 0;
320
321 // TODO: find other UCode versions with different mixer_control values
322 if (m_CRC == 0x4e8a8b21)
323 {
324 ret |= MIX_L | MIX_R;
325 if (mixer_control & 0x0001) ret |= MIX_AUXA_L | MIX_AUXA_R;
326 if (mixer_control & 0x0002) ret |= MIX_AUXB_L | MIX_AUXB_R;
327 if (mixer_control & 0x0004)
328 {
329 ret |= MIX_S;
330 if (ret & MIX_AUXA_L) ret |= MIX_AUXA_S;
331 if (ret & MIX_AUXB_L) ret |= MIX_AUXB_S;
332 }
333 if (mixer_control & 0x0008)
334 {
335 ret |= MIX_L_RAMP | MIX_R_RAMP;
336 if (ret & MIX_AUXA_L) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
337 if (ret & MIX_AUXB_L) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
338 if (ret & MIX_AUXA_S) ret |= MIX_AUXA_S_RAMP;
339 if (ret & MIX_AUXB_S) ret |= MIX_AUXB_S_RAMP;
340 }
341 }
342 else
343 {
344 if (mixer_control & 0x0001) ret |= MIX_L;
345 if (mixer_control & 0x0002) ret |= MIX_R;
346 if (mixer_control & 0x0004) ret |= MIX_S;
347 if (mixer_control & 0x0008) ret |= MIX_L_RAMP | MIX_R_RAMP | MIX_S_RAMP;
348 if (mixer_control & 0x0010) ret |= MIX_AUXA_L;
349 if (mixer_control & 0x0020) ret |= MIX_AUXA_R;
350 if (mixer_control & 0x0040) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
351 if (mixer_control & 0x0080) ret |= MIX_AUXA_S;
352 if (mixer_control & 0x0100) ret |= MIX_AUXA_S_RAMP;
353 if (mixer_control & 0x0200) ret |= MIX_AUXB_L;
354 if (mixer_control & 0x0400) ret |= MIX_AUXB_R;
355 if (mixer_control & 0x0800) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
356 if (mixer_control & 0x1000) ret |= MIX_AUXB_S;
357 if (mixer_control & 0x2000) ret |= MIX_AUXB_S_RAMP;
358
359 // TODO: 0x4000 is used for Dolby Pro 2 sound mixing
360 }
361
362 return (AXMixControl)ret;
363}
364
365void CUCode_AX::SetupProcessing(u32 init_addr)
366{
367 u16 init_data[0x20];
368
369 for (u32 i = 0; i < 0x20; ++i)
370 init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
371
372 // List of all buffers we have to initialize
373 int* buffers[] = {
374 m_samples_left,
375 m_samples_right,
376 m_samples_surround,
377 m_samples_auxA_left,
378 m_samples_auxA_right,
379 m_samples_auxA_surround,
380 m_samples_auxB_left,
381 m_samples_auxB_right,
382 m_samples_auxB_surround
383 };
384
385 u32 init_idx = 0;
386 for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
387 {
388 s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
389 s16 delta = (s16)init_data[init_idx + 2];
390
391 init_idx += 3;
392
393 if (!init_val)
394 {
395 memset(buffers[i], 0, 5 * 32 * sizeof (int));
396 }
397 else
398 {
399 for (u32 j = 0; j < 32 * 5; ++j)
400 {
401 buffers[i][j] = init_val;
402 init_val += delta;
403 }
404 }
405 }
406}
407
408void CUCode_AX::DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb)
409{
410 int* buffers_main[3] = { m_samples_left, m_samples_right, m_samples_surround };
411 int* buffers_auxa[3] = { m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround };
412 int* buffers_auxb[3] = { m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround };
413 int** buffers[3] = { buffers_main, buffers_auxa, buffers_auxb };
414 u16 volumes[3] = { vol_main, vol_auxa, vol_auxb };
415
416 for (u32 i = 0; i < 3; ++i)
417 {
418 int* ptr = (int*)HLEMemory_Get_Pointer(addr);
419 u16 volume = volumes[i];
420 for (u32 j = 0; j < 3; ++j)
421 {
422 int* buffer = buffers[i][j];
423 for (u32 k = 0; k < 5 * 32; ++k)
424 {
425 s64 sample = (s64)(s32)Common::swap32(*ptr++);
426 sample *= volume;
427 buffer[k] += (s32)(sample >> 15);
428 }
429 }
430 }
431}
432
433void CUCode_AX::ProcessPBList(u32 pb_addr)
434{
435 // Samples per millisecond. In theory DSP sampling rate can be changed from
436 // 32KHz to 48KHz, but AX always process at 32KHz.
437 const u32 spms = 32;
438
439 AXPB pb;
440
441 while (pb_addr)
442 {
443 AXBuffers buffers = {{
444 m_samples_left,
445 m_samples_right,
446 m_samples_surround,
447 m_samples_auxA_left,
448 m_samples_auxA_right,
449 m_samples_auxA_surround,
450 m_samples_auxB_left,
451 m_samples_auxB_right,
452 m_samples_auxB_surround
453 }};
454
455 if (!ReadPB(pb_addr, pb))
456 break;
457
458 u32 updates_addr = HILO_TO_32(pb.updates.data)((pb.updates.data_hi << 16) | pb.updates.data_lo);
459 u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr);
460
461 for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
462 {
463 ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates);
464
465 ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control),
466 m_coeffs_available ? m_coeffs : NULL__null);
467
468 // Forward the buffers
469 for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
470 buffers.ptrs[i] += spms;
471 }
472
473 WritePB(pb_addr, pb);
474 pb_addr = HILO_TO_32(pb.next_pb)((pb.next_pb_hi << 16) | pb.next_pb_lo);
475 }
476}
477
478void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
479{
480 int* buffers[3] = { 0 };
481
482 switch (aux_id)
483 {
484 case 0:
485 buffers[0] = m_samples_auxA_left;
486 buffers[1] = m_samples_auxA_right;
487 buffers[2] = m_samples_auxA_surround;
488 break;
489
490 case 1:
491 buffers[0] = m_samples_auxB_left;
492 buffers[1] = m_samples_auxB_right;
493 buffers[2] = m_samples_auxB_surround;
494 break;
495 }
496
497 // First, we need to send the contents of our AUX buffers to the CPU.
498 if (write_addr)
499 {
500 int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
501 for (u32 i = 0; i < 3; ++i)
502 for (u32 j = 0; j < 5 * 32; ++j)
503 *ptr++ = Common::swap32(buffers[i][j]);
504 }
505
506 // Then, we read the new temp from the CPU and add to our current
507 // temp.
508 int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
509 for (u32 i = 0; i < 5 * 32; ++i)
510 m_samples_left[i] += (int)Common::swap32(*ptr++);
511 for (u32 i = 0; i < 5 * 32; ++i)
512 m_samples_right[i] += (int)Common::swap32(*ptr++);
513 for (u32 i = 0; i < 5 * 32; ++i)
514 m_samples_surround[i] += (int)Common::swap32(*ptr++);
515}
516
517void CUCode_AX::UploadLRS(u32 dst_addr)
518{
519 int buffers[3][5 * 32];
520
521 for (u32 i = 0; i < 5 * 32; ++i)
522 {
523 buffers[0][i] = Common::swap32(m_samples_left[i]);
524 buffers[1][i] = Common::swap32(m_samples_right[i]);
525 buffers[2][i] = Common::swap32(m_samples_surround[i]);
526 }
527 memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof (buffers));
528}
529
530void CUCode_AX::SetMainLR(u32 src_addr)
531{
532 int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
533 for (u32 i = 0; i < 5 * 32; ++i)
534 {
535 int samp = (int)Common::swap32(*ptr++);
536 m_samples_left[i] = samp;
537 m_samples_right[i] = samp;
538 m_samples_surround[i] = 0;
539 }
540}
541
542void CUCode_AX::OutputSamples(u32 lr_addr, u32 surround_addr)
543{
544 int surround_buffer[5 * 32];
545
546 for (u32 i = 0; i < 5 * 32; ++i)
547 surround_buffer[i] = Common::swap32(m_samples_surround[i]);
548 memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
549
550 // 32 samples per ms, 5 ms, 2 channels
551 short buffer[5 * 32 * 2];
552
553 // Output samples clamped to 16 bits and interlaced RLRLRLRLRL...
554 for (u32 i = 0; i < 5 * 32; ++i)
555 {
556 int left = m_samples_left[i];
557 int right = m_samples_right[i];
558
559 if (left < -32767) left = -32767;
560 if (left > 32767) left = 32767;
561 if (right < -32767) right = -32767;
562 if (right > 32767) right = 32767;
563
564 buffer[2 * i] = Common::swap16(right);
565 buffer[2 * i + 1] = Common::swap16(left);
566 }
567
568 memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
569}
570
571void CUCode_AX::MixAUXBLR(u32 ul_addr, u32 dl_addr)
572{
573 // Upload AUXB L/R
574 int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr);
575 for (u32 i = 0; i < 5 * 32; ++i)
576 *ptr++ = Common::swap32(m_samples_auxB_left[i]);
577 for (u32 i = 0; i < 5 * 32; ++i)
578 *ptr++ = Common::swap32(m_samples_auxB_right[i]);
579
580 // Mix AUXB L/R to MAIN L/R, and replace AUXB L/R
581 ptr = (int*)HLEMemory_Get_Pointer(dl_addr);
582 for (u32 i = 0; i < 5 * 32; ++i)
583 {
584 int samp = Common::swap32(*ptr++);
585 m_samples_auxB_left[i] = samp;
586 m_samples_left[i] += samp;
587 }
588 for (u32 i = 0; i < 5 * 32; ++i)
589 {
590 int samp = Common::swap32(*ptr++);
591 m_samples_auxB_right[i] = samp;
592 m_samples_right[i] += samp;
593 }
594}
595
596void CUCode_AX::SetOppositeLR(u32 src_addr)
597{
598 int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
599 for (u32 i = 0; i < 5 * 32; ++i)
600 {
601 int inp = Common::swap32(*ptr++);
602 m_samples_left[i] = -inp;
603 m_samples_right[i] = inp;
604 m_samples_surround[i] = 0;
605 }
606}
607
608void CUCode_AX::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl,
609 u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl)
610{
611 // Buffers to upload first
612 int* up_buffers[] = {
613 m_samples_auxA_left,
614 m_samples_auxA_right,
615 m_samples_auxA_surround
616 };
617
618 // Upload AUXA LRS
619 int* ptr = (int*)HLEMemory_Get_Pointer(main_auxa_up);
620 for (u32 i = 0; i < sizeof (up_buffers) / sizeof (up_buffers[0]); ++i)
621 for (u32 j = 0; j < 32 * 5; ++j)
622 *ptr++ = Common::swap32(up_buffers[i][j]);
623
624 // Upload AUXB S
625 ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up);
626 for (u32 i = 0; i < 32 * 5; ++i)
627 *ptr++ = Common::swap32(m_samples_auxB_surround[i]);
628
629 // Download buffers and addresses
630 int* dl_buffers[] = {
631 m_samples_left,
632 m_samples_right,
633 m_samples_auxB_left,
634 m_samples_auxB_right
635 };
636 u32 dl_addrs[] = {
637 main_l_dl,
638 main_r_dl,
639 auxb_l_dl,
640 auxb_r_dl
641 };
642
643 // Download and mix
644 for (u32 i = 0; i < sizeof (dl_buffers) / sizeof (dl_buffers[0]); ++i)
645 {
646 int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]);
647 for (u32 j = 0; j < 32 * 5; ++j)
648 dl_buffers[i][j] += (int)Common::swap32(*dl_src++);
649 }
650}
651
652void CUCode_AX::HandleMail(u32 mail)
653{
654 // Indicates if the next message is a command list address.
655 static bool next_is_cmdlist = false;
656 static u16 cmdlist_size = 0;
657
658 bool set_next_is_cmdlist = false;
659
660 // Wait for DSP processing to be done before answering any mail. This is
661 // safe to do because it matches what the DSP does on real hardware: there
662 // is no interrupt when a mail from CPU is received.
663 m_processing.lock();
664
665 if (next_is_cmdlist)
666 {
667 CopyCmdList(mail, cmdlist_size);
668 StartWorking();
669 NotifyAXThread();
670 }
671 else if (m_UploadSetupInProgress)
672 {
673 PrepareBootUCode(mail);
674 }
675 else if (mail == MAIL_RESUME)
676 {
677 // Acknowledge the resume request
678 m_rMailHandler.PushMail(DSP_RESUME);
679 DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
680 }
681 else if (mail == MAIL_NEW_UCODE)
682 {
683 soundStream->GetMixer()->SetHLEReady(false);
684 m_UploadSetupInProgress = true;
685 }
686 else if (mail == MAIL_RESET)
687 {
688 m_DSPHLE->SetUCode(UCODE_ROM0x00000000);
689 }
690 else if (mail == MAIL_CONTINUE)
691 {
692 // We don't have to do anything here - the CPU does not wait for a ACK
693 // and sends a cmdlist mail just after.
694 }
695 else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST)
696 {
697 // A command list address is going to be sent next.
698 set_next_is_cmdlist = true;
699 cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK);
700 }
701 else
702 {
703 ERROR_LOG(DSPHLE, "Unknown mail sent to AX::HandleMail: %08x", mail)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 703, "Unknown mail sent to AX::HandleMail: %08x", mail); } }
while (0)
;
704 }
705
706 m_processing.unlock();
707 next_is_cmdlist = set_next_is_cmdlist;
708}
709
710void CUCode_AX::CopyCmdList(u32 addr, u16 size)
711{
712 if (size >= (sizeof (m_cmdlist) / sizeof (u16)))
713 {
714 ERROR_LOG(DSPHLE, "Command list at %08x is too large: size=%d", addr, size)do { { if (LogTypes::LERROR <= 3) GenericLog(LogTypes::LERROR
, LogTypes::DSPHLE, "/home/anal/dolphin-emu/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp"
, 714, "Command list at %08x is too large: size=%d", addr, size
); } } while (0)
;
715 return;
716 }
717
718 for (u32 i = 0; i < size; ++i, addr += 2)
719 m_cmdlist[i] = HLEMemory_Read_U16(addr);
720 m_cmdlist_size = size;
721}
722
723void CUCode_AX::MixAdd(short* out_buffer, int nsamples)
724{
725 // Should never be called: we do not set HLE as ready.
726 // We accurately send samples to RAM instead of directly to the mixer.
727}
728
729void CUCode_AX::Update(int cycles)
730{
731 // Used for UCode switching.
732 if (NeedsResumeMail())
733 {
734 m_rMailHandler.PushMail(DSP_RESUME);
735 DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
736 }
737 else if (m_work_available)
738 {
739 HandleCommandList();
740 m_cmdlist_size = 0;
741 SignalWorkEnd();
742 }
743}
744
745u32 CUCode_AX::GetUpdateMs()
746{
747 return 5;
748}
749
750void CUCode_AX::DoAXState(PointerWrap& p)
751{
752 p.Do(m_cmdlist);
753 p.Do(m_cmdlist_size);
754
755 p.Do(m_samples_left);
756 p.Do(m_samples_right);
757 p.Do(m_samples_surround);
758 p.Do(m_samples_auxA_left);
759 p.Do(m_samples_auxA_right);
760 p.Do(m_samples_auxA_surround);
761 p.Do(m_samples_auxB_left);
762 p.Do(m_samples_auxB_right);
763 p.Do(m_samples_auxB_surround);
764}
765
766void CUCode_AX::DoState(PointerWrap& p)
767{
768 std::lock_guard<std::mutex> lk(m_processing);
769
770 DoStateShared(p);
771 DoAXState(p);
772}