Пример #1
0
void AXUCode::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, u32 main_r_dl,
                            u32 auxb_l_dl, u32 auxb_r_dl)
{
  // Buffers to upload first
  int* up_buffers[] = {m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround};

  // Upload AUXA LRS
  int* ptr = (int*)HLEMemory_Get_Pointer(main_auxa_up);
  for (auto& up_buffer : up_buffers)
    for (u32 j = 0; j < 32 * 5; ++j)
      *ptr++ = Common::swap32(up_buffer[j]);

  // Upload AUXB S
  ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up);
  for (auto& sample : m_samples_auxB_surround)
    *ptr++ = Common::swap32(sample);

  // Download buffers and addresses
  int* dl_buffers[] = {m_samples_left, m_samples_right, m_samples_auxB_left, m_samples_auxB_right};
  u32 dl_addrs[] = {main_l_dl, main_r_dl, auxb_l_dl, auxb_r_dl};

  // Download and mix
  for (size_t i = 0; i < ArraySize(dl_buffers); ++i)
  {
    int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]);
    for (size_t j = 0; j < 32 * 5; ++j)
      dl_buffers[i][j] += (int)Common::swap32(*dl_src++);
  }
}
Пример #2
0
void ROMUCode::BootUCode()
{
	u32 ector_crc = HashEctor(
		(u8*)HLEMemory_Get_Pointer(m_current_ucode.m_ram_address),
		m_current_ucode.m_length);

#if defined(_DEBUG) || defined(DEBUGFAST)
	std::string ucode_dump_path = StringFromFormat(
		"%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc);

	File::IOFile fp(ucode_dump_path, "wb");
	if (fp)
	{
		fp.WriteArray((u8*)HLEMemory_Get_Pointer(m_current_ucode.m_ram_address),
		              m_current_ucode.m_length);
	}
#endif

	DEBUG_LOG(DSPHLE, "CurrentUCode SOURCE Addr: 0x%08x", m_current_ucode.m_ram_address);
	DEBUG_LOG(DSPHLE, "CurrentUCode Length:      0x%08x", m_current_ucode.m_length);
	DEBUG_LOG(DSPHLE, "CurrentUCode DEST Addr:   0x%08x", m_current_ucode.m_imem_address);
	DEBUG_LOG(DSPHLE, "CurrentUCode DMEM Length: 0x%08x", m_current_ucode.m_dmem_length);
	DEBUG_LOG(DSPHLE, "CurrentUCode init_vector: 0x%08x", m_current_ucode.m_start_pc);
	DEBUG_LOG(DSPHLE, "CurrentUCode CRC:         0x%08x", ector_crc);
	DEBUG_LOG(DSPHLE, "BootTask - done");

	m_dsphle->SetUCode(ector_crc);
}
Пример #3
0
void CUCode_AX::OutputSamples(u32 lr_addr, u32 surround_addr)
{
	int surround_buffer[5 * 32];

	for (u32 i = 0; i < 5 * 32; ++i)
		surround_buffer[i] = Common::swap32(m_samples_surround[i]);
	memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer));

	// 32 samples per ms, 5 ms, 2 channels
	short buffer[5 * 32 * 2];

	// Output samples clamped to 16 bits and interlaced RLRLRLRLRL...
	for (u32 i = 0; i < 5 * 32; ++i)
	{
		int left  = m_samples_left[i];
		int right = m_samples_right[i];

		if (left < -32767)  left = -32767;
		if (left > 32767)   left = 32767;
		if (right < -32767) right = -32767;
		if (right >  32767) right = 32767;

		buffer[2 * i] = Common::swap16(right);
		buffer[2 * i + 1] = Common::swap16(left);
	}

	memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));
}
Пример #4
0
void CUCode_AXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume,
                                 bool upload_auxc)
{
	u16 volume_ramp[96];
	GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, 96);
	m_last_main_volume = volume;

	int upload_buffer[3 * 32] = { 0 };

	for (u32 i = 0; i < 3 * 32; ++i)
		upload_buffer[i] = Common::swap32(m_samples_surround[i]);
	memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer));

	if (upload_auxc)
	{
		surround_addr += sizeof (upload_buffer);
		for (u32 i = 0; i < 3 * 32; ++i)
			upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]);
		memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer));
	}

	short buffer[3 * 32 * 2];

	// Clamp internal buffers to 16 bits.
	for (u32 i = 0; i < 3 * 32; ++i)
	{
		int left  = m_samples_left[i];
		int right = m_samples_right[i];

		// Apply global volume. Cast to s64 to avoid overflow.
		left = ((s64)left * volume_ramp[i]) >> 15;
		right = ((s64)right * volume_ramp[i]) >> 15;

		if (left < -32767)  left = -32767;
		if (left > 32767)   left = 32767;
		if (right < -32767) right = -32767;
		if (right >  32767) right = 32767;

		m_samples_left[i] = left;
		m_samples_right[i] = right;
	}

	for (u32 i = 0; i < 3 * 32; ++i)
	{
		buffer[2 * i] = Common::swap16(m_samples_right[i]);
		buffer[2 * i + 1] = Common::swap16(m_samples_left[i]);
	}

	memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer));

	// There should be a DSP_SYNC message sent here. However, it looks like not
	// sending it does not cause any issue, and sending it actually causes some
	// sounds to go at half speed. I have no idea why.
}
Пример #5
0
void CUCode_AXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume)
{
	u16 volume_ramp[96];
	GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96);
	m_last_aux_volumes[aux_id] = volume;

	int* buffers[3] = { 0 };
	int* main_buffers[3] = {
		m_samples_left,
		m_samples_right,
		m_samples_surround
	};

	switch (aux_id)
	{
	case 0:
		buffers[0] = m_samples_auxA_left;
		buffers[1] = m_samples_auxA_right;
		buffers[2] = m_samples_auxA_surround;
		break;

	case 1:
		buffers[0] = m_samples_auxB_left;
		buffers[1] = m_samples_auxB_right;
		buffers[2] = m_samples_auxB_surround;
		break;

	case 2:
		buffers[0] = m_samples_auxC_left;
		buffers[1] = m_samples_auxC_right;
		buffers[2] = m_samples_auxC_surround;
		break;
	}

	// Send the content of AUX buffers to the CPU
	if (write_addr)
	{
		int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
		for (auto& buffer : buffers)
			for (u32 j = 0; j < 3 * 32; ++j)
				*ptr++ = Common::swap32(buffer[j]);
	}

	// Then read the buffers from the CPU and add to our main buffers.
	int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
	for (auto& main_buffer : main_buffers)
		for (u32 j = 0; j < 3 * 32; ++j)
		{
			s64 sample = (s64)(s32)Common::swap32(*ptr++);
			sample *= volume_ramp[j];
			main_buffer[j] += (s32)(sample >> 15);
		}
}
Пример #6
0
void AXUCode::ProcessPBList(u32 pb_addr)
{
  // Samples per millisecond. In theory DSP sampling rate can be changed from
  // 32KHz to 48KHz, but AX always process at 32KHz.
  const u32 spms = 32;

  AXPB pb;

  while (pb_addr)
  {
    AXBuffers buffers = {{m_samples_left, m_samples_right, m_samples_surround, m_samples_auxA_left,
                          m_samples_auxA_right, m_samples_auxA_surround, m_samples_auxB_left,
                          m_samples_auxB_right, m_samples_auxB_surround}};

    ReadPB(pb_addr, pb);

    u32 updates_addr = HILO_TO_32(pb.updates.data);
    u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr);

    for (int curr_ms = 0; curr_ms < 5; ++curr_ms)
    {
      ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates);

      ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control),
                   m_coeffs_available ? m_coeffs : nullptr);

      // Forward the buffers
      for (size_t i = 0; i < ArraySize(buffers.ptrs); ++i)
        buffers.ptrs[i] += spms;
    }

    WritePB(pb_addr, pb);
    pb_addr = HILO_TO_32(pb.next_pb);
  }
}
Пример #7
0
void AXWiiUCode::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, bool upload_auxc)
{
	u16 volume_ramp[96];
	GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, ArraySize(volume_ramp));
	m_last_main_volume = volume;

	int upload_buffer[3 * 32] = { 0 };

	for (u32 i = 0; i < 3 * 32; ++i)
		upload_buffer[i] = Common::swap32(m_samples_surround[i]);
	memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof(upload_buffer));

	if (upload_auxc)
	{
		surround_addr += sizeof(upload_buffer);
		for (u32 i = 0; i < 3 * 32; ++i)
			upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]);
		memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof(upload_buffer));
	}

	short buffer[3 * 32 * 2];

	// Clamp internal buffers to 16 bits.
	for (u32 i = 0; i < 3 * 32; ++i)
	{
		int left = m_samples_left[i];
		int right = m_samples_right[i];

		// Apply global volume. Cast to s64 to avoid overflow.
		left = ((s64)left * volume_ramp[i]) >> 15;
		right = ((s64)right * volume_ramp[i]) >> 15;

		m_samples_left[i] = MathUtil::Clamp(left, -32767, 32767);
		m_samples_right[i] = MathUtil::Clamp(right, -32767, 32767);
	}

	for (u32 i = 0; i < 3 * 32; ++i)
	{
		buffer[2 * i] = Common::swap16(m_samples_right[i]);
		buffer[2 * i + 1] = Common::swap16(m_samples_left[i]);
	}

	memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof(buffer));
	m_mail_handler.PushMail(DSP_SYNC, true);
}
Пример #8
0
void CUCode_AXWii::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume)
{
	int* aux_left = aux_id ? m_samples_auxB_left : m_samples_auxA_left;
	int* aux_right = aux_id ? m_samples_auxB_right : m_samples_auxA_right;
	int* aux_surround = aux_id ? m_samples_auxB_surround : m_samples_auxA_surround;
	int* auxc_buffer = aux_id ? m_samples_auxC_surround : m_samples_auxC_right;

	int* upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[0]);
	for (u32 i = 0; i < 96; ++i)
		*upload_ptr++ = Common::swap32(aux_left[i]);
	for (u32 i = 0; i < 96; ++i)
		*upload_ptr++ = Common::swap32(aux_right[i]);
	for (u32 i = 0; i < 96; ++i)
		*upload_ptr++ = Common::swap32(aux_surround[i]);

	upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[1]);
	for (u32 i = 0; i < 96; ++i)
		*upload_ptr++ = Common::swap32(auxc_buffer[i]);

	u16 volume_ramp[96];
	GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96);
	m_last_aux_volumes[aux_id] = volume;

	int* mix_dest[4] = {
		m_samples_left,
		m_samples_right,
		m_samples_surround,
		m_samples_auxC_left
	};
	for (u32 mix_i = 0; mix_i < 4; ++mix_i)
	{
		int* dl_ptr = (int*)HLEMemory_Get_Pointer(addresses[2 + mix_i]);
		for (u32 i = 0; i < 96; ++i)
			aux_left[i] = Common::swap32(dl_ptr[i]);

		for (u32 i = 0; i < 96; ++i)
		{
			s64 sample = (s64)(s32)aux_left[i];
			sample *= volume_ramp[i];
			mix_dest[mix_i][i] += (s32)(sample >> 15);
		}
	}
}
Пример #9
0
void CUCode_AX::SetOppositeLR(u32 src_addr)
{
	int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
	for (u32 i = 0; i < 5 * 32; ++i)
	{
		int inp = Common::swap32(*ptr++);
		m_samples_left[i] = -inp;
		m_samples_right[i] = inp;
		m_samples_surround[i] = 0;
	}
}
Пример #10
0
void CUCode_AX::SetMainLR(u32 src_addr)
{
	int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
	for (u32 i = 0; i < 5 * 32; ++i)
	{
		int samp = (int)Common::swap32(*ptr++);
		m_samples_left[i] = samp;
		m_samples_right[i] = samp;
		m_samples_surround[i] = 0;
	}
}
Пример #11
0
void CUCode_AX::UploadLRS(u32 dst_addr)
{
	int buffers[3][5 * 32];

	for (u32 i = 0; i < 5 * 32; ++i)
	{
		buffers[0][i] = Common::swap32(m_samples_left[i]);
		buffers[1][i] = Common::swap32(m_samples_right[i]);
		buffers[2][i] = Common::swap32(m_samples_surround[i]);
	}
	memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof (buffers));
}
Пример #12
0
void CUCode_AXWii::AddToLR(u32 val_addr, bool neg)
{
	int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
	for (int i = 0; i < 32 * 3; ++i)
	{
		int val = (int)Common::swap32(*ptr++);
		if (neg)
			val = -val;

		m_samples_left[i] += val;
		m_samples_right[i] += val;
	}
}
Пример #13
0
void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr)
{
	int* buffers[3] = { 0 };

	switch (aux_id)
	{
	case 0:
		buffers[0] = m_samples_auxA_left;
		buffers[1] = m_samples_auxA_right;
		buffers[2] = m_samples_auxA_surround;
		break;

	case 1:
		buffers[0] = m_samples_auxB_left;
		buffers[1] = m_samples_auxB_right;
		buffers[2] = m_samples_auxB_surround;
		break;
	}

	// First, we need to send the contents of our AUX buffers to the CPU.
	if (write_addr)
	{
		int* ptr = (int*)HLEMemory_Get_Pointer(write_addr);
		for (u32 i = 0; i < 3; ++i)
			for (u32 j = 0; j < 5 * 32; ++j)
				*ptr++ = Common::swap32(buffers[i][j]);
	}

	// Then, we read the new temp from the CPU and add to our current
	// temp.
	int* ptr = (int*)HLEMemory_Get_Pointer(read_addr);
	for (u32 i = 0; i < 5 * 32; ++i)
		m_samples_left[i] += (int)Common::swap32(*ptr++);
	for (u32 i = 0; i < 5 * 32; ++i)
		m_samples_right[i] += (int)Common::swap32(*ptr++);
	for (u32 i = 0; i < 5 * 32; ++i)
		m_samples_surround[i] += (int)Common::swap32(*ptr++);
}
Пример #14
0
void AXWiiUCode::AddSubToLR(u32 val_addr)
{
	int* ptr = (int*)HLEMemory_Get_Pointer(val_addr);
	for (int i = 0; i < 32 * 3; ++i)
	{
		int val = (int)Common::swap32(*ptr++);
		m_samples_left[i] += val;
	}
	for (int i = 0; i < 32 * 3; ++i)
	{
		int val = (int)Common::swap32(*ptr++);
		m_samples_right[i] -= val;
	}
}
Пример #15
0
void CUCode_AX::MixAUXBLR(u32 ul_addr, u32 dl_addr)
{
	// Upload AUXB L/R
	int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr);
	for (u32 i = 0; i < 5 * 32; ++i)
		*ptr++ = Common::swap32(m_samples_auxB_left[i]);
	for (u32 i = 0; i < 5 * 32; ++i)
		*ptr++ = Common::swap32(m_samples_auxB_right[i]);

	// Mix AUXB L/R to MAIN L/R, and replace AUXB L/R
	ptr = (int*)HLEMemory_Get_Pointer(dl_addr);
	for (u32 i = 0; i < 5 * 32; ++i)
	{
		int samp = Common::swap32(*ptr++);
		m_samples_auxB_left[i] = samp;
		m_samples_left[i] += samp;
	}
	for (u32 i = 0; i < 5 * 32; ++i)
	{
		int samp = Common::swap32(*ptr++);
		m_samples_auxB_right[i] = samp;
		m_samples_right[i] += samp;
	}
}
Пример #16
0
void AXWiiUCode::OutputWMSamples(u32* addresses)
{
  int* buffers[] = {m_samples_wm0, m_samples_wm1, m_samples_wm2, m_samples_wm3};

  for (u32 i = 0; i < 4; ++i)
  {
    int* in = buffers[i];
    u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
    for (u32 j = 0; j < 3 * 6; ++j)
    {
      int sample = MathUtil::Clamp(in[j], -32767, 32767);
      out[j] = Common::swap16((u16)sample);
    }
  }
}
Пример #17
0
bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates,
                                        u32* updates_addr)
{
	u16* pb_mem = (u16*)&pb;

	if (!m_old_axwii)
		return false;

	// Copy the num_updates field.
	memcpy(num_updates, pb_mem + 41, 6);

	// Get the address of the updates data
	u16 addr_hi = pb_mem[44];
	u16 addr_lo = pb_mem[45];
	u32 addr = HILO_TO_32(addr);
	u16* ptr = (u16*)HLEMemory_Get_Pointer(addr);

	*updates_addr = addr;

	// Copy the updates data and change the offset to match a PB without
	// updates data.
	u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2];
	for (u32 i = 0; i < updates_count; ++i)
	{
		u16 update_off = Common::swap16(ptr[2 * i]);
		u16 update_val = Common::swap16(ptr[2 * i + 1]);

		if (update_off > 45)
			update_off -= 5;

		updates[2 * i] = update_off;
		updates[2 * i + 1] = update_val;
	}

	// Remove the updates data from the PB
	memmove(pb_mem + 41, pb_mem + 46, sizeof (pb) - 2 * 46);

	return true;
}
Пример #18
0
void CUCode_AXWii::OutputWMSamples(u32* addresses)
{
	int* buffers[] = {
		m_samples_wm0,
		m_samples_wm1,
		m_samples_wm2,
		m_samples_wm3
	};

	for (u32 i = 0; i < 4; ++i)
	{
		int* in = buffers[i];
		u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]);
		for (u32 j = 0; j < 3 * 6; ++j)
		{
			int sample = in[j];
			if (sample < -32767) sample = -32767;
			if (sample > 32767) sample = 32767;
			out[j] = Common::swap16((u16)sample);
		}
	}
}
Пример #19
0
void CUCode_AX::DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb)
{
	int* buffers_main[3] = { m_samples_left, m_samples_right, m_samples_surround };
	int* buffers_auxa[3] = { m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround };
	int* buffers_auxb[3] = { m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround };
	int** buffers[3] = { buffers_main, buffers_auxa, buffers_auxb };
	u16 volumes[3] = { vol_main, vol_auxa, vol_auxb };

	for (u32 i = 0; i < 3; ++i)
	{
		int* ptr = (int*)HLEMemory_Get_Pointer(addr);
		u16 volume = volumes[i];
		for (u32 j = 0; j < 3; ++j)
		{
			int* buffer = buffers[i][j];
			for (u32 k = 0; k < 5 * 32; ++k)
			{
				s64 sample = (s64)(s32)Common::swap32(*ptr++);
				sample *= volume;
				buffer[k] += (s32)(sample >> 15);
			}
		}
	}
}
Пример #20
0
void IUCode::PrepareBootUCode(u32 mail)
{
	switch (m_NextUCode_steps)
	{
	case 0: m_NextUCode.mram_dest_addr	= mail;				break;
	case 1: m_NextUCode.mram_size		= mail & 0xffff;	break;
	case 2: m_NextUCode.mram_dram_addr	= mail & 0xffff;	break;
	case 3: m_NextUCode.iram_mram_addr	= mail;				break;
	case 4: m_NextUCode.iram_size		= mail & 0xffff;	break;
	case 5: m_NextUCode.iram_dest		= mail & 0xffff;	break;
	case 6: m_NextUCode.iram_startpc	= mail & 0xffff;	break;
	case 7: m_NextUCode.dram_mram_addr	= mail;				break;
	case 8: m_NextUCode.dram_size		= mail & 0xffff;	break;
	case 9: m_NextUCode.dram_dest		= mail & 0xffff;	break;
	}
	m_NextUCode_steps++;

	if (m_NextUCode_steps == 10)
	{
		m_NextUCode_steps = 0;
		m_NeedsResumeMail = true;
		m_UploadSetupInProgress = false;

		u32 ector_crc = HashEctor(
			(u8*)HLEMemory_Get_Pointer(m_NextUCode.iram_mram_addr),
			m_NextUCode.iram_size);

#if defined(_DEBUG) || defined(DEBUGFAST)
		char binFile[MAX_PATH];
		sprintf(binFile, "%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc);

		File::IOFile pFile(binFile, "wb");
		if (pFile)
		pFile.WriteArray((u8*)Memory::GetPointer(m_NextUCode.iram_mram_addr), m_NextUCode.iram_size);
#endif

		DEBUG_LOG(DSPHLE, "PrepareBootUCode 0x%08x", ector_crc);
		DEBUG_LOG(DSPHLE, "DRAM -> MRAM: src %04x dst %08x size %04x",
			m_NextUCode.mram_dram_addr, m_NextUCode.mram_dest_addr,
			m_NextUCode.mram_size);
		DEBUG_LOG(DSPHLE, "MRAM -> IRAM: src %08x dst %04x size %04x startpc %04x",
			m_NextUCode.iram_mram_addr, m_NextUCode.iram_dest,
			m_NextUCode.iram_size, m_NextUCode.iram_startpc);
		DEBUG_LOG(DSPHLE, "MRAM -> DRAM: src %08x dst %04x size %04x",
			m_NextUCode.dram_mram_addr, m_NextUCode.dram_dest,
			m_NextUCode.dram_size);

		if (m_NextUCode.mram_size)
		{
			WARN_LOG(DSPHLE,
				"Trying to boot new ucode with dram download - not implemented");
		}
		if (m_NextUCode.dram_size)
		{
			WARN_LOG(DSPHLE,
				"Trying to boot new ucode with dram upload - not implemented");
		}

		m_DSPHLE->SwapUCode(ector_crc);
	}
}
Пример #21
0
void UCodeInterface::PrepareBootUCode(u32 mail)
{
    switch (m_next_ucode_steps)
    {
    case 0:
        m_next_ucode.mram_dest_addr = mail;
        break;
    case 1:
        m_next_ucode.mram_size      = mail & 0xffff;
        break;
    case 2:
        m_next_ucode.mram_dram_addr = mail & 0xffff;
        break;
    case 3:
        m_next_ucode.iram_mram_addr = mail;
        break;
    case 4:
        m_next_ucode.iram_size      = mail & 0xffff;
        break;
    case 5:
        m_next_ucode.iram_dest      = mail & 0xffff;
        break;
    case 6:
        m_next_ucode.iram_startpc   = mail & 0xffff;
        break;
    case 7:
        m_next_ucode.dram_mram_addr = mail;
        break;
    case 8:
        m_next_ucode.dram_size      = mail & 0xffff;
        break;
    case 9:
        m_next_ucode.dram_dest      = mail & 0xffff;
        break;
    }
    m_next_ucode_steps++;

    if (m_next_ucode_steps == 10)
    {
        m_next_ucode_steps = 0;
        m_needs_resume_mail = true;
        m_upload_setup_in_progress = false;

        u32 ector_crc = HashEctor(
                            (u8*)HLEMemory_Get_Pointer(m_next_ucode.iram_mram_addr),
                            m_next_ucode.iram_size);

#if defined(_DEBUG) || defined(DEBUGFAST)
        std::string ucode_dump_path = StringFromFormat(
                                          "%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc);

        File::IOFile fp(ucode_dump_path, "wb");
        if (fp)
        {
            fp.WriteArray((u8*)Memory::GetPointer(m_next_ucode.iram_mram_addr),
                          m_next_ucode.iram_size);
        }
#endif

        DEBUG_LOG(DSPHLE, "PrepareBootUCode 0x%08x", ector_crc);
        DEBUG_LOG(DSPHLE, "DRAM -> MRAM: src %04x dst %08x size %04x",
                  m_next_ucode.mram_dram_addr, m_next_ucode.mram_dest_addr,
                  m_next_ucode.mram_size);
        DEBUG_LOG(DSPHLE, "MRAM -> IRAM: src %08x dst %04x size %04x startpc %04x",
                  m_next_ucode.iram_mram_addr, m_next_ucode.iram_dest,
                  m_next_ucode.iram_size, m_next_ucode.iram_startpc);
        DEBUG_LOG(DSPHLE, "MRAM -> DRAM: src %08x dst %04x size %04x",
                  m_next_ucode.dram_mram_addr, m_next_ucode.dram_dest,
                  m_next_ucode.dram_size);

        if (m_next_ucode.mram_size)
        {
            WARN_LOG(DSPHLE,
                     "Trying to boot new ucode with dram download - not implemented");
        }
        if (m_next_ucode.dram_size)
        {
            WARN_LOG(DSPHLE,
                     "Trying to boot new ucode with dram upload - not implemented");
        }

        m_dsphle->SwapUCode(ector_crc);
    }
}