1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +00:00

Takes a run at contended timings.

This commit is contained in:
Thomas Harte 2021-03-19 08:49:56 -04:00
parent f8c9ef2950
commit 93b9ea67e6
2 changed files with 59 additions and 33 deletions

View File

@ -225,11 +225,13 @@ template <VideoTiming timing> class Video {
return time_since_interrupt_ < interrupt_duration; return time_since_interrupt_ < interrupt_duration;
} }
int access_delay() const { int access_delay(HalfCycles offset) const {
constexpr auto timings = get_timings(); constexpr auto timings = get_timings();
if(time_since_interrupt_ < timings.first_delay) return 0; const int delay_time = (time_since_interrupt_ + offset.as<int>()) % (timings.cycles_per_line * timings.lines_per_frame);
const int time_since = time_since_interrupt_ - timings.first_delay; if(delay_time < timings.first_delay) return 0;
const int time_since = delay_time - timings.first_delay;
const int lines = time_since / timings.cycles_per_line; const int lines = time_since / timings.cycles_per_line;
if(lines >= 192) return 0; if(lines >= 192) return 0;

View File

@ -107,27 +107,36 @@ template<Model model> class ConcreteMachine:
// MARK: - BusHandler // MARK: - BusHandler
forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
time_since_audio_update_ += cycle.length;
video_ += cycle.length;
if(video_.did_flush()) {
z80_.set_interrupt_line(video_.last_valid()->get_interrupt_line());
}
// Ignore all but terminal cycles. // Ignore all but terminal cycles.
// TODO: I doubt this is correct for timing. // TODO: I doubt this is correct for timing.
if(!cycle.is_terminal()) return HalfCycles(0); if(!cycle.is_terminal()) {
advance(cycle.length);
return HalfCycles(0);
}
HalfCycles delay(0);
uint16_t address = cycle.address ? *cycle.address : 0x0000; uint16_t address = cycle.address ? *cycle.address : 0x0000;
using PartialMachineCycle = CPU::Z80::PartialMachineCycle; using PartialMachineCycle = CPU::Z80::PartialMachineCycle;
switch(cycle.operation) { switch(cycle.operation) {
default: break; default: break;
case PartialMachineCycle::ReadOpcode: case PartialMachineCycle::ReadOpcode:
case PartialMachineCycle::Read: case PartialMachineCycle::Read:
// Apply contention if necessary.
if(is_contended_[address >> 14]) {
delay = video_.last_valid()->access_delay(video_.time_since_flush());
}
*cycle.value = read_pointers_[address >> 14][address]; *cycle.value = read_pointers_[address >> 14][address];
break; break;
case PartialMachineCycle::Write: case PartialMachineCycle::Write:
// Apply contention if necessary.
// For now this causes a video sync up every time any contended area is written to.
// TODO: flush only upon a video-area write.
if(is_contended_[address >> 14]) {
delay = video_->access_delay(HalfCycles(0));
}
write_pointers_[address >> 14][address] = *cycle.value; write_pointers_[address >> 14][address] = *cycle.value;
break; break;
@ -211,9 +220,22 @@ template<Model model> class ConcreteMachine:
break; break;
} }
return HalfCycles(0); advance(cycle.length + delay);
return delay;
} }
private:
void advance(HalfCycles duration) {
time_since_audio_update_ += duration;
video_ += duration;
if(video_.did_flush()) {
z80_.set_interrupt_line(video_.last_valid()->get_interrupt_line());
}
}
public:
// MARK: - Typer // MARK: - Typer
// HalfCycles get_typer_delay(const std::string &) const final { // HalfCycles get_typer_delay(const std::string &) const final {
// return z80_.get_is_resetting() ? Cycles(7'000'000) : Cycles(0); // return z80_.get_is_resetting() ? Cycles(7'000'000) : Cycles(0);
@ -246,6 +268,7 @@ template<Model model> class ConcreteMachine:
std::array<uint8_t, 16*1024> scratch_; std::array<uint8_t, 16*1024> scratch_;
const uint8_t *read_pointers_[4]; const uint8_t *read_pointers_[4];
uint8_t *write_pointers_[4]; uint8_t *write_pointers_[4];
bool is_contended_[4];
uint8_t port1ffd_ = 0; uint8_t port1ffd_ = 0;
uint8_t port7ffd_ = 0; uint8_t port7ffd_ = 0;
@ -267,31 +290,31 @@ template<Model model> class ConcreteMachine:
switch(port1ffd_ & 0x6) { switch(port1ffd_ & 0x6) {
default: default:
case 0x00: case 0x00:
set_memory(0, &ram_[0 * 16384], &ram_[0 * 16384]); set_memory(0, &ram_[0 * 16384], &ram_[0 * 16384], false);
set_memory(1, &ram_[1 * 16384], &ram_[1 * 16384]); set_memory(1, &ram_[1 * 16384], &ram_[1 * 16384], false);
set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384]); set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384], false);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384]); set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384], false);
break; break;
case 0x02: case 0x02:
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384]); set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384], true);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384]); set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384], true);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384]); set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384], true);
set_memory(3, &ram_[7 * 16384], &ram_[7 * 16384]); set_memory(3, &ram_[7 * 16384], &ram_[7 * 16384], true);
break; break;
case 0x04: case 0x04:
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384]); set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384], true);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384]); set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384], true);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384]); set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384], true);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384]); set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384], false);
break; break;
case 0x06: case 0x06:
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384]); set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384], true);
set_memory(1, &ram_[7 * 16384], &ram_[7 * 16384]); set_memory(1, &ram_[7 * 16384], &ram_[7 * 16384], true);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384]); set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384], true);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384]); set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384], false);
break; break;
} }
@ -300,16 +323,17 @@ template<Model model> class ConcreteMachine:
// Apply standard 128kb-esque mapping (albeit with extra ROM to pick from). // Apply standard 128kb-esque mapping (albeit with extra ROM to pick from).
const auto rom = &rom_[ (((port1ffd_ >> 1) & 2) | ((port7ffd_ >> 4) & 1)) * 16384]; const auto rom = &rom_[ (((port1ffd_ >> 1) & 2) | ((port7ffd_ >> 4) & 1)) * 16384];
set_memory(0, rom, nullptr); set_memory(0, rom, nullptr, false);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384]); set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384], true);
set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384]); set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384], false);
const auto high_ram = &ram_[(port7ffd_ & 7) * 16384]; const auto high_ram = &ram_[(port7ffd_ & 7) * 16384];
set_memory(3, high_ram, high_ram); set_memory(3, high_ram, high_ram, (port7ffd_ & 7) >= 4);
} }
void set_memory(int bank, const uint8_t *read, uint8_t *write) { void set_memory(int bank, const uint8_t *read, uint8_t *write, bool is_contended) {
is_contended_[bank] = is_contended;
read_pointers_[bank] = read - bank*16384; read_pointers_[bank] = read - bank*16384;
write_pointers_[bank] = (write ? write : scratch_.data()) - bank*16384; write_pointers_[bank] = (write ? write : scratch_.data()) - bank*16384;
} }