From 642bb8333f435a7c18b06ce5d9505d4c3a117bd1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 28 Nov 2017 21:10:30 -0500 Subject: [PATCH] Introduces something of a first attempt at graphics collection and display. An unsuccessful attempt. --- Components/9918/9918.cpp | 77 +++++++++++++++++++++++++++++++--------- Components/9918/9918.hpp | 21 ++++++++++- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index 99753c51f..662cbf776 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -53,6 +53,7 @@ TMS9918::TMS9918(Personality p) : "{" "return texture(sampler, coordinate).rgb / vec3(255.0);" "}"); + crt_->set_output_device(Outputs::CRT::OutputDevice::Monitor); } std::shared_ptr TMS9918::get_crt() { @@ -81,42 +82,76 @@ void TMS9918::run_for(const HalfCycles cycles) { column_ += cycles_left; if(row_ < 192) { + // Do memory accesses. + switch(next_screen_mode_) { + default: // TODO: other graphics mode; this is graphics 1. + while(access_pointer_ < (column_ >> 1)) { + if(access_pointer_ < 26) { + access_pointer_ = std::min(26, column_ >> 1); + } + if(access_pointer_ >= 26) { + int end = std::min(154, column_); + + // TODO: optimise this, probably + const int row_base = ((row_ >> 3)&~31); + while(access_pointer_ < end) { + switch(access_pointer_&1) { + case 0: line_buffer_[access_pointer_] = ram_[pattern_name_address_ + row_base + ((access_pointer_ - 26) >> 2)]; break; + case 1: break; // TODO: sprites / CPU access. + case 2: line_buffer_[access_pointer_] = ram_[colour_table_address_ + (line_buffer_[access_pointer_ - 2] >> 3)]; break; + case 3: line_buffer_[access_pointer_] = ram_[pattern_generator_table_address_ + (line_buffer_[access_pointer_-3] << 3) + (row_ & 7)]; break; + } + access_pointer_++; + } + } + if(access_pointer_ >= 154) { + access_pointer_ = column_ >> 1; + } + } + break; + } + // Pixels. if(!output_column_ && column_ >= 26) { crt_->output_sync(static_cast(26)); output_column_ = 26; } // TODO: colour burst. - if(output_column_ >= 26) { // TODO: modes other than text - int pixels_end = std::min(69, column_); + if(output_column_ >= 26) { + int pixels_end = std::min(first_pixel_column_, column_); if(output_column_ < pixels_end) { - output_border(static_cast(pixels_end - output_column_)); + output_border(pixels_end - output_column_); output_column_ = pixels_end; - if(pixels_end == 69) { - pixel_target_ = reinterpret_cast(crt_->allocate_write_area(256)); + if(pixels_end == first_pixel_column_) { + pixel_target_ = reinterpret_cast(crt_->allocate_write_area(static_cast(first_right_border_column_ - first_pixel_column_))); } } } - if(output_column_ >= 69) { - int pixels_end = std::min(309, column_); + if(output_column_ >= first_pixel_column_) { + int pixels_end = std::min(first_right_border_column_, column_); if(output_column_ < pixels_end) { - while(output_column_ < pixels_end) { // TODO: modes other than text - pixel_target_[0] = 0xff; + while(output_column_ < pixels_end) { + int base = (output_column_ >> 1); + int address = base & ~3; +// uint8_t colour = line_buffer_[address]; + uint8_t pattern = line_buffer_[address+1]; + pattern >>= ((base&3)*2) + (output_column_ & 1); + pixel_target_[0] = (pattern&1) ? 0xffffff : 0x000000; pixel_target_ ++; output_column_ ++; } - if(output_column_ == 309) { - crt_->output_data(240, 1); // TODO: modes other than text + if(output_column_ == first_right_border_column_) { + crt_->output_data(static_cast(first_right_border_column_ - first_pixel_column_), 1); } } } - if(column_ >= 309) { - output_border(static_cast(column_ - output_column_)); + if(column_ >= first_pixel_column_) { + output_border(column_ - output_column_); output_column_ = column_; } - } else if(row_ >= 227 && row_ < 230) { // TODO: don't hard-code NTSC. + } else if(row_ >= first_vsync_line_ && row_ < first_vsync_line_+3) { // Vertical sync. if(column_ == 342) { crt_->output_sync(static_cast(342)); @@ -135,9 +170,19 @@ void TMS9918::run_for(const HalfCycles cycles) { int_cycles -= cycles_left; if(column_ == 342) { - column_ = output_column_ = 0; - row_ = (row_ + 1) % 262; // TODO: don't hard-code NTSC. + access_pointer_ = column_ = output_column_ = 0; + row_ = (row_ + 1) % frame_lines_; + // TODO: consider triggering an interrupt here. + screen_mode_ = next_screen_mode_; + switch(screen_mode_) { + // TODO: text mdoe. + default: + line_mode_ = LineMode::Character; + first_pixel_column_ = 63; + first_right_border_column_ = 319; + break; + } } } } diff --git a/Components/9918/9918.hpp b/Components/9918/9918.hpp index 32d3a03f5..8af29d49d 100644 --- a/Components/9918/9918.hpp +++ b/Components/9918/9918.hpp @@ -19,7 +19,7 @@ namespace TI { class TMS9918 { public: enum Personality { - TMS9918A, // includes the 9928A + TMS9918A, // includes the 9928A; set TV standard as desired. }; /*! @@ -28,6 +28,11 @@ class TMS9918 { */ TMS9918(Personality p); + enum TVStandard { + PAL, NTSC + }; + void set_tv_standard(TVStandard standard); + std::shared_ptr get_crt(); /*! @@ -73,6 +78,20 @@ class TMS9918 { uint32_t *pixel_target_ = nullptr; void output_border(int cycles); + + // Vertical timing details. + int frame_lines_ = 262; + int first_vsync_line_ = 227; + + // Horizontal selections. + enum class LineMode { + Text, + Character + } line_mode_ = LineMode::Text; + int first_pixel_column_, first_right_border_column_; + + uint8_t line_buffer_[171]; + int access_pointer_ = 0; }; };