diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index 2c02748a1..84f24d6ec 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -66,11 +66,15 @@ void TMS9918::run_for(const HalfCycles cycles) { // PAL output is 313 lines total. NTSC output is 262 lines total. // Interrupt is signalled upon entering the lower border. + // Keep a count of cycles separate from internal counts to avoid + // potential errors mapping back and forth. + half_cycles_into_frame_ = (half_cycles_into_frame_ + cycles) % HalfCycles(frame_lines_ * 228 * 2); + // Convert to 342 cycles per line; the internal clock is 1.5 times the // nominal 3.579545 Mhz that I've advertised for this part. int int_cycles = (cycles.as_int() * 3) + cycles_error_; - cycles_error_ = int_cycles & 3; - int_cycles >>= 2; + cycles_error_ = int_cycles & 7; + int_cycles >>= 3; if(!int_cycles) return; // @@ -296,3 +300,16 @@ uint8_t TMS9918::get_register(int address) { void TMS9918::reevaluate_interrupts() { } + +HalfCycles TMS9918::get_time_until_interrupt() { + if(!generate_interrupts_) return HalfCycles(-1); + if(get_interrupt_line()) return HalfCycles(-1); + + const int half_cycles_per_frame = frame_lines_ * 228 * 2; + int half_cycles_remaining = (192 * 228 * 2 + half_cycles_per_frame - half_cycles_into_frame_.as_int()) % half_cycles_per_frame; + return HalfCycles(half_cycles_remaining); +} + +bool TMS9918::get_interrupt_line() { + return (status_ & 0x80) && generate_interrupts_; +} diff --git a/Components/9918/9918.hpp b/Components/9918/9918.hpp index 3bed97931..fc8c2b1e5 100644 --- a/Components/9918/9918.hpp +++ b/Components/9918/9918.hpp @@ -44,6 +44,9 @@ class TMS9918 { void set_register(int address, uint8_t value); uint8_t get_register(int address); + HalfCycles get_time_until_interrupt(); + bool get_interrupt_line(); + private: std::shared_ptr crt_; @@ -73,6 +76,7 @@ class TMS9918 { void reevaluate_interrupts(); + HalfCycles half_cycles_into_frame_; int column_ = 0, row_ = 0, output_column_ = 0; int cycles_error_ = 0; uint32_t *pixel_target_ = nullptr; @@ -93,7 +97,7 @@ class TMS9918 { uint8_t pattern_buffer_[40]; uint8_t colour_buffer_[32]; int access_pointer_ = 0; - uint8_t pattern_name_; + uint8_t pattern_name_ = 0; }; }; diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index c395c84f7..f50af639c 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -20,7 +20,15 @@ namespace MSX { -class AYPortHandler: public GI::AY38910::PortHandler { +struct AYPortHandler: public GI::AY38910::PortHandler { + void set_port_output(bool port_b, uint8_t value) { + printf("AY port %c output: %02x\n", port_b ? 'b' : 'a', value); + } + + uint8_t get_port_input(bool port_b) { + printf("AY port %c input\n", port_b ? 'b' : 'a'); + return 0xff; + } }; class ConcreteMachine: @@ -65,6 +73,7 @@ class ConcreteMachine: } void page_memory(uint8_t value) { + printf("Page %02x\n", value); for(int c = 0; c < 4; ++c) { read_pointers_[c] = unpopulated_; write_pointers_[c] = scratch_; @@ -87,6 +96,13 @@ class ConcreteMachine: } HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { + if(time_until_interrupt_ > 0) { + time_until_interrupt_ -= cycle.length; + if(time_until_interrupt_ <= HalfCycles(0)) { + z80_.set_interrupt_line(true, time_until_interrupt_); + } + } + uint16_t address = cycle.address ? *cycle.address : 0x0000; switch(cycle.operation) { case CPU::Z80::PartialMachineCycle::ReadOpcode: @@ -104,6 +120,8 @@ class ConcreteMachine: vdp_->run_for(time_since_vdp_update_); time_since_vdp_update_ = 0; *cycle.value = vdp_->get_register(address); + z80_.set_interrupt_line(vdp_->get_interrupt_line()); + time_until_interrupt_ = vdp_->get_time_until_interrupt(); break; case 0xa2: @@ -124,6 +142,8 @@ class ConcreteMachine: vdp_->run_for(time_since_vdp_update_); time_since_vdp_update_ = 0; vdp_->set_register(address, *cycle.value); + z80_.set_interrupt_line(vdp_->get_interrupt_line()); + time_until_interrupt_ = vdp_->get_time_until_interrupt(); break; case 0xa0: @@ -205,7 +225,7 @@ class ConcreteMachine: uint8_t get_value(int port) { if(port == 1) { printf("?? Read keyboard\n"); - } + } else printf("What what?\n"); return 0xff; } @@ -229,6 +249,7 @@ class ConcreteMachine: std::vector basic_, main_; HalfCycles time_since_vdp_update_; + HalfCycles time_until_interrupt_; }; }