1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-06 13:31:55 +00:00

The 6522 is now a ClockReceiver.

This commit is contained in:
Thomas Harte 2017-07-24 22:29:09 -04:00
parent 2912d7055b
commit efdac2ce8c
5 changed files with 25 additions and 37 deletions

View File

@ -13,6 +13,8 @@
#include <typeinfo> #include <typeinfo>
#include <cstdio> #include <cstdio>
#include "../ClockReceiver.hpp"
namespace MOS { namespace MOS {
/*! /*!
@ -26,7 +28,7 @@ namespace MOS {
Consumers should derive their own curiously-recurring-template-pattern subclass, Consumers should derive their own curiously-recurring-template-pattern subclass,
implementing bus communications as required. implementing bus communications as required.
*/ */
template <class T> class MOS6522 { template <class T> class MOS6522: public ClockReceiver<MOS6522<T>> {
private: private:
enum InterruptFlag: uint8_t { enum InterruptFlag: uint8_t {
CA2ActiveEdge = 1 << 0, CA2ActiveEdge = 1 << 0,
@ -250,32 +252,22 @@ template <class T> class MOS6522 {
timer_is_running_[0] = false;\ timer_is_running_[0] = false;\
} }
/*! /*! Runs for a specified number of half cycles. */
Runs for a specified number of half cycles. inline void run_for(const HalfCycles &half_cycles) {
int number_of_half_cycles = half_cycles.as_int();
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 therefore may be 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.
Callers should decide whether they are going to use @c run_for_half_cycles or @c run_for_cycles, and not
intermingle usage.
*/
inline void run_for_half_cycles(unsigned int number_of_cycles) {
if(is_phase2_) { if(is_phase2_) {
phase2(); phase2();
number_of_cycles--; number_of_half_cycles--;
} }
while(number_of_cycles >= 2) { while(number_of_half_cycles >= 2) {
phase1(); phase1();
phase2(); phase2();
number_of_cycles -= 2; number_of_half_cycles -= 2;
} }
if(number_of_cycles) { if(number_of_half_cycles) {
phase1(); phase1();
is_phase2_ = true; is_phase2_ = true;
} else { } else {
@ -283,13 +275,9 @@ template <class T> class MOS6522 {
} }
} }
/*! /*! Runs for a specified number of cycles. */
Runs for a specified number of cycles. inline void run_for(const Cycles &cycles) {
int number_of_cycles = cycles.as_int();
Callers should decide whether they are going to use @c run_for_half_cycles or @c run_for_cycles, and not
intermingle usage.
*/
inline void run_for_cycles(unsigned int number_of_cycles) {
while(number_of_cycles--) { while(number_of_cycles--) {
phase1(); phase1();
phase2(); phase2();

View File

@ -63,8 +63,8 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
drive_VIA_.set_register(address, *value); drive_VIA_.set_register(address, *value);
} }
serial_port_VIA_->run_for_cycles(1); serial_port_VIA_->run_for(Cycles(1));
drive_VIA_.run_for_cycles(1); drive_VIA_.run_for(Cycles(1));
return 1; return 1;
} }

View File

@ -179,8 +179,8 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
} }
} }
user_port_via_->run_for_cycles(1); user_port_via_->run_for(Cycles(1));
keyboard_via_->run_for_cycles(1); keyboard_via_->run_for(Cycles(1));
if(typer_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && address == 0xEB1E) { if(typer_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && address == 0xEB1E) {
if(!typer_->type_next_character()) { if(!typer_->type_next_character()) {
clear_all_keys(); clear_all_keys();

View File

@ -130,7 +130,7 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
} }
} }
via_.run_for_cycles(1); via_.run_for(Cycles(1));
if(microdisc_is_enabled_) microdisc_.run_for(Cycles(8)); if(microdisc_is_enabled_) microdisc_.run_for(Cycles(8));
cycles_since_video_update_++; cycles_since_video_update_++;
return 1; return 1;
@ -235,15 +235,15 @@ uint8_t Machine::VIA::get_port_input(Port port) {
} }
void Machine::VIA::flush() { void Machine::VIA::flush() {
ay8910->run_for(Cycles((int)cycles_since_ay_update_)); ay8910->run_for(Cycles(cycles_since_ay_update_));
ay8910->flush(); ay8910->flush();
cycles_since_ay_update_ = 0; cycles_since_ay_update_ = 0;
} }
void Machine::VIA::run_for_cycles(unsigned int number_of_cycles) { void Machine::VIA::run_for(const Cycles &cycles) {
cycles_since_ay_update_ += number_of_cycles; cycles_since_ay_update_ += cycles.as_int();
MOS::MOS6522<VIA>::run_for_cycles(number_of_cycles); MOS::MOS6522<VIA>::run_for(cycles);
tape->run_for(Cycles((int)number_of_cycles)); tape->run_for(cycles);
} }
void Machine::VIA::update_ay() { void Machine::VIA::update_ay() {

View File

@ -143,7 +143,7 @@ class Machine:
void set_control_line_output(Port port, Line line, bool value); void set_control_line_output(Port port, Line line, bool value);
void set_port_output(Port port, uint8_t value, uint8_t direction_mask); void set_port_output(Port port, uint8_t value, uint8_t direction_mask);
uint8_t get_port_input(Port port); uint8_t get_port_input(Port port);
inline void run_for_cycles(unsigned int number_of_cycles); inline void run_for(const Cycles &cycles);
std::shared_ptr<GI::AY38910> ay8910; std::shared_ptr<GI::AY38910> ay8910;
std::unique_ptr<TapePlayer> tape; std::unique_ptr<TapePlayer> tape;
@ -154,7 +154,7 @@ class Machine:
private: private:
void update_ay(); void update_ay();
bool ay_bdir_, ay_bc1_; bool ay_bdir_, ay_bc1_;
unsigned int cycles_since_ay_update_; int cycles_since_ay_update_;
}; };
VIA via_; VIA via_;
std::shared_ptr<Keyboard> keyboard_; std::shared_ptr<Keyboard> keyboard_;