mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-14 13:33:42 +00:00
Takes a shot at emulation-mode 'exceptions'.
It's just RTI and correct decimal SBC left of the official 6502s now, I think.
This commit is contained in:
parent
054e0af071
commit
0418f51ef2
@ -9,7 +9,6 @@
|
|||||||
#import "TestMachine6502.h"
|
#import "TestMachine6502.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../../../../Processors/6502/AllRAM/6502AllRAM.hpp"
|
#include "../../../../Processors/6502/AllRAM/6502AllRAM.hpp"
|
||||||
//#include "../../../../Processors/65816/AllRAM/65816AllRAM.hpp"
|
|
||||||
#import "TestMachine+ForSubclassEyesOnly.h"
|
#import "TestMachine+ForSubclassEyesOnly.h"
|
||||||
|
|
||||||
const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode;
|
const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode;
|
||||||
|
@ -55,7 +55,9 @@ class KlausDormannTests: XCTestCase {
|
|||||||
case 0x36ac, 0x36f6: return "Improper JSR return address on stack"
|
case 0x36ac, 0x36f6: return "Improper JSR return address on stack"
|
||||||
case 0x36c6: return "Unexpected RESET"
|
case 0x36c6: return "Unexpected RESET"
|
||||||
case 0x36d1: return "BRK: unexpected BRK or IRQ"
|
case 0x36d1: return "BRK: unexpected BRK or IRQ"
|
||||||
case 0x36e5: return "BRK flag not set on stack"
|
case 0x36e5: return "BRK flag not set on stack following BRK"
|
||||||
|
case 0x36ea: return "BRK did not set the I flag"
|
||||||
|
case 0x36fd: return "Wrong address put on stack by BRK"
|
||||||
|
|
||||||
case 0: return "Didn't find tests"
|
case 0: return "Didn't find tests"
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#define BE_NOISY
|
||||||
|
|
||||||
using namespace CPU::MOS6502;
|
using namespace CPU::MOS6502;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -28,20 +30,31 @@ template <Type type> class ConcreteAllRAMProcessor: public AllRAMProcessor, publ
|
|||||||
timestamp_ += Cycles(1);
|
timestamp_ += Cycles(1);
|
||||||
|
|
||||||
if(operation == BusOperation::ReadOpcode) {
|
if(operation == BusOperation::ReadOpcode) {
|
||||||
// TEMPORARY LOGGING. TODO: remove.
|
#ifdef BE_NOISY
|
||||||
printf("[%04x] %02x a:%04x x:%04x y:%04x p:%02x s:%02x\n", address, memory_[address],
|
printf("[%04x] %02x a:%04x x:%04x y:%04x p:%02x s:%02x\n", address, memory_[address],
|
||||||
mos6502_.get_value_of_register(Register::A),
|
mos6502_.get_value_of_register(Register::A),
|
||||||
mos6502_.get_value_of_register(Register::X),
|
mos6502_.get_value_of_register(Register::X),
|
||||||
mos6502_.get_value_of_register(Register::Y),
|
mos6502_.get_value_of_register(Register::Y),
|
||||||
mos6502_.get_value_of_register(Register::Flags) & 0xff,
|
mos6502_.get_value_of_register(Register::Flags) & 0xff,
|
||||||
mos6502_.get_value_of_register(Register::StackPointer) & 0xff);
|
mos6502_.get_value_of_register(Register::StackPointer) & 0xff);
|
||||||
|
#endif
|
||||||
check_address_for_trap(address);
|
check_address_for_trap(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isReadOperation(operation)) {
|
if(isReadOperation(operation)) {
|
||||||
*value = memory_[address];
|
*value = memory_[address];
|
||||||
|
#ifdef BE_NOISY
|
||||||
|
if((address&0xff00) == 0x100) {
|
||||||
|
printf("%04x -> %02x\n", address, *value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
memory_[address] = *value;
|
memory_[address] = *value;
|
||||||
|
#ifdef BE_NOISY
|
||||||
|
if((address&0xff00) == 0x100) {
|
||||||
|
printf("%04x <- %02x\n", address, *value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cycles(1);
|
return Cycles(1);
|
||||||
|
@ -296,6 +296,49 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
|
|||||||
data_address_ = data_bank_ + (instruction_buffer_.value + y()) & 0xffff;
|
data_address_ = data_bank_ + (instruction_buffer_.value + y()) & 0xffff;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case OperationPrepareException: {
|
||||||
|
// Put the proper exception vector into the data address, put the flags and PC
|
||||||
|
// into the data buffer (possibly also PBR), and skip an instruction if in
|
||||||
|
// emulation mode.
|
||||||
|
|
||||||
|
bool is_brk = false;
|
||||||
|
|
||||||
|
if(pending_exceptions_ & (Reset | PowerOn)) {
|
||||||
|
// TODO: set emulation mode, etc.
|
||||||
|
pending_exceptions_ &= ~(Reset | PowerOn);
|
||||||
|
data_address_ = 0xfffc;
|
||||||
|
} else if(pending_exceptions_ & NMI) {
|
||||||
|
pending_exceptions_ &= ~NMI;
|
||||||
|
data_address_ = 0xfffa;
|
||||||
|
} else if(pending_exceptions_ & IRQ) {
|
||||||
|
pending_exceptions_ &= ~IRQ;
|
||||||
|
data_address_ = 0xfffe;
|
||||||
|
} else {
|
||||||
|
is_brk = active_instruction_ == instructions;
|
||||||
|
if(is_brk) {
|
||||||
|
data_address_ = emulation_flag_ ? 0xfffe : 0xfff6;
|
||||||
|
} else {
|
||||||
|
// Implicitly: COP.
|
||||||
|
data_address_ = 0xfff4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data_buffer_.value = (pc_ << 8) | flags_.get();
|
||||||
|
if(emulation_flag_) {
|
||||||
|
if(is_brk) data_buffer_.value |= Flag::Break;
|
||||||
|
data_buffer_.size = 3;
|
||||||
|
++next_op_;
|
||||||
|
} else {
|
||||||
|
data_buffer_.value |= program_bank_ << 24;
|
||||||
|
data_buffer_.size = 4;
|
||||||
|
program_bank_ = 0;
|
||||||
|
|
||||||
|
assert(false); // TODO: proper flags, still.
|
||||||
|
}
|
||||||
|
|
||||||
|
flags_.inverse_interrupt = 0;
|
||||||
|
} continue;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Performance.
|
// Performance.
|
||||||
//
|
//
|
||||||
@ -687,7 +730,6 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
|
|||||||
// XCE, XBA,
|
// XCE, XBA,
|
||||||
// STP, WAI,
|
// STP, WAI,
|
||||||
// RTI, RTL,
|
// RTI, RTL,
|
||||||
// BRK,
|
|
||||||
// TCD, TCS, TDC, TSC
|
// TCD, TCS, TDC, TSC
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -695,8 +737,6 @@ template <typename BusHandler> void Processor<BusHandler>::run_for(const Cycles
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: OperationPrepareException
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
|
|||||||
const auto map_entry = installed_patterns.find(key);
|
const auto map_entry = installed_patterns.find(key);
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[0] =
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[0] =
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[1] = uint16_t(map_entry->second.first);
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[1] = uint16_t(map_entry->second.first);
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = BRK;
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = JMPind;
|
||||||
}
|
}
|
||||||
|
|
||||||
void install_fetch_decode_execute() {
|
void install_fetch_decode_execute() {
|
||||||
@ -579,6 +579,7 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
|
|||||||
target(CyclePush); // PCL
|
target(CyclePush); // PCL
|
||||||
target(CyclePush); // P
|
target(CyclePush); // P
|
||||||
|
|
||||||
|
// TODO: I think I need a seperate vector fetch here, to signal vector pull?
|
||||||
target(CycleFetchIncrementData); // AAVL
|
target(CycleFetchIncrementData); // AAVL
|
||||||
target(CycleFetchData); // AAVH
|
target(CycleFetchData); // AAVH
|
||||||
|
|
||||||
@ -677,8 +678,23 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 22j. Stack; s, BRK/COP.
|
// 22j. Stack; s, BRK/COP.
|
||||||
|
static void brk_cop(AccessType, bool, const std::function<void(MicroOp)> &target) {
|
||||||
|
target(CycleFetchIncrementPC); // Signature.
|
||||||
|
|
||||||
// Covered by stack_exception.
|
target(OperationPrepareException); // Populates the data buffer; this skips a micro-op if
|
||||||
|
// in emulation mode.
|
||||||
|
|
||||||
|
target(CyclePush); // PBR [skipped in emulation mode]
|
||||||
|
target(CyclePush); // PCH
|
||||||
|
target(CyclePush); // PCL
|
||||||
|
target(CyclePush); // P
|
||||||
|
|
||||||
|
// TODO: I think I need a seperate vector fetch here, to signal vector pull?
|
||||||
|
target(CycleFetchIncrementData); // AAVL
|
||||||
|
target(CycleFetchData); // AAVH
|
||||||
|
|
||||||
|
target(OperationPerform); // Jumps to the vector address.
|
||||||
|
}
|
||||||
|
|
||||||
// 23. Stack Relative; d, s.
|
// 23. Stack Relative; d, s.
|
||||||
static void stack_relative(AccessType type, bool is8bit, const std::function<void(MicroOp)> &target) {
|
static void stack_relative(AccessType type, bool is8bit, const std::function<void(MicroOp)> &target) {
|
||||||
@ -710,9 +726,9 @@ ProcessorStorage::ProcessorStorage() {
|
|||||||
// Install the instructions.
|
// Install the instructions.
|
||||||
#define op(x, y) constructor.install(&ProcessorStorageConstructor::x, y)
|
#define op(x, y) constructor.install(&ProcessorStorageConstructor::x, y)
|
||||||
|
|
||||||
/* 0x00 BRK s */ op(stack_exception, BRK);
|
/* 0x00 BRK s */ op(brk_cop, JMPind);
|
||||||
/* 0x01 ORA (d, x) */ op(direct_indexed_indirect, ORA);
|
/* 0x01 ORA (d, x) */ op(direct_indexed_indirect, ORA);
|
||||||
/* 0x02 COP s */ op(stack_exception, BRK);
|
/* 0x02 COP s */ op(brk_cop, JMPind);
|
||||||
/* 0x03 ORA d, s */ op(stack_relative, ORA);
|
/* 0x03 ORA d, s */ op(stack_relative, ORA);
|
||||||
/* 0x04 TSB d */ op(direct_rmw, TSB);
|
/* 0x04 TSB d */ op(direct_rmw, TSB);
|
||||||
/* 0x05 ORA d */ op(direct, ORA);
|
/* 0x05 ORA d */ op(direct, ORA);
|
||||||
|
@ -193,10 +193,6 @@ enum Operation: uint8_t {
|
|||||||
|
|
||||||
/// Loads the PC with the contents of the data buffer + 1.
|
/// Loads the PC with the contents of the data buffer + 1.
|
||||||
RTS,
|
RTS,
|
||||||
|
|
||||||
/// i.e. jump to vector. TODO: is this really distinct from JMP? I'm assuming so for now,
|
|
||||||
/// as I assume the PBR is implicitly modified. But then is it just JML? We'll see.
|
|
||||||
BRK,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcessorStorageConstructor;
|
class ProcessorStorageConstructor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user