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

Merge pull request #634 from TomHarte/OpenCrash

Resolves a potential crash at launch on the Mac
This commit is contained in:
Thomas Harte 2019-07-31 14:11:58 -04:00 committed by GitHub
commit 1ae3799aee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 11 deletions

View File

@ -23,13 +23,14 @@ DoubleDensityDrive::DoubleDensityDrive(int input_clock_rate, bool is_800k) :
is_800k_(is_800k) { is_800k_(is_800k) {
// Start with a valid rotation speed. // Start with a valid rotation speed.
if(is_800k) { if(is_800k) {
set_rotation_speed(393.3807f); Drive::set_rotation_speed(393.3807f);
} }
} }
// MARK: - Speed Selection // MARK: - Speed Selection
void DoubleDensityDrive::did_step(Storage::Disk::HeadPosition to_position) { void DoubleDensityDrive::did_step(Storage::Disk::HeadPosition to_position) {
// printf("At track %d\n", to_position.as_int());
// The 800kb drive automatically selects rotation speed as a function of // The 800kb drive automatically selects rotation speed as a function of
// head position; the 400kb drive doesn't do so. // head position; the 400kb drive doesn't do so.
if(is_800k_) { if(is_800k_) {
@ -51,15 +52,23 @@ void DoubleDensityDrive::did_step(Storage::Disk::HeadPosition to_position) {
*/ */
const int zone = to_position.as_int() >> 4; const int zone = to_position.as_int() >> 4;
switch(zone) { switch(zone) {
case 0: set_rotation_speed(393.3807f); break; case 0: Drive::set_rotation_speed(393.3807f); break;
case 1: set_rotation_speed(429.1723f); break; case 1: Drive::set_rotation_speed(429.1723f); break;
case 2: set_rotation_speed(472.1435f); break; case 2: Drive::set_rotation_speed(472.1435f); break;
case 3: set_rotation_speed(524.5672f); break; case 3: Drive::set_rotation_speed(524.5672f); break;
default: set_rotation_speed(590.1098f); break; default: Drive::set_rotation_speed(590.1098f); break;
} }
} }
} }
void DoubleDensityDrive::set_rotation_speed(float revolutions_per_minute) {
if(!is_800k_) {
// Don't allow drive speeds to drop below 10 RPM, as a temporary sop
// to sanity.
Drive::set_rotation_speed(std::max(10.0f, revolutions_per_minute));
}
}
// MARK: - Control input/output. // MARK: - Control input/output.
void DoubleDensityDrive::set_enabled(bool) { void DoubleDensityDrive::set_enabled(bool) {

View File

@ -18,6 +18,20 @@ class DoubleDensityDrive: public IWMDrive {
public: public:
DoubleDensityDrive(int input_clock_rate, bool is_800k); DoubleDensityDrive(int input_clock_rate, bool is_800k);
/*!
@returns @c true if this is an 800kb drive; @c false otherwise.
*/
bool is_800k() {
return is_800k_;
}
/*!
Sets the current rotation speed of this drive only if it is a 400kb drive.
800kb drives select their own rotation speed based on head position,
and ignore this input.
*/
void set_rotation_speed(float revolutions_per_minute);
void set_enabled(bool) override; void set_enabled(bool) override;
void set_control_lines(int) override; void set_control_lines(int) override;
bool read() override; bool read() override;

View File

@ -11,6 +11,8 @@
using namespace Apple::Macintosh; using namespace Apple::Macintosh;
void DriveSpeedAccumulator::post_sample(uint8_t sample) { void DriveSpeedAccumulator::post_sample(uint8_t sample) {
if(!number_of_drives_) return;
// An Euler-esque approximation is used here: just collect all // An Euler-esque approximation is used here: just collect all
// the samples until there is a certain small quantity of them, // the samples until there is a certain small quantity of them,
// then produce a new estimate of rotation speed and start the // then produce a new estimate of rotation speed and start the
@ -20,9 +22,31 @@ void DriveSpeedAccumulator::post_sample(uint8_t sample) {
if(sample_pointer_ == samples_.size()) { if(sample_pointer_ == samples_.size()) {
sample_pointer_ = 0; sample_pointer_ = 0;
// for(int c = 0; c < 512; c += 32) {
// printf("%u ", samples_[c]); // Treat 33 as a zero point and count zero crossings; then approximate
// } // the RPM from the frequency of those.
// printf("\n"); int samples_over = 0;
int sum = 0;
const uint8_t centre = 33;
for(size_t c = 0; c < 512; ++c) {
if(samples_[c] > centre) ++ samples_over;
sum += samples_[c];
}
// TODO: if the above is the correct test, do it on sample receipt rather than
// bothering with an intermediate buffer.
// The below fits for a function like `a + bc`.
const float rotation_speed = (float(sum) * 0.052896440564137f) - 259.0f;
for(int c = 0; c < number_of_drives_; ++c) {
drives_[c]->set_rotation_speed(rotation_speed);
}
// printf("RPM: %0.2f (%d over; %d sum)\n", rotation_speed, samples_over, sum);
} }
} }
void DriveSpeedAccumulator::add_drive(Apple::Macintosh::DoubleDensityDrive *drive) {
drives_[number_of_drives_] = drive;
++number_of_drives_;
}

View File

@ -13,6 +13,8 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include "../../../Components/DiskII/MacintoshDoubleDensityDrive.hpp"
namespace Apple { namespace Apple {
namespace Macintosh { namespace Macintosh {
@ -23,9 +25,18 @@ class DriveSpeedAccumulator {
*/ */
void post_sample(uint8_t sample); void post_sample(uint8_t sample);
/*!
Adds a connected drive. Up to two of these
can be supplied. Only Macintosh DoubleDensityDrives
are supported.
*/
void add_drive(Apple::Macintosh::DoubleDensityDrive *drive);
private: private:
std::array<uint8_t, 512> samples_; std::array<uint8_t, 512> samples_;
std::size_t sample_pointer_ = 0; std::size_t sample_pointer_ = 0;
Apple::Macintosh::DoubleDensityDrive *drives_[2] = {nullptr, nullptr};
int number_of_drives_ = 0;
}; };
} }

View File

@ -116,6 +116,10 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
iwm_.iwm.set_drive(0, &drives_[0]); iwm_.iwm.set_drive(0, &drives_[0]);
iwm_.iwm.set_drive(1, &drives_[1]); iwm_.iwm.set_drive(1, &drives_[1]);
// If they are 400kb drives, also attach them to the drive-speed accumulator.
if(!drives_[0].is_800k()) drive_speed_accumulator_.add_drive(&drives_[0]);
if(!drives_[1].is_800k()) drive_speed_accumulator_.add_drive(&drives_[1]);
// Make sure interrupt changes from the SCC are observed. // Make sure interrupt changes from the SCC are observed.
scc_.set_delegate(this); scc_.set_delegate(this);

View File

@ -56,7 +56,16 @@ class MachineDocument:
override func windowControllerDidLoadNib(_ aController: NSWindowController) { override func windowControllerDidLoadNib(_ aController: NSWindowController) {
super.windowControllerDidLoadNib(aController) super.windowControllerDidLoadNib(aController)
aController.window?.contentAspectRatio = self.aspectRatio() aController.window?.contentAspectRatio = self.aspectRatio()
if self.machine != nil {
setupMachineOutput() setupMachineOutput()
} else {
// This is somewhat of a desperate workaround; just having loaded the Nib doesn't
// mean that the window is visible yet, but presenting the ROM import sheet before
// the window is visible will result in it being free floating.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(500)) {
self.configureAs(self.selectedMachine!)
}
}
} }
// Attempting to show a sheet before the window is visible (such as when the NIB is loaded) results in // Attempting to show a sheet before the window is visible (such as when the NIB is loaded) results in
@ -340,6 +349,11 @@ class MachineDocument:
@IBOutlet var romReceiverView: CSROMReceiverView? @IBOutlet var romReceiverView: CSROMReceiverView?
private var romRequestBaseText = "" private var romRequestBaseText = ""
func requestRoms() { func requestRoms() {
// Don't act yet if there's no window controller yet.
if self.windowControllers.count == 0 {
return
}
// Load the ROM requester dialogue. // Load the ROM requester dialogue.
Bundle.main.loadNibNamed("ROMRequester", owner: self, topLevelObjects: nil) Bundle.main.loadNibNamed("ROMRequester", owner: self, topLevelObjects: nil)
self.romReceiverView!.delegate = self self.romReceiverView!.delegate = self