mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
Rolls out JustInTime acting to the MSX and ColecoVision.
This commit is contained in:
parent
7dcad516bd
commit
f3dd4b028d
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "../../Configurable/StandardOptions.hpp"
|
#include "../../Configurable/StandardOptions.hpp"
|
||||||
#include "../../ClockReceiver/ForceInline.hpp"
|
#include "../../ClockReceiver/ForceInline.hpp"
|
||||||
|
#include "../../ClockReceiver/JustInTime.hpp"
|
||||||
|
|
||||||
#include "../../Outputs/Speaker/Implementation/CompoundSource.hpp"
|
#include "../../Outputs/Speaker/Implementation/CompoundSource.hpp"
|
||||||
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
@ -169,7 +170,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ColecoVisions have composite output only.
|
// ColecoVisions have composite output only.
|
||||||
vdp_.set_display_type(Outputs::Display::DisplayType::CompositeColour);
|
vdp_->set_display_type(Outputs::Display::DisplayType::CompositeColour);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ConcreteMachine() {
|
~ConcreteMachine() {
|
||||||
@ -181,11 +182,11 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
|
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
|
||||||
vdp_.set_scan_target(scan_target);
|
vdp_->set_scan_target(scan_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_display_type(Outputs::Display::DisplayType display_type) override {
|
void set_display_type(Outputs::Display::DisplayType display_type) override {
|
||||||
vdp_.set_display_type(display_type);
|
vdp_->set_display_type(display_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Outputs::Speaker::Speaker *get_speaker() override {
|
Outputs::Speaker::Speaker *get_speaker() override {
|
||||||
@ -210,7 +211,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
const HalfCycles length = cycle.length + penalty;
|
const HalfCycles length = cycle.length + penalty;
|
||||||
|
|
||||||
time_since_vdp_update_ += length;
|
vdp_ += length;
|
||||||
time_since_sn76489_update_ += length;
|
time_since_sn76489_update_ += length;
|
||||||
|
|
||||||
// Act only if necessary.
|
// Act only if necessary.
|
||||||
@ -255,10 +256,9 @@ class ConcreteMachine:
|
|||||||
case CPU::Z80::PartialMachineCycle::Input:
|
case CPU::Z80::PartialMachineCycle::Input:
|
||||||
switch((address >> 5) & 7) {
|
switch((address >> 5) & 7) {
|
||||||
case 5:
|
case 5:
|
||||||
update_video();
|
*cycle.value = vdp_->get_register(address);
|
||||||
*cycle.value = vdp_.get_register(address);
|
z80_.set_non_maskable_interrupt_line(vdp_->get_interrupt_line());
|
||||||
z80_.set_non_maskable_interrupt_line(vdp_.get_interrupt_line());
|
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
||||||
time_until_interrupt_ = vdp_.get_time_until_interrupt();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: {
|
case 7: {
|
||||||
@ -299,10 +299,9 @@ class ConcreteMachine:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
update_video();
|
vdp_->set_register(address, *cycle.value);
|
||||||
vdp_.set_register(address, *cycle.value);
|
z80_.set_non_maskable_interrupt_line(vdp_->get_interrupt_line());
|
||||||
z80_.set_non_maskable_interrupt_line(vdp_.get_interrupt_line());
|
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
||||||
time_until_interrupt_ = vdp_.get_time_until_interrupt();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
@ -354,7 +353,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
update_video();
|
vdp_.flush();
|
||||||
update_audio();
|
update_audio();
|
||||||
audio_queue_.perform();
|
audio_queue_.perform();
|
||||||
}
|
}
|
||||||
@ -396,12 +395,9 @@ class ConcreteMachine:
|
|||||||
inline void update_audio() {
|
inline void update_audio() {
|
||||||
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
|
speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
|
||||||
}
|
}
|
||||||
inline void update_video() {
|
|
||||||
vdp_.run_for(time_since_vdp_update_.flush<HalfCycles>());
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
|
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
|
||||||
TI::TMS::TMS9918 vdp_;
|
JustInTimeActor<TI::TMS::TMS9918, HalfCycles> vdp_;
|
||||||
|
|
||||||
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
||||||
TI::SN76489 sn76489_;
|
TI::SN76489 sn76489_;
|
||||||
@ -424,7 +420,6 @@ class ConcreteMachine:
|
|||||||
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
|
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
|
||||||
bool joysticks_in_keypad_mode_ = false;
|
bool joysticks_in_keypad_mode_ = false;
|
||||||
|
|
||||||
HalfCycles time_since_vdp_update_;
|
|
||||||
HalfCycles time_since_sn76489_update_;
|
HalfCycles time_since_sn76489_update_;
|
||||||
HalfCycles time_until_interrupt_;
|
HalfCycles time_until_interrupt_;
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
#include "../../Configurable/StandardOptions.hpp"
|
#include "../../Configurable/StandardOptions.hpp"
|
||||||
#include "../../ClockReceiver/ForceInline.hpp"
|
#include "../../ClockReceiver/ForceInline.hpp"
|
||||||
|
#include "../../ClockReceiver/JustInTime.hpp"
|
||||||
|
|
||||||
#include "../../Analyser/Static/MSX/Target.hpp"
|
#include "../../Analyser/Static/MSX/Target.hpp"
|
||||||
|
|
||||||
@ -187,7 +188,7 @@ class ConcreteMachine:
|
|||||||
switch(target.region) {
|
switch(target.region) {
|
||||||
case Target::Region::Japan:
|
case Target::Region::Japan:
|
||||||
required_roms.emplace_back(machine_name, "a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390);
|
required_roms.emplace_back(machine_name, "a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390);
|
||||||
vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC);
|
vdp_->set_tv_standard(TI::TMS::TVStandard::NTSC);
|
||||||
|
|
||||||
is_ntsc = true;
|
is_ntsc = true;
|
||||||
character_generator = 0;
|
character_generator = 0;
|
||||||
@ -195,7 +196,7 @@ class ConcreteMachine:
|
|||||||
break;
|
break;
|
||||||
case Target::Region::USA:
|
case Target::Region::USA:
|
||||||
required_roms.emplace_back(machine_name, "an American MSX BIOS", "msx-american.rom", 32*1024, 0);
|
required_roms.emplace_back(machine_name, "an American MSX BIOS", "msx-american.rom", 32*1024, 0);
|
||||||
vdp_.set_tv_standard(TI::TMS::TVStandard::NTSC);
|
vdp_->set_tv_standard(TI::TMS::TVStandard::NTSC);
|
||||||
|
|
||||||
is_ntsc = true;
|
is_ntsc = true;
|
||||||
character_generator = 1;
|
character_generator = 1;
|
||||||
@ -203,7 +204,7 @@ class ConcreteMachine:
|
|||||||
break;
|
break;
|
||||||
case Target::Region::Europe:
|
case Target::Region::Europe:
|
||||||
required_roms.emplace_back(machine_name, "a European MSX BIOS", "msx-european.rom", 32*1024, 0);
|
required_roms.emplace_back(machine_name, "a European MSX BIOS", "msx-european.rom", 32*1024, 0);
|
||||||
vdp_.set_tv_standard(TI::TMS::TVStandard::PAL);
|
vdp_->set_tv_standard(TI::TMS::TVStandard::PAL);
|
||||||
|
|
||||||
is_ntsc = false;
|
is_ntsc = false;
|
||||||
character_generator = 1;
|
character_generator = 1;
|
||||||
@ -278,11 +279,11 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
|
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
|
||||||
vdp_.set_scan_target(scan_target);
|
vdp_->set_scan_target(scan_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_display_type(Outputs::Display::DisplayType display_type) override {
|
void set_display_type(Outputs::Display::DisplayType display_type) override {
|
||||||
vdp_.set_display_type(display_type);
|
vdp_->set_display_type(display_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Outputs::Speaker::Speaker *get_speaker() override {
|
Outputs::Speaker::Speaker *get_speaker() override {
|
||||||
@ -411,7 +412,7 @@ class ConcreteMachine:
|
|||||||
// but otherwise runs without pause.
|
// but otherwise runs without pause.
|
||||||
const HalfCycles addition((cycle.operation == CPU::Z80::PartialMachineCycle::ReadOpcode) ? 2 : 0);
|
const HalfCycles addition((cycle.operation == CPU::Z80::PartialMachineCycle::ReadOpcode) ? 2 : 0);
|
||||||
const HalfCycles total_length = addition + cycle.length;
|
const HalfCycles total_length = addition + cycle.length;
|
||||||
time_since_vdp_update_ += total_length;
|
vdp_ += total_length;
|
||||||
time_since_ay_update_ += total_length;
|
time_since_ay_update_ += total_length;
|
||||||
memory_slots_[0].cycles_since_update += total_length;
|
memory_slots_[0].cycles_since_update += total_length;
|
||||||
memory_slots_[1].cycles_since_update += total_length;
|
memory_slots_[1].cycles_since_update += total_length;
|
||||||
@ -508,10 +509,9 @@ class ConcreteMachine:
|
|||||||
case CPU::Z80::PartialMachineCycle::Input:
|
case CPU::Z80::PartialMachineCycle::Input:
|
||||||
switch(address & 0xff) {
|
switch(address & 0xff) {
|
||||||
case 0x98: case 0x99:
|
case 0x98: case 0x99:
|
||||||
vdp_.run_for(time_since_vdp_update_.flush<HalfCycles>());
|
*cycle.value = vdp_->get_register(address);
|
||||||
*cycle.value = vdp_.get_register(address);
|
z80_.set_interrupt_line(vdp_->get_interrupt_line());
|
||||||
z80_.set_interrupt_line(vdp_.get_interrupt_line());
|
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
||||||
time_until_interrupt_ = vdp_.get_time_until_interrupt();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa2:
|
case 0xa2:
|
||||||
@ -536,10 +536,9 @@ class ConcreteMachine:
|
|||||||
const int port = address & 0xff;
|
const int port = address & 0xff;
|
||||||
switch(port) {
|
switch(port) {
|
||||||
case 0x98: case 0x99:
|
case 0x98: case 0x99:
|
||||||
vdp_.run_for(time_since_vdp_update_.flush<HalfCycles>());
|
vdp_->set_register(address, *cycle.value);
|
||||||
vdp_.set_register(address, *cycle.value);
|
z80_.set_interrupt_line(vdp_->get_interrupt_line());
|
||||||
z80_.set_interrupt_line(vdp_.get_interrupt_line());
|
time_until_interrupt_ = vdp_->get_time_until_interrupt();
|
||||||
time_until_interrupt_ = vdp_.get_time_until_interrupt();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa0: case 0xa1:
|
case 0xa0: case 0xa1:
|
||||||
@ -612,7 +611,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
vdp_.run_for(time_since_vdp_update_.flush<HalfCycles>());
|
vdp_.flush();
|
||||||
update_audio();
|
update_audio();
|
||||||
audio_queue_.perform();
|
audio_queue_.perform();
|
||||||
}
|
}
|
||||||
@ -753,7 +752,7 @@ class ConcreteMachine:
|
|||||||
};
|
};
|
||||||
|
|
||||||
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
|
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
|
||||||
TI::TMS::TMS9918 vdp_;
|
JustInTimeActor<TI::TMS::TMS9918, HalfCycles> vdp_;
|
||||||
Intel::i8255::i8255<i8255PortHandler> i8255_;
|
Intel::i8255::i8255<i8255PortHandler> i8255_;
|
||||||
|
|
||||||
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
||||||
@ -797,7 +796,6 @@ class ConcreteMachine:
|
|||||||
uint8_t scratch_[8192];
|
uint8_t scratch_[8192];
|
||||||
uint8_t unpopulated_[8192];
|
uint8_t unpopulated_[8192];
|
||||||
|
|
||||||
HalfCycles time_since_vdp_update_;
|
|
||||||
HalfCycles time_since_ay_update_;
|
HalfCycles time_since_ay_update_;
|
||||||
HalfCycles time_until_interrupt_;
|
HalfCycles time_until_interrupt_;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user