From ce2f5515c0417c7d04cc75316ee484e0dd3d954c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jun 2016 18:11:37 -0400 Subject: [PATCH 1/5] Made some minor documentation improvements, killed 6522.cpp as the 6522 is going to be a template only, attempting to promote good inlining behaviour. --- Components/6522/6522.cpp | 12 -------- Components/6522/6522.hpp | 28 +++++++++++++++++++ Components/6532/6532.cpp | 9 ++++++ Components/6532/6532.hpp | 14 ++++++++++ Components/6560/6560.hpp | 4 +-- .../Clock Signal.xcodeproj/project.pbxproj | 18 +++++++++--- 6 files changed, 67 insertions(+), 18 deletions(-) delete mode 100644 Components/6522/6522.cpp create mode 100644 Components/6532/6532.cpp create mode 100644 Components/6532/6532.hpp diff --git a/Components/6522/6522.cpp b/Components/6522/6522.cpp deleted file mode 100644 index 412cf4791..000000000 --- a/Components/6522/6522.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// 6522.cpp -// Clock Signal -// -// Created by Thomas Harte on 06/06/2016. -// Copyright © 2016 Thomas Harte. All rights reserved. -// - -#include "6522.hpp" - -using namespace MOS; - diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 4cd616fde..58180edcf 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -14,6 +14,17 @@ namespace MOS { +/*! + Implements the template for an emulation of the MOS 6522 Versatile Interface Adaptor ('VIA'). + + The VIA provides: + * two timers, each of which may trigger interrupts and one of which may repeat; + * two digial input/output ports; and + * a serial-to-parallel shifter. + + Consumers should derive their own curiously-recurring-template-pattern subclass of MOS6522, + implementing bus communications as required for the specific machine. +*/ template class MOS6522 { private: enum InterruptFlag: uint8_t { @@ -27,6 +38,7 @@ template class MOS6522 { }; public: + /*! Sets a register value. */ void set_register(int address, uint8_t value) { address &= 0xf; @@ -98,6 +110,7 @@ template class MOS6522 { } } + /*! Gets a register value. */ uint8_t get_register(int address) { address &= 0xf; @@ -143,6 +156,16 @@ template class MOS6522 { { } + /*! + Runs for a specified number of half cycles. + + Although the original chip accepts only a phase-2 input, timer reloads are specified as occuring + 1.5 cycles after the timer hits zero. It is therefore necessary to emulate at half-cycle precision. + + The first emulated half-cycle will be the period between the trailing edge of a phase-2 input and the + next rising edge. So it should align with a full system's phase-1. The next emulated half-cycle will be + that which occurs during phase-2. + */ void run_for_half_cycles(unsigned int number_of_cycles) { while(number_of_cycles--) @@ -188,6 +211,7 @@ template class MOS6522 { } } + /*! @returns @c true if the IRQ line is currently active; @c false otherwise. */ bool get_interrupt_line() { uint8_t interrupt_status = _registers.interrupt_flags & _registers.interrupt_enable & 0x7f; @@ -249,6 +273,10 @@ template class MOS6522 { bool _timer_is_running[2]; }; +/*! + Provided for optional composition with @c MOS6522, @c MOS6522IRQDelegate provides for a delegate + that will receive IRQ line change notifications. +*/ class MOS6522IRQDelegate { public: class Delegate { diff --git a/Components/6532/6532.cpp b/Components/6532/6532.cpp new file mode 100644 index 000000000..ce466a685 --- /dev/null +++ b/Components/6532/6532.cpp @@ -0,0 +1,9 @@ +// +// 6532.cpp +// Clock Signal +// +// Created by Thomas Harte on 19/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "6532.hpp" diff --git a/Components/6532/6532.hpp b/Components/6532/6532.hpp new file mode 100644 index 000000000..2fd8a1989 --- /dev/null +++ b/Components/6532/6532.hpp @@ -0,0 +1,14 @@ +// +// 6532.hpp +// Clock Signal +// +// Created by Thomas Harte on 19/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef _532_hpp +#define _532_hpp + +#include + +#endif /* _532_hpp */ diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index bad97523e..4c041a962 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -15,9 +15,9 @@ namespace MOS { /*! - The 6560 is a video and audio output chip; it therefore vends both a @c CRT and a @c Speaker. + The 6560 Video Interface Chip ('VIC') is a video and audio output chip; it therefore vends both a @c CRT and a @c Speaker. - To run the 6560 for a cycle, the caller should call @c get_address, make the requested bus access + To run the VIC for a cycle, the caller should call @c get_address, make the requested bus access and call @c set_graphics_value with the result. @c set_register and @c get_register provide register access. diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index d7c054aac..06a18303e 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */; }; 4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; }; 4B1E85751D170228001EF87D /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85731D170228001EF87D /* Typer.cpp */; }; + 4B1E857C1D174DEC001EF87D /* 6532.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E857A1D174DEC001EF87D /* 6532.cpp */; }; 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2409531C45AB05004DA684 /* Speaker.cpp */; }; 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; }; 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53961D117D36003C6002 /* CSMachine.mm */; }; @@ -320,7 +321,6 @@ 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; }; 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; - 4BCA98C31D065CA20062F44C /* 6522.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCA98C11D065CA20062F44C /* 6522.cpp */; }; 4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; }; /* End PBXBuildFile section */ @@ -355,6 +355,8 @@ 4B1414611B58888700E04248 /* KlausDormannTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KlausDormannTests.swift; sourceTree = ""; }; 4B1E85731D170228001EF87D /* Typer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Typer.cpp; sourceTree = ""; }; 4B1E85741D170228001EF87D /* Typer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Typer.hpp; sourceTree = ""; }; + 4B1E857A1D174DEC001EF87D /* 6532.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6532.cpp; sourceTree = ""; }; + 4B1E857B1D174DEC001EF87D /* 6532.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6532.hpp; sourceTree = ""; }; 4B2409531C45AB05004DA684 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Speaker.cpp; path = ../../Outputs/Speaker.cpp; sourceTree = ""; }; 4B2409541C45AB05004DA684 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Speaker.hpp; path = ../../Outputs/Speaker.hpp; sourceTree = ""; }; 4B24095A1C45DF85004DA684 /* Stepper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stepper.hpp; sourceTree = ""; }; @@ -699,7 +701,6 @@ 4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = ""; }; 4BC9DF4D1D04691600F44158 /* 6560.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6560.cpp; sourceTree = ""; }; 4BC9DF4E1D04691600F44158 /* 6560.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6560.hpp; sourceTree = ""; }; - 4BCA98C11D065CA20062F44C /* 6522.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6522.cpp; sourceTree = ""; }; 4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = ""; }; 4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = ""; }; 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = ""; }; @@ -765,6 +766,15 @@ name = "Test Binaries"; sourceTree = ""; }; + 4B1E85791D174DEC001EF87D /* 6532 */ = { + isa = PBXGroup; + children = ( + 4B1E857A1D174DEC001EF87D /* 6532.cpp */, + 4B1E857B1D174DEC001EF87D /* 6532.hpp */, + ); + path = 6532; + sourceTree = ""; + }; 4B2409591C45DF85004DA684 /* SignalProcessing */ = { isa = PBXGroup; children = ( @@ -1304,6 +1314,7 @@ isa = PBXGroup; children = ( 4BC9DF4B1D04691600F44158 /* 6522 */, + 4B1E85791D174DEC001EF87D /* 6532 */, 4BC9DF4C1D04691600F44158 /* 6560 */, ); name = Components; @@ -1313,7 +1324,6 @@ 4BC9DF4B1D04691600F44158 /* 6522 */ = { isa = PBXGroup; children = ( - 4BCA98C11D065CA20062F44C /* 6522.cpp */, 4BCA98C21D065CA20062F44C /* 6522.hpp */, ); path = 6522; @@ -1764,8 +1774,8 @@ 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */, 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */, 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, - 4BCA98C31D065CA20062F44C /* 6522.cpp in Sources */, 4B2A53A11D117D36003C6002 /* CSAtari2600.mm in Sources */, + 4B1E857C1D174DEC001EF87D /* 6532.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, 4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */, 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */, From 65413f078cd9991f0f235b4fceb2d3441236fd01 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jun 2016 18:57:40 -0400 Subject: [PATCH 2/5] Factored out the 6532, eventually to make it testable. --- Components/6522/6522.hpp | 16 ++-- Components/6532/6532.hpp | 124 ++++++++++++++++++++++++++++++- Machines/Atari2600/Atari2600.cpp | 80 ++++---------------- Machines/Atari2600/Atari2600.hpp | 35 ++++++--- 4 files changed, 170 insertions(+), 85 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 58180edcf..509e83109 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -15,15 +15,15 @@ namespace MOS { /*! - Implements the template for an emulation of the MOS 6522 Versatile Interface Adaptor ('VIA'). + Implements a template for emulation of the MOS 6522 Versatile Interface Adaptor ('VIA'). The VIA provides: * two timers, each of which may trigger interrupts and one of which may repeat; * two digial input/output ports; and * a serial-to-parallel shifter. - Consumers should derive their own curiously-recurring-template-pattern subclass of MOS6522, - implementing bus communications as required for the specific machine. + Consumers should derive their own curiously-recurring-template-pattern subclass, + implementing bus communications as required. */ template class MOS6522 { private: @@ -39,7 +39,7 @@ template class MOS6522 { public: /*! Sets a register value. */ - void set_register(int address, uint8_t value) + inline void set_register(int address, uint8_t value) { address &= 0xf; // printf("6522 %p: %d <- %02x\n", this, address, value); @@ -111,7 +111,7 @@ template class MOS6522 { } /*! Gets a register value. */ - uint8_t get_register(int address) + inline uint8_t get_register(int address) { address &= 0xf; // printf("6522 %p: %d\n", this, address); @@ -152,7 +152,7 @@ template class MOS6522 { return 0xff; } - void set_control_line_input(int port, int line, bool value) + inline void set_control_line_input(int port, int line, bool value) { } @@ -166,7 +166,7 @@ template class MOS6522 { next rising edge. So it should align with a full system's phase-1. The next emulated half-cycle will be that which occurs during phase-2. */ - void run_for_half_cycles(unsigned int number_of_cycles) + inline void run_for_half_cycles(unsigned int number_of_cycles) { while(number_of_cycles--) { @@ -212,7 +212,7 @@ template class MOS6522 { } /*! @returns @c true if the IRQ line is currently active; @c false otherwise. */ - bool get_interrupt_line() + inline bool get_interrupt_line() { uint8_t interrupt_status = _registers.interrupt_flags & _registers.interrupt_enable & 0x7f; return !!interrupt_status; diff --git a/Components/6532/6532.hpp b/Components/6532/6532.hpp index 2fd8a1989..3df6178d3 100644 --- a/Components/6532/6532.hpp +++ b/Components/6532/6532.hpp @@ -9,6 +9,128 @@ #ifndef _532_hpp #define _532_hpp -#include +#include + +namespace MOS { + +/*! + Implements a template for emulation of the MOS 6532 RAM-I/O-Timer ('RIOT'). + + The RIOT provides: + * 128 bytes of static RAM; + * an interval timer; and + * two digital input/output ports. + + Consumers should derive their own curiously-recurring-template-pattern subclass, + implementing bus communications as required. +*/ +template class MOS6532 { + public: + inline void set_ram(uint16_t address, uint8_t value) { _ram[address&0x7f] = value; } + inline uint8_t get_ram(uint16_t address) { return _ram[address & 0x7f]; } + + inline void set_register(int address, uint8_t value) + { + const uint8_t decodedAddress = address & 0x0f; + switch(decodedAddress) { + case 0x00: + case 0x02: + static_cast(this)->set_port_output(decodedAddress / 2, value, _port[decodedAddress / 2].direction); + _port[decodedAddress/2].output = value; + break; + + case 0x01: + case 0x03: + _port[decodedAddress / 2].direction = value; + break; + + case 0x04: + case 0x05: + case 0x06: + case 0x07: + _timer.writtenShift = _timer.activeShift = (decodedAddress - 0x04) * 3 + (decodedAddress / 0x07); // i.e. 0, 3, 6, 10 + _timer.value = ((unsigned int)(value) << _timer.activeShift) | ((1 << _timer.activeShift)-1); + _timer.status &= ~0x40; + break; + } + } + + inline uint8_t get_register(int address) + { + const uint8_t decodedAddress = address & 0xf; + switch(decodedAddress) { + case 0x00: + case 0x02: + { + const int port = decodedAddress / 2; + uint8_t input = static_cast(this)->get_port_input(port); + return (input & ~_port[port].direction) | (_port[port].output & _port[port].direction); + } + break; + case 0x01: + case 0x03: + return _port[decodedAddress / 2].direction; + break; + case 0x04: + case 0x06: + { + uint8_t value = (uint8_t)(_timer.value >> _timer.activeShift); + + if(_timer.activeShift != _timer.writtenShift) { + unsigned int shift = _timer.writtenShift - _timer.activeShift; + _timer.value = (_timer.value << shift) | ((1 << shift) - 1); + _timer.activeShift = _timer.writtenShift; + } + + return value; + } + break; + case 0x05: + case 0x07: + { + uint8_t value = _timer.status; + _timer.status &= ~0x80; + return value; + } + break; + } + + return 0xff; + } + + inline void run_for_cycles(unsigned int number_of_cycles) + { + if(_timer.value >= number_of_cycles) { + _timer.value -= number_of_cycles; + } else { + _timer.value = 0x100 + ((_timer.value - (number_of_cycles / 3)) >> _timer.activeShift); + _timer.activeShift = 0; + _timer.status |= 0xc0; + } + } + + MOS6532() : + _timer({.status = 0}) + {} + + private: + uint8_t _ram[128]; + + struct { + unsigned int value; + unsigned int activeShift, writtenShift; + uint8_t status; + } _timer; + + struct { + uint8_t direction, output; + } _port[2]; + + // expected to be overridden + uint8_t get_port_input(int port) { return 0xff; } + void set_port_output(int port, uint8_t value, uint8_t direction_mask) {} +}; + +} #endif /* _532_hpp */ diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 8912b56c0..26014eb98 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -19,9 +19,7 @@ Machine::Machine() : _horizontalTimer(0), _lastOutputStateDuration(0), _lastOutputState(OutputState::Sync), - _piaTimerStatus(0xff), _rom(nullptr), - _piaDataValue{0xff, 0xff}, _tiaInputValue{0xff, 0xff}, _upcomingEventsPointer(0), _objectCounterPointer(0), @@ -455,9 +453,9 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // check for a RAM access if((address&0x1280) == 0x80) { if(isReadOperation(operation)) { - returnValue &= _ram[address&0x7f]; + returnValue &= _mos6532.get_ram(address); } else { - _ram[address&0x7f] = *value; + _mos6532.set_ram(address, *value); } } @@ -687,44 +685,9 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // check for a PIA access if((address&0x1280) == 0x280) { if(isReadOperation(operation)) { - const uint8_t decodedAddress = address & 0xf; - switch(address & 0xf) { - case 0x00: - case 0x02: - returnValue &= _piaDataValue[decodedAddress / 2]; - break; - case 0x01: - case 0x03: - // TODO: port DDR - printf("!!!DDR!!!"); - break; - case 0x04: - case 0x06: - returnValue &= _piaTimerValue >> _piaTimerShift; - - if(_writtenPiaTimerShift != _piaTimerShift) { - _piaTimerShift = _writtenPiaTimerShift; - _piaTimerValue <<= _writtenPiaTimerShift; - } - break; - case 0x05: - case 0x07: - returnValue &= _piaTimerStatus; - _piaTimerStatus &= ~0x80; - break; - } + returnValue &= _mos6532.get_register(address); } else { - const uint8_t decodedAddress = address & 0x0f; - switch(decodedAddress) { - case 0x04: - case 0x05: - case 0x06: - case 0x07: - _writtenPiaTimerShift = _piaTimerShift = (decodedAddress - 0x04) * 3 + (decodedAddress / 0x07); // i.e. 0, 3, 6, 10 - _piaTimerValue = ((unsigned int)(*value) << _piaTimerShift) | ((1 << _piaTimerShift)-1); - _piaTimerStatus &= ~0x40; - break; - } + _mos6532.set_register(address, *value); } } @@ -733,24 +696,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } } - if(_piaTimerValue >= cycles_run_for / 3) { - _piaTimerValue -= cycles_run_for / 3; - } else { - _piaTimerValue = 0x100 + ((_piaTimerValue - (cycles_run_for / 3)) >> _piaTimerShift); - _piaTimerShift = 0; - _piaTimerStatus |= 0xc0; - } - -// static unsigned int total_cycles = 0; -// total_cycles += cycles_run_for / 3; -// static time_t logged_time = 0; -// time_t time_now = time(nullptr); -// if(time_now - logged_time > 0) -// { -// printf("[c] %ld : %d\n", time_now - logged_time, total_cycles); -// total_cycles = 0; -// logged_time = time_now; -// } + _mos6532.run_for_cycles(cycles_run_for / 3); return cycles_run_for / 3; } @@ -758,15 +704,15 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin void Machine::set_digital_input(Atari2600DigitalInput input, bool state) { switch (input) { - case Atari2600DigitalInputJoy1Up: if(state) _piaDataValue[0] &= ~0x10; else _piaDataValue[0] |= 0x10; break; - case Atari2600DigitalInputJoy1Down: if(state) _piaDataValue[0] &= ~0x20; else _piaDataValue[0] |= 0x20; break; - case Atari2600DigitalInputJoy1Left: if(state) _piaDataValue[0] &= ~0x40; else _piaDataValue[0] |= 0x40; break; - case Atari2600DigitalInputJoy1Right: if(state) _piaDataValue[0] &= ~0x80; else _piaDataValue[0] |= 0x80; break; + case Atari2600DigitalInputJoy1Up: _mos6532.update_port_input(0, 0x10, state); break; + case Atari2600DigitalInputJoy1Down: _mos6532.update_port_input(0, 0x20, state); break; + case Atari2600DigitalInputJoy1Left: _mos6532.update_port_input(0, 0x40, state); break; + case Atari2600DigitalInputJoy1Right: _mos6532.update_port_input(0, 0x80, state); break; - case Atari2600DigitalInputJoy2Up: if(state) _piaDataValue[0] &= ~0x01; else _piaDataValue[0] |= 0x01; break; - case Atari2600DigitalInputJoy2Down: if(state) _piaDataValue[0] &= ~0x02; else _piaDataValue[0] |= 0x02; break; - case Atari2600DigitalInputJoy2Left: if(state) _piaDataValue[0] &= ~0x04; else _piaDataValue[0] |= 0x04; break; - case Atari2600DigitalInputJoy2Right: if(state) _piaDataValue[0] &= ~0x08; else _piaDataValue[0] |= 0x08; break; + case Atari2600DigitalInputJoy2Up: _mos6532.update_port_input(0, 0x01, state); break; + case Atari2600DigitalInputJoy2Down: _mos6532.update_port_input(0, 0x02, state); break; + case Atari2600DigitalInputJoy2Left: _mos6532.update_port_input(0, 0x04, state); break; + case Atari2600DigitalInputJoy2Right: _mos6532.update_port_input(0, 0x08, state); break; // TODO: latching case Atari2600DigitalInputJoy1Fire: if(state) _tiaInputValue[0] &= ~0x80; else _tiaInputValue[0] |= 0x80; break; diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index 109565257..a03157e63 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -9,9 +9,12 @@ #ifndef Atari2600_cpp #define Atari2600_cpp -#include "../../Processors/6502/CPU6502.hpp" -#include "../CRTMachine.hpp" #include + +#include "../../Processors/6502/CPU6502.hpp" +#include "../../Components/6532/6532.hpp" +#include "../CRTMachine.hpp" + #include "Atari2600Inputs.h" namespace Atari2600 { @@ -47,6 +50,24 @@ class Speaker: public ::Outputs::Filter { int _patterns[16][512]; }; +class PIA: public MOS::MOS6532 { + public: + inline uint8_t get_port_input(int port) + { + return _portValues[port]; + } + + inline void update_port_input(int port, uint8_t mask, bool set) + { + if(set) _portValues[port] |= mask; else _portValues[port] &= ~mask; + } + + private: + uint8_t _portValues[2]; + +}; + + class Machine: public CPU6502::Processor, public CRTMachine::Machine { public: @@ -72,13 +93,11 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { // TODO: different rate for PAL private: - uint8_t *_rom, *_romPages[4], _ram[128]; + uint8_t *_rom, *_romPages[4]; size_t _rom_size; - // the timer - unsigned int _piaTimerValue; - unsigned int _piaTimerShift, _writtenPiaTimerShift; - uint8_t _piaTimerStatus; + // the RIOT + PIA _mos6532; // playfield registers uint8_t _playfieldControl; @@ -162,8 +181,6 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { uint8_t _hMoveFlags; // joystick state - uint8_t _piaDataDirection[2]; - uint8_t _piaDataValue[2]; uint8_t _tiaInputValue[2]; // collisions From 065ec618c41ebe88965f280d8bb0f9932b31a5db Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jun 2016 19:36:34 -0400 Subject: [PATCH 3/5] Factored out and templated the 6532, finally taking the opportunity to add a means to control the on-console switches of an Atari 2600. --- Machines/Atari2600/Atari2600.cpp | 12 +++ Machines/Atari2600/Atari2600.hpp | 7 +- Machines/Atari2600/Atari2600Inputs.h | 8 ++ .../Base.lproj/Atari2600Document.xib | 89 +++++++++++++++++++ .../Base.lproj/ElectronDocument.xib | 2 +- .../Documents/Atari2600Document.swift | 22 ++++- .../Machine/Wrappers/CSAtari2600.h | 6 ++ .../Machine/Wrappers/CSAtari2600.mm | 42 +++++++++ 8 files changed, 185 insertions(+), 3 deletions(-) diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 26014eb98..ba56db751 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -722,6 +722,18 @@ void Machine::set_digital_input(Atari2600DigitalInput input, bool state) } } +void Machine::set_switch_is_enabled(Atari2600Switch input, bool state) +{ + switch(input) { + case Atari2600SwitchReset: _mos6532.update_port_input(1, 0x01, state); break; + case Atari2600SwitchSelect: _mos6532.update_port_input(1, 0x02, state); break; + case Atari2600SwitchColour: _mos6532.update_port_input(1, 0x08, state); break; + case Atari2600SwitchLeftPlayerDifficulty: _mos6532.update_port_input(1, 0x40, state); break; + case Atari2600SwitchRightPlayerDifficulty: _mos6532.update_port_input(1, 0x80, state); break; + } +} + + void Machine::set_rom(size_t length, const uint8_t *data) { _rom_size = 1024; diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index a03157e63..baa8dd0b0 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -59,9 +59,13 @@ class PIA: public MOS::MOS6532 { inline void update_port_input(int port, uint8_t mask, bool set) { - if(set) _portValues[port] |= mask; else _portValues[port] &= ~mask; + if(set) _portValues[port] &= ~mask; else _portValues[port] |= mask; } + PIA() : + _portValues{0xff, 0xff} + {} + private: uint8_t _portValues[2]; @@ -78,6 +82,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { void switch_region(); void set_digital_input(Atari2600DigitalInput input, bool state); + void set_switch_is_enabled(Atari2600Switch input, bool state); // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); diff --git a/Machines/Atari2600/Atari2600Inputs.h b/Machines/Atari2600/Atari2600Inputs.h index 780c90ff2..30ec4447c 100644 --- a/Machines/Atari2600/Atari2600Inputs.h +++ b/Machines/Atari2600/Atari2600Inputs.h @@ -27,6 +27,14 @@ typedef enum { Atari2600DigitalInputJoy2Fire, } Atari2600DigitalInput; +typedef enum { + Atari2600SwitchReset, + Atari2600SwitchSelect, + Atari2600SwitchColour, + Atari2600SwitchLeftPlayerDifficulty, + Atari2600SwitchRightPlayerDifficulty +} Atari2600Switch; + #ifdef __cplusplus } #endif diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib b/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib index e1f140fda..7fd9c5d3e 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib @@ -6,7 +6,13 @@ + + + + + + @@ -37,6 +43,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/ElectronDocument.xib b/OSBindings/Mac/Clock Signal/Base.lproj/ElectronDocument.xib index f5c6a8e5a..a74f5d383 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/ElectronDocument.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/ElectronDocument.xib @@ -1,5 +1,5 @@ - + diff --git a/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift b/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift index 4cfd1d4da..862f9f3c2 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift @@ -29,7 +29,6 @@ class Atari2600Document: MachineDocument { } // MARK: CSOpenGLViewResponderDelegate - private func inputForKey(event: NSEvent) -> Atari2600DigitalInput? { switch event.keyCode { case 123: return Atari2600DigitalInputJoy1Left @@ -64,4 +63,25 @@ class Atari2600Document: MachineDocument { atari2600.setResetLineEnabled(false) } } + + // MARK: Options + @IBOutlet var resetButton: NSButton! + @IBOutlet var selectButton: NSButton! + @IBOutlet var colourButton: NSButton! + @IBOutlet var leftPlayerDifficultyButton: NSButton! + @IBOutlet var rightPlayerDifficultyButton: NSButton! + + @IBAction func optionDidChange(sender: AnyObject!) { + atari2600.colourButton = colourButton.state == NSOnState + atari2600.leftPlayerDifficultyButton = leftPlayerDifficultyButton.state == NSOnState + atari2600.rightPlayerDifficultyButton = rightPlayerDifficultyButton.state == NSOnState + } + + @IBAction func optionWasPressed(sender: NSButton!) { + if sender == resetButton { + atari2600.pressResetButton() + } else { + atari2600.pressSelectButton() + } + } } \ No newline at end of file diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h index 05a0b70c3..4e842c19a 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.h @@ -15,4 +15,10 @@ - (void)setState:(BOOL)state forDigitalInput:(Atari2600DigitalInput)digitalInput; - (void)setResetLineEnabled:(BOOL)enabled; +@property (nonatomic, assign) BOOL colourButton; +@property (nonatomic, assign) BOOL leftPlayerDifficultyButton; +@property (nonatomic, assign) BOOL rightPlayerDifficultyButton; +- (void)pressResetButton; +- (void)pressSelectButton; + @end diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm index cec8e85bf..39bb10e8a 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSAtari2600.mm @@ -79,4 +79,46 @@ struct CRTDelegate: public Outputs::CRT::Delegate { return &_atari2600; } +#pragma mark - Switches + +- (void)setColourButton:(BOOL)colourButton { + _colourButton = colourButton; + @synchronized(self) { + _atari2600.set_switch_is_enabled(Atari2600SwitchColour, colourButton); + } +} + +- (void)setLeftPlayerDifficultyButton:(BOOL)leftPlayerDifficultyButton { + _leftPlayerDifficultyButton = leftPlayerDifficultyButton; + @synchronized(self) { + _atari2600.set_switch_is_enabled(Atari2600SwitchLeftPlayerDifficulty, leftPlayerDifficultyButton); + } +} + +- (void)setRightPlayerDifficultyButton:(BOOL)rightPlayerDifficultyButton { + _rightPlayerDifficultyButton = rightPlayerDifficultyButton; + @synchronized(self) { + _atari2600.set_switch_is_enabled(Atari2600SwitchRightPlayerDifficulty, rightPlayerDifficultyButton); + } +} + +- (void)toggleSwitch:(Atari2600Switch)toggleSwitch { + @synchronized(self) { + _atari2600.set_switch_is_enabled(toggleSwitch, true); + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + @synchronized(self) { + _atari2600.set_switch_is_enabled(toggleSwitch, false); + } + }); +} + +- (void)pressResetButton { + [self toggleSwitch:Atari2600SwitchReset]; +} + +- (void)pressSelectButton { + [self toggleSwitch:Atari2600SwitchSelect]; +} + @end From 7cf6008e7c631a360ee5a850fd234f55fa72a300 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jun 2016 20:12:47 -0400 Subject: [PATCH 4/5] Started some very basic RIOT unit tests; corrected to pass. --- Components/6532/6532.hpp | 7 ++- .../Clock Signal.xcodeproj/project.pbxproj | 10 +++ .../Mac/Clock SignalTests/6532Tests.swift | 61 +++++++++++++++++++ .../Clock SignalTests-Bridging-Header.h | 1 + .../Mac/Clock SignalTests/MOS6532Bridge.h | 22 +++++++ .../Mac/Clock SignalTests/MOS6532Bridge.mm | 35 +++++++++++ 6 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 OSBindings/Mac/Clock SignalTests/6532Tests.swift create mode 100644 OSBindings/Mac/Clock SignalTests/MOS6532Bridge.h create mode 100644 OSBindings/Mac/Clock SignalTests/MOS6532Bridge.mm diff --git a/Components/6532/6532.hpp b/Components/6532/6532.hpp index 3df6178d3..0201cfa32 100644 --- a/Components/6532/6532.hpp +++ b/Components/6532/6532.hpp @@ -50,7 +50,7 @@ template class MOS6532 { case 0x07: _timer.writtenShift = _timer.activeShift = (decodedAddress - 0x04) * 3 + (decodedAddress / 0x07); // i.e. 0, 3, 6, 10 _timer.value = ((unsigned int)(value) << _timer.activeShift) | ((1 << _timer.activeShift)-1); - _timer.status &= ~0x40; + _timer.status &= ~0x80; break; } } @@ -89,7 +89,7 @@ template class MOS6532 { case 0x07: { uint8_t value = _timer.status; - _timer.status &= ~0x80; + _timer.status &= ~0x40; return value; } break; @@ -103,7 +103,8 @@ template class MOS6532 { if(_timer.value >= number_of_cycles) { _timer.value -= number_of_cycles; } else { - _timer.value = 0x100 + ((_timer.value - (number_of_cycles / 3)) >> _timer.activeShift); + number_of_cycles -= _timer.value; + _timer.value = 0x100 - number_of_cycles; _timer.activeShift = 0; _timer.status |= 0xc0; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 06a18303e..efd57e617 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; }; 4B1E85751D170228001EF87D /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85731D170228001EF87D /* Typer.cpp */; }; 4B1E857C1D174DEC001EF87D /* 6532.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E857A1D174DEC001EF87D /* 6532.cpp */; }; + 4B1E857F1D17644D001EF87D /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E857E1D17644D001EF87D /* MOS6532Bridge.mm */; }; + 4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85801D176468001EF87D /* 6532Tests.swift */; }; 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2409531C45AB05004DA684 /* Speaker.cpp */; }; 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; }; 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53961D117D36003C6002 /* CSMachine.mm */; }; @@ -357,6 +359,9 @@ 4B1E85741D170228001EF87D /* Typer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Typer.hpp; sourceTree = ""; }; 4B1E857A1D174DEC001EF87D /* 6532.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6532.cpp; sourceTree = ""; }; 4B1E857B1D174DEC001EF87D /* 6532.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6532.hpp; sourceTree = ""; }; + 4B1E857D1D17644D001EF87D /* MOS6532Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOS6532Bridge.h; sourceTree = ""; }; + 4B1E857E1D17644D001EF87D /* MOS6532Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOS6532Bridge.mm; sourceTree = ""; }; + 4B1E85801D176468001EF87D /* 6532Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6532Tests.swift; sourceTree = ""; }; 4B2409531C45AB05004DA684 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Speaker.cpp; path = ../../Outputs/Speaker.cpp; sourceTree = ""; }; 4B2409541C45AB05004DA684 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Speaker.hpp; path = ../../Outputs/Speaker.hpp; sourceTree = ""; }; 4B24095A1C45DF85004DA684 /* Stepper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stepper.hpp; sourceTree = ""; }; @@ -1234,11 +1239,14 @@ children = ( 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */, 4BC751B41D157EB3006C31D9 /* MOS6522Bridge.h */, + 4B1E857D1D17644D001EF87D /* MOS6532Bridge.h */, 4BB297E21B587D8300A49093 /* TestMachine.h */, + 4B1E857E1D17644D001EF87D /* MOS6532Bridge.mm */, 4BC751B51D157EB3006C31D9 /* MOS6522Bridge.mm */, 4BB297E31B587D8300A49093 /* TestMachine.mm */, 4BB73EB81B587A5100552FC2 /* Info.plist */, 4BC751B11D157E61006C31D9 /* 6522Tests.swift */, + 4B1E85801D176468001EF87D /* 6532Tests.swift */, 4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */, 4B1414611B58888700E04248 /* KlausDormannTests.swift */, 4B92EAC91B7C112B00246143 /* TimingTests.swift */, @@ -1801,11 +1809,13 @@ 4BC751B61D157EB3006C31D9 /* MOS6522Bridge.mm in Sources */, 4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */, 4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */, + 4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */, 4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */, 4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */, 4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */, 4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */, 4BB298F01B587D8400A49093 /* TestMachine.mm in Sources */, + 4B1E857F1D17644D001EF87D /* MOS6532Bridge.mm in Sources */, 4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/OSBindings/Mac/Clock SignalTests/6532Tests.swift b/OSBindings/Mac/Clock SignalTests/6532Tests.swift new file mode 100644 index 000000000..2f29bf4e2 --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/6532Tests.swift @@ -0,0 +1,61 @@ +// +// 6532Tests.swift +// Clock Signal +// +// Created by Thomas Harte on 19/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +import XCTest +import Foundation + +class MOS6532Tests: XCTestCase { + + private func with6532(action: (MOS6532Bridge) -> ()) { + let bridge = MOS6532Bridge() + action(bridge) + } + + // MARK: Timer tests + func testOneTickTimer() { + with6532 { + // set a count of 128 at single-clock intervals + $0.setValue(128, forRegister:4) + + // run for one clock and the count should now be 127 + $0.runForCycles(1) + XCTAssert($0.valueForRegister(4) == 127, "A single tick should decrease the counter once") + + // run for a further 200 clock counts; timer should reach -73 = 183 + $0.runForCycles(200) + XCTAssert($0.valueForRegister(4) == 183, "Timer should underflow and keep counting") + } + } + + func testEightTickTimer() { + with6532 { + // set a count of 28 at eight-clock intervals + $0.setValue(28, forRegister:5) + + // run for seven clock and the count should still be 28 + $0.runForCycles(7) + XCTAssert($0.valueForRegister(4) == 28, "The timer should remain unchanged for seven clocks") + + // run for a further clock and the count should now be 27 + $0.runForCycles(1) + XCTAssert($0.valueForRegister(4) == 27, "The timer should have decremented once after 8 cycles") + + // run for a further 7 + 27*8 + 5 = 228 clock counts; timer should reach -5 = 0xfb + $0.runForCycles(228) + XCTAssert($0.valueForRegister(4) == 0xfb, "Timer should underflow and start counting at single-clock pace") + + // timer should now resume dividing by eight + $0.runForCycles(7) + XCTAssert($0.valueForRegister(4) == 0xfb, "Timer should remain unchanged for seven cycles") + + // timer should now resume dividing by eight + $0.runForCycles(1) + XCTAssert($0.valueForRegister(4) == 0xfa, "Timer should decrement after eighth cycle") + } + } +} diff --git a/OSBindings/Mac/Clock SignalTests/Clock SignalTests-Bridging-Header.h b/OSBindings/Mac/Clock SignalTests/Clock SignalTests-Bridging-Header.h index 0bcb4a76b..b14444445 100644 --- a/OSBindings/Mac/Clock SignalTests/Clock SignalTests-Bridging-Header.h +++ b/OSBindings/Mac/Clock SignalTests/Clock SignalTests-Bridging-Header.h @@ -4,3 +4,4 @@ #import "TestMachine.h" #import "MOS6522Bridge.h" +#import "MOS6532Bridge.h" diff --git a/OSBindings/Mac/Clock SignalTests/MOS6532Bridge.h b/OSBindings/Mac/Clock SignalTests/MOS6532Bridge.h new file mode 100644 index 000000000..47d0f7ebc --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/MOS6532Bridge.h @@ -0,0 +1,22 @@ +// +// MOS6532Bridge.h +// Clock Signal +// +// Created by Thomas Harte on 19/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import + +@interface MOS6532Bridge : NSObject + +@property (nonatomic, readonly) BOOL irqLine; +@property (nonatomic) uint8_t portBInput; +@property (nonatomic) uint8_t portAInput; + +- (void)setValue:(uint8_t)value forRegister:(NSUInteger)registerNumber; +- (uint8_t)valueForRegister:(NSUInteger)registerNumber; + +- (void)runForCycles:(NSUInteger)numberOfCycles; + +@end diff --git a/OSBindings/Mac/Clock SignalTests/MOS6532Bridge.mm b/OSBindings/Mac/Clock SignalTests/MOS6532Bridge.mm new file mode 100644 index 000000000..c7db4c24f --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/MOS6532Bridge.mm @@ -0,0 +1,35 @@ +// +// MOS6532Bridge.m +// Clock Signal +// +// Created by Thomas Harte on 19/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import "MOS6532Bridge.h" +#include "6532.hpp" + +class VanillaRIOT: public MOS::MOS6532 { +}; + +@implementation MOS6532Bridge +{ + VanillaRIOT _riot; +} + +- (void)setValue:(uint8_t)value forRegister:(NSUInteger)registerNumber +{ + _riot.set_register((int)registerNumber, value); +} + +- (uint8_t)valueForRegister:(NSUInteger)registerNumber +{ + return _riot.get_register((int)registerNumber); +} + +- (void)runForCycles:(NSUInteger)numberOfCycles +{ + _riot.run_for_cycles((int)numberOfCycles); +} + +@end From d5aaad396eca56385c30e46f9e250d0ef3d5b256 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jun 2016 20:13:31 -0400 Subject: [PATCH 5/5] Added a TODO on my lack of knowledge. --- OSBindings/Mac/Clock SignalTests/6532Tests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/OSBindings/Mac/Clock SignalTests/6532Tests.swift b/OSBindings/Mac/Clock SignalTests/6532Tests.swift index 2f29bf4e2..77bf396c9 100644 --- a/OSBindings/Mac/Clock SignalTests/6532Tests.swift +++ b/OSBindings/Mac/Clock SignalTests/6532Tests.swift @@ -32,6 +32,7 @@ class MOS6532Tests: XCTestCase { } } + // TODO: the test below makes the assumption that divider phase is flexible; verify func testEightTickTimer() { with6532 { // set a count of 28 at eight-clock intervals