mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Merge pull request #1157 from TomHarte/ADBRate
Add basic ADB controller interrupts.
This commit is contained in:
commit
6cbd152ff5
@ -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<false>(0x1ff4);
|
||||
// }
|
||||
if(line) {
|
||||
set_interrupt_request(interrupt_control_, 0x02, 0x1ff4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,6 +223,16 @@ template<bool is_brk> 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) {
|
||||
// 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<false>(vector);
|
||||
}
|
||||
}
|
||||
|
||||
template <Operation operation, AddressingMode addressing_mode> 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 +797,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 +817,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");
|
||||
|
@ -165,6 +165,8 @@ class Executor: public CachingExecutor {
|
||||
template<bool is_brk> 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_;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user