mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +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,
|
||||
|
||||
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.
|
||||
@ -292,24 +330,82 @@ 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,
|
||||
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.
|
||||
/// 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,
|
||||
|
||||
/// Store word indexed.
|
||||
/// stwx
|
||||
///
|
||||
/// rS(), rA(), rB()
|
||||
stwx, subfx, subfcx,
|
||||
subfex, subfic, subfmex, subfzex, sync, tw, twi, xorx, xori, xoris, mftb,
|
||||
/// [ (ra()|0) + rB() ] = rS()
|
||||
/// i.e. if rA() is 0 then the value 0 is used, not the contents of r0.
|
||||
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.
|
||||
@ -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.
|
||||
uint32_t l() const { return opcode & 0x200000; }
|
||||
/// 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.
|
||||
|
@ -790,12 +790,13 @@ template <bool has_fdc> class ConcreteMachine:
|
||||
bool has_amsdos = false;
|
||||
ROM::Name firmware, basic;
|
||||
|
||||
using Model = Analyser::Static::AmstradCPC::Target::Model;
|
||||
switch(target.model) {
|
||||
case Analyser::Static::AmstradCPC::Target::Model::CPC464:
|
||||
case Model::CPC464:
|
||||
firmware = ROM::Name::CPC464Firmware;
|
||||
basic = ROM::Name::CPC464BASIC;
|
||||
break;
|
||||
case Analyser::Static::AmstradCPC::Target::Model::CPC664:
|
||||
case Model::CPC664:
|
||||
firmware = ROM::Name::CPC664Firmware;
|
||||
basic = ROM::Name::CPC664BASIC;
|
||||
has_amsdos = true;
|
||||
@ -838,6 +839,9 @@ template <bool has_fdc> class ConcreteMachine:
|
||||
read_pointers_[2] = write_pointers_[2];
|
||||
read_pointers_[3] = roms_[upper_rom_].data();
|
||||
|
||||
// Set total RAM available.
|
||||
has_128k_ = target.model == Model::CPC6128;
|
||||
|
||||
// Type whatever is required.
|
||||
if(!target.loading_command.empty()) {
|
||||
type_string(target.loading_command);
|
||||
@ -1248,20 +1252,20 @@ template <bool has_fdc> class ConcreteMachine:
|
||||
HalfCycles crtc_counter_;
|
||||
HalfCycles half_cycles_since_ay_update_;
|
||||
|
||||
bool fdc_is_sleeping_;
|
||||
bool tape_player_is_sleeping_;
|
||||
bool has_128k_;
|
||||
bool fdc_is_sleeping_ = false;
|
||||
bool tape_player_is_sleeping_ = false;
|
||||
bool has_128k_ = false;
|
||||
|
||||
enum ROMType: int {
|
||||
AMSDOS = 0, OS = 1, BASIC = 2
|
||||
};
|
||||
std::vector<uint8_t> roms_[3];
|
||||
bool upper_rom_is_paged_;
|
||||
bool upper_rom_is_paged_ = false;
|
||||
ROMType upper_rom_;
|
||||
|
||||
uint8_t *ram_pages_[4];
|
||||
const uint8_t *read_pointers_[4];
|
||||
uint8_t *write_pointers_[4];
|
||||
uint8_t *ram_pages_[4]{};
|
||||
const uint8_t *read_pointers_[4]{};
|
||||
uint8_t *write_pointers_[4]{};
|
||||
|
||||
KeyboardState key_state_;
|
||||
AmstradCPC::KeyboardMapper keyboard_mapper_;
|
||||
|
@ -17,15 +17,36 @@ 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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
- (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 rB = [NSString stringWithFormat:@"r%d", instruction.rB()];
|
||||
NSString *const rD = [NSString stringWithFormat:@"r%d", instruction.rD()];
|
||||
XCTAssertEqualObjects(rD, columns[3]);
|
||||
XCTAssertEqualObjects(rA, columns[4]);
|
||||
XCTAssertEqualObjects(rB, columns[5]);
|
||||
|
||||
if([columns count] > 5) {
|
||||
NSString *const rB = [NSString stringWithFormat:@"r%d", instruction.rB()];
|
||||
XCTAssertEqualObjects(rB, columns[5]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testDecoding {
|
||||
@ -57,24 +78,73 @@ 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
|
||||
|
||||
#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::bclrx:
|
||||
case Operation::bcctrx: {
|
||||
@ -164,7 +234,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 +260,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));
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -17,7 +18,6 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
|
@ -9,10 +9,10 @@
|
||||
#ifndef MacintoshVolume_hpp
|
||||
#define MacintoshVolume_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
namespace Storage {
|
||||
namespace MassStorage {
|
||||
|
Loading…
Reference in New Issue
Block a user