1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-18 01:07:58 +00:00

Match majority of branch tests.

This commit is contained in:
Thomas Harte 2022-03-25 08:41:57 -04:00
parent 7d4fe55d63
commit 1a5d3bb69c
2 changed files with 96 additions and 16 deletions

View File

@ -37,7 +37,7 @@ enum class Condition: uint32_t {
// CRs27 fill out the condition register. // CRs27 fill out the condition register.
}; };
enum class BranchOptions: uint32_t { enum class BranchOption: uint32_t {
// Naming convention: // Naming convention:
// //
// Dec_ prefix => decrement the CTR; // Dec_ prefix => decrement the CTR;
@ -239,8 +239,8 @@ struct Instruction {
/// Branch conditional options as per PowerPC spec, i.e. options + branch-prediction flag. /// Branch conditional options as per PowerPC spec, i.e. options + branch-prediction flag.
uint32_t bo() const { return (opcode >> 21) & 0x1f; } uint32_t bo() const { return (opcode >> 21) & 0x1f; }
/// Just the branch options, with the branch prediction flag severed. /// Just the branch options, with the branch prediction flag severed.
BranchOptions branch_options() const { BranchOption branch_options() const {
return BranchOptions((opcode >> 22) & 0xf); return BranchOption((opcode >> 22) & 0xf);
} }
/// Just the branch-prediction hint; @c 0 => expect untaken; @c non-0 => expect take. /// Just the branch-prediction hint; @c 0 => expect untaken; @c non-0 => expect take.
uint32_t branch_prediction_hint() const { uint32_t branch_prediction_hint() const {

View File

@ -53,13 +53,18 @@ using namespace InstructionSet::PowerPC;
NSAssert(FALSE, @"Didn't handle %@", line); NSAssert(FALSE, @"Didn't handle %@", line);
break; break;
case Operation::bcx:
case Operation::bclrx: case Operation::bclrx:
case Operation::bcctrx: { case Operation::bcctrx: {
NSString *baseOperation = nil; NSString *baseOperation = nil;
BOOL addConditionToOperand = NO;
switch(instruction.branch_options()) { switch(instruction.branch_options()) {
case BranchOptions::Always: baseOperation = @"b"; break; case BranchOption::Always: baseOperation = @"b"; break;
case BranchOptions::Clear: case BranchOption::Dec_Zero: baseOperation = @"bdz"; break;
case BranchOption::Dec_NotZero: baseOperation = @"bdnz"; break;
case BranchOption::Clear:
switch(Condition(instruction.bi() & 3)) { switch(Condition(instruction.bi() & 3)) {
default: break; default: break;
case Condition::Negative: baseOperation = @"bge"; break; case Condition::Negative: baseOperation = @"bge"; break;
@ -70,7 +75,16 @@ using namespace InstructionSet::PowerPC;
break; break;
} }
break; break;
case BranchOptions::Set: case BranchOption::Dec_ZeroAndClear:
baseOperation = @"bdzf";
addConditionToOperand = YES;
break;
case BranchOption::Dec_NotZeroAndClear:
baseOperation = @"bdnzf";
addConditionToOperand = YES;
break;
case BranchOption::Set:
switch(Condition(instruction.bi() & 3)) { switch(Condition(instruction.bi() & 3)) {
default: break; default: break;
case Condition::Negative: baseOperation = @"blt"; break; case Condition::Negative: baseOperation = @"blt"; break;
@ -81,13 +95,39 @@ using namespace InstructionSet::PowerPC;
break; break;
} }
break; break;
case BranchOption::Dec_ZeroAndSet:
baseOperation = @"bdzt";
addConditionToOperand = YES;
break;
case BranchOption::Dec_NotZeroAndSet:
baseOperation = @"bdnzt";
addConditionToOperand = YES;
break;
default: break; default: break;
} }
if(instruction.operation == Operation::bcctrx) { switch(instruction.operation) {
baseOperation = [baseOperation stringByAppendingString:@"ctr"]; case Operation::bcctrx:
} else { baseOperation = [baseOperation stringByAppendingString:@"ctr"];
baseOperation = [baseOperation stringByAppendingString:@"lr"]; break;
case Operation::bclrx:
baseOperation = [baseOperation stringByAppendingString:@"lr"];
break;
case Operation::bcx: {
// if(instruction.aa()) {
// baseOperation = [baseOperation stringByAppendingString:@"a"];
// } else {
//
// }
const uint32_t destination = uint32_t(std::strtol([[columns lastObject] UTF8String], 0, 16));
const uint32_t decoded_destination = instruction.bd() + address;
XCTAssertEqual(decoded_destination, destination);
} break;
default: break;
} }
if(!baseOperation) { if(!baseOperation) {
@ -103,25 +143,65 @@ using namespace InstructionSet::PowerPC;
} }
if(instruction.bi() & ~3) { if(instruction.bi() & ~3) {
NSString *const expectedCR = [NSString stringWithFormat:@"cr%d", instruction.bi() >> 2]; NSString *expectedCR;
if(addConditionToOperand) {
NSString *suffix;
switch(Condition(instruction.bi() & 3)) {
default: break;
case Condition::Negative: suffix = @"lt"; break;
case Condition::Positive: suffix = @"gt"; break;
case Condition::Zero: suffix = @"eq"; break;
case Condition::SummaryOverflow: suffix = @"so"; break;
}
expectedCR = [NSString stringWithFormat:@"4*cr%d+%@", instruction.bi() >> 2, suffix];
} else {
expectedCR = [NSString stringWithFormat:@"cr%d", instruction.bi() >> 2];
}
XCTAssertEqualObjects(columns[3], expectedCR); XCTAssertEqualObjects(columns[3], expectedCR);
} }
} break; } break;
case Operation::bcx: { /* case Operation::bcx: {
NSString *expectedOperation;
switch(instruction.branch_options()) { switch(instruction.branch_options()) {
case BranchOptions::Always: case BranchOption::Always: expectedOperation = @"b"; break;
XCTAssertEqualObjects(operation, @"b"); case BranchOption::Set:
switch(Condition(instruction.bi() & 3)) {
default: break;
case Condition::Negative: expectedOperation = @"blt"; break;
case Condition::Positive: expectedOperation = @"bgt"; break;
case Condition::Zero: expectedOperation = @"beq"; break;
case Condition::SummaryOverflow: expectedOperation = @"bso"; break;
}
break;
case BranchOption::Clear:
switch(Condition(instruction.bi() & 3)) {
default: break;
case Condition::Negative: expectedOperation = @"bge"; break;
case Condition::Positive: expectedOperation = @"ble"; break;
case Condition::Zero: expectedOperation = @"bne"; break;
case Condition::SummaryOverflow: expectedOperation = @"bns"; break;
}
break; break;
default: default:
NSLog(@"No opcode tested for bcx with bo %02x", instruction.bo()); NSLog(@"No opcode tested for bcx with bo %02x [%@]", instruction.bo(), line);
break; break;
} }
if(instruction.lk()) {
expectedOperation = [expectedOperation stringByAppendingString:@"l"];
}
if(instruction.branch_prediction_hint()) {
expectedOperation = [expectedOperation stringByAppendingString:@"+"];
}
XCTAssertEqualObjects(operation, expectedOperation);
const uint32_t destination = uint32_t(std::strtol([columns[3] UTF8String], 0, 16)); const uint32_t destination = uint32_t(std::strtol([columns[3] UTF8String], 0, 16));
const uint32_t decoded_destination = instruction.bd() + address; const uint32_t decoded_destination = instruction.bd() + address;
XCTAssertEqual(decoded_destination, destination); XCTAssertEqual(decoded_destination, destination);
} break; } break;*/
case Operation::bx: { case Operation::bx: {
switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) { switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) {