From 7722596a3b133038db0be7c773af5e0abebb1759 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 8 Oct 2019 21:18:08 -0400 Subject: [PATCH] Makes a first attempt to box out the ST display area. --- Machines/AtariST/AtariST.cpp | 1 + Machines/AtariST/Video.cpp | 102 ++++++++++++++++++++++++++++++++++- Machines/AtariST/Video.hpp | 19 +++++-- 3 files changed, 118 insertions(+), 4 deletions(-) diff --git a/Machines/AtariST/AtariST.cpp b/Machines/AtariST/AtariST.cpp index 042261312..68303d23c 100644 --- a/Machines/AtariST/AtariST.cpp +++ b/Machines/AtariST/AtariST.cpp @@ -267,6 +267,7 @@ class ConcreteMachine: void flush() { audio_queue_.perform(); + video_.flush(); } private: diff --git a/Machines/AtariST/Video.cpp b/Machines/AtariST/Video.cpp index 5387799fd..bad48c124 100644 --- a/Machines/AtariST/Video.cpp +++ b/Machines/AtariST/Video.cpp @@ -8,10 +8,47 @@ #include "Video.hpp" +#include + using namespace Atari::ST; +namespace { + +struct ModeParams { + const int lines_per_frame; + + const int first_video_line; + const int final_video_line; + + const int line_length; + + const int end_of_blank; + + const int start_of_display_enable; + const int end_of_display_enable; + + const int start_of_output; + const int end_of_output; + + const int start_of_blank; + + const int start_of_hsync; + const int end_of_hsync; +} modes[3] = { + {313, 56, 256, 1024, 64, 116, 116+640, 116+48, 116+48+640, 904, 928, 1008 }, + {}, + {} +}; + +const ModeParams &mode_params_for_mode() { + // TODO: rest of potential combinations, and accept mode as a paramter. + return modes[0]; +} + +} + Video::Video() : - crt_(512, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4) { + crt_(1024, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4) { } void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) { @@ -19,4 +56,67 @@ void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) { } void Video::run_for(HalfCycles duration) { + int integer_duration = duration.as_int(); + const auto mode_params = mode_params_for_mode(); + +#define Period(lower, upper, type) \ + if(x >= lower && x < upper) { \ + const auto target = std::min(upper, final_x); \ + type(target - x); \ + x = target; \ + } + + while(integer_duration) { + const int final_x = std::min(x + integer_duration, mode_params.line_length); + integer_duration -= (final_x - x); + + if(y >= mode_params.first_video_line && y < mode_params.final_video_line) { + // TODO: Prior to output: collect all necessary data, obeying start_of_display_enable and end_of_display_enable. + + Period(0, mode_params.end_of_blank, crt_.output_blank); + Period(mode_params.end_of_blank, mode_params.start_of_output, output_border); + + if(x >= mode_params.start_of_output && x < mode_params.end_of_output) { + const auto target = std::min(mode_params.end_of_output, final_x); + x = target; + + if(x == mode_params.end_of_output) { + uint16_t *colour_pointer = reinterpret_cast(crt_.begin_data(1)); + if(colour_pointer) *colour_pointer = 0xffff; + crt_.output_level(mode_params.end_of_output - mode_params.start_of_output); + } + } + + Period(mode_params.end_of_output, mode_params.start_of_blank, output_border); + Period(mode_params.start_of_blank, mode_params.start_of_hsync, crt_.output_blank); + Period(mode_params.start_of_hsync, mode_params.start_of_blank, crt_.output_sync); + Period(mode_params.start_of_blank, mode_params.line_length, crt_.output_blank); + } else { + // Hard code the first three lines as vertical sync. + if(y < 3) { + Period(0, mode_params.start_of_hsync, crt_.output_sync); + Period(mode_params.start_of_hsync, mode_params.end_of_hsync, crt_.output_blank); + Period(mode_params.end_of_hsync, mode_params.line_length, crt_.output_sync); + } else { + Period(0, mode_params.end_of_blank, crt_.output_blank); + Period(mode_params.end_of_blank, mode_params.start_of_blank, output_border); + Period(mode_params.start_of_blank, mode_params.start_of_hsync, crt_.output_blank); + Period(mode_params.start_of_hsync, mode_params.start_of_blank, crt_.output_sync); + Period(mode_params.start_of_blank, mode_params.line_length, crt_.output_blank); + } + } + + if(x == mode_params.line_length) { + x = 0; + y = (y + 1) % mode_params.lines_per_frame; + } + } + +#undef Period +} + +void Video::output_border(int duration) { + uint16_t *colour_pointer = reinterpret_cast(crt_.begin_data(1)); + if(colour_pointer) *colour_pointer = 0x333; + crt_.output_level(duration); } diff --git a/Machines/AtariST/Video.hpp b/Machines/AtariST/Video.hpp index 8a93e5c6b..d27dd5b3b 100644 --- a/Machines/AtariST/Video.hpp +++ b/Machines/AtariST/Video.hpp @@ -6,8 +6,8 @@ // Copyright © 2019 Thomas Harte. All rights reserved. // -#ifndef Video_hpp -#define Video_hpp +#ifndef Atari_ST_Video_hpp +#define Atari_ST_Video_hpp #include "../../Outputs/CRT/CRT.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" @@ -29,11 +29,24 @@ class Video { */ void run_for(HalfCycles duration); + /*! + @returns the number of cycles until there is next a change in the hsync, + vsync or display_enable outputs. + */ + HalfCycles get_next_sequence_point(); + + bool hsync(); + bool vsync(); + bool display_enabled(); + private: Outputs::CRT::CRT crt_; + + int x = 0, y = 0; + void output_border(int duration); }; } } -#endif /* Video_hpp */ +#endif /* Atari_ST_Video_hpp */