1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-26 09:29:45 +00:00

Worked logic all the way down to the CPC. If the 8272 announces that it is asleep, it is now no longer clocked. Also very slightly cut down on IRQ line chatter to the Z80.

This commit is contained in:
Thomas Harte 2017-08-20 12:05:00 -04:00
parent 49285e9caa
commit e88a51e75e
3 changed files with 30 additions and 5 deletions

View File

@ -88,6 +88,10 @@ i8272::i8272(BusHandler &bus_handler, Cycles clock_rate, int clock_rate_multipli
posit_event((int)Event8272::CommandByte);
}
bool i8272::is_sleeping() {
return is_sleeping_ && Storage::Disk::MFMController::is_sleeping();
}
void i8272::run_for(Cycles cycles) {
Storage::Disk::MFMController::run_for(cycles);
@ -154,6 +158,7 @@ void i8272::run_for(Cycles cycles) {
}
is_sleeping_ = !delay_time_ && !drives_seeking_ && !head_timers_running_;
if(is_sleeping_) update_sleep_observer();
}
void i8272::set_register(int address, uint8_t value) {
@ -198,7 +203,7 @@ void i8272::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
#define MS_TO_CYCLES(x) x * 8000
#define WAIT_FOR_EVENT(mask) resume_point_ = __LINE__; interesting_event_mask_ = (int)mask; return; case __LINE__:
#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; interesting_event_mask_ = (int)Event8272::Timer; delay_time_ = MS_TO_CYCLES(ms); is_sleeping_ = false; case __LINE__: if(delay_time_) return;
#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; interesting_event_mask_ = (int)Event8272::Timer; delay_time_ = MS_TO_CYCLES(ms); is_sleeping_ = false; update_sleep_observer(); case __LINE__: if(delay_time_) return;
#define PASTE(x, y) x##y
#define CONCAT(x, y) PASTE(x, y)
@ -257,6 +262,7 @@ void i8272::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
if(drives_[active_drive_].head_unload_delay[active_head_] == 0) { \
head_timers_running_++; \
is_sleeping_ = false; \
update_sleep_observer(); \
} \
drives_[active_drive_].head_unload_delay[active_head_] = MS_TO_CYCLES(head_unload_time_);\
}
@ -711,6 +717,7 @@ void i8272::posit_event(int event_type) {
if(drives_[drive].phase != Drive::Seeking) {
drives_seeking_++;
is_sleeping_ = false;
update_sleep_observer();
}
// Set currently seeking, with a step to occur right now (yes, it sounds like jamming these

View File

@ -41,6 +41,8 @@ class i8272: public Storage::Disk::MFMController {
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive);
bool is_sleeping();
private:
// The bus handler, for interrupt and DMA-driven usage.
BusHandler &bus_handler_;

View File

@ -76,7 +76,12 @@ class InterruptTimer {
/// @returns @c true if an interrupt is currently requested; @c false otherwise.
inline bool get_request() {
return interrupt_request_;
return last_interrupt_request_ = interrupt_request_;
}
/// Asks whether the interrupt status has changed.
inline bool request_has_changed() {
return last_interrupt_request_ != interrupt_request_;
}
/// Resets the timer.
@ -88,6 +93,7 @@ class InterruptTimer {
private:
int reset_counter_;
bool interrupt_request_;
bool last_interrupt_request_;
int timer_;
};
@ -659,6 +665,7 @@ class i8255PortHandler : public Intel::i8255::PortHandler {
class ConcreteMachine:
public Utility::TypeRecipient,
public CPU::Z80::BusHandler,
public Sleeper::SleepObserver,
public Machine {
public:
ConcreteMachine() :
@ -674,6 +681,10 @@ class ConcreteMachine:
// ensure memory starts in a random state
Memory::Fuzz(ram_, sizeof(ram_));
// register this class as the sleep observer for the FDC
fdc_.set_sleep_observer(this);
fdc_is_sleeping_ = fdc_.is_sleeping();
}
/// The entry point for performing a partial Z80 machine cycle.
@ -689,7 +700,7 @@ class ConcreteMachine:
crtc_counter_ += cycle.length;
Cycles crtc_cycles = crtc_counter_.divide_cycles(Cycles(4));
if(crtc_cycles > Cycles(0)) crtc_.run_for(crtc_cycles);
z80_.set_interrupt_line(interrupt_timer_.get_request());
if(interrupt_timer_.request_has_changed()) z80_.set_interrupt_line(interrupt_timer_.get_request());
// TODO (in the player, not here): adapt it to accept an input clock rate and
// run_for as HalfCycles
@ -699,7 +710,7 @@ class ConcreteMachine:
ay_.run_for(cycle.length);
// Clock the FDC, if connected, using a lazy scale by two
if(has_fdc_) fdc_.run_for(Cycles(cycle.length.as_int()));
if(has_fdc_ && !fdc_is_sleeping_) fdc_.run_for(Cycles(cycle.length.as_int()));
// Update typing activity
if(typer_) typer_->run_for(cycle.length);
@ -902,6 +913,11 @@ class ConcreteMachine:
roms_[(int)type] = data;
}
void set_component_is_sleeping(void *component, bool is_sleeping) {
// The FDC is the only thing this registers with as a sleep observer.
fdc_is_sleeping_ = is_sleeping;
}
#pragma mark - Keyboard
void set_typer_for_string(const char *string) {
@ -995,7 +1011,7 @@ class ConcreteMachine:
std::vector<uint8_t> roms_[7];
int rom_model_;
bool has_fdc_;
bool has_fdc_, fdc_is_sleeping_;
bool has_128k_;
bool upper_rom_is_paged_;
int upper_rom_;