Bug Summary

File:Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
Location:line 249, column 5
Description:Value stored to 'addr_lo' 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_UNK_11: curr_idx += 2; break;
243
244 case CMD_UNK_12:
245 {
246 u16 samp_val = m_cmdlist[curr_idx++];
247 u16 idx = m_cmdlist[curr_idx++];
248 addr_hi = m_cmdlist[curr_idx++];
249 addr_lo = m_cmdlist[curr_idx++];
Value stored to 'addr_lo' is never read
250 // TODO
251 // suppress warnings:
252 (void)samp_val; (void)idx;
253 break;
254 }
255
256 // Send the contents of MAIN LRS, AUXA LRS and AUXB S to RAM, and
257 // mix data to MAIN LR and AUXB LR.
258 case CMD_SEND_AUX_AND_MIX:
259 {
260 // Address for Main + AUXA LRS upload
261 u16 main_auxa_up_hi = m_cmdlist[curr_idx++];
262 u16 main_auxa_up_lo = m_cmdlist[curr_idx++];
263
264 // Address for AUXB S upload
265 u16 auxb_s_up_hi = m_cmdlist[curr_idx++];
266 u16 auxb_s_up_lo = m_cmdlist[curr_idx++];
267
268 // Address to read data for Main L
269 u16 main_l_dl_hi = m_cmdlist[curr_idx++];
270 u16 main_l_dl_lo = m_cmdlist[curr_idx++];
271
272 // Address to read data for Main R
273 u16 main_r_dl_hi = m_cmdlist[curr_idx++];
274 u16 main_r_dl_lo = m_cmdlist[curr_idx++];
275
276 // Address to read data for AUXB L
277 u16 auxb_l_dl_hi = m_cmdlist[curr_idx++];
278 u16 auxb_l_dl_lo = m_cmdlist[curr_idx++];
279
280 // Address to read data for AUXB R
281 u16 auxb_r_dl_hi = m_cmdlist[curr_idx++];
282 u16 auxb_r_dl_lo = m_cmdlist[curr_idx++];
283
284 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),
285 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),
286 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));
287 break;
288 }
289
290 default:
291 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"
, 291, "Unknown command in AX command list: %04x", cmd); } } while
(0)
;
292 end = true;
293 break;
294 }
295 }
296}
297
298void CUCode_AX::ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates)
299{
300 u32 start_idx = 0;
301 for (int i = 0; i < curr_ms; ++i)
302 start_idx += num_updates[i];
303
304 for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i)
305 {
306 u16 update_off = Common::swap16(updates[2 * i]);
307 u16 update_val = Common::swap16(updates[2 * i + 1]);
308
309 pb[update_off] = update_val;
310 }
311}
312
313AXMixControl CUCode_AX::ConvertMixerControl(u32 mixer_control)
314{
315 u32 ret = 0;
316
317 // TODO: find other UCode versions with different mixer_control values
318 if (m_CRC == 0x4e8a8b21)
319 {
320 ret |= MIX_L | MIX_R;
321 if (mixer_control & 0x0001) ret |= MIX_AUXA_L | MIX_AUXA_R;
322 if (mixer_control & 0x0002) ret |= MIX_AUXB_L | MIX_AUXB_R;
323 if (mixer_control & 0x0004)
324 {
325 ret |= MIX_S;
326 if (ret & MIX_AUXA_L) ret |= MIX_AUXA_S;
327 if (ret & MIX_AUXB_L) ret |= MIX_AUXB_S;
328 }
329 if (mixer_control & 0x0008)
330 {
331 ret |= MIX_L_RAMP | MIX_R_RAMP;
332 if (ret & MIX_AUXA_L) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
333 if (ret & MIX_AUXB_L) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
334 if (ret & MIX_AUXA_S) ret |= MIX_AUXA_S_RAMP;
335 if (ret & MIX_AUXB_S) ret |= MIX_AUXB_S_RAMP;
336 }
337 }
338 else
339 {
340 if (mixer_control & 0x0001) ret |= MIX_L;
341 if (mixer_control & 0x0002) ret |= MIX_R;
342 if (mixer_control & 0x0004) ret |= MIX_S;
343 if (mixer_control & 0x0008) ret |= MIX_L_RAMP | MIX_R_RAMP | MIX_S_RAMP;
344 if (mixer_control & 0x0010) ret |= MIX_AUXA_L;
345 if (mixer_control & 0x0020) ret |= MIX_AUXA_R;
346 if (mixer_control & 0x0040) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP;
347 if (mixer_control & 0x0080) ret |= MIX_AUXA_S;
348 if (mixer_control & 0x0100) ret |= MIX_AUXA_S_RAMP;
349 if (mixer_control & 0x0200) ret |= MIX_AUXB_L;
350 if (mixer_control & 0x0400) ret |= MIX_AUXB_R;
351 if (mixer_control & 0x0800) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP;
352 if (mixer_control & 0x1000) ret |= MIX_AUXB_S;
353 if (mixer_control & 0x2000) ret |= MIX_AUXB_S_RAMP;
354
355 // TODO: 0x4000 is used for Dolby Pro 2 sound mixing
356 }
357
358 return (AXMixControl)ret;
359}
360
361void CUCode_AX::SetupProcessing(u32 init_addr)
362{
363 u16 init_data[0x20];
364
365 for (u32 i = 0; i < 0x20; ++i)
366 init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i);
367
368 // List of all buffers we have to initialize
369 int* buffers[] = {
370 m_samples_left,
371 m_samples_right,
372 m_samples_surround,
373 m_samples_auxA_left,
374 m_samples_auxA_right,
375 m_samples_auxA_surround,
376 m_samples_auxB_left,
377 m_samples_auxB_right,
378 m_samples_auxB_surround
379 };
380
381 u32 init_idx = 0;
382 for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i)
383 {
384 s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]);
385 s16 delta = (s16)init_data[init_idx + 2];
386
387 init_idx += 3;
388
389 if (!init_val)
390 {
391 memset(buffers[i], 0, 5 * 32 * sizeof (int));
392 }
393 else
394 {
395 for (u32 j = 0; j < 32 * 5; ++j)
396 {
397 buffers[i][j] = init_val;
398 init_val += delta;
399 }
400 }
401 }
402}
403
404void CUCode_AX::DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb)
405{
406 int* buffers_main[3] = { m_samples_left, m_samples_right, m_samples_surround };
407 int* buffers_auxa[3] = { m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround };
408 int* buffers_auxb[3] = { m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround };
409 int** buffers[3] = { buffers_main, buffers_auxa, buffers_auxb };
410 u16 volumes[3] = { vol_main, vol_auxa, vol_auxb };
411
412 for (u32 i = 0; i < 3; ++i)
413 {
414 int* ptr = (int*)HLEMemory_Get_Pointer(addr);
415 u16 volume = volumes[i];
416 for (u32 j = 0; j < 3; ++j)
417 {
418 int* buffer = buffers[i][j];
419 for (u32 k = 0; k < 5 * 32; ++k)
420 {
421 s64 sample = (s64)(s32)Common::swap32(*ptr++);
422 sample *= volume;
423 buffer[k] += (s32)(sample >> 15);
424 }
425 }
426 }
427}
428
429void CUCode_AX::ProcessPBList(u32 pb_addr)
430{
431 // Samples per millisecond. In theory DSP sampling rate can be changed from
432 // 32KHz to 48KHz, but AX always process at 32KHz.
433 const u32 spms = 32;
434
435 AXPB pb;
436
437 while (pb_addr)
438 {
439 AXBuffers buffers = {{
440 m_samples_left,
441 m_samples_right,
442 m_samples_surround,
443 m_samples_auxA_left,
444 m_samples_auxA_right,
445 m_samples_auxA_surround,
446 m_samples_auxB_left,
447 m_samples_auxB_right,
448 m_samples_auxB_surround
449 }};
450
451 if (!ReadPB(pb_addr, pb))
452 break;
453
454 u32 updates_addr = HILO_TO_32(pb.updates.data)((pb.updates.data_hi << 16) | pb.updates.data_lo);
455 u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr);
456
457 for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
458 {
459 ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates);
460
461 ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control),
462 m_coeffs_available ? m_coeffs : NULL__null);
463
464 // Forward the buffers
465 for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i)
466 buffers.ptrs[i] += spms;
467 }
468
469 WritePB(pb_addr, pb);
470 pb_addr = HILO_TO_32(pb.next_pb)((pb.next_pb_hi << 16) | pb.next_pb_lo);
471 }
472}
473
474void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
475{
476 int* buffers[3] = { 0 };
477
478 switch (aux_id)
479 {
480 case 0:
481 buffers[0] = m_samples_auxA_left;
482 buffers[1] = m_samples_auxA_right;
483 buffers[2] = m_samples_auxA_surround;
484 break;
485
486 case 1:
487 buffers[0] = m_samples_auxB_left;
488 buffers[1] = m_samples_auxB_right;
489 buffers[2] = m_samples_auxB_surround;
490 break;
491 }
492
493 // First, we need to send the contents of our AUX buffers to the CPU.
494 if (write_addr)
495 {
496 int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
497 for (u32 i = 0; i < 3; ++i)
498 for (u32 j = 0; j < 5 * 32; ++j)
499 *ptr++ = Common::swap32(buffers[i][j]);
500 }
501
502 // Then, we read the new temp from the CPU and add to our current
503 // temp.
504 int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
505 for (u32 i = 0; i < 5 * 32; ++i)
506 m_samples_left[i] += (int)Common::swap32(*ptr++);
507 for (u32 i = 0; i < 5 * 32; ++i)
508 m_samples_right[i] += (int)Common::swap32(*ptr++);
509 for (u32 i = 0; i < 5 * 32; ++i)
510 m_samples_surround[i] += (int)Common::swap32(*ptr++);
511}
512
513void CUCode_AX::UploadLRS(u32 dst_addr)
514{
515 int buffers[3][5 * 32];
516
517 for (u32 i = 0; i < 5 * 32; ++i)
518 {
519 buffers[0][i] = Common::swap32(m_samples_left[i]);
520 buffers[1][i] = Common::swap32(m_samples_right[i]);
521 buffers[2][i] = Common::swap32(m_samples_surround[i]);
522 }
523 memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof (buffers));
524}
525
526void CUCode_AX::SetMainLR(u32 src_addr)
527{
528 int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
529 for (u32 i = 0; i < 5 * 32; ++i)
530 {
531 int samp = (int)Common::swap32(*ptr++);
532 m_samples_left[i] = samp;
533 m_samples_right[i] = samp;
534 m_samples_surround[i] = 0;
535 }
536}
537
538void CUCode_AX::OutputSamples(u32 lr_addr, u32 surround_addr)
539{
540 int surround_buffer[5 * 32];
541
542 for (u32 i = 0; i < 5 * 32; ++i)
543 surround_buffer[i] = Common::swap32(m_samples_surround[i]);
544 memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));
545
546 // 32 samples per ms, 5 ms, 2 channels
547 short buffer[5 * 32 * 2];
548
549 // Output samples clamped to 16 bits and interlaced RLRLRLRLRL...
550 for (u32 i = 0; i < 5 * 32; ++i)
551 {
552 int left = m_samples_left[i];
553 int right = m_samples_right[i];
554
555 if (left < -32767) left = -32767;
556 if (left > 32767) left = 32767;
557 if (right < -32767) right = -32767;
558 if (right > 32767) right = 32767;
559
560 buffer[2 * i] = Common::swap16(right);
561 buffer[2 * i + 1] = Common::swap16(left);
562 }
563
564 memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
565}
566
567void CUCode_AX::MixAUXBLR(u32 ul_addr, u32 dl_addr)
568{
569 // Upload AUXB L/R
570 int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr);
571 for (u32 i = 0; i < 5 * 32; ++i)
572 *ptr++ = Common::swap32(m_samples_auxB_left[i]);
573 for (u32 i = 0; i < 5 * 32; ++i)
574 *ptr++ = Common::swap32(m_samples_auxB_right[i]);
575
576 // Mix AUXB L/R to MAIN L/R, and replace AUXB L/R
577 ptr = (int*)HLEMemory_Get_Pointer(dl_addr);
578 for (u32 i = 0; i < 5 * 32; ++i)
579 {
580 int samp = Common::swap32(*ptr++);
581 m_samples_auxB_left[i] = samp;
582 m_samples_left[i] += samp;
583 }
584 for (u32 i = 0; i < 5 * 32; ++i)
585 {
586 int samp = Common::swap32(*ptr++);
587 m_samples_auxB_right[i] = samp;
588 m_samples_right[i] += samp;
589 }
590}
591
592void CUCode_AX::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl,
593 u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl)
594{
595 // Buffers to upload first
596 int* up_buffers[] = {
597 m_samples_auxA_left,
598 m_samples_auxA_right,
599 m_samples_auxA_surround
600 };
601
602 // Upload AUXA LRS
603 int* ptr = (int*)HLEMemory_Get_Pointer(main_auxa_up);
604 for (u32 i = 0; i < sizeof (up_buffers) / sizeof (up_buffers[0]); ++i)
605 for (u32 j = 0; j < 32 * 5; ++j)
606 *ptr++ = Common::swap32(up_buffers[i][j]);
607
608 // Upload AUXB S
609 ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up);
610 for (u32 i = 0; i < 32 * 5; ++i)
611 *ptr++ = Common::swap32(m_samples_auxB_surround[i]);
612
613 // Download buffers and addresses
614 int* dl_buffers[] = {
615 m_samples_left,
616 m_samples_right,
617 m_samples_auxB_left,
618 m_samples_auxB_right
619 };
620 u32 dl_addrs[] = {
621 main_l_dl,
622 main_r_dl,
623 auxb_l_dl,
624 auxb_r_dl
625 };
626
627 // Download and mix
628 for (u32 i = 0; i < sizeof (dl_buffers) / sizeof (dl_buffers[0]); ++i)
629 {
630 int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]);
631 for (u32 j = 0; j < 32 * 5; ++j)
632 dl_buffers[i][j] += (int)Common::swap32(*dl_src++);
633 }
634}
635
636void CUCode_AX::HandleMail(u32 mail)
637{
638 // Indicates if the next message is a command list address.
639 static bool next_is_cmdlist = false;
640 static u16 cmdlist_size = 0;
641
642 bool set_next_is_cmdlist = false;
643
644 // Wait for DSP processing to be done before answering any mail. This is
645 // safe to do because it matches what the DSP does on real hardware: there
646 // is no interrupt when a mail from CPU is received.
647 m_processing.lock();
648
649 if (next_is_cmdlist)
650 {
651 CopyCmdList(mail, cmdlist_size);
652 StartWorking();
653 NotifyAXThread();
654 }
655 else if (m_UploadSetupInProgress)
656 {
657 PrepareBootUCode(mail);
658 }
659 else if (mail == MAIL_RESUME)
660 {
661 // Acknowledge the resume request
662 m_rMailHandler.PushMail(DSP_RESUME);
663 DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
664 }
665 else if (mail == MAIL_NEW_UCODE)
666 {
667 soundStream->GetMixer()->SetHLEReady(false);
668 m_UploadSetupInProgress = true;
669 }
670 else if (mail == MAIL_RESET)
671 {
672 m_DSPHLE->SetUCode(UCODE_ROM0x00000000);
673 }
674 else if (mail == MAIL_CONTINUE)
675 {
676 // We don't have to do anything here - the CPU does not wait for a ACK
677 // and sends a cmdlist mail just after.
678 }
679 else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST)
680 {
681 // A command list address is going to be sent next.
682 set_next_is_cmdlist = true;
683 cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK);
684 }
685 else
686 {
687 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"
, 687, "Unknown mail sent to AX::HandleMail: %08x", mail); } }
while (0)
;
688 }
689
690 m_processing.unlock();
691 next_is_cmdlist = set_next_is_cmdlist;
692}
693
694void CUCode_AX::CopyCmdList(u32 addr, u16 size)
695{
696 if (size >= (sizeof (m_cmdlist) / sizeof (u16)))
697 {
698 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"
, 698, "Command list at %08x is too large: size=%d", addr, size
); } } while (0)
;
699 return;
700 }
701
702 for (u32 i = 0; i < size; ++i, addr += 2)
703 m_cmdlist[i] = HLEMemory_Read_U16(addr);
704 m_cmdlist_size = size;
705}
706
707void CUCode_AX::MixAdd(short* out_buffer, int nsamples)
708{
709 // Should never be called: we do not set HLE as ready.
710 // We accurately send samples to RAM instead of directly to the mixer.
711}
712
713void CUCode_AX::Update(int cycles)
714{
715 // Used for UCode switching.
716 if (NeedsResumeMail())
717 {
718 m_rMailHandler.PushMail(DSP_RESUME);
719 DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
720 }
721 else if (m_work_available)
722 {
723 HandleCommandList();
724 m_cmdlist_size = 0;
725 SignalWorkEnd();
726 }
727}
728
729u32 CUCode_AX::GetUpdateMs()
730{
731 return 5;
732}
733
734void CUCode_AX::DoAXState(PointerWrap& p)
735{
736 p.Do(m_cmdlist);
737 p.Do(m_cmdlist_size);
738
739 p.Do(m_samples_left);
740 p.Do(m_samples_right);
741 p.Do(m_samples_surround);
742 p.Do(m_samples_auxA_left);
743 p.Do(m_samples_auxA_right);
744 p.Do(m_samples_auxA_surround);
745 p.Do(m_samples_auxB_left);
746 p.Do(m_samples_auxB_right);
747 p.Do(m_samples_auxB_surround);
748}
749
750void CUCode_AX::DoState(PointerWrap& p)
751{
752 std::lock_guard<std::mutex> lk(m_processing);
753
754 DoStateShared(p);
755 DoAXState(p);
756}