1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-23 20:29:42 +00:00

Test loads and stores, and immediate arithmetic.

This commit is contained in:
Thomas Harte 2022-03-27 08:47:01 -04:00
parent 2d69896f64
commit d84c72afe5
2 changed files with 186 additions and 14 deletions

View File

@ -63,8 +63,10 @@ enum class BranchOption: uint32_t {
enum class Operation: uint8_t {
Undefined,
//
// These 601-exclusive instructions; a lot of them are carry-overs
// 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
/// 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,
sraiqx, sraqx, srex, sreax, sreqx, sriqx, srliqx, srlqx, srqx,
//
// 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_,
/// Branch unconditional.
@ -169,7 +198,45 @@ enum class Operation: uint8_t {
lbzx,
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,
/// Load word and zero with update indexed.
@ -189,12 +256,74 @@ enum class Operation: uint8_t {
mcrf, mcrfs, mcrxr,
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,
sc, slwx, srawx, srawix, srwx, stb, stbu, stbux, stbx, stfd, stfdu,
stfdux, stfdx, stfs, stfsu, stfsux, stfsx, sth, sthbrx, sthu, sthux, sthx,
stmw, stswi, stswx, stw, stwbrx, stwcx_, stwu, stwux, stwx, subfx, subfcx,
subfex, subfic, subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
sc, slwx, srawx, srawix, srwx, stb, stbu,
/// Store byte with update indexed.
///
/// [ (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.
dcbi,
@ -205,7 +334,9 @@ enum class Operation: uint8_t {
// Optional.
fresx, frsqrtex, fselx, fsqrtx, slbia, slbie, stfiwx,
//
// 64-bit only PowerPC instructions.
//
cntlzdx, divdx, divdux, extswx, fcfidx, fctidx, fctidzx, tdi, mulhdux,
ldx, sldx, ldux, td, mulhdx, ldarx, stdx, stdux, mulld, lwax, lwaux,
sradix, srdx, sradx, extsw, fsqrtsx, std, stdu, stdcx_,

View File

@ -17,6 +17,16 @@ using namespace InstructionSet::PowerPC;
@interface DingusdevPowerPCTests : XCTestCase
@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
- (void)testABDInstruction:(Instruction)instruction columns:(NSArray<NSString *> *)columns testZero:(BOOL)testZero {
@ -57,21 +67,52 @@ using namespace InstructionSet::PowerPC;
NSString *const operation = columns[2];
const auto instruction = decoder.decode(opcode);
NSLog(@"%@", line);
switch(instruction.operation) {
default:
NSAssert(FALSE, @"Didn't handle %@", line);
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) \
case Operation::x: \
XCTAssertEqualObjects(operation, @#x); \
AssertEqualOperationName(operation, @#x); \
[self testABDInstruction:instruction columns:columns testZero:YES]; \
break;
ABCz(lwzux);
ABCz(lwzx);
ABCz(lwzux);
ABCz(lbzx);
ABCz(lbzux);
ABCz(stwx);
ABCz(stwux);
ABCz(stbx);
ABCz(stbux);
ABCz(lhzx);
ABCz(lhzux);
ABCz(lhax);
ABCz(lhaux);
ABCz(sthx);
ABCz(sthux);
#undef ABCz
@ -164,7 +205,7 @@ using namespace InstructionSet::PowerPC;
if(instruction.branch_prediction_hint()) {
baseOperation = [baseOperation stringByAppendingString:@"+"];
}
XCTAssertEqualObjects(operation, baseOperation);
AssertEqualOperationName(operation, baseOperation);
}
if(instruction.bi() & ~3) {
@ -190,10 +231,10 @@ using namespace InstructionSet::PowerPC;
case Operation::bx: {
switch((instruction.aa() ? 2 : 0) | (instruction.lk() ? 1 : 0)) {
case 0: XCTAssertEqualObjects(operation, @"b"); break;
case 1: XCTAssertEqualObjects(operation, @"bl"); break;
case 2: XCTAssertEqualObjects(operation, @"ba"); break;
case 3: XCTAssertEqualObjects(operation, @"bla"); break;
case 0: AssertEqualOperationName(operation, @"b"); break;
case 1: AssertEqualOperationName(operation, @"bl"); break;
case 2: AssertEqualOperationName(operation, @"ba"); break;
case 3: AssertEqualOperationName(operation, @"bla"); break;
}
const uint32_t destination = uint32_t(std::strtol([columns[3] UTF8String], 0, 16));