mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-06 10:38:16 +00:00
Introduces a first test of PowerPC decoding.
Corrected as a result: the bcx conditional, that stdu is 64-bit only, extraction of the li field.
This commit is contained in:
parent
1a3effc692
commit
c934e22cee
@ -185,6 +185,7 @@
|
||||
4B3BF5B01F146265005B6C36 /* CSW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BF5AE1F146264005B6C36 /* CSW.cpp */; };
|
||||
4B3F76AE25A0196100178AEC /* x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F76AD25A0196100178AEC /* x86.cpp */; };
|
||||
4B3F76AF25A0196100178AEC /* x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F76AD25A0196100178AEC /* x86.cpp */; };
|
||||
4B3F76B925A1635300178AEC /* PowerPCDecoderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F76B825A1635300178AEC /* PowerPCDecoderTests.mm */; };
|
||||
4B3FCC40201EC24200960631 /* MultiMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FCC3F201EC24200960631 /* MultiMachine.cpp */; };
|
||||
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */; };
|
||||
4B448E811F1C45A00009ABD6 /* TZX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B448E7F1F1C45A00009ABD6 /* TZX.cpp */; };
|
||||
@ -1081,6 +1082,7 @@
|
||||
4B3F769E259FCE0F00178AEC /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
4B3F76AC25A0196100178AEC /* x86.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = x86.hpp; sourceTree = "<group>"; };
|
||||
4B3F76AD25A0196100178AEC /* x86.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x86.cpp; sourceTree = "<group>"; };
|
||||
4B3F76B825A1635300178AEC /* PowerPCDecoderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PowerPCDecoderTests.mm; sourceTree = "<group>"; };
|
||||
4B3FCC3E201EC24200960631 /* MultiMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MultiMachine.hpp; sourceTree = "<group>"; };
|
||||
4B3FCC3F201EC24200960631 /* MultiMachine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiMachine.cpp; sourceTree = "<group>"; };
|
||||
4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CPM.cpp; path = Parsers/CPM.cpp; sourceTree = "<group>"; };
|
||||
@ -3479,6 +3481,7 @@
|
||||
4BC0CB272446BC7B00A79DBB /* OPLTests.mm */,
|
||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
|
||||
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
|
||||
4B3F76B825A1635300178AEC /* PowerPCDecoderTests.mm */,
|
||||
4BE76CF822641ED300ACD6FA /* QLTests.mm */,
|
||||
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
|
||||
4B1D08051E0F7A1100763741 /* TimeTests.mm */,
|
||||
@ -4919,6 +4922,7 @@
|
||||
4B778F4223A5F1A70000D260 /* MemoryFuzzer.cpp in Sources */,
|
||||
4B778F0123A5EBA00000D260 /* MacintoshIMG.cpp in Sources */,
|
||||
4BFF1D3D2235C3C100838EA1 /* EmuTOSTests.mm in Sources */,
|
||||
4B3F76B925A1635300178AEC /* PowerPCDecoderTests.mm in Sources */,
|
||||
4B778F0A23A5EC150000D260 /* TapePRG.cpp in Sources */,
|
||||
4B778F0823A5EC150000D260 /* CSW.cpp in Sources */,
|
||||
4B778F5323A5F23F0000D260 /* SerialBus.cpp in Sources */,
|
||||
|
203
OSBindings/Mac/Clock SignalTests/PowerPCDecoderTests.mm
Normal file
203
OSBindings/Mac/Clock SignalTests/PowerPCDecoderTests.mm
Normal file
@ -0,0 +1,203 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
@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 {
|
||||
CPU::Decoder::PowerPC::Instruction instructions[32];
|
||||
}
|
||||
|
||||
- (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]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testStream1 {
|
||||
const uint32_t stream[] = {
|
||||
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,
|
||||
};
|
||||
[self decode:stream];
|
||||
|
||||
// addic r23,r14,-4187
|
||||
XCTAssertEqual(instructions[0].operation, Operation::addic);
|
||||
XCTAssertEqual(instructions[0].rD(), 23);
|
||||
XCTAssertEqual(instructions[0].rA(), 14);
|
||||
XCTAssertEqual(instructions[0].simm(), -4187);
|
||||
|
||||
// lfs f23,1926(r14)
|
||||
XCTAssertEqual(instructions[1].operation, Operation::lfs);
|
||||
XCTAssertEqual(instructions[1].frD(), 23);
|
||||
XCTAssertEqual(instructions[1].rA(), 14);
|
||||
XCTAssertEqual(instructions[1].d(), 1926);
|
||||
|
||||
// lwz r6,21804(r14)
|
||||
XCTAssertEqual(instructions[2].operation, Operation::lwz);
|
||||
XCTAssertEqual(instructions[2].rD(), 6);
|
||||
XCTAssertEqual(instructions[2].rA(), 14);
|
||||
XCTAssertEqual(instructions[2].d(), 21804);
|
||||
|
||||
// lbz r6,-4054(r21)
|
||||
XCTAssertEqual(instructions[3].operation, Operation::lbz);
|
||||
XCTAssertEqual(instructions[3].rD(), 6);
|
||||
XCTAssertEqual(instructions[3].rA(), 21);
|
||||
XCTAssertEqual(instructions[3].d(), -4054);
|
||||
|
||||
// .long 0xf8c2e801
|
||||
// .long 0xe83d5cdf
|
||||
// .long 0x7fa51fbb
|
||||
XCTAssertEqual(instructions[4].operation, Operation::Undefined);
|
||||
XCTAssertEqual(instructions[5].operation, Operation::Undefined);
|
||||
XCTAssertEqual(instructions[6].operation, Operation::Undefined);
|
||||
|
||||
// lha r22,-22352(r14)
|
||||
XCTAssertEqual(instructions[7].operation, Operation::lha);
|
||||
XCTAssertEqual(instructions[7].rD(), 22);
|
||||
XCTAssertEqual(instructions[7].rA(), 14);
|
||||
XCTAssertEqual(instructions[7].d(), -22352);
|
||||
|
||||
// .long 0x7d4d4d21
|
||||
// .long 0x1314cf89
|
||||
// .long 0x47e0014b
|
||||
XCTAssertEqual(instructions[8].operation, Operation::Undefined);
|
||||
XCTAssertEqual(instructions[9].operation, Operation::Undefined);
|
||||
// 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)
|
||||
XCTAssertEqual(instructions[11].operation, Operation::stfdu);
|
||||
XCTAssertEqual(instructions[11].frS(), 27);
|
||||
XCTAssertEqual(instructions[11].rA(), 7);
|
||||
XCTAssertEqual(instructions[11].d(), 22125);
|
||||
|
||||
// .long 0xfb29a33e
|
||||
XCTAssertEqual(instructions[12].operation, Operation::Undefined);
|
||||
|
||||
// addic r9,r12,-16557
|
||||
XCTAssertEqual(instructions[13].operation, Operation::addic);
|
||||
XCTAssertEqual(instructions[13].rD(), 9);
|
||||
XCTAssertEqual(instructions[13].rA(), 12);
|
||||
XCTAssertEqual(instructions[13].simm(), -16557);
|
||||
|
||||
// andi. r15,r3,6677
|
||||
XCTAssertEqual(instructions[14].operation, Operation::andi_);
|
||||
XCTAssertEqual(instructions[14].rA(), 15);
|
||||
XCTAssertEqual(instructions[14].rS(), 3);
|
||||
XCTAssertEqual(instructions[14].uimm(), 6677);
|
||||
|
||||
// lha r3,28689(r27)
|
||||
XCTAssertEqual(instructions[15].operation, Operation::lha);
|
||||
XCTAssertEqual(instructions[15].rD(), 3);
|
||||
XCTAssertEqual(instructions[15].rA(), 27);
|
||||
XCTAssertEqual(instructions[15].d(), 28689);
|
||||
|
||||
// subfic r8,r7,2316
|
||||
XCTAssertEqual(instructions[16].operation, Operation::subfic);
|
||||
XCTAssertEqual(instructions[16].rD(), 8);
|
||||
XCTAssertEqual(instructions[16].rA(), 7);
|
||||
XCTAssertEqual(instructions[16].simm(), 2316);
|
||||
|
||||
// lfdu f16,-27810(r4)
|
||||
XCTAssertEqual(instructions[17].operation, Operation::lfdu);
|
||||
XCTAssertEqual(instructions[17].frD(), 16);
|
||||
XCTAssertEqual(instructions[17].rA(), 4);
|
||||
XCTAssertEqual(instructions[17].d(), -27810);
|
||||
|
||||
// oris r14,r1,17994
|
||||
XCTAssertEqual(instructions[18].operation, Operation::oris);
|
||||
XCTAssertEqual(instructions[18].rA(), 14);
|
||||
XCTAssertEqual(instructions[18].rS(), 1);
|
||||
XCTAssertEqual(instructions[18].uimm(), 17994);
|
||||
|
||||
// stw r24,-28998(r30)
|
||||
XCTAssertEqual(instructions[19].operation, Operation::stw);
|
||||
XCTAssertEqual(instructions[19].rS(), 24);
|
||||
XCTAssertEqual(instructions[19].rA(), 30);
|
||||
XCTAssertEqual(instructions[19].d(), -28998);
|
||||
|
||||
// .long 0xee396d5b
|
||||
XCTAssertEqual(instructions[20].operation, Operation::Undefined);
|
||||
|
||||
// bl 0x01011890 [disassmebled at address 0x54]
|
||||
XCTAssertEqual(instructions[21].operation, Operation::bx);
|
||||
XCTAssertEqual(instructions[21].li() + 0x54, 0x01011890);
|
||||
XCTAssertTrue(instructions[21].lk());
|
||||
XCTAssertFalse(instructions[21].aa());
|
||||
|
||||
// addic r14,r12,-21862
|
||||
XCTAssertEqual(instructions[22].operation, Operation::addic);
|
||||
XCTAssertEqual(instructions[22].rD(), 14);
|
||||
XCTAssertEqual(instructions[22].rA(), 12);
|
||||
XCTAssertEqual(instructions[22].simm(), -21862);
|
||||
|
||||
// .long 0x42b61a86 [10101]
|
||||
XCTAssertEqual(instructions[23].operation, Operation::Undefined);
|
||||
|
||||
// mulli r22,r20,29981
|
||||
XCTAssertEqual(instructions[24].operation, Operation::mulli);
|
||||
XCTAssertEqual(instructions[24].rD(), 22);
|
||||
XCTAssertEqual(instructions[24].rA(), 20);
|
||||
XCTAssertEqual(instructions[24].simm(), 29981);
|
||||
|
||||
// lwzu r21,30436(r15)
|
||||
XCTAssertEqual(instructions[25].operation, Operation::lwzu);
|
||||
XCTAssertEqual(instructions[25].rD(), 21);
|
||||
XCTAssertEqual(instructions[25].rA(), 15);
|
||||
XCTAssertEqual(instructions[25].d(), 30436);
|
||||
|
||||
// .long 0x151405a9
|
||||
XCTAssertEqual(instructions[26].operation, Operation::Undefined);
|
||||
|
||||
// lfd f16,-16363(r10)
|
||||
XCTAssertEqual(instructions[27].operation, Operation::lfd);
|
||||
XCTAssertEqual(instructions[27].frD(), 16);
|
||||
XCTAssertEqual(instructions[27].rA(), 10);
|
||||
XCTAssertEqual(instructions[27].d(), -16363);
|
||||
|
||||
// ori r29,r6,8093
|
||||
XCTAssertEqual(instructions[28].operation, Operation::ori);
|
||||
XCTAssertEqual(instructions[28].rA(), 29);
|
||||
XCTAssertEqual(instructions[28].rS(), 6);
|
||||
XCTAssertEqual(instructions[28].uimm(), 8093);
|
||||
|
||||
// .long 0xecff44f6
|
||||
// .long 0xf2c1110e
|
||||
XCTAssertEqual(instructions[29].operation, Operation::Undefined);
|
||||
XCTAssertEqual(instructions[30].operation, Operation::Undefined);
|
||||
|
||||
// stb r21,25915(r6)
|
||||
XCTAssertEqual(instructions[31].operation, Operation::stb);
|
||||
XCTAssertEqual(instructions[31].rS(), 21);
|
||||
XCTAssertEqual(instructions[31].rA(), 6);
|
||||
XCTAssertEqual(instructions[31].d(), 25915);
|
||||
}
|
||||
|
||||
@end
|
@ -58,7 +58,17 @@ Instruction Decoder::decode(uint32_t opcode) {
|
||||
Bind(Six(0b001000), subfic);
|
||||
Bind(Six(0b001100), addic); Bind(Six(0b001101), addic_);
|
||||
Bind(Six(0b001110), addi); Bind(Six(0b001111), addis);
|
||||
Bind(Six(0b010000), bcx);
|
||||
case Six(0b010000): {
|
||||
// This might be a bcx, but check for a valid bo field.
|
||||
switch((opcode >> 21) & 0x1f) {
|
||||
case 0: case 1: case 2: case 3: case 4: case 5:
|
||||
case 8: case 9: case 10: case 11: case 12: case 13:
|
||||
case 16: case 17: case 18: case 19: case 20:
|
||||
return Instruction(Operation::bcx, opcode);
|
||||
|
||||
default: return Instruction(opcode);
|
||||
}
|
||||
} break;
|
||||
Bind(Six(0b010010), bx);
|
||||
Bind(Six(0b010100), rlwimix);
|
||||
Bind(Six(0b010101), rlwinmx);
|
||||
@ -317,7 +327,9 @@ Instruction Decoder::decode(uint32_t opcode) {
|
||||
// std and stdu
|
||||
switch(opcode & 0b111111'00'00000000'00000000'000000'11){
|
||||
case 0b111110'00'00000000'00000000'000000'00: return Instruction(Operation::std, opcode);
|
||||
case 0b111110'00'00000000'00000000'000000'01: return Instruction(Operation::stdu, opcode);
|
||||
case 0b111110'00'00000000'00000000'000000'01:
|
||||
if(is64bit()) return Instruction(Operation::stdu, opcode);
|
||||
return Instruction(opcode);
|
||||
}
|
||||
|
||||
// sc
|
||||
|
@ -75,15 +75,16 @@ enum class Operation: uint8_t {
|
||||
only the operation has been decoded ahead of time; all other fields are decoded on-demand.
|
||||
*/
|
||||
struct Instruction {
|
||||
const Operation operation = Operation::Undefined;
|
||||
const bool is_supervisor = false;
|
||||
const uint32_t opcode = 0;
|
||||
Operation operation = Operation::Undefined;
|
||||
bool is_supervisor = false;
|
||||
uint32_t opcode = 0;
|
||||
|
||||
// PowerPC uses a fixed-size instruction word.
|
||||
size_t size() {
|
||||
int size() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
Instruction() {}
|
||||
Instruction(uint32_t opcode) : opcode(opcode) {}
|
||||
Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {}
|
||||
|
||||
@ -177,7 +178,7 @@ struct Instruction {
|
||||
0x0000'0000,
|
||||
0xfc00'0000
|
||||
};
|
||||
const uint32_t value = (opcode & 0x3fff'fffc) | extensions[(opcode >> 26) & 1];
|
||||
const uint32_t value = (opcode & 0x03ff'fffc) | extensions[(opcode >> 26) & 1];
|
||||
return int32_t(value);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user