diff --git a/InstructionSets/PowerPC/Instruction.hpp b/InstructionSets/PowerPC/Instruction.hpp index 0ba3038c7..d970324c2 100644 --- a/InstructionSets/PowerPC/Instruction.hpp +++ b/InstructionSets/PowerPC/Instruction.hpp @@ -25,7 +25,52 @@ enum class Operation: uint8_t { // 32- and 64-bit PowerPC instructions. addx, addcx, addex, addi, addic, addic_, addis, addmex, addzex, andx, - andcx, andi_, andis_, bx, bcx, bcctrx, bclrx, cmp, cmpi, cmpl, cmpli, + andcx, andi_, andis_, + + /// Branch unconditional. + /// + /// Use li() to get the included immediate value. + /// + /// Use aa() to determine whether it's a relative (aa() = 0) or absolute (aa() != 0) address. + /// Also check lk() to determine whether to update the link register. + /// + /// Synonyms include: + /// * b (relative, no link) [though assemblers might encode as a bcx]; + /// * bl (relative, link); + /// * ba (absolute, no link); + /// * bla (absolute, link). + bx, + + /// Branch conditional. + /// + /// lk() determines whether to update the link register. + /// bd() supplies a relative displacment. + /// bi() specifies which CR bit to use as a condition. + /// bo() provides other branch options: + /// 0000y => decrement count register, branch if new value != 0 && !condition. + /// 0001y => decrement count register, branch if new value == 0 && !condition. + /// 001zy => branch if !condition + /// 0100y => decrement count register, branch if new value != 0 && condition. + /// 0101y => decrement count register, branch if new value == 0 && condition. + /// 011zy => branch if condition. + /// 1z00y => decrement count register, branch if new value != 0. + /// 1z01y => decrement count register, branch if new value == 0. + /// 1z1zz => branch always. + /// (z should be 0 to create a valid field; y can be any value) + /// + /// Synonyms incude: + /// * b (relative, no link) [though assemblers might encode as a bx]. + bcx, + + /// Branch conditional to count register. + /// + /// bi(), bo() and lk() are as per bcx. + /// + /// On the MPC601, anything that decrements the count register will use the non-decremented + /// version as the branch target. Other processors will use the decremented version. + bcctrx, + + bclrx, cmp, cmpi, cmpl, cmpli, cntlzwx, crand, crandc, creqv, crnand, crnor, cror, crorc, crxor, dcbf, dcbst, dcbt, dcbtst, dcbz, divwx, divwux, eciwx, ecowx, eieio, eqvx, extsbx, extshx, fabsx, faddx, faddsx, fcmpo, fcmpu, fctiwx, fctiwzx, diff --git a/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm b/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm index e47b9f8a0..c40f99609 100644 --- a/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm +++ b/OSBindings/Mac/Clock SignalTests/DingusdevPowerPCTests.mm @@ -53,12 +53,23 @@ namespace { switch(instruction.operation) { default: -// NSAssert(FALSE, @"Didn't handle %@", line); + NSAssert(FALSE, @"Didn't handle %@", line); break; - case Operation::bx: { - const uint32_t destination = uint32_t(std::strtol([columns[3] UTF8String], 0, 16)); + case Operation::bcx: { + switch(instruction.bo()) { + case 0x14: case 0x15: XCTAssertEqualObjects(operation, @"b"); break; + default: + NSLog(@"No opcode tested for bcx with bo %02x", instruction.bo()); + break; + } + const uint32_t destination = uint32_t(std::strtol([columns[3] UTF8String], 0, 16)); + const uint32_t decoded_destination = instruction.bd() + address; + XCTAssertEqual(decoded_destination, destination); + } break; + + case Operation::bx: { switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) { case 0: XCTAssertEqualObjects(operation, @"b"); break; case 1: XCTAssertEqualObjects(operation, @"bl"); break; @@ -66,6 +77,7 @@ namespace { case 3: XCTAssertEqualObjects(operation, @"bla"); break; } + const uint32_t destination = uint32_t(std::strtol([columns[3] UTF8String], 0, 16)); const uint32_t decoded_destination = instruction.li() + (instruction.aa() ? 0 : address); XCTAssertEqual(decoded_destination, destination);