/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/cpu/ppc/ppc_context.h" #include #include #include "xenia/base/assert.h" #include "xenia/base/string_util.h" namespace xe { namespace cpu { namespace ppc { uint64_t PPCContext::cr() const { uint64_t final_bits = 0; for (int i = 0; i < 8; ++i) { uint32_t crf = *(&cr0.value + i); uint64_t bits = (crf & 0x1) << (4 * (7 - i) + 3) | ((crf >> 8) & 0x1) << (4 * (7 - i) + 2) | ((crf >> 16) & 0x1) << (4 * (7 - i) + 1) | ((crf >> 24) & 0x1) << (4 * (7 - i) + 0); final_bits |= bits << (i * 4); } return final_bits; } void PPCContext::set_cr(uint64_t value) { assert_always("not yet implemented"); } std::string PPCContext::GetRegisterName(PPCRegister reg) { switch (reg) { case PPCRegister::kLR: return "lr"; case PPCRegister::kCTR: return "ctr"; case PPCRegister::kXER: return "xer"; case PPCRegister::kFPSCR: return "fpscr"; case PPCRegister::kVSCR: return "vscr"; case PPCRegister::kCR: return "cr"; default: if (static_cast(reg) >= static_cast(PPCRegister::kR0) && static_cast(reg) <= static_cast(PPCRegister::kR31)) { return std::string("r") + std::to_string(static_cast(reg) - static_cast(PPCRegister::kR0)); } else if (static_cast(reg) >= static_cast(PPCRegister::kFR0) && static_cast(reg) <= static_cast(PPCRegister::kFR31)) { return std::string("fr") + std::to_string(static_cast(reg) - static_cast(PPCRegister::kFR0)); } else if (static_cast(reg) >= static_cast(PPCRegister::kVR0) && static_cast(reg) <= static_cast(PPCRegister::kVR128)) { return std::string("vr") + std::to_string(static_cast(reg) - static_cast(PPCRegister::kVR0)); } else { assert_unhandled_case(reg); return "?"; } } } std::string PPCContext::GetStringFromValue(PPCRegister reg) const { switch (reg) { case PPCRegister::kLR: return string_util::to_hex_string(lr); case PPCRegister::kCTR: return string_util::to_hex_string(ctr); case PPCRegister::kXER: // return Int64ToHex(xer_ca); return "?"; case PPCRegister::kFPSCR: // return Int64ToHex(fpscr); return "?"; case PPCRegister::kVSCR: // return Int64ToHex(vscr_sat); return "?"; case PPCRegister::kCR: // return Int64ToHex(cr); return "?"; default: if (static_cast(reg) >= static_cast(PPCRegister::kR0) && static_cast(reg) <= static_cast(PPCRegister::kR31)) { return string_util::to_hex_string( r[static_cast(reg) - static_cast(PPCRegister::kR0)]); } else if (static_cast(reg) >= static_cast(PPCRegister::kFR0) && static_cast(reg) <= static_cast(PPCRegister::kFR31)) { return string_util::to_hex_string( f[static_cast(reg) - static_cast(PPCRegister::kFR0)]); } else if (static_cast(reg) >= static_cast(PPCRegister::kVR0) && static_cast(reg) <= static_cast(PPCRegister::kVR128)) { return string_util::to_hex_string( v[static_cast(reg) - static_cast(PPCRegister::kVR0)]); } else { assert_unhandled_case(reg); return ""; } } } void PPCContext::SetValueFromString(PPCRegister reg, std::string value) { // TODO(benvanik): set value from string to replace SetRegFromString? assert_always(false); } void PPCContext::SetRegFromString(const char* name, const char* value) { int n; if (sscanf(name, "r%d", &n) == 1) { this->r[n] = string_util::from_string(value); } else if (sscanf(name, "f%d", &n) == 1) { this->f[n] = string_util::from_string(value); } else if (sscanf(name, "v%d", &n) == 1) { this->v[n] = string_util::from_string(value); } else if (std::strcmp(name, "cr") == 0) { this->set_cr(string_util::from_string(value)); } else { printf("Unrecognized register name: %s\n", name); } } bool PPCContext::CompareRegWithString(const char* name, const char* value, char* out_value, size_t out_value_size) const { int n; if (sscanf(name, "r%d", &n) == 1) { uint64_t expected = string_util::from_string(value); if (this->r[n] != expected) { std::snprintf(out_value, out_value_size, "%016" PRIX64, this->r[n]); return false; } return true; } else if (sscanf(name, "f%d", &n) == 1) { double expected = string_util::from_string(value); // TODO(benvanik): epsilon if (this->f[n] != expected) { std::snprintf(out_value, out_value_size, "%f", this->f[n]); return false; } return true; } else if (sscanf(name, "v%d", &n) == 1) { vec128_t expected = string_util::from_string(value); if (this->v[n] != expected) { std::snprintf(out_value, out_value_size, "[%.8X, %.8X, %.8X, %.8X]", this->v[n].i32[0], this->v[n].i32[1], this->v[n].i32[2], this->v[n].i32[3]); return false; } return true; } else if (std::strcmp(name, "cr") == 0) { uint64_t actual = this->cr(); uint64_t expected = string_util::from_string(value); if (actual != expected) { std::snprintf(out_value, out_value_size, "%016" PRIX64, actual); return false; } return true; } else { assert_always("Unrecognized register name: %s\n", name); return false; } } } // namespace ppc } // namespace cpu } // namespace xe