1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-10 22:37:30 +00:00

Merge pull request #630 from TomHarte/IWMWrites

Makes various fixes to `Drive` and `Track`.
This commit is contained in:
Thomas Harte 2019-07-26 23:41:20 -04:00 committed by GitHub
commit 4033c0c754
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 22 deletions

View File

@ -54,8 +54,8 @@
*/
template <class T> class WrappedInt {
public:
forceinline constexpr WrappedInt(int l) : length_(l) {}
forceinline constexpr WrappedInt() : length_(0) {}
forceinline constexpr WrappedInt(int l) noexcept : length_(l) {}
forceinline constexpr WrappedInt() noexcept : length_(0) {}
forceinline T &operator =(const T &rhs) {
length_ = rhs.length_;
@ -165,19 +165,19 @@ template <class T> class WrappedInt {
/// Describes an integer number of whole cycles: pairs of clock signal transitions.
class Cycles: public WrappedInt<Cycles> {
public:
forceinline constexpr Cycles(int l) : WrappedInt<Cycles>(l) {}
forceinline constexpr Cycles() : WrappedInt<Cycles>() {}
forceinline constexpr Cycles(const Cycles &cycles) : WrappedInt<Cycles>(cycles.length_) {}
forceinline constexpr Cycles(int l) noexcept : WrappedInt<Cycles>(l) {}
forceinline constexpr Cycles() noexcept : WrappedInt<Cycles>() {}
forceinline constexpr Cycles(const Cycles &cycles) noexcept : WrappedInt<Cycles>(cycles.length_) {}
};
/// Describes an integer number of half cycles: single clock signal transitions.
class HalfCycles: public WrappedInt<HalfCycles> {
public:
forceinline constexpr HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
forceinline constexpr HalfCycles() : WrappedInt<HalfCycles>() {}
forceinline constexpr HalfCycles(int l) noexcept : WrappedInt<HalfCycles>(l) {}
forceinline constexpr HalfCycles() noexcept : WrappedInt<HalfCycles>() {}
forceinline constexpr HalfCycles(const Cycles cycles) : WrappedInt<HalfCycles>(cycles.as_int() * 2) {}
forceinline constexpr HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
forceinline constexpr HalfCycles(const Cycles cycles) noexcept : WrappedInt<HalfCycles>(cycles.as_int() * 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 {

View File

@ -97,7 +97,7 @@ class IWM:
void propose_shift(uint8_t bit);
Cycles cycles_since_shift_;
Cycles bit_length_;
Cycles bit_length_ = Cycles(16);
void push_drive_state();

View File

@ -22,6 +22,7 @@
#include "../../MouseMachine.hpp"
#include "../../../Inputs/QuadratureMouse/QuadratureMouse.hpp"
#include "../../../Outputs/Log.hpp"
//#define LOG_TRACE
@ -288,10 +289,10 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
default:
if(cycle.operation & Microcycle::Read) {
printf("Unrecognised read %06x\n", *cycle.address & 0xffffff);
LOG("Unrecognised read " << PADHEX(6) << (*cycle.address & 0xffffff));
cycle.value->halves.low = 0x00;
} else {
printf("Unrecognised write %06x\n", *cycle.address & 0xffffff);
LOG("Unrecognised write %06x" << PADHEX(6) << (*cycle.address & 0xffffff));
}
break;
}
@ -560,7 +561,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
if(port == Port::B && line == Line::Two) {
keyboard_.set_input(value);
}
else printf("Unhandled control line output: %c %d\n", port ? 'B' : 'A', int(line));
else LOG("Unhandled control line output: " << (port ? 'B' : 'A') << int(line));
}
void run_for(HalfCycles duration) {

View File

@ -3013,7 +3013,7 @@ struct ProcessorStorageConstructor {
}
if(storage_.all_micro_ops_[index].is_terminal()) {
storage_.all_micro_ops_[index].bus_program = seq("");
storage_.all_micro_ops_[index].bus_program = uint16_t(seq(""));
}
}
@ -3259,10 +3259,10 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
// Complete linkage of the exception micro program.
short_exception_micro_ops_ = &all_micro_ops_[short_exception_offset];
short_exception_micro_ops_->bus_program = trap_offset;
short_exception_micro_ops_->bus_program = uint16_t(trap_offset);
long_exception_micro_ops_ = &all_micro_ops_[long_exception_offset];
long_exception_micro_ops_->bus_program = bus_error_offset;
long_exception_micro_ops_->bus_program = uint16_t(bus_error_offset);
// Set initial state.
active_step_ = reset_bus_steps_;

View File

@ -38,9 +38,15 @@ Drive::Drive(int input_clock_rate, int revolutions_per_minute, int number_of_hea
Drive::Drive(int input_clock_rate, int number_of_heads) : Drive(input_clock_rate, 300, number_of_heads) {}
void Drive::set_rotation_speed(float revolutions_per_minute) {
// TODO: probably I should look into
// whether doing all this with quotients is really a good idea.
rotational_multiplier_ = 60.0f / revolutions_per_minute;
// Rationalise the supplied speed so that cycles_per_revolution_ is exact.
cycles_per_revolution_ = int(0.5f + float(get_input_clock_rate()) * 60.0f / revolutions_per_minute);
// From there derive the appropriate rotational multiplier and possibly update the
// count of cycles since the index hole proportionally.
const float new_rotational_multiplier = float(cycles_per_revolution_) / float(get_input_clock_rate());
cycles_since_index_hole_ *= new_rotational_multiplier / rotational_multiplier_;
rotational_multiplier_ = new_rotational_multiplier;
cycles_since_index_hole_ %= cycles_per_revolution_;
}
Drive::~Drive() {
@ -296,6 +302,10 @@ void Drive::setup_track() {
offset = track_time_now - time_found;
}
// Reseed cycles_since_index_hole_; 99.99% of the time it'll still be correct as is,
// but if the track has rounded one way or the other it may now be very slightly adrift.
cycles_since_index_hole_ = (int((time_found + offset) * cycles_per_revolution_)) % cycles_per_revolution_;
get_next_event(offset);
}
@ -340,7 +350,10 @@ void Drive::write_bit(bool value) {
void Drive::end_writing() {
// If the user modifies a track, it's scaled up to a "high" resolution and modifications
// are plotted on top of that.
const size_t high_resolution_track_rate = 500000;
//
// "High" is defined as: two samples per clock relative to an idiomatic
// 8Mhz disk controller and 300RPM disk speed.
const size_t high_resolution_track_rate = 3200000;
if(!is_reading_) {
is_reading_ = true;
@ -354,7 +367,7 @@ void Drive::end_writing() {
}
}
patched_track_->add_segment(write_start_time_, write_segment_, clamp_writing_to_index_hole_);
cycles_since_index_hole_ %= get_input_clock_rate();
cycles_since_index_hole_ %= cycles_per_revolution_;
invalidate_track();
}
}

View File

@ -198,6 +198,10 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
// a new track.
int cycles_since_index_hole_ = 0;
// The number of cycles that should fall within one revolution at the
// current rotation speed.
int cycles_per_revolution_ = 1;
// A record of head position and active head.
HeadPosition head_position_;
int head_ = 0;

View File

@ -80,6 +80,8 @@ Storage::Disk::PCMSegment six_and_two_sync(int length);
/*!
Produces the data section of a five-and-three format sector; the segment returned
will be 3,336 bits long, encoding the first 256 bytes from @c source.
(TODO).
*/
Storage::Disk::PCMSegment five_and_three_data(const uint8_t *source);

View File

@ -264,7 +264,7 @@ struct Time {
// If the mantissa is negative and its absolute value fits within a 64-bit integer,
// just load up.
if(relative_exponent <= 0 && relative_exponent > -64) {
install_result(loaded_mantissa, uint64_t(1 << -relative_exponent));
install_result(loaded_mantissa, uint64_t(1) << -relative_exponent);
return;
}