1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +00:00

Rejigs time-until-event tracking.

This commit is contained in:
Thomas Harte 2019-07-09 23:27:27 -04:00
parent ed4ddcfda8
commit 886946cc8c
5 changed files with 85 additions and 26 deletions

View File

@ -101,6 +101,14 @@ class QuadratureMouse: public Mouse {
return button_flags_;
}
/*!
@returns @c true if any mouse motion is waiting to be communicated;
@c false otherwise.
*/
bool has_steps() {
return axes_[0] || axes_[1];
}
private:
int number_of_buttons_ = 0;
std::atomic<int> button_flags_;

View File

@ -147,16 +147,18 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
// See: Guide to the Macintosh Hardware Family p149 (PDF p188). Some extra division
// may occur here in order to provide VSYNC at a proper moment.
// Possibly route vsync.
if(time_until_video_event_ >= cycle.length) {
if(time_since_video_update_ < time_until_video_event_) {
via_clock_ += cycle.length;
via_.run_for(via_clock_.divide(HalfCycles(10)));
time_until_video_event_ -= cycle.length;
} else {
auto cycles_to_progress = cycle.length;
while(time_until_video_event_ < cycles_to_progress) {
cycles_to_progress -= time_until_video_event_;
auto via_time_base = time_since_video_update_ - cycle.length;
auto via_cycles_outstanding = cycle.length;
while(time_until_video_event_ < time_since_video_update_) {
const auto via_cycles = time_until_video_event_ - via_time_base;
via_time_base = HalfCycles(0);
via_cycles_outstanding -= via_cycles;
via_clock_ += time_until_video_event_;
via_clock_ += via_cycles;
via_.run_for(via_clock_.divide(HalfCycles(10)));
video_.run_for(time_until_video_event_);
@ -166,9 +168,8 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !video_.vsync());
}
via_clock_ += cycles_to_progress;
via_clock_ += via_cycles_outstanding;
via_.run_for(via_clock_.divide(HalfCycles(10)));
time_until_video_event_ -= cycles_to_progress;
}
// The keyboard also has a clock, albeit a very slow one — 100,000 cycles/second.
@ -182,12 +183,14 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
}
// Feed mouse inputs within at most 1250 cycles of each other.
time_since_mouse_update_ += cycle.length;
const auto mouse_ticks = time_since_mouse_update_.divide(HalfCycles(2500));
if(mouse_ticks > HalfCycles(0)) {
mouse_.prepare_step();
scc_.set_dcd(0, mouse_.get_channel(1) & 1);
scc_.set_dcd(1, mouse_.get_channel(0) & 1);
if(mouse_.has_steps()) {
time_since_mouse_update_ += cycle.length;
const auto mouse_ticks = time_since_mouse_update_.divide(HalfCycles(2500));
if(mouse_ticks > HalfCycles(0)) {
mouse_.prepare_step();
scc_.set_dcd(0, mouse_.get_channel(1) & 1);
scc_.set_dcd(1, mouse_.get_channel(0) & 1);
}
}
// TODO: SCC should be clocked at a divide-by-two, if and when it actually has
@ -438,8 +441,8 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
struct IWM {
IWM(int clock_rate) : iwm(clock_rate) {}
Apple::IWM iwm;
HalfCycles time_since_update;
Apple::IWM iwm;
void flush() {
iwm.run_for(time_since_update.flush_cycles());

View File

@ -54,10 +54,10 @@ void Video::run_for(HalfCycles duration) {
// since pixel output occurs at twice the processor clock. So divide by 16 to get
// the number of fetches.
while(duration > HalfCycles(0)) {
auto cycles_left_in_line = std::min(line_length - frame_position_%line_length, duration);
const int line = (frame_position_ / line_length).as_int();
const auto pixel_start = frame_position_ % line_length;
const int line = (frame_position_ / line_length).as_int();
const auto cycles_left_in_line = std::min(line_length - pixel_start, duration);
// Line timing, entirely invented as I can find exactly zero words of documentation:
//
@ -119,16 +119,14 @@ void Video::run_for(HalfCycles duration) {
if(first_word < sync_start && final_word >= sync_start) crt_.output_blank((sync_start - 32) * 16);
if(first_word < sync_end && final_word >= sync_end) crt_.output_sync((sync_end - sync_start) * 16);
if(final_word == 44) crt_.output_blank((44 - sync_end) * 16);
} else if(line >= 353 && line < 356) {
/* Output a sync line. */
if(final_word == 44) {
} else if(final_word == 44) {
if(line >= 353 && line < 356) {
/* Output a sync line. */
crt_.output_sync(sync_start * 16);
crt_.output_blank((sync_end - sync_start) * 16);
crt_.output_sync((44 - sync_end) * 16);
}
} else {
/* Output a blank line. */
if(final_word == 44) {
} else {
/* Output a blank line. */
crt_.output_blank(sync_start * 16);
crt_.output_sync((sync_end - sync_start) * 16);
crt_.output_blank((44 - sync_end) * 16);
@ -172,7 +170,7 @@ HalfCycles Video::get_next_sequence_point() {
if(line >= 353 && line < 356) {
// Currently in vsync, so get time until start of line 357,
// when vsync will end.
return HalfCycles(357) * line_length - frame_position_;
return HalfCycles(356) * line_length - frame_position_;
} else {
// Not currently in vsync, so get time until start of line 353.
const auto start_of_vsync = HalfCycles(353) * line_length;

View File

@ -671,6 +671,7 @@
4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; };
4BE76CF922641ED400ACD6FA /* QLTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BE76CF822641ED300ACD6FA /* QLTests.mm */; };
4BE7C9181E3D397100A5496D /* TIA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE7C9161E3D397100A5496D /* TIA.cpp */; };
4BE90FFD22D5864800FB464D /* MacintoshVideoTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BE90FFC22D5864800FB464D /* MacintoshVideoTests.mm */; };
4BE9A6B11EDE293000CBCB47 /* zexdoc.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BE9A6B01EDE293000CBCB47 /* zexdoc.com */; };
4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA525D1DF33323007E74F2 /* Tape.cpp */; };
4BEA52631DF339D7007E74F2 /* SoundGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52611DF339D7007E74F2 /* SoundGenerator.cpp */; };
@ -1485,6 +1486,7 @@
4BE7C9161E3D397100A5496D /* TIA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cpp; sourceTree = "<group>"; };
4BE7C9171E3D397100A5496D /* TIA.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIA.hpp; sourceTree = "<group>"; };
4BE845201F2FF7F100A5EA22 /* CRTC6845.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRTC6845.hpp; path = 6845/CRTC6845.hpp; sourceTree = "<group>"; };
4BE90FFC22D5864800FB464D /* MacintoshVideoTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MacintoshVideoTests.mm; sourceTree = "<group>"; };
4BE9A6B01EDE293000CBCB47 /* zexdoc.com */ = {isa = PBXFileReference; lastKnownFileType = file; name = zexdoc.com; path = Zexall/zexdoc.com; sourceTree = "<group>"; };
4BEA525D1DF33323007E74F2 /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = Electron/Tape.cpp; sourceTree = "<group>"; };
4BEA525F1DF333D8007E74F2 /* Tape.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = Electron/Tape.hpp; sourceTree = "<group>"; };
@ -2960,6 +2962,7 @@
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */,
4BEE1EBF22B5E236000A26A6 /* MacGCRTests.mm */,
4BE90FFC22D5864800FB464D /* MacintoshVideoTests.mm */,
4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */,
4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */,
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
@ -4255,6 +4258,7 @@
4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */,
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
4BEE1EC022B5E236000A26A6 /* MacGCRTests.mm in Sources */,
4BE90FFD22D5864800FB464D /* MacintoshVideoTests.mm in Sources */,
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
4B322E011F5A2990004EB04C /* Z80AllRAM.cpp in Sources */,

View File

@ -0,0 +1,46 @@
//
// MacintoshVideoTests.m
// Clock SignalTests
//
// Created by Thomas Harte on 09/07/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#import <XCTest/XCTest.h>
#include <memory>
#include "../../../Machines/Apple/Macintosh/Video.hpp"
@interface MacintoshVideoTests : XCTestCase
@end
@implementation MacintoshVideoTests {
Apple::Macintosh::DeferredAudio _dummy_audio;
Apple::Macintosh::DriveSpeedAccumulator _dummy_drive_speed_accumulator;
std::unique_ptr<Apple::Macintosh::Video> _video;
uint16_t _ram[64*1024];
}
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
_video.reset(new Apple::Macintosh::Video(_ram, _dummy_audio, _dummy_drive_speed_accumulator));
}
- (void)testPrediction {
int c = 5;
bool vsync = _video->vsync();
while(c--) {
int remaining_time_in_state = _video->get_next_sequence_point().as_int();
NSLog(@"Vsync %@ expected for %@ half-cycles", vsync ? @"on" : @"off", @(remaining_time_in_state));
while(remaining_time_in_state--) {
XCTAssertEqual(vsync, _video->vsync());
_video->run_for(HalfCycles(1));
if(remaining_time_in_state)
XCTAssertEqual(remaining_time_in_state, _video->get_next_sequence_point().as_int());
}
vsync ^= true;
}
}
@end