1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 01:32:55 +00:00

Merge pull request #1401 from TomHarte/OricVSync

Add the Oric's v-sync hardware hack.
This commit is contained in:
Thomas Harte 2024-09-10 21:18:03 -04:00 committed by GitHub
commit 60bd877ed9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 64 additions and 26 deletions

View File

@ -57,16 +57,18 @@ class Joystick: public Inputs::ConcreteJoystick {
}) {} }) {}
void did_set_input(const Input &digital_input, bool is_active) final { void did_set_input(const Input &digital_input, bool is_active) final {
#define APPLY(b) if(is_active) state_ &= ~b; else state_ |= b; const auto apply = [&](uint8_t bit) {
if(is_active) state_ &= ~bit; else state_ |= bit;
};
switch(digital_input.type) { switch(digital_input.type) {
default: return; default: return;
case Input::Right: APPLY(0x02); break; case Input::Right: apply(0x02); break;
case Input::Left: APPLY(0x01); break; case Input::Left: apply(0x01); break;
case Input::Down: APPLY(0x08); break; case Input::Down: apply(0x08); break;
case Input::Up: APPLY(0x10); break; case Input::Up: apply(0x10); break;
case Input::Fire: APPLY(0x20); break; case Input::Fire: apply(0x20); break;
} }
#undef APPLY
} }
uint8_t get_state() { uint8_t get_state() {
@ -574,7 +576,9 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
break; break;
} }
video_ += Cycles(1); if(video_ += Cycles(1)) {
set_via_port_b_input();
}
return Cycles(1); return Cycles(1);
} }
@ -619,9 +623,18 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
} }
// to satisfy Storage::Tape::BinaryTapePlayer::Delegate // to satisfy Storage::Tape::BinaryTapePlayer::Delegate
void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) final { void tape_did_change_input(Storage::Tape::BinaryTapePlayer *) final {
set_via_port_b_input();
}
void set_via_port_b_input() {
// set CB1 // set CB1
via_.set_control_line_input(MOS::MOS6522::Port::B, MOS::MOS6522::Line::One, !tape_player->get_input()); via_.set_control_line_input(
MOS::MOS6522::Port::B, MOS::MOS6522::Line::One,
tape_player_.get_motor_control() ?
!tape_player_.get_input() :
!video_->vsync()
);
} }
// for Utility::TypeRecipient::Delegate // for Utility::TypeRecipient::Delegate
@ -795,24 +808,27 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
using namespace Oric; using namespace Oric;
namespace {
template <CPU::MOS6502Esque::Type processor> std::unique_ptr<Machine> machine(const Analyser::Static::Oric::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) {
switch(target.disk_interface) {
default: return std::make_unique<ConcreteMachine<DiskInterface::None, processor>>(target, rom_fetcher);
case DiskInterface::Microdisc: return std::make_unique<ConcreteMachine<DiskInterface::Microdisc, processor>>(target, rom_fetcher);
case DiskInterface::Pravetz: return std::make_unique<ConcreteMachine<DiskInterface::Pravetz, processor>>(target, rom_fetcher);
case DiskInterface::Jasmin: return std::make_unique<ConcreteMachine<DiskInterface::Jasmin, processor>>(target, rom_fetcher);
case DiskInterface::BD500: return std::make_unique<ConcreteMachine<DiskInterface::BD500, processor>>(target, rom_fetcher);
}
}
}
std::unique_ptr<Machine> Machine::Oric(const Analyser::Static::Target *target_hint, const ROMMachine::ROMFetcher &rom_fetcher) { std::unique_ptr<Machine> Machine::Oric(const Analyser::Static::Target *target_hint, const ROMMachine::ROMFetcher &rom_fetcher) {
auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target_hint); auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target_hint);
#define DiskInterfaceSwitch(processor) \
switch(oric_target->disk_interface) { \
default: return std::make_unique<ConcreteMachine<DiskInterface::None, processor>>(*oric_target, rom_fetcher); \
case DiskInterface::Microdisc: return std::make_unique<ConcreteMachine<DiskInterface::Microdisc, processor>>(*oric_target, rom_fetcher); \
case DiskInterface::Pravetz: return std::make_unique<ConcreteMachine<DiskInterface::Pravetz, processor>>(*oric_target, rom_fetcher); \
case DiskInterface::Jasmin: return std::make_unique<ConcreteMachine<DiskInterface::Jasmin, processor>>(*oric_target, rom_fetcher); \
case DiskInterface::BD500: return std::make_unique<ConcreteMachine<DiskInterface::BD500, processor>>(*oric_target, rom_fetcher); \
}
switch(oric_target->processor) { switch(oric_target->processor) {
case Processor::WDC65816: DiskInterfaceSwitch(CPU::MOS6502Esque::Type::TWDC65816); case Processor::WDC65816: return machine<CPU::MOS6502Esque::Type::TWDC65816>(*oric_target, rom_fetcher);
case Processor::MOS6502: DiskInterfaceSwitch(CPU::MOS6502Esque::Type::T6502); case Processor::MOS6502: return machine<CPU::MOS6502Esque::Type::T6502>(*oric_target, rom_fetcher);
} }
#undef DiskInterfaceSwitch
return nullptr; return nullptr;
} }

