mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 03:32:01 +00:00
Merge pull request #800 from TomHarte/QtProject
UNREADY. Adds a provisional Qt target.
This commit is contained in:
commit
2230ac6c38
@ -24,13 +24,13 @@ namespace Activity {
|
||||
class Observer {
|
||||
public:
|
||||
/// Announces to the receiver that there is an LED of name @c name.
|
||||
virtual void register_led(const std::string &name) {}
|
||||
virtual void register_led([[maybe_unused]] const std::string &name) {}
|
||||
|
||||
/// Announces to the receiver that there is a drive of name @c name.
|
||||
virtual void register_drive(const std::string &name) {}
|
||||
virtual void register_drive([[maybe_unused]] const std::string &name) {}
|
||||
|
||||
/// Informs the receiver of the new state of the LED with name @c name.
|
||||
virtual void set_led_status(const std::string &name, bool lit) {}
|
||||
virtual void set_led_status([[maybe_unused]] const std::string &name, [[maybe_unused]] bool lit) {}
|
||||
|
||||
enum class DriveEvent {
|
||||
StepNormal,
|
||||
@ -39,10 +39,10 @@ class Observer {
|
||||
};
|
||||
|
||||
/// Informs the receiver that the named event just occurred for the drive with name @c name.
|
||||
virtual void announce_drive_event(const std::string &name, DriveEvent event) {}
|
||||
virtual void announce_drive_event([[maybe_unused]] const std::string &name, [[maybe_unused]] DriveEvent event) {}
|
||||
|
||||
/// Informs the receiver of the motor-on status of the drive with name @c name.
|
||||
virtual void set_drive_motor_status(const std::string &name, bool is_on) {}
|
||||
virtual void set_drive_motor_status([[maybe_unused]] const std::string &name, [[maybe_unused]] bool is_on) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ void MultiInterface<MachineType>::perform_parallel(const std::function<void(Mach
|
||||
std::condition_variable condition;
|
||||
std::mutex mutex;
|
||||
{
|
||||
std::lock_guard<decltype(machines_mutex_)> machines_lock(machines_mutex_);
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
std::lock_guard lock(mutex);
|
||||
outstanding_machines = machines_.size();
|
||||
|
||||
for(std::size_t index = 0; index < machines_.size(); ++index) {
|
||||
@ -32,20 +32,20 @@ void MultiInterface<MachineType>::perform_parallel(const std::function<void(Mach
|
||||
queues_[index].enqueue([&mutex, &condition, machine, function, &outstanding_machines]() {
|
||||
if(machine) function(machine);
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::lock_guard lock(mutex);
|
||||
outstanding_machines--;
|
||||
condition.notify_all();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
std::unique_lock lock(mutex);
|
||||
condition.wait(lock, [&outstanding_machines] { return !outstanding_machines; });
|
||||
}
|
||||
|
||||
template <typename MachineType>
|
||||
void MultiInterface<MachineType>::perform_serial(const std::function<void(MachineType *)> &function) {
|
||||
std::lock_guard<decltype(machines_mutex_)> machines_lock(machines_mutex_);
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
for(const auto &machine: machines_) {
|
||||
const auto typed_machine = ::Machine::get<MachineType>(*machine.get());
|
||||
if(typed_machine) function(typed_machine);
|
||||
@ -56,13 +56,13 @@ void MultiInterface<MachineType>::perform_serial(const std::function<void(Machin
|
||||
void MultiScanProducer::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
|
||||
scan_target_ = scan_target;
|
||||
|
||||
std::lock_guard<decltype(machines_mutex_)> machines_lock(machines_mutex_);
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
const auto machine = machines_.front()->scan_producer();
|
||||
if(machine) machine->set_scan_target(scan_target);
|
||||
}
|
||||
|
||||
Outputs::Display::ScanStatus MultiScanProducer::get_scan_status() const {
|
||||
std::lock_guard<decltype(machines_mutex_)> machines_lock(machines_mutex_);
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
const auto machine = machines_.front()->scan_producer();
|
||||
if(machine) return machine->get_scan_status();
|
||||
return Outputs::Display::ScanStatus();
|
||||
@ -74,7 +74,7 @@ void MultiScanProducer::did_change_machine_order() {
|
||||
perform_serial([](MachineTypes::ScanProducer *machine) {
|
||||
machine->set_scan_target(nullptr);
|
||||
});
|
||||
std::lock_guard<decltype(machines_mutex_)> machines_lock(machines_mutex_);
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
const auto machine = machines_.front()->scan_producer();
|
||||
if(machine) machine->set_scan_target(scan_target_);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class MultiTimedMachine: public MultiInterface<MachineTypes::TimedMachine>, publ
|
||||
void run_for(Time::Seconds duration) final;
|
||||
|
||||
private:
|
||||
void run_for(const Cycles cycles) final {}
|
||||
void run_for(const Cycles) final {}
|
||||
Delegate *delegate_ = nullptr;
|
||||
};
|
||||
|
||||
|
@ -67,7 +67,7 @@ void MultiSpeaker::set_delegate(Outputs::Speaker::Speaker::Delegate *delegate) {
|
||||
void MultiSpeaker::speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) {
|
||||
if(!delegate_) return;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
||||
std::lock_guard lock_guard(front_speaker_mutex_);
|
||||
if(speaker != front_speaker_) return;
|
||||
}
|
||||
did_complete_samples(this, buffer, stereo_output_);
|
||||
@ -76,7 +76,7 @@ void MultiSpeaker::speaker_did_complete_samples(Speaker *speaker, const std::vec
|
||||
void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {
|
||||
if(!delegate_) return;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
||||
std::lock_guard lock_guard(front_speaker_mutex_);
|
||||
if(speaker != front_speaker_) return;
|
||||
}
|
||||
delegate_->speaker_did_change_input_clock(this);
|
||||
@ -84,7 +84,7 @@ void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {
|
||||
|
||||
void MultiSpeaker::set_new_front_machine(::Machine::DynamicMachine *machine) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
||||
std::lock_guard lock_guard(front_speaker_mutex_);
|
||||
front_speaker_ = machine->audio_producer()->get_speaker();
|
||||
}
|
||||
if(delegate_) {
|
||||
|
@ -60,7 +60,7 @@ bool MultiMachine::would_collapse(const std::vector<std::unique_ptr<DynamicMachi
|
||||
}
|
||||
|
||||
void MultiMachine::did_run_machines(MultiTimedMachine *) {
|
||||
std::lock_guard<decltype(machines_mutex_)> machines_lock(machines_mutex_);
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
#ifndef NDEBUG
|
||||
for(const auto &machine: machines_) {
|
||||
auto timed_machine = machine->timed_machine();
|
||||
|
@ -57,7 +57,7 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return acorn_cartridges;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5; // TODO: a proper estimation
|
||||
target->has_dfs = false;
|
||||
|
@ -179,7 +179,7 @@ static bool CheckBootSector(const std::shared_ptr<Storage::Disk::Disk> &disk, co
|
||||
return false;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
TargetList destination;
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AppleII::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::AppleII::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->media = media;
|
||||
|
||||
|
@ -88,7 +88,7 @@ static void DeterminePagingFor8kCartridge(Target &target, const Storage::Cartrid
|
||||
else if(tigervision_access_count > atari_access_count) target.paging_model = Target::PagingModel::Tigervision;
|
||||
}
|
||||
|
||||
static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
// Make an assumption that this is the Atari paging model.
|
||||
target.paging_model = Target::PagingModel::Atari16k;
|
||||
|
||||
@ -108,7 +108,7 @@ static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartri
|
||||
if(mnetwork_access_count > atari_access_count) target.paging_model = Target::PagingModel::MNetwork;
|
||||
}
|
||||
|
||||
static void DeterminePagingFor64kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
static void DeterminePagingFor64kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
// Make an assumption that this is a Tigervision if there is a write to 3F.
|
||||
target.paging_model =
|
||||
(disassembly.external_stores.find(0x3f) != disassembly.external_stores.end()) ?
|
||||
@ -177,7 +177,7 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
|
||||
}
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Atari2600::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Atari2600::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
// TODO: sanity checking; is this image really for an Atari 2600?
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AtariST::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::AtariST::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
// This analyser can comprehend disks and mass-storage devices only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
|
@ -52,7 +52,7 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return coleco_cartridges;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Coleco::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Coleco::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
TargetList targets;
|
||||
auto target = std::make_unique<Target>(Machine::ColecoVision);
|
||||
target->confidence = 1.0f - 1.0f / 32768.0f;
|
||||
|
@ -42,7 +42,7 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return vic20_cartridges;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
|
||||
TargetList destination;
|
||||
|
||||
auto target = std::make_unique<Target>();
|
||||
@ -94,6 +94,7 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
||||
switch(files.front().starting_address) {
|
||||
default:
|
||||
LOG("Unrecognised loading address for Commodore program: " << PADHEX(4) << files.front().starting_address);
|
||||
[[fallthrough]];
|
||||
case 0x1001:
|
||||
memory_model = Target::MemoryModel::Unexpanded;
|
||||
break;
|
||||
|
@ -31,7 +31,7 @@ Analyser::Static::Target *AppleTarget(const Storage::Encodings::AppleGCR::Sector
|
||||
return target;
|
||||
}
|
||||
|
||||
Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector *sector_zero) {
|
||||
Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector *) {
|
||||
using Target = Analyser::Static::Oric::Target;
|
||||
auto *const target = new Target;
|
||||
target->rom = Target::ROM::Pravetz;
|
||||
@ -42,7 +42,7 @@ Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector
|
||||
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
// This analyser can comprehend disks only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
|
@ -260,7 +260,7 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
|
||||
return targets;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
TargetList destination;
|
||||
|
||||
// Append targets for any cartridges that look correct.
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
// This analyser can comprehend disks and mass-storage devices only.
|
||||
if(media.disks.empty() && media.mass_storage_devices.empty()) return {};
|
||||
|
||||
|
@ -145,7 +145,7 @@ bool is_bd500(Storage::Encodings::MFM::Parser &parser) {
|
||||
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
|
||||
if(media.cartridges.empty())
|
||||
return {};
|
||||
|
||||
|
@ -28,7 +28,7 @@ static std::vector<Storage::Data::ZX8081::File> GetFiles(const std::shared_ptr<S
|
||||
return files;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::ZX8081::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::ZX8081::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType potential_platforms) {
|
||||
TargetList destination;
|
||||
if(!media.tapes.empty()) {
|
||||
std::vector<Storage::Data::ZX8081::File> files = GetFiles(media.tapes.front());
|
||||
|
@ -176,7 +176,6 @@ class Cycles: public WrappedInt<Cycles> {
|
||||
public:
|
||||
forceinline constexpr Cycles(IntType l) noexcept : WrappedInt<Cycles>(l) {}
|
||||
forceinline constexpr Cycles() noexcept : WrappedInt<Cycles>() {}
|
||||
forceinline constexpr Cycles(const Cycles &cycles) noexcept : WrappedInt<Cycles>(cycles.length_) {}
|
||||
|
||||
private:
|
||||
friend WrappedInt;
|
||||
@ -198,7 +197,6 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
||||
forceinline constexpr HalfCycles() noexcept : WrappedInt<HalfCycles>() {}
|
||||
|
||||
forceinline constexpr HalfCycles(const Cycles &cycles) noexcept : WrappedInt<HalfCycles>(cycles.as_integral() * 2) {}
|
||||
forceinline constexpr HalfCycles(const HalfCycles &half_cycles) noexcept : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
||||
|
||||
/// @returns The number of whole cycles completely covered by this span of half cycles.
|
||||
forceinline constexpr Cycles cycles() const {
|
||||
|
151
ClockReceiver/VSyncPredictor.hpp
Normal file
151
ClockReceiver/VSyncPredictor.hpp
Normal file
@ -0,0 +1,151 @@
|
||||
//
|
||||
// VSyncPredictor.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 14/06/2020.
|
||||
// Copyright © 2020 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef VSyncPredictor_hpp
|
||||
#define VSyncPredictor_hpp
|
||||
|
||||
#include "TimeTypes.hpp"
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
namespace Time {
|
||||
|
||||
/*!
|
||||
For platforms that provide no avenue into vsync tracking other than block-until-sync,
|
||||
this class tracks: (i) how long frame draw takes; (ii) the apparent frame period; and
|
||||
(iii) optionally, timer jitter; in order to suggest when you should next start drawing.
|
||||
*/
|
||||
class VSyncPredictor {
|
||||
public:
|
||||
/*!
|
||||
Announces to the predictor that the work of producing an output frame has begun.
|
||||
*/
|
||||
void begin_redraw() {
|
||||
redraw_begin_time_ = nanos_now();
|
||||
}
|
||||
|
||||
/*!
|
||||
Announces to the predictor that the work of producing an output frame has ended;
|
||||
the predictor will use the amount of time between each begin/end pair to modify
|
||||
its expectations as to how long it takes to draw a frame.
|
||||
*/
|
||||
void end_redraw() {
|
||||
redraw_period_.post(nanos_now() - redraw_begin_time_);
|
||||
}
|
||||
|
||||
/*!
|
||||
Informs the predictor that a block-on-vsync has just ended, i.e. that the moment this
|
||||
machine calls retrace is now. The predictor uses these notifications to estimate output
|
||||
frame rate.
|
||||
*/
|
||||
void announce_vsync() {
|
||||
const auto now = nanos_now();
|
||||
|
||||
if(last_vsync_) {
|
||||
last_vsync_ += frame_duration_;
|
||||
vsync_jitter_.post(last_vsync_ - now);
|
||||
last_vsync_ = (last_vsync_ + now) >> 1;
|
||||
} else {
|
||||
last_vsync_ = now;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the frame rate for the target display.
|
||||
*/
|
||||
void set_frame_rate(float rate) {
|
||||
frame_duration_ = Nanos(1'000'000'000.0f / rate);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a record of how much jitter was experienced in scheduling; these values will be
|
||||
factored into the @c suggested_draw_time if supplied.
|
||||
|
||||
A positive number means the timer occurred late. A negative number means it occurred early.
|
||||
*/
|
||||
void add_timer_jitter(Time::Nanos jitter) {
|
||||
timer_jitter_.post(jitter);
|
||||
}
|
||||
|
||||
/*!
|
||||
Announces to the vsync predictor that output is now paused. This ends frame period
|
||||
calculations until the next announce_vsync() restarts frame-length counting.
|
||||
*/
|
||||
void pause() {
|
||||
last_vsync_ = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@return The time at which redrawing should begin, given the predicted frame period, how
|
||||
long it appears to take to draw a frame and how much jitter there is in scheduling
|
||||
(if those figures are being supplied).
|
||||
*/
|
||||
Nanos suggested_draw_time() {
|
||||
const auto mean = redraw_period_.mean() - timer_jitter_.mean() - vsync_jitter_.mean();
|
||||
const auto variance = redraw_period_.variance() + timer_jitter_.variance() + vsync_jitter_.variance();
|
||||
|
||||
// Permit three standard deviations from the mean, to cover 99.9% of cases.
|
||||
const auto period = mean - Nanos(3.0f * sqrt(float(variance)));
|
||||
|
||||
assert(abs(period) < 10'000'000'000);
|
||||
|
||||
return last_vsync_ + period;
|
||||
}
|
||||
|
||||
private:
|
||||
class VarianceCollector {
|
||||
public:
|
||||
VarianceCollector(Time::Nanos default_value) {
|
||||
sum_ = default_value * 128;
|
||||
for(int c = 0; c < 128; ++c) {
|
||||
history_[c] = default_value;
|
||||
}
|
||||
}
|
||||
|
||||
void post(Time::Nanos value) {
|
||||
assert(abs(value) < 10'000'000'000); // 10 seconds is a very liberal maximum.
|
||||
sum_ -= history_[write_pointer_];
|
||||
sum_ += value;
|
||||
history_[write_pointer_] = value;
|
||||
write_pointer_ = (write_pointer_ + 1) & 127;
|
||||
}
|
||||
|
||||
Time::Nanos mean() {
|
||||
return sum_ / 128;
|
||||
}
|
||||
|
||||
Time::Nanos variance() {
|
||||
// I haven't yet come up with a better solution that calculating this
|
||||
// in whole every time, given the way that the mean mutates.
|
||||
Time::Nanos variance = 0;
|
||||
for(int c = 0; c < 128; ++c) {
|
||||
const auto difference = ((history_[c] * 128) - sum_) / 128;
|
||||
variance += (difference * difference);
|
||||
}
|
||||
return variance / 128;
|
||||
}
|
||||
|
||||
private:
|
||||
Time::Nanos sum_;
|
||||
Time::Nanos history_[128];
|
||||
size_t write_pointer_ = 0;
|
||||
};
|
||||
|
||||
Nanos redraw_begin_time_ = 0;
|
||||
Nanos last_vsync_ = 0;
|
||||
Nanos frame_duration_ = 1'000'000'000 / 60;
|
||||
|
||||
VarianceCollector vsync_jitter_{0};
|
||||
VarianceCollector redraw_period_{1'000'000'000 / 60}; // A less convincing first guess.
|
||||
VarianceCollector timer_jitter_{0}; // Seed at 0 in case this feature isn't used by the owner.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* VSyncPredictor_hpp */
|
@ -498,7 +498,7 @@ void WD1770::posit_event(int new_event_type) {
|
||||
|
||||
if(get_crc_generator().get_value()) {
|
||||
LOG("CRC error; terminating");
|
||||
update_status([this] (Status &status) {
|
||||
update_status([] (Status &status) {
|
||||
status.crc_error = true;
|
||||
});
|
||||
goto wait_for_command;
|
||||
@ -816,8 +816,8 @@ void WD1770::update_status(std::function<void(Status &)> updater) {
|
||||
if(status_.busy != old_status.busy) update_clocking_observer();
|
||||
}
|
||||
|
||||
void WD1770::set_head_load_request(bool head_load) {}
|
||||
void WD1770::set_motor_on(bool motor_on) {}
|
||||
void WD1770::set_head_load_request(bool) {}
|
||||
void WD1770::set_motor_on(bool) {}
|
||||
|
||||
void WD1770::set_head_loaded(bool head_loaded) {
|
||||
head_is_loaded_ = head_loaded;
|
||||
|
@ -31,6 +31,7 @@ class WD1770: public Storage::Disk::MFMController {
|
||||
@param p The type of controller to emulate.
|
||||
*/
|
||||
WD1770(Personality p);
|
||||
virtual ~WD1770() {}
|
||||
|
||||
/// Sets the value of the double-density input; when @c is_double_density is @c true, reads and writes double-density format data.
|
||||
using Storage::Disk::MFMController::set_is_double_density;
|
||||
|
@ -18,9 +18,14 @@ NCR5380::NCR5380(SCSI::Bus &bus, int clock_rate) :
|
||||
clock_rate_(clock_rate) {
|
||||
device_id_ = bus_.add_device();
|
||||
bus_.add_observer(this);
|
||||
|
||||
// TODO: use clock rate and expected phase. This implementation currently
|
||||
// provides only CPU-driven polling behaviour.
|
||||
(void)clock_rate_;
|
||||
(void)expected_phase_;
|
||||
}
|
||||
|
||||
void NCR5380::write(int address, uint8_t value, bool dma_acknowledge) {
|
||||
void NCR5380::write(int address, uint8_t value, bool) {
|
||||
switch(address & 7) {
|
||||
case 0:
|
||||
// LOG("[SCSI 0] Set current SCSI bus state to " << PADHEX(2) << int(value));
|
||||
@ -128,7 +133,7 @@ void NCR5380::write(int address, uint8_t value, bool dma_acknowledge) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t NCR5380::read(int address, bool dma_acknowledge) {
|
||||
uint8_t NCR5380::read(int address, bool) {
|
||||
switch(address & 7) {
|
||||
case 0:
|
||||
// LOG("[SCSI 0] Get current SCSI bus state: " << PADHEX(2) << (bus_.get_state() & 0xff));
|
||||
@ -258,6 +263,7 @@ void NCR5380::scsi_bus_did_change(SCSI::Bus *, SCSI::BusState new_state, double
|
||||
case ExecutionState::WaitingForBusy:
|
||||
if(!(new_state & SCSI::Line::Busy) || time_since_change < SCSI::DeskewDelay) return;
|
||||
state_ = ExecutionState::WatchingBusy;
|
||||
[[fallthrough]];
|
||||
|
||||
case ExecutionState::WatchingBusy:
|
||||
if(!(new_state & SCSI::Line::Busy)) {
|
||||
|
@ -37,22 +37,22 @@ enum Line {
|
||||
class PortHandler {
|
||||
public:
|
||||
/// Requests the current input value of @c port from the port handler.
|
||||
uint8_t get_port_input(Port port) { return 0xff; }
|
||||
uint8_t get_port_input([[maybe_unused]] Port port) { return 0xff; }
|
||||
|
||||
/// Sets the current output value of @c port and provides @c direction_mask, indicating which pins are marked as output.
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask) {}
|
||||
void set_port_output([[maybe_unused]] Port port, [[maybe_unused]] uint8_t value, [[maybe_unused]] uint8_t direction_mask) {}
|
||||
|
||||
/// Sets the current logical output level for line @c line on port @c port.
|
||||
void set_control_line_output(Port port, Line line, bool value) {}
|
||||
void set_control_line_output([[maybe_unused]] Port port, [[maybe_unused]] Line line, [[maybe_unused]] bool value) {}
|
||||
|
||||
/// Sets the current logical value of the interrupt line.
|
||||
void set_interrupt_status(bool status) {}
|
||||
void set_interrupt_status([[maybe_unused]] bool status) {}
|
||||
|
||||
/// Provides a measure of time elapsed between other calls.
|
||||
void run_for(HalfCycles duration) {}
|
||||
void run_for([[maybe_unused]] HalfCycles duration) {}
|
||||
|
||||
/// Receives passed-on flush() calls from the 6522.
|
||||
void flush() {}
|
||||
void flush() {}
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -14,6 +14,6 @@ void IRQDelegatePortHandler::set_interrupt_delegate(Delegate *delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
void IRQDelegatePortHandler::set_interrupt_status(bool new_status) {
|
||||
void IRQDelegatePortHandler::set_interrupt_status(bool) {
|
||||
if(delegate_) delegate_->mos6522_did_change_interrupt_status(this);
|
||||
}
|
||||
|
@ -173,9 +173,11 @@ template <class T> class MOS6532 {
|
||||
bool interrupt_line_ = false;
|
||||
|
||||
// expected to be overridden
|
||||
uint8_t get_port_input(int port) { return 0xff; }
|
||||
void set_port_output(int port, uint8_t value, uint8_t output_mask) {}
|
||||
void set_irq_line(bool new_value) {}
|
||||
void set_port_output([[maybe_unused]] int port, [[maybe_unused]] uint8_t value, [[maybe_unused]] uint8_t output_mask) {}
|
||||
uint8_t get_port_input([[maybe_unused]] int port) {
|
||||
return 0xff;
|
||||
}
|
||||
void set_irq_line(bool) {}
|
||||
|
||||
inline void evaluate_interrupts() {
|
||||
interrupt_line_ =
|
||||
|
@ -43,7 +43,7 @@ class AudioGenerator: public ::Outputs::Speaker::SampleSource {
|
||||
};
|
||||
|
||||
struct BusHandler {
|
||||
void perform_read(uint16_t address, uint8_t *pixel_data, uint8_t *colour_data) {
|
||||
void perform_read([[maybe_unused]] uint16_t address, [[maybe_unused]] uint8_t *pixel_data, [[maybe_unused]] uint8_t *colour_data) {
|
||||
*pixel_data = 0xff;
|
||||
*colour_data = 0xff;
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ uint8_t ACIA::parity(uint8_t value) {
|
||||
return value ^ (parity_ == Parity::Even);
|
||||
}
|
||||
|
||||
bool ACIA::serial_line_did_produce_bit(Serial::Line *line, int bit) {
|
||||
bool ACIA::serial_line_did_produce_bit(Serial::Line *, int bit) {
|
||||
// Shift this bit into the 11-bit input register; this is big enough to hold
|
||||
// the largest transmission symbol.
|
||||
++bits_received_;
|
||||
|
@ -9,13 +9,15 @@
|
||||
#ifndef i8255_hpp
|
||||
#define i8255_hpp
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Intel {
|
||||
namespace i8255 {
|
||||
|
||||
class PortHandler {
|
||||
public:
|
||||
void set_value(int port, uint8_t value) {}
|
||||
uint8_t get_value(int port) { return 0xff; }
|
||||
void set_value([[maybe_unused]] int port, [[maybe_unused]] uint8_t value) {}
|
||||
uint8_t get_value([[maybe_unused]] int port) { return 0xff; }
|
||||
};
|
||||
|
||||
// TODO: Modes 1 and 2.
|
||||
|
@ -80,6 +80,10 @@ i8272::i8272(BusHandler &bus_handler, Cycles clock_rate) :
|
||||
Storage::Disk::MFMController(clock_rate),
|
||||
bus_handler_(bus_handler) {
|
||||
posit_event(int(Event8272::CommandByte));
|
||||
|
||||
// TODO: implement DMA, etc. I have a vague intention to implement the IBM PC
|
||||
// one day, that should help to force that stuff.
|
||||
(void)bus_handler_;
|
||||
}
|
||||
|
||||
ClockingHint::Preference i8272::preferred_clocking() const {
|
||||
@ -880,13 +884,13 @@ bool i8272::seek_is_satisfied(int drive) {
|
||||
(drives_[drive].target_head_position == -1 && get_drive().get_is_track_zero());
|
||||
}
|
||||
|
||||
void i8272::set_dma_acknowledge(bool dack) {
|
||||
void i8272::set_dma_acknowledge(bool) {
|
||||
}
|
||||
|
||||
void i8272::set_terminal_count(bool tc) {
|
||||
void i8272::set_terminal_count(bool) {
|
||||
}
|
||||
|
||||
void i8272::set_data_input(uint8_t value) {
|
||||
void i8272::set_data_input(uint8_t) {
|
||||
}
|
||||
|
||||
uint8_t i8272::get_data_output() {
|
||||
|
@ -20,8 +20,9 @@ namespace i8272 {
|
||||
|
||||
class BusHandler {
|
||||
public:
|
||||
virtual void set_dma_data_request(bool drq) {}
|
||||
virtual void set_interrupt(bool irq) {}
|
||||
virtual ~BusHandler() {}
|
||||
virtual void set_dma_data_request([[maybe_unused]] bool drq) {}
|
||||
virtual void set_interrupt([[maybe_unused]] bool irq) {}
|
||||
};
|
||||
|
||||
class i8272 : public Storage::Disk::MFMController {
|
||||
@ -45,7 +46,7 @@ class i8272 : public Storage::Disk::MFMController {
|
||||
virtual void select_drive(int number) = 0;
|
||||
|
||||
private:
|
||||
// The bus handler, for interrupt and DMA-driven usage.
|
||||
// The bus handler, for interrupt and DMA-driven usage. [TODO]
|
||||
BusHandler &bus_handler_;
|
||||
std::unique_ptr<BusHandler> allocated_bus_handler_;
|
||||
|
||||
|
@ -40,7 +40,7 @@ enum class TVStandard {
|
||||
|
||||
class Base {
|
||||
public:
|
||||
static const uint32_t palette_pack(uint8_t r, uint8_t g, uint8_t b) {
|
||||
static uint32_t palette_pack(uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint32_t result = 0;
|
||||
uint8_t *const result_ptr = reinterpret_cast<uint8_t *>(&result);
|
||||
result_ptr[0] = r;
|
||||
@ -421,7 +421,8 @@ class Base {
|
||||
*/
|
||||
|
||||
#define slot(n) \
|
||||
if(use_end && end == n) return;\
|
||||
if(use_end && end == n) return; \
|
||||
[[fallthrough]]; \
|
||||
case n
|
||||
|
||||
#define external_slot(n) \
|
||||
@ -449,7 +450,7 @@ class Base {
|
||||
|
||||
|
||||
/***********************************************
|
||||
TMS9918 Fetching Code
|
||||
TMS9918 Fetching Code
|
||||
************************************************/
|
||||
|
||||
template<bool use_end> void fetch_tms_refresh(int start, int end) {
|
||||
@ -693,7 +694,7 @@ class Base {
|
||||
|
||||
|
||||
/***********************************************
|
||||
Master System Fetching Code
|
||||
Master System Fetching Code
|
||||
************************************************/
|
||||
|
||||
template<bool use_end> void fetch_sms(int start, int end) {
|
||||
|
@ -30,7 +30,7 @@ class PortHandler {
|
||||
|
||||
@param port_b @c true if the input being queried is Port B. @c false if it is Port A.
|
||||
*/
|
||||
virtual uint8_t get_port_input(bool port_b) {
|
||||
virtual uint8_t get_port_input([[maybe_unused]] bool port_b) {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ class PortHandler {
|
||||
@param port_b @c true if the output being posted is Port B. @c false if it is Port A.
|
||||
@param value the value now being output.
|
||||
*/
|
||||
virtual void set_port_output(bool port_b, uint8_t value) {}
|
||||
virtual void set_port_output([[maybe_unused]] bool port_b, [[maybe_unused]] uint8_t value) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -23,7 +23,7 @@ void Toggle::set_sample_volume_range(std::int16_t range) {
|
||||
volume_ = range;
|
||||
}
|
||||
|
||||
void Toggle::skip_samples(const std::size_t number_of_samples) {}
|
||||
void Toggle::skip_samples(std::size_t) {}
|
||||
|
||||
void Toggle::set_output(bool enabled) {
|
||||
if(is_enabled_ == enabled) return;
|
||||
|
@ -219,7 +219,7 @@ void DiskII::process_event(const Storage::Disk::Drive::Event &event) {
|
||||
}
|
||||
}
|
||||
|
||||
void DiskII::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) {
|
||||
void DiskII::set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) {
|
||||
drive_is_sleeping_[0] = drives_[0].preferred_clocking() == ClockingHint::Preference::None;
|
||||
drive_is_sleeping_[1] = drives_[1].preferred_clocking() == ClockingHint::Preference::None;
|
||||
decide_clocking_preference();
|
||||
|
@ -307,8 +307,8 @@ void IWM::run_for(const Cycles cycles) {
|
||||
} else {
|
||||
shift_register_ = sense();
|
||||
}
|
||||
[[fallthrough]];
|
||||
|
||||
/* Deliberate fallthrough. */
|
||||
default:
|
||||
if(drive_is_rotating_[active_drive_]) drives_[active_drive_]->run_for(cycles);
|
||||
break;
|
||||
|
@ -24,7 +24,7 @@ namespace Apple {
|
||||
Defines the drive interface used by the IWM, derived from the external pinout as
|
||||
per e.g. https://old.pinouts.ru/HD/MacExtDrive_pinout.shtml
|
||||
|
||||
These are subclassed of Storage::Disk::Drive, so accept any disk the emulator supports,
|
||||
These are subclasses of Storage::Disk::Drive, so accept any disk the emulator supports,
|
||||
and provide the usual read/write interface for on-disk data.
|
||||
*/
|
||||
struct IWMDrive: public Storage::Disk::Drive {
|
||||
@ -82,8 +82,9 @@ class IWM:
|
||||
|
||||
uint8_t data_register_ = 0;
|
||||
uint8_t mode_ = 0;
|
||||
bool read_write_ready_ = true;
|
||||
bool write_overran_ = false;
|
||||
// These related to functionality not-yet implemented.
|
||||
// bool read_write_ready_ = true;
|
||||
// bool write_overran_ = false;
|
||||
|
||||
int state_ = 0;
|
||||
|
||||
|
@ -61,7 +61,6 @@ class SCC: public ::Outputs::Speaker::SampleSource {
|
||||
} waves_[4];
|
||||
|
||||
std::uint8_t channel_enable_ = 0;
|
||||
std::uint8_t test_register_ = 0;
|
||||
|
||||
void evaluate_output_volume();
|
||||
|
||||
|
@ -23,7 +23,7 @@ AsyncTaskQueue::AsyncTaskQueue()
|
||||
std::function<void(void)> next_function;
|
||||
|
||||
// Take lock, check for a new task
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
std::unique_lock lock(queue_mutex_);
|
||||
if(!pending_tasks_.empty()) {
|
||||
next_function = pending_tasks_.front();
|
||||
pending_tasks_.pop_front();
|
||||
@ -60,7 +60,7 @@ void AsyncTaskQueue::enqueue(std::function<void(void)> function) {
|
||||
#ifdef __APPLE__
|
||||
dispatch_async(serial_dispatch_queue_, ^{function();});
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(queue_mutex_);
|
||||
std::lock_guard lock(queue_mutex_);
|
||||
pending_tasks_.push_back(function);
|
||||
processing_condition_.notify_all();
|
||||
#endif
|
||||
@ -72,9 +72,9 @@ void AsyncTaskQueue::flush() {
|
||||
#else
|
||||
auto flush_mutex = std::make_shared<std::mutex>();
|
||||
auto flush_condition = std::make_shared<std::condition_variable>();
|
||||
std::unique_lock<std::mutex> lock(*flush_mutex);
|
||||
std::unique_lock lock(*flush_mutex);
|
||||
enqueue([=] () {
|
||||
std::unique_lock<std::mutex> inner_lock(*flush_mutex);
|
||||
std::unique_lock inner_lock(*flush_mutex);
|
||||
flush_condition->notify_all();
|
||||
});
|
||||
flush_condition->wait(lock);
|
||||
|
@ -216,11 +216,8 @@ class ConcreteJoystick: public Joystick {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void did_set_input(const Input &input, float value) {
|
||||
}
|
||||
|
||||
virtual void did_set_input(const Input &input, bool value) {
|
||||
}
|
||||
virtual void did_set_input([[maybe_unused]] const Input &input, [[maybe_unused]] float value) {}
|
||||
virtual void did_set_input([[maybe_unused]] const Input &input, [[maybe_unused]] bool value) {}
|
||||
|
||||
private:
|
||||
const std::vector<Input> inputs_;
|
||||
|
@ -19,7 +19,7 @@ Keyboard::Keyboard(const std::set<Key> &essential_modifiers) : essential_modifie
|
||||
Keyboard::Keyboard(const std::set<Key> &observed_keys, const std::set<Key> &essential_modifiers) :
|
||||
observed_keys_(observed_keys), essential_modifiers_(essential_modifiers), is_exclusive_(false) {}
|
||||
|
||||
bool Keyboard::set_key_pressed(Key key, char value, bool is_pressed) {
|
||||
bool Keyboard::set_key_pressed(Key key, char, bool is_pressed) {
|
||||
const size_t key_offset = size_t(key);
|
||||
if(key_offset >= key_states_.size()) {
|
||||
key_states_.resize(key_offset+1, false);
|
||||
|
@ -20,7 +20,7 @@ class Mouse {
|
||||
/*!
|
||||
Indicates a movement of the mouse.
|
||||
*/
|
||||
virtual void move(int x, int y) {}
|
||||
virtual void move([[maybe_unused]] int x, [[maybe_unused]] int y) {}
|
||||
|
||||
/*!
|
||||
@returns the number of buttons on this mouse.
|
||||
@ -34,7 +34,7 @@ class Mouse {
|
||||
The intention is that @c index be semantic, not positional:
|
||||
0 for the primary button, 1 for the secondary, 2 for the tertiary, etc.
|
||||
*/
|
||||
virtual void set_button_pressed(int index, bool is_pressed) {}
|
||||
virtual void set_button_pressed([[maybe_unused]] int index, [[maybe_unused]] bool is_pressed) {}
|
||||
|
||||
/*!
|
||||
Releases all depressed buttons.
|
||||
|
@ -691,11 +691,11 @@ class FDC: public Intel::i8272::i8272 {
|
||||
get_drive().set_motor_on(on);
|
||||
}
|
||||
|
||||
void select_drive(int c) {
|
||||
// TODO: support more than one drive.
|
||||
void select_drive(int) {
|
||||
// TODO: support more than one drive. (and in set_disk)
|
||||
}
|
||||
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int) {
|
||||
get_drive().set_disk(disk);
|
||||
}
|
||||
|
||||
@ -1075,7 +1075,7 @@ template <bool has_fdc> class ConcreteMachine:
|
||||
return !media.tapes.empty() || (!media.disks.empty() && has_fdc);
|
||||
}
|
||||
|
||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final {
|
||||
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) final {
|
||||
fdc_is_sleeping_ = fdc_.preferred_clocking() == ClockingHint::Preference::None;
|
||||
tape_player_is_sleeping_ = tape_player_.preferred_clocking() == ClockingHint::Preference::None;
|
||||
}
|
||||
@ -1112,7 +1112,7 @@ template <bool has_fdc> class ConcreteMachine:
|
||||
}
|
||||
|
||||
// MARK: - Activity Source
|
||||
void set_activity_observer(Activity::Observer *observer) final {
|
||||
void set_activity_observer([[maybe_unused]] Activity::Observer *observer) final {
|
||||
if constexpr (has_fdc) fdc_.set_activity_observer(observer);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ class Machine {
|
||||
class Options: public Reflection::StructImpl<Options>, public Configurable::DisplayOption<Options> {
|
||||
friend Configurable::DisplayOption<Options>;
|
||||
public:
|
||||
Options(Configurable::OptionsType type) : Configurable::DisplayOption<Options>(Configurable::Display::RGB) {
|
||||
Options(Configurable::OptionsType) : Configurable::DisplayOption<Options>(Configurable::Display::RGB) {
|
||||
if(needs_declare()) {
|
||||
declare_display_option();
|
||||
limit_enum(&output, Configurable::Display::RGB, Configurable::Display::CompositeColour, -1);
|
||||
|
@ -804,7 +804,7 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
void reset_all_keys() final {
|
||||
void reset_all_keys(Inputs::Keyboard *) final {
|
||||
open_apple_is_pressed_ = closed_apple_is_pressed_ = key_is_down_ = false;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class Machine {
|
||||
class Options: public Reflection::StructImpl<Options>, public Configurable::DisplayOption<Options> {
|
||||
friend Configurable::DisplayOption<Options>;
|
||||
public:
|
||||
Options(Configurable::OptionsType type) : Configurable::DisplayOption<Options>(Configurable::Display::CompositeColour) {
|
||||
Options(Configurable::OptionsType) : Configurable::DisplayOption<Options>(Configurable::Display::CompositeColour) {
|
||||
if(needs_declare()) {
|
||||
declare_display_option();
|
||||
limit_enum(&output, Configurable::Display::CompositeMonochrome, Configurable::Display::CompositeColour, -1);
|
||||
|
@ -54,7 +54,7 @@ class Card {
|
||||
no constraints, that want to be informed of every machine cycle, will receive
|
||||
a call to perform_bus_operation every cycle and should use that for time keeping.
|
||||
*/
|
||||
virtual void run_for(Cycles half_cycles, int stretches) {}
|
||||
virtual void run_for([[maybe_unused]] Cycles half_cycles, [[maybe_unused]] int stretches) {}
|
||||
|
||||
/// Requests a flush of any pending audio or video output.
|
||||
virtual void flush() {}
|
||||
@ -89,7 +89,7 @@ class Card {
|
||||
}
|
||||
|
||||
/*! Cards may supply a target for activity observation if desired. */
|
||||
virtual void set_activity_observer(Activity::Observer *observer) {}
|
||||
virtual void set_activity_observer([[maybe_unused]] Activity::Observer *observer) {}
|
||||
|
||||
struct Delegate {
|
||||
virtual void card_did_change_select_constraints(Card *card) = 0;
|
||||
|
@ -50,7 +50,7 @@ void DiskIICard::perform_bus_operation(Select select, bool is_read, uint16_t add
|
||||
}
|
||||
}
|
||||
|
||||
void DiskIICard::run_for(Cycles cycles, int stretches) {
|
||||
void DiskIICard::run_for(Cycles cycles, int) {
|
||||
if(diskii_clocking_preference_ == ClockingHint::Preference::None) return;
|
||||
diskii_.run_for(Cycles(cycles.as_integral() * 2));
|
||||
}
|
||||
@ -63,7 +63,7 @@ void DiskIICard::set_activity_observer(Activity::Observer *observer) {
|
||||
diskii_.set_activity_observer(observer);
|
||||
}
|
||||
|
||||
void DiskIICard::set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) {
|
||||
void DiskIICard::set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference preference) {
|
||||
diskii_clocking_preference_ = preference;
|
||||
set_select_constraints((preference != ClockingHint::Preference::RealTime) ? (IO | Device) : None);
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ void VideoBase::output_low_resolution(uint8_t *target, const uint8_t *const sour
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBase::output_fat_low_resolution(uint8_t *target, const uint8_t *const source, size_t length, int column, int row) const {
|
||||
void VideoBase::output_fat_low_resolution(uint8_t *target, const uint8_t *const source, size_t length, int, int row) const {
|
||||
const int row_shift = row&4;
|
||||
for(size_t c = 0; c < length; ++c) {
|
||||
// Fat low-resolution mode appears not to do anything to try to make odd and
|
||||
|
@ -29,7 +29,7 @@ class BusHandler {
|
||||
from auxiliary memory to @c auxiliary_target. If the machine has no axiliary memory,
|
||||
it needn't write anything to auxiliary_target.
|
||||
*/
|
||||
void perform_read(uint16_t address, size_t count, uint8_t *base_target, uint8_t *auxiliary_target) {
|
||||
void perform_read([[maybe_unused]] uint16_t address, [[maybe_unused]] size_t count, [[maybe_unused]] uint8_t *base_target, [[maybe_unused]] uint8_t *auxiliary_target) {
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,7 +135,7 @@ class Keyboard {
|
||||
/*!
|
||||
The keyboard expects ~10 µs-frequency ticks, i.e. a clock rate of just around 100 kHz.
|
||||
*/
|
||||
void run_for(HalfCycles cycle) {
|
||||
void run_for(HalfCycles) { // TODO: honour the HalfCycles argument.
|
||||
switch(mode_) {
|
||||
default:
|
||||
case Mode::Waiting: return;
|
||||
@ -210,7 +210,7 @@ class Keyboard {
|
||||
|
||||
void enqueue_key_state(uint16_t key, bool is_pressed) {
|
||||
// Front insert; messages will be pop_back'd.
|
||||
std::lock_guard<decltype(key_queue_mutex_)> lock(key_queue_mutex_);
|
||||
std::lock_guard lock(key_queue_mutex_);
|
||||
|
||||
// Keys on the keypad are preceded by a $79 keycode; in the internal naming scheme
|
||||
// they are indicated by having bit 8 set. So add the $79 prefix if required.
|
||||
@ -228,7 +228,7 @@ class Keyboard {
|
||||
switch(command) {
|
||||
case 0x10: // Inquiry.
|
||||
case 0x14: { // Instant.
|
||||
std::lock_guard<decltype(key_queue_mutex_)> lock(key_queue_mutex_);
|
||||
std::lock_guard lock(key_queue_mutex_);
|
||||
if(!key_queue_.empty()) {
|
||||
const auto new_message = key_queue_.back();
|
||||
key_queue_.pop_back();
|
||||
|
@ -183,7 +183,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
|
||||
using Microcycle = CPU::MC68000::Microcycle;
|
||||
|
||||
forceinline HalfCycles perform_bus_operation(const Microcycle &cycle, int is_supervisor) {
|
||||
forceinline HalfCycles perform_bus_operation(const Microcycle &cycle, int) {
|
||||
// Advance time.
|
||||
advance_time(cycle.length);
|
||||
|
||||
@ -490,7 +490,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
|
||||
// MARK: Interrupt updates.
|
||||
|
||||
void did_change_interrupt_status(Zilog::SCC::z8530 *sender, bool new_status) final {
|
||||
void did_change_interrupt_status(Zilog::SCC::z8530 *, bool) final {
|
||||
update_interrupt_input();
|
||||
}
|
||||
|
||||
@ -541,7 +541,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
private:
|
||||
bool quickboot_ = false;
|
||||
|
||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final {
|
||||
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) final {
|
||||
scsi_bus_is_clocked_ = scsi_bus_.preferred_clocking() != ClockingHint::Preference::None;
|
||||
}
|
||||
|
||||
@ -654,7 +654,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
using Port = MOS::MOS6522::Port;
|
||||
using Line = MOS::MOS6522::Line;
|
||||
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask) {
|
||||
void set_port_output(Port port, uint8_t value, uint8_t) {
|
||||
/*
|
||||
Peripheral lines: keyboard data, interrupt configuration.
|
||||
(See p176 [/215])
|
||||
@ -745,7 +745,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
audio_.flush();
|
||||
}
|
||||
|
||||
void set_interrupt_status(bool status) {
|
||||
void set_interrupt_status(bool) {
|
||||
machine_.update_interrupt_input();
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ class ConcreteMachine:
|
||||
|
||||
using namespace Atari2600;
|
||||
|
||||
Machine *Machine::Atari2600(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) {
|
||||
Machine *Machine::Atari2600(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &) {
|
||||
const Target *const atari_target = dynamic_cast<const Target *>(target);
|
||||
return new Atari2600::ConcreteMachine(*atari_target);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class BusExtender: public CPU::MOS6502::BusHandler {
|
||||
public:
|
||||
BusExtender(uint8_t *rom_base, std::size_t rom_size) : rom_base_(rom_base), rom_size_(rom_size) {}
|
||||
|
||||
void advance_cycles(int cycles) {}
|
||||
void advance_cycles(int) {}
|
||||
|
||||
protected:
|
||||
uint8_t *rom_base_;
|
||||
|
@ -117,7 +117,6 @@ class Pitfall2: public BusExtender {
|
||||
|
||||
uint16_t featcher_address_[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t top_[8], bottom_[8], mask_[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t music_mode_[3];
|
||||
uint8_t random_number_generator_ = 0;
|
||||
uint8_t *rom_ptr_;
|
||||
uint8_t audio_channel_[3];
|
||||
|
@ -586,7 +586,7 @@ template<class T> void TIA::perform_motion_step(T &object) {
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> void TIA::perform_border_motion(T &object, int start, int end) {
|
||||
template<class T> void TIA::perform_border_motion(T &object, int, int end) {
|
||||
while(object.is_moving && object.motion_time < end)
|
||||
perform_motion_step<T>(object);
|
||||
}
|
||||
|
@ -239,15 +239,15 @@ class TIA {
|
||||
int size = 1;
|
||||
const bool enqueues = false;
|
||||
|
||||
inline void skip_pixels(const int count, int from_horizontal_counter) {
|
||||
inline void skip_pixels(const int count, int) {
|
||||
pixel_position = std::max(0, pixel_position - count);
|
||||
}
|
||||
|
||||
inline void reset_pixels(int copy) {
|
||||
inline void reset_pixels(int) {
|
||||
pixel_position = size;
|
||||
}
|
||||
|
||||
inline void output_pixels(uint8_t *const target, const int count, const uint8_t collision_identity, int from_horizontal_counter) {
|
||||
inline void output_pixels(uint8_t *const target, const int count, const uint8_t collision_identity, [[maybe_unused]] int from_horizontal_counter) {
|
||||
int output_cursor = 0;
|
||||
while(pixel_position && output_cursor < count)
|
||||
{
|
||||
@ -257,8 +257,8 @@ class TIA {
|
||||
}
|
||||
}
|
||||
|
||||
void dequeue_pixels(uint8_t *const target, const uint8_t collision_identity, const int time_now) {}
|
||||
void enqueue_pixels(const int start, const int end, int from_horizontal_counter) {}
|
||||
void dequeue_pixels([[maybe_unused]] uint8_t *const target, [[maybe_unused]] uint8_t collision_identity, [[maybe_unused]] int time_now) {}
|
||||
void enqueue_pixels([[maybe_unused]] int start, [[maybe_unused]] int end, [[maybe_unused]] int from_horizontal_counter) {}
|
||||
};
|
||||
|
||||
// missile state
|
||||
|
@ -237,6 +237,7 @@ class ConcreteMachine:
|
||||
memory = rom_.data();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case BusDevice::RAM:
|
||||
memory = ram_.data();
|
||||
break;
|
||||
@ -529,7 +530,7 @@ class ConcreteMachine:
|
||||
bool keyboard_needs_clock_ = false;
|
||||
bool mfp_is_realtime_ = false;
|
||||
ClockingHint::Preference dma_clocking_preference_ = ClockingHint::Preference::None;
|
||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final {
|
||||
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) final {
|
||||
// This is being called by one of the components; avoid any time flushing here as that's
|
||||
// already dealt with (and, just to be absolutely sure, to avoid recursive mania).
|
||||
may_defer_acias_ =
|
||||
@ -580,7 +581,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
// MARK - MFP input.
|
||||
void mfp68901_did_change_interrupt_status(Motorola::MFP68901::MFP68901 *mfp) final {
|
||||
void mfp68901_did_change_interrupt_status(Motorola::MFP68901::MFP68901 *) final {
|
||||
update_interrupt_input();
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ void IntelligentKeyboard::run_for(HalfCycles duration) {
|
||||
// Forward key changes; implicit assumption here: mutexs are cheap while there's
|
||||
// negligible contention.
|
||||
{
|
||||
std::lock_guard<decltype(key_queue_mutex_)> guard(key_queue_mutex_);
|
||||
std::lock_guard guard(key_queue_mutex_);
|
||||
for(uint8_t key: key_queue_) {
|
||||
output_bytes({key});
|
||||
}
|
||||
@ -286,7 +286,7 @@ void IntelligentKeyboard::set_mouse_position(uint16_t x, uint16_t y) {
|
||||
mouse_position_[1] = std::min(int(y), mouse_range_[1]);
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::set_mouse_keycode_reporting(uint8_t delta_x, uint8_t delta_y) {
|
||||
void IntelligentKeyboard::set_mouse_keycode_reporting(uint8_t, uint8_t) {
|
||||
LOG("Unimplemented: set mouse keycode reporting");
|
||||
}
|
||||
|
||||
@ -308,7 +308,7 @@ void IntelligentKeyboard::set_mouse_y_upward() {
|
||||
mouse_y_multiplier_ = -1;
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::set_mouse_button_actions(uint8_t actions) {
|
||||
void IntelligentKeyboard::set_mouse_button_actions(uint8_t) {
|
||||
LOG("Unimplemented: set mouse button actions");
|
||||
}
|
||||
|
||||
@ -348,7 +348,7 @@ void IntelligentKeyboard::post_relative_mouse_event(int x, int y) {
|
||||
|
||||
// MARK: - Keyboard Input
|
||||
void IntelligentKeyboard::set_key_state(Key key, bool is_pressed) {
|
||||
std::lock_guard<decltype(key_queue_mutex_)> guard(key_queue_mutex_);
|
||||
std::lock_guard guard(key_queue_mutex_);
|
||||
if(is_pressed) {
|
||||
key_queue_.push_back(uint8_t(key));
|
||||
} else {
|
||||
@ -461,6 +461,10 @@ void IntelligentKeyboard::set_joystick_interrogation_mode() {
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical) {
|
||||
// TODO: honour velocity thresholds.
|
||||
(void)horizontal;
|
||||
(void)vertical;
|
||||
|
||||
joystick_mode_ = JoystickMode::KeyCode;
|
||||
clear_joystick_events();
|
||||
}
|
||||
@ -494,7 +498,7 @@ void IntelligentKeyboard::interrogate_joysticks() {
|
||||
}
|
||||
}
|
||||
|
||||
void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t rate) {
|
||||
void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t) {
|
||||
LOG("Unimplemented: joystick monitoring mode");
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ Video::Video() :
|
||||
crt_.set_visible_area(crt_.get_rect_for_area(33, 260, 440, 1700, 4.0f / 3.0f));
|
||||
}
|
||||
|
||||
void Video::set_ram(uint16_t *ram, size_t size) {
|
||||
void Video::set_ram(uint16_t *ram, size_t) {
|
||||
ram_ = ram;
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,7 @@ class ConcreteMachine:
|
||||
switch(cycle.operation) {
|
||||
case CPU::Z80::PartialMachineCycle::ReadOpcode:
|
||||
if(!address) pc_zero_accesses_++;
|
||||
[[fallthrough]];
|
||||
case CPU::Z80::PartialMachineCycle::Read:
|
||||
if(address < 0x2000) {
|
||||
if(super_game_module_.replace_bios) {
|
||||
|
@ -39,7 +39,7 @@ namespace C1540 {
|
||||
/*!
|
||||
Provides an emulation of the C1540.
|
||||
*/
|
||||
class Machine: public MachineBase {
|
||||
class Machine final: public MachineBase {
|
||||
public:
|
||||
Machine(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher);
|
||||
|
||||
|
@ -122,7 +122,7 @@ void MachineBase::set_activity_observer(Activity::Observer *observer) {
|
||||
|
||||
// MARK: - 6522 delegate
|
||||
|
||||
void MachineBase::mos6522_did_change_interrupt_status(void *mos6522) {
|
||||
void MachineBase::mos6522_did_change_interrupt_status(void *) {
|
||||
// both VIAs are connected to the IRQ line
|
||||
m6502_.set_irq_line(serial_port_VIA_.get_interrupt_line() || drive_VIA_.get_interrupt_line());
|
||||
}
|
||||
@ -153,11 +153,11 @@ void MachineBase::process_index_hole() {}
|
||||
|
||||
// MARK: - Drive VIA delegate
|
||||
|
||||
void MachineBase::drive_via_did_step_head(void *driveVIA, int direction) {
|
||||
void MachineBase::drive_via_did_step_head(void *, int direction) {
|
||||
get_drive().step(Storage::Disk::HeadPosition(direction, 2));
|
||||
}
|
||||
|
||||
void MachineBase::drive_via_did_set_data_density(void *driveVIA, int density) {
|
||||
void MachineBase::drive_via_did_set_data_density(void *, int density) {
|
||||
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(unsigned(density)));
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ uint8_t SerialPortVIA::get_port_input(MOS::MOS6522::Port port) {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void SerialPortVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t mask) {
|
||||
void SerialPortVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
std::shared_ptr<::Commodore::Serial::Port> serialPort = serial_port_.lock();
|
||||
if(serialPort) {
|
||||
@ -243,7 +243,7 @@ void DriveVIA::set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Li
|
||||
}
|
||||
}
|
||||
|
||||
void DriveVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t direction_mask) {
|
||||
void DriveVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
if(previous_port_b_output_ != value) {
|
||||
// record drive motor state
|
||||
|
@ -75,6 +75,7 @@ namespace Serial {
|
||||
class Port {
|
||||
public:
|
||||
Port() : line_levels_{High, High, High, High, High} {}
|
||||
virtual ~Port() {}
|
||||
|
||||
/*!
|
||||
Sets the current level of an output line on this serial port.
|
||||
|
@ -99,7 +99,7 @@ class UserPortVIA: public MOS::MOS6522::IRQDelegatePortHandler {
|
||||
}
|
||||
|
||||
/// Receives announcements from the 6522 of user-port output, which might affect what's currently being presented onto the serial bus.
|
||||
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t mask) {
|
||||
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
// Line 7 of port A is inverted and output as serial ATN.
|
||||
if(!port) {
|
||||
std::shared_ptr<::Commodore::Serial::Port> serialPort = serial_port_.lock();
|
||||
@ -654,7 +654,7 @@ class ConcreteMachine:
|
||||
return mos6560_.get_speaker();
|
||||
}
|
||||
|
||||
void mos6522_did_change_interrupt_status(void *mos6522) final {
|
||||
void mos6522_did_change_interrupt_status(void *) final {
|
||||
m6502_.set_nmi_line(user_port_via_.get_interrupt_line());
|
||||
m6502_.set_irq_line(keyboard_via_.get_interrupt_line());
|
||||
}
|
||||
@ -691,7 +691,7 @@ class ConcreteMachine:
|
||||
set_use_fast_tape();
|
||||
}
|
||||
|
||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final {
|
||||
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference clocking) final {
|
||||
tape_is_sleeping_ = clocking == ClockingHint::Preference::None;
|
||||
set_use_fast_tape();
|
||||
}
|
||||
|
@ -215,7 +215,8 @@ class ConcreteMachine:
|
||||
activity_observer_->set_led_status(caps_led, caps_led_state_);
|
||||
}
|
||||
|
||||
// deliberate fallthrough; fe07 contains the display mode.
|
||||
[[fallthrough]]; // fe07 contains the display mode.
|
||||
|
||||
|
||||
case 0xfe02: case 0xfe03:
|
||||
case 0xfe08: case 0xfe09: case 0xfe0a: case 0xfe0b:
|
||||
@ -421,7 +422,7 @@ class ConcreteMachine:
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
void tape_did_change_interrupt_status(Tape *tape) final {
|
||||
void tape_did_change_interrupt_status(Tape *) final {
|
||||
interrupt_status_ = (interrupt_status_ & ~(Interrupt::TransmitDataEmpty | Interrupt::ReceiveDataFull | Interrupt::HighToneDetect)) | tape_.get_interrupt_status();
|
||||
evaluate_interrupts();
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
namespace Electron {
|
||||
|
||||
class Plus3 : public WD::WD1770 {
|
||||
class Plus3 final : public WD::WD1770 {
|
||||
public:
|
||||
Plus3();
|
||||
|
||||
@ -26,7 +26,7 @@ class Plus3 : public WD::WD1770 {
|
||||
void set_control_register(uint8_t control, uint8_t changes);
|
||||
uint8_t last_control_ = 0;
|
||||
|
||||
void set_motor_on(bool on);
|
||||
void set_motor_on(bool on) override;
|
||||
std::string drive_name(size_t drive);
|
||||
};
|
||||
|
||||
|
@ -52,6 +52,9 @@ void Tape::set_is_in_input_mode(bool is_in_input_mode) {
|
||||
}
|
||||
|
||||
void Tape::set_counter(uint8_t value) {
|
||||
// TODO: use value.
|
||||
(void)value;
|
||||
|
||||
output_.cycles_into_pulse = 0;
|
||||
output_.bits_remaining_until_empty = 0;
|
||||
}
|
||||
|
@ -93,7 +93,6 @@ class VideoOutput {
|
||||
inline void setup_base_address();
|
||||
|
||||
int output_position_ = 0;
|
||||
int unused_cycles_ = 0;
|
||||
|
||||
uint8_t palette_[16];
|
||||
uint8_t screen_mode_ = 6;
|
||||
|
@ -14,14 +14,14 @@ MachineTypes::MappedKeyboardMachine::MappedKeyboardMachine(const std::set<Inputs
|
||||
keyboard_.set_delegate(this);
|
||||
}
|
||||
|
||||
bool MappedKeyboardMachine::keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) {
|
||||
bool MappedKeyboardMachine::keyboard_did_change_key(Inputs::Keyboard *, Inputs::Keyboard::Key key, bool is_pressed) {
|
||||
const uint16_t mapped_key = get_keyboard_mapper()->mapped_key_for_key(key);
|
||||
if(mapped_key == KeyNotMapped) return false;
|
||||
set_key_state(mapped_key, is_pressed);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MappedKeyboardMachine::reset_all_keys(Inputs::Keyboard *keyboard) {
|
||||
void MappedKeyboardMachine::reset_all_keys(Inputs::Keyboard *) {
|
||||
// TODO: unify naming.
|
||||
clear_all_keys();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct KeyActions {
|
||||
Indicates that the key @c key has been either pressed or released, according to
|
||||
the state of @c isPressed.
|
||||
*/
|
||||
virtual void set_key_state(uint16_t key, bool is_pressed) {}
|
||||
virtual void set_key_state([[maybe_unused]] uint16_t key, [[maybe_unused]] bool is_pressed) {}
|
||||
|
||||
/*!
|
||||
Instructs that all keys should now be treated as released.
|
||||
@ -49,7 +49,7 @@ class KeyboardMachine: public KeyActions {
|
||||
/*!
|
||||
@returns @c true if this machine can type the character @c c as part of a @c type_string; @c false otherwise.
|
||||
*/
|
||||
virtual bool can_type(char c) const { return false; }
|
||||
virtual bool can_type([[maybe_unused]] char c) const { return false; }
|
||||
|
||||
/*!
|
||||
Provides a destination for keyboard input.
|
||||
|
@ -17,14 +17,14 @@ DiskROM::DiskROM(const std::vector<uint8_t> &rom) :
|
||||
set_is_double_density(true);
|
||||
}
|
||||
|
||||
void DiskROM::write(uint16_t address, uint8_t value, bool pc_is_outside_bios) {
|
||||
void DiskROM::write(uint16_t address, uint8_t value, bool) {
|
||||
switch(address) {
|
||||
case 0x7ff8: case 0x7ff9: case 0x7ffa: case 0x7ffb:
|
||||
WD::WD1770::write(address, value);
|
||||
break;
|
||||
case 0x7ffc: {
|
||||
const int selected_head = value & 1;
|
||||
for_all_drives([selected_head] (Storage::Disk::Drive &drive, size_t index) {
|
||||
for_all_drives([selected_head] (Storage::Disk::Drive &drive, size_t) {
|
||||
drive.set_head(selected_head);
|
||||
});
|
||||
} break;
|
||||
@ -32,7 +32,7 @@ void DiskROM::write(uint16_t address, uint8_t value, bool pc_is_outside_bios) {
|
||||
set_drive(1 << (value & 1));
|
||||
|
||||
const bool drive_motor = value & 0x80;
|
||||
for_all_drives([drive_motor] (Storage::Disk::Drive &drive, size_t index) {
|
||||
for_all_drives([drive_motor] (Storage::Disk::Drive &drive, size_t) {
|
||||
drive.set_motor_on(drive_motor);
|
||||
});
|
||||
} break;
|
||||
|
@ -492,6 +492,8 @@ class ConcreteMachine:
|
||||
performed_unmapped_access_ = true;
|
||||
}
|
||||
pc_address_ = address; // This is retained so as to be able to name the source of an access to cartridge handlers.
|
||||
[[fallthrough]];
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Read:
|
||||
if(read_pointers_[address >> 13]) {
|
||||
*cycle.value = read_pointers_[address >> 13][address & 8191];
|
||||
@ -662,7 +664,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
// MARK: - Sleeper
|
||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference clocking) final {
|
||||
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) final {
|
||||
tape_player_is_sleeping_ = tape_player_.preferred_clocking() == ClockingHint::Preference::None;
|
||||
set_use_fast_tape();
|
||||
}
|
||||
|
@ -47,13 +47,13 @@ class ROMSlotHandler {
|
||||
virtual ~ROMSlotHandler() {}
|
||||
|
||||
/*! Advances time by @c half_cycles. */
|
||||
virtual void run_for(HalfCycles half_cycles) {}
|
||||
virtual void run_for([[maybe_unused]] HalfCycles half_cycles) {}
|
||||
|
||||
/*! Announces an attempt to write @c value to @c address. */
|
||||
virtual void write(uint16_t address, uint8_t value, bool pc_is_outside_bios) = 0;
|
||||
|
||||
/*! Seeks the result of a read at @c address; this is used only if the area is unmapped. */
|
||||
virtual uint8_t read(uint16_t address) { return 0xff; }
|
||||
virtual uint8_t read([[maybe_unused]] uint16_t address) { return 0xff; }
|
||||
|
||||
enum class WrappingStrategy {
|
||||
/// Repeat causes all accesses to be modulo the size of the ROM.
|
||||
|
@ -155,7 +155,7 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
|
||||
Reponds to changes in the 6522's port output. On an Oric port B sets the tape motor control
|
||||
and the keyboard's active row. Port A is connected to the AY's data bus.
|
||||
*/
|
||||
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t direction_mask) {
|
||||
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
|
||||
if(port) {
|
||||
keyboard_.set_active_row(value);
|
||||
tape_player_.set_motor_control(value & 0x40);
|
||||
@ -267,13 +267,13 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case DiskInterface::BD500:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Byte Drive 500 ROM", "bd500.rom", 8*1024, 0x61952e34);
|
||||
rom_names.emplace_back(machine_name, "the Oric Byte Drive 500 ROM", "bd500.rom", 8*1024, 0x61952e34);
|
||||
break;
|
||||
case DiskInterface::Jasmin:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89);
|
||||
rom_names.emplace_back(machine_name, "the Oric Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89);
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
rom_names.emplace_back(machine_name, "the ORIC Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9c);
|
||||
rom_names.emplace_back(machine_name, "the Oric Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9c);
|
||||
break;
|
||||
case DiskInterface::Pravetz:
|
||||
rom_names.emplace_back(machine_name, "the 8DOS boot ROM", "8dos.rom", 512, 0x49a74c06);
|
||||
@ -568,7 +568,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
}
|
||||
|
||||
// to satisfy MOS::MOS6522IRQDelegate::Delegate
|
||||
void mos6522_did_change_interrupt_status(void *mos6522) final {
|
||||
void mos6522_did_change_interrupt_status(void *) final {
|
||||
set_interrupt_line();
|
||||
}
|
||||
|
||||
@ -608,7 +608,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
}
|
||||
|
||||
// WD::WD1770::Delegate
|
||||
void wd1770_did_change_output(WD::WD1770 *wd1770) final {
|
||||
void wd1770_did_change_output(WD::WD1770 *) final {
|
||||
set_interrupt_line();
|
||||
}
|
||||
|
||||
@ -648,7 +648,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
||||
}
|
||||
}
|
||||
|
||||
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) final {
|
||||
void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference) final {
|
||||
diskii_clocking_preference_ = diskii_.preferred_clocking();
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ class ScanProducer {
|
||||
/*!
|
||||
Sets the display type.
|
||||
*/
|
||||
virtual void set_display_type(Outputs::Display::DisplayType display_type) {}
|
||||
virtual void set_display_type(Outputs::Display::DisplayType) {}
|
||||
|
||||
/*!
|
||||
Gets the display type.
|
||||
|
@ -82,6 +82,7 @@ std::vector<std::string> AllMachines(Type type, bool long_names);
|
||||
|
||||
/*!
|
||||
Returns a map from long machine name to the list of options that machine exposes, for all machines.
|
||||
In all cases, user-friendly selections will have been filled in by default.
|
||||
*/
|
||||
std::map<std::string, std::unique_ptr<Reflection::Struct>> AllOptionsByMachineName();
|
||||
|
||||
|
@ -38,7 +38,7 @@ class CharacterMapper {
|
||||
/// that may not be necessary — it'll often depends on whether the machine needs time to
|
||||
/// observe a modifier like shift before it sees the actual keypress.
|
||||
/// @returns @c true if the typer should pause after forwarding @c key; @c false otherwise.
|
||||
virtual bool needs_pause_after_key(uint16_t key) const { return true; }
|
||||
virtual bool needs_pause_after_key([[maybe_unused]] uint16_t key) const { return true; }
|
||||
|
||||
protected:
|
||||
typedef uint16_t KeySequence[16];
|
||||
@ -127,7 +127,7 @@ class TypeRecipient: public Typer::Delegate {
|
||||
Provided in order to conform to that part of the Typer::Delegate interface that goes above and
|
||||
beyond KeyboardMachine::Machine; responds to the end of typing by clearing all keys.
|
||||
*/
|
||||
void typer_reset(Typer *typer) {
|
||||
void typer_reset(Typer *) override {
|
||||
clear_all_keys();
|
||||
|
||||
// It's unsafe to deallocate typer right now, since it is the caller, but also it has a small
|
||||
|
@ -31,6 +31,7 @@ class Video {
|
||||
|
||||
/// Advances time by @c half-cycles.
|
||||
void run_for(const HalfCycles);
|
||||
|
||||
/// Forces output to catch up to the current output position.
|
||||
void flush();
|
||||
|
||||
|
@ -269,6 +269,7 @@ template<bool is_zx81> class ConcreteMachine:
|
||||
tape_player_.set_motor_control((address >= automatic_tape_motor_start_address_) && (address < automatic_tape_motor_end_address_));
|
||||
}
|
||||
is_opcode_read = true;
|
||||
[[fallthrough]];
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Read:
|
||||
if(address < ram_base_) {
|
||||
|
@ -1317,6 +1317,7 @@
|
||||
4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CSROMFetcher.mm; sourceTree = "<group>"; };
|
||||
4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MSXStaticAnalyserTests.mm; sourceTree = "<group>"; };
|
||||
4B98A1CD1FFADEC400ADF63B /* MSX ROMs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "MSX ROMs"; sourceTree = "<group>"; };
|
||||
4B996B2D2496DAC2001660EF /* VSyncPredictor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VSyncPredictor.hpp; sourceTree = "<group>"; };
|
||||
4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiSpeaker.cpp; sourceTree = "<group>"; };
|
||||
4B9BE3FF203A0C0600FFAE60 /* MultiSpeaker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiSpeaker.hpp; sourceTree = "<group>"; };
|
||||
4B9D0C4A22C7D70900DE1AD3 /* 68000BCDTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000BCDTests.mm; sourceTree = "<group>"; };
|
||||
@ -3855,8 +3856,9 @@
|
||||
4B8A7E85212F988200F2BBC6 /* DeferredQueue.hpp */,
|
||||
4BB06B211F316A3F00600C7A /* ForceInline.hpp */,
|
||||
4B80214322EE7C3E00068002 /* JustInTime.hpp */,
|
||||
4B449C942063389900A095C8 /* TimeTypes.hpp */,
|
||||
4B644ED023F0FB55006C0CC5 /* ScanSynchroniser.hpp */,
|
||||
4B449C942063389900A095C8 /* TimeTypes.hpp */,
|
||||
4B996B2D2496DAC2001660EF /* VSyncPredictor.hpp */,
|
||||
);
|
||||
name = ClockReceiver;
|
||||
path = ../../ClockReceiver;
|
||||
@ -5137,6 +5139,7 @@
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
@ -5187,6 +5190,7 @@
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
|
@ -72,7 +72,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
[machine.delegate machine:machine led:[NSString stringWithUTF8String:name.c_str()] didChangeToLit:lit];
|
||||
}
|
||||
|
||||
void announce_drive_event(const std::string &name, DriveEvent event) final {
|
||||
void announce_drive_event(const std::string &name, DriveEvent) final {
|
||||
[machine.delegate machine:machine ledShouldBlink:[NSString stringWithUTF8String:name.c_str()]];
|
||||
}
|
||||
|
||||
@ -151,7 +151,6 @@ struct ActivityObserver: public Activity::Observer {
|
||||
MachineTypes::JoystickMachine *_joystickMachine;
|
||||
|
||||
CSJoystickManager *_joystickManager;
|
||||
std::bitset<65536> _depressedKeys;
|
||||
NSMutableArray<NSString *> *_leds;
|
||||
|
||||
CSHighPrecisionTimer *_timer;
|
||||
|
@ -13,7 +13,7 @@
|
||||
@implementation NSData (StdVector)
|
||||
|
||||
- (NSNumber *)crc32 {
|
||||
return @(crc32(crc32(0, Z_NULL, 0), self.bytes, (uInt)self.length));
|
||||
return @(crc32(crc32(0, Z_NULL, 0), self.bytes, (uInt)self.length));
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -29,6 +29,8 @@
|
||||
Analyser::Static::TargetList _targets;
|
||||
}
|
||||
|
||||
// MARK: - File-based Initialiser
|
||||
|
||||
- (instancetype)initWithFileAtURL:(NSURL *)url {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
@ -42,6 +44,55 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
// MARK: - Machine-based Initialisers
|
||||
|
||||
- (instancetype)initWithAmstradCPCModel:(CSMachineCPCModel)model {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::AmstradCPC::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
switch(model) {
|
||||
case CSMachineCPCModel464: target->model = Target::Model::CPC464; break;
|
||||
case CSMachineCPCModel664: target->model = Target::Model::CPC664; break;
|
||||
case CSMachineCPCModel6128: target->model = Target::Model::CPC6128; break;
|
||||
}
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAppleIIModel:(CSMachineAppleIIModel)model diskController:(CSMachineAppleIIDiskController)diskController {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::AppleII::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
switch(model) {
|
||||
default: target->model = Target::Model::II; break;
|
||||
case CSMachineAppleIIModelAppleIIPlus: target->model = Target::Model::IIplus; break;
|
||||
case CSMachineAppleIIModelAppleIIe: target->model = Target::Model::IIe; break;
|
||||
case CSMachineAppleIIModelAppleEnhancedIIe: target->model = Target::Model::EnhancedIIe; break;
|
||||
}
|
||||
switch(diskController) {
|
||||
default:
|
||||
case CSMachineAppleIIDiskControllerNone: target->disk_controller = Target::DiskController::None; break;
|
||||
case CSMachineAppleIIDiskControllerSixteenSector: target->disk_controller = Target::DiskController::SixteenSector; break;
|
||||
case CSMachineAppleIIDiskControllerThirteenSector: target->disk_controller = Target::DiskController::ThirteenSector; break;
|
||||
}
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAtariSTModel:(CSMachineAtariSTModel)model {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::AtariST::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithElectronDFS:(BOOL)dfs adfs:(BOOL)adfs {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
@ -54,16 +105,21 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAmstradCPCModel:(CSMachineCPCModel)model {
|
||||
- (instancetype)initWithMacintoshModel:(CSMachineMacintoshModel)model {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::AmstradCPC::Target;
|
||||
using Target = Analyser::Static::Macintosh::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
|
||||
using Model = Target::Model;
|
||||
switch(model) {
|
||||
case CSMachineCPCModel464: target->model = Analyser::Static::AmstradCPC::Target::Model::CPC464; break;
|
||||
case CSMachineCPCModel664: target->model = Analyser::Static::AmstradCPC::Target::Model::CPC664; break;
|
||||
case CSMachineCPCModel6128: target->model = Analyser::Static::AmstradCPC::Target::Model::CPC6128; break;
|
||||
default:
|
||||
case CSMachineMacintoshModel128k: target->model = Model::Mac128k; break;
|
||||
case CSMachineMacintoshModel512k: target->model = Model::Mac512k; break;
|
||||
case CSMachineMacintoshModel512ke: target->model = Model::Mac512ke; break;
|
||||
case CSMachineMacintoshModelPlus: target->model = Model::MacPlus; break;
|
||||
}
|
||||
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
@ -76,9 +132,9 @@
|
||||
auto target = std::make_unique<Target>();
|
||||
target->has_disk_drive = !!hasDiskDrive;
|
||||
switch(region) {
|
||||
case CSMachineMSXRegionAmerican: target->region = Analyser::Static::MSX::Target::Region::USA; break;
|
||||
case CSMachineMSXRegionEuropean: target->region = Analyser::Static::MSX::Target::Region::Europe; break;
|
||||
case CSMachineMSXRegionJapanese: target->region = Analyser::Static::MSX::Target::Region::Japan; break;
|
||||
case CSMachineMSXRegionAmerican: target->region = Target::Region::USA; break;
|
||||
case CSMachineMSXRegionEuropean: target->region = Target::Region::Europe; break;
|
||||
case CSMachineMSXRegionJapanese: target->region = Target::Region::Japan; break;
|
||||
}
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
@ -166,57 +222,7 @@ static Analyser::Static::ZX8081::Target::MemoryModel ZX8081MemoryModelFromSize(K
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAppleIIModel:(CSMachineAppleIIModel)model diskController:(CSMachineAppleIIDiskController)diskController {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::AppleII::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
switch(model) {
|
||||
default: target->model = Target::Model::II; break;
|
||||
case CSMachineAppleIIModelAppleIIPlus: target->model = Target::Model::IIplus; break;
|
||||
case CSMachineAppleIIModelAppleIIe: target->model = Target::Model::IIe; break;
|
||||
case CSMachineAppleIIModelAppleEnhancedIIe: target->model = Target::Model::EnhancedIIe; break;
|
||||
}
|
||||
switch(diskController) {
|
||||
default:
|
||||
case CSMachineAppleIIDiskControllerNone: target->disk_controller = Target::DiskController::None; break;
|
||||
case CSMachineAppleIIDiskControllerSixteenSector: target->disk_controller = Target::DiskController::SixteenSector; break;
|
||||
case CSMachineAppleIIDiskControllerThirteenSector: target->disk_controller = Target::DiskController::ThirteenSector; break;
|
||||
}
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithMacintoshModel:(CSMachineMacintoshModel)model {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::Macintosh::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
|
||||
using Model = Target::Model;
|
||||
switch(model) {
|
||||
default:
|
||||
case CSMachineMacintoshModel128k: target->model = Model::Mac128k; break;
|
||||
case CSMachineMacintoshModel512k: target->model = Model::Mac512k; break;
|
||||
case CSMachineMacintoshModel512ke: target->model = Model::Mac512ke; break;
|
||||
case CSMachineMacintoshModelPlus: target->model = Model::MacPlus; break;
|
||||
}
|
||||
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAtariSTModel:(CSMachineAtariSTModel)model {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::AtariST::Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
// MARK: - NIB mapping
|
||||
|
||||
- (NSString *)optionsPanelNibName {
|
||||
switch(_targets.front()->machine) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="16097" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16097"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@ -189,7 +189,7 @@ Gw
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Electron" identifier="electron" id="muc-z9-Vqc">
|
||||
<view key="view" id="SRc-2D-95G">
|
||||
<rect key="frame" x="10" y="33" width="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JqM-IK-FMP">
|
||||
@ -220,7 +220,7 @@ Gw
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Macintosh" identifier="mac" id="lmR-z3-xSm">
|
||||
<view key="view" id="7Yf-vi-Q0W">
|
||||
<rect key="frame" x="10" y="33" width="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZOY-4E-Cfl">
|
||||
@ -257,7 +257,7 @@ Gw
|
||||
</tabViewItem>
|
||||
<tabViewItem label="MSX" identifier="msx" id="6SR-DY-zdI">
|
||||
<view key="view" id="mWD-An-tR7">
|
||||
<rect key="frame" x="10" y="33" width="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8xT-Pr-8SE">
|
||||
@ -449,7 +449,7 @@ Gw
|
||||
</tabViewItem>
|
||||
<tabViewItem label="ZX80" identifier="zx80" id="tMH-kF-GUz">
|
||||
<view key="view" id="8hL-Vn-Hg0">
|
||||
<rect key="frame" x="10" y="33" width="604" height="94"/>
|
||||
<rect key="frame" x="10" y="33" width="674" height="94"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I1a-Eu-5UB">
|
||||
|
@ -67,7 +67,7 @@
|
||||
CVDisplayLinkStart(_displayLink);
|
||||
}
|
||||
|
||||
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) {
|
||||
static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, __unused CVOptionFlags flagsIn, __unused CVOptionFlags *flagsOut, void *displayLinkContext) {
|
||||
CSOpenGLView *const view = (__bridge CSOpenGLView *)displayLinkContext;
|
||||
|
||||
// Schedule an opportunity to check that the display link is still linked to the correct display.
|
||||
@ -298,7 +298,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
||||
if(!self.shouldCaptureMouse) {
|
||||
[_mouseHideTimer invalidate];
|
||||
|
||||
_mouseHideTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 repeats:NO block:^(NSTimer * _Nonnull timer) {
|
||||
_mouseHideTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 repeats:NO block:^(__unused NSTimer * _Nonnull timer) {
|
||||
[NSCursor setHiddenUntilMouseMoves:YES];
|
||||
[self.delegate openGLViewWillHideOSMouseCursor:self];
|
||||
}];
|
||||
|
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
@ -1137,7 +1137,7 @@
|
||||
|
||||
- (void)testMULU_Imm {
|
||||
self.machine->set_program({
|
||||
0xc4fc, 0xffff // MULU.W #$ffff, D2
|
||||
0xc4fc, 0xffff // MULU.W #$ffff, D2
|
||||
});
|
||||
auto state = self.machine->get_processor_state();
|
||||
state.data[2] = 0xffff;
|
||||
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
@ -110,7 +110,7 @@ class CPU::MC68000::ProcessorStorageTests {
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
_machine = std::make_unique<RAM68000>();
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
|
@ -105,15 +105,15 @@ class EmuTOS: public ComparativeBusHandler {
|
||||
|
||||
- (void)testImage:(NSString *)image trace:(NSString *)trace length:(int)length {
|
||||
const std::vector<ROMMachine::ROM> rom_names = {{"AtariST", "", image.UTF8String, 0, 0 }};
|
||||
const auto roms = CSROMFetcher()(rom_names);
|
||||
const auto roms = CSROMFetcher()(rom_names);
|
||||
NSString *const traceLocation = [[NSBundle bundleForClass:[self class]] pathForResource:trace ofType:@"trace.txt.gz"];
|
||||
_machine = std::make_unique<EmuTOS>(*roms[0], traceLocation.UTF8String);
|
||||
_machine->run_for(HalfCycles(length));
|
||||
_machine = std::make_unique<EmuTOS>(*roms[0], traceLocation.UTF8String);
|
||||
_machine->run_for(HalfCycles(length));
|
||||
}
|
||||
|
||||
- (void)testEmuTOSStartup {
|
||||
[self testImage:@"etos192uk.img" trace:@"etos192uk" length:313490];
|
||||
// TODO: assert that machine is now STOPped.
|
||||
// TODO: assert that machine is now STOPped.
|
||||
}
|
||||
|
||||
- (void)testTOSStartup {
|
||||
|
73
OSBindings/Qt/.gitignore
vendored
Normal file
73
OSBindings/Qt/.gitignore
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
261
OSBindings/Qt/ClockSignal.pro
Normal file
261
OSBindings/Qt/ClockSignal.pro
Normal file
@ -0,0 +1,261 @@
|
||||
QT += core gui multimedia widgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# Permit multiple source files in different directories to have the same file name.
|
||||
CONFIG += object_parallel_to_source
|
||||
|
||||
# Link against ZLib.
|
||||
INCLUDEPATH += $$[QT_INSTALL_PREFIX]/src/3rdparty/zlib
|
||||
LIBS += -lz
|
||||
|
||||
# Add flags (i) to identify that this is a Qt build; and
|
||||
# (ii) to disable asserts in release builds.
|
||||
DEFINES += TARGET_QT
|
||||
QMAKE_CXXFLAGS_RELEASE += -DNDEBUG
|
||||
|
||||
# Generate warnings for any use of APIs deprecated prior to Qt 6.0.0.
|
||||
# Development was performed against Qt 5.14.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000
|
||||
|
||||
SOURCES += \
|
||||
../../Analyser/Dynamic/*.cpp \
|
||||
../../Analyser/Dynamic/MultiMachine/*.cpp \
|
||||
../../Analyser/Dynamic/MultiMachine/Implementation/*.cpp \
|
||||
\
|
||||
../../Analyser/Static/*.cpp \
|
||||
../../Analyser/Static/Acorn/*.cpp \
|
||||
../../Analyser/Static/AmstradCPC/*.cpp \
|
||||
../../Analyser/Static/AppleII/*.cpp \
|
||||
../../Analyser/Static/Atari2600/*.cpp \
|
||||
../../Analyser/Static/AtariST/*.cpp \
|
||||
../../Analyser/Static/Coleco/*.cpp \
|
||||
../../Analyser/Static/Commodore/*.cpp \
|
||||
../../Analyser/Static/Disassembler/*.cpp \
|
||||
../../Analyser/Static/DiskII/*.cpp \
|
||||
../../Analyser/Static/Macintosh/*.cpp \
|
||||
../../Analyser/Static/MSX/*.cpp \
|
||||
../../Analyser/Static/Oric/*.cpp \
|
||||
../../Analyser/Static/Sega/*.cpp \
|
||||
../../Analyser/Static/ZX8081/*.cpp \
|
||||
\
|
||||
../../Components/1770/*.cpp \
|
||||
../../Components/5380/*.cpp \
|
||||
../../Components/6522/Implementation/*.cpp \
|
||||
../../Components/6560/*.cpp \
|
||||
../../Components/6850/*.cpp \
|
||||
../../Components/68901/*.cpp \
|
||||
../../Components/8272/*.cpp \
|
||||
../../Components/8530/*.cpp \
|
||||
../../Components/9918/*.cpp \
|
||||
../../Components/AudioToggle/*.cpp \
|
||||
../../Components/AY38910/*.cpp \
|
||||
../../Components/DiskII/*.cpp \
|
||||
../../Components/KonamiSCC/*.cpp \
|
||||
../../Components/OPx/*.cpp \
|
||||
../../Components/SN76489/*.cpp \
|
||||
../../Components/Serial/*.cpp \
|
||||
\
|
||||
../../Concurrency/*.cpp \
|
||||
\
|
||||
../../Inputs/*.cpp \
|
||||
\
|
||||
../../Machines/*.cpp \
|
||||
../../Machines/AmstradCPC/*.cpp \
|
||||
../../Machines/Apple/AppleII/*.cpp \
|
||||
../../Machines/Apple/Macintosh/*.cpp \
|
||||
../../Machines/Atari/2600/*.cpp \
|
||||
../../Machines/Atari/ST/*.cpp \
|
||||
../../Machines/ColecoVision/*.cpp \
|
||||
../../Machines/Commodore/*.cpp \
|
||||
../../Machines/Commodore/1540/Implementation/*.cpp \
|
||||
../../Machines/Commodore/Vic-20/*.cpp \
|
||||
../../Machines/Electron/*.cpp \
|
||||
../../Machines/MasterSystem/*.cpp \
|
||||
../../Machines/MSX/*.cpp \
|
||||
../../Machines/Oric/*.cpp \
|
||||
../../Machines/Utility/*.cpp \
|
||||
../../Machines/ZX8081/*.cpp \
|
||||
\
|
||||
../../Outputs/*.cpp \
|
||||
../../Outputs/CRT/*.cpp \
|
||||
../../Outputs/OpenGL/*.cpp \
|
||||
../../Outputs/OpenGL/Primitives/*.cpp \
|
||||
\
|
||||
../../Processors/6502/Implementation/*.cpp \
|
||||
../../Processors/6502/State/*.cpp \
|
||||
../../Processors/68000/Implementation/*.cpp \
|
||||
../../Processors/68000/State/*.cpp \
|
||||
../../Processors/Z80/Implementation/*.cpp \
|
||||
../../Processors/Z80/State/*.cpp \
|
||||
\
|
||||
../../Reflection/*.cpp \
|
||||
\
|
||||
../../SignalProcessing/*.cpp \
|
||||
\
|
||||
../../Storage/*.cpp \
|
||||
../../Storage/Cartridge/*.cpp \
|
||||
../../Storage/Cartridge/Encodings/*.cpp \
|
||||
../../Storage/Cartridge/Formats/*.cpp \
|
||||
../../Storage/Data/*.cpp \
|
||||
../../Storage/Disk/*.cpp \
|
||||
../../Storage/Disk/Controller/*.cpp \
|
||||
../../Storage/Disk/DiskImage/Formats/*.cpp \
|
||||
../../Storage/Disk/DiskImage/Formats/Utility/*.cpp \
|
||||
../../Storage/Disk/Encodings/*.cpp \
|
||||
../../Storage/Disk/Encodings/AppleGCR/*.cpp \
|
||||
../../Storage/Disk/Encodings/MFM/*.cpp \
|
||||
../../Storage/Disk/Parsers/*.cpp \
|
||||
../../Storage/Disk/Track/*.cpp \
|
||||
../../Storage/MassStorage/*.cpp \
|
||||
../../Storage/MassStorage/Encodings/*.cpp \
|
||||
../../Storage/MassStorage/Formats/*.cpp \
|
||||
../../Storage/MassStorage/SCSI/*.cpp \
|
||||
../../Storage/Tape/*.cpp \
|
||||
../../Storage/Tape/Formats/*.cpp \
|
||||
../../Storage/Tape/Parsers/*.cpp \
|
||||
\
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
scantargetwidget.cpp \
|
||||
timer.cpp
|
||||
|
||||
HEADERS += \
|
||||
../../Activity/*.hpp \
|
||||
\
|
||||
../../Analyser/*.hpp \
|
||||
../../Analyser/Dynamic/*.hpp \
|
||||
../../Analyser/Dynamic/MultiMachine/*.hpp \
|
||||
../../Analyser/Dynamic/MultiMachine/Implementation/*.hpp \
|
||||
\
|
||||
../../Analyser/Static/*.hpp \
|
||||
../../Analyser/Static/Acorn/*.hpp \
|
||||
../../Analyser/Static/AmstradCPC/*.hpp \
|
||||
../../Analyser/Static/AppleII/*.hpp \
|
||||
../../Analyser/Static/Atari2600/*.hpp \
|
||||
../../Analyser/Static/AtariST/*.hpp \
|
||||
../../Analyser/Static/Coleco/*.hpp \
|
||||
../../Analyser/Static/Commodore/*.hpp \
|
||||
../../Analyser/Static/Disassembler/*.hpp \
|
||||
../../Analyser/Static/DiskII/*.hpp \
|
||||
../../Analyser/Static/Macintosh/*.hpp \
|
||||
../../Analyser/Static/MSX/*.hpp \
|
||||
../../Analyser/Static/Oric/*.hpp \
|
||||
../../Analyser/Static/Sega/*.hpp \
|
||||
../../Analyser/Static/ZX8081/*.hpp \
|
||||
\
|
||||
../../ClockReceiver/*.hpp \
|
||||
\
|
||||
../../Components/1770/*.hpp \
|
||||
../../Components/5380/*.hpp \
|
||||
../../Components/6522/*.hpp \
|
||||
../../Components/6522/Implementation/*.hpp \
|
||||
../../Components/6532/*.hpp \
|
||||
../../Components/6560/*.hpp \
|
||||
../../Components/6845/*.hpp \
|
||||
../../Components/6850/*.hpp \
|
||||
../../Components/8255/*.hpp \
|
||||
../../Components/8272/*.hpp \
|
||||
../../Components/8530/*.hpp \
|
||||
../../Components/9918/*.hpp \
|
||||
../../Components/9918/Implementation/*.hpp \
|
||||
../../Components/68901/*.hpp \
|
||||
../../Components/AudioToggle/*.hpp \
|
||||
../../Components/AY38910/*.hpp \
|
||||
../../Components/DiskII/*.hpp \
|
||||
../../Components/KonamiSCC/*.hpp \
|
||||
../../Components/OPx/*.hpp \
|
||||
../../Components/OPx/Implementation/*.hpp \
|
||||
../../Components/Serial/*.hpp \
|
||||
../../Components/SN76489/*.hpp \
|
||||
\
|
||||
../../Concurrency/*.hpp \
|
||||
\
|
||||
../../Configurable/*.hpp \
|
||||
\
|
||||
../../Inputs/*.hpp \
|
||||
../../Inputs/QuadratureMouse/*.hpp \
|
||||
\
|
||||
../../Machines/*.hpp \
|
||||
../../Machines/AmstradCPC/*.hpp \
|
||||
../../Machines/Apple/AppleII/*.hpp \
|
||||
../../Machines/Apple/Macintosh/*.hpp \
|
||||
../../Machines/Atari/2600/*.hpp \
|
||||
../../Machines/Atari/ST/*.hpp \
|
||||
../../Machines/ColecoVision/*.hpp \
|
||||
../../Machines/Commodore/*.hpp \
|
||||
../../Machines/Commodore/1540/Implementation/*.hpp \
|
||||
../../Machines/Commodore/Vic-20/*.hpp \
|
||||
../../Machines/Electron/*.hpp \
|
||||
../../Machines/MasterSystem/*.hpp \
|
||||
../../Machines/MSX/*.hpp \
|
||||
../../Machines/Oric/*.hpp \
|
||||
../../Machines/Utility/*.hpp \
|
||||
../../Machines/ZX8081/*.hpp \
|
||||
\
|
||||
../../Numeric/*.hpp \
|
||||
\
|
||||
../../Outputs/*.hpp \
|
||||
../../Outputs/CRT/*.hpp \
|
||||
../../Outputs/CRT/Internals/*.hpp \
|
||||
../../Outputs/OpenGL/*.hpp \
|
||||
../../Outputs/OpenGL/Primitives/*.hpp \
|
||||
../../Outputs/Speaker/*.hpp \
|
||||
../../Outputs/Speaker/Implementation/*.hpp \
|
||||
\
|
||||
../../Processors/6502/*.hpp \
|
||||
../../Processors/6502/Implementation/*.hpp \
|
||||
../../Processors/6502/State/*.hpp \
|
||||
../../Processors/68000/*.hpp \
|
||||
../../Processors/68000/Implementation/*.hpp \
|
||||
../../Processors/68000/State/*.hpp \
|
||||
../../Processors/Z80/*.hpp \
|
||||
../../Processors/Z80/Implementation/*.hpp \
|
||||
../../Processors/Z80/State/*.hpp \
|
||||
\
|
||||
../../Reflection/*.hpp \
|
||||
\
|
||||
../../SignalProcessing/*.hpp \
|
||||
\
|
||||
../../Storage/*.hpp \
|
||||
../../Storage/Cartridge/*.hpp \
|
||||
../../Storage/Cartridge/Encodings/*.hpp \
|
||||
../../Storage/Cartridge/Formats/*.hpp \
|
||||
../../Storage/Data/*.hpp \
|
||||
../../Storage/Disk/*.hpp \
|
||||
../../Storage/Disk/Controller/*.hpp \
|
||||
../../Storage/Disk/DiskImage/*.hpp \
|
||||
../../Storage/Disk/DiskImage/Formats/*.hpp \
|
||||
../../Storage/Disk/DiskImage/Formats/Utility/*.hpp \
|
||||
../../Storage/Disk/DPLL/*.hpp \
|
||||
../../Storage/Disk/Encodings/*.hpp \
|
||||
../../Storage/Disk/Encodings/AppleGCR/*.hpp \
|
||||
../../Storage/Disk/Encodings/MFM/*.hpp \
|
||||
../../Storage/Disk/Parsers/*.hpp \
|
||||
../../Storage/Disk/Track/*.hpp \
|
||||
../../Storage/MassStorage/*.hpp \
|
||||
../../Storage/MassStorage/Encodings/*.hpp \
|
||||
../../Storage/MassStorage/Formats/*.hpp \
|
||||
../../Storage/MassStorage/SCSI/*.hpp \
|
||||
../../Storage/Tape/*.hpp \
|
||||
../../Storage/Tape/Formats/*.hpp \
|
||||
../../Storage/Tape/Parsers/*.hpp \
|
||||
\
|
||||
audiobuffer.h \
|
||||
functionthread.h \
|
||||
mainwindow.h \
|
||||
scantargetwidget.h \
|
||||
settings.h \
|
||||
timer.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
TRANSLATIONS += \
|
||||
ClockSignal_en_GB.ts
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
3
OSBindings/Qt/ClockSignal_en_GB.ts
Normal file
3
OSBindings/Qt/ClockSignal_en_GB.ts
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="ClockSignal_en_GB"></TS>
|
95
OSBindings/Qt/audiobuffer.h
Normal file
95
OSBindings/Qt/audiobuffer.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef AUDIOSOURCE_H
|
||||
#define AUDIOSOURCE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
/*!
|
||||
* \brief Provides an intermediate receipticle for audio data.
|
||||
*
|
||||
* Provides a QIODevice that will attempt to buffer the minimum amount
|
||||
* of data before handing it off to a polling QAudioOutput.
|
||||
*
|
||||
* Adding an extra buffer increases worst-case latency but resolves a
|
||||
* startup race condition in which it is difficult to tell how much data a
|
||||
* QAudioOutput that is populated by pushing data currently has buffered;
|
||||
* it also works around what empirically seemed to be a minimum 16384-byte
|
||||
* latency on push audio generation.
|
||||
*/
|
||||
struct AudioBuffer: public QIODevice {
|
||||
AudioBuffer() {
|
||||
open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
||||
}
|
||||
|
||||
void setDepth(size_t depth) {
|
||||
std::lock_guard lock(mutex);
|
||||
buffer.resize(depth);
|
||||
}
|
||||
|
||||
// AudioBuffer-specific behaviour: always provide the latest data,
|
||||
// even if that means skipping some.
|
||||
qint64 readData(char *data, const qint64 maxlen) override {
|
||||
if(!maxlen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
if(readPointer == writePointer || buffer.empty()) return 0;
|
||||
|
||||
const size_t dataAvailable = std::min(writePointer - readPointer, size_t(maxlen));
|
||||
size_t bytesToCopy = dataAvailable;
|
||||
while(bytesToCopy) {
|
||||
const size_t nextLength = std::min(buffer.size() - (readPointer % buffer.size()), bytesToCopy);
|
||||
memcpy(data, &buffer[readPointer % buffer.size()], nextLength);
|
||||
|
||||
bytesToCopy -= nextLength;
|
||||
data += nextLength;
|
||||
readPointer += nextLength;
|
||||
}
|
||||
|
||||
return qint64(dataAvailable);
|
||||
}
|
||||
|
||||
qint64 bytesAvailable() const override {
|
||||
std::lock_guard lock(mutex);
|
||||
return qint64(writePointer - readPointer);
|
||||
}
|
||||
|
||||
// Required to make QIODevice concrete; not used.
|
||||
qint64 writeData(const char *, qint64) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Posts a new set of source data. This buffer permits only the amount of data
|
||||
// specified by @c setDepth to be enqueued into the future. Additional writes
|
||||
// after the buffer is full will overwrite the newest data.
|
||||
void write(const std::vector<int16_t> &source) {
|
||||
std::lock_guard lock(mutex);
|
||||
if(buffer.empty()) return;
|
||||
const size_t sourceSize = source.size() * sizeof(int16_t);
|
||||
|
||||
size_t bytesToCopy = sourceSize;
|
||||
auto data = reinterpret_cast<const uint8_t *>(source.data());
|
||||
while(bytesToCopy) {
|
||||
size_t nextLength = std::min(buffer.size() - (writePointer % buffer.size()), bytesToCopy);
|
||||
memcpy(&buffer[writePointer % buffer.size()], data, nextLength);
|
||||
|
||||
bytesToCopy -= nextLength;
|
||||
data += nextLength;
|
||||
writePointer += nextLength;
|
||||
}
|
||||
|
||||
readPointer = std::max(readPointer, writePointer - buffer.size());
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex mutex;
|
||||
std::vector<uint8_t> buffer;
|
||||
mutable size_t readPointer = 0;
|
||||
size_t writePointer = 0;
|
||||
};
|
||||
|
||||
#endif // AUDIOSOURCE_H
|
91
OSBindings/Qt/functionthread.h
Normal file
91
OSBindings/Qt/functionthread.h
Normal file
@ -0,0 +1,91 @@
|
||||
#ifndef FUNCTIONTHREAD_H
|
||||
#define FUNCTIONTHREAD_H
|
||||
|
||||
#include <atomic>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QEvent>
|
||||
#include <QThread>
|
||||
|
||||
/*!
|
||||
* \brief The LambdaThread class
|
||||
*
|
||||
* Provides a QThread to which lambdas can be posted.
|
||||
*
|
||||
* Disclaimer: this might be a crutch that reveals a misunderstanding of the Qt
|
||||
* threading infrastructure. We'll see.
|
||||
*/
|
||||
class FunctionThread: public QThread {
|
||||
public:
|
||||
~FunctionThread() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void run() override {
|
||||
// Gymnastics here: events posted directly to the QThread will occur on the thread
|
||||
// that created the QThread. To have events occur within a QThread, they have to be
|
||||
// posted to an object created on that thread. FunctionPerformer fills that role.
|
||||
if(!performer) performer = std::make_unique<FunctionPerformer>();
|
||||
performerFlag.clear();
|
||||
exec();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
if(isRunning()) {
|
||||
performAsync([this] {
|
||||
this->quit();
|
||||
});
|
||||
}
|
||||
wait();
|
||||
}
|
||||
|
||||
void start() {
|
||||
if(isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: I've assumed a race condition here with the creation of performer; if QThread
|
||||
// blocks on completion of `run` when starting then this is redundant.
|
||||
performerFlag.test_and_set();
|
||||
QThread::start();
|
||||
while(performerFlag.test_and_set());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Schedules a function to be performed on this thread. Control
|
||||
* must return to the main event loop for the function to be performed;
|
||||
* use QCoreApplication::sendPostedEvents() to ensure the function is
|
||||
* performed before then, if required.
|
||||
*
|
||||
* \param function The function to perform.
|
||||
*/
|
||||
void performAsync(const std::function<void(void)> &function) {
|
||||
QApplication::instance()->postEvent(performer.get(), new FunctionEvent(function));
|
||||
QCoreApplication::sendPostedEvents();
|
||||
}
|
||||
|
||||
private:
|
||||
struct FunctionEvent: public QEvent {
|
||||
FunctionEvent(const std::function<void(void)> &function) : QEvent(QEvent::Type::User), function(function) {}
|
||||
std::function<void(void)> function;
|
||||
};
|
||||
|
||||
struct FunctionPerformer: public QObject {
|
||||
FunctionPerformer(): QObject() {}
|
||||
|
||||
bool event(QEvent *event) override {
|
||||
if(event->type() == QEvent::Type::User) {
|
||||
const auto functionEvent = dynamic_cast<FunctionEvent *>(event);
|
||||
if(functionEvent) {
|
||||
functionEvent->function();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QObject::event(event);
|
||||
}
|
||||
};
|
||||
std::unique_ptr<FunctionPerformer> performer;
|
||||
std::atomic_flag performerFlag;
|
||||
};
|
||||
|
||||
#endif // FUNCTIONTHREAD_H
|
26
OSBindings/Qt/main.cpp
Normal file
26
OSBindings/Qt/main.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// "Calling QSurfaceFormat::setDefaultFormat() before constructing the
|
||||
// QApplication instance is mandatory on some platforms ... when an
|
||||
// OpenGL core profile context is requested."
|
||||
QSurfaceFormat format;
|
||||
format.setVersion(3, 2);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setDepthBufferSize(0);
|
||||
format.setStencilBufferSize(0);
|
||||
QSurfaceFormat::setDefaultFormat(format);
|
||||
|
||||
// TODO: something with QCommandLineParser to accept a file to launch.
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
MainWindow *w = new MainWindow();
|
||||
w->setAttribute(Qt::WA_DeleteOnClose);
|
||||
w->show();
|
||||
|
||||
return a.exec();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user