mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Makes first effort to wire up the ADB vertical blank input.
However: looking at the disassembly, I'm not sure it really is wired to INTR. So work to do.
This commit is contained in:
parent
24af62a3e5
commit
eccf5ca043
@ -62,6 +62,20 @@ void Executor::reset() {
|
||||
set_program_counter(uint16_t(memory_[0x1ffe] | (memory_[0x1fff] << 8)));
|
||||
}
|
||||
|
||||
void Executor::set_interrupt_line(bool line) {
|
||||
// Super hack: interrupt now, if permitted. Otherwise do nothing.
|
||||
// So this will fail to catch enabling of interrupts while the 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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Executor::read(uint16_t address) {
|
||||
address &= 0x1fff;
|
||||
|
||||
@ -78,7 +92,7 @@ uint8_t Executor::read(uint16_t address) {
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
LOG("Unimplemented Port R read from " << PADHEX(4) << address);
|
||||
return 0xff;
|
||||
return 0x00;
|
||||
|
||||
// Ports P0–P3.
|
||||
case 0xe0: case 0xe2:
|
||||
@ -199,7 +213,7 @@ uint8_t Executor::flags() {
|
||||
carry_flag_;
|
||||
}
|
||||
|
||||
template<bool is_brk> inline void Executor::perform_interrupt() {
|
||||
template<bool is_brk> inline void Executor::perform_interrupt(uint16_t vector) {
|
||||
// BRK has an unused operand.
|
||||
++program_counter_;
|
||||
push(uint8_t(program_counter_ >> 8));
|
||||
@ -456,7 +470,7 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
|
||||
|
||||
case AddressingMode::AbsoluteIndirect:
|
||||
address = next16();
|
||||
address = unsigned(memory_[address] | (memory_[(address + 1) & 0x1fff] << 8));
|
||||
address = unsigned(memory_[address & 0x1fff] | (memory_[(address + 1) & 0x1fff] << 8));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -587,7 +601,7 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
|
||||
} break;
|
||||
|
||||
case Operation::BRK:
|
||||
perform_interrupt<true>();
|
||||
perform_interrupt<true>(0x1ff4);
|
||||
--program_counter_; // To undo the unavoidable increment
|
||||
// after exiting from here.
|
||||
break;
|
||||
|
@ -40,7 +40,9 @@ class Executor: public CachingExecutor {
|
||||
public:
|
||||
Executor(PortHandler &);
|
||||
void set_rom(const std::vector<uint8_t> &rom);
|
||||
|
||||
void reset();
|
||||
void set_interrupt_line(bool);
|
||||
|
||||
/*!
|
||||
Runs, in discrete steps, the minimum number of instructions as it takes to complete at least @c cycles.
|
||||
@ -150,6 +152,7 @@ class Executor: public CachingExecutor {
|
||||
|
||||
// Interrupt and timer control.
|
||||
uint8_t interrupt_control_ = 0, timer_control_ = 0;
|
||||
bool interrupt_line_ = false;
|
||||
|
||||
// Access helpers.
|
||||
inline uint8_t read(uint16_t address);
|
||||
@ -158,7 +161,7 @@ class Executor: public CachingExecutor {
|
||||
inline uint8_t pull();
|
||||
inline void set_flags(uint8_t);
|
||||
inline uint8_t flags();
|
||||
template<bool is_brk> inline void perform_interrupt();
|
||||
template<bool is_brk> inline void perform_interrupt(uint16_t vector);
|
||||
inline void set_port_output(int port);
|
||||
|
||||
// MARK: - Execution time
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "../../../InstructionSets/M50740/Parser.hpp"
|
||||
#include "../../../InstructionSets/Disassembler.hpp"
|
||||
|
||||
#define LOG_PREFIX "[ADB GLU] "
|
||||
#include "../../../Outputs/Log.hpp"
|
||||
|
||||
using namespace Apple::IIgs::ADB;
|
||||
|
||||
namespace {
|
||||
@ -199,7 +202,10 @@ void GLU::set_port_output(int port, uint8_t value) {
|
||||
}
|
||||
} break;
|
||||
case 3:
|
||||
modifier_state_ = value;
|
||||
if(modifier_state_ != (value & 0x30)) {
|
||||
modifier_state_ = value & 0x30;
|
||||
LOG("Modifier state: " << int(value & 0x30));
|
||||
}
|
||||
|
||||
// Output is inverted respective to input; the microcontroller
|
||||
// sets a value of '1' in order to pull the ADB bus low.
|
||||
@ -239,3 +245,7 @@ uint8_t GLU::get_port_input(int port) {
|
||||
void GLU::run_ports_for(Cycles cycles) {
|
||||
bus_.run_for(cycles);
|
||||
}
|
||||
|
||||
void GLU::set_vertical_blank(bool is_blank) {
|
||||
executor_.set_interrupt_line(is_blank);
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ class GLU: public InstructionSet::M50740::PortHandler {
|
||||
bool get_command_button() const;
|
||||
bool get_option_button() const;
|
||||
|
||||
void set_vertical_blank(bool);
|
||||
|
||||
private:
|
||||
InstructionSet::M50740::Executor executor_;
|
||||
|
||||
|
@ -895,6 +895,9 @@ class ConcreteMachine:
|
||||
}
|
||||
if(video_.did_flush()) {
|
||||
update_interrupts();
|
||||
|
||||
const bool is_vertical_blank = video_.last_valid()->get_is_vertical_blank(video_.time_since_flush());
|
||||
adb_glu_->set_vertical_blank(is_vertical_blank);
|
||||
}
|
||||
|
||||
return duration;
|
||||
|
@ -193,7 +193,7 @@ Cycles Video::get_next_sequence_point() const {
|
||||
|
||||
constexpr int sequence_point_offset = (blank_ticks + left_border_ticks) * CyclesPerTick;
|
||||
|
||||
// Seed as the distance ot the next row 0.
|
||||
// Seed as the distance to the next row 0.
|
||||
int result = CyclesPerLine + sequence_point_offset - cycles_into_row + (Lines - row - 1)*CyclesPerLine;
|
||||
|
||||
// Replace with the start of the next line, if closer.
|
||||
|
Loading…
x
Reference in New Issue
Block a user