View File

@ -17,10 +17,10 @@ using namespace Oric;
namespace { namespace {
const unsigned int PAL50VSyncStartPosition = 256*64; const unsigned int PAL50VSyncStartPosition = 256*64;
const unsigned int PAL60VSyncStartPosition = 234*64; const unsigned int PAL60VSyncStartPosition = 234*64;
const unsigned int PAL50VSyncEndPosition = 259*64; const unsigned int PAL50VSyncEndPosition = 259*64; // 19966
const unsigned int PAL60VSyncEndPosition = 238*64; const unsigned int PAL60VSyncEndPosition = 238*64;
const unsigned int PAL50Period = 312*64; const unsigned int PAL50Period = 312*64;
const unsigned int PAL60Period = 262*64; const unsigned int PAL60Period = 264*64;
} }
VideoOutput::VideoOutput(uint8_t *memory) : VideoOutput::VideoOutput(uint8_t *memory) :
@ -111,6 +111,25 @@ void VideoOutput::set_colour_rom(const std::vector<uint8_t> &rom) {
// } // }
} }
bool VideoOutput::vsync() {
return counter_ >= v_sync_start_position_ && counter_ < v_sync_end_position_;
}
Cycles VideoOutput::next_sequence_point() const {
if(counter_ < v_sync_start_position_) {
return Cycles(v_sync_start_position_ - counter_);
} else if(counter_ < v_sync_end_position_) {
return Cycles(v_sync_end_position_ - counter_);
} else {
// After vsync the length of the next frame is baked in, so this is safe
// (but should probably be factored out).
return Cycles(
counter_period_ + static_cast<int>(next_frame_is_sixty_hertz_ ? PAL60VSyncStartPosition : PAL50VSyncStartPosition)
- counter_
);
}
}
void VideoOutput::run_for(const Cycles cycles) { void VideoOutput::run_for(const Cycles cycles) {
// Horizontal: 0-39: pixels; otherwise blank; 48-53 sync, 54-56 colour burst. // Horizontal: 0-39: pixels; otherwise blank; 48-53 sync, 54-56 colour burst.
// Vertical: 0-223: pixels; otherwise blank; 256-259 (50Hz) or 234-238 (60Hz) sync. // Vertical: 0-223: pixels; otherwise blank; 256-259 (50Hz) or 234-238 (60Hz) sync.
@ -123,7 +142,7 @@ void VideoOutput::run_for(const Cycles cycles) {
int h_counter = counter_ & 63; int h_counter = counter_ & 63;
int cycles_run_for = 0; int cycles_run_for = 0;
if(counter_ >= v_sync_start_position_ && counter_ < v_sync_end_position_) { if(vsync()) {
// this is a sync line // this is a sync line
cycles_run_for = v_sync_end_position_ - counter_; cycles_run_for = v_sync_end_position_ - counter_;
clamp(crt_.output_sync((v_sync_end_position_ - v_sync_start_position_) * 6)); clamp(crt_.output_sync((v_sync_end_position_ - v_sync_start_position_) * 6));

View File

@ -23,6 +23,9 @@ class VideoOutput {
void set_colour_rom(const std::vector<uint8_t> &colour_rom); void set_colour_rom(const std::vector<uint8_t> &colour_rom);
void run_for(const Cycles cycles); void run_for(const Cycles cycles);
Cycles next_sequence_point() const;
bool vsync();
void set_scan_target(Outputs::Display::ScanTarget *scan_target); void set_scan_target(Outputs::Display::ScanTarget *scan_target);
void set_display_type(Outputs::Display::DisplayType display_type); void set_display_type(Outputs::Display::DisplayType display_type);