mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +00:00
The 6522 is now a ClockReceiver
.
This commit is contained in:
parent
2912d7055b
commit
efdac2ce8c
@ -13,6 +13,8 @@
|
||||
#include <typeinfo>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../ClockReceiver.hpp"
|
||||
|
||||
namespace MOS {
|
||||
|
||||
/*!
|
||||
@ -26,7 +28,7 @@ namespace MOS {
|
||||
Consumers should derive their own curiously-recurring-template-pattern subclass,
|
||||
implementing bus communications as required.
|
||||
*/
|
||||
template <class T> class MOS6522 {
|
||||
template <class T> class MOS6522: public ClockReceiver<MOS6522<T>> {
|
||||
private:
|
||||
enum InterruptFlag: uint8_t {
|
||||
CA2ActiveEdge = 1 << 0,
|
||||
@ -250,32 +252,22 @@ template <class T> class MOS6522 {
|
||||
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_) {
|
||||
phase2();
|
||||
number_of_cycles--;
|
||||
number_of_half_cycles--;
|
||||
}
|
||||
|
||||
while(number_of_cycles >= 2) {
|
||||
while(number_of_half_cycles >= 2) {
|
||||
phase1();
|
||||
phase2();
|
||||
number_of_cycles -= 2;
|
||||
number_of_half_cycles -= 2;
|
||||
}
|
||||
|
||||
if(number_of_cycles) {
|
||||
if(number_of_half_cycles) {
|
||||
phase1();
|
||||
is_phase2_ = true;
|
||||
} else {
|
||||
@ -283,13 +275,9 @@ template <class T> class MOS6522 {
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Runs for a specified number of cycles.
|
||||
|
||||
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) {
|
||||
/*! Runs for a specified number of cycles. */
|
||||
inline void run_for(const Cycles &cycles) {
|
||||
int number_of_cycles = cycles.as_int();
|
||||
while(number_of_cycles--) {
|
||||
phase1();
|
||||
phase2();
|
||||
|
@ -63,8 +63,8 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
|
||||
drive_VIA_.set_register(address, *value);
|
||||
}
|
||||
|
||||
serial_port_VIA_->run_for_cycles(1);
|
||||
drive_VIA_.run_for_cycles(1);
|
||||
serial_port_VIA_->run_for(Cycles(1));
|
||||
drive_VIA_.run_for(Cycles(1));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -179,8 +179,8 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
|
||||
}
|
||||
}
|
||||
|
||||
user_port_via_->run_for_cycles(1);
|
||||
keyboard_via_->run_for_cycles(1);
|
||||
user_port_via_->run_for(Cycles(1));
|
||||
keyboard_via_->run_for(Cycles(1));
|
||||
if(typer_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && address == 0xEB1E) {
|
||||
if(!typer_->type_next_character()) {
|
||||
clear_all_keys();
|
||||
|
@ -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));
|
||||
cycles_since_video_update_++;
|
||||
return 1;
|
||||
@ -235,15 +235,15 @@ uint8_t Machine::VIA::get_port_input(Port port) {
|
||||
}
|
||||
|
||||
void Machine::VIA::flush() {
|
||||
ay8910->run_for(Cycles((int)cycles_since_ay_update_));
|
||||
ay8910->run_for(Cycles(cycles_since_ay_update_));
|
||||
ay8910->flush();
|
||||
cycles_since_ay_update_ = 0;
|
||||
}
|
||||
|
||||
void Machine::VIA::run_for_cycles(unsigned int number_of_cycles) {
|
||||
cycles_since_ay_update_ += number_of_cycles;
|
||||
MOS::MOS6522<VIA>::run_for_cycles(number_of_cycles);
|
||||
tape->run_for(Cycles((int)number_of_cycles));
|
||||
void Machine::VIA::run_for(const Cycles &cycles) {
|
||||
cycles_since_ay_update_ += cycles.as_int();
|
||||
MOS::MOS6522<VIA>::run_for(cycles);
|
||||
tape->run_for(cycles);
|
||||
}
|
||||
|
||||
void Machine::VIA::update_ay() {
|
||||
|
@ -143,7 +143,7 @@ class Machine:
|
||||
void set_control_line_output(Port port, Line line, bool value);
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask);
|
||||
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::unique_ptr<TapePlayer> tape;
|
||||
@ -154,7 +154,7 @@ class Machine:
|
||||
private:
|
||||
void update_ay();
|
||||
bool ay_bdir_, ay_bc1_;
|
||||
unsigned int cycles_since_ay_update_;
|
||||
int cycles_since_ay_update_;
|
||||
};
|
||||
VIA via_;
|
||||
std::shared_ptr<Keyboard> keyboard_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user