Bug Summary

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