1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-09 06:29:33 +00:00

Seeks to introduce MSX interrupts.

This commit is contained in:
Thomas Harte 2017-11-29 20:31:55 -05:00
parent 69ec8a362e
commit aa4eef41d8
3 changed files with 47 additions and 5 deletions

View File

@ -66,11 +66,15 @@ void TMS9918::run_for(const HalfCycles cycles) {
// PAL output is 313 lines total. NTSC output is 262 lines total. // PAL output is 313 lines total. NTSC output is 262 lines total.
// Interrupt is signalled upon entering the lower border. // 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 // 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. // nominal 3.579545 Mhz that I've advertised for this part.
int int_cycles = (cycles.as_int() * 3) + cycles_error_; int int_cycles = (cycles.as_int() * 3) + cycles_error_;
cycles_error_ = int_cycles & 3; cycles_error_ = int_cycles & 7;
int_cycles >>= 2; int_cycles >>= 3;
if(!int_cycles) return; if(!int_cycles) return;
// //
@ -296,3 +300,16 @@ uint8_t TMS9918::get_register(int address) {
void TMS9918::reevaluate_interrupts() { 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_;
}

View File

@ -44,6 +44,9 @@ class TMS9918 {
void set_register(int address, uint8_t value); void set_register(int address, uint8_t value);
uint8_t get_register(int address); uint8_t get_register(int address);
HalfCycles get_time_until_interrupt();
bool get_interrupt_line();
private: private:
std::shared_ptr<Outputs::CRT::CRT> crt_; std::shared_ptr<Outputs::CRT::CRT> crt_;
@ -73,6 +76,7 @@ class TMS9918 {
void reevaluate_interrupts(); void reevaluate_interrupts();
HalfCycles half_cycles_into_frame_;
int column_ = 0, row_ = 0, output_column_ = 0; int column_ = 0, row_ = 0, output_column_ = 0;
int cycles_error_ = 0; int cycles_error_ = 0;
uint32_t *pixel_target_ = nullptr; uint32_t *pixel_target_ = nullptr;
@ -93,7 +97,7 @@ class TMS9918 {
uint8_t pattern_buffer_[40]; uint8_t pattern_buffer_[40];
uint8_t colour_buffer_[32]; uint8_t colour_buffer_[32];
int access_pointer_ = 0; int access_pointer_ = 0;
uint8_t pattern_name_; uint8_t pattern_name_ = 0;
}; };
}; };

View File

@ -20,7 +20,15 @@
namespace MSX { 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: class ConcreteMachine:
@ -65,6 +73,7 @@ class ConcreteMachine:
} }
void page_memory(uint8_t value) { void page_memory(uint8_t value) {
printf("Page %02x\n", value);
for(int c = 0; c < 4; ++c) { for(int c = 0; c < 4; ++c) {
read_pointers_[c] = unpopulated_; read_pointers_[c] = unpopulated_;
write_pointers_[c] = scratch_; write_pointers_[c] = scratch_;
@ -87,6 +96,13 @@ class ConcreteMachine:
} }
HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { 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; uint16_t address = cycle.address ? *cycle.address : 0x0000;
switch(cycle.operation) { switch(cycle.operation) {
case CPU::Z80::PartialMachineCycle::ReadOpcode: case CPU::Z80::PartialMachineCycle::ReadOpcode:
@ -104,6 +120,8 @@ class ConcreteMachine:
vdp_->run_for(time_since_vdp_update_); vdp_->run_for(time_since_vdp_update_);
time_since_vdp_update_ = 0; time_since_vdp_update_ = 0;
*cycle.value = vdp_->get_register(address); *cycle.value = vdp_->get_register(address);
z80_.set_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
break; break;
case 0xa2: case 0xa2:
@ -124,6 +142,8 @@ class ConcreteMachine:
vdp_->run_for(time_since_vdp_update_); vdp_->run_for(time_since_vdp_update_);
time_since_vdp_update_ = 0; time_since_vdp_update_ = 0;
vdp_->set_register(address, *cycle.value); vdp_->set_register(address, *cycle.value);
z80_.set_interrupt_line(vdp_->get_interrupt_line());
time_until_interrupt_ = vdp_->get_time_until_interrupt();
break; break;
case 0xa0: case 0xa0:
@ -205,7 +225,7 @@ class ConcreteMachine:
uint8_t get_value(int port) { uint8_t get_value(int port) {
if(port == 1) { if(port == 1) {
printf("?? Read keyboard\n"); printf("?? Read keyboard\n");
} } else printf("What what?\n");
return 0xff; return 0xff;
} }
@ -229,6 +249,7 @@ class ConcreteMachine:
std::vector<uint8_t> basic_, main_; std::vector<uint8_t> basic_, main_;
HalfCycles time_since_vdp_update_; HalfCycles time_since_vdp_update_;
HalfCycles time_until_interrupt_;
}; };
} }