mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-06 01:28:57 +00:00
Gets started on different video timings.
This commit is contained in:
parent
0af405aa46
commit
f10ec80153
@ -69,48 +69,111 @@ template <VideoTiming timing> class Video {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Timings get_timings() {
|
static constexpr Timings get_timings() {
|
||||||
// Amstrad gate array timings, classic statement:
|
if constexpr (timing == VideoTiming::Plus3) {
|
||||||
//
|
// Amstrad gate array timings, classic statement:
|
||||||
// Contention begins 14361 cycles "after interrupt" and follows the pattern [1, 0, 7, 6 5 4, 3, 2].
|
//
|
||||||
// The first four bytes of video are fetched at 14365–14368 cycles, in the order [pixels, attribute, pixels, attribute].
|
// Contention begins 14361 cycles "after interrupt" and follows the pattern [1, 0, 7, 6 5 4, 3, 2].
|
||||||
//
|
// The first four bytes of video are fetched at 14365–14368 cycles, in the order [pixels, attribute, pixels, attribute].
|
||||||
// For my purposes:
|
//
|
||||||
//
|
// For my purposes:
|
||||||
// Video fetching always begins at 0. Since there are 311*228 = 70908 cycles per frame, and the interrupt
|
//
|
||||||
// should "occur" (I assume: begin) 14365 before that, it should actually begin at 70908 - 14365 = 56543.
|
// Video fetching always begins at 0. Since there are 311*228 = 70908 cycles per frame, and the interrupt
|
||||||
//
|
// should "occur" (I assume: begin) 14365 before that, it should actually begin at 70908 - 14365 = 56543.
|
||||||
// Contention begins four cycles before the first video fetch, so it begins at 70904. I don't currently
|
//
|
||||||
// know whether the four cycles is true across all models, so it's given here as convention_leadin.
|
// Contention begins four cycles before the first video fetch, so it begins at 70904. I don't currently
|
||||||
//
|
// know whether the four cycles is true across all models, so it's given here as convention_leadin.
|
||||||
// ... except that empirically that all seems to be two cycles off. So maybe I misunderstand what the
|
//
|
||||||
// contention patterns are supposed to indicate relative to MREQ? It's frustrating that all documentation
|
// ... except that empirically that all seems to be two cycles off. So maybe I misunderstand what the
|
||||||
// I can find is vaguely in terms of contention patterns, and what they mean isn't well-defined in terms
|
// contention patterns are supposed to indicate relative to MREQ? It's frustrating that all documentation
|
||||||
// of regular Z80 signalling.
|
// I can find is vaguely in terms of contention patterns, and what they mean isn't well-defined in terms
|
||||||
constexpr Timings result = {
|
// of regular Z80 signalling.
|
||||||
.cycles_per_line = 228 * 2,
|
constexpr Timings result = {
|
||||||
.lines_per_frame = 311,
|
.cycles_per_line = 228 * 2,
|
||||||
|
.lines_per_frame = 311,
|
||||||
|
|
||||||
// i.e. video fetching begins five cycles after the start of the
|
// i.e. video fetching begins five cycles after the start of the
|
||||||
// contended memory pattern below; that should put a clear two
|
// contended memory pattern below; that should put a clear two
|
||||||
// cycles between a Z80 access and the first video fetch.
|
// cycles between a Z80 access and the first video fetch.
|
||||||
.contention_leadin = 5 * 2,
|
.contention_leadin = 5 * 2,
|
||||||
.contention_duration = 129 * 2,
|
.contention_duration = 129 * 2,
|
||||||
|
|
||||||
// i.e. interrupt is first signalled 14368 cycles before the first video fetch.
|
// i.e. interrupt is first signalled 14368 cycles before the first video fetch.
|
||||||
.interrupt_time = (228*311 - 14368) * 2,
|
.interrupt_time = (228*311 - 14368) * 2,
|
||||||
|
|
||||||
.delays = {
|
.delays = {
|
||||||
2, 1,
|
2, 1,
|
||||||
0, 0,
|
0, 0,
|
||||||
14, 13,
|
14, 13,
|
||||||
12, 11,
|
12, 11,
|
||||||
10, 9,
|
10, 9,
|
||||||
8, 7,
|
8, 7,
|
||||||
6, 5,
|
6, 5,
|
||||||
4, 3,
|
4, 3,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return result;
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fix 48kb and 128kb timings, below.
|
||||||
|
|
||||||
|
if constexpr (timing == VideoTiming::OneTwoEightK) {
|
||||||
|
constexpr Timings result = {
|
||||||
|
.cycles_per_line = 228 * 2,
|
||||||
|
.lines_per_frame = 311,
|
||||||
|
|
||||||
|
// i.e. video fetching begins five cycles after the start of the
|
||||||
|
// contended memory pattern below; that should put a clear two
|
||||||
|
// cycles between a Z80 access and the first video fetch.
|
||||||
|
.contention_leadin = 5 * 2,
|
||||||
|
.contention_duration = 128 * 2,
|
||||||
|
|
||||||
|
// i.e. interrupt is first signalled 14368 cycles before the first video fetch.
|
||||||
|
.interrupt_time = (228*311 - 14361) * 2,
|
||||||
|
|
||||||
|
.delays = {
|
||||||
|
12, 11,
|
||||||
|
10, 9,
|
||||||
|
8, 7,
|
||||||
|
6, 5,
|
||||||
|
4, 3,
|
||||||
|
2, 1,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (timing == VideoTiming::FortyEightK) {
|
||||||
|
constexpr Timings result = {
|
||||||
|
.cycles_per_line = 224 * 2,
|
||||||
|
.lines_per_frame = 312,
|
||||||
|
|
||||||
|
// i.e. video fetching begins five cycles after the start of the
|
||||||
|
// contended memory pattern below; that should put a clear two
|
||||||
|
// cycles between a Z80 access and the first video fetch.
|
||||||
|
.contention_leadin = 5 * 2,
|
||||||
|
.contention_duration = 128 * 2,
|
||||||
|
|
||||||
|
// i.e. interrupt is first signalled 14368 cycles before the first video fetch.
|
||||||
|
.interrupt_time = (224*312 - 14361) * 2,
|
||||||
|
|
||||||
|
.delays = {
|
||||||
|
12, 11,
|
||||||
|
10, 9,
|
||||||
|
8, 7,
|
||||||
|
6, 5,
|
||||||
|
4, 3,
|
||||||
|
2, 1,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: how long is the interrupt line held for?
|
// TODO: how long is the interrupt line held for?
|
||||||
@ -238,9 +301,14 @@ template <VideoTiming timing> class Video {
|
|||||||
|
|
||||||
if(offset >= burst_position && offset < burst_position+burst_length && end_offset > offset) {
|
if(offset >= burst_position && offset < burst_position+burst_length && end_offset > offset) {
|
||||||
const int burst_duration = std::min(burst_position + burst_length, end_offset) - offset;
|
const int burst_duration = std::min(burst_position + burst_length, end_offset) - offset;
|
||||||
crt_.output_colour_burst(burst_duration, 116, is_alternate_line_);
|
|
||||||
|
if constexpr (timing >= VideoTiming::OneTwoEightK) {
|
||||||
|
crt_.output_colour_burst(burst_duration, 116, is_alternate_line_);
|
||||||
|
// The colour burst phase above is an empirical guess. I need to research further.
|
||||||
|
} else {
|
||||||
|
crt_.output_default_colour_burst(burst_duration);
|
||||||
|
}
|
||||||
offset += burst_duration;
|
offset += burst_duration;
|
||||||
// The colour burst phase above is an empirical guess. I need to research further.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(offset >= burst_position+burst_length && end_offset > offset) {
|
if(offset >= burst_position+burst_length && end_offset > offset) {
|
||||||
@ -261,9 +329,21 @@ template <VideoTiming timing> class Video {
|
|||||||
crt_.output_level(duration);
|
crt_.output_level(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr int half_cycles_per_line() {
|
||||||
|
if constexpr (timing == VideoTiming::FortyEightK) {
|
||||||
|
// TODO: determine real figure here, if one exists.
|
||||||
|
// The source I'm looking at now suggests that the theoretical
|
||||||
|
// ideal of 224*2 ignores the real-life effects of separate
|
||||||
|
// crystals, so I've nudged this experimentally.
|
||||||
|
return 224*2 - 1;
|
||||||
|
} else {
|
||||||
|
return 227*2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Video() :
|
Video() :
|
||||||
crt_(227 * 2, 2, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red2Green2Blue2)
|
crt_(half_cycles_per_line(), 2, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red2Green2Blue2)
|
||||||
{
|
{
|
||||||
// Show only the centre 80% of the TV frame.
|
// Show only the centre 80% of the TV frame.
|
||||||
crt_.set_display_type(Outputs::Display::DisplayType::RGB);
|
crt_.set_display_type(Outputs::Display::DisplayType::RGB);
|
||||||
|
@ -638,8 +638,15 @@ template<Model model> class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Video.
|
// MARK: - Video.
|
||||||
static constexpr VideoTiming video_timing = VideoTiming::Plus3;
|
using VideoType =
|
||||||
JustInTimeActor<Video<video_timing>> video_;
|
std::conditional_t<
|
||||||
|
model <= Model::FortyEightK, Video<VideoTiming::FortyEightK>,
|
||||||
|
std::conditional_t<
|
||||||
|
model <= Model::Plus2, Video<VideoTiming::OneTwoEightK>,
|
||||||
|
Video<VideoTiming::Plus3>
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
JustInTimeActor<VideoType> video_;
|
||||||
|
|
||||||
// MARK: - Keyboard.
|
// MARK: - Keyboard.
|
||||||
Sinclair::ZX::Keyboard::Keyboard keyboard_;
|
Sinclair::ZX::Keyboard::Keyboard keyboard_;
|
||||||
|
Loading…
Reference in New Issue
Block a user