bool runTests(const std::string &path) { uint32_t testsFailed = 0, testsPassed = 0; uint32_t baseAddress = mem::MEM2Base; Instruction bclr = encodeInstruction(InstructionID::bclr); bclr.bo = 0x1f; mem::write(baseAddress + 4, bclr.value); fs::FileSystem filesystem; fs::FolderEntry entry; fs::HostPath base = path; filesystem.mountHostFolder("/tests", base, fs::Permissions::Read); auto folder = filesystem.openFolder("/tests"); while (folder->read(entry)) { std::ifstream file(base.join(entry.name).path(), std::ifstream::in | std::ifstream::binary); cereal::BinaryInputArchive cerealInput(file); TestFile testFile; // Parse test file with cereal testFile.name = entry.name; cerealInput(testFile); // Run tests gLog->info("Checking {}", testFile.name); for (auto &test : testFile.tests) { bool failed = false; if (!TEST_FMADDSUB) { auto data = espresso::decodeInstruction(test.instr); switch (data->id) { case InstructionID::fmadd: case InstructionID::fmadds: case InstructionID::fmsub: case InstructionID::fmsubs: case InstructionID::fnmadd: case InstructionID::fnmadds: case InstructionID::fnmsub: case InstructionID::fnmsubs: failed = true; break; } if (failed) { continue; } } // Setup core state from test input cpu::CoreRegs *state = cpu::this_core::state(); memset(state, 0, sizeof(cpu::CoreRegs)); state->cia = 0; state->nia = baseAddress; state->xer = test.input.xer; state->cr = test.input.cr; state->fpscr = test.input.fpscr; state->ctr = test.input.ctr; for (auto i = 0; i < 4; ++i) { state->gpr[i + 3] = test.input.gpr[i]; state->fpr[i + 1].paired0 = test.input.fr[i]; } // Execute test mem::write(baseAddress, test.instr.value); cpu::jit::clearCache(); cpu::this_core::executeSub(); // Check XER (all bits) if (state->xer.value != test.output.xer.value) { gLog->error("Test failed, xer expected {:08X} found {:08X}", test.output.xer.value, state->xer.value); failed = true; } // Check Condition Register (all bits) if (state->cr.value != test.output.cr.value) { gLog->error("Test failed, cr expected {:08X} found {:08X}", test.output.cr.value, state->cr.value); failed = true; } // Check FPSCR if (TEST_FPSCR) { if (!TEST_FPSCR_FR) { state->fpscr.fr = 0; test.output.fpscr.fr = 0; } if (!TEST_FPSCR_UX) { state->fpscr.ux = 0; test.output.fpscr.ux = 0; } auto state_fpscr = state->fpscr.value; auto test_fpscr = test.output.fpscr.value; if (state_fpscr != test_fpscr) { gLog->error("Test failed, fpscr {:08X} found {:08X}", test.output.fpscr.value, state->fpscr.value); compareFPSCR(test.input.fpscr, state->fpscr, test.output.fpscr); failed = true; } } // Check CTR if (state->ctr != test.output.ctr) { gLog->error("Test failed, ctr expected {:08X} found {:08X}", test.output.ctr, state->ctr); failed = true; } // Check all GPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::GPR_BASE; auto value = state->gpr[reg]; auto expected = test.output.gpr[i]; if (value != expected) { gLog->error("Test failed, r{} expected {:08X} found {:08X}", reg, expected, value); failed = true; } } // Check all FPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::FPR_BASE; auto value = state->fpr[reg].value; auto expected = test.output.fr[i]; if (!is_nan(value) && !is_nan(expected) && !is_infinity(value) && !is_infinity(expected)) { double dval = value / expected; if (dval < 0.999 || dval > 1.001) { gLog->error("Test failed, f{} expected {:16f} found {:16f}", reg, expected, value); failed = true; } } else { if (is_nan(value) && is_nan(expected)) { auto bits = get_float_bits(value); bits.sign = get_float_bits(expected).sign; value = bits.v; } if (bit_cast<uint64_t>(value) != bit_cast<uint64_t>(expected)) { gLog->error("Test failed, f{} expected {:16X} found {:16X}", reg, bit_cast<uint64_t>(expected), bit_cast<uint64_t>(value)); failed = true; } } } if (failed) { Disassembly dis; // Print disassembly disassemble(test.instr, dis, baseAddress); gLog->debug(dis.text); // Print all test fields gLog->debug("{:08x} Input Hardware Interp", test.instr.value); for (auto field : dis.instruction->read) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->write) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->flags) { printTestField(field, test.instr, &test.input, &test.output, state); } gLog->debug(""); ++testsFailed; } else { ++testsPassed; } } } gLog->info("Passed: {}, Failed: {}", testsPassed, testsFailed); return true; }
int runTests(const std::string &path) { uint32_t testsFailed = 0, testsPassed = 0; auto baseAddress = cpu::VirtualAddress { 0x02000000u }; auto basePhysicalAddress = cpu::PhysicalAddress { 0x50000000u }; auto codeSize = 2048u; cpu::allocateVirtualAddress(baseAddress, codeSize); cpu::mapMemory(baseAddress, basePhysicalAddress, codeSize, cpu::MapPermission::ReadWrite); Instruction bclr = encodeInstruction(InstructionID::bclr); bclr.bo = 0x1f; mem::write(baseAddress.getAddress() + 4, bclr.value); auto ec = std::error_code { }; for (auto itr = std::filesystem::directory_iterator { "/tests", ec }; itr != end(itr); ++itr) { std::ifstream file(itr->path().string(), std::ifstream::in | std::ifstream::binary); cereal::BinaryInputArchive cerealInput(file); TestFile testFile; // Parse test file with cereal testFile.name = itr->path().filename().string(); cerealInput(testFile); // Run tests for (auto &test : testFile.tests) { bool failed = false; if (!TEST_FMADDSUB) { auto data = espresso::decodeInstruction(test.instr); switch (data->id) { case InstructionID::fmadd: case InstructionID::fmadds: case InstructionID::fmsub: case InstructionID::fmsubs: case InstructionID::fnmadd: case InstructionID::fnmadds: case InstructionID::fnmsub: case InstructionID::fnmsubs: failed = true; break; } if (failed) { continue; } } // Setup core state from test input cpu::CoreRegs *state = cpu::this_core::state(); memset(state, 0, sizeof(cpu::CoreRegs)); state->cia = 0; state->nia = baseAddress.getAddress(); state->xer = test.input.xer; state->cr = test.input.cr; state->fpscr = test.input.fpscr; state->ctr = test.input.ctr; for (auto i = 0; i < 4; ++i) { state->gpr[i + 3] = test.input.gpr[i]; state->fpr[i + 1].paired0 = test.input.fr[i]; } // Execute test mem::write(baseAddress.getAddress(), test.instr.value); cpu::clearInstructionCache(); cpu::this_core::executeSub(); // Check XER (all bits) if (state->xer.value != test.output.xer.value) { gLog->error("Test failed, xer expected {:08X} found {:08X}", test.output.xer.value, state->xer.value); failed = true; } // Check Condition Register (all bits) if (state->cr.value != test.output.cr.value) { gLog->error("Test failed, cr expected {:08X} found {:08X}", test.output.cr.value, state->cr.value); failed = true; } // Check FPSCR if (TEST_FPSCR) { if (!TEST_FPSCR_FR) { state->fpscr.fr = 0; test.output.fpscr.fr = 0; } if (!TEST_FPSCR_UX) { state->fpscr.ux = 0; test.output.fpscr.ux = 0; } auto state_fpscr = state->fpscr.value; auto test_fpscr = test.output.fpscr.value; if (state_fpscr != test_fpscr) { gLog->error("Test failed, fpscr {:08X} found {:08X}", test.output.fpscr.value, state->fpscr.value); compareFPSCR(test.input.fpscr, state->fpscr, test.output.fpscr); failed = true; } } // Check CTR if (state->ctr != test.output.ctr) { gLog->error("Test failed, ctr expected {:08X} found {:08X}", test.output.ctr, state->ctr); failed = true; } // Check all GPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::GPR_BASE; auto value = state->gpr[reg]; auto expected = test.output.gpr[i]; if (value != expected) { gLog->error("Test failed, r{} expected {:08X} found {:08X}", reg, expected, value); failed = true; } } // Check all FPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::FPR_BASE; auto value = state->fpr[reg].value; auto expected = test.output.fr[i]; if (!is_nan(value) && !is_nan(expected) && !is_infinity(value) && !is_infinity(expected)) { double dval = value / expected; if (dval < 0.999 || dval > 1.001) { gLog->error("Test failed, f{} expected {:16f} found {:16f}", reg, expected, value); failed = true; } } else { if (is_nan(value) && is_nan(expected)) { auto bits = get_float_bits(value); bits.sign = get_float_bits(expected).sign; value = bits.v; } if (bit_cast<uint64_t>(value) != bit_cast<uint64_t>(expected)) { gLog->error("Test failed, f{} expected {:16X} found {:16X}", reg, bit_cast<uint64_t>(expected), bit_cast<uint64_t>(value)); failed = true; } } } if (failed) { Disassembly dis; // Print disassembly disassemble(test.instr, dis, baseAddress.getAddress()); gLog->debug(dis.text); // Print all test fields gLog->debug("{:08x} Input Hardware Interp", test.instr.value); for (auto field : dis.instruction->read) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->write) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->flags) { printTestField(field, test.instr, &test.input, &test.output, state); } gLog->debug(""); ++testsFailed; } else { ++testsPassed; } } } if (testsFailed) { gLog->error("Failed {} of {} tests.", testsFailed, testsFailed + testsPassed); } return testsFailed; }