mirror of
https://github.com/TomHarte/CLK.git
synced 2025-03-25 06:30:38 +00:00
Proceed to complete test running.
This commit is contained in:
parent
fa49737538
commit
3827ecd6d3
InstructionSets/M68k
OSBindings/Mac
@ -1,10 +0,0 @@
|
||||
//
|
||||
// Executor.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 29/04/2022.
|
||||
// Copyright © 2022 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Executor.hpp"
|
||||
|
@ -46,6 +46,17 @@ template <Model model, typename BusHandler> class Executor {
|
||||
void add_pc(uint32_t);
|
||||
void decline_branch();
|
||||
|
||||
// TODO: ownership of this shouldn't be here.
|
||||
struct Registers {
|
||||
uint32_t data[8], address[7];
|
||||
uint32_t user_stack_pointer;
|
||||
uint32_t supervisor_stack_pointer;
|
||||
uint16_t status;
|
||||
uint32_t program_counter;
|
||||
};
|
||||
Registers get_state();
|
||||
void set_state(const Registers &);
|
||||
|
||||
private:
|
||||
BusHandler &bus_handler_;
|
||||
Predecoder<model> decoder_;
|
||||
|
@ -201,7 +201,6 @@ void Executor<model, BusHandler>::run_for_instructions(int count) {
|
||||
instruction_address_ = program_counter_.l;
|
||||
const auto opcode = read_pc<uint16_t>();
|
||||
const Preinstruction instruction = decoder_.decode(opcode);
|
||||
program_counter_.l += 2;
|
||||
|
||||
// TODO: check privilege level.
|
||||
|
||||
@ -277,6 +276,45 @@ void Executor<model, BusHandler>::run_for_instructions(int count) {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - State
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
typename Executor<model, BusHandler>::Registers Executor<model, BusHandler>::get_state() {
|
||||
Registers result;
|
||||
|
||||
for(int c = 0; c < 8; c++) {
|
||||
result.data[c] = data_[c].l;
|
||||
}
|
||||
for(int c = 0; c < 7; c++) {
|
||||
result.address[c] = address_[c].l;
|
||||
}
|
||||
result.status = status_.status();
|
||||
result.program_counter = program_counter_.l;
|
||||
|
||||
stack_pointers_[status_.is_supervisor_] = address_[7];
|
||||
result.user_stack_pointer = stack_pointers_[0].l;
|
||||
result.supervisor_stack_pointer = stack_pointers_[1].l;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
void Executor<model, BusHandler>::set_state(const Registers &state) {
|
||||
for(int c = 0; c < 8; c++) {
|
||||
data_[c].l = state.data[c];
|
||||
}
|
||||
for(int c = 0; c < 7; c++) {
|
||||
address_[c].l = state.address[c];
|
||||
}
|
||||
status_.set_status(state.status);
|
||||
program_counter_.l = state.program_counter;
|
||||
|
||||
stack_pointers_[0].l = state.user_stack_pointer;
|
||||
stack_pointers_[1].l = state.supervisor_stack_pointer;
|
||||
address_[7] = stack_pointers_[status_.is_supervisor_];
|
||||
}
|
||||
|
||||
// MARK: - Flow Control.
|
||||
// TODO: flow control, all below here.
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
|
@ -868,7 +868,7 @@ template <
|
||||
status.overflow_flag_ = status.carry_flag_ = 0;
|
||||
break;
|
||||
|
||||
#define sbcd() \
|
||||
#define sbcd(d) \
|
||||
/* Perform the BCD arithmetic by evaluating the two nibbles separately. */ \
|
||||
const int unadjusted_result = destination - source - (status.extend_flag_ ? 1 : 0); \
|
||||
int result = (destination & 0xf) - (source & 0xf) - (status.extend_flag_ ? 1 : 0); \
|
||||
@ -883,7 +883,7 @@ template <
|
||||
status.overflow_flag_ = unadjusted_result & ~result & 0x80; \
|
||||
\
|
||||
/* Store the result. */ \
|
||||
dest.b = uint8_t(result);
|
||||
d = uint8_t(result);
|
||||
|
||||
/*
|
||||
SBCD subtracts the lowest byte of the source from that of the destination using
|
||||
@ -892,17 +892,17 @@ template <
|
||||
case Operation::SBCD: {
|
||||
const uint8_t source = src.b;
|
||||
const uint8_t destination = dest.b;
|
||||
sbcd();
|
||||
sbcd(dest.b);
|
||||
} break;
|
||||
|
||||
/*
|
||||
NBCD is like SBCD except that the result is 0 - destination rather than
|
||||
NBCD is like SBCD except that the result is 0 - source rather than
|
||||
destination - source.
|
||||
*/
|
||||
case Operation::NBCD: {
|
||||
const uint8_t source = dest.b;
|
||||
const uint8_t source = src.b;
|
||||
const uint8_t destination = 0;
|
||||
sbcd();
|
||||
sbcd(src.b);
|
||||
} break;
|
||||
|
||||
#undef sbcd
|
||||
|
@ -894,8 +894,6 @@
|
||||
4BB4BFB022A42F290069048D /* MacintoshIMG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4BFAE22A42F290069048D /* MacintoshIMG.cpp */; };
|
||||
4BB4BFB922A4372F0069048D /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4BFB822A4372E0069048D /* StaticAnalyser.cpp */; };
|
||||
4BB4BFBA22A4372F0069048D /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4BFB822A4372E0069048D /* StaticAnalyser.cpp */; };
|
||||
4BB5B99D281C814E00522DA9 /* Executor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB5B99B281C805300522DA9 /* Executor.cpp */; };
|
||||
4BB5B99E281C814F00522DA9 /* Executor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB5B99B281C805300522DA9 /* Executor.cpp */; };
|
||||
4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; };
|
||||
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; };
|
||||
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; };
|
||||
@ -1941,7 +1939,6 @@
|
||||
4BB5B996281B1E3F00522DA9 /* Perform.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Perform.hpp; sourceTree = "<group>"; };
|
||||
4BB5B997281B1F7B00522DA9 /* Status.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Status.hpp; sourceTree = "<group>"; };
|
||||
4BB5B99A281B244400522DA9 /* PerformImplementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PerformImplementation.hpp; sourceTree = "<group>"; };
|
||||
4BB5B99B281C805300522DA9 /* Executor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Executor.cpp; sourceTree = "<group>"; };
|
||||
4BB5B99C281C805300522DA9 /* Executor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Executor.hpp; sourceTree = "<group>"; };
|
||||
4BB5B99F281F121200522DA9 /* ExecutorImplementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExecutorImplementation.hpp; sourceTree = "<group>"; };
|
||||
4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = "<group>"; };
|
||||
@ -3170,7 +3167,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B79629F2819681F008130F9 /* Decoder.cpp */,
|
||||
4BB5B99B281C805300522DA9 /* Executor.cpp */,
|
||||
4B7962A4281C2EE3008130F9 /* Sequence.cpp */,
|
||||
4B79629E2819681F008130F9 /* Decoder.hpp */,
|
||||
4BB5B99C281C805300522DA9 /* Executor.hpp */,
|
||||
@ -5466,7 +5462,6 @@
|
||||
4B1B88C1202E3DB200B67DFF /* MultiConfigurable.cpp in Sources */,
|
||||
4B055AA31FAE85DF0060FFFF /* ImplicitSectors.cpp in Sources */,
|
||||
4B8318B322D3E540006DB630 /* Audio.cpp in Sources */,
|
||||
4BB5B99E281C814F00522DA9 /* Executor.cpp in Sources */,
|
||||
4B055AAE1FAE85FD0060FFFF /* TrackSerialiser.cpp in Sources */,
|
||||
4B89452B201967B4007DE474 /* File.cpp in Sources */,
|
||||
4B6AAEAC230E40250078E864 /* SCSI.cpp in Sources */,
|
||||
@ -5717,7 +5712,6 @@
|
||||
4BC890D3230F86020025A55A /* DirectAccessDevice.cpp in Sources */,
|
||||
4B7BA03723CEB86000B98D9E /* BD500.cpp in Sources */,
|
||||
4B38F3481F2EC11D00D9235D /* AmstradCPC.cpp in Sources */,
|
||||
4BB5B99D281C814E00522DA9 /* Executor.cpp in Sources */,
|
||||
4B8FE2221DA19FB20090D3CE /* MachineController.swift in Sources */,
|
||||
4B4518A41F75FD1C00926311 /* OricMFMDSK.cpp in Sources */,
|
||||
4B4B1A3C200198CA00A0F866 /* KonamiSCC.cpp in Sources */,
|
||||
|
@ -274,24 +274,25 @@
|
||||
NSNumber *const value = [enumerator nextObject];
|
||||
|
||||
if(!address || !value) break;
|
||||
test68000->ram[address.integerValue ^ 1] = value.integerValue; // Effect a short-resolution endianness swap.
|
||||
test68000->ram[address.integerValue] = value.integerValue;
|
||||
}
|
||||
|
||||
// Apply initial processor state.
|
||||
// NSDictionary *const initialState = test[@"initial state"];
|
||||
// auto state = test68000->processor.get_state();
|
||||
// for(int c = 0; c < 8; ++c) {
|
||||
// const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
||||
// const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
||||
//
|
||||
// state.data[c] = uint32_t([initialState[dX] integerValue]);
|
||||
// if(c < 7)
|
||||
// state.address[c] = uint32_t([initialState[aX] integerValue]);
|
||||
// }
|
||||
// state.supervisor_stack_pointer = uint32_t([initialState[@"a7"] integerValue]);
|
||||
// state.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
|
||||
// state.status = [initialState[@"sr"] integerValue];
|
||||
// test68000->processor.set_state(state);
|
||||
NSDictionary *const initialState = test[@"initial state"];
|
||||
auto state = test68000->processor.get_state();
|
||||
for(int c = 0; c < 8; ++c) {
|
||||
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
||||
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
||||
|
||||
state.data[c] = uint32_t([initialState[dX] integerValue]);
|
||||
if(c < 7)
|
||||
state.address[c] = uint32_t([initialState[aX] integerValue]);
|
||||
}
|
||||
state.supervisor_stack_pointer = uint32_t([initialState[@"a7"] integerValue]);
|
||||
state.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
|
||||
state.status = [initialState[@"sr"] integerValue];
|
||||
state.program_counter = uint32_t([initialState[@"pc"] integerValue]);
|
||||
test68000->processor.set_state(state);
|
||||
}
|
||||
|
||||
// Run the thing.
|
||||
@ -299,27 +300,27 @@
|
||||
|
||||
// Test the end state.
|
||||
NSDictionary *const finalState = test[@"final state"];
|
||||
// const auto state = test68000->processor.get_state();
|
||||
// for(int c = 0; c < 8; ++c) {
|
||||
// const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
||||
// const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
||||
//
|
||||
// if(state.data[c] != [finalState[dX] integerValue]) [_failures addObject:name];
|
||||
// if(c < 7 && state.address[c] != [finalState[aX] integerValue]) [_failures addObject:name];
|
||||
//
|
||||
// XCTAssertEqual(state.data[c], [finalState[dX] integerValue], @"%@: D%d inconsistent", name, c);
|
||||
// if(c < 7) {
|
||||
// XCTAssertEqual(state.address[c], [finalState[aX] integerValue], @"%@: A%d inconsistent", name, c);
|
||||
// }
|
||||
// }
|
||||
// if(state.supervisor_stack_pointer != [finalState[@"a7"] integerValue]) [_failures addObject:name];
|
||||
// if(state.user_stack_pointer != [finalState[@"usp"] integerValue]) [_failures addObject:name];
|
||||
// if(state.status != [finalState[@"sr"] integerValue]) [_failures addObject:name];
|
||||
//
|
||||
// XCTAssertEqual(state.supervisor_stack_pointer, [finalState[@"a7"] integerValue], @"%@: A7 inconsistent", name);
|
||||
// XCTAssertEqual(state.user_stack_pointer, [finalState[@"usp"] integerValue], @"%@: USP inconsistent", name);
|
||||
// XCTAssertEqual(state.status, [finalState[@"sr"] integerValue], @"%@: Status inconsistent", name);
|
||||
// XCTAssertEqual(state.program_counter - 4, [finalState[@"pc"] integerValue], @"%@: Program counter inconsistent", name);
|
||||
const auto state = test68000->processor.get_state();
|
||||
for(int c = 0; c < 8; ++c) {
|
||||
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
||||
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
||||
|
||||
if(state.data[c] != [finalState[dX] integerValue]) [_failures addObject:name];
|
||||
if(c < 7 && state.address[c] != [finalState[aX] integerValue]) [_failures addObject:name];
|
||||
|
||||
XCTAssertEqual(state.data[c], [finalState[dX] integerValue], @"%@: D%d inconsistent", name, c);
|
||||
if(c < 7) {
|
||||
XCTAssertEqual(state.address[c], [finalState[aX] integerValue], @"%@: A%d inconsistent", name, c);
|
||||
}
|
||||
}
|
||||
if(state.supervisor_stack_pointer != [finalState[@"a7"] integerValue]) [_failures addObject:name];
|
||||
if(state.user_stack_pointer != [finalState[@"usp"] integerValue]) [_failures addObject:name];
|
||||
if(state.status != [finalState[@"sr"] integerValue]) [_failures addObject:name];
|
||||
|
||||
XCTAssertEqual(state.supervisor_stack_pointer, [finalState[@"a7"] integerValue], @"%@: A7 inconsistent", name);
|
||||
XCTAssertEqual(state.user_stack_pointer, [finalState[@"usp"] integerValue], @"%@: USP inconsistent", name);
|
||||
XCTAssertEqual(state.status, [finalState[@"sr"] integerValue], @"%@: Status inconsistent", name);
|
||||
XCTAssertEqual(state.program_counter, [finalState[@"pc"] integerValue], @"%@: Program counter inconsistent", name);
|
||||
|
||||
// Test final memory state.
|
||||
NSArray<NSNumber *> *const finalMemory = test[@"final memory"];
|
||||
@ -329,13 +330,13 @@
|
||||
NSNumber *const value = [enumerator nextObject];
|
||||
|
||||
if(!address || !value) break;
|
||||
XCTAssertEqual(test68000->ram[address.integerValue ^ 1], value.integerValue, @"%@: Memory at location %@ inconsistent", name, address);
|
||||
if(test68000->ram[address.integerValue ^ 1] != value.integerValue) [_failures addObject:name];
|
||||
XCTAssertEqual(test68000->ram[address.integerValue], value.integerValue, @"%@: Memory at location %@ inconsistent", name, address);
|
||||
if(test68000->ram[address.integerValue] != value.integerValue) [_failures addObject:name];
|
||||
}
|
||||
|
||||
// Consider collating extra detail.
|
||||
if([_failures containsObject:name]) {
|
||||
[_failingOpcodes addObject:@((test68000->ram[0x101] << 8) | test68000->ram[0x100])];
|
||||
[_failingOpcodes addObject:@((test68000->ram[0x100] << 8) | test68000->ram[0x101])];
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user