1
0
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:
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,
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.

View File

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

View File

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

View File

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

View File

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