1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef TIA_YSTART_DETECTOR
19#define TIA_YSTART_DETECTOR
20
21#include "AbstractFrameManager.hxx"
22
23/**
24 * This frame manager detects ystart from the first line with vblank = off.
25 */
26
27class YStartDetector: public AbstractFrameManager {
28
29 public:
30
31 YStartDetector();
32
33 public:
34
35 /**
36 * Getter for the detected ystart value
37 */
38 uInt32 detectedYStart() const;
39
40 /**
41 * We require frame layout to be set from outside.
42 */
43 void setLayout(FrameLayout layout) override { this->layout(layout); }
44
45 protected:
46
47 /**
48 * We need to track vsync changes.
49 */
50 void onSetVsync() override;
51
52 /**
53 * Reset hook.
54 */
55 void onReset() override;
56
57 /**
58 * The workhorse.
59 */
60 void onNextLine() override;
61
62 private:
63
64 /**
65 * Our various states.
66 */
67 enum class State {
68 // Wait for vsync on
69 waitForVsyncStart,
70
71 // Wait for vsync off
72 waitForVsyncEnd,
73
74 // Wait for the visible frame to start
75 waitForFrameStart
76 };
77
78 /**
79 * Have we settled on a frame start?
80 */
81 enum class VblankMode {
82 // We have settled on a frame start and have some hysteresis before we return to floating
83 locked,
84
85 // We are actively looking for the frame to start
86 floating
87 };
88
89 private:
90
91 /**
92 * Side effects for state transitions.
93 */
94 void setState(State state);
95
96 /**
97 * Perform detection and decide whether the frame starts now.
98 */
99 bool shouldTransitionToFrame();
100
101 private:
102
103 /**
104 * State.
105 */
106 State myState;
107
108 /**
109 * locked / floating
110 */
111 VblankMode myVblankMode;
112
113 /**
114 * Counts the scanlines that we wait for vsync to start.
115 */
116 uInt32 myLinesWaitingForVsyncToStart;
117
118 /**
119 * The number of lines we are currently waiting for the frame to start (and vblank to end).
120 */
121 uInt32 myCurrentVblankLines;
122
123 /**
124 * The number of vblank lines on the last frame.
125 */
126 uInt32 myLastVblankLines;
127
128 /**
129 * Count "vblank violations" in fixed mode (the number of consecutive frames where ystart
130 * differs from the previously detected value). Once a trip point is reached, we transition
131 * back to floating mode.
132 */
133 uInt32 myVblankViolations;
134
135 /**
136 * The number of frames in floating mode with stable ystart. Once a trip point is reacted,
137 * we transition to fixed mode
138 */
139 uInt32 myStableVblankFrames;
140
141 /**
142 * Tracks deviations from the determined ystart value during a fixed mode frame in order to
143 * avoid double counting.
144 */
145 bool myVblankViolated;
146
147 private:
148
149 YStartDetector(const YStartDetector&) = delete;
150 YStartDetector(YStartDetector&&) = delete;
151 YStartDetector& operator=(const YStartDetector&) = delete;
152 YStartDetector& operator=(YStartDetector&&) = delete;
153};
154
155#endif // TIA_YSTART_DETECTOR
156