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:
parent
ed4ddcfda8
commit
886946cc8c
@ -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_;
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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 */,
|
||||
|
46
OSBindings/Mac/Clock SignalTests/MacintoshVideoTests.mm
Normal file
46
OSBindings/Mac/Clock SignalTests/MacintoshVideoTests.mm
Normal 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
|
Loading…
Reference in New Issue
Block a user