From bb84a5a474ce38d737052bd7209626510baf71a3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 21 Aug 2023 15:35:13 -0400 Subject: [PATCH 1/2] Enable various ADB-controller interrupts. --- InstructionSets/M50740/Executor.cpp | 35 +++++++++++++++++++---------- InstructionSets/M50740/Executor.hpp | 2 ++ Machines/Apple/AppleIIgs/ADB.cpp | 1 + 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/InstructionSets/M50740/Executor.cpp b/InstructionSets/M50740/Executor.cpp index 1bdf666c5..4cb79358d 100644 --- a/InstructionSets/M50740/Executor.cpp +++ b/InstructionSets/M50740/Executor.cpp @@ -68,11 +68,9 @@ void Executor::set_interrupt_line(bool line) { // is active, amongst other things. if(interrupt_line_ != line) { interrupt_line_ = line; - - // TODO: verify interrupt connection. Externally, but stubbed off here. -// if(!interrupt_disable_ && line) { -// perform_interrupt(0x1ff4); -// } + if(line) { + set_interrupt_request(interrupt_control_, 0x02, 0x1ff4); + } } } @@ -225,6 +223,13 @@ template inline void Executor::perform_interrupt(uint16_t vector) { set_program_counter(uint16_t(memory_[vector] | (memory_[vector+1] << 8))); } +void Executor::set_interrupt_request(uint8_t ®, uint8_t value, uint16_t vector) { + reg |= value; + if(!interrupt_disable_ && (reg & (value >> 1))) { + perform_interrupt(vector); + } +} + template void Executor::perform() { // Post cycle cost; this emulation _does not provide accurate timing_. #define TLength(mode, base) case AddressingMode::mode: subtract_duration(base + t_lengths[index_mode_]); break; @@ -789,12 +794,17 @@ inline void Executor::subtract_duration(int duration) { // this additional divide by 4 produces the correct net divide by 16. timer_divider_ += duration; - const int t12_ticks = update_timer(prescalers_[0], timer_divider_ / t12_divider); + const int clock_ticks = timer_divider_ / t12_divider; timer_divider_ &= (t12_divider-1); - // Update timers 1 and 2. TODO: interrupts (elsewhere?). - if(update_timer(timers_[0], t12_ticks)) interrupt_control_ |= 0x20; - if(update_timer(timers_[1], t12_ticks)) interrupt_control_ |= 0x08; + // Update timers 1 and 2. + const int t12_ticks = update_timer(prescalers_[0], timer_divider_ / t12_divider); + if(update_timer(timers_[0], t12_ticks)) { + set_interrupt_request(interrupt_control_, 0x20, 0x1ff8); + } + if(update_timer(timers_[1], t12_ticks)) { + set_interrupt_request(interrupt_control_, 0x08, 0x1ff6); + } // If timer X is disabled, stop. if(timer_control_&0x20) { @@ -804,9 +814,10 @@ inline void Executor::subtract_duration(int duration) { // Update timer X prescaler. switch(timer_control_ & 0x0c) { default: { - const int tx_ticks = update_timer(prescalers_[1], t12_ticks); // TODO: don't hard code this. And is this even right? - if(update_timer(timers_[2], tx_ticks)) - timer_control_ |= 0x80; // TODO: interrupt result of this. + const int tx_ticks = update_timer(prescalers_[1], clock_ticks); + if(update_timer(timers_[2], tx_ticks)) { + set_interrupt_request(timer_control_, 0x80, 0x1ffa); + } } break; case 0x04: LOG("TODO: Timer X; Pulse output mode"); diff --git a/InstructionSets/M50740/Executor.hpp b/InstructionSets/M50740/Executor.hpp index 8d87e9de3..193cae11c 100644 --- a/InstructionSets/M50740/Executor.hpp +++ b/InstructionSets/M50740/Executor.hpp @@ -165,6 +165,8 @@ class Executor: public CachingExecutor { template inline void perform_interrupt(uint16_t vector); inline void set_port_output(int port); + void set_interrupt_request(uint8_t ®, uint8_t value, uint16_t vector); + // MARK: - Execution time Cycles cycles_; diff --git a/Machines/Apple/AppleIIgs/ADB.cpp b/Machines/Apple/AppleIIgs/ADB.cpp index 3ffd099f0..97fa9dff2 100644 --- a/Machines/Apple/AppleIIgs/ADB.cpp +++ b/Machines/Apple/AppleIIgs/ADB.cpp @@ -289,5 +289,6 @@ void GLU::run_ports_for(Cycles cycles) { } void GLU::set_vertical_blank(bool is_blank) { + vertical_blank_ = is_blank; executor_.set_interrupt_line(is_blank); } From a5038259bc63e43f153822b9de7fb6ee16d51b15 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 21 Aug 2023 19:30:34 -0400 Subject: [PATCH 2/2] Add admission. --- InstructionSets/M50740/Executor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InstructionSets/M50740/Executor.cpp b/InstructionSets/M50740/Executor.cpp index 4cb79358d..f791663a5 100644 --- a/InstructionSets/M50740/Executor.cpp +++ b/InstructionSets/M50740/Executor.cpp @@ -224,6 +224,9 @@ template inline void Executor::perform_interrupt(uint16_t vector) { } void Executor::set_interrupt_request(uint8_t ®, uint8_t value, uint16_t vector) { + // TODO: this allows interrupts through only if fully enabled at the time they + // signal. Which isn't quite correct, albeit that it seems sufficient for the + // IIgs ADB controller. reg |= value; if(!interrupt_disable_ && (reg & (value >> 1))) { perform_interrupt(vector);