mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-28 21:49:27 +00:00
Merge pull request #1401 from TomHarte/OricVSync
Add the Oric's v-sync hardware hack.
This commit is contained in:
commit
60bd877ed9
@ -57,16 +57,18 @@ class Joystick: public Inputs::ConcreteJoystick {
|
||||
}) {}
|
||||
|
||||
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) {
|
||||
default: return;
|
||||
case Input::Right: APPLY(0x02); break;
|
||||
case Input::Left: APPLY(0x01); break;
|
||||
case Input::Down: APPLY(0x08); break;
|
||||
case Input::Up: APPLY(0x10); break;
|
||||
case Input::Fire: APPLY(0x20); break;
|
||||
case Input::Right: apply(0x02); break;
|
||||
case Input::Left: apply(0x01); break;
|
||||
case Input::Down: apply(0x08); break;
|
||||
case Input::Up: apply(0x10); break;
|
||||
case Input::Fire: apply(0x20); break;
|
||||
}
|
||||
#undef APPLY
|
||||
}
|
||||
|
||||
uint8_t get_state() {
|
||||
@ -574,7 +576,9 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
|
||||
break;
|
||||
}
|
||||
|
||||
video_ += Cycles(1);
|
||||
if(video_ += Cycles(1)) {
|
||||
set_via_port_b_input();
|
||||
}
|
||||
return Cycles(1);
|
||||
}
|
||||
|
||||
@ -619,9 +623,18 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
@ -795,24 +808,27 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
|
||||
|
||||
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) {
|
||||
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) {
|
||||
case Processor::WDC65816: DiskInterfaceSwitch(CPU::MOS6502Esque::Type::TWDC65816);
|
||||
case Processor::MOS6502: DiskInterfaceSwitch(CPU::MOS6502Esque::Type::T6502);
|
||||
case Processor::WDC65816: return machine<CPU::MOS6502Esque::Type::TWDC65816>(*oric_target, rom_fetcher);
|
||||
case Processor::MOS6502: return machine<CPU::MOS6502Esque::Type::T6502>(*oric_target, rom_fetcher);
|
||||
}
|
||||
|
||||
#undef DiskInterfaceSwitch
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ using namespace Oric;
|
||||
namespace {
|
||||
const unsigned int PAL50VSyncStartPosition = 256*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 PAL50Period = 312*64;
|
||||
const unsigned int PAL60Period = 262*64;
|
||||
const unsigned int PAL60Period = 264*64;
|
||||
}
|
||||
|
||||
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) {
|
||||
// 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.
|
||||
@ -123,7 +142,7 @@ void VideoOutput::run_for(const Cycles cycles) {
|
||||
int h_counter = counter_ & 63;
|
||||
int cycles_run_for = 0;
|
||||
|
||||
if(counter_ >= v_sync_start_position_ && counter_ < v_sync_end_position_) {
|
||||
if(vsync()) {
|
||||
// this is a sync line
|
||||
cycles_run_for = v_sync_end_position_ - counter_;
|
||||
clamp(crt_.output_sync((v_sync_end_position_ - v_sync_start_position_) * 6));
|
||||
|
@ -23,6 +23,9 @@ class VideoOutput {
|
||||
void set_colour_rom(const std::vector<uint8_t> &colour_rom);
|
||||
|
||||
void run_for(const Cycles cycles);
|
||||
Cycles next_sequence_point() const;
|
||||
|
||||
bool vsync();
|
||||
|
||||
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
|
||||
void set_display_type(Outputs::Display::DisplayType display_type);
|
||||
|
Loading…
Reference in New Issue
Block a user