1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-01 11:49:58 +00:00

Merge branch 'PowerPCTests' of github.com:TomHarte/CLK into PowerPCTests

This commit is contained in:
Thomas Harte 2022-03-29 14:38:28 -04:00
commit 5ec291df5c
5 changed files with 202 additions and 32 deletions

View File

@ -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.

View File

@ -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_;

View File

@ -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));

View File

@ -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>

View File

@ -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 {