1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-03 11:30:02 +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;
}
int access_delay() const {
int access_delay(HalfCycles offset) const {
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;
if(lines >= 192) return 0;

View File

@ -107,27 +107,36 @@ template<Model model> class ConcreteMachine:
// MARK: - BusHandler
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.
// 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;
using PartialMachineCycle = CPU::Z80::PartialMachineCycle;
switch(cycle.operation) {
default: break;
case PartialMachineCycle::ReadOpcode:
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];
break;
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;
break;
@ -211,9 +220,22 @@ template<Model model> class ConcreteMachine:
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
// HalfCycles get_typer_delay(const std::string &) const final {
// 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_;
const uint8_t *read_pointers_[4];
uint8_t *write_pointers_[4];
bool is_contended_[4];
uint8_t port1ffd_ = 0;
uint8_t port7ffd_ = 0;
@ -267,31 +290,31 @@ template<Model model> class ConcreteMachine:
switch(port1ffd_ & 0x6) {
default:
case 0x00:
set_memory(0, &ram_[0 * 16384], &ram_[0 * 16384]);
set_memory(1, &ram_[1 * 16384], &ram_[1 * 16384]);
set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384]);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384]);
set_memory(0, &ram_[0 * 16384], &ram_[0 * 16384], false);
set_memory(1, &ram_[1 * 16384], &ram_[1 * 16384], false);
set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384], false);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384], false);
break;
case 0x02:
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384]);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384]);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384]);
set_memory(3, &ram_[7 * 16384], &ram_[7 * 16384]);
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384], true);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384], true);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384], true);
set_memory(3, &ram_[7 * 16384], &ram_[7 * 16384], true);
break;
case 0x04:
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384]);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384]);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384]);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384]);
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384], true);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384], true);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384], true);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384], false);
break;
case 0x06:
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384]);
set_memory(1, &ram_[7 * 16384], &ram_[7 * 16384]);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384]);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384]);
set_memory(0, &ram_[4 * 16384], &ram_[4 * 16384], true);
set_memory(1, &ram_[7 * 16384], &ram_[7 * 16384], true);
set_memory(2, &ram_[6 * 16384], &ram_[6 * 16384], true);
set_memory(3, &ram_[3 * 16384], &ram_[3 * 16384], false);
break;
}
@ -300,16 +323,17 @@ template<Model model> class ConcreteMachine:
// Apply standard 128kb-esque mapping (albeit with extra ROM to pick from).
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(2, &ram_[2 * 16384], &ram_[2 * 16384]);
set_memory(1, &ram_[5 * 16384], &ram_[5 * 16384], true);
set_memory(2, &ram_[2 * 16384], &ram_[2 * 16384], false);
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;
write_pointers_[bank] = (write ? write : scratch_.data()) - bank*16384;
}