mirror of
https://github.com/TomHarte/CLK.git
synced 2024-08-16 16:28:59 +00:00
Merge branch 'PowerPCTests' of github.com:TomHarte/CLK into PowerPCTests
This commit is contained in:
commit
5ec291df5c
@ -270,7 +270,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.
|
||||||
@ -292,24 +330,82 @@ 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,
|
|
||||||
|
/// 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,
|
stmw, stswi, stswx, stw, stwbrx, stwcx_, stwu,
|
||||||
|
|
||||||
/// Store word with update indexed.
|
/// Store word with update indexed.
|
||||||
/// stwux
|
|
||||||
///
|
///
|
||||||
/// rS(), rA(), rB()
|
/// [ (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,
|
stwux,
|
||||||
|
|
||||||
/// Store word indexed.
|
/// Store word indexed.
|
||||||
/// stwx
|
|
||||||
///
|
///
|
||||||
/// rS(), rA(), rB()
|
/// [ (ra()|0) + rB() ] = rS()
|
||||||
stwx, subfx, subfcx,
|
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||||
subfex, subfic, subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
|
stwx,
|
||||||
|
|
||||||
|
subfx,
|
||||||
|
|
||||||
|
/// Subtract from carrying.
|
||||||
|
/// subfc, subfc., subfco, subfco.
|
||||||
|
///
|
||||||
|
/// rD() = -rA() +rB() + 1
|
||||||
|
///
|
||||||
|
/// oe(), rc() apply.
|
||||||
|
subfcx,
|
||||||
|
subfex,
|
||||||
|
|
||||||
|
/// Subtract from immediate carrying
|
||||||
|
///
|
||||||
|
/// rD() = ~rA() + simm() + 1
|
||||||
|
subfic,
|
||||||
|
|
||||||
|
subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
|
||||||
|
|
||||||
//
|
//
|
||||||
// MARK: - 32-bit, supervisor level.
|
// MARK: - 32-bit, supervisor level.
|
||||||
@ -463,7 +559,7 @@ struct Instruction {
|
|||||||
/// Whether to compare 32-bit or 64-bit numbers [for 64-bit implementations only]; @c 0 or @c non-0.
|
/// Whether to compare 32-bit or 64-bit numbers [for 64-bit implementations only]; @c 0 or @c non-0.
|
||||||
uint32_t l() const { return opcode & 0x200000; }
|
uint32_t l() const { return opcode & 0x200000; }
|
||||||
/// Enables setting of OV and SO in the XER; @c 0 or @c non-0.
|
/// Enables setting of OV and SO in the XER; @c 0 or @c non-0.
|
||||||
uint32_t oe() const { return opcode & 0x800; }
|
uint32_t oe() const { return opcode & 0x400; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sanity check on Instruction size.
|
// Sanity check on Instruction size.
|
||||||
|
@ -790,12 +790,13 @@ template <bool has_fdc> class ConcreteMachine:
|
|||||||
bool has_amsdos = false;
|
bool has_amsdos = false;
|
||||||
ROM::Name firmware, basic;
|
ROM::Name firmware, basic;
|
||||||
|
|
||||||
|
using Model = Analyser::Static::AmstradCPC::Target::Model;
|
||||||
switch(target.model) {
|
switch(target.model) {
|
||||||
case Analyser::Static::AmstradCPC::Target::Model::CPC464:
|
case Model::CPC464:
|
||||||
firmware = ROM::Name::CPC464Firmware;
|
firmware = ROM::Name::CPC464Firmware;
|
||||||
basic = ROM::Name::CPC464BASIC;
|
basic = ROM::Name::CPC464BASIC;
|
||||||
break;
|
break;
|
||||||
case Analyser::Static::AmstradCPC::Target::Model::CPC664:
|
case Model::CPC664:
|
||||||
firmware = ROM::Name::CPC664Firmware;
|
firmware = ROM::Name::CPC664Firmware;
|
||||||
basic = ROM::Name::CPC664BASIC;
|
basic = ROM::Name::CPC664BASIC;
|
||||||
has_amsdos = true;
|
has_amsdos = true;
|
||||||
@ -838,6 +839,9 @@ template <bool has_fdc> class ConcreteMachine:
|
|||||||
read_pointers_[2] = write_pointers_[2];
|
read_pointers_[2] = write_pointers_[2];
|
||||||
read_pointers_[3] = roms_[upper_rom_].data();
|
read_pointers_[3] = roms_[upper_rom_].data();
|
||||||
|
|
||||||
|
// Set total RAM available.
|
||||||
|
has_128k_ = target.model == Model::CPC6128;
|
||||||
|
|
||||||
// Type whatever is required.
|
// Type whatever is required.
|
||||||
if(!target.loading_command.empty()) {
|
if(!target.loading_command.empty()) {
|
||||||
type_string(target.loading_command);
|
type_string(target.loading_command);
|
||||||
@ -1248,20 +1252,20 @@ template <bool has_fdc> class ConcreteMachine:
|
|||||||
HalfCycles crtc_counter_;
|
HalfCycles crtc_counter_;
|
||||||
HalfCycles half_cycles_since_ay_update_;
|
HalfCycles half_cycles_since_ay_update_;
|
||||||
|
|
||||||
bool fdc_is_sleeping_;
|
bool fdc_is_sleeping_ = false;
|
||||||
bool tape_player_is_sleeping_;
|
bool tape_player_is_sleeping_ = false;
|
||||||
bool has_128k_;
|
bool has_128k_ = false;
|
||||||
|
|
||||||
enum ROMType: int {
|
enum ROMType: int {
|
||||||
AMSDOS = 0, OS = 1, BASIC = 2
|
AMSDOS = 0, OS = 1, BASIC = 2
|
||||||
};
|
};
|
||||||
std::vector<uint8_t> roms_[3];
|
std::vector<uint8_t> roms_[3];
|
||||||
bool upper_rom_is_paged_;
|
bool upper_rom_is_paged_ = false;
|
||||||
ROMType upper_rom_;
|
ROMType upper_rom_;
|
||||||
|
|
||||||
uint8_t *ram_pages_[4];
|
uint8_t *ram_pages_[4]{};
|
||||||
const uint8_t *read_pointers_[4];
|
const uint8_t *read_pointers_[4]{};
|
||||||
uint8_t *write_pointers_[4];
|
uint8_t *write_pointers_[4]{};
|
||||||
|
|
||||||
KeyboardState key_state_;
|
KeyboardState key_state_;
|
||||||
AmstradCPC::KeyboardMapper keyboard_mapper_;
|
AmstradCPC::KeyboardMapper keyboard_mapper_;
|
||||||
|
@ -17,15 +17,36 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertEqualOperationNameOE(NSString *lhs, Instruction instruction, NSString *rhs) {
|
||||||
|
XCTAssert([lhs characterAtIndex:lhs.length - 1] == 'x');
|
||||||
|
lhs = [lhs substringToIndex:lhs.length - 1];
|
||||||
|
if(instruction.oe()) lhs = [lhs stringByAppendingString:@"o"];
|
||||||
|
if(instruction.rc()) lhs = [lhs stringByAppendingString:@"."];
|
||||||
|
XCTAssertEqualObjects(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@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 {
|
||||||
NSString *const rA = (instruction.rA() || !testZero) ? [NSString stringWithFormat:@"r%d", instruction.rA()] : @"0";
|
NSString *const rA = (instruction.rA() || !testZero) ? [NSString stringWithFormat:@"r%d", instruction.rA()] : @"0";
|
||||||
NSString *const rB = [NSString stringWithFormat:@"r%d", instruction.rB()];
|
|
||||||
NSString *const rD = [NSString stringWithFormat:@"r%d", instruction.rD()];
|
NSString *const rD = [NSString stringWithFormat:@"r%d", instruction.rD()];
|
||||||
XCTAssertEqualObjects(rD, columns[3]);
|
XCTAssertEqualObjects(rD, columns[3]);
|
||||||
XCTAssertEqualObjects(rA, columns[4]);
|
XCTAssertEqualObjects(rA, columns[4]);
|
||||||
|
|
||||||
|
if([columns count] > 5) {
|
||||||
|
NSString *const rB = [NSString stringWithFormat:@"r%d", instruction.rB()];
|
||||||
XCTAssertEqualObjects(rB, columns[5]);
|
XCTAssertEqualObjects(rB, columns[5]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testDecoding {
|
- (void)testDecoding {
|
||||||
@ -57,24 +78,73 @@ 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
|
||||||
|
|
||||||
|
#define ABD(x) \
|
||||||
|
case Operation::x: \
|
||||||
|
AssertEqualOperationNameOE(@#x, instruction, operation); \
|
||||||
|
[self testABDInstruction:instruction columns:columns testZero:NO]; \
|
||||||
|
break;
|
||||||
|
|
||||||
|
ABD(subfcx);
|
||||||
|
ABD(subfx);
|
||||||
|
ABD(negx);
|
||||||
|
ABD(subfex);
|
||||||
|
ABD(subfzex);
|
||||||
|
ABD(subfmex);
|
||||||
|
ABD(dozx);
|
||||||
|
ABD(absx);
|
||||||
|
ABD(nabsx);
|
||||||
|
|
||||||
|
#undef ABD
|
||||||
|
|
||||||
case Operation::bcx:
|
case Operation::bcx:
|
||||||
case Operation::bclrx:
|
case Operation::bclrx:
|
||||||
case Operation::bcctrx: {
|
case Operation::bcctrx: {
|
||||||
@ -164,7 +234,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 +260,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));
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -17,7 +18,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
#ifndef MacintoshVolume_hpp
|
#ifndef MacintoshVolume_hpp
|
||||||
#define MacintoshVolume_hpp
|
#define MacintoshVolume_hpp
|
||||||
|
|
||||||
#include <vector>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <vector>
|
||||||
|
|
||||||
namespace Storage {
|
namespace Storage {
|
||||||
namespace MassStorage {
|
namespace MassStorage {
|
||||||
|
Loading…
Reference in New Issue
Block a user