2022-03-18 21:24:12 +00:00
|
|
|
|
//
|
|
|
|
|
// DingusdevPowerPCTests.mm
|
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
|
|
|
|
// Created by Thomas Harte on 18/03/2022.
|
|
|
|
|
// Copyright 2022 Thomas Harte. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
|
|
#include "../../../InstructionSets/PowerPC/Decoder.hpp"
|
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
using namespace InstructionSet::PowerPC;
|
2022-03-18 21:24:12 +00:00
|
|
|
|
|
2022-04-01 21:22:32 +00:00
|
|
|
|
@interface NSString (HexConversion)
|
|
|
|
|
|
|
|
|
|
- (long int)hexInt;
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSString (HexConversion)
|
|
|
|
|
|
|
|
|
|
- (long int)hexInt {
|
|
|
|
|
return strtol([self UTF8String], NULL, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2022-03-18 21:24:12 +00:00
|
|
|
|
@interface DingusdevPowerPCTests : XCTestCase
|
|
|
|
|
@end
|
|
|
|
|
|
2022-03-27 12:47:01 +00:00
|
|
|
|
namespace {
|
|
|
|
|
|
2022-04-01 21:22:32 +00:00
|
|
|
|
enum class NamingConvention {
|
|
|
|
|
None = 0,
|
|
|
|
|
ApplyO = 1,
|
|
|
|
|
ApplyE = 2,
|
|
|
|
|
ApplyOE = 3
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Converts any underscores in @c rhs to dots.
|
|
|
|
|
///
|
|
|
|
|
/// If convention != NamingConvention::None, trims the trailing 'x' from the @c rhs and
|
|
|
|
|
/// appends one or more of @c o and @c . depending on the @c oe() and @c rc() flags of @c instruction.
|
|
|
|
|
///
|
|
|
|
|
/// Then compares with the @c lhs.
|
|
|
|
|
void AssertEqualOperationName(NSString *lhs, NSString *rhs, Instruction instruction = Instruction(), NamingConvention convention = NamingConvention::None) {
|
|
|
|
|
rhs = [rhs stringByReplacingOccurrencesOfString:@"_" withString:@"."];
|
|
|
|
|
|
|
|
|
|
if(convention != NamingConvention::None) {
|
|
|
|
|
XCTAssert([rhs characterAtIndex:rhs.length - 1] == 'x');
|
|
|
|
|
rhs = [rhs substringToIndex:rhs.length - 1];
|
|
|
|
|
}
|
|
|
|
|
if(int(convention) & int(NamingConvention::ApplyO) && instruction.oe()) rhs = [rhs stringByAppendingString:@"o"];
|
|
|
|
|
if(int(convention) & int(NamingConvention::ApplyE) && instruction.rc()) rhs = [rhs stringByAppendingString:@"."];
|
2022-03-27 12:47:01 +00:00
|
|
|
|
|
2022-03-29 00:39:52 +00:00
|
|
|
|
XCTAssertEqualObjects(lhs, rhs);
|
|
|
|
|
}
|
2022-04-01 21:22:32 +00:00
|
|
|
|
void AssertEqualOperationNameE(NSString *lhs, NSString *rhs, Instruction instruction) {
|
|
|
|
|
AssertEqualOperationName(lhs, rhs, instruction, NamingConvention::ApplyE);
|
|
|
|
|
}
|
|
|
|
|
void AssertEqualOperationNameOE(NSString *lhs, NSString *rhs, Instruction instruction) {
|
|
|
|
|
AssertEqualOperationName(lhs, rhs, instruction, NamingConvention::ApplyOE);
|
|
|
|
|
}
|
2022-03-29 00:39:52 +00:00
|
|
|
|
|
2022-03-30 21:04:41 +00:00
|
|
|
|
/// Forms the string @c r[reg] and compares it to @c name
|
2022-04-01 21:22:32 +00:00
|
|
|
|
void AssertEqualR(NSString *name, uint32_t reg, bool permitR0 = true) {
|
|
|
|
|
NSString *const regName = (reg || permitR0) ? [NSString stringWithFormat:@"r%d", reg] : @"0";
|
2022-03-30 20:43:09 +00:00
|
|
|
|
XCTAssertEqualObjects(name, regName);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-02 19:40:17 +00:00
|
|
|
|
/// Forms the string @c f[reg] and compares it to @c name
|
|
|
|
|
void AssertEqualFR(NSString *name, uint32_t reg, bool permitR0 = true) {
|
|
|
|
|
NSString *const regName = (reg || permitR0) ? [NSString stringWithFormat:@"f%d", reg] : @"0";
|
|
|
|
|
XCTAssertEqualObjects(name, regName);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 21:04:41 +00:00
|
|
|
|
/// @returns the text name of the condition code @c code
|
2022-03-30 16:40:57 +00:00
|
|
|
|
NSString *condition(uint32_t code) {
|
|
|
|
|
NSString *suffix;
|
|
|
|
|
switch(Condition(code & 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(code & ~3) {
|
|
|
|
|
return [NSString stringWithFormat:@"4*cr%d+%@", code >> 2, suffix];
|
|
|
|
|
} else {
|
|
|
|
|
return suffix;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-03 12:06:59 +00:00
|
|
|
|
NSString *conditionreg(uint32_t code) {
|
|
|
|
|
return [NSString stringWithFormat:@"cr%d", code];
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-02 19:27:12 +00:00
|
|
|
|
NSString *offset(Instruction instruction) {
|
|
|
|
|
NSString *const hexPart = [NSString stringWithFormat:@"%s%X", (instruction.d() < 0) ? "-0x" : "0x", abs(instruction.d())];
|
|
|
|
|
|
|
|
|
|
if(instruction.rA()) {
|
|
|
|
|
return [hexPart stringByAppendingFormat:@"(r%d)", instruction.rA()];
|
|
|
|
|
} else {
|
|
|
|
|
return hexPart;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-27 12:47:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 21:24:12 +00:00
|
|
|
|
@implementation DingusdevPowerPCTests
|
|
|
|
|
|
|
|
|
|
- (void)testDecoding {
|
|
|
|
|
NSData *const testData =
|
|
|
|
|
[NSData dataWithContentsOfURL:
|
|
|
|
|
[[NSBundle bundleForClass:[self class]]
|
|
|
|
|
URLForResource:@"ppcdisasmtest"
|
|
|
|
|
withExtension:@"csv"
|
|
|
|
|
subdirectory:@"dingusdev PowerPC tests"]];
|
|
|
|
|
|
|
|
|
|
NSString *const wholeFile = [[NSString alloc] initWithData:testData encoding:NSUTF8StringEncoding];
|
|
|
|
|
NSArray<NSString *> *const lines = [wholeFile componentsSeparatedByString:@"\n"];
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
InstructionSet::PowerPC::Decoder<InstructionSet::PowerPC::Model::MPC601, true> decoder;
|
2022-03-18 21:24:12 +00:00
|
|
|
|
for(NSString *const line in lines) {
|
|
|
|
|
// Ignore empty lines and comments.
|
|
|
|
|
if([line length] == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if([line characterAtIndex:0] == '#') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSArray<NSString *> *const columns = [line componentsSeparatedByString:@","];
|
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
// Columns are 1: address; 2: opcode; 3–: specific to the instruction.
|
2022-04-01 21:22:32 +00:00
|
|
|
|
const auto address = uint32_t([columns[0] hexInt]);
|
|
|
|
|
const auto opcode = uint32_t([columns[1] hexInt]);
|
2022-03-18 21:24:12 +00:00
|
|
|
|
NSString *const operation = columns[2];
|
|
|
|
|
const auto instruction = decoder.decode(opcode);
|
|
|
|
|
|
2022-04-04 12:09:59 +00:00
|
|
|
|
// Deal with some of the simplified mnemonics as special cases;
|
|
|
|
|
// underlying observation: distinguishing special cases isn't that
|
|
|
|
|
// important to a mere decoder.
|
|
|
|
|
if([operation isEqualToString:@"nop"]) {
|
|
|
|
|
// These tests use ORI for NOP.
|
|
|
|
|
XCTAssertEqual(instruction.operation, Operation::ori);
|
|
|
|
|
XCTAssertEqual(instruction.rD(), instruction.rA());
|
|
|
|
|
XCTAssertEqual(instruction.simm(), 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"mr"] || [operation isEqualToString:@"mr."]) {
|
|
|
|
|
// OR is used to achieve MR (i.e. move register).
|
|
|
|
|
XCTAssertEqual(instruction.operation, Operation::orx);
|
|
|
|
|
XCTAssertEqual((instruction.rc() != 0), ([operation characterAtIndex:operation.length - 1] == '.'));
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rB());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"li"]) {
|
|
|
|
|
// ADDI is used to achieve LI (i.e. load immediate).
|
|
|
|
|
XCTAssertEqual(instruction.operation, Operation::addi);
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD());
|
|
|
|
|
XCTAssertEqual(0, instruction.rA());
|
|
|
|
|
XCTAssertEqual([columns[4] hexInt], instruction.simm());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 21:24:12 +00:00
|
|
|
|
switch(instruction.operation) {
|
|
|
|
|
default:
|
2022-03-18 23:55:26 +00:00
|
|
|
|
NSAssert(FALSE, @"Didn't handle %@", line);
|
2022-03-18 21:24:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
case Operation::Undefined:
|
|
|
|
|
XCTAssertEqualObjects(operation, @"dc.l");
|
|
|
|
|
break;
|
|
|
|
|
|
2022-03-30 21:04:41 +00:00
|
|
|
|
case Operation::rlwimix: {
|
|
|
|
|
// This maps the opposite way from most of the other tests
|
|
|
|
|
// owing to the simplified names being a shade harder to
|
|
|
|
|
// detect motivationally.
|
|
|
|
|
XCTAssertEqual((instruction.rc() != 0), ([operation characterAtIndex:operation.length - 1] == '.'));
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS());
|
|
|
|
|
|
|
|
|
|
const auto n = [columns[5] intValue];
|
|
|
|
|
const auto b = [columns[6] intValue];
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"inslwi"] || [operation isEqualToString:@"inslwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), 32 - b);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), b);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), b + n - 1);
|
2022-03-30 21:04:41 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"insrwi"] || [operation isEqualToString:@"insrwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), 32 - (b + n));
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), b);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), b + n - 1);
|
2022-03-30 21:04:41 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSAssert(FALSE, @"Didn't handle rlwimix %@", line);
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case Operation::rlwnmx: {
|
|
|
|
|
XCTAssertEqual((instruction.rc() != 0), ([operation characterAtIndex:operation.length - 1] == '.'));
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS());
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB());
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"rotlw"] || [operation isEqualToString:@"rotlw."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31);
|
2022-03-30 21:04:41 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSAssert(FALSE, @"Didn't handle rlwnmx %@", line);
|
|
|
|
|
} break;
|
|
|
|
|
|
2022-03-30 20:43:09 +00:00
|
|
|
|
case Operation::rlwinmx: {
|
|
|
|
|
// This maps the opposite way from most of the other tests
|
|
|
|
|
// owing to the simplified names being a shade harder to
|
|
|
|
|
// detect motivationally.
|
|
|
|
|
XCTAssertEqual((instruction.rc() != 0), ([operation characterAtIndex:operation.length - 1] == '.'));
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS());
|
|
|
|
|
|
|
|
|
|
const auto n = [columns[5] intValue];
|
|
|
|
|
const auto b = columns.count > 6 ? [columns[6] intValue] : 0;
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"extlwi"] || [operation isEqualToString:@"extlwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), b);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), n - 1);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"extrwi"] || [operation isEqualToString:@"extrwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), b + n);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 32 - n);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"rotlwi"] || [operation isEqualToString:@"rotlwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), n);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"rotrwi"] || [operation isEqualToString:@"rotrwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), 32 - n);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"slwi"] || [operation isEqualToString:@"slwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), n);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31 - n);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"srwi"] || [operation isEqualToString:@"srwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), 32 - n);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), n);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"clrlwi"] || [operation isEqualToString:@"clrlwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), n);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"clrrwi"] || [operation isEqualToString:@"clrrwi."]) {
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), 0);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31 - n);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"clrlslwi"] || [operation isEqualToString:@"clrlslwi."]) {
|
2022-03-30 21:04:41 +00:00
|
|
|
|
// FreeScale switched the order of b and n in the short-form instruction here;
|
|
|
|
|
// they are therefore transposed in the tests below.
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual(instruction.sh<uint32_t>(), b);
|
|
|
|
|
XCTAssertEqual(instruction.mb<uint32_t>(), n - b);
|
|
|
|
|
XCTAssertEqual(instruction.me<uint32_t>(), 31 - b);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 21:04:41 +00:00
|
|
|
|
NSAssert(FALSE, @"Didn't handle rlwinmx %@", line);
|
2022-03-30 20:43:09 +00:00
|
|
|
|
} break;
|
|
|
|
|
|
2022-04-02 14:09:35 +00:00
|
|
|
|
case Operation::tw:
|
|
|
|
|
AssertEqualOperationName(operation, @"tw");
|
|
|
|
|
XCTAssertEqual([columns[3] intValue], instruction.to());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::twi:
|
|
|
|
|
AssertEqualOperationName(operation, @"twi");
|
|
|
|
|
XCTAssertEqual([columns[3] intValue], instruction.to());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.simm());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-03 12:55:28 +00:00
|
|
|
|
case Operation::mtfsfx:
|
|
|
|
|
AssertEqualOperationNameE(operation, @"mtfsfx", instruction);
|
|
|
|
|
XCTAssertEqual([columns[3] intValue], instruction.fm());
|
|
|
|
|
AssertEqualFR(columns[4], instruction.frB());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::mtfsfix:
|
|
|
|
|
AssertEqualOperationNameE(operation, @"mtfsfix", instruction);
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD()));
|
|
|
|
|
XCTAssertEqual([columns[4] intValue], instruction.imm());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-03 22:29:40 +00:00
|
|
|
|
case Operation::mcrxr:
|
|
|
|
|
AssertEqualOperationName(operation, @"mcrxr");
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD()));
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-04 00:33:32 +00:00
|
|
|
|
case Operation::mffsx:
|
|
|
|
|
AssertEqualOperationNameE(operation, @"mffsx", instruction);
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frD());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::mtmsr:
|
|
|
|
|
AssertEqualOperationName(operation, @"mtmsr");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rS());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::mtsrin:
|
|
|
|
|
AssertEqualOperationName(operation, @"mtsrin");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rB());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
case Operation::clcs:
|
|
|
|
|
AssertEqualOperationName(operation, @"clcs");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-04 00:33:32 +00:00
|
|
|
|
case Operation::mtsr:
|
|
|
|
|
AssertEqualOperationName(operation, @"mtsr");
|
|
|
|
|
XCTAssertEqual([columns[3] intValue], instruction.sr());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::tlbie:
|
|
|
|
|
AssertEqualOperationName(operation, @"tlbie");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rB());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-03 22:29:40 +00:00
|
|
|
|
case Operation::icbi:
|
|
|
|
|
AssertEqualOperationName(operation, @"icbi");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA(), false);
|
|
|
|
|
AssertEqualR(columns[4], instruction.rB());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::lswi:
|
|
|
|
|
AssertEqualOperationName(operation, @"lswi");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.nb());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::stswi:
|
|
|
|
|
AssertEqualOperationName(operation, @"stswi");
|
|
|
|
|
AssertEqualR(columns[3], instruction.rS());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.nb());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
case Operation::rlmix:
|
|
|
|
|
AssertEqualOperationNameE(operation, @"rlmix", instruction);
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS());
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB());
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual([columns[6] intValue], instruction.mb<uint32_t>());
|
|
|
|
|
XCTAssertEqual([columns[7] intValue], instruction.me<uint32_t>());
|
2022-04-07 01:09:58 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2022-04-03 19:50:03 +00:00
|
|
|
|
case Operation::cmp:
|
|
|
|
|
if([operation isEqualToString:@"cmpw"]) {
|
|
|
|
|
XCTAssertFalse(instruction.l());
|
|
|
|
|
XCTAssertFalse(instruction.crfD());
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rB());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if([operation isEqualToString:@"cmp"]) {
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD()));
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSAssert(FALSE, @"Didn't handle cmp %@", line);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::cmpl:
|
|
|
|
|
if([operation isEqualToString:@"cmplw"]) {
|
|
|
|
|
XCTAssertFalse(instruction.l());
|
|
|
|
|
if(instruction.crfD()) {
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD()));
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB());
|
|
|
|
|
} else {
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA());
|
|
|
|
|
AssertEqualR(columns[4], instruction.rB());
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSAssert(FALSE, @"Didn't handle cmpl %@", line);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::cmpli:
|
|
|
|
|
case Operation::cmpi:
|
|
|
|
|
if([operation isEqualToString:@"cmpwi"] || [operation isEqualToString:@"cmplwi"]) {
|
|
|
|
|
XCTAssertFalse(instruction.l());
|
|
|
|
|
} else {
|
|
|
|
|
XCTAssertTrue(instruction.l());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD()));
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA());
|
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.simm());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-03 22:29:40 +00:00
|
|
|
|
case Operation::mtfsb0x:
|
|
|
|
|
case Operation::mtfsb1x:
|
|
|
|
|
AssertEqualOperationNameE(
|
|
|
|
|
operation,
|
|
|
|
|
instruction.operation == Operation::mtfsb0x ? @"mtfsb0x" : @"mtfsb1x",
|
|
|
|
|
instruction);
|
|
|
|
|
XCTAssertEqual([columns[3] intValue], instruction.crbD());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-02 14:09:35 +00:00
|
|
|
|
#define NoArg(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-04 00:33:32 +00:00
|
|
|
|
NoArg(isync);
|
|
|
|
|
NoArg(sync);
|
|
|
|
|
NoArg(eieio);
|
|
|
|
|
NoArg(tlbia);
|
2022-04-02 14:09:35 +00:00
|
|
|
|
|
|
|
|
|
#undef NoArg
|
|
|
|
|
|
2022-04-04 00:33:32 +00:00
|
|
|
|
#define D(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
D(mfcr);
|
|
|
|
|
D(mfmsr);
|
|
|
|
|
|
|
|
|
|
#undef D
|
|
|
|
|
|
2022-04-01 21:22:32 +00:00
|
|
|
|
#define Shift(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS()); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-04 00:33:32 +00:00
|
|
|
|
Shift(slwx);
|
|
|
|
|
Shift(srwx);
|
|
|
|
|
Shift(srawx);
|
2022-04-01 21:22:32 +00:00
|
|
|
|
|
|
|
|
|
#undef Shift
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
|
|
|
|
|
#define ASsh(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS()); \
|
2022-04-10 01:11:58 +00:00
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.sh<uint32_t>()); \
|
2022-04-01 21:22:32 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
ASsh(sliqx);
|
|
|
|
|
ASsh(slliqx);
|
|
|
|
|
ASsh(sraiqx);
|
|
|
|
|
ASsh(sriqx);
|
|
|
|
|
ASsh(srliqx);
|
|
|
|
|
ASsh(srawix);
|
|
|
|
|
|
|
|
|
|
#undef ASsh
|
|
|
|
|
|
2022-03-30 16:40:57 +00:00
|
|
|
|
#define CRMod(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
|
|
|
|
XCTAssertEqualObjects(columns[3], condition(instruction.crbD())); \
|
|
|
|
|
XCTAssertEqualObjects(columns[4], condition(instruction.crbA())); \
|
|
|
|
|
XCTAssertEqualObjects(columns[5], condition(instruction.crbB())); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
CRMod(crand);
|
|
|
|
|
CRMod(crandc);
|
|
|
|
|
CRMod(creqv);
|
|
|
|
|
CRMod(crnand);
|
|
|
|
|
CRMod(crnor);
|
|
|
|
|
CRMod(cror);
|
|
|
|
|
CRMod(crorc);
|
|
|
|
|
CRMod(crxor);
|
|
|
|
|
|
|
|
|
|
#undef CRMod
|
|
|
|
|
|
2022-03-30 00:48:43 +00:00
|
|
|
|
case Operation::mtcrf: {
|
|
|
|
|
AssertEqualOperationName(operation,
|
|
|
|
|
instruction.crm() != 0xff ? @"mtcrf" : @"mtcr");
|
|
|
|
|
|
2022-03-30 21:04:41 +00:00
|
|
|
|
AssertEqualR([columns lastObject], instruction.rS());
|
2022-03-30 00:48:43 +00:00
|
|
|
|
|
|
|
|
|
if(columns.count > 4) {
|
2022-04-01 21:22:32 +00:00
|
|
|
|
XCTAssertEqual([columns[3] hexInt], instruction.crm());
|
2022-03-30 00:48:43 +00:00
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
2022-03-27 12:47:01 +00:00
|
|
|
|
#define ArithImm(x) \
|
|
|
|
|
case Operation::x: { \
|
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
2022-03-30 21:04:41 +00:00
|
|
|
|
AssertEqualR(columns[3], instruction.rD()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA()); \
|
2022-04-01 21:22:32 +00:00
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.simm()); \
|
2022-03-27 12:47:01 +00:00
|
|
|
|
} break;
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
ArithImm(dozi);
|
2022-03-27 12:47:01 +00:00
|
|
|
|
ArithImm(addi);
|
|
|
|
|
ArithImm(addic);
|
|
|
|
|
ArithImm(addic_);
|
|
|
|
|
ArithImm(addis);
|
2022-04-07 01:09:58 +00:00
|
|
|
|
ArithImm(mulli);
|
|
|
|
|
ArithImm(subfic);
|
2022-03-27 12:47:01 +00:00
|
|
|
|
|
|
|
|
|
#undef ArithImm
|
|
|
|
|
|
2022-04-01 21:52:38 +00:00
|
|
|
|
#define LogicImm(x) \
|
|
|
|
|
case Operation::x: { \
|
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS()); \
|
|
|
|
|
XCTAssertEqual([columns[5] hexInt], instruction.uimm()); \
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
LogicImm(andi_);
|
|
|
|
|
LogicImm(andis_);
|
|
|
|
|
LogicImm(ori);
|
|
|
|
|
LogicImm(oris);
|
|
|
|
|
LogicImm(xori);
|
|
|
|
|
LogicImm(xoris);
|
|
|
|
|
|
|
|
|
|
#undef ArithImm
|
|
|
|
|
|
2022-04-10 01:25:00 +00:00
|
|
|
|
#define DAB(x) \
|
2022-03-26 12:45:07 +00:00
|
|
|
|
case Operation::x: \
|
2022-03-27 12:47:01 +00:00
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
2022-04-10 01:25:00 +00:00
|
|
|
|
AssertEqualR(columns[3], instruction.rD()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA(), false); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
DAB(lwzx);
|
|
|
|
|
DAB(lwzux);
|
|
|
|
|
DAB(lbzx);
|
|
|
|
|
DAB(lbzux);
|
|
|
|
|
DAB(lhzx);
|
|
|
|
|
DAB(lhzux);
|
|
|
|
|
DAB(lhax);
|
|
|
|
|
DAB(lhaux);
|
|
|
|
|
DAB(lhbrx);
|
|
|
|
|
DAB(lwbrx);
|
|
|
|
|
DAB(lwarx);
|
|
|
|
|
DAB(eciwx);
|
|
|
|
|
DAB(lswx);
|
|
|
|
|
DAB(lwa);
|
|
|
|
|
DAB(lwaux);
|
|
|
|
|
DAB(lwax);
|
|
|
|
|
|
|
|
|
|
#undef DAB
|
|
|
|
|
|
|
|
|
|
#define DAe(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameOE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA()); \
|
2022-03-26 00:31:47 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2022-04-10 01:25:00 +00:00
|
|
|
|
DAe(negx);
|
|
|
|
|
DAe(subfzex);
|
|
|
|
|
DAe(subfmex);
|
|
|
|
|
DAe(absx);
|
|
|
|
|
DAe(nabsx);
|
|
|
|
|
DAe(addzex);
|
|
|
|
|
DAe(addmex);
|
|
|
|
|
|
|
|
|
|
#undef DAe
|
2022-03-26 00:23:21 +00:00
|
|
|
|
|
2022-04-03 22:29:40 +00:00
|
|
|
|
#define DABe(x) \
|
2022-03-29 00:18:41 +00:00
|
|
|
|
case Operation::x: \
|
2022-04-01 21:22:32 +00:00
|
|
|
|
AssertEqualOperationNameOE(operation, @#x, instruction); \
|
2022-04-10 01:25:00 +00:00
|
|
|
|
AssertEqualR(columns[3], instruction.rD()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA()); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
2022-03-29 00:18:41 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2022-04-03 22:29:40 +00:00
|
|
|
|
DABe(subfcx);
|
|
|
|
|
DABe(subfx);
|
|
|
|
|
DABe(subfex);
|
|
|
|
|
DABe(dozx);
|
|
|
|
|
DABe(addx);
|
|
|
|
|
DABe(addcx);
|
|
|
|
|
DABe(addex);
|
|
|
|
|
DABe(mulhwx);
|
|
|
|
|
DABe(mulhwux);
|
|
|
|
|
DABe(mulx);
|
|
|
|
|
DABe(mullwx);
|
|
|
|
|
DABe(divx);
|
|
|
|
|
DABe(divsx);
|
|
|
|
|
DABe(divwux);
|
|
|
|
|
DABe(divwx);
|
|
|
|
|
DABe(lscbxx);
|
|
|
|
|
|
|
|
|
|
#undef DABe
|
2022-03-29 00:18:41 +00:00
|
|
|
|
|
2022-04-01 21:35:47 +00:00
|
|
|
|
#define ASB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS()); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-07 01:09:58 +00:00
|
|
|
|
ASB(maskgx);
|
|
|
|
|
ASB(maskirx);
|
|
|
|
|
ASB(rribx);
|
|
|
|
|
ASB(slex);
|
|
|
|
|
ASB(sleqx);
|
|
|
|
|
ASB(sllqx);
|
|
|
|
|
ASB(slqx);
|
|
|
|
|
ASB(sraqx);
|
|
|
|
|
ASB(srex);
|
|
|
|
|
ASB(sreax);
|
|
|
|
|
ASB(sreqx);
|
|
|
|
|
ASB(srlqx);
|
|
|
|
|
ASB(srqx);
|
|
|
|
|
|
2022-04-01 21:35:47 +00:00
|
|
|
|
ASB(andx);
|
|
|
|
|
ASB(andcx);
|
|
|
|
|
ASB(norx);
|
|
|
|
|
ASB(eqvx);
|
|
|
|
|
ASB(xorx);
|
|
|
|
|
ASB(orcx);
|
|
|
|
|
ASB(orx);
|
|
|
|
|
ASB(nandx);
|
|
|
|
|
|
|
|
|
|
#undef ASB
|
|
|
|
|
|
2022-04-02 00:37:36 +00:00
|
|
|
|
#define SAB(x) \
|
|
|
|
|
case Operation::x: \
|
2022-04-03 22:29:40 +00:00
|
|
|
|
AssertEqualOperationName(operation, @#x); \
|
2022-04-02 00:37:36 +00:00
|
|
|
|
AssertEqualR(columns[3], instruction.rS()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA(), false); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
2022-04-04 00:33:32 +00:00
|
|
|
|
SAB(ecowx);
|
|
|
|
|
SAB(stbux);
|
|
|
|
|
SAB(stbx);
|
|
|
|
|
SAB(sthbrx);
|
|
|
|
|
SAB(sthux);
|
|
|
|
|
SAB(sthx);
|
|
|
|
|
SAB(stswx);
|
|
|
|
|
SAB(stwbrx);
|
2022-04-02 00:37:36 +00:00
|
|
|
|
SAB(stwcx_);
|
2022-04-04 00:33:32 +00:00
|
|
|
|
SAB(stwux);
|
|
|
|
|
SAB(stwx);
|
|
|
|
|
SAB(stdcx_);
|
|
|
|
|
SAB(stdux);
|
|
|
|
|
SAB(stdx);
|
2022-04-02 00:37:36 +00:00
|
|
|
|
|
|
|
|
|
#undef SAB
|
|
|
|
|
|
2022-04-03 22:29:40 +00:00
|
|
|
|
#define AS(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rA()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rS()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
AS(cntlzwx);
|
|
|
|
|
AS(extsbx);
|
|
|
|
|
AS(extshx);
|
|
|
|
|
AS(extswx);
|
|
|
|
|
|
|
|
|
|
#undef AS
|
|
|
|
|
|
2022-04-02 19:40:17 +00:00
|
|
|
|
#define fSAB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frS()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA(), false); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fSAB(stfdx);
|
|
|
|
|
fSAB(stfdux);
|
|
|
|
|
fSAB(stfsx);
|
|
|
|
|
fSAB(stfsux);
|
|
|
|
|
fSAB(stfiwx);
|
|
|
|
|
|
|
|
|
|
#undef fSAB
|
|
|
|
|
|
|
|
|
|
#define fDAB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frD()); \
|
|
|
|
|
AssertEqualR(columns[4], instruction.rA(), false); \
|
|
|
|
|
AssertEqualR(columns[5], instruction.rB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fDAB(lfdux);
|
|
|
|
|
fDAB(lfdx);
|
|
|
|
|
fDAB(lfsux);
|
|
|
|
|
fDAB(lfsx);
|
|
|
|
|
|
|
|
|
|
#undef fDAB
|
|
|
|
|
|
2022-04-02 23:58:21 +00:00
|
|
|
|
#define fDfAfB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frD()); \
|
|
|
|
|
AssertEqualFR(columns[4], instruction.frA(), false); \
|
|
|
|
|
AssertEqualFR(columns[5], instruction.frB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fDfAfB(faddx);
|
|
|
|
|
fDfAfB(faddsx);
|
|
|
|
|
fDfAfB(fsubx);
|
|
|
|
|
fDfAfB(fsubsx);
|
|
|
|
|
fDfAfB(fdivx);
|
|
|
|
|
fDfAfB(fdivsx);
|
|
|
|
|
|
|
|
|
|
#undef fDfAfB
|
|
|
|
|
|
2022-04-03 12:06:59 +00:00
|
|
|
|
#define fDfB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frD()); \
|
|
|
|
|
AssertEqualFR(columns[4], instruction.frB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fDfB(fabsx);
|
|
|
|
|
fDfB(fnabsx);
|
|
|
|
|
fDfB(fnegx);
|
|
|
|
|
fDfB(frsqrtex);
|
|
|
|
|
fDfB(frspx);
|
|
|
|
|
fDfB(fctiwx);
|
|
|
|
|
fDfB(fctiwzx);
|
|
|
|
|
fDfB(fctidx);
|
|
|
|
|
fDfB(fctidzx);
|
|
|
|
|
fDfB(fcfidx);
|
|
|
|
|
fDfB(fresx);
|
|
|
|
|
fDfB(fmrx);
|
|
|
|
|
|
|
|
|
|
#undef fDfB
|
|
|
|
|
|
2022-04-02 23:58:21 +00:00
|
|
|
|
#define fDfAfC(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frD()); \
|
|
|
|
|
AssertEqualFR(columns[4], instruction.frA(), false); \
|
|
|
|
|
AssertEqualFR(columns[5], instruction.frC()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fDfAfC(fmulx);
|
|
|
|
|
fDfAfC(fmulsx);
|
|
|
|
|
|
|
|
|
|
#undef fDfAfC
|
|
|
|
|
|
|
|
|
|
#define fDfAfCfB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationNameE(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.frD()); \
|
|
|
|
|
AssertEqualFR(columns[4], instruction.frA()); \
|
|
|
|
|
AssertEqualFR(columns[5], instruction.frC()); \
|
|
|
|
|
AssertEqualFR(columns[6], instruction.frB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fDfAfCfB(fnmaddx);
|
|
|
|
|
fDfAfCfB(fnmaddsx);
|
|
|
|
|
fDfAfCfB(fnmsubx);
|
|
|
|
|
fDfAfCfB(fnmsubsx);
|
|
|
|
|
fDfAfCfB(fmaddx);
|
|
|
|
|
fDfAfCfB(fmaddsx);
|
|
|
|
|
fDfAfCfB(fmsubx);
|
|
|
|
|
fDfAfCfB(fmsubsx);
|
|
|
|
|
fDfAfCfB(fselx);
|
|
|
|
|
|
|
|
|
|
#undef fDfAfBfC
|
|
|
|
|
|
2022-04-02 19:27:12 +00:00
|
|
|
|
#define DDA(x) \
|
|
|
|
|
case Operation::x: { \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rD()); \
|
|
|
|
|
XCTAssertEqualObjects(columns[4], offset(instruction)); \
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
DDA(lbz);
|
|
|
|
|
DDA(lbzu);
|
|
|
|
|
DDA(lmw);
|
|
|
|
|
DDA(lwz);
|
|
|
|
|
DDA(lwzu);
|
|
|
|
|
DDA(lhz);
|
|
|
|
|
DDA(lhzu);
|
|
|
|
|
DDA(lha);
|
|
|
|
|
DDA(lhau);
|
|
|
|
|
|
|
|
|
|
#undef DDA
|
|
|
|
|
|
2022-04-02 19:40:17 +00:00
|
|
|
|
#define fDDA(x) \
|
|
|
|
|
case Operation::x: { \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.rD()); \
|
|
|
|
|
XCTAssertEqualObjects(columns[4], offset(instruction)); \
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
fDDA(lfd);
|
|
|
|
|
fDDA(lfdu);
|
|
|
|
|
fDDA(lfs);
|
|
|
|
|
fDDA(lfsu);
|
|
|
|
|
|
|
|
|
|
#undef fDDA
|
|
|
|
|
|
2022-04-02 19:27:12 +00:00
|
|
|
|
#define SDA(x) \
|
|
|
|
|
case Operation::x: { \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualR(columns[3], instruction.rS()); \
|
|
|
|
|
XCTAssertEqualObjects(columns[4], offset(instruction)); \
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
SDA(stb);
|
|
|
|
|
SDA(stbu);
|
|
|
|
|
SDA(sth);
|
|
|
|
|
SDA(sthu);
|
|
|
|
|
SDA(stmw);
|
|
|
|
|
SDA(stw);
|
|
|
|
|
SDA(stwu);
|
|
|
|
|
|
|
|
|
|
#undef SDA
|
|
|
|
|
|
2022-04-02 19:40:17 +00:00
|
|
|
|
#define fSDA(x) \
|
|
|
|
|
case Operation::x: { \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
AssertEqualFR(columns[3], instruction.rS()); \
|
|
|
|
|
XCTAssertEqualObjects(columns[4], offset(instruction)); \
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
fSDA(stfd);
|
|
|
|
|
fSDA(stfdu);
|
|
|
|
|
fSDA(stfs);
|
|
|
|
|
fSDA(stfsu);
|
|
|
|
|
|
|
|
|
|
#undef fSDA
|
|
|
|
|
|
2022-04-03 12:06:59 +00:00
|
|
|
|
#define crfDS(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD())); \
|
|
|
|
|
XCTAssertEqualObjects(columns[4], conditionreg(instruction.crfS())); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
crfDS(mcrf);
|
|
|
|
|
crfDS(mcrfs);
|
|
|
|
|
|
|
|
|
|
#undef crfDS
|
|
|
|
|
|
2022-04-03 19:50:03 +00:00
|
|
|
|
#define crfDfAfB(x) \
|
|
|
|
|
case Operation::x: \
|
|
|
|
|
AssertEqualOperationName(operation, @#x, instruction); \
|
|
|
|
|
XCTAssertEqualObjects(columns[3], conditionreg(instruction.crfD())); \
|
|
|
|
|
AssertEqualFR(columns[4], instruction.frA()); \
|
|
|
|
|
AssertEqualFR(columns[5], instruction.frB()); \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
crfDfAfB(fcmpo);
|
|
|
|
|
crfDfAfB(fcmpu);
|
|
|
|
|
|
|
|
|
|
#undef crfDfAfB
|
|
|
|
|
|
2022-03-25 12:41:57 +00:00
|
|
|
|
case Operation::bcx:
|
2022-03-25 10:25:06 +00:00
|
|
|
|
case Operation::bclrx:
|
2022-03-25 00:44:03 +00:00
|
|
|
|
case Operation::bcctrx: {
|
|
|
|
|
NSString *baseOperation = nil;
|
2022-03-25 12:41:57 +00:00
|
|
|
|
BOOL addConditionToOperand = NO;
|
2022-03-25 10:25:06 +00:00
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
switch(instruction.branch_options()) {
|
2022-03-25 12:41:57 +00:00
|
|
|
|
case BranchOption::Always: baseOperation = @"b"; break;
|
|
|
|
|
case BranchOption::Dec_Zero: baseOperation = @"bdz"; break;
|
2022-03-26 00:23:21 +00:00
|
|
|
|
case BranchOption::Dec_NotZero: baseOperation = @"bdnz"; break;
|
2022-03-25 12:41:57 +00:00
|
|
|
|
|
|
|
|
|
case BranchOption::Clear:
|
2022-03-25 00:44:03 +00:00
|
|
|
|
switch(Condition(instruction.bi() & 3)) {
|
|
|
|
|
default: break;
|
2022-03-25 10:25:06 +00:00
|
|
|
|
case Condition::Negative: baseOperation = @"bge"; break;
|
|
|
|
|
case Condition::Positive: baseOperation = @"ble"; break;
|
|
|
|
|
case Condition::Zero: baseOperation = @"bne"; break;
|
2022-03-25 00:44:03 +00:00
|
|
|
|
case Condition::SummaryOverflow:
|
2022-03-25 10:25:06 +00:00
|
|
|
|
baseOperation = @"bns";
|
2022-03-25 00:44:03 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-03-25 12:41:57 +00:00
|
|
|
|
case BranchOption::Dec_ZeroAndClear:
|
|
|
|
|
baseOperation = @"bdzf";
|
|
|
|
|
addConditionToOperand = YES;
|
|
|
|
|
break;
|
|
|
|
|
case BranchOption::Dec_NotZeroAndClear:
|
|
|
|
|
baseOperation = @"bdnzf";
|
|
|
|
|
addConditionToOperand = YES;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BranchOption::Set:
|
2022-03-25 00:44:03 +00:00
|
|
|
|
switch(Condition(instruction.bi() & 3)) {
|
|
|
|
|
default: break;
|
2022-03-25 10:25:06 +00:00
|
|
|
|
case Condition::Negative: baseOperation = @"blt"; break;
|
|
|
|
|
case Condition::Positive: baseOperation = @"bgt"; break;
|
|
|
|
|
case Condition::Zero: baseOperation = @"beq"; break;
|
2022-03-25 00:44:03 +00:00
|
|
|
|
case Condition::SummaryOverflow:
|
2022-03-25 10:25:06 +00:00
|
|
|
|
baseOperation = @"bso";
|
2022-03-25 00:44:03 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-03-25 12:41:57 +00:00
|
|
|
|
case BranchOption::Dec_ZeroAndSet:
|
|
|
|
|
baseOperation = @"bdzt";
|
|
|
|
|
addConditionToOperand = YES;
|
|
|
|
|
break;
|
|
|
|
|
case BranchOption::Dec_NotZeroAndSet:
|
|
|
|
|
baseOperation = @"bdnzt";
|
|
|
|
|
addConditionToOperand = YES;
|
|
|
|
|
break;
|
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-25 12:41:57 +00:00
|
|
|
|
switch(instruction.operation) {
|
|
|
|
|
case Operation::bcctrx:
|
|
|
|
|
baseOperation = [baseOperation stringByAppendingString:@"ctr"];
|
|
|
|
|
break;
|
|
|
|
|
case Operation::bclrx:
|
|
|
|
|
baseOperation = [baseOperation stringByAppendingString:@"lr"];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Operation::bcx: {
|
2022-03-26 00:10:08 +00:00
|
|
|
|
uint32_t decoded_destination;
|
|
|
|
|
if(instruction.aa()) {
|
|
|
|
|
decoded_destination = instruction.bd();
|
|
|
|
|
} else {
|
|
|
|
|
decoded_destination = instruction.bd() + address;
|
|
|
|
|
}
|
2022-03-25 12:41:57 +00:00
|
|
|
|
|
2022-04-01 21:22:32 +00:00
|
|
|
|
XCTAssertEqual(decoded_destination, [[columns lastObject] hexInt]);
|
2022-03-25 12:41:57 +00:00
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
default: break;
|
2022-03-25 10:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-25 00:44:03 +00:00
|
|
|
|
if(!baseOperation) {
|
|
|
|
|
NSAssert(FALSE, @"Didn't handle bi %d for bo %d, %@", instruction.bi() & 3, instruction.bo(), line);
|
|
|
|
|
} else {
|
|
|
|
|
if(instruction.lk()) {
|
|
|
|
|
baseOperation = [baseOperation stringByAppendingString:@"l"];
|
|
|
|
|
}
|
2022-03-26 00:10:08 +00:00
|
|
|
|
if(instruction.aa()) {
|
|
|
|
|
baseOperation = [baseOperation stringByAppendingString:@"a"];
|
|
|
|
|
}
|
2022-03-25 00:44:03 +00:00
|
|
|
|
if(instruction.branch_prediction_hint()) {
|
|
|
|
|
baseOperation = [baseOperation stringByAppendingString:@"+"];
|
|
|
|
|
}
|
2022-03-27 12:47:01 +00:00
|
|
|
|
AssertEqualOperationName(operation, baseOperation);
|
2022-03-25 00:44:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(instruction.bi() & ~3) {
|
2022-03-25 12:41:57 +00:00
|
|
|
|
NSString *expectedCR;
|
|
|
|
|
|
|
|
|
|
if(addConditionToOperand) {
|
2022-04-01 21:22:32 +00:00
|
|
|
|
expectedCR = condition(instruction.bi());
|
2022-03-25 12:41:57 +00:00
|
|
|
|
} else {
|
|
|
|
|
expectedCR = [NSString stringWithFormat:@"cr%d", instruction.bi() >> 2];
|
|
|
|
|
}
|
2022-03-25 00:44:03 +00:00
|
|
|
|
XCTAssertEqualObjects(columns[3], expectedCR);
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
|
2022-03-18 23:55:26 +00:00
|
|
|
|
case Operation::bx: {
|
2022-03-18 21:24:12 +00:00
|
|
|
|
switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) {
|
2022-03-27 12:47:01 +00:00
|
|
|
|
case 0: AssertEqualOperationName(operation, @"b"); break;
|
2022-03-30 00:48:43 +00:00
|
|
|
|
case 1: AssertEqualOperationName(operation, @"bl"); break;
|
|
|
|
|
case 2: AssertEqualOperationName(operation, @"ba"); break;
|
2022-03-27 12:47:01 +00:00
|
|
|
|
case 3: AssertEqualOperationName(operation, @"bla"); break;
|
2022-03-18 21:24:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uint32_t decoded_destination =
|
|
|
|
|
instruction.li() + (instruction.aa() ? 0 : address);
|
2022-04-01 21:22:32 +00:00
|
|
|
|
XCTAssertEqual(decoded_destination, [columns[3] hexInt]);
|
2022-03-18 21:24:12 +00:00
|
|
|
|
} break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|