mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-07 23:25:00 +00:00
Eliminates the 6502's specialised jam handler in favour of the generic trap handler, and simplifies the lookup costs of that as it's otherwise doubling execution costs.
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
class WolfgangLorenzTests: XCTestCase, CSTestMachineTrapHandler {
|
||||||
|
|
||||||
func testWolfgangLorenzStart() {
|
func testWolfgangLorenzStart() {
|
||||||
self.runWolfgangLorenzTest(" start")
|
self.runWolfgangLorenzTest(" start")
|
||||||
@@ -201,7 +201,7 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
|||||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||||
|
|
||||||
machine = CSTestMachine6502()
|
machine = CSTestMachine6502()
|
||||||
machine.jamHandler = self
|
machine.trapHandler = self
|
||||||
// machine.logActivity = true
|
// machine.logActivity = true
|
||||||
output = ""
|
output = ""
|
||||||
|
|
||||||
@@ -225,11 +225,18 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
|||||||
] as [UInt8]), count: 19)
|
] as [UInt8]), count: 19)
|
||||||
machine.setData( irqHandler, atAddress: 0xff48)
|
machine.setData( irqHandler, atAddress: 0xff48)
|
||||||
|
|
||||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffd2) // print character
|
machine.addTrapAddress(0xffd2) // print character
|
||||||
|
machine.addTrapAddress(0xffe4) // scan keyboard
|
||||||
|
|
||||||
|
machine.addTrapAddress(0x8000) // exit
|
||||||
|
machine.addTrapAddress(0xa474) // exit
|
||||||
|
|
||||||
|
machine.setValue(0x60, forAddress:0xffd2) // 0x60 is RTS
|
||||||
|
machine.setValue(0x60, forAddress:0xffe4)
|
||||||
|
machine.setValue(0x60, forAddress:0x8000)
|
||||||
|
machine.setValue(0x60, forAddress:0xa474)
|
||||||
|
|
||||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xe16f) // load
|
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xe16f) // load
|
||||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffe4) // scan keyboard
|
|
||||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0x8000) // exit
|
|
||||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xa474) // exit
|
|
||||||
|
|
||||||
machine.setValue(0x0801, for: CSTestMachine6502Register.programCounter)
|
machine.setValue(0x0801, for: CSTestMachine6502Register.programCounter)
|
||||||
machine.setValue(0xfd, for: CSTestMachine6502Register.stackPointer)
|
machine.setValue(0xfd, for: CSTestMachine6502Register.stackPointer)
|
||||||
@@ -296,19 +303,17 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMachine(_ machine: CSTestMachine6502!, didJamAtAddress address: UInt16) {
|
func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) {
|
||||||
|
let testMachine6502 = testMachine as! CSTestMachine6502
|
||||||
switch address {
|
switch address {
|
||||||
case 0xffd2:
|
case 0xffd2:
|
||||||
machine.setValue(0x00, forAddress: 0x030c)
|
testMachine6502.setValue(0x00, forAddress: 0x030c)
|
||||||
|
|
||||||
let character = machine.value(for: CSTestMachine6502Register.A)
|
let character = testMachine6502.value(for: CSTestMachine6502Register.A)
|
||||||
output.append(Character(UnicodeScalar(character)!))
|
output.append(Character(UnicodeScalar(character)!))
|
||||||
|
|
||||||
machine.returnFromSubroutine()
|
|
||||||
|
|
||||||
case 0xffe4:
|
case 0xffe4:
|
||||||
machine.setValue(0x3, for:CSTestMachine6502Register.A)
|
testMachine6502.setValue(0x3, for:CSTestMachine6502Register.A)
|
||||||
machine.returnFromSubroutine()
|
|
||||||
|
|
||||||
case 0x8000, 0xa474:
|
case 0x8000, 0xa474:
|
||||||
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: self.petsciiToString(output), userInfo: nil).raise()
|
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: self.petsciiToString(output), userInfo: nil).raise()
|
||||||
@@ -316,9 +321,6 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
|||||||
case 0x0000:
|
case 0x0000:
|
||||||
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: "Execution hit 0000", userInfo: nil).raise()
|
NSException(name: NSExceptionName(rawValue: "Failed test"), reason: "Execution hit 0000", userInfo: nil).raise()
|
||||||
|
|
||||||
case 0xe16f: // load next (which we consider to be success)
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
let hexAddress = String(format:"%04x", address)
|
let hexAddress = String(format:"%04x", address)
|
||||||
NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()
|
NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()
|
||||||
|
@@ -78,13 +78,6 @@ extern const uint8_t JamOpcode;
|
|||||||
jammed state.
|
jammed state.
|
||||||
*/
|
*/
|
||||||
template <class T> class Processor {
|
template <class T> class Processor {
|
||||||
public:
|
|
||||||
|
|
||||||
class JamHandler {
|
|
||||||
public:
|
|
||||||
virtual void processor_did_jam(Processor *processor, uint16_t address) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -426,8 +419,6 @@ template <class T> class Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_jammed_;
|
bool is_jammed_;
|
||||||
JamHandler *jam_handler_;
|
|
||||||
|
|
||||||
int cycles_left_to_run_;
|
int cycles_left_to_run_;
|
||||||
|
|
||||||
enum InterruptRequestFlags: uint8_t {
|
enum InterruptRequestFlags: uint8_t {
|
||||||
@@ -511,7 +502,6 @@ template <class T> class Processor {
|
|||||||
protected:
|
protected:
|
||||||
Processor() :
|
Processor() :
|
||||||
is_jammed_(false),
|
is_jammed_(false),
|
||||||
jam_handler_(nullptr),
|
|
||||||
cycles_left_to_run_(0),
|
cycles_left_to_run_(0),
|
||||||
ready_line_is_enabled_(false),
|
ready_line_is_enabled_(false),
|
||||||
ready_is_active_(false),
|
ready_is_active_(false),
|
||||||
@@ -704,11 +694,6 @@ template <class T> class Processor {
|
|||||||
is_jammed_ = true;
|
is_jammed_ = true;
|
||||||
static const MicroOp jam[] = JAM;
|
static const MicroOp jam[] = JAM;
|
||||||
scheduled_program_counter_ = jam;
|
scheduled_program_counter_ = jam;
|
||||||
|
|
||||||
if(jam_handler_) {
|
|
||||||
jam_handler_->processor_did_jam(this, pc_.full - 1);
|
|
||||||
checkSchedule(is_jammed_ = false;);
|
|
||||||
}
|
|
||||||
} continue;
|
} continue;
|
||||||
|
|
||||||
#pragma mark - Bitwise
|
#pragma mark - Bitwise
|
||||||
@@ -1230,15 +1215,6 @@ template <class T> class Processor {
|
|||||||
inline bool is_jammed() {
|
inline bool is_jammed() {
|
||||||
return is_jammed_;
|
return is_jammed_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Installs a jam handler. Jam handlers are notified if a running 6502 jams.
|
|
||||||
|
|
||||||
@param handler The class instance that will be this 6502's jam handler from now on.
|
|
||||||
*/
|
|
||||||
inline void set_jam_handler(JamHandler *handler) {
|
|
||||||
jam_handler_ = handler;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ class AllRAMProcessor:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static AllRAMProcessor *Processor();
|
static AllRAMProcessor *Processor();
|
||||||
|
virtual ~AllRAMProcessor() {}
|
||||||
|
|
||||||
virtual void run_for_cycles(int number_of_cycles) = 0;
|
virtual void run_for_cycles(int number_of_cycles) = 0;
|
||||||
virtual bool is_jammed() = 0;
|
virtual bool is_jammed() = 0;
|
||||||
|
@@ -12,6 +12,7 @@ using namespace CPU;
|
|||||||
|
|
||||||
AllRAMProcessor::AllRAMProcessor(size_t memory_size) :
|
AllRAMProcessor::AllRAMProcessor(size_t memory_size) :
|
||||||
memory_(memory_size),
|
memory_(memory_size),
|
||||||
|
traps_(memory_size, false),
|
||||||
timestamp_(0) {}
|
timestamp_(0) {}
|
||||||
|
|
||||||
void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data) {
|
void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data) {
|
||||||
@@ -33,5 +34,5 @@ void AllRAMProcessor::set_trap_handler(TrapHandler *trap_handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AllRAMProcessor::add_trap_address(uint16_t address) {
|
void AllRAMProcessor::add_trap_address(uint16_t address) {
|
||||||
trap_addresses_.insert(address);
|
traps_[address] = true;
|
||||||
}
|
}
|
||||||
|
@@ -34,14 +34,14 @@ class AllRAMProcessor {
|
|||||||
uint32_t timestamp_;
|
uint32_t timestamp_;
|
||||||
|
|
||||||
inline void check_address_for_trap(uint16_t address) {
|
inline void check_address_for_trap(uint16_t address) {
|
||||||
if(trap_addresses_.find(address) != trap_addresses_.end()) {
|
if(traps_[address]) {
|
||||||
trap_handler_->processor_did_trap(*this, address);
|
trap_handler_->processor_did_trap(*this, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<uint16_t> trap_addresses_;
|
|
||||||
TrapHandler *trap_handler_;
|
TrapHandler *trap_handler_;
|
||||||
|
std::vector<bool> traps_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user