mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Test loads and stores, and immediate arithmetic.
This commit is contained in:
parent
2d69896f64
commit
d84c72afe5
@ -63,8 +63,10 @@ enum class BranchOption: uint32_t {
|
|||||||
enum class Operation: uint8_t {
|
enum class Operation: uint8_t {
|
||||||
Undefined,
|
Undefined,
|
||||||
|
|
||||||
|
//
|
||||||
// These 601-exclusive instructions; a lot of them are carry-overs
|
// These 601-exclusive instructions; a lot of them are carry-overs
|
||||||
// from POWER. These are not part of the PowerPC architecture.
|
// from POWER. These are not part of the PowerPC architecture.
|
||||||
|
//
|
||||||
|
|
||||||
/// |rA| is placed into rD. If rA = 0x8000'0000 then 0x8000'0000 is placed into rD
|
/// |rA| is placed into rD. If rA = 0x8000'0000 then 0x8000'0000 is placed into rD
|
||||||
/// and XER[OV] is set if oe() indicates that overflow is enabled.
|
/// and XER[OV] is set if oe() indicates that overflow is enabled.
|
||||||
@ -100,8 +102,35 @@ enum class Operation: uint8_t {
|
|||||||
nabsx, rlmix, rribx, slex, sleqx, sliqx, slliqx, sllqx, slqx,
|
nabsx, rlmix, rribx, slex, sleqx, sliqx, slliqx, sllqx, slqx,
|
||||||
sraiqx, sraqx, srex, sreax, sreqx, sriqx, srliqx, srlqx, srqx,
|
sraiqx, sraqx, srex, sreax, sreqx, sriqx, srliqx, srlqx, srqx,
|
||||||
|
|
||||||
|
//
|
||||||
// 32- and 64-bit PowerPC instructions.
|
// 32- and 64-bit PowerPC instructions.
|
||||||
addx, addcx, addex, addi, addic, addic_, addis, addmex, addzex, andx,
|
//
|
||||||
|
|
||||||
|
addx, addcx, addex,
|
||||||
|
|
||||||
|
/// Add immediate.
|
||||||
|
///
|
||||||
|
/// rD() = (rA() | 0) + simm()
|
||||||
|
addi,
|
||||||
|
|
||||||
|
/// Add immediate carrying.
|
||||||
|
///
|
||||||
|
/// rD() = (rA() | 0) + simm()
|
||||||
|
/// XER[CA] = carry.
|
||||||
|
addic,
|
||||||
|
|
||||||
|
/// Add immediate carrying.
|
||||||
|
///
|
||||||
|
/// rD() = (rA() | 0) + simm()
|
||||||
|
/// XER[CA] = carry, and the condition register is updated.
|
||||||
|
addic_,
|
||||||
|
|
||||||
|
/// Add immediate shifter.
|
||||||
|
///
|
||||||
|
/// rD() = (rA() | 0) + (simm() << 16)
|
||||||
|
addis,
|
||||||
|
|
||||||
|
addmex, addzex, andx,
|
||||||
andcx, andi_, andis_,
|
andcx, andi_, andis_,
|
||||||
|
|
||||||
/// Branch unconditional.
|
/// Branch unconditional.
|
||||||
@ -169,7 +198,45 @@ enum class Operation: uint8_t {
|
|||||||
lbzx,
|
lbzx,
|
||||||
|
|
||||||
lfd, lfdu, lfdux, lfdx, lfs, lfsu,
|
lfd, lfdu, lfdux, lfdx, lfs, lfsu,
|
||||||
lfsux, lfsx, lha, lhau, lhaux, lhax, lhbrx, lhz, lhzu, lhzux, lhzx, lmw,
|
lfsux, lfsx, lha, lhau,
|
||||||
|
|
||||||
|
/// Load half-word algebraic with update indexed.
|
||||||
|
///
|
||||||
|
/// rD()[16, 31] = [ rA()|0 + rB() ]; and rA() is set to the calculated address
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
/// The result in rD is sign extended.
|
||||||
|
///
|
||||||
|
/// PowerPC defines rA=0 and rA=rD to be invalid forms; the MPC601
|
||||||
|
/// will suppress the update if rA=0 or rA=rD.
|
||||||
|
lhaux,
|
||||||
|
|
||||||
|
/// Load half-word algebraic indexed.
|
||||||
|
///
|
||||||
|
/// rD[16, 31] = [ (rA()|0) + rB() ]
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
/// The result in rD is sign extended.
|
||||||
|
lhax,
|
||||||
|
|
||||||
|
lhbrx, lhz, lhzu,
|
||||||
|
|
||||||
|
/// Load half-word and zero with update indexed.
|
||||||
|
///
|
||||||
|
/// rD()[16, 31] = [ rA()|0 + rB() ]; and rA() is set to the calculated address
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
/// The rest of rD is set to 0.
|
||||||
|
///
|
||||||
|
/// PowerPC defines rA=0 and rA=rD to be invalid forms; the MPC601
|
||||||
|
/// will suppress the update if rA=0 or rA=rD.
|
||||||
|
lhzux,
|
||||||
|
|
||||||
|
/// Load half-word and zero indexed.
|
||||||
|
///
|
||||||
|
/// rD[16, 31] = [ (rA()|0) + rB() ]
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
/// The rest of rD is set to 0.
|
||||||
|
lhzx,
|
||||||
|
|
||||||
|
lmw,
|
||||||
lswi, lswx, lwarx, lwbrx, lwz, lwzu,
|
lswi, lswx, lwarx, lwbrx, lwz, lwzu,
|
||||||
|
|
||||||
/// Load word and zero with update indexed.
|
/// Load word and zero with update indexed.
|
||||||
@ -189,12 +256,74 @@ enum class Operation: uint8_t {
|
|||||||
|
|
||||||
mcrf, mcrfs, mcrxr,
|
mcrf, mcrfs, mcrxr,
|
||||||
mfcr, mffsx, mfmsr, mfspr, mfsr, mfsrin, mtcrf, mtfsb0x, mtfsb1x, mtfsfx,
|
mfcr, mffsx, mfmsr, mfspr, mfsr, mfsrin, mtcrf, mtfsb0x, mtfsb1x, mtfsfx,
|
||||||
mtfsfix, mtmsr, mtspr, mtsr, mtsrin, mulhwx, mulhwux, mulli, mullwx,
|
mtfsfix, mtmsr, mtspr, mtsr, mtsrin, mulhwx, mulhwux,
|
||||||
|
|
||||||
|
/// Multiply low immediate.
|
||||||
|
///
|
||||||
|
/// rD() = [low 32 bits of] rA() * simm()
|
||||||
|
/// XER[OV] is set if, were the operands treated as signed, overflow occurred.
|
||||||
|
mulli,
|
||||||
|
|
||||||
|
mullwx,
|
||||||
nandx, negx, norx, orx, orcx, ori, oris, rfi, rlwimix, rlwinmx, rlwnmx,
|
nandx, negx, norx, orx, orcx, ori, oris, rfi, rlwimix, rlwinmx, rlwnmx,
|
||||||
sc, slwx, srawx, srawix, srwx, stb, stbu, stbux, stbx, stfd, stfdu,
|
sc, slwx, srawx, srawix, srwx, stb, stbu,
|
||||||
stfdux, stfdx, stfs, stfsu, stfsux, stfsx, sth, sthbrx, sthu, sthux, sthx,
|
|
||||||
stmw, stswi, stswx, stw, stwbrx, stwcx_, stwu, stwux, stwx, subfx, subfcx,
|
/// Store byte with update indexed.
|
||||||
subfex, subfic, subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
|
///
|
||||||
|
/// [ (ra()|0) + rB() ] = rS()[24, 31]; and rA() is updated with the calculated address.
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
///
|
||||||
|
/// PowerPC defines rA=0 to an invalid form; the MPC601 will store to r0.
|
||||||
|
stbux,
|
||||||
|
|
||||||
|
/// Store byte indexed.
|
||||||
|
///
|
||||||
|
/// [ (ra()|0) + rB() ] = rS()[24, 31]
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
stbx,
|
||||||
|
|
||||||
|
stfd, stfdu,
|
||||||
|
stfdux, stfdx, stfs, stfsu, stfsux, stfsx, sth, sthbrx, sthu,
|
||||||
|
|
||||||
|
/// Store half-word with update indexed.
|
||||||
|
///
|
||||||
|
/// [ (ra()|0) + rB() ] = rS()[16, 31]; and rA() is updated with the calculated address.
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
///
|
||||||
|
/// PowerPC defines rA=0 to an invalid form; the MPC601 will store to r0.
|
||||||
|
sthux,
|
||||||
|
|
||||||
|
/// Store half-word indexed.
|
||||||
|
///
|
||||||
|
/// [ (ra()|0) + rB() ] = rS()[16, 31]
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
sthx,
|
||||||
|
|
||||||
|
stmw, stswi, stswx, stw, stwbrx, stwcx_, stwu,
|
||||||
|
|
||||||
|
/// Store word with update indexed.
|
||||||
|
///
|
||||||
|
/// [ (ra()|0) + rB() ] = rS(); and rA() is updated with the calculated address.
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
///
|
||||||
|
/// PowerPC defines rA=0 to an invalid form; the MPC601 will store to r0.
|
||||||
|
stwux,
|
||||||
|
|
||||||
|
/// Store word indexed.
|
||||||
|
///
|
||||||
|
/// [ (ra()|0) + rB() ] = rS()
|
||||||
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
|
stwx,
|
||||||
|
|
||||||
|
subfx, subfcx,
|
||||||
|
subfex,
|
||||||
|
|
||||||
|
/// Subtract from immediate carrying
|
||||||
|
///
|
||||||
|
/// rD() = ~rA() + simm() + 1
|
||||||
|
subfic,
|
||||||
|
|
||||||
|
subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
|
||||||
|
|
||||||
// 32-bit, supervisor level.
|
// 32-bit, supervisor level.
|
||||||
dcbi,
|
dcbi,
|
||||||
@ -205,7 +334,9 @@ enum class Operation: uint8_t {
|
|||||||
// Optional.
|
// Optional.
|
||||||
fresx, frsqrtex, fselx, fsqrtx, slbia, slbie, stfiwx,
|
fresx, frsqrtex, fselx, fsqrtx, slbia, slbie, stfiwx,
|
||||||
|
|
||||||
|
//
|
||||||
// 64-bit only PowerPC instructions.
|
// 64-bit only PowerPC instructions.
|
||||||
|
//
|
||||||
cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux,
|
cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux,
|
||||||
ldx, sldx, ldux, td, mulhdx, ldarx, stdx, stdux, mulld, lwax, lwaux,
|
ldx, sldx, ldux, td, mulhdx, ldarx, stdx, stdux, mulld, lwax, lwaux,
|
||||||
sradix, srdx, sradx, extsw, fsqrtsx, std, stdu, stdcx_,
|
sradix, srdx, sradx, extsw, fsqrtsx, std, stdu, stdcx_,
|
||||||
|
@ -17,6 +17,16 @@ using namespace InstructionSet::PowerPC;
|
|||||||
@interface DingusdevPowerPCTests : XCTestCase
|
@interface DingusdevPowerPCTests : XCTestCase
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void AssertEqualOperationName(NSString *lhs, NSString *rhs) {
|
||||||
|
NSString *const lhsMapped = [lhs stringByReplacingOccurrencesOfString:@"_" withString:@"."];
|
||||||
|
NSString *const rhsMapped = [rhs stringByReplacingOccurrencesOfString:@"_" withString:@"."];
|
||||||
|
XCTAssertEqualObjects(lhsMapped, rhsMapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@implementation DingusdevPowerPCTests
|
@implementation DingusdevPowerPCTests
|
||||||
|
|
||||||
- (void)testABDInstruction:(Instruction)instruction columns:(NSArray<NSString *> *)columns testZero:(BOOL)testZero {
|
- (void)testABDInstruction:(Instruction)instruction columns:(NSArray<NSString *> *)columns testZero:(BOOL)testZero {
|
||||||
@ -57,21 +67,52 @@ using namespace InstructionSet::PowerPC;
|
|||||||
NSString *const operation = columns[2];
|
NSString *const operation = columns[2];
|
||||||
const auto instruction = decoder.decode(opcode);
|
const auto instruction = decoder.decode(opcode);
|
||||||
|
|
||||||
|
NSLog(@"%@", line);
|
||||||
switch(instruction.operation) {
|
switch(instruction.operation) {
|
||||||
default:
|
default:
|
||||||
NSAssert(FALSE, @"Didn't handle %@", line);
|
NSAssert(FALSE, @"Didn't handle %@", line);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#define ArithImm(x) \
|
||||||
|
case Operation::x: { \
|
||||||
|
NSString *const rD = [NSString stringWithFormat:@"r%d", instruction.rD()]; \
|
||||||
|
NSString *const rA = [NSString stringWithFormat:@"r%d", instruction.rA()]; \
|
||||||
|
const auto simm = strtol([columns[5] UTF8String], NULL, 16); \
|
||||||
|
AssertEqualOperationName(operation, @#x); \
|
||||||
|
XCTAssertEqualObjects(columns[3], rD); \
|
||||||
|
XCTAssertEqualObjects(columns[4], rA); \
|
||||||
|
XCTAssertEqual(simm, instruction.simm()); \
|
||||||
|
} break;
|
||||||
|
|
||||||
|
ArithImm(mulli);
|
||||||
|
ArithImm(subfic);
|
||||||
|
ArithImm(addi);
|
||||||
|
ArithImm(addic);
|
||||||
|
ArithImm(addic_);
|
||||||
|
ArithImm(addis);
|
||||||
|
|
||||||
|
#undef ArithImm
|
||||||
|
|
||||||
#define ABCz(x) \
|
#define ABCz(x) \
|
||||||
case Operation::x: \
|
case Operation::x: \
|
||||||
XCTAssertEqualObjects(operation, @#x); \
|
AssertEqualOperationName(operation, @#x); \
|
||||||
[self testABDInstruction:instruction columns:columns testZero:YES]; \
|
[self testABDInstruction:instruction columns:columns testZero:YES]; \
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ABCz(lwzux);
|
|
||||||
ABCz(lwzx);
|
ABCz(lwzx);
|
||||||
|
ABCz(lwzux);
|
||||||
ABCz(lbzx);
|
ABCz(lbzx);
|
||||||
ABCz(lbzux);
|
ABCz(lbzux);
|
||||||
|
ABCz(stwx);
|
||||||
|
ABCz(stwux);
|
||||||
|
ABCz(stbx);
|
||||||
|
ABCz(stbux);
|
||||||
|
ABCz(lhzx);
|
||||||
|
ABCz(lhzux);
|
||||||
|
ABCz(lhax);
|
||||||
|
ABCz(lhaux);
|
||||||
|
ABCz(sthx);
|
||||||
|
ABCz(sthux);
|
||||||
|
|
||||||
#undef ABCz
|
#undef ABCz
|
||||||
|
|
||||||
@ -164,7 +205,7 @@ using namespace InstructionSet::PowerPC;
|
|||||||
if(instruction.branch_prediction_hint()) {
|
if(instruction.branch_prediction_hint()) {
|
||||||
baseOperation = [baseOperation stringByAppendingString:@"+"];
|
baseOperation = [baseOperation stringByAppendingString:@"+"];
|
||||||
}
|
}
|
||||||
XCTAssertEqualObjects(operation, baseOperation);
|
AssertEqualOperationName(operation, baseOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(instruction.bi() & ~3) {
|
if(instruction.bi() & ~3) {
|
||||||
@ -190,10 +231,10 @@ using namespace InstructionSet::PowerPC;
|
|||||||
|
|
||||||
case Operation::bx: {
|
case Operation::bx: {
|
||||||
switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) {
|
switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) {
|
||||||
case 0: XCTAssertEqualObjects(operation, @"b"); break;
|
case 0: AssertEqualOperationName(operation, @"b"); break;
|
||||||
case 1: XCTAssertEqualObjects(operation, @"bl"); break;
|
case 1: AssertEqualOperationName(operation, @"bl"); break;
|
||||||
case 2: XCTAssertEqualObjects(operation, @"ba"); break;
|
case 2: AssertEqualOperationName(operation, @"ba"); break;
|
||||||
case 3: XCTAssertEqualObjects(operation, @"bla"); break;
|
case 3: AssertEqualOperationName(operation, @"bla"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user