1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Begins addition of interrupt feedback from Nick.

Also fixes clock rate. Though clearly get_next_sequence_point isn't quite right yet.
This commit is contained in:
Thomas Harte 2021-06-17 22:30:24 -04:00
parent 0c3e9dca28
commit 2fd8a8aa66
3 changed files with 49 additions and 3 deletions

View File

@ -94,13 +94,26 @@ class ConcreteMachine:
page<3>(0x00);
}
int halves = 0;
// MARK: - Z80::BusHandler.
forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
using PartialMachineCycle = CPU::Z80::PartialMachineCycle;
const uint16_t address = cycle.address ? *cycle.address : 0x0000;
// TODO: possibly apply an access penalty.
nick_ += cycle.length;
halves += cycle.length.as<int>();
if(nick_ += cycle.length) {
const auto nick = nick_.last_valid();
const bool nick_interrupt_line = nick->get_interrupt_line();
if(nick_interrupt_line && !previous_nick_interrupt_line_) {
printf("Interrupt after %d\n", halves + nick_.last_sequence_point_overrun().as<int>());
halves = - nick_.last_sequence_point_overrun().as<int>();
}
previous_nick_interrupt_line_ = nick_interrupt_line;
}
switch(cycle.operation) {
default: break;
@ -270,6 +283,7 @@ class ConcreteMachine:
// MARK: - Chips.
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
JustInTimeActor<Nick, HalfCycles, 444923, 125000> nick_;
bool previous_nick_interrupt_line_ = false;
// Cf. timing guesses above.
};

View File

@ -82,7 +82,7 @@ uint8_t Nick::read([[maybe_unused]] uint16_t address) {
return 0xff;
}
void Nick::run_for(HalfCycles duration) {
void Nick::run_for(Cycles duration) {
constexpr int line_length = 912;
int clocks_remaining = duration.as<int>();
@ -112,8 +112,13 @@ void Nick::run_for(HalfCycles duration) {
++fetch_spot;
}
// TODO: when exactly does the interrupt output change? Am I a window too late? Or two too early?
// Special: set mode as soon as it's known. It'll be needed at the end of HSYNC.
if(window < 2 && fetch_spot >= 2) {
// Set the new interrupt line output.
interrupt_line_ = line_parameters_[1] & 0x80;
// Determine the margins.
left_margin_ = line_parameters_[2] & 0x3f;
right_margin_ = line_parameters_[3] & 0x3f;
@ -326,6 +331,22 @@ void Nick::flush_pixels() {
allocated_pointer_ = nullptr;
}
// MARK: - Sequence points.
Cycles Nick::get_next_sequence_point() {
// TODO: the below is incorrect; unit test and correct.
// Changing to e.g. Cycles(1) reveals the relevant discrepancy.
// return Cycles(1);
// Any mode line may cause a change in the interrupt output, so as a first blush
// just always report the time until the end of the mode line.
if(lines_remaining_ || horizontal_counter_ >= 2) {
return Cycles(2 + (912 - horizontal_counter_) + (0xff - lines_remaining_) * 912);
} else {
return Cycles(2 - horizontal_counter_);
}
}
// MARK: - CRT passthroughs.
void Nick::set_scan_target(Outputs::Display::ScanTarget *scan_target) {

View File

@ -22,11 +22,21 @@ class Nick {
void write(uint16_t address, uint8_t value);
uint8_t read(uint16_t address);
void run_for(HalfCycles);
void run_for(Cycles);
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
Outputs::Display::ScanStatus get_scaled_scan_status() const;
Cycles get_next_sequence_point();
/*!
@returns The current state of the interrupt line @c true for active;
@c false for inactive.
*/
inline bool get_interrupt_line() {
return interrupt_line_;
}
private:
Outputs::CRT::CRT crt_;
const uint8_t *const ram_;
@ -64,6 +74,7 @@ class Nick {
} state_ = State::Sync;
int bpp_ = 0;
int column_size_ = 0;
bool interrupt_line_ = true;
// An accumulator for border output regions.
int border_duration_ = 0;