mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-24 12:30:17 +00:00
Merge pull request #124 from TomHarte/Z80
Introduces a decent but as-yet-imperfect implementation of the Z80 processor.
This commit is contained in:
commit
0f438f524b
@ -323,7 +323,7 @@ template <class T> class MOS6560 {
|
||||
/*!
|
||||
Causes the 6560 to flush as much pending CRT and speaker communications as possible.
|
||||
*/
|
||||
inline void synchronise() { update_audio(); speaker_->flush(); }
|
||||
inline void flush() { update_audio(); speaker_->flush(); }
|
||||
|
||||
/*!
|
||||
Writes to a 6560 register.
|
||||
|
@ -22,7 +22,7 @@ namespace Concurrency {
|
||||
|
||||
/*!
|
||||
An async task queue allows a caller to enqueue void(void) functions. Those functions are guaranteed
|
||||
to be performed serially and asynchronously from the caller. A caller may also request to synchronise,
|
||||
to be performed serially and asynchronously from the caller. A caller may also request to flush,
|
||||
causing it to block until all previously-enqueued functions are complete.
|
||||
*/
|
||||
class AsyncTaskQueue {
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "Bus.hpp"
|
||||
#include "PIA.hpp"
|
||||
|
@ -9,25 +9,25 @@
|
||||
#ifndef Atari2600_Cartridge_hpp
|
||||
#define Atari2600_Cartridge_hpp
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
#include "../Bus.hpp"
|
||||
|
||||
namespace Atari2600 {
|
||||
|
||||
template<class T> class Cartridge:
|
||||
public CPU6502::Processor<Cartridge<T>>,
|
||||
public CPU::MOS6502::Processor<Cartridge<T>>,
|
||||
public Bus {
|
||||
|
||||
public:
|
||||
Cartridge(const std::vector<uint8_t> &rom) :
|
||||
rom_(rom) {}
|
||||
|
||||
void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Cartridge<T>>::run_for_cycles(number_of_cycles); }
|
||||
void set_reset_line(bool state) { CPU6502::Processor<Cartridge<T>>::set_reset_line(state); }
|
||||
void run_for_cycles(int number_of_cycles) { CPU::MOS6502::Processor<Cartridge<T>>::run_for_cycles(number_of_cycles); }
|
||||
void set_reset_line(bool state) { CPU::MOS6502::Processor<Cartridge<T>>::set_reset_line(state); }
|
||||
void advance_cycles(unsigned int cycles) {}
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
uint8_t returnValue = 0xff;
|
||||
unsigned int cycles_run_for = 3;
|
||||
|
||||
@ -35,7 +35,7 @@ template<class T> class Cartridge:
|
||||
// leap to the end of ready only once ready is signalled — because on a 6502 ready doesn't take
|
||||
// effect until the next read; therefore it isn't safe to assume that signalling ready immediately
|
||||
// skips to the end of the line.
|
||||
if(operation == CPU6502::BusOperation::Ready)
|
||||
if(operation == CPU::MOS6502::BusOperation::Ready)
|
||||
cycles_run_for = (unsigned int)tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_);
|
||||
|
||||
cycles_since_speaker_update_ += cycles_run_for;
|
||||
@ -43,7 +43,7 @@ template<class T> class Cartridge:
|
||||
cycles_since_6532_update_ += (cycles_run_for / 3);
|
||||
static_cast<T *>(this)->advance_cycles(cycles_run_for / 3);
|
||||
|
||||
if(operation != CPU6502::BusOperation::Ready) {
|
||||
if(operation != CPU::MOS6502::BusOperation::Ready) {
|
||||
// give the cartridge a chance to respond to the bus access
|
||||
static_cast<T *>(this)->perform_bus_operation(operation, address, value);
|
||||
|
||||
@ -91,7 +91,7 @@ template<class T> class Cartridge:
|
||||
case 0x00: update_video(); tia_->set_sync(*value & 0x02); break;
|
||||
case 0x01: update_video(); tia_->set_blank(*value & 0x02); break;
|
||||
|
||||
case 0x02: CPU6502::Processor<Cartridge<T>>::set_ready_line(true); break;
|
||||
case 0x02: CPU::MOS6502::Processor<Cartridge<T>>::set_ready_line(true); break;
|
||||
case 0x03: update_video(); tia_->reset_horizontal_counter(); break;
|
||||
// TODO: audio will now be out of synchronisation — fix
|
||||
|
||||
@ -156,12 +156,12 @@ template<class T> class Cartridge:
|
||||
}
|
||||
}
|
||||
|
||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) CPU6502::Processor<Cartridge<T>>::set_ready_line(false);
|
||||
if(!tia_->get_cycles_until_horizontal_blank(cycles_since_video_update_)) CPU::MOS6502::Processor<Cartridge<T>>::set_ready_line(false);
|
||||
|
||||
return cycles_run_for / 3;
|
||||
}
|
||||
|
||||
void synchronise() {
|
||||
void flush() {
|
||||
update_audio();
|
||||
update_video();
|
||||
speaker_->flush();
|
||||
|
@ -19,13 +19,13 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
// This is a bit of a hack; a real cartridge can't see either the sync or read lines, and can't see
|
||||
// address line 13. Instead it looks for a pattern in recent address accesses that would imply an
|
||||
// RST or JSR.
|
||||
if(operation == CPU6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) {
|
||||
if(operation == CPU::MOS6502::BusOperation::ReadOpcode && (last_opcode_ == 0x20 || last_opcode_ == 0x60)) {
|
||||
if(address & 0x2000) {
|
||||
rom_ptr_ = rom_.data();
|
||||
} else {
|
||||
@ -37,7 +37,7 @@ class CartridgeActivisionStack: public Cartridge<CartridgeActivisionStack> {
|
||||
*value = rom_ptr_[address & 4095];
|
||||
}
|
||||
|
||||
if(operation == CPU6502::BusOperation::ReadOpcode) last_opcode_ = *value;
|
||||
if(operation == CPU::MOS6502::BusOperation::ReadOpcode) last_opcode_ = *value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -20,7 +20,7 @@ class CartridgeAtari16k: public Cartridge<CartridgeAtari16k> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
@ -42,7 +42,7 @@ class CartridgeAtari16kSuperChip: public Cartridge<CartridgeAtari16kSuperChip> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CartridgeAtari32k: public Cartridge<CartridgeAtari32k> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
@ -42,7 +42,7 @@ class CartridgeAtari32kSuperChip: public Cartridge<CartridgeAtari32kSuperChip> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CartridgeAtari8k: public Cartridge<CartridgeAtari8k> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
@ -43,7 +43,7 @@ class CartridgeAtari8kSuperChip: public Cartridge<CartridgeAtari8kSuperChip> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CartridgeCBSRAMPlus: public Cartridge<CartridgeCBSRAMPlus> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -16,7 +16,7 @@ class CartridgeCommaVid: public Cartridge<CartridgeCommaVid> {
|
||||
CartridgeCommaVid(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(!(address & 0x1000)) return;
|
||||
address &= 0x1fff;
|
||||
|
||||
|
@ -22,7 +22,7 @@ class CartridgeMNetwork: public Cartridge<CartridgeMNetwork> {
|
||||
high_ram_ptr_ = high_ram_;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -21,7 +21,7 @@ class CartridgeMegaBoy: public Cartridge<CartridgeMegaBoy> {
|
||||
rom_ptr_ = rom_.data();
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -23,7 +23,7 @@ class CartridgeParkerBros: public Cartridge<CartridgeParkerBros> {
|
||||
rom_ptr_[3] = rom_ptr_[2] + 1024;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -26,7 +26,7 @@ class CartridgePitfall2: public Cartridge<CartridgePitfall2> {
|
||||
cycles_since_audio_update_ += cycles;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
address &= 0x1fff;
|
||||
if(!(address & 0x1000)) return;
|
||||
|
||||
|
@ -21,7 +21,7 @@ class CartridgeTigervision: public Cartridge<CartridgeTigervision> {
|
||||
rom_ptr_[1] = rom_ptr_[0] + 2048;
|
||||
}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if((address&0x1fff) == 0x3f) {
|
||||
int offset = ((*value) * 2048) & (rom_.size() - 1);
|
||||
rom_ptr_[0] = rom_.data() + offset;
|
||||
|
@ -18,7 +18,7 @@ class CartridgeUnpaged: public Cartridge<CartridgeUnpaged> {
|
||||
CartridgeUnpaged(const std::vector<uint8_t> &rom) :
|
||||
Cartridge(rom) {}
|
||||
|
||||
void perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(isReadOperation(operation) && (address & 0x1000)) {
|
||||
*value = rom_[address & (rom_.size() - 1)];
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bu
|
||||
Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus);
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
/*
|
||||
Memory map (given that I'm unsure yet on any potential mirroring):
|
||||
|
||||
@ -80,7 +80,7 @@ void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk) {
|
||||
}
|
||||
|
||||
void Machine::run_for_cycles(int number_of_cycles) {
|
||||
CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
set_motor_on(drive_VIA_.get_motor_enabled());
|
||||
if(drive_VIA_.get_motor_enabled()) // TODO: motor speed up/down
|
||||
Storage::Disk::Controller::run_for_cycles(number_of_cycles);
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef Commodore1540_hpp
|
||||
#define Commodore1540_hpp
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
#include "../../../Components/6522/6522.hpp"
|
||||
|
||||
#include "../SerialBus.hpp"
|
||||
@ -120,7 +120,7 @@ class SerialPort : public ::Commodore::Serial::Port {
|
||||
Provides an emulation of the C1540.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public DriveVIA::Delegate,
|
||||
public Storage::Disk::Controller {
|
||||
@ -141,8 +141,8 @@ class Machine:
|
||||
void run_for_cycles(int number_of_cycles);
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
|
||||
// to satisfy MOS::MOS6522::Delegate
|
||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
|
@ -97,7 +97,7 @@ Machine::~Machine() {
|
||||
delete[] rom_;
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
// run the phase-1 part of this cycle, in which the VIC accesses memory
|
||||
if(!is_running_at_zero_cost_) mos6560_->run_for_cycles(1);
|
||||
|
||||
@ -115,7 +115,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
// PC hits the start of the loop that just waits for an interesting tape interrupt to have
|
||||
// occurred then skip both 6522s and the tape ahead to the next interrupt without any further
|
||||
// CPU or 6560 costs.
|
||||
if(use_fast_tape_hack_ && tape_->has_tape() && operation == CPU6502::BusOperation::ReadOpcode) {
|
||||
if(use_fast_tape_hack_ && tape_->has_tape() && operation == CPU::MOS6502::BusOperation::ReadOpcode) {
|
||||
if(address == 0xf7b2) {
|
||||
// Address 0xf7b2 contains a JSR to 0xf8c0 that will fill the tape buffer with the next header.
|
||||
// So cancel that via a double NOP and fill in the next header programmatically.
|
||||
@ -137,7 +137,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
*value = 0x0c; // i.e. NOP abs
|
||||
} else if(address == 0xf90b) {
|
||||
uint8_t x = (uint8_t)get_value_of_register(CPU6502::Register::X);
|
||||
uint8_t x = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X);
|
||||
if(x == 0xe) {
|
||||
Storage::Tape::Commodore::Parser parser;
|
||||
std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(tape_->get_tape());
|
||||
@ -158,13 +158,13 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
// set tape status, carry and flag
|
||||
user_basic_memory_[0x90] |= 0x40;
|
||||
uint8_t flags = (uint8_t)get_value_of_register(CPU6502::Register::Flags);
|
||||
flags &= ~(uint8_t)(CPU6502::Flag::Carry | CPU6502::Flag::Interrupt);
|
||||
set_value_of_register(CPU6502::Register::Flags, flags);
|
||||
uint8_t flags = (uint8_t)get_value_of_register(CPU::MOS6502::Register::Flags);
|
||||
flags &= ~(uint8_t)(CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Interrupt);
|
||||
set_value_of_register(CPU::MOS6502::Register::Flags, flags);
|
||||
|
||||
// to ensure that execution proceeds to 0xfccf, pretend a NOP was here and
|
||||
// ensure that the PC leaps to 0xfccf
|
||||
set_value_of_register(CPU6502::Register::ProgramCounter, 0xfccf);
|
||||
set_value_of_register(CPU::MOS6502::Register::ProgramCounter, 0xfccf);
|
||||
*value = 0xea; // i.e. NOP implied
|
||||
}
|
||||
}
|
||||
@ -181,7 +181,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
|
||||
user_port_via_->run_for_cycles(1);
|
||||
keyboard_via_->run_for_cycles(1);
|
||||
if(typer_ && operation == CPU6502::BusOperation::ReadOpcode && address == 0xEB1E) {
|
||||
if(typer_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && address == 0xEB1E) {
|
||||
if(!typer_->type_next_character()) {
|
||||
clear_all_keys();
|
||||
typer_.reset();
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "../../CRTMachine.hpp"
|
||||
#include "../../Typer.hpp"
|
||||
|
||||
#include "../../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../../Processors/6502/6502.hpp"
|
||||
#include "../../../Components/6560/6560.hpp"
|
||||
#include "../../../Components/6522/6522.hpp"
|
||||
|
||||
@ -141,7 +141,7 @@ class Vic6560: public MOS::MOS6560<Vic6560> {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CRTMachine::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
@ -167,16 +167,16 @@ class Machine:
|
||||
|
||||
inline void set_use_fast_tape_hack(bool activate) { use_fast_tape_hack_ = activate; }
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void synchronise() { mos6560_->synchronise(); }
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void flush() { mos6560_->flush(); }
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
virtual void setup_output(float aspect_ratio);
|
||||
virtual void close_output();
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return mos6560_->get_crt(); }
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return mos6560_->get_speaker(); }
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
|
||||
// to satisfy MOS::MOS6522::Delegate
|
||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
|
@ -123,7 +123,7 @@ void Machine::set_rom(ROMSlot slot, std::vector<uint8_t> data, bool is_writeable
|
||||
|
||||
#pragma mark - The bus
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int cycles = 1;
|
||||
|
||||
if(address < 0x8000) {
|
||||
@ -246,7 +246,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
if(
|
||||
use_fast_tape_hack_ &&
|
||||
tape_.has_tape() &&
|
||||
(operation == CPU6502::BusOperation::ReadOpcode) &&
|
||||
(operation == CPU::MOS6502::BusOperation::ReadOpcode) &&
|
||||
(
|
||||
(address == 0xf4e5) || (address == 0xf4e6) || // double NOPs at 0xf4e5, 0xf6de, 0xf6fa and 0xfa51
|
||||
(address == 0xf6de) || (address == 0xf6df) || // act to disable the normal branch into tape-handling
|
||||
@ -263,7 +263,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
// allow the PC read to return an RTS.
|
||||
)
|
||||
) {
|
||||
uint8_t service_call = (uint8_t)get_value_of_register(CPU6502::Register::X);
|
||||
uint8_t service_call = (uint8_t)get_value_of_register(CPU::MOS6502::Register::X);
|
||||
if(address == 0xf0a8) {
|
||||
if(!ram_[0x247] && service_call == 14) {
|
||||
tape_.set_delegate(nullptr);
|
||||
@ -285,8 +285,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
interrupt_status_ |= tape_.get_interrupt_status();
|
||||
|
||||
fast_load_is_in_data_ = true;
|
||||
set_value_of_register(CPU6502::Register::A, 0);
|
||||
set_value_of_register(CPU6502::Register::Y, tape_.get_data_register());
|
||||
set_value_of_register(CPU::MOS6502::Register::A, 0);
|
||||
set_value_of_register(CPU::MOS6502::Register::Y, tape_.get_data_register());
|
||||
*value = 0x60; // 0x60 is RTS
|
||||
}
|
||||
else *value = os_[address & 16383];
|
||||
@ -343,7 +343,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
return cycles;
|
||||
}
|
||||
|
||||
void Machine::synchronise() {
|
||||
void Machine::flush() {
|
||||
update_display();
|
||||
update_audio();
|
||||
speaker_->flush();
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef Electron_hpp
|
||||
#define Electron_hpp
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Storage/Tape/Tape.hpp"
|
||||
|
||||
#include "../ConfigurationTarget.hpp"
|
||||
@ -68,7 +68,7 @@ enum Key: uint16_t {
|
||||
Acorn Electron.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CRTMachine::Machine,
|
||||
public Tape::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
@ -87,16 +87,16 @@ class Machine:
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void synchronise();
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void flush();
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
virtual void setup_output(float aspect_ratio);
|
||||
virtual void close_output();
|
||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt();
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker();
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
virtual void run_for_cycles(int number_of_cycles) { CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
|
||||
|
||||
// to satisfy Tape::Delegate
|
||||
virtual void tape_did_change_interrupt_status(Tape *tape);
|
||||
|
@ -78,16 +78,16 @@ void Machine::set_rom(ROM rom, const std::vector<uint8_t> &data) {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(address > ram_top_) {
|
||||
if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1];
|
||||
|
||||
// 024D = 0 => fast; otherwise slow
|
||||
// E6C9 = read byte: return byte in A
|
||||
if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) {
|
||||
if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) {
|
||||
uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
|
||||
set_value_of_register(CPU6502::A, next_byte);
|
||||
set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero);
|
||||
set_value_of_register(CPU::MOS6502::A, next_byte);
|
||||
set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
|
||||
*value = 0x60; // i.e. RTS
|
||||
}
|
||||
} else {
|
||||
@ -120,7 +120,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
}
|
||||
}
|
||||
|
||||
if(typer_ && address == scan_keyboard_address_ && operation == CPU6502::BusOperation::ReadOpcode) {
|
||||
if(typer_ && address == scan_keyboard_address_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) {
|
||||
// the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't
|
||||
// do anything until at least the second, regardless of machine
|
||||
if(!keyboard_read_count_) keyboard_read_count_++;
|
||||
@ -136,9 +136,9 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Machine::synchronise() {
|
||||
void Machine::flush() {
|
||||
update_video();
|
||||
via_.synchronise();
|
||||
via_.flush();
|
||||
}
|
||||
|
||||
void Machine::update_video() {
|
||||
@ -199,7 +199,7 @@ std::shared_ptr<Outputs::Speaker> Machine::get_speaker() {
|
||||
}
|
||||
|
||||
void Machine::run_for_cycles(int number_of_cycles) {
|
||||
CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
CPU::MOS6502::Processor<Machine>::run_for_cycles(number_of_cycles);
|
||||
}
|
||||
|
||||
#pragma mark - The 6522
|
||||
@ -234,7 +234,7 @@ uint8_t Machine::VIA::get_port_input(Port port) {
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::VIA::synchronise() {
|
||||
void Machine::VIA::flush() {
|
||||
ay8910->run_for_cycles(cycles_since_ay_update_);
|
||||
ay8910->flush();
|
||||
cycles_since_ay_update_ = 0;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "../Typer.hpp"
|
||||
|
||||
#include "../../Processors/6502/CPU6502.hpp"
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Components/6522/6522.hpp"
|
||||
#include "../../Components/AY38910/AY38910.hpp"
|
||||
#include "../../Storage/Tape/Parsers/Oric.hpp"
|
||||
@ -57,7 +57,7 @@ enum ROM {
|
||||
};
|
||||
|
||||
class Machine:
|
||||
public CPU6502::Processor<Machine>,
|
||||
public CPU::MOS6502::Processor<Machine>,
|
||||
public CRTMachine::Machine,
|
||||
public ConfigurationTarget::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
@ -78,9 +78,9 @@ class Machine:
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
|
||||
// to satisfy CPU6502::Processor
|
||||
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void synchronise();
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
unsigned int perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void flush();
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
virtual void setup_output(float aspect_ratio);
|
||||
@ -151,7 +151,7 @@ class Machine:
|
||||
std::unique_ptr<TapePlayer> tape;
|
||||
std::shared_ptr<Keyboard> keyboard;
|
||||
|
||||
void synchronise();
|
||||
void flush();
|
||||
|
||||
private:
|
||||
void update_ay();
|
||||
|
@ -8,13 +8,14 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.swift */; };
|
||||
4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; };
|
||||
4B0BE4281D3481E700D5256B /* DigitalPhaseLockedLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */; };
|
||||
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; };
|
||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; };
|
||||
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */; };
|
||||
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
|
||||
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; };
|
||||
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */; };
|
||||
4B14145B1B58879D00E04248 /* 6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* 6502.cpp */; };
|
||||
4B14145D1B5887A600E04248 /* 6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* 6502.cpp */; };
|
||||
4B14145E1B5887AA00E04248 /* 6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* 6502AllRAM.cpp */; };
|
||||
4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */; };
|
||||
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; };
|
||||
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D08051E0F7A1100763741 /* TimeTests.mm */; };
|
||||
@ -43,7 +44,7 @@
|
||||
4B3BA0CE1D318B44005DD7A7 /* C1540Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */; };
|
||||
4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */; };
|
||||
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */; };
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */; };
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine6502.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */; };
|
||||
4B3F1B461E0388D200DB26EE /* PCMPatchedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F1B441E0388D200DB26EE /* PCMPatchedTrack.cpp */; };
|
||||
4B44EBF51DC987AF00A7820C /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */; };
|
||||
4B44EBF71DC9883B00A7820C /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */; };
|
||||
@ -68,6 +69,7 @@
|
||||
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; };
|
||||
4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; };
|
||||
4B6C73BD1D387AE500AFCFCA /* DiskController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6C73BB1D387AE500AFCFCA /* DiskController.cpp */; };
|
||||
4B77069D1EC904570053B588 /* Z80.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B77069B1EC904570053B588 /* Z80.cpp */; };
|
||||
4B7913CC1DFCD80E00175A82 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7913CA1DFCD80E00175A82 /* Video.cpp */; };
|
||||
4B79E4441E3AF38600141F11 /* cassette.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B79E4411E3AF38600141F11 /* cassette.png */; };
|
||||
4B79E4451E3AF38600141F11 /* floppy35.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B79E4421E3AF38600141F11 /* floppy35.png */; };
|
||||
@ -96,6 +98,8 @@
|
||||
4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */; };
|
||||
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAB62B31D327F7E00DF5BA0 /* G64.cpp */; };
|
||||
4BAB62B81D3302CA00DF5BA0 /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAB62B61D3302CA00DF5BA0 /* PCMTrack.cpp */; };
|
||||
4BB17D4E1ED7909F00ABD1E1 /* tests.expected.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BB17D4C1ED7909F00ABD1E1 /* tests.expected.json */; };
|
||||
4BB17D4F1ED7909F00ABD1E1 /* tests.in.json in Resources */ = {isa = PBXBuildFile; fileRef = 4BB17D4D1ED7909F00ABD1E1 /* tests.in.json */; };
|
||||
4BB298F11B587D8400A49093 /* start in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E51B587D8300A49093 /* start */; };
|
||||
4BB298F21B587D8400A49093 /* adca in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E61B587D8300A49093 /* adca */; };
|
||||
4BB298F31B587D8400A49093 /* adcax in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E71B587D8300A49093 /* adcax */; };
|
||||
@ -370,6 +374,7 @@
|
||||
4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */; };
|
||||
4BB73EC21B587A5100552FC2 /* Clock_SignalUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EC11B587A5100552FC2 /* Clock_SignalUITests.swift */; };
|
||||
4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB142F1CD2CECE00BDB55C /* IntermediateShader.cpp */; };
|
||||
4BBF49AF1ED2880200AB3669 /* FUSETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF49AE1ED2880200AB3669 /* FUSETests.swift */; };
|
||||
4BBF99141C8FBA6F0075DAFB /* TextureBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99081C8FBA6F0075DAFB /* TextureBuilder.cpp */; };
|
||||
4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */; };
|
||||
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99121C8FBA6F0075DAFB /* TextureTarget.cpp */; };
|
||||
@ -399,6 +404,7 @@
|
||||
4BD69F941D98760000243FE1 /* AcornADF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD69F921D98760000243FE1 /* AcornADF.cpp */; };
|
||||
4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE77A2C1D84ADFB00BC3827 /* File.cpp */; };
|
||||
4BE7C9181E3D397100A5496D /* TIA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE7C9161E3D397100A5496D /* TIA.cpp */; };
|
||||
4BE9A6B11EDE293000CBCB47 /* zexdoc.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BE9A6B01EDE293000CBCB47 /* zexdoc.com */; };
|
||||
4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA525D1DF33323007E74F2 /* Tape.cpp */; };
|
||||
4BEA52631DF339D7007E74F2 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52611DF339D7007E74F2 /* Speaker.cpp */; };
|
||||
4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52641DF3472B007E74F2 /* Speaker.cpp */; };
|
||||
@ -410,6 +416,11 @@
|
||||
4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295B1D8F048B001BAE39 /* MFM.cpp */; };
|
||||
4BF829631D8F536B001BAE39 /* SSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829611D8F536B001BAE39 /* SSD.cpp */; };
|
||||
4BF829661D8F732B001BAE39 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829641D8F732B001BAE39 /* Disk.cpp */; };
|
||||
4BFCA1201ECBDC1500AC40C1 /* Z80AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.cpp */; };
|
||||
4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */; };
|
||||
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */; };
|
||||
4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BFCA1281ECBE7A700AC40C1 /* zexall.com */; };
|
||||
4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -432,6 +443,7 @@
|
||||
/* Begin PBXFileReference section */
|
||||
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTMachine.hpp; sourceTree = "<group>"; };
|
||||
4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = "<group>"; };
|
||||
4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = "<group>"; };
|
||||
4B0B6E121C9DBD5D00FFB60D /* CRTConstants.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CRTConstants.hpp; sourceTree = "<group>"; };
|
||||
4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DigitalPhaseLockedLoop.cpp; sourceTree = "<group>"; };
|
||||
4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DigitalPhaseLockedLoop.hpp; sourceTree = "<group>"; };
|
||||
@ -442,10 +454,10 @@
|
||||
4B121F971E060CF000BFDA12 /* PCMSegment.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMSegment.hpp; sourceTree = "<group>"; };
|
||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMSegmentEventSourceTests.mm; sourceTree = "<group>"; };
|
||||
4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ClockSignal-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
4B1414571B58879D00E04248 /* CPU6502.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPU6502.cpp; sourceTree = "<group>"; };
|
||||
4B1414581B58879D00E04248 /* CPU6502.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502.hpp; sourceTree = "<group>"; };
|
||||
4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPU6502AllRAM.cpp; sourceTree = "<group>"; };
|
||||
4B14145A1B58879D00E04248 /* CPU6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502AllRAM.hpp; sourceTree = "<group>"; };
|
||||
4B1414571B58879D00E04248 /* 6502.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502.cpp; sourceTree = "<group>"; };
|
||||
4B1414581B58879D00E04248 /* 6502.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502.hpp; sourceTree = "<group>"; };
|
||||
4B1414591B58879D00E04248 /* 6502AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502AllRAM.cpp; sourceTree = "<group>"; };
|
||||
4B14145A1B58879D00E04248 /* 6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502AllRAM.hpp; sourceTree = "<group>"; };
|
||||
4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WolfgangLorenzTests.swift; sourceTree = "<group>"; };
|
||||
4B1414611B58888700E04248 /* KlausDormannTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KlausDormannTests.swift; sourceTree = "<group>"; };
|
||||
4B1D08051E0F7A1100763741 /* TimeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TimeTests.mm; sourceTree = "<group>"; };
|
||||
@ -479,6 +491,7 @@
|
||||
4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Oric/Video.cpp; sourceTree = "<group>"; };
|
||||
4B2BFDB11DAEF5FF001A68B8 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Oric/Video.hpp; sourceTree = "<group>"; };
|
||||
4B2C45411E3C3896002A2389 /* cartridge.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cartridge.png; sourceTree = "<group>"; };
|
||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RegisterSizes.hpp; sourceTree = "<group>"; };
|
||||
4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = "<group>"; };
|
||||
4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = "<group>"; };
|
||||
4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = "<group>"; };
|
||||
@ -500,8 +513,8 @@
|
||||
4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6522Bridge.mm; sourceTree = "<group>"; };
|
||||
4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOS6532Bridge.h; sourceTree = "<group>"; };
|
||||
4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6532Bridge.mm; sourceTree = "<group>"; };
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = "<group>"; };
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = "<group>"; };
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine6502.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine6502.h; sourceTree = "<group>"; };
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine6502.mm; sourceTree = "<group>"; };
|
||||
4B3F1B441E0388D200DB26EE /* PCMPatchedTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMPatchedTrack.cpp; sourceTree = "<group>"; };
|
||||
4B3F1B451E0388D200DB26EE /* PCMPatchedTrack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMPatchedTrack.hpp; sourceTree = "<group>"; };
|
||||
4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = AllSuiteA.bin; path = AllSuiteA/AllSuiteA.bin; sourceTree = "<group>"; };
|
||||
@ -544,6 +557,9 @@
|
||||
4B69FB451C4D950F00B5F0AA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
4B6C73BB1D387AE500AFCFCA /* DiskController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskController.cpp; sourceTree = "<group>"; };
|
||||
4B6C73BC1D387AE500AFCFCA /* DiskController.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = "<group>"; };
|
||||
4B77069B1EC904570053B588 /* Z80.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80.cpp; path = Z80/Z80.cpp; sourceTree = "<group>"; };
|
||||
4B77069C1EC904570053B588 /* Z80.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80.hpp; path = Z80/Z80.hpp; sourceTree = "<group>"; };
|
||||
4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MicroOpScheduler.hpp; sourceTree = "<group>"; };
|
||||
4B7913CA1DFCD80E00175A82 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Electron/Video.cpp; sourceTree = "<group>"; };
|
||||
4B7913CB1DFCD80E00175A82 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Electron/Video.hpp; sourceTree = "<group>"; };
|
||||
4B79E4411E3AF38600141F11 /* cassette.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cassette.png; sourceTree = "<group>"; };
|
||||
@ -590,6 +606,8 @@
|
||||
4BAB62B41D327F7E00DF5BA0 /* G64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = G64.hpp; sourceTree = "<group>"; };
|
||||
4BAB62B61D3302CA00DF5BA0 /* PCMTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMTrack.cpp; sourceTree = "<group>"; };
|
||||
4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMTrack.hpp; sourceTree = "<group>"; };
|
||||
4BB17D4C1ED7909F00ABD1E1 /* tests.expected.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = tests.expected.json; path = FUSE/tests.expected.json; sourceTree = "<group>"; };
|
||||
4BB17D4D1ED7909F00ABD1E1 /* tests.in.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = tests.in.json; path = FUSE/tests.in.json; sourceTree = "<group>"; };
|
||||
4BB297E51B587D8300A49093 /* start */ = {isa = PBXFileReference; lastKnownFileType = file; path = " start"; sourceTree = "<group>"; };
|
||||
4BB297E61B587D8300A49093 /* adca */ = {isa = PBXFileReference; lastKnownFileType = file; path = adca; sourceTree = "<group>"; };
|
||||
4BB297E71B587D8300A49093 /* adcax */ = {isa = PBXFileReference; lastKnownFileType = file; path = adcax; sourceTree = "<group>"; };
|
||||
@ -876,6 +894,7 @@
|
||||
4BBB142F1CD2CECE00BDB55C /* IntermediateShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermediateShader.cpp; sourceTree = "<group>"; };
|
||||
4BBB14301CD2CECE00BDB55C /* IntermediateShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IntermediateShader.hpp; sourceTree = "<group>"; };
|
||||
4BBC34241D2208B100FFC9DF /* CSFastLoading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSFastLoading.h; sourceTree = "<group>"; };
|
||||
4BBF49AE1ED2880200AB3669 /* FUSETests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FUSETests.swift; sourceTree = "<group>"; };
|
||||
4BBF99081C8FBA6F0075DAFB /* TextureBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextureBuilder.cpp; sourceTree = "<group>"; };
|
||||
4BBF99091C8FBA6F0075DAFB /* TextureBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TextureBuilder.hpp; sourceTree = "<group>"; };
|
||||
4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTOpenGL.cpp; sourceTree = "<group>"; };
|
||||
@ -928,6 +947,7 @@
|
||||
4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = "<group>"; };
|
||||
4BE7C9161E3D397100A5496D /* TIA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cpp; sourceTree = "<group>"; };
|
||||
4BE7C9171E3D397100A5496D /* TIA.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIA.hpp; sourceTree = "<group>"; };
|
||||
4BE9A6B01EDE293000CBCB47 /* zexdoc.com */ = {isa = PBXFileReference; lastKnownFileType = file; name = zexdoc.com; path = Zexall/zexdoc.com; sourceTree = "<group>"; };
|
||||
4BEA525D1DF33323007E74F2 /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = Electron/Tape.cpp; sourceTree = "<group>"; };
|
||||
4BEA525F1DF333D8007E74F2 /* Tape.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = Electron/Tape.hpp; sourceTree = "<group>"; };
|
||||
4BEA52601DF3343A007E74F2 /* Interrupts.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Interrupts.hpp; path = Electron/Interrupts.hpp; sourceTree = "<group>"; };
|
||||
@ -967,6 +987,14 @@
|
||||
4BF829641D8F732B001BAE39 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disk.cpp; path = ../../StaticAnalyser/Acorn/Disk.cpp; sourceTree = "<group>"; };
|
||||
4BF829651D8F732B001BAE39 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Disk.hpp; path = ../../StaticAnalyser/Acorn/Disk.hpp; sourceTree = "<group>"; };
|
||||
4BF829681D8F7361001BAE39 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Acorn/File.hpp; sourceTree = "<group>"; };
|
||||
4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80AllRAM.cpp; path = Z80/Z80AllRAM.cpp; sourceTree = "<group>"; };
|
||||
4BFCA11E1ECBD9BD00AC40C1 /* Z80AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80AllRAM.hpp; path = Z80/Z80AllRAM.hpp; sourceTree = "<group>"; };
|
||||
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AllRAMProcessor.cpp; sourceTree = "<group>"; };
|
||||
4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AllRAMProcessor.hpp; sourceTree = "<group>"; };
|
||||
4BFCA1251ECBE33200AC40C1 /* TestMachineZ80.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachineZ80.h; sourceTree = "<group>"; };
|
||||
4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachineZ80.mm; sourceTree = "<group>"; };
|
||||
4BFCA1281ECBE7A700AC40C1 /* zexall.com */ = {isa = PBXFileReference; lastKnownFileType = file; name = zexall.com; path = Zexall/zexall.com; sourceTree = "<group>"; };
|
||||
4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZexallTests.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -1011,10 +1039,10 @@
|
||||
4B1414561B58879D00E04248 /* 6502 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B1414571B58879D00E04248 /* CPU6502.cpp */,
|
||||
4B1414581B58879D00E04248 /* CPU6502.hpp */,
|
||||
4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */,
|
||||
4B14145A1B58879D00E04248 /* CPU6502AllRAM.hpp */,
|
||||
4B1414571B58879D00E04248 /* 6502.cpp */,
|
||||
4B1414581B58879D00E04248 /* 6502.hpp */,
|
||||
4B1414591B58879D00E04248 /* 6502AllRAM.cpp */,
|
||||
4B14145A1B58879D00E04248 /* 6502AllRAM.hpp */,
|
||||
);
|
||||
path = 6502;
|
||||
sourceTree = "<group>";
|
||||
@ -1023,9 +1051,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B9252CD1E74D28200B76AF1 /* Atari ROMs */,
|
||||
4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */,
|
||||
4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */,
|
||||
4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */,
|
||||
4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */,
|
||||
4BE9A6B21EDE294200CBCB47 /* Zexall */,
|
||||
4BBF49B41ED2881600AB3669 /* FUSE */,
|
||||
4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */,
|
||||
);
|
||||
name = "Test Binaries";
|
||||
@ -1169,12 +1199,14 @@
|
||||
4BEF6AA81D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.h */,
|
||||
4B3BA0C81D318B44005DD7A7 /* MOS6522Bridge.h */,
|
||||
4B3BA0CA1D318B44005DD7A7 /* MOS6532Bridge.h */,
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine.h */,
|
||||
4B3BA0CC1D318B44005DD7A7 /* TestMachine6502.h */,
|
||||
4BFCA1251ECBE33200AC40C1 /* TestMachineZ80.h */,
|
||||
4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */,
|
||||
4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */,
|
||||
4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */,
|
||||
4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */,
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */,
|
||||
4B3BA0CD1D318B44005DD7A7 /* TestMachine6502.mm */,
|
||||
4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */,
|
||||
);
|
||||
path = Bridges;
|
||||
sourceTree = "<group>";
|
||||
@ -1315,6 +1347,17 @@
|
||||
path = Formats;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B77069E1EC9045B0053B588 /* Z80 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B77069B1EC904570053B588 /* Z80.cpp */,
|
||||
4B77069C1EC904570053B588 /* Z80.hpp */,
|
||||
4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.cpp */,
|
||||
4BFCA11E1ECBD9BD00AC40C1 /* Z80AllRAM.hpp */,
|
||||
);
|
||||
name = Z80;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B8805F11DCFC9A2003085B1 /* Parsers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1751,8 +1794,11 @@
|
||||
4B049CDC1DA3C82F00322067 /* BCDTest.swift */,
|
||||
4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */,
|
||||
4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */,
|
||||
4BBF49AE1ED2880200AB3669 /* FUSETests.swift */,
|
||||
4B1414611B58888700E04248 /* KlausDormannTests.swift */,
|
||||
4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */,
|
||||
4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */,
|
||||
4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */,
|
||||
4B3BA0C41D318B44005DD7A7 /* Bridges */,
|
||||
4B1414631B588A1100E04248 /* Test Binaries */,
|
||||
);
|
||||
@ -1791,11 +1837,25 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B1414561B58879D00E04248 /* 6502 */,
|
||||
4B77069E1EC9045B0053B588 /* Z80 */,
|
||||
4B7706A01EC9398D0053B588 /* MicroOpScheduler.hpp */,
|
||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
|
||||
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */,
|
||||
4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */,
|
||||
);
|
||||
name = Processors;
|
||||
path = ../../Processors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BBF49B41ED2881600AB3669 /* FUSE */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BB17D4C1ED7909F00ABD1E1 /* tests.expected.json */,
|
||||
4BB17D4D1ED7909F00ABD1E1 /* tests.in.json */,
|
||||
);
|
||||
name = FUSE;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BBF99071C8FBA6F0075DAFB /* Internals */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1948,6 +2008,15 @@
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BE9A6B21EDE294200CBCB47 /* Zexall */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BFCA1281ECBE7A700AC40C1 /* zexall.com */,
|
||||
4BE9A6B01EDE293000CBCB47 /* zexdoc.com */,
|
||||
);
|
||||
name = Zexall;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BEAC0801E7E0DF800EE56B2 /* Cartridges */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2147,6 +2216,7 @@
|
||||
4BB2998A1B587D8400A49093 /* lseix in Resources */,
|
||||
4BB2994E1B587D8400A49093 /* dexn in Resources */,
|
||||
4BB299971B587D8400A49093 /* nopa in Resources */,
|
||||
4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */,
|
||||
4BB299521B587D8400A49093 /* eoray in Resources */,
|
||||
4BB299411B587D8400A49093 /* cpyb in Resources */,
|
||||
4BB299A61B587D8400A49093 /* phan in Resources */,
|
||||
@ -2230,6 +2300,7 @@
|
||||
4BB298F21B587D8400A49093 /* adca in Resources */,
|
||||
4BB299391B587D8400A49093 /* cntdef in Resources */,
|
||||
4BB299591B587D8400A49093 /* flipos in Resources */,
|
||||
4BB17D4E1ED7909F00ABD1E1 /* tests.expected.json in Resources */,
|
||||
4BB2998F1B587D8400A49093 /* lsrax in Resources */,
|
||||
4BB299001B587D8400A49093 /* andix in Resources */,
|
||||
4BB2993A1B587D8400A49093 /* cnto2 in Resources */,
|
||||
@ -2281,6 +2352,7 @@
|
||||
4BB299C61B587D8400A49093 /* sbcay in Resources */,
|
||||
4BB299601B587D8400A49093 /* insa in Resources */,
|
||||
4BB299951B587D8400A49093 /* mmufetch in Resources */,
|
||||
4BB17D4F1ED7909F00ABD1E1 /* tests.in.json in Resources */,
|
||||
4BB299A71B587D8400A49093 /* phpn in Resources */,
|
||||
4BB299CC1B587D8400A49093 /* sbczx in Resources */,
|
||||
4BB299C91B587D8400A49093 /* sbcix in Resources */,
|
||||
@ -2312,6 +2384,7 @@
|
||||
4BB299781B587D8400A49093 /* ldaix in Resources */,
|
||||
4B44EBF71DC9883B00A7820C /* 6502_functional_test.bin in Resources */,
|
||||
4BB299291B587D8400A49093 /* cia2pb7 in Resources */,
|
||||
4BE9A6B11EDE293000CBCB47 /* zexdoc.com in Resources */,
|
||||
4BB2994A1B587D8400A49093 /* deca in Resources */,
|
||||
4BB299CA1B587D8400A49093 /* sbciy in Resources */,
|
||||
4BB2993D1B587D8400A49093 /* cpxa in Resources */,
|
||||
@ -2464,6 +2537,7 @@
|
||||
4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */,
|
||||
4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */,
|
||||
4B5FADBD1DE31D1500AEC565 /* OricMFMDSK.cpp in Sources */,
|
||||
4B77069D1EC904570053B588 /* Z80.cpp in Sources */,
|
||||
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */,
|
||||
4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */,
|
||||
4BBF99141C8FBA6F0075DAFB /* TextureBuilder.cpp in Sources */,
|
||||
@ -2502,7 +2576,7 @@
|
||||
4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */,
|
||||
4B4C83701D4F623200CD541F /* D64.cpp in Sources */,
|
||||
4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */,
|
||||
4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */,
|
||||
4B14145B1B58879D00E04248 /* 6502.cpp in Sources */,
|
||||
4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */,
|
||||
4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */,
|
||||
4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */,
|
||||
@ -2522,22 +2596,27 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */,
|
||||
4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */,
|
||||
4B14145E1B5887AA00E04248 /* 6502AllRAM.cpp in Sources */,
|
||||
4B14145D1B5887A600E04248 /* 6502.cpp in Sources */,
|
||||
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */,
|
||||
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */,
|
||||
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */,
|
||||
4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */,
|
||||
4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */,
|
||||
4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */,
|
||||
4B50730A1DDFCFDF00C48FBD /* ArrayBuilderTests.mm in Sources */,
|
||||
4BBF49AF1ED2880200AB3669 /* FUSETests.swift in Sources */,
|
||||
4B2AF8691E513FC20027EE29 /* TIATests.mm in Sources */,
|
||||
4B3BA0CE1D318B44005DD7A7 /* C1540Bridge.mm in Sources */,
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine.mm in Sources */,
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine6502.mm in Sources */,
|
||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */,
|
||||
4BFCA1201ECBDC1500AC40C1 /* Z80AllRAM.cpp in Sources */,
|
||||
4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */,
|
||||
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */,
|
||||
4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */,
|
||||
4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */,
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */,
|
||||
4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */,
|
||||
4BB2A9AF1E13367E001A5C23 /* CRCTests.mm in Sources */,
|
||||
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */,
|
||||
4B3BA0C31D318AEC005DD7A7 /* C1540Tests.swift in Sources */,
|
||||
@ -2546,6 +2625,7 @@
|
||||
4BD4A8D01E077FD20020D856 /* PCMTrackTests.mm in Sources */,
|
||||
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */,
|
||||
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
|
||||
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
|
||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -38,6 +38,11 @@
|
||||
BlueprintName = "Clock SignalTests"
|
||||
ReferencedContainer = "container:Clock Signal.xcodeproj">
|
||||
</BuildableReference>
|
||||
<SkippedTests>
|
||||
<Test
|
||||
Identifier = "ZexallTests">
|
||||
</Test>
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "YES">
|
||||
@ -63,7 +68,7 @@
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
@ -10,12 +10,12 @@ import XCTest
|
||||
|
||||
class MOS6502InterruptTests: XCTestCase {
|
||||
|
||||
var machine: CSTestMachine! = nil
|
||||
var machine: CSTestMachine6502! = nil
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
// create a machine full of NOPs
|
||||
machine = CSTestMachine()
|
||||
machine = CSTestMachine6502()
|
||||
for c in 0...65535 {
|
||||
machine.setValue(0xea, forAddress: UInt16(c))
|
||||
}
|
||||
@ -28,7 +28,7 @@ class MOS6502InterruptTests: XCTestCase {
|
||||
machine.setValue(0x58, forAddress: 0x4000)
|
||||
|
||||
// pick things off at 0x4000
|
||||
machine.setValue(0x4000, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0x4000, for: CSTestMachine6502Register.programCounter)
|
||||
}
|
||||
|
||||
func testIRQLine() {
|
||||
|
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
class MOS6502TimingTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
|
||||
fileprivate var endTime: UInt32 = 0
|
||||
|
||||
@ -20,7 +20,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0xca, // [2] DEX
|
||||
0x18, // [2] CLC
|
||||
0x2a, // [2] ROL A
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 10)
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0xa1, 0x44, // [6] LDA ($44, x)
|
||||
0xb1, 0x00, // [5] LDA ($00), y (no wrap)
|
||||
0xb1, 0x02, // [6] LDA ($01), y (wrap)
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 48)
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
let code: [UInt8] = [
|
||||
0x24, 0x2a, // [3] BIT $2a
|
||||
0x2c, 0x2a, 0x2b, // [4] BIT $2b2a
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 7)
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0x81, 0x44, // [6] STA ($44, x)
|
||||
0x91, 0x00, // [6] STA ($00), y (no wrap)
|
||||
0x91, 0x02, // [6] STA ($01), y (wrap)
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 49)
|
||||
}
|
||||
|
||||
@ -72,14 +72,14 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0xee, 0x00, 0x00, // [6] INC $0000
|
||||
0xfe, 0x00, 0x00, // [7] INC $0000, x (no wrap)
|
||||
0xfe, 0x02, 0x00, // [7] INC $0002, x (wrap)
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 31)
|
||||
}
|
||||
|
||||
func testJSR() {
|
||||
let code: [UInt8] = [
|
||||
0x20, 0x04, 0x02, // [6] JSR $0204
|
||||
CSTestMachineJamOpcode,
|
||||
CSTestMachine6502JamOpcode,
|
||||
0x60, // [6] RTS
|
||||
]
|
||||
self.runTest(code, expectedRunLength: 12)
|
||||
@ -90,7 +90,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0x6c, 0x04, 0x00, // [5] JMP ($0004)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x4c, 0x0b, 0x02, // [3] JMP 020b
|
||||
CSTestMachineJamOpcode,
|
||||
CSTestMachine6502JamOpcode,
|
||||
]
|
||||
self.runTest(code, expectedRunLength: 8)
|
||||
}
|
||||
@ -100,7 +100,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0x48, // [3] PHA
|
||||
0x48, // [3] PHA
|
||||
0x68, // [4] PLA
|
||||
CSTestMachineJamOpcode,
|
||||
CSTestMachine6502JamOpcode,
|
||||
]
|
||||
self.runTest(code, expectedRunLength: 10)
|
||||
}
|
||||
@ -128,7 +128,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 14)
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
let code: [UInt8] = [
|
||||
0x8d, 0x08, 0x00, // [4] STA $0008
|
||||
0xc6, 0xb4, // [5] DEC $B4
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 9)
|
||||
}
|
||||
|
||||
@ -144,14 +144,14 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
let code: [UInt8] = [
|
||||
0x16, 0x16, // [6] ASL $16, x
|
||||
0x46, 0x46, // [5] LSR $46
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 11)
|
||||
}
|
||||
|
||||
func testSnippet3() {
|
||||
let code: [UInt8] = [
|
||||
0x20, 0x04, 0x02, // [6] JSR $0204
|
||||
CSTestMachineJamOpcode,
|
||||
CSTestMachine6502JamOpcode,
|
||||
0x86, 0x09, // [3] STX $09
|
||||
0x86, 0x09, // [3] STX $09
|
||||
0x85, 0x09, // [3] STA $09
|
||||
@ -171,7 +171,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0x86, 0x09, // [3] STX $09
|
||||
0x87, 0x09, // [3] SAX $09
|
||||
0x60, // [6] RTS
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 66)
|
||||
}
|
||||
|
||||
@ -191,12 +191,12 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
0xd4, 0x00, // [4] NOP zpg, x
|
||||
0xe2, 0x00, // [2] NOP #
|
||||
0xf4, 0x00, // [4] NOP zpg, x
|
||||
CSTestMachineJamOpcode]
|
||||
CSTestMachine6502JamOpcode]
|
||||
self.runTest(code, expectedRunLength: 43)
|
||||
}
|
||||
|
||||
func runTest(_ code: [UInt8], expectedRunLength: UInt32) {
|
||||
let machine = CSTestMachine()
|
||||
let machine = CSTestMachine6502()
|
||||
|
||||
machine.jamHandler = self
|
||||
|
||||
@ -208,9 +208,9 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
machine.setValue(0x00, forAddress: 0x0003)
|
||||
machine.setValue(0x08, forAddress: 0x0004)
|
||||
machine.setValue(0x02, forAddress: 0x0005)
|
||||
machine.setValue(0x200, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0xff, for: CSTestMachineRegister.X)
|
||||
machine.setValue(0xfe, for: CSTestMachineRegister.Y)
|
||||
machine.setValue(0x200, for: CSTestMachine6502Register.programCounter)
|
||||
machine.setValue(0xff, for: CSTestMachine6502Register.X)
|
||||
machine.setValue(0xfe, for: CSTestMachine6502Register.Y)
|
||||
|
||||
self.endTime = 0
|
||||
while self.endTime == 0 {
|
||||
@ -220,7 +220,7 @@ class MOS6502TimingTests: XCTestCase, CSTestMachineJamHandler {
|
||||
XCTAssert(self.endTime == expectedRunLength, "Took \(self.endTime) cycles to perform rather than \(expectedRunLength)")
|
||||
}
|
||||
|
||||
func testMachine(_ machine: CSTestMachine!, didJamAtAddress address: UInt16) {
|
||||
func testMachine(_ machine: CSTestMachine6502!, didJamAtAddress address: UInt16) {
|
||||
if self.endTime == 0 {
|
||||
self.endTime = machine.timestamp - 9
|
||||
}
|
||||
|
@ -7,19 +7,18 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Clock_Signal
|
||||
|
||||
class AllSuiteATests: XCTestCase {
|
||||
|
||||
func testAllSuiteA() {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "AllSuiteA", ofType: "bin") {
|
||||
if let allSuiteA = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine()
|
||||
let machine = CSTestMachine6502()
|
||||
|
||||
machine.setData(allSuiteA, atAddress: 0x4000)
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0x45c0); // end
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0x45c0); // end
|
||||
|
||||
machine.setValue(0x4000, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0x4000, for: CSTestMachine6502Register.programCounter)
|
||||
while !machine.isJammed {
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
}
|
||||
|
@ -9,12 +9,12 @@
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
class BCDTest: XCTestCase, CSTestMachineJamHandler {
|
||||
class BCDTest: XCTestCase, CSTestMachine6502JamHandler {
|
||||
|
||||
func testBCD() {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "BCDTEST_beeb", ofType: nil) {
|
||||
if let bcdTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine()
|
||||
let machine = CSTestMachine6502()
|
||||
machine.jamHandler = self
|
||||
|
||||
machine.setData(bcdTest, atAddress: 0x2900)
|
||||
@ -27,10 +27,10 @@ class BCDTest: XCTestCase, CSTestMachineJamHandler {
|
||||
machine.setValue(0x03, forAddress:0x204)
|
||||
machine.setValue(0x02, forAddress:0x205)
|
||||
|
||||
machine.setValue(0x200, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0x200, for: .programCounter)
|
||||
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0xffee) // OSWRCH
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0xffff) // end of test
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffee) // OSWRCH
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffff) // end of test
|
||||
|
||||
while(machine.value(for: .programCounter) != 0x203) {
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
@ -41,11 +41,11 @@ class BCDTest: XCTestCase, CSTestMachineJamHandler {
|
||||
}
|
||||
|
||||
fileprivate var output: String = ""
|
||||
func testMachine(_ machine: CSTestMachine!, didJamAtAddress address: UInt16) {
|
||||
func testMachine(_ machine: CSTestMachine6502!, didJamAtAddress address: UInt16) {
|
||||
|
||||
switch address {
|
||||
case 0xffee:
|
||||
let character = machine.value(for: CSTestMachineRegister.A)
|
||||
let character = machine.value(for: .A)
|
||||
output.append(Character(UnicodeScalar(character)!))
|
||||
|
||||
machine.returnFromSubroutine()
|
||||
|
@ -2,7 +2,10 @@
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "TestMachine.h"
|
||||
#import "ClockSignal-Bridging-Header.h"
|
||||
|
||||
#import "TestMachine6502.h"
|
||||
#import "TestMachineZ80.h"
|
||||
#import "MOS6522Bridge.h"
|
||||
#import "MOS6532Bridge.h"
|
||||
#import "C1540Bridge.h"
|
||||
|
@ -1,47 +0,0 @@
|
||||
//
|
||||
// Machine.h
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 29/06/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSTestMachineRegister) {
|
||||
CSTestMachineRegisterLastOperationAddress,
|
||||
CSTestMachineRegisterProgramCounter,
|
||||
CSTestMachineRegisterStackPointer,
|
||||
CSTestMachineRegisterFlags,
|
||||
CSTestMachineRegisterA,
|
||||
CSTestMachineRegisterX,
|
||||
CSTestMachineRegisterY,
|
||||
};
|
||||
|
||||
extern const uint8_t CSTestMachineJamOpcode;
|
||||
|
||||
@class CSTestMachine;
|
||||
@protocol CSTestMachineJamHandler <NSObject>
|
||||
- (void)testMachine:(CSTestMachine *)machine didJamAtAddress:(uint16_t)address;
|
||||
@end
|
||||
|
||||
@interface CSTestMachine : NSObject
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (void)runForNumberOfCycles:(int)cycles;
|
||||
|
||||
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address;
|
||||
- (uint8_t)valueForAddress:(uint16_t)address;
|
||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineRegister)reg;
|
||||
- (uint16_t)valueForRegister:(CSTestMachineRegister)reg;
|
||||
|
||||
//- (void)reset;
|
||||
- (void)returnFromSubroutine;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isJammed;
|
||||
@property (nonatomic, readonly) uint32_t timestamp;
|
||||
@property (nonatomic, weak) id <CSTestMachineJamHandler> jamHandler;
|
||||
@property (nonatomic, assign) BOOL irqLine;
|
||||
@property (nonatomic, assign) BOOL nmiLine;
|
||||
|
||||
@end
|
@ -1,112 +0,0 @@
|
||||
//
|
||||
// Machine.m
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 29/06/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TestMachine.h"
|
||||
#include <stdint.h>
|
||||
#include "CPU6502AllRAM.hpp"
|
||||
|
||||
const uint8_t CSTestMachineJamOpcode = CPU6502::JamOpcode;
|
||||
|
||||
class MachineJamHandler: public CPU6502::AllRAMProcessor::JamHandler {
|
||||
public:
|
||||
MachineJamHandler(CSTestMachine *targetMachine) : _targetMachine(targetMachine) {}
|
||||
|
||||
void processor_did_jam(CPU6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
|
||||
[_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address];
|
||||
}
|
||||
|
||||
private:
|
||||
CSTestMachine *_targetMachine;
|
||||
};
|
||||
|
||||
@implementation CSTestMachine {
|
||||
CPU6502::AllRAMProcessor _processor;
|
||||
MachineJamHandler *_cppJamHandler;
|
||||
}
|
||||
|
||||
- (uint8_t)valueForAddress:(uint16_t)address {
|
||||
uint8_t value;
|
||||
_processor.perform_bus_operation(CPU6502::BusOperation::Read, address, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address {
|
||||
_processor.perform_bus_operation(CPU6502::BusOperation::Write, address, &value);
|
||||
}
|
||||
|
||||
- (void)returnFromSubroutine {
|
||||
_processor.return_from_subroutine();
|
||||
}
|
||||
|
||||
- (CPU6502::Register)registerForRegister:(CSTestMachineRegister)reg {
|
||||
switch (reg) {
|
||||
case CSTestMachineRegisterProgramCounter: return CPU6502::Register::ProgramCounter;
|
||||
case CSTestMachineRegisterLastOperationAddress: return CPU6502::Register::LastOperationAddress;
|
||||
case CSTestMachineRegisterFlags: return CPU6502::Register::Flags;
|
||||
case CSTestMachineRegisterA: return CPU6502::Register::A;
|
||||
case CSTestMachineRegisterX: return CPU6502::Register::X;
|
||||
case CSTestMachineRegisterY: return CPU6502::Register::Y;
|
||||
case CSTestMachineRegisterStackPointer: return CPU6502::Register::S;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineRegister)reg {
|
||||
_processor.set_value_of_register([self registerForRegister:reg], value);
|
||||
}
|
||||
|
||||
- (uint16_t)valueForRegister:(CSTestMachineRegister)reg {
|
||||
return _processor.get_value_of_register([self registerForRegister:reg]);
|
||||
}
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress {
|
||||
_processor.set_data_at_address(startAddress, data.length, (const uint8_t *)data.bytes);
|
||||
}
|
||||
|
||||
//- (void)reset {
|
||||
// _processor.reset();
|
||||
//}
|
||||
|
||||
- (void)runForNumberOfCycles:(int)cycles {
|
||||
_processor.run_for_cycles(cycles);
|
||||
}
|
||||
|
||||
- (BOOL)isJammed {
|
||||
return _processor.is_jammed();
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
if(self) {
|
||||
_cppJamHandler = new MachineJamHandler(self);
|
||||
_processor.set_jam_handler(_cppJamHandler);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete _cppJamHandler;
|
||||
}
|
||||
|
||||
- (uint32_t)timestamp {
|
||||
return _processor.get_timestamp();
|
||||
}
|
||||
|
||||
- (void)setIrqLine:(BOOL)irqLine {
|
||||
_irqLine = irqLine;
|
||||
_processor.set_irq_line(irqLine);
|
||||
}
|
||||
|
||||
- (void)setNmiLine:(BOOL)nmiLine {
|
||||
_nmiLine = nmiLine;
|
||||
_processor.set_nmi_line(nmiLine);
|
||||
}
|
||||
|
||||
@end
|
46
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h
Normal file
46
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// TestMachine6502.h
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 29/06/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSTestMachine6502Register) {
|
||||
CSTestMachine6502RegisterLastOperationAddress,
|
||||
CSTestMachine6502RegisterProgramCounter,
|
||||
CSTestMachine6502RegisterStackPointer,
|
||||
CSTestMachine6502RegisterFlags,
|
||||
CSTestMachine6502RegisterA,
|
||||
CSTestMachine6502RegisterX,
|
||||
CSTestMachine6502RegisterY,
|
||||
};
|
||||
|
||||
extern const uint8_t CSTestMachine6502JamOpcode;
|
||||
|
||||
@class CSTestMachine6502;
|
||||
@protocol CSTestMachine6502JamHandler <NSObject>
|
||||
- (void)testMachine:(CSTestMachine6502 *)machine didJamAtAddress:(uint16_t)address;
|
||||
@end
|
||||
|
||||
@interface CSTestMachine6502 : NSObject
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (void)runForNumberOfCycles:(int)cycles;
|
||||
|
||||
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address;
|
||||
- (uint8_t)valueForAddress:(uint16_t)address;
|
||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachine6502Register)reg;
|
||||
- (uint16_t)valueForRegister:(CSTestMachine6502Register)reg;
|
||||
|
||||
- (void)returnFromSubroutine;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isJammed;
|
||||
@property (nonatomic, readonly) uint32_t timestamp;
|
||||
@property (nonatomic, weak) id <CSTestMachine6502JamHandler> jamHandler;
|
||||
@property (nonatomic, assign) BOOL irqLine;
|
||||
@property (nonatomic, assign) BOOL nmiLine;
|
||||
|
||||
@end
|
119
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm
Normal file
119
OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm
Normal file
@ -0,0 +1,119 @@
|
||||
//
|
||||
// Machine.m
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 29/06/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TestMachine6502.h"
|
||||
#include <stdint.h>
|
||||
#include "6502AllRAM.hpp"
|
||||
|
||||
const uint8_t CSTestMachine6502JamOpcode = CPU::MOS6502::JamOpcode;
|
||||
|
||||
#pragma mark - C++ jam handler
|
||||
|
||||
class MachineJamHandler: public CPU::MOS6502::AllRAMProcessor::JamHandler {
|
||||
public:
|
||||
MachineJamHandler(CSTestMachine6502 *targetMachine) : _targetMachine(targetMachine) {}
|
||||
|
||||
void processor_did_jam(CPU::MOS6502::AllRAMProcessor::Processor *processor, uint16_t address) override {
|
||||
[_targetMachine.jamHandler testMachine:_targetMachine didJamAtAddress:address];
|
||||
}
|
||||
|
||||
private:
|
||||
CSTestMachine6502 *_targetMachine;
|
||||
};
|
||||
|
||||
#pragma mark - Register enum map
|
||||
|
||||
static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg) {
|
||||
switch (reg) {
|
||||
case CSTestMachine6502RegisterProgramCounter: return CPU::MOS6502::Register::ProgramCounter;
|
||||
case CSTestMachine6502RegisterLastOperationAddress: return CPU::MOS6502::Register::LastOperationAddress;
|
||||
case CSTestMachine6502RegisterFlags: return CPU::MOS6502::Register::Flags;
|
||||
case CSTestMachine6502RegisterA: return CPU::MOS6502::Register::A;
|
||||
case CSTestMachine6502RegisterX: return CPU::MOS6502::Register::X;
|
||||
case CSTestMachine6502RegisterY: return CPU::MOS6502::Register::Y;
|
||||
case CSTestMachine6502RegisterStackPointer: return CPU::MOS6502::Register::S;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Test class
|
||||
|
||||
@implementation CSTestMachine6502 {
|
||||
CPU::MOS6502::AllRAMProcessor _processor;
|
||||
MachineJamHandler *_cppJamHandler;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
if(self) {
|
||||
_cppJamHandler = new MachineJamHandler(self);
|
||||
_processor.set_jam_handler(_cppJamHandler);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete _cppJamHandler;
|
||||
}
|
||||
|
||||
#pragma mark - Accessors
|
||||
|
||||
- (uint8_t)valueForAddress:(uint16_t)address {
|
||||
uint8_t value;
|
||||
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Read, address, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setValue:(uint8_t)value forAddress:(uint16_t)address {
|
||||
_processor.perform_bus_operation(CPU::MOS6502::BusOperation::Write, address, &value);
|
||||
}
|
||||
|
||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachine6502Register)reg {
|
||||
_processor.set_value_of_register(registerForRegister(reg), value);
|
||||
}
|
||||
|
||||
- (uint16_t)valueForRegister:(CSTestMachine6502Register)reg {
|
||||
return _processor.get_value_of_register(registerForRegister(reg));
|
||||
}
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress {
|
||||
_processor.set_data_at_address(startAddress, data.length, (const uint8_t *)data.bytes);
|
||||
}
|
||||
|
||||
- (BOOL)isJammed {
|
||||
return _processor.is_jammed();
|
||||
}
|
||||
|
||||
- (uint32_t)timestamp {
|
||||
return _processor.get_timestamp();
|
||||
}
|
||||
|
||||
- (void)setIrqLine:(BOOL)irqLine {
|
||||
_irqLine = irqLine;
|
||||
_processor.set_irq_line(irqLine);
|
||||
}
|
||||
|
||||
- (void)setNmiLine:(BOOL)nmiLine {
|
||||
_nmiLine = nmiLine;
|
||||
_processor.set_nmi_line(nmiLine);
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)returnFromSubroutine {
|
||||
_processor.return_from_subroutine();
|
||||
}
|
||||
|
||||
- (void)runForNumberOfCycles:(int)cycles {
|
||||
_processor.run_for_cycles(cycles);
|
||||
}
|
||||
|
||||
@end
|
72
OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h
Normal file
72
OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// TestMachineZ80.h
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <stdint.h>
|
||||
|
||||
@class CSTestMachineZ80;
|
||||
|
||||
@protocol CSTestMachineTrapHandler
|
||||
- (void)testMachine:(nonnull CSTestMachineZ80 *)testMachine didTrapAtAddress:(uint16_t)address;
|
||||
@end
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSTestMachineZ80BusOperationCaptureOperation) {
|
||||
CSTestMachineZ80BusOperationCaptureOperationRead,
|
||||
CSTestMachineZ80BusOperationCaptureOperationWrite,
|
||||
CSTestMachineZ80BusOperationCaptureOperationPortRead,
|
||||
CSTestMachineZ80BusOperationCaptureOperationPortWrite,
|
||||
};
|
||||
|
||||
@interface CSTestMachineZ80BusOperationCapture: NSObject
|
||||
@property(nonatomic, readonly) CSTestMachineZ80BusOperationCaptureOperation operation;
|
||||
@property(nonatomic, readonly) uint16_t address;
|
||||
@property(nonatomic, readonly) uint8_t value;
|
||||
@property(nonatomic, readonly) int timeStamp;
|
||||
@end
|
||||
|
||||
typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) {
|
||||
CSTestMachineZ80RegisterProgramCounter,
|
||||
CSTestMachineZ80RegisterStackPointer,
|
||||
|
||||
CSTestMachineZ80RegisterA, CSTestMachineZ80RegisterF, CSTestMachineZ80RegisterAF,
|
||||
CSTestMachineZ80RegisterB, CSTestMachineZ80RegisterC, CSTestMachineZ80RegisterBC,
|
||||
CSTestMachineZ80RegisterD, CSTestMachineZ80RegisterE, CSTestMachineZ80RegisterDE,
|
||||
CSTestMachineZ80RegisterH, CSTestMachineZ80RegisterL, CSTestMachineZ80RegisterHL,
|
||||
CSTestMachineZ80RegisterAFDash,
|
||||
CSTestMachineZ80RegisterBCDash,
|
||||
CSTestMachineZ80RegisterDEDash,
|
||||
CSTestMachineZ80RegisterHLDash,
|
||||
CSTestMachineZ80RegisterIX, CSTestMachineZ80RegisterIY,
|
||||
CSTestMachineZ80RegisterI, CSTestMachineZ80RegisterR,
|
||||
CSTestMachineZ80RegisterIFF1, CSTestMachineZ80RegisterIFF2, CSTestMachineZ80RegisterIM
|
||||
};
|
||||
|
||||
@interface CSTestMachineZ80 : NSObject
|
||||
|
||||
- (void)setData:(nonnull NSData *)data atAddress:(uint16_t)startAddress;
|
||||
- (void)setValue:(uint8_t)value atAddress:(uint16_t)address;
|
||||
- (uint8_t)valueAtAddress:(uint16_t)address;
|
||||
|
||||
- (void)runForNumberOfCycles:(int)cycles;
|
||||
- (void)runToNextInstruction;
|
||||
|
||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg;
|
||||
- (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg;
|
||||
|
||||
@property(nonatomic, weak, nullable) id<CSTestMachineTrapHandler> trapHandler;
|
||||
- (void)addTrapAddress:(uint16_t)trapAddress;
|
||||
|
||||
@property(nonatomic, assign) BOOL captureBusActivity;
|
||||
@property(nonatomic, readonly, nonnull) NSArray<CSTestMachineZ80BusOperationCapture *> *busOperationCaptures;
|
||||
|
||||
@property(nonatomic, readonly) BOOL isHalted;
|
||||
|
||||
@property(nonatomic) BOOL nmiLine;
|
||||
@property(nonatomic) BOOL irqLine;
|
||||
|
||||
@end
|
245
OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm
Normal file
245
OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm
Normal file
@ -0,0 +1,245 @@
|
||||
//
|
||||
// TestMachineZ80.m
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TestMachineZ80.h"
|
||||
#include "Z80AllRAM.hpp"
|
||||
|
||||
@interface CSTestMachineZ80 ()
|
||||
- (void)testMachineDidTrapAtAddress:(uint16_t)address;
|
||||
- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp;
|
||||
@end
|
||||
|
||||
#pragma mark - C++ delegate handlers
|
||||
|
||||
class MachineTrapHandler: public CPU::AllRAMProcessor::TrapHandler {
|
||||
public:
|
||||
MachineTrapHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {}
|
||||
|
||||
void processor_did_trap(CPU::AllRAMProcessor &, uint16_t address) {
|
||||
[target_ testMachineDidTrapAtAddress:address];
|
||||
}
|
||||
|
||||
private:
|
||||
CSTestMachineZ80 *target_;
|
||||
};
|
||||
|
||||
class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegate {
|
||||
public:
|
||||
BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {}
|
||||
|
||||
void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::BusOperation operation, uint16_t address, uint8_t value, int time_stamp) {
|
||||
[target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp];
|
||||
}
|
||||
|
||||
private:
|
||||
CSTestMachineZ80 *target_;
|
||||
};
|
||||
|
||||
#pragma mark - Register enum map
|
||||
|
||||
static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
|
||||
switch (reg) {
|
||||
case CSTestMachineZ80RegisterAF: return CPU::Z80::Register::AF;
|
||||
case CSTestMachineZ80RegisterA: return CPU::Z80::Register::A;
|
||||
case CSTestMachineZ80RegisterF: return CPU::Z80::Register::Flags;
|
||||
case CSTestMachineZ80RegisterBC: return CPU::Z80::Register::BC;
|
||||
case CSTestMachineZ80RegisterB: return CPU::Z80::Register::B;
|
||||
case CSTestMachineZ80RegisterC: return CPU::Z80::Register::C;
|
||||
case CSTestMachineZ80RegisterDE: return CPU::Z80::Register::DE;
|
||||
case CSTestMachineZ80RegisterD: return CPU::Z80::Register::D;
|
||||
case CSTestMachineZ80RegisterE: return CPU::Z80::Register::E;
|
||||
case CSTestMachineZ80RegisterHL: return CPU::Z80::Register::HL;
|
||||
case CSTestMachineZ80RegisterH: return CPU::Z80::Register::H;
|
||||
case CSTestMachineZ80RegisterL: return CPU::Z80::Register::L;
|
||||
|
||||
case CSTestMachineZ80RegisterAFDash: return CPU::Z80::Register::AFDash;
|
||||
case CSTestMachineZ80RegisterBCDash: return CPU::Z80::Register::BCDash;
|
||||
case CSTestMachineZ80RegisterDEDash: return CPU::Z80::Register::DEDash;
|
||||
case CSTestMachineZ80RegisterHLDash: return CPU::Z80::Register::HLDash;
|
||||
|
||||
case CSTestMachineZ80RegisterIX: return CPU::Z80::Register::IX;
|
||||
case CSTestMachineZ80RegisterIY: return CPU::Z80::Register::IY;
|
||||
|
||||
case CSTestMachineZ80RegisterI: return CPU::Z80::Register::I;
|
||||
case CSTestMachineZ80RegisterR: return CPU::Z80::Register::R;
|
||||
|
||||
case CSTestMachineZ80RegisterIFF1: return CPU::Z80::Register::IFF1;
|
||||
case CSTestMachineZ80RegisterIFF2: return CPU::Z80::Register::IFF2;
|
||||
case CSTestMachineZ80RegisterIM: return CPU::Z80::Register::IM;
|
||||
|
||||
case CSTestMachineZ80RegisterProgramCounter: return CPU::Z80::Register::ProgramCounter;
|
||||
case CSTestMachineZ80RegisterStackPointer: return CPU::Z80::Register::StackPointer;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Capture class
|
||||
|
||||
@interface CSTestMachineZ80BusOperationCapture()
|
||||
@property(nonatomic, assign) CSTestMachineZ80BusOperationCaptureOperation operation;
|
||||
@property(nonatomic, assign) uint16_t address;
|
||||
@property(nonatomic, assign) uint8_t value;
|
||||
@property(nonatomic, assign) int timeStamp;
|
||||
@end
|
||||
|
||||
@implementation CSTestMachineZ80BusOperationCapture
|
||||
|
||||
- (NSString *)description {
|
||||
NSString *opName = @"";
|
||||
switch(self.operation) {
|
||||
case CSTestMachineZ80BusOperationCaptureOperationRead: opName = @"r"; break;
|
||||
case CSTestMachineZ80BusOperationCaptureOperationWrite: opName = @"w"; break;
|
||||
case CSTestMachineZ80BusOperationCaptureOperationPortRead: opName = @"i"; break;
|
||||
case CSTestMachineZ80BusOperationCaptureOperationPortWrite: opName = @"o"; break;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@ %04x %02x [%d]", opName, self.address, self.value, self.timeStamp];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Test class
|
||||
|
||||
@implementation CSTestMachineZ80 {
|
||||
CPU::Z80::AllRAMProcessor *_processor;
|
||||
MachineTrapHandler *_cppTrapHandler;
|
||||
BusOperationHandler *_busOperationHandler;
|
||||
|
||||
NSMutableArray<CSTestMachineZ80BusOperationCapture *> *_busOperationCaptures;
|
||||
BOOL _isAtReadOpcode;
|
||||
int _timeSeekingReadOpcode;
|
||||
int _lastOpcodeTime;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init {
|
||||
if(self = [super init]) {
|
||||
_processor = CPU::Z80::AllRAMProcessor::Processor();
|
||||
_processor->reset_power_on();
|
||||
_cppTrapHandler = new MachineTrapHandler(self);
|
||||
_busOperationHandler = new BusOperationHandler(self);
|
||||
_busOperationCaptures = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete _cppTrapHandler;
|
||||
delete _busOperationHandler;
|
||||
}
|
||||
|
||||
#pragma mark - Accessors
|
||||
|
||||
- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress {
|
||||
_processor->set_data_at_address(startAddress, data.length, (const uint8_t *)data.bytes);
|
||||
}
|
||||
|
||||
- (void)runForNumberOfCycles:(int)cycles {
|
||||
_processor->run_for_cycles(cycles);
|
||||
}
|
||||
|
||||
- (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg {
|
||||
_processor->set_value_of_register(registerForRegister(reg), value);
|
||||
}
|
||||
|
||||
- (void)setValue:(uint8_t)value atAddress:(uint16_t)address {
|
||||
_processor->set_data_at_address(address, 1, &value);
|
||||
}
|
||||
|
||||
- (uint8_t)valueAtAddress:(uint16_t)address {
|
||||
uint8_t value;
|
||||
_processor->get_data_at_address(address, 1, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
- (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg {
|
||||
return _processor->get_value_of_register(registerForRegister(reg));
|
||||
}
|
||||
|
||||
- (void)addTrapAddress:(uint16_t)trapAddress {
|
||||
_processor->set_trap_handler(_cppTrapHandler);
|
||||
_processor->add_trap_address(trapAddress);
|
||||
}
|
||||
|
||||
- (void)testMachineDidTrapAtAddress:(uint16_t)address {
|
||||
[self.trapHandler testMachine:self didTrapAtAddress:address];
|
||||
}
|
||||
|
||||
- (BOOL)isHalted {
|
||||
return _processor->get_halt_line() ? YES : NO;
|
||||
}
|
||||
|
||||
- (void)setNmiLine:(BOOL)nmiLine {
|
||||
_nmiLine = nmiLine;
|
||||
_processor->set_non_maskable_interrupt_line(nmiLine ? true : false);
|
||||
}
|
||||
|
||||
- (void)setIrqLine:(BOOL)irqLine {
|
||||
_irqLine = irqLine;
|
||||
_processor->set_interrupt_line(irqLine ? true : false);
|
||||
}
|
||||
|
||||
#pragma mark - Z80-specific Runner
|
||||
|
||||
- (void)runToNextInstruction {
|
||||
_isAtReadOpcode = NO;
|
||||
_timeSeekingReadOpcode = 0;
|
||||
while(!_isAtReadOpcode) {
|
||||
_timeSeekingReadOpcode++;
|
||||
_processor->run_for_cycles(1);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Bus operation accumulation
|
||||
|
||||
- (void)setCaptureBusActivity:(BOOL)captureBusActivity {
|
||||
_captureBusActivity = captureBusActivity;
|
||||
_processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr);
|
||||
}
|
||||
|
||||
- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp {
|
||||
int length = timeStamp - _lastOpcodeTime;
|
||||
_lastOpcodeTime = timeStamp;
|
||||
if(operation == CPU::Z80::BusOperation::ReadOpcode && length < _timeSeekingReadOpcode)
|
||||
_isAtReadOpcode = YES;
|
||||
|
||||
if(self.captureBusActivity) {
|
||||
CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init];
|
||||
switch(operation) {
|
||||
case CPU::Z80::BusOperation::Write:
|
||||
capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite;
|
||||
break;
|
||||
|
||||
case CPU::Z80::BusOperation::Read:
|
||||
case CPU::Z80::BusOperation::ReadOpcode:
|
||||
capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead;
|
||||
break;
|
||||
|
||||
case CPU::Z80::BusOperation::Input:
|
||||
capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead;
|
||||
break;
|
||||
|
||||
case CPU::Z80::BusOperation::Output:
|
||||
capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
capture.address = address;
|
||||
capture.value = value;
|
||||
capture.timeStamp = timeStamp;
|
||||
|
||||
[_busOperationCaptures addObject:capture];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<CSTestMachineZ80BusOperationCapture *> *)busOperationCaptures {
|
||||
return [_busOperationCaptures copy];
|
||||
}
|
||||
|
||||
@end
|
339
OSBindings/Mac/Clock SignalTests/FUSE/COPYING
Normal file
339
OSBindings/Mac/Clock SignalTests/FUSE/COPYING
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
5
OSBindings/Mac/Clock SignalTests/FUSE/readme.txt
Normal file
5
OSBindings/Mac/Clock SignalTests/FUSE/readme.txt
Normal file
@ -0,0 +1,5 @@
|
||||
tests.expected and tests.in are sourced from FUSE, the For UNIX Spectrum Emulator. FUSE is GPL software, and can be found at:
|
||||
|
||||
https://github.com/tom-seddon/fuse-emulator-code/
|
||||
|
||||
tests.exepected.json and tests.in.json are direct derivatives of those files and therefore are also offered under the GPL.
|
18395
OSBindings/Mac/Clock SignalTests/FUSE/tests.expected
Normal file
18395
OSBindings/Mac/Clock SignalTests/FUSE/tests.expected
Normal file
File diff suppressed because it is too large
Load Diff
48494
OSBindings/Mac/Clock SignalTests/FUSE/tests.expected.json
Normal file
48494
OSBindings/Mac/Clock SignalTests/FUSE/tests.expected.json
Normal file
File diff suppressed because it is too large
Load Diff
9011
OSBindings/Mac/Clock SignalTests/FUSE/tests.in
Normal file
9011
OSBindings/Mac/Clock SignalTests/FUSE/tests.in
Normal file
File diff suppressed because it is too large
Load Diff
37048
OSBindings/Mac/Clock SignalTests/FUSE/tests.in.json
Normal file
37048
OSBindings/Mac/Clock SignalTests/FUSE/tests.in.json
Normal file
File diff suppressed because it is too large
Load Diff
276
OSBindings/Mac/Clock SignalTests/FUSETests.swift
Normal file
276
OSBindings/Mac/Clock SignalTests/FUSETests.swift
Normal file
@ -0,0 +1,276 @@
|
||||
//
|
||||
// FUSETests.swift
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 21/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
fileprivate func readHexInt16(from scanner: Scanner) -> UInt16 {
|
||||
var temporary: UInt32 = 0
|
||||
scanner.scanHexInt32(&temporary)
|
||||
return UInt16(temporary)
|
||||
}
|
||||
|
||||
fileprivate func readHexInt8(from scanner: Scanner) -> UInt8 {
|
||||
var temporary: UInt32 = 0
|
||||
scanner.scanHexInt32(&temporary)
|
||||
return UInt8(temporary)
|
||||
}
|
||||
|
||||
fileprivate struct RegisterState {
|
||||
let af: UInt16, bc: UInt16, de: UInt16, hl: UInt16
|
||||
let afDash: UInt16, bcDash: UInt16, deDash: UInt16, hlDash: UInt16
|
||||
let ix: UInt16, iy: UInt16, sp: UInt16, pc: UInt16
|
||||
let i: UInt8, r: UInt8
|
||||
let iff1: Bool, iff2: Bool, interruptMode: Int
|
||||
let isHalted: Bool
|
||||
let tStates: Int
|
||||
|
||||
func set(onMachine machine: CSTestMachineZ80) {
|
||||
machine.setValue(af, for: .AF)
|
||||
machine.setValue(bc, for: .BC)
|
||||
machine.setValue(de, for: .DE)
|
||||
machine.setValue(hl, for: .HL)
|
||||
machine.setValue(afDash, for: .afDash)
|
||||
machine.setValue(bcDash, for: .bcDash)
|
||||
machine.setValue(deDash, for: .deDash)
|
||||
machine.setValue(hlDash, for: .hlDash)
|
||||
machine.setValue(ix, for: .IX)
|
||||
machine.setValue(iy, for: .IY)
|
||||
machine.setValue(sp, for: .stackPointer)
|
||||
machine.setValue(pc, for: .programCounter)
|
||||
machine.setValue(UInt16(i), for: .I)
|
||||
machine.setValue(UInt16(r), for: .R)
|
||||
machine.setValue(iff1 ? 1 : 0, for: .IFF1)
|
||||
machine.setValue(iff2 ? 1 : 0, for: .IFF2)
|
||||
machine.setValue(UInt16(interruptMode), for: .IM)
|
||||
// TODO: isHalted
|
||||
}
|
||||
|
||||
/*
|
||||
Re: bits 3 and 5; the FUSE tests seem to be inconsistent with other documentation
|
||||
in expectations as to 5 and 3 from the FDCB and DDCB pages. So I've disabled 3
|
||||
and 5 testing until I can make a value judgment.
|
||||
*/
|
||||
|
||||
init(dictionary: [String: Any]) {
|
||||
// don't test bits 3 and 5 for now
|
||||
af = UInt16(dictionary["af"] as! NSNumber)
|
||||
bc = UInt16(dictionary["bc"] as! NSNumber)
|
||||
de = UInt16(dictionary["de"] as! NSNumber)
|
||||
hl = UInt16(dictionary["hl"] as! NSNumber)
|
||||
|
||||
afDash = UInt16(dictionary["afDash"] as! NSNumber)
|
||||
bcDash = UInt16(dictionary["bcDash"] as! NSNumber)
|
||||
deDash = UInt16(dictionary["deDash"] as! NSNumber)
|
||||
hlDash = UInt16(dictionary["hlDash"] as! NSNumber)
|
||||
|
||||
ix = UInt16(dictionary["ix"] as! NSNumber)
|
||||
iy = UInt16(dictionary["iy"] as! NSNumber)
|
||||
|
||||
sp = UInt16(dictionary["sp"] as! NSNumber)
|
||||
pc = UInt16(dictionary["pc"] as! NSNumber)
|
||||
|
||||
i = UInt8(dictionary["i"] as! NSNumber)
|
||||
r = UInt8(dictionary["r"] as! NSNumber)
|
||||
|
||||
iff1 = (dictionary["iff1"] as! NSNumber).boolValue
|
||||
iff2 = (dictionary["iff2"] as! NSNumber).boolValue
|
||||
|
||||
interruptMode = (dictionary["im"] as! NSNumber).intValue
|
||||
isHalted = (dictionary["halted"] as! NSNumber).boolValue
|
||||
|
||||
tStates = (dictionary["tStates"] as! NSNumber).intValue
|
||||
}
|
||||
|
||||
init(machine: CSTestMachineZ80) {
|
||||
// don't test bits 3 and 5 for now
|
||||
af = machine.value(for: .AF)
|
||||
bc = machine.value(for: .BC)
|
||||
de = machine.value(for: .DE)
|
||||
hl = machine.value(for: .HL)
|
||||
|
||||
afDash = machine.value(for: .afDash)
|
||||
bcDash = machine.value(for: .bcDash)
|
||||
deDash = machine.value(for: .deDash)
|
||||
hlDash = machine.value(for: .hlDash)
|
||||
|
||||
ix = machine.value(for: .IX)
|
||||
iy = machine.value(for: .IY)
|
||||
|
||||
sp = machine.value(for: .stackPointer)
|
||||
pc = machine.value(for: .programCounter)
|
||||
|
||||
i = UInt8(machine.value(for: .I))
|
||||
r = UInt8(machine.value(for: .R))
|
||||
|
||||
iff1 = machine.value(for: .IFF1) != 0
|
||||
iff2 = machine.value(for: .IFF2) != 0
|
||||
|
||||
interruptMode = Int(machine.value(for: .IM))
|
||||
|
||||
isHalted = machine.isHalted
|
||||
tStates = 0 // TODO (?)
|
||||
}
|
||||
}
|
||||
|
||||
extension RegisterState: Equatable {}
|
||||
|
||||
fileprivate func ==(lhs: RegisterState, rhs: RegisterState) -> Bool {
|
||||
return (lhs.af & ~0x0028) == (rhs.af & ~0x0028) &&
|
||||
lhs.bc == rhs.bc &&
|
||||
lhs.de == rhs.de &&
|
||||
lhs.hl == rhs.hl &&
|
||||
(lhs.afDash & ~0x0028) == (rhs.afDash & ~0x0028) &&
|
||||
lhs.bcDash == rhs.bcDash &&
|
||||
lhs.deDash == rhs.deDash &&
|
||||
lhs.hlDash == rhs.hlDash &&
|
||||
lhs.ix == rhs.ix &&
|
||||
lhs.iy == rhs.iy &&
|
||||
lhs.sp == rhs.sp &&
|
||||
lhs.pc == rhs.pc &&
|
||||
lhs.i == rhs.i &&
|
||||
lhs.r == rhs.r &&
|
||||
lhs.iff1 == rhs.iff1 &&
|
||||
lhs.iff2 == rhs.iff2 &&
|
||||
lhs.interruptMode == rhs.interruptMode &&
|
||||
lhs.isHalted == rhs.isHalted
|
||||
}
|
||||
|
||||
class FUSETests: XCTestCase {
|
||||
|
||||
func testFUSE() {
|
||||
let inputFilename: String! = Bundle(for: type(of: self)).path(forResource: "tests.in", ofType: "json")
|
||||
let outputFilename: String! = Bundle(for: type(of: self)).path(forResource: "tests.expected", ofType: "json")
|
||||
|
||||
XCTAssert(inputFilename != nil && outputFilename != nil)
|
||||
|
||||
let inputData: Data! = try? Data(contentsOf: URL(fileURLWithPath: inputFilename))
|
||||
let outputData: Data! = try? Data(contentsOf: URL(fileURLWithPath: outputFilename))
|
||||
|
||||
XCTAssert(inputData != nil && outputData != nil)
|
||||
|
||||
let inputArray: [Any]! = try! JSONSerialization.jsonObject(with: inputData, options: []) as? [Any]
|
||||
let outputArray: [Any]! = try! JSONSerialization.jsonObject(with: outputData, options: []) as? [Any]
|
||||
|
||||
XCTAssert(inputArray != nil && outputArray != nil)
|
||||
|
||||
var index = 0
|
||||
for item in inputArray {
|
||||
let itemDictionary = item as! [String: Any]
|
||||
let outputDictionary = outputArray[index] as! [String: Any]
|
||||
index = index + 1
|
||||
|
||||
let name = itemDictionary["name"] as! String
|
||||
|
||||
// if name != "02" {
|
||||
// continue;
|
||||
// }
|
||||
// print("\(name)")
|
||||
|
||||
let initialState = RegisterState(dictionary: itemDictionary["state"] as! [String: Any])
|
||||
let targetState = RegisterState(dictionary: outputDictionary["state"] as! [String: Any])
|
||||
|
||||
let machine = CSTestMachineZ80()
|
||||
machine.captureBusActivity = true
|
||||
initialState.set(onMachine: machine)
|
||||
|
||||
let inputMemoryGroups = itemDictionary["memory"] as? [Any]
|
||||
if let inputMemoryGroups = inputMemoryGroups {
|
||||
for group in inputMemoryGroups {
|
||||
let groupDictionary = group as! [String: Any]
|
||||
var address = UInt16(groupDictionary["address"] as! NSNumber)
|
||||
let data = groupDictionary["data"] as! [NSNumber]
|
||||
for value in data {
|
||||
machine.setValue(UInt8(value), atAddress: address)
|
||||
address = address + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
machine.runForNumber(ofCycles: Int32(targetState.tStates))
|
||||
|
||||
let finalState = RegisterState(machine: machine)
|
||||
|
||||
// Compare processor state.
|
||||
XCTAssertEqual(finalState, targetState, "Failed processor state \(name)")
|
||||
|
||||
// Compare memory state.
|
||||
let outputMemoryGroups = outputDictionary["memory"] as? [Any]
|
||||
if let outputMemoryGroups = outputMemoryGroups {
|
||||
for group in outputMemoryGroups {
|
||||
let groupDictionary = group as! [String: Any]
|
||||
var address = UInt16(groupDictionary["address"] as! NSNumber)
|
||||
let data = groupDictionary["data"] as! [NSNumber]
|
||||
for value in data {
|
||||
XCTAssert(machine.value(atAddress: address) == UInt8(value), "Failed memory state \(name)")
|
||||
address = address + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare bus operations.
|
||||
let capturedBusActivity = machine.busOperationCaptures
|
||||
var capturedBusAcivityIndex = 0;
|
||||
|
||||
// I presently believe the FUSE unit test bus results for DJNZ — opcode 0x10 — to be
|
||||
// in error by omitting the final offset read. Therefore I am skipping that.
|
||||
// TODO: enquire with the author.
|
||||
if name == "10" {
|
||||
continue
|
||||
}
|
||||
|
||||
let desiredBusActivity = outputDictionary["busActivity"] as? [[String: Any]]
|
||||
if let desiredBusActivity = desiredBusActivity {
|
||||
for action in desiredBusActivity {
|
||||
let type = action["type"] as! String
|
||||
let time = action["time"] as! Int32
|
||||
let address = action["address"] as! UInt16
|
||||
let value = action["value"] as? UInt8
|
||||
|
||||
if type == "MC" || type == "PC" {
|
||||
// Don't do anything with FUSE's contended memory records; it's
|
||||
// presently unclear to me exactly what they're supposed to communicate
|
||||
continue
|
||||
}
|
||||
|
||||
// FUSE counts a memory access as occurring at the last cycle of its bus operation;
|
||||
// it counts a port access as occurring on the second. timeOffset is used to adjust
|
||||
// the FUSE numbers as required.
|
||||
var operation: CSTestMachineZ80BusOperationCaptureOperation = .read
|
||||
var timeOffset: Int32 = 0
|
||||
switch type {
|
||||
case "MR":
|
||||
operation = .read
|
||||
|
||||
case "MW":
|
||||
operation = .write
|
||||
|
||||
case "PR":
|
||||
operation = .portRead
|
||||
timeOffset = 3
|
||||
|
||||
case "PW":
|
||||
operation = .portWrite
|
||||
timeOffset = 3
|
||||
|
||||
default:
|
||||
print("Unhandled activity type \(type)!")
|
||||
}
|
||||
|
||||
XCTAssert(
|
||||
capturedBusActivity[capturedBusAcivityIndex].address == address &&
|
||||
capturedBusActivity[capturedBusAcivityIndex].value == value! &&
|
||||
capturedBusActivity[capturedBusAcivityIndex].timeStamp == (time + timeOffset) &&
|
||||
capturedBusActivity[capturedBusAcivityIndex].operation == operation,
|
||||
"Failed bus operation match \(name) (at time \(time) with address \(address), value was \(value != nil ? value! : 0), tracking index \(capturedBusAcivityIndex) amongst \(capturedBusActivity))")
|
||||
capturedBusAcivityIndex += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -34,19 +34,19 @@ class KlausDormannTests: XCTestCase {
|
||||
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "6502_functional_test", ofType: "bin") {
|
||||
if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
let machine = CSTestMachine()
|
||||
let machine = CSTestMachine6502()
|
||||
|
||||
machine.setData(functionalTest, atAddress: 0)
|
||||
machine.setValue(0x400, for: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0x400, for: .programCounter)
|
||||
|
||||
while true {
|
||||
let oldPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
|
||||
let oldPC = machine.value(for: .lastOperationAddress)
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
let newPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
|
||||
let newPC = machine.value(for: .lastOperationAddress)
|
||||
|
||||
if newPC == oldPC {
|
||||
let error = errorForTrapAddress(oldPC)
|
||||
XCTAssert(error == nil, "Failed with error \(error)")
|
||||
XCTAssert(error == nil, "Failed with error \(error!)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
class WolfgangLorenzTests: XCTestCase, CSTestMachine6502JamHandler {
|
||||
|
||||
func testWolfgangLorenzStart() {
|
||||
self.runWolfgangLorenzTest(" start")
|
||||
@ -195,13 +195,12 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
|
||||
fileprivate var output: String = ""
|
||||
fileprivate func runWolfgangLorenzTest(_ name: String) {
|
||||
|
||||
var machine: CSTestMachine!
|
||||
var machine: CSTestMachine6502!
|
||||
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: name, ofType: nil) {
|
||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
|
||||
machine = CSTestMachine()
|
||||
machine = CSTestMachine6502()
|
||||
machine.jamHandler = self
|
||||
// machine.logActivity = true
|
||||
output = ""
|
||||
@ -226,15 +225,15 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
] as [UInt8]), count: 19)
|
||||
machine.setData( irqHandler, atAddress: 0xff48)
|
||||
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0xffd2) // print character
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0xe16f) // load
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0xffe4) // scan keyboard
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0x8000) // exit
|
||||
machine.setValue(CSTestMachineJamOpcode, forAddress:0xa474) // exit
|
||||
machine.setValue(CSTestMachine6502JamOpcode, forAddress:0xffd2) // print character
|
||||
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: CSTestMachineRegister.programCounter)
|
||||
machine.setValue(0xfd, for: CSTestMachineRegister.stackPointer)
|
||||
machine.setValue(0x04, for: CSTestMachineRegister.flags)
|
||||
machine.setValue(0x0801, for: CSTestMachine6502Register.programCounter)
|
||||
machine.setValue(0xfd, for: CSTestMachine6502Register.stackPointer)
|
||||
machine.setValue(0x04, for: CSTestMachine6502Register.flags)
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +245,7 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
machine.runForNumber(ofCycles: 1000)
|
||||
}
|
||||
|
||||
let jammedPC = machine.value(for: CSTestMachineRegister.lastOperationAddress)
|
||||
let jammedPC = machine.value(for: CSTestMachine6502Register.lastOperationAddress)
|
||||
if jammedPC != 0xe16f {
|
||||
let hexAddress = String(format:"%04x", jammedPC)
|
||||
NSException(name: NSExceptionName(rawValue: "Failed Test"), reason: "Processor jammed unexpectedly at \(hexAddress)", userInfo: nil).raise()
|
||||
@ -297,19 +296,18 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineJamHandler {
|
||||
return result
|
||||
}
|
||||
|
||||
func testMachine(_ machine: CSTestMachine!, didJamAtAddress address: UInt16) {
|
||||
|
||||
func testMachine(_ machine: CSTestMachine6502!, didJamAtAddress address: UInt16) {
|
||||
switch address {
|
||||
case 0xffd2:
|
||||
machine.setValue(0x00, forAddress: 0x030c)
|
||||
|
||||
let character = machine.value(for: CSTestMachineRegister.A)
|
||||
let character = machine.value(for: CSTestMachine6502Register.A)
|
||||
output.append(Character(UnicodeScalar(character)!))
|
||||
|
||||
machine.returnFromSubroutine()
|
||||
|
||||
case 0xffe4:
|
||||
machine.setValue(0x3, for:CSTestMachineRegister.A)
|
||||
machine.setValue(0x3, for:CSTestMachine6502Register.A)
|
||||
machine.returnFromSubroutine()
|
||||
|
||||
case 0x8000, 0xa474:
|
||||
|
191
OSBindings/Mac/Clock SignalTests/Z80InterruptTests.swift
Normal file
191
OSBindings/Mac/Clock SignalTests/Z80InterruptTests.swift
Normal file
@ -0,0 +1,191 @@
|
||||
//
|
||||
// Z80InterruptTests.swift
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 03/06/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class Z80InterruptTests: XCTestCase {
|
||||
|
||||
func testNMI() {
|
||||
let machine = CSTestMachineZ80()
|
||||
|
||||
// start the PC at 0x0100 and install two NOPs for it
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
machine.setValue(0, for: .IFF1)
|
||||
machine.setValue(1, for: .IFF2)
|
||||
machine.setValue(0x00, atAddress: 0x0100)
|
||||
machine.setValue(0x00, atAddress: 0x0101)
|
||||
|
||||
// put the stack at the top of memory
|
||||
machine.setValue(0, for: .stackPointer)
|
||||
|
||||
// run for four cycles, and signal an NMI
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
machine.nmiLine = true
|
||||
|
||||
// run for four more cycles to get to where the NMI should be recognised
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
|
||||
|
||||
// run for eleven more cycles to allow the NMI to begin
|
||||
machine.runForNumber(ofCycles: 11)
|
||||
|
||||
// confirm that the PC is now at 0x66, that the old is on the stack and
|
||||
// that IFF1 has migrated to IFF2
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x66)
|
||||
XCTAssertEqual(machine.value(atAddress: 0xffff), 0x01)
|
||||
XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02)
|
||||
XCTAssertEqual(machine.value(for: .IFF2), 0)
|
||||
}
|
||||
|
||||
func testIRQDisabled() {
|
||||
let machine = CSTestMachineZ80()
|
||||
|
||||
// start the PC at 0x0100, interrupts disabled
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
machine.setValue(0, for: .IFF1)
|
||||
machine.setValue(0, for: .IFF2)
|
||||
|
||||
// install six NOPs
|
||||
for address: UInt16 in 0x0100 ..< 0x0106 {
|
||||
machine.setValue(0x00, atAddress: address)
|
||||
}
|
||||
|
||||
// replace the fourth NOP with an EI
|
||||
machine.setValue(0xfb, atAddress: 0x0103)
|
||||
|
||||
// run for four cycles, signal IRQ and run for 8 more
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
machine.irqLine = true
|
||||
machine.runForNumber(ofCycles: 8)
|
||||
|
||||
// confirm that the request was ignored
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0103)
|
||||
|
||||
// run for 12 more cycles, hitting the EI and, if no interrupt occured, the two NOPs after it
|
||||
machine.runForNumber(ofCycles: 12)
|
||||
|
||||
// confirm that an interruption occurred, causing the PC not yet to have proceeded beyond 0x0105
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0105)
|
||||
}
|
||||
|
||||
func testIRQMode0() {
|
||||
// In interrupt mode 0, receipt of an IRQ causes an instruction to be read from the bus and
|
||||
// executed, with a two-cycle penalty. The test machine posts 0x21 during an interrupt acknowledge
|
||||
// cycle so the instruction that is executed will be LD HL, nnnn
|
||||
|
||||
let machine = CSTestMachineZ80()
|
||||
|
||||
// start the PC at 0x0100 and install two NOPs for it and then one copy of 0x83, then
|
||||
// something that isn't 0x83, and ensuring interrupts are enabled and in mode 1
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
machine.setValue(1, for: .IFF1)
|
||||
machine.setValue(0, for: .IM)
|
||||
machine.setValue(0x1010, for: .HL)
|
||||
machine.setValue(0x00, atAddress: 0x0100)
|
||||
machine.setValue(0x00, atAddress: 0x0101)
|
||||
machine.setValue(0x83, atAddress: 0x0102)
|
||||
machine.setValue(0x9b, atAddress: 0x0103)
|
||||
|
||||
// run for four cycles, and signal an IRQ
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
machine.irqLine = true
|
||||
|
||||
// run for four more cycles to get to where the IRQ should be recognised
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
|
||||
|
||||
// run for twelve more cycles, to complete a LD HL, nnnn with the additional two cycles
|
||||
// of cost for it being an IRQ program
|
||||
machine.runForNumber(ofCycles: 12)
|
||||
|
||||
// confirm that the PC is still where it was, but HL is now 0x8383, and interrupts are disabled
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
|
||||
XCTAssertEqual(machine.value(for: .HL), 0x8383)
|
||||
XCTAssertEqual(machine.value(for: .IFF1), 0)
|
||||
}
|
||||
|
||||
func testIRQMode1() {
|
||||
// In interrupt mode 1, receipt of an IRQ means that the interrupt flag is disabled,
|
||||
// the PC is pushed to the stack and execution resumes at 0x38.
|
||||
|
||||
let machine = CSTestMachineZ80()
|
||||
|
||||
// start the PC at 0x0100 and install three NOPs for it, ensuring interrupts are enabled
|
||||
// and in mode 1
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
machine.setValue(1, for: .IFF1)
|
||||
machine.setValue(1, for: .IM)
|
||||
machine.setValue(0x00, atAddress: 0x0100)
|
||||
machine.setValue(0x00, atAddress: 0x0101)
|
||||
machine.setValue(0x00, atAddress: 0x0102)
|
||||
|
||||
// put the stack at the top of memory
|
||||
machine.setValue(0, for: .stackPointer)
|
||||
|
||||
// run for four cycles, and signal an IRQ
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
machine.irqLine = true
|
||||
|
||||
// run for four more cycles to get to where the IRQ should be recognised
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
|
||||
|
||||
// run for eleven more cycles to allow the IRQ to begin
|
||||
machine.runForNumber(ofCycles: 13)
|
||||
|
||||
// confirm that the PC is now at 0x38, that the old is on the stack and
|
||||
// that interrupts are now disabled
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x38)
|
||||
XCTAssertEqual(machine.value(atAddress: 0xffff), 0x01)
|
||||
XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02)
|
||||
XCTAssertEqual(machine.value(for: .IFF1), 0)
|
||||
}
|
||||
|
||||
func testIRQMode2() {
|
||||
// In interrupt mode 2, the current bus value is combined with the I register to look
|
||||
// up a vector from memory; the PC calls that vector. Total cost: 19 cycles.
|
||||
|
||||
let machine = CSTestMachineZ80()
|
||||
|
||||
// start the PC at 0x0100 and install two NOPs for it and then one copy of 0x83, then
|
||||
// something that isn't 0x83, and ensuring interrupts are enabled and in mode 1
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
machine.setValue(1, for: .IFF1)
|
||||
machine.setValue(2, for: .IM)
|
||||
machine.setValue(0x00, atAddress: 0x0100)
|
||||
machine.setValue(0x00, atAddress: 0x0101)
|
||||
|
||||
// set I to 0x0200 to establish the location of our vector table, and because the test
|
||||
// machine will post a 0x21 in response to the interrupt cycle, at 0x0221 put the
|
||||
// arbitrarily-chosen address 0x8049
|
||||
machine.setValue(0x02, for: .I)
|
||||
machine.setValue(0x49, atAddress: 0x0221)
|
||||
machine.setValue(0x80, atAddress: 0x0222)
|
||||
|
||||
// put the stack at the top of memory
|
||||
machine.setValue(0, for: .stackPointer)
|
||||
|
||||
// run for four cycles, and signal an IRQ
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
machine.irqLine = true
|
||||
|
||||
// run for four more cycles to get to where the IRQ should be recognised
|
||||
machine.runForNumber(ofCycles: 4)
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x0102)
|
||||
|
||||
// run for nineteen more cycles, to complete the interrupt beginning
|
||||
machine.runForNumber(ofCycles: 19)
|
||||
|
||||
// confirm that the PC is now at 0x8049, the old is on the stack, and interrupts
|
||||
// are disabled
|
||||
XCTAssertEqual(machine.value(for: .programCounter), 0x8049)
|
||||
XCTAssertEqual(machine.value(atAddress: 0xffff), 0x01)
|
||||
XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02)
|
||||
XCTAssertEqual(machine.value(for: .IFF1), 0)
|
||||
}
|
||||
}
|
339
OSBindings/Mac/Clock SignalTests/Zexall/Copying
Normal file
339
OSBindings/Mac/Clock SignalTests/Zexall/Copying
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
BIN
OSBindings/Mac/Clock SignalTests/Zexall/zexall.com
Executable file
BIN
OSBindings/Mac/Clock SignalTests/Zexall/zexall.com
Executable file
Binary file not shown.
1561
OSBindings/Mac/Clock SignalTests/Zexall/zexall.src
Normal file
1561
OSBindings/Mac/Clock SignalTests/Zexall/zexall.src
Normal file
File diff suppressed because it is too large
Load Diff
BIN
OSBindings/Mac/Clock SignalTests/Zexall/zexdoc.com
Executable file
BIN
OSBindings/Mac/Clock SignalTests/Zexall/zexdoc.com
Executable file
Binary file not shown.
1561
OSBindings/Mac/Clock SignalTests/Zexall/zexdoc.src
Normal file
1561
OSBindings/Mac/Clock SignalTests/Zexall/zexdoc.src
Normal file
File diff suppressed because it is too large
Load Diff
168
OSBindings/Mac/Clock SignalTests/ZexallTests.swift
Normal file
168
OSBindings/Mac/Clock SignalTests/ZexallTests.swift
Normal file
@ -0,0 +1,168 @@
|
||||
//
|
||||
// ZexallTests.swift
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
|
||||
class ZexallTests: XCTestCase, CSTestMachineTrapHandler {
|
||||
|
||||
fileprivate var done = false
|
||||
fileprivate var output = ""
|
||||
|
||||
func testZexall() {
|
||||
if let filename = Bundle(for: type(of: self)).path(forResource: "zexdoc", ofType: "com") {
|
||||
if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) {
|
||||
|
||||
// install test program, at the usual CP/M place
|
||||
let machine = CSTestMachineZ80()
|
||||
machine.setData(testData, atAddress: 0x0100)
|
||||
|
||||
// add a RET at the CP/M entry location, and establish it as a trap location
|
||||
machine.setValue(0xc9, atAddress: 0x0005)
|
||||
machine.setValue(0xff, atAddress: 0x0006)
|
||||
machine.setValue(0xff, atAddress: 0x0007)
|
||||
machine.addTrapAddress(0x0005);
|
||||
machine.trapHandler = self
|
||||
|
||||
// establish 0 as another trap location, as RST 0h is one of the ways that
|
||||
// CP/M programs can exit
|
||||
machine.addTrapAddress(0);
|
||||
|
||||
// ensure that if the CPU hits zero, it stays there until the end of the
|
||||
// sampling window
|
||||
machine.setValue(0xc3, atAddress: 0x0000)
|
||||
machine.setValue(0x00, atAddress: 0x0001)
|
||||
machine.setValue(0x00, atAddress: 0x0002)
|
||||
|
||||
// seed execution at 0x0100
|
||||
machine.setValue(0x0100, for: .programCounter)
|
||||
|
||||
// run!
|
||||
let cyclesPerIteration: Int32 = 400_000_000
|
||||
var cyclesToDate: TimeInterval = 0
|
||||
let startDate = Date()
|
||||
var printDate = Date()
|
||||
while !done {
|
||||
machine.runForNumber(ofCycles: cyclesPerIteration)
|
||||
cyclesToDate += TimeInterval(cyclesPerIteration)
|
||||
if printDate.timeIntervalSinceNow < -5.0 {
|
||||
print("\(cyclesToDate / -startDate.timeIntervalSinceNow) Mhz")
|
||||
printDate = Date()
|
||||
}
|
||||
}
|
||||
|
||||
let targetOutput =
|
||||
"Z80doc instruction exerciser\n\r" +
|
||||
"<adc,sbc> hl,<bc,de,hl,sp>.... OK\n\r" +
|
||||
"add hl,<bc,de,hl,sp>.......... OK\n\r" +
|
||||
"add ix,<bc,de,ix,sp>.......... OK\n\r" +
|
||||
"add iy,<bc,de,iy,sp>.......... OK\n\r" +
|
||||
"aluop a,nn.................... OK\n\r" +
|
||||
"aluop a,<b,c,d,e,h,l,(hl),a>.. OK\n\r" +
|
||||
"aluop a,<ixh,ixl,iyh,iyl>..... OK\n\r" +
|
||||
"aluop a,(<ix,iy>+1)........... OK\n\r" +
|
||||
"bit n,(<ix,iy>+1)............. OK\n\r" +
|
||||
"bit n,<b,c,d,e,h,l,(hl),a>.... OK\n\r" +
|
||||
"cpd<r>........................ OK\n\r" +
|
||||
"cpi<r>........................ OK\n\r" +
|
||||
"<daa,cpl,scf,ccf>............. OK\n\r" +
|
||||
"<inc,dec> a................... OK\n\r" +
|
||||
"<inc,dec> b................... OK\n\r" +
|
||||
"<inc,dec> bc.................. OK\n\r" +
|
||||
"<inc,dec> c................... OK\n\r" +
|
||||
"<inc,dec> d................... OK\n\r" +
|
||||
"<inc,dec> de.................. OK\n\r" +
|
||||
"<inc,dec> e................... OK\n\r" +
|
||||
"<inc,dec> h................... OK\n\r" +
|
||||
"<inc,dec> hl.................. OK\n\r" +
|
||||
"<inc,dec> ix.................. OK\n\r" +
|
||||
"<inc,dec> iy.................. OK\n\r" +
|
||||
"<inc,dec> l................... OK\n\r" +
|
||||
"<inc,dec> (hl)................ OK\n\r" +
|
||||
"<inc,dec> sp.................. OK\n\r" +
|
||||
"<inc,dec> (<ix,iy>+1)......... OK\n\r" +
|
||||
"<inc,dec> ixh................. OK\n\r" +
|
||||
"<inc,dec> ixl................. OK\n\r" +
|
||||
"<inc,dec> iyh................. OK\n\r" +
|
||||
"<inc,dec> iyl................. OK\n\r" +
|
||||
"ld <bc,de>,(nnnn)............. OK\n\r" +
|
||||
"ld hl,(nnnn).................. OK\n\r" +
|
||||
"ld sp,(nnnn).................. OK\n\r" +
|
||||
"ld <ix,iy>,(nnnn)............. OK\n\r" +
|
||||
"ld (nnnn),<bc,de>............. OK\n\r" +
|
||||
"ld (nnnn),hl.................. OK\n\r" +
|
||||
"ld (nnnn),sp.................. OK\n\r" +
|
||||
"ld (nnnn),<ix,iy>............. OK\n\r" +
|
||||
"ld <bc,de,hl,sp>,nnnn......... OK\n\r" +
|
||||
"ld <ix,iy>,nnnn............... OK\n\r" +
|
||||
"ld a,<(bc),(de)>.............. OK\n\r" +
|
||||
"ld <b,c,d,e,h,l,(hl),a>,nn.... OK\n\r" +
|
||||
"ld (<ix,iy>+1),nn............. OK\n\r" +
|
||||
"ld <b,c,d,e>,(<ix,iy>+1)...... OK\n\r" +
|
||||
"ld <h,l>,(<ix,iy>+1).......... OK\n\r" +
|
||||
"ld a,(<ix,iy>+1).............. OK\n\r" +
|
||||
"ld <ixh,ixl,iyh,iyl>,nn....... OK\n\r" +
|
||||
"ld <bcdehla>,<bcdehla>........ OK\n\r" +
|
||||
"ld <bcdexya>,<bcdexya>........ OK\n\r" +
|
||||
"ld a,(nnnn) / ld (nnnn),a..... OK\n\r" +
|
||||
"ldd<r> (1).................... OK\n\r" +
|
||||
"ldd<r> (2).................... OK\n\r" +
|
||||
"ldi<r> (1).................... OK\n\r" +
|
||||
"ldi<r> (2).................... OK\n\r" +
|
||||
"neg........................... OK\n\r" +
|
||||
"<rrd,rld>..................... OK\n\r" +
|
||||
"<rlca,rrca,rla,rra>........... OK\n\r" +
|
||||
"shf/rot (<ix,iy>+1)........... OK\n\r" +
|
||||
"shf/rot <b,c,d,e,h,l,(hl),a>.. OK\n\r" +
|
||||
"<set,res> n,<bcdehl(hl)a>..... OK\n\r" +
|
||||
"<set,res> n,(<ix,iy>+1)....... OK\n\r" +
|
||||
"ld (<ix,iy>+1),<b,c,d,e>...... OK\n\r" +
|
||||
"ld (<ix,iy>+1),<h,l>.......... OK\n\r" +
|
||||
"ld (<ix,iy>+1),a.............. OK\n\r" +
|
||||
"ld (<bc,de>),a................ OK\n\r" +
|
||||
"Tests complete\n\r"
|
||||
XCTAssertEqual(targetOutput, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testMachine(_ testMachine: CSTestMachineZ80, didTrapAtAddress address: UInt16) {
|
||||
switch address {
|
||||
case 0x0005:
|
||||
let cRegister = testMachine.value(for: .C)
|
||||
var textToAppend = ""
|
||||
switch cRegister {
|
||||
case 9:
|
||||
var address = testMachine.value(for: .DE)
|
||||
var character: Character = " "
|
||||
while true {
|
||||
character = Character(UnicodeScalar(testMachine.value(atAddress: address)))
|
||||
if character == "$" {
|
||||
break
|
||||
}
|
||||
textToAppend += String(character)
|
||||
address = address + 1
|
||||
}
|
||||
case 5:
|
||||
textToAppend = String(describing: UnicodeScalar(testMachine.value(for: .E)))
|
||||
case 0:
|
||||
done = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
output += textToAppend
|
||||
print(textToAppend)
|
||||
|
||||
case 0x0000:
|
||||
done = true
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
//
|
||||
// CPU6502.cpp
|
||||
// 6502.cpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "CPU6502.hpp"
|
||||
#include "6502.hpp"
|
||||
|
||||
const uint8_t CPU6502::JamOpcode = 0xf2;
|
||||
const uint8_t CPU::MOS6502::JamOpcode = 0xf2;
|
@ -1,18 +1,22 @@
|
||||
//
|
||||
// CPU6502.hpp
|
||||
// 6502.hpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 09/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPU6502_cpp
|
||||
#define CPU6502_cpp
|
||||
#ifndef MOS6502_cpp
|
||||
#define MOS6502_cpp
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
namespace CPU6502 {
|
||||
#include "../MicroOpScheduler.hpp"
|
||||
#include "../RegisterSizes.hpp"
|
||||
|
||||
namespace CPU {
|
||||
namespace MOS6502 {
|
||||
|
||||
/*
|
||||
The list of registers that can be accessed via @c set_value_of_register and @c set_value_of_register.
|
||||
@ -56,25 +60,70 @@ enum BusOperation {
|
||||
/*!
|
||||
Evaluates to `true` if the operation is a read; `false` if it is a write.
|
||||
*/
|
||||
#define isReadOperation(v) (v == CPU6502::BusOperation::Read || v == CPU6502::BusOperation::ReadOpcode)
|
||||
#define isReadOperation(v) (v == CPU::MOS6502::BusOperation::Read || v == CPU::MOS6502::BusOperation::ReadOpcode)
|
||||
|
||||
/*!
|
||||
An opcode that is guaranteed to cause the CPU to jam.
|
||||
*/
|
||||
extern const uint8_t JamOpcode;
|
||||
|
||||
/*
|
||||
This emulation functions by decomposing instructions into micro programs, consisting of the micro operations
|
||||
as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle
|
||||
to perform whereas those called OperationX occur for free (so, in effect, their cost is loaded onto the next cycle).
|
||||
*/
|
||||
enum MicroOp {
|
||||
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
|
||||
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
|
||||
OperationSetI,
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead,
|
||||
OperationMoveToNextProgram, OperationIncrementPC,
|
||||
CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA,
|
||||
CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand,
|
||||
OperationIncrementOperand, OperationORA, OperationAND, OperationEOR,
|
||||
OperationINS, OperationADC, OperationSBC, OperationLDA,
|
||||
OperationLDX, OperationLDY, OperationLAX, OperationSTA,
|
||||
OperationSTX, OperationSTY, OperationSAX, OperationSHA,
|
||||
OperationSHX, OperationSHY, OperationSHS, OperationCMP,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationASL,
|
||||
OperationASO, OperationROL, OperationRLA, OperationLSR,
|
||||
OperationLSE, OperationASR, OperationROR, OperationRRA,
|
||||
OperationCLC, OperationCLI, OperationCLV, OperationCLD,
|
||||
OperationSEC, OperationSEI, OperationSED, OperationINC,
|
||||
OperationDEC, OperationINX, OperationDEX, OperationINY,
|
||||
OperationDEY, OperationBPL, OperationBMI, OperationBVC,
|
||||
OperationBVS, OperationBCC, OperationBCS, OperationBNE,
|
||||
OperationBEQ, OperationTXA, OperationTYA, OperationTXS,
|
||||
OperationTAY, OperationTAX, OperationTSX, OperationARR,
|
||||
OperationSBX, OperationLXA, OperationANE, OperationANC,
|
||||
OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA,
|
||||
CycleScheduleJam
|
||||
};
|
||||
|
||||
/*!
|
||||
@abstact An abstract base class for emulation of a 6502 processor via the curiously recurring template pattern/f-bounded polymorphism.
|
||||
|
||||
@discussion Subclasses should implement @c perform_bus_operation(BusOperation operation, uint16_t address, uint8_t *value) in
|
||||
order to provide the bus on which the 6502 operates and @c synchronise(), which is called upon completion of a continuous run
|
||||
order to provide the bus on which the 6502 operates and @c flush(), which is called upon completion of a continuous run
|
||||
of cycles to allow a subclass to bring any on-demand activities up to date.
|
||||
|
||||
Additional functionality can be provided by the host machine by providing a jam handler and inserting jam opcodes where appropriate;
|
||||
that will cause call outs when the program counter reaches those addresses. @c return_from_subroutine can be used to exit from a
|
||||
jammed state.
|
||||
*/
|
||||
template <class T> class Processor {
|
||||
template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
||||
public:
|
||||
|
||||
class JamHandler {
|
||||
@ -84,60 +133,8 @@ template <class T> class Processor {
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
This emulation funcitons by decomposing instructions into micro programs, consisting of the micro operations
|
||||
as per the enum below. Each micro op takes at most one cycle. By convention, those called CycleX take a cycle
|
||||
to perform whereas those called OperationX occur for free (so, in effect, their cost is loaded onto the next cycle).
|
||||
*/
|
||||
enum MicroOp {
|
||||
CycleFetchOperation, CycleFetchOperand, OperationDecodeOperation, CycleIncPCPushPCH,
|
||||
CyclePushPCH, CyclePushPCL, CyclePushA, CyclePushOperand,
|
||||
OperationSetI,
|
||||
|
||||
OperationBRKPickVector, OperationNMIPickVector, OperationRSTPickVector,
|
||||
CycleReadVectorLow, CycleReadVectorHigh,
|
||||
|
||||
CycleReadFromS, CycleReadFromPC,
|
||||
CyclePullOperand, CyclePullPCL, CyclePullPCH, CyclePullA,
|
||||
CycleNoWritePush,
|
||||
CycleReadAndIncrementPC, CycleIncrementPCAndReadStack, CycleIncrementPCReadPCHLoadPCL, CycleReadPCHLoadPCL,
|
||||
CycleReadAddressHLoadAddressL, CycleReadPCLFromAddress, CycleReadPCHFromAddress, CycleLoadAddressAbsolute,
|
||||
OperationLoadAddressZeroPage, CycleLoadAddessZeroX, CycleLoadAddessZeroY, CycleAddXToAddressLow,
|
||||
CycleAddYToAddressLow, CycleAddXToAddressLowRead, OperationCorrectAddressHigh, CycleAddYToAddressLowRead,
|
||||
OperationMoveToNextProgram, OperationIncrementPC,
|
||||
CycleFetchOperandFromAddress, CycleWriteOperandToAddress, OperationCopyOperandFromA, OperationCopyOperandToA,
|
||||
CycleIncrementPCFetchAddressLowFromOperand, CycleAddXToOperandFetchAddressLow, CycleIncrementOperandFetchAddressHigh, OperationDecrementOperand,
|
||||
OperationIncrementOperand, OperationORA, OperationAND, OperationEOR,
|
||||
OperationINS, OperationADC, OperationSBC, OperationLDA,
|
||||
OperationLDX, OperationLDY, OperationLAX, OperationSTA,
|
||||
OperationSTX, OperationSTY, OperationSAX, OperationSHA,
|
||||
OperationSHX, OperationSHY, OperationSHS, OperationCMP,
|
||||
OperationCPX, OperationCPY, OperationBIT, OperationASL,
|
||||
OperationASO, OperationROL, OperationRLA, OperationLSR,
|
||||
OperationLSE, OperationASR, OperationROR, OperationRRA,
|
||||
OperationCLC, OperationCLI, OperationCLV, OperationCLD,
|
||||
OperationSEC, OperationSEI, OperationSED, OperationINC,
|
||||
OperationDEC, OperationINX, OperationDEX, OperationINY,
|
||||
OperationDEY, OperationBPL, OperationBMI, OperationBVC,
|
||||
OperationBVS, OperationBCC, OperationBCS, OperationBNE,
|
||||
OperationBEQ, OperationTXA, OperationTYA, OperationTXS,
|
||||
OperationTAY, OperationTAX, OperationTSX, OperationARR,
|
||||
OperationSBX, OperationLXA, OperationANE, OperationANC,
|
||||
OperationLAS, CycleAddSignedOperandToPC, OperationSetFlagsFromOperand, OperationSetOperandFromFlagsWithBRKSet,
|
||||
OperationSetOperandFromFlags,
|
||||
OperationSetFlagsFromA,
|
||||
CycleScheduleJam
|
||||
};
|
||||
|
||||
#define JAM {CycleFetchOperand, CycleScheduleJam, OperationMoveToNextProgram}
|
||||
|
||||
union RegisterPair {
|
||||
uint16_t full;
|
||||
struct {
|
||||
uint8_t low, high;
|
||||
} bytes;
|
||||
};
|
||||
|
||||
/*
|
||||
Storage for the 6502 registers; F is stored as individual flags.
|
||||
*/
|
||||
@ -151,16 +148,6 @@ template <class T> class Processor {
|
||||
uint8_t operation_, operand_;
|
||||
RegisterPair address_, next_address_;
|
||||
|
||||
/*
|
||||
Up to four programs can be scheduled; each will be carried out in turn. This
|
||||
storage maintains pointers to the scheduled list of programs.
|
||||
|
||||
Programs should be terminated by an OperationMoveToNextProgram, causing this
|
||||
queue to take that step.
|
||||
*/
|
||||
const MicroOp *scheduled_programs_[4];
|
||||
unsigned int schedule_programs_write_pointer_, schedule_programs_read_pointer_, schedule_program_program_counter_;
|
||||
|
||||
/*
|
||||
Temporary storage allowing a common dispatch point for calling perform_bus_operation;
|
||||
possibly deferring is no longer of value.
|
||||
@ -169,18 +156,6 @@ template <class T> class Processor {
|
||||
uint16_t bus_address_;
|
||||
uint8_t *bus_value_;
|
||||
|
||||
/*!
|
||||
Schedules a new program, adding it to the end of the queue. Programs should be
|
||||
terminated with a OperationMoveToNextProgram. No attempt to copy the program
|
||||
is made; a non-owning reference is kept.
|
||||
|
||||
@param program The program to schedule.
|
||||
*/
|
||||
inline void schedule_program(const MicroOp *program) {
|
||||
scheduled_programs_[schedule_programs_write_pointer_] = program;
|
||||
schedule_programs_write_pointer_ = (schedule_programs_write_pointer_+1)&3;
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the flags register.
|
||||
|
||||
@ -535,14 +510,11 @@ template <class T> class Processor {
|
||||
|
||||
protected:
|
||||
Processor() :
|
||||
schedule_programs_read_pointer_(0),
|
||||
schedule_programs_write_pointer_(0),
|
||||
is_jammed_(false),
|
||||
jam_handler_(nullptr),
|
||||
cycles_left_to_run_(0),
|
||||
ready_line_is_enabled_(false),
|
||||
ready_is_active_(false),
|
||||
scheduled_programs_{nullptr, nullptr, nullptr, nullptr},
|
||||
inverse_interrupt_flag_(0),
|
||||
irq_request_history_(0),
|
||||
s_(0),
|
||||
@ -585,16 +557,14 @@ template <class T> class Processor {
|
||||
// These plus program below act to give the compiler permission to update these values
|
||||
// without touching the class storage (i.e. it explicitly says they need be completely up
|
||||
// to date in this stack frame only); which saves some complicated addressing
|
||||
unsigned int scheduleProgramsReadPointer = schedule_programs_read_pointer_;
|
||||
unsigned int scheduleProgramProgramCounter = schedule_program_program_counter_;
|
||||
RegisterPair nextAddress = next_address_;
|
||||
BusOperation nextBusOperation = next_bus_operation_;
|
||||
uint16_t busAddress = bus_address_;
|
||||
uint8_t *busValue = bus_value_;
|
||||
|
||||
#define checkSchedule(op) \
|
||||
if(!scheduled_programs_[scheduleProgramsReadPointer]) {\
|
||||
scheduleProgramsReadPointer = schedule_programs_write_pointer_ = scheduleProgramProgramCounter = 0;\
|
||||
if(!scheduled_program_counter_) {\
|
||||
schedule_programs_read_pointer_ = schedule_programs_write_pointer_ = 0; \
|
||||
if(interrupt_requests_) {\
|
||||
if(interrupt_requests_ & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn)) {\
|
||||
interrupt_requests_ &= ~InterruptRequestFlags::PowerOn;\
|
||||
@ -620,7 +590,6 @@ template <class T> class Processor {
|
||||
|
||||
checkSchedule();
|
||||
number_of_cycles += cycles_left_to_run_;
|
||||
const MicroOp *program = scheduled_programs_[scheduleProgramsReadPointer];
|
||||
|
||||
while(number_of_cycles > 0) {
|
||||
|
||||
@ -635,8 +604,8 @@ template <class T> class Processor {
|
||||
|
||||
while(1) {
|
||||
|
||||
const MicroOp cycle = program[scheduleProgramProgramCounter];
|
||||
scheduleProgramProgramCounter++;
|
||||
const MicroOp cycle = *scheduled_program_counter_;
|
||||
scheduled_program_counter_++;
|
||||
|
||||
#define read_op(val, addr) nextBusOperation = BusOperation::ReadOpcode; busAddress = addr; busValue = &val; val = 0xff
|
||||
#define read_mem(val, addr) nextBusOperation = BusOperation::Read; busAddress = addr; busValue = &val; val = 0xff
|
||||
@ -675,11 +644,8 @@ template <class T> class Processor {
|
||||
continue;
|
||||
|
||||
case OperationMoveToNextProgram:
|
||||
scheduled_programs_[scheduleProgramsReadPointer] = NULL;
|
||||
scheduleProgramsReadPointer = (scheduleProgramsReadPointer+1)&3;
|
||||
scheduleProgramProgramCounter = 0;
|
||||
move_to_next_program();
|
||||
checkSchedule();
|
||||
program = scheduled_programs_[scheduleProgramsReadPointer];
|
||||
continue;
|
||||
|
||||
#define push(v) {\
|
||||
@ -742,7 +708,7 @@ template <class T> class Processor {
|
||||
|
||||
if(jam_handler_) {
|
||||
jam_handler_->processor_did_jam(this, pc_.full - 1);
|
||||
checkSchedule(is_jammed_ = false; program = scheduled_programs_[scheduleProgramsReadPointer]);
|
||||
checkSchedule(is_jammed_ = false;);
|
||||
}
|
||||
} continue;
|
||||
|
||||
@ -1110,14 +1076,12 @@ template <class T> class Processor {
|
||||
}
|
||||
|
||||
cycles_left_to_run_ = number_of_cycles;
|
||||
schedule_programs_read_pointer_ = scheduleProgramsReadPointer;
|
||||
schedule_program_program_counter_ = scheduleProgramProgramCounter;
|
||||
next_address_ = nextAddress;
|
||||
next_bus_operation_ = nextBusOperation;
|
||||
bus_address_ = busAddress;
|
||||
bus_value_ = busValue;
|
||||
|
||||
static_cast<T *>(this)->synchronise();
|
||||
static_cast<T *>(this)->flush();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1125,7 +1089,7 @@ template <class T> class Processor {
|
||||
|
||||
Users of the 6502 template may override this.
|
||||
*/
|
||||
void synchronise() {}
|
||||
void flush() {}
|
||||
|
||||
/*!
|
||||
Gets the value of a register.
|
||||
@ -1176,12 +1140,13 @@ template <class T> class Processor {
|
||||
*/
|
||||
void return_from_subroutine() {
|
||||
s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(CPU6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(CPU6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high);
|
||||
static_cast<T *>(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.low); s_++;
|
||||
static_cast<T *>(this)->perform_bus_operation(MOS6502::BusOperation::Read, 0x100 | s_, &pc_.bytes.high);
|
||||
pc_.full++;
|
||||
|
||||
if(is_jammed_) {
|
||||
scheduled_programs_[0] = scheduled_programs_[1] = scheduled_programs_[2] = scheduled_programs_[3] = nullptr;
|
||||
scheduled_program_counter_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1278,6 +1243,7 @@ template <class T> class Processor {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CPU6502_cpp */
|
||||
#endif /* MOS6502_cpp */
|
29
Processors/6502/6502AllRAM.cpp
Normal file
29
Processors/6502/6502AllRAM.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// 6502AllRAM.cpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 13/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "6502AllRAM.hpp"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
using namespace CPU::MOS6502;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor() : ::CPU::AllRAMProcessor(65536) {
|
||||
set_power_on(false);
|
||||
}
|
||||
|
||||
int AllRAMProcessor::perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
timestamp_++;
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
*value = memory_[address];
|
||||
} else {
|
||||
memory_[address] = *value;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
31
Processors/6502/6502AllRAM.hpp
Normal file
31
Processors/6502/6502AllRAM.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// 6502AllRAM.hpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 13/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MOS6502AllRAM_cpp
|
||||
#define MOS6502AllRAM_cpp
|
||||
|
||||
#include "6502.hpp"
|
||||
#include "../AllRAMProcessor.hpp"
|
||||
|
||||
namespace CPU {
|
||||
namespace MOS6502 {
|
||||
|
||||
class AllRAMProcessor:
|
||||
public ::CPU::AllRAMProcessor,
|
||||
public Processor<AllRAMProcessor> {
|
||||
|
||||
public:
|
||||
AllRAMProcessor();
|
||||
|
||||
int perform_bus_operation(MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MOS6502AllRAM_cpp */
|
@ -1,38 +0,0 @@
|
||||
//
|
||||
// CPU6502AllRAM.cpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 13/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "CPU6502AllRAM.hpp"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
using namespace CPU6502;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor() : _timestamp(0) {
|
||||
set_power_on(false);
|
||||
}
|
||||
|
||||
int AllRAMProcessor::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
_timestamp++;
|
||||
|
||||
if(isReadOperation(operation)) {
|
||||
*value = _memory[address];
|
||||
} else {
|
||||
_memory[address] = *value;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data) {
|
||||
size_t endAddress = std::min(startAddress + length, (size_t)65536);
|
||||
memcpy(&_memory[startAddress], data, endAddress - startAddress);
|
||||
}
|
||||
|
||||
uint32_t AllRAMProcessor::get_timestamp() {
|
||||
return _timestamp;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
//
|
||||
// CPU6502AllRAM.hpp
|
||||
// CLK
|
||||
//
|
||||
// Created by Thomas Harte on 13/07/2015.
|
||||
// Copyright © 2015 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPU6502AllRAM_cpp
|
||||
#define CPU6502AllRAM_cpp
|
||||
|
||||
#include "CPU6502.hpp"
|
||||
|
||||
namespace CPU6502 {
|
||||
|
||||
class AllRAMProcessor: public Processor<AllRAMProcessor> {
|
||||
|
||||
public:
|
||||
|
||||
AllRAMProcessor();
|
||||
|
||||
int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
|
||||
void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data);
|
||||
uint32_t get_timestamp();
|
||||
|
||||
private:
|
||||
uint8_t _memory[65536];
|
||||
uint32_t _timestamp;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CPU6502AllRAM_cpp */
|
37
Processors/AllRAMProcessor.cpp
Normal file
37
Processors/AllRAMProcessor.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// AllRAMProcessor.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "AllRAMProcessor.hpp"
|
||||
|
||||
using namespace CPU;
|
||||
|
||||
AllRAMProcessor::AllRAMProcessor(size_t memory_size) :
|
||||
memory_(memory_size),
|
||||
timestamp_(0) {}
|
||||
|
||||
void AllRAMProcessor::set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data) {
|
||||
size_t endAddress = std::min(startAddress + length, (size_t)65536);
|
||||
memcpy(&memory_[startAddress], data, endAddress - startAddress);
|
||||
}
|
||||
|
||||
void AllRAMProcessor::get_data_at_address(uint16_t startAddress, size_t length, uint8_t *data) {
|
||||
size_t endAddress = std::min(startAddress + length, (size_t)65536);
|
||||
memcpy(data, &memory_[startAddress], endAddress - startAddress);
|
||||
}
|
||||
|
||||
uint32_t AllRAMProcessor::get_timestamp() {
|
||||
return timestamp_;
|
||||
}
|
||||
|
||||
void AllRAMProcessor::set_trap_handler(TrapHandler *trap_handler) {
|
||||
trap_handler_ = trap_handler;
|
||||
}
|
||||
|
||||
void AllRAMProcessor::add_trap_address(uint16_t address) {
|
||||
trap_addresses_.insert(address);
|
||||
}
|
49
Processors/AllRAMProcessor.hpp
Normal file
49
Processors/AllRAMProcessor.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// AllRAMProcessor.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef AllRAMProcessor_hpp
|
||||
#define AllRAMProcessor_hpp
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace CPU {
|
||||
|
||||
class AllRAMProcessor {
|
||||
public:
|
||||
AllRAMProcessor(size_t memory_size);
|
||||
uint32_t get_timestamp();
|
||||
void set_data_at_address(uint16_t startAddress, size_t length, const uint8_t *data);
|
||||
void get_data_at_address(uint16_t startAddress, size_t length, uint8_t *data);
|
||||
|
||||
class TrapHandler {
|
||||
public:
|
||||
virtual void processor_did_trap(AllRAMProcessor &, uint16_t address) = 0;
|
||||
};
|
||||
void set_trap_handler(TrapHandler *trap_handler);
|
||||
void add_trap_address(uint16_t address);
|
||||
|
||||
protected:
|
||||
std::vector<uint8_t> memory_;
|
||||
uint32_t timestamp_;
|
||||
|
||||
inline void check_address_for_trap(uint16_t address) {
|
||||
if(trap_addresses_.find(address) != trap_addresses_.end()) {
|
||||
trap_handler_->processor_did_trap(*this, address);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<uint16_t> trap_addresses_;
|
||||
TrapHandler *trap_handler_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* AllRAMProcessor_hpp */
|
56
Processors/MicroOpScheduler.hpp
Normal file
56
Processors/MicroOpScheduler.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// MicroOpScheduler.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MicroOpScheduler_hpp
|
||||
#define MicroOpScheduler_hpp
|
||||
|
||||
namespace CPU {
|
||||
|
||||
template <class T> class MicroOpScheduler {
|
||||
public:
|
||||
MicroOpScheduler() :
|
||||
scheduled_programs_{nullptr, nullptr, nullptr, nullptr},
|
||||
schedule_programs_write_pointer_(0),
|
||||
schedule_programs_read_pointer_(0),
|
||||
scheduled_program_counter_(nullptr) {}
|
||||
|
||||
protected:
|
||||
/*
|
||||
Up to four programs can be scheduled; each will be carried out in turn. This
|
||||
storage maintains pointers to the scheduled list of programs.
|
||||
|
||||
Programs should be terminated by an OperationMoveToNextProgram, causing this
|
||||
queue to take that step.
|
||||
*/
|
||||
const T *scheduled_programs_[4];
|
||||
const T *scheduled_program_counter_;
|
||||
unsigned int schedule_programs_write_pointer_, schedule_programs_read_pointer_;
|
||||
|
||||
/*!
|
||||
Schedules a new program, adding it to the end of the queue. Programs should be
|
||||
terminated with a OperationMoveToNextProgram. No attempt to copy the program
|
||||
is made; a non-owning reference is kept.
|
||||
|
||||
@param program The program to schedule.
|
||||
*/
|
||||
inline void schedule_program(const T *program) {
|
||||
scheduled_programs_[schedule_programs_write_pointer_] = program;
|
||||
if(schedule_programs_write_pointer_ == schedule_programs_read_pointer_) scheduled_program_counter_ = program;
|
||||
schedule_programs_write_pointer_ = (schedule_programs_write_pointer_+1)&3;
|
||||
}
|
||||
|
||||
inline void move_to_next_program() {
|
||||
scheduled_programs_[schedule_programs_read_pointer_] = nullptr;
|
||||
schedule_programs_read_pointer_ = (schedule_programs_read_pointer_+1)&3;
|
||||
scheduled_program_counter_ = scheduled_programs_[schedule_programs_read_pointer_];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MicroOpScheduler_hpp */
|
28
Processors/RegisterSizes.hpp
Normal file
28
Processors/RegisterSizes.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// RegisterSizes.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef RegisterSizes_hpp
|
||||
#define RegisterSizes_hpp
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace CPU {
|
||||
|
||||
union RegisterPair {
|
||||
RegisterPair(uint16_t v) : full(v) {}
|
||||
RegisterPair() {}
|
||||
|
||||
uint16_t full;
|
||||
struct {
|
||||
uint8_t low, high;
|
||||
} bytes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* RegisterSizes_hpp */
|
9
Processors/Z80/Z80.cpp
Normal file
9
Processors/Z80/Z80.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
// Z80.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Z80.hpp"
|
1768
Processors/Z80/Z80.hpp
Normal file
1768
Processors/Z80/Z80.hpp
Normal file
File diff suppressed because it is too large
Load Diff
97
Processors/Z80/Z80AllRAM.cpp
Normal file
97
Processors/Z80/Z80AllRAM.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// Z80AllRAM.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Z80AllRAM.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace CPU::Z80;
|
||||
namespace {
|
||||
|
||||
class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor<ConcreteAllRAMProcessor> {
|
||||
public:
|
||||
ConcreteAllRAMProcessor() : AllRAMProcessor() {}
|
||||
|
||||
inline int perform_machine_cycle(const MachineCycle &cycle) {
|
||||
uint16_t address = cycle.address ? *cycle.address : 0x0000;
|
||||
switch(cycle.operation) {
|
||||
case BusOperation::ReadOpcode:
|
||||
// printf("! ");
|
||||
check_address_for_trap(address);
|
||||
case BusOperation::Read:
|
||||
// printf("r %04x [%02x] AF:%04x BC:%04x DE:%04x HL:%04x SP:%04x\n", address, memory_[address], get_value_of_register(CPU::Z80::Register::AF), get_value_of_register(CPU::Z80::Register::BC), get_value_of_register(CPU::Z80::Register::DE), get_value_of_register(CPU::Z80::Register::HL), get_value_of_register(CPU::Z80::Register::StackPointer));
|
||||
*cycle.value = memory_[address];
|
||||
break;
|
||||
case BusOperation::Write:
|
||||
// printf("w %04x\n", address);
|
||||
memory_[address] = *cycle.value;
|
||||
break;
|
||||
|
||||
case BusOperation::Output:
|
||||
break;
|
||||
case BusOperation::Input:
|
||||
// This logic is selected specifically because it seems to match
|
||||
// the FUSE unit tests. It might need factoring out.
|
||||
*cycle.value = address >> 8;
|
||||
break;
|
||||
|
||||
case BusOperation::Internal:
|
||||
break;
|
||||
|
||||
case BusOperation::Interrupt:
|
||||
// A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise
|
||||
// arbitrary.
|
||||
*cycle.value = 0x21;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("???\n");
|
||||
break;
|
||||
}
|
||||
timestamp_ += cycle.length;
|
||||
|
||||
if(delegate_ != nullptr) {
|
||||
delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_for_cycles(int cycles) {
|
||||
CPU::Z80::Processor<ConcreteAllRAMProcessor>::run_for_cycles(cycles);
|
||||
}
|
||||
|
||||
uint16_t get_value_of_register(Register r) {
|
||||
return CPU::Z80::Processor<ConcreteAllRAMProcessor>::get_value_of_register(r);
|
||||
}
|
||||
|
||||
void set_value_of_register(Register r, uint16_t value) {
|
||||
CPU::Z80::Processor<ConcreteAllRAMProcessor>::set_value_of_register(r, value);
|
||||
}
|
||||
|
||||
bool get_halt_line() {
|
||||
return CPU::Z80::Processor<ConcreteAllRAMProcessor>::get_halt_line();
|
||||
}
|
||||
|
||||
void reset_power_on() {
|
||||
return CPU::Z80::Processor<ConcreteAllRAMProcessor>::reset_power_on();
|
||||
}
|
||||
|
||||
void set_interrupt_line(bool value) {
|
||||
CPU::Z80::Processor<ConcreteAllRAMProcessor>::set_interrupt_line(value);
|
||||
}
|
||||
|
||||
void set_non_maskable_interrupt_line(bool value) {
|
||||
CPU::Z80::Processor<ConcreteAllRAMProcessor>::set_non_maskable_interrupt_line(value);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
AllRAMProcessor *AllRAMProcessor::Processor() {
|
||||
return new ConcreteAllRAMProcessor;
|
||||
}
|
47
Processors/Z80/Z80AllRAM.hpp
Normal file
47
Processors/Z80/Z80AllRAM.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// Z80AllRAM.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 16/05/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Z80AllRAM_hpp
|
||||
#define Z80AllRAM_hpp
|
||||
|
||||
#include "Z80.hpp"
|
||||
#include "../AllRAMProcessor.hpp"
|
||||
|
||||
namespace CPU {
|
||||
namespace Z80 {
|
||||
|
||||
class AllRAMProcessor:
|
||||
public ::CPU::AllRAMProcessor {
|
||||
|
||||
public:
|
||||
static AllRAMProcessor *Processor();
|
||||
|
||||
struct MemoryAccessDelegate {
|
||||
virtual void z80_all_ram_processor_did_perform_bus_operation(AllRAMProcessor &processor, BusOperation operation, uint16_t address, uint8_t value, int time_stamp) = 0;
|
||||
};
|
||||
inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
virtual void run_for_cycles(int cycles) = 0;
|
||||
virtual uint16_t get_value_of_register(Register r) = 0;
|
||||
virtual void set_value_of_register(Register r, uint16_t value) = 0;
|
||||
virtual bool get_halt_line() = 0;
|
||||
virtual void reset_power_on() = 0;
|
||||
virtual void set_interrupt_line(bool value) = 0;
|
||||
virtual void set_non_maskable_interrupt_line(bool value) = 0;
|
||||
|
||||
protected:
|
||||
MemoryAccessDelegate *delegate_;
|
||||
AllRAMProcessor() : ::CPU::AllRAMProcessor(65536), delegate_(nullptr) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Z80AllRAM_hpp */
|
Loading…
Reference in New Issue
Block a user