2021-01-03 03:47:42 +00:00
|
|
|
//
|
|
|
|
// PowerPCDecoderTests.m
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 02/01/2021.
|
|
|
|
// Copyright 2021 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
|
|
|
|
#include "../../../Processors/Decoders/PowerPC/PowerPC.hpp"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
using Operation = CPU::Decoder::PowerPC::Operation;
|
2021-01-03 16:14:30 +00:00
|
|
|
using Instruction = CPU::Decoder::PowerPC::Instruction;
|
2021-01-03 03:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@interface PowerPCDecoderTests : XCTestCase
|
|
|
|
@end
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Tests PowerPC decoding by throwing a bunch of randomly-generated
|
|
|
|
word streams and checking that the result matches what I got from a
|
|
|
|
disassembler elsewhere.
|
|
|
|
*/
|
|
|
|
@implementation PowerPCDecoderTests {
|
2021-01-03 16:14:30 +00:00
|
|
|
Instruction instructions[32];
|
2021-01-03 03:47:42 +00:00
|
|
|
}
|
|
|
|
|
2021-01-03 16:14:30 +00:00
|
|
|
// MARK: - Specific instruction asserts.
|
|
|
|
|
|
|
|
- (void)assertUndefined:(Instruction &)instruction {
|
|
|
|
XCTAssertEqual(instruction.operation, Operation::Undefined);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation rD:(int)rD rA:(int)rA simm:(int)simm {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.rD(), rD);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.simm(), simm);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation rD:(int)rD rA:(int)rA d:(int)d {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.rD(), rD);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.d(), d);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation rA:(int)rA rS:(int)rS uimm:(int)uimm {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.rS(), rS);
|
|
|
|
XCTAssertEqual(instruction.uimm(), uimm);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation rS:(int)rS rA:(int)rA d:(int)d {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.rS(), rS);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.d(), d);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation frD:(int)frD rA:(int)rA d:(int)d {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.frD(), frD);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.d(), d);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation frS:(int)frS rA:(int)rA d:(int)d {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.frS(), frS);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.d(), d);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation li:(int)li lk:(BOOL)lk aa:(BOOL)aa {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.li(), li);
|
|
|
|
XCTAssertEqual(!!instruction.lk(), lk);
|
|
|
|
XCTAssertEqual(!!instruction.aa(), aa);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation rA:(int)rA rS:(int)rS rB:(int)rB mb:(int)mb me:(int)me rc:(BOOL)rc {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.rS(), rS);
|
|
|
|
XCTAssertEqual(instruction.rB(), rB);
|
|
|
|
XCTAssertEqual(instruction.mb(), mb);
|
|
|
|
XCTAssertEqual(instruction.me(), me);
|
|
|
|
XCTAssertEqual(!!instruction.rc(), rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)assert:(Instruction &)instruction operation:(Operation)operation to:(int)to rA:(int)rA simm:(int)simm {
|
|
|
|
XCTAssertEqual(instruction.operation, operation);
|
|
|
|
XCTAssertEqual(instruction.to(), to);
|
|
|
|
XCTAssertEqual(instruction.rA(), rA);
|
|
|
|
XCTAssertEqual(instruction.simm(), simm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Decoder
|
|
|
|
|
2021-01-03 03:47:42 +00:00
|
|
|
- (void)decode:(const uint32_t *)stream {
|
|
|
|
CPU::Decoder::PowerPC::Decoder decoder(CPU::Decoder::PowerPC::Model::MPC601);
|
|
|
|
for(int c = 0; c < 32; c++) {
|
|
|
|
instructions[c] = decoder.decode(stream[c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-03 16:14:30 +00:00
|
|
|
// MARK: - Tests
|
|
|
|
|
|
|
|
- (void)testSequence1 {
|
|
|
|
const uint32_t sequence[] = {
|
2021-01-03 03:47:42 +00:00
|
|
|
0x32eeefa5, 0xc2ee0786, 0x80ce552c, 0x88d5f02a,
|
|
|
|
0xf8c2e801, 0xe83d5cdf, 0x7fa51fbb, 0xaacea8b0,
|
|
|
|
0x7d4d4d21, 0x1314cf89, 0x47e0014b, 0xdf67566d,
|
|
|
|
0xfb29a33e, 0x312cbf53, 0x706f1a15, 0xa87b7011,
|
|
|
|
0x2107090c, 0xce04935e, 0x642e464a, 0x931e8eba,
|
|
|
|
0xee396d5b, 0x4901183d, 0x31ccaa9a, 0x42b61a86,
|
|
|
|
0x1ed4751d, 0x86af76e4, 0x151405a9, 0xca0ac015,
|
|
|
|
0x60dd1f9d, 0xecff44f6, 0xf2c1110e, 0x9aa6653b,
|
|
|
|
};
|
2021-01-03 16:14:30 +00:00
|
|
|
[self decode:sequence];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// addic r23,r14,-4187
|
|
|
|
// lfs f23,1926(r14)
|
|
|
|
// lwz r6,21804(r14)
|
|
|
|
// lbz r6,-4054(r21)
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assert:instructions[0] operation:Operation::addic rD:23 rA:14 simm:-4187];
|
|
|
|
[self assert:instructions[1] operation:Operation::lfs frD:23 rA:14 d:1926];
|
|
|
|
[self assert:instructions[2] operation:Operation::lwz rD:6 rA:14 d:21804];
|
|
|
|
[self assert:instructions[3] operation:Operation::lbz rD:6 rA:21 d:-4054];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// .long 0xf8c2e801
|
|
|
|
// .long 0xe83d5cdf
|
|
|
|
// .long 0x7fa51fbb
|
|
|
|
// lha r22,-22352(r14)
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assertUndefined:instructions[4]];
|
|
|
|
[self assertUndefined:instructions[5]];
|
|
|
|
[self assertUndefined:instructions[6]];
|
|
|
|
[self assert:instructions[7] operation:Operation::lha rD:22 rA:14 d:-22352];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// .long 0x7d4d4d21
|
|
|
|
// .long 0x1314cf89
|
|
|
|
// .long 0x47e0014b
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assertUndefined:instructions[8]];
|
|
|
|
[self assertUndefined:instructions[9]];
|
2021-01-03 03:47:42 +00:00
|
|
|
// CLK decodes this as sc because it ignores reserved bits; the disassembler
|
|
|
|
// I used checks the reserved bits. For now: don't test.
|
|
|
|
// XCTAssertEqual(instructions[10].operation, Operation::Undefined);
|
|
|
|
|
|
|
|
// stfdu f27,22125(r7)
|
|
|
|
// .long 0xfb29a33e
|
|
|
|
// addic r9,r12,-16557
|
|
|
|
// andi. r15,r3,6677
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assert:instructions[11] operation:Operation::stfdu frS:27 rA:7 d:22125];
|
|
|
|
[self assertUndefined:instructions[12]];
|
|
|
|
[self assert:instructions[13] operation:Operation::addic rD:9 rA:12 simm:-16557];
|
|
|
|
[self assert:instructions[14] operation:Operation::andi_ rA:15 rS:3 uimm:6677];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// lha r3,28689(r27)
|
|
|
|
// subfic r8,r7,2316
|
|
|
|
// lfdu f16,-27810(r4)
|
|
|
|
// oris r14,r1,17994
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assert:instructions[15] operation:Operation::lha rD:3 rA:27 d:28689];
|
|
|
|
[self assert:instructions[16] operation:Operation::subfic rD:8 rA:7 simm:2316];
|
|
|
|
[self assert:instructions[17] operation:Operation::lfdu frD:16 rA:4 d:-27810];
|
|
|
|
[self assert:instructions[18] operation:Operation::oris rA:14 rS:1 uimm:17994];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// stw r24,-28998(r30)
|
|
|
|
// .long 0xee396d5b
|
|
|
|
// bl 0x01011890 [disassmebled at address 0x54]
|
|
|
|
// addic r14,r12,-21862
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assert:instructions[19] operation:Operation::stw rS:24 rA:30 d:-28998];
|
|
|
|
[self assertUndefined:instructions[20]];
|
|
|
|
[self assert:instructions[21] operation:Operation::bx li:0x01011890 - 0x54 lk:TRUE aa:FALSE];
|
|
|
|
[self assert:instructions[22] operation:Operation::addic rD:14 rA:12 simm:-21862];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// .long 0x42b61a86 [10101]
|
|
|
|
// mulli r22,r20,29981
|
|
|
|
// lwzu r21,30436(r15)
|
|
|
|
// .long 0x151405a9
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assertUndefined:instructions[23]];
|
|
|
|
[self assert:instructions[24] operation:Operation::mulli rD:22 rA:20 simm:29981];
|
|
|
|
[self assert:instructions[25] operation:Operation::lwzu rD:21 rA:15 d:30436];
|
|
|
|
[self assertUndefined:instructions[26]];
|
2021-01-03 03:47:42 +00:00
|
|
|
|
|
|
|
// lfd f16,-16363(r10)
|
|
|
|
// ori r29,r6,8093
|
|
|
|
// .long 0xecff44f6
|
|
|
|
// .long 0xf2c1110e
|
|
|
|
// stb r21,25915(r6)
|
2021-01-03 16:14:30 +00:00
|
|
|
[self assert:instructions[27] operation:Operation::lfd frD:16 rA:10 d:-16363];
|
|
|
|
[self assert:instructions[28] operation:Operation::ori rA:29 rS:6 uimm:8093];
|
|
|
|
[self assertUndefined:instructions[29]];
|
|
|
|
[self assertUndefined:instructions[30]];
|
|
|
|
[self assert:instructions[31] operation:Operation::stb rS:21 rA:6 d:25915];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testSequence2 {
|
|
|
|
const uint32_t sequence[] = {
|
|
|
|
0x90252dae, 0x7429ee14, 0x618935bc, 0xd6c94af0,
|
|
|
|
0xba1d295f, 0x649e3869, 0x6def742c, 0x5c64cdce,
|
|
|
|
0x762d59ee, 0x565c8189, 0xc7c59f81, 0xce1157fd,
|
|
|
|
0xc86aef59, 0x81325882, 0x1336fad6, 0xe1ddfa2b,
|
|
|
|
0x18c60357, 0x4c122cb5, 0xccb1f749, 0xdbdcebc3,
|
|
|
|
0x0fc60187, 0x117eb911, 0x80334c43, 0xe65371e8,
|
|
|
|
0xa047c94d, 0xe671dd0b, 0xe07992bb, 0x6a332fe8,
|
|
|
|
0xfc361c6b, 0x5e8b5a28, 0xb2b64a22, 0x045dd156,
|
|
|
|
};
|
|
|
|
[self decode:sequence];
|
|
|
|
|
|
|
|
// stw r1,11694(r5)
|
|
|
|
// andis. r9,r1,60948
|
|
|
|
// ori r9,r12,13756
|
|
|
|
// stfsu f22,19184(r9)
|
|
|
|
[self assert:instructions[0] operation:Operation::stw rS:1 rA:5 d:11694];
|
|
|
|
[self assert:instructions[1] operation:Operation::andis_ rA:9 rS:1 uimm:60948];
|
|
|
|
[self assert:instructions[2] operation:Operation::ori rA:9 rS:12 uimm:13756];
|
|
|
|
[self assert:instructions[3] operation:Operation::stfsu frS:22 rA:9 d:19184];
|
|
|
|
|
|
|
|
// lmw r16,10591(r29)
|
|
|
|
// oris r30,r4,14441
|
|
|
|
// xoris r15,r15,29740
|
|
|
|
// rlwnm r4,r3,r25,23,7
|
|
|
|
[self assert:instructions[4] operation:Operation::lmw rD:16 rA:29 d:10591];
|
|
|
|
[self assert:instructions[5] operation:Operation::oris rA:30 rS:4 uimm:14441];
|
|
|
|
[self assert:instructions[6] operation:Operation::xoris rA:15 rS:15 uimm:29740];
|
|
|
|
[self assert:instructions[7] operation:Operation::rlwnmx rA:4 rS:3 rB:25 mb:23 me:7 rc:FALSE];
|
|
|
|
|
|
|
|
// andis. r13,r17,23022
|
|
|
|
// rlwinm. r28,r18,16,6,4
|
|
|
|
// lfsu f30,-24703(r5)
|
|
|
|
// lfdu f16,22525(r17)
|
|
|
|
[self assert:instructions[8] operation:Operation::andis_ rA:13 rS:17 uimm:23022];
|
|
|
|
[self assert:instructions[9] operation:Operation::rlwinmx rA:28 rS:18 rB:16 mb:6 me:4 rc:TRUE];
|
|
|
|
[self assert:instructions[10] operation:Operation::lfsu frD:30 rA:5 d:-24703];
|
|
|
|
[self assert:instructions[11] operation:Operation::lfdu frD:16 rA:17 d:22525];
|
|
|
|
|
|
|
|
// lfd f3,-4263(r10)
|
|
|
|
// lwz r9,22658(r18)
|
|
|
|
// .long 0x1336fad6
|
|
|
|
// .long 0xe1ddfa2b
|
|
|
|
[self assert:instructions[12] operation:Operation::lfd frD:3 rA:10 d:-4263];
|
|
|
|
[self assert:instructions[13] operation:Operation::lwz rD:9 rA:18 d:22658];
|
|
|
|
[self assertUndefined:instructions[14]];
|
|
|
|
[self assertUndefined:instructions[15]];
|
|
|
|
|
|
|
|
// .long 0x18c60357
|
|
|
|
// .long 0x4c122cb5
|
|
|
|
// lfdu f5,-2231(r17)
|
|
|
|
// stfd f30,-5181(r28)
|
|
|
|
[self assertUndefined:instructions[16]];
|
|
|
|
[self assertUndefined:instructions[17]];
|
|
|
|
[self assert:instructions[18] operation:Operation::lfdu frD:5 rA:17 d:-2231];
|
|
|
|
[self assert:instructions[19] operation:Operation::stfd frD:30 rA:28 d:-5181];
|
|
|
|
|
|
|
|
// twi 30,r6,391
|
|
|
|
// .long 0x117eb911
|
|
|
|
// lwz r1,19523(r19)
|
|
|
|
// .long 0xe65371e8
|
|
|
|
[self assert:instructions[20] operation:Operation::twi to:30 rA:6 simm:391];
|
|
|
|
[self assertUndefined:instructions[21]];
|
|
|
|
[self assert:instructions[22] operation:Operation::lwz rD:1 rA:19 d:19523];
|
|
|
|
[self assertUndefined:instructions[23]];
|
|
|
|
|
|
|
|
// lhz r2,-14003(r7)
|
|
|
|
// .long 0xe671dd0b
|
|
|
|
// .long 0xe07992bb
|
|
|
|
// xori r19,r17,12264
|
|
|
|
[self assert:instructions[24] operation:Operation::lhz rD:2 rA:7 d:-14003];
|
|
|
|
[self assertUndefined:instructions[25]];
|
|
|
|
[self assertUndefined:instructions[26]];
|
|
|
|
[self assert:instructions[27] operation:Operation::xori rA:19 rS:17 uimm:12264];
|
|
|
|
|
|
|
|
// .long 0xfc361c6b
|
|
|
|
// rlwnm r11,r20,r11,8,20
|
|
|
|
// sth r21,18978(r22)
|
|
|
|
// .long 0x45dd156
|
|
|
|
// [self assertUndefined:instructions[28]]; // Disabled due to reserved field; I'm decoding this as faddx.
|
|
|
|
[self assert:instructions[29] operation:Operation::rlwnmx rA:11 rS:20 rB:11 mb:8 me:20 rc:FALSE];
|
|
|
|
[self assert:instructions[30] operation:Operation::sth rS:21 rA:22 d:18978];
|
|
|
|
[self assertUndefined:instructions[31]];
|
2021-01-03 03:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|