From 9dff13cbbfd3266afb64cdf1a36ee6d1a6c09c2b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 14 Nov 2018 22:25:19 -0500 Subject: [PATCH] Re-establishes output from the machines with 9918s and derivatives. --- Components/9918/9918.cpp | 53 +++++++++--------- Components/9918/9918.hpp | 2 +- Components/9918/Implementation/9918Base.hpp | 4 +- Machines/ColecoVision/ColecoVision.cpp | 28 ++++------ Machines/MSX/MSX.cpp | 31 +++++------ Machines/MasterSystem/MasterSystem.cpp | 59 +++++++++++---------- 6 files changed, 81 insertions(+), 96 deletions(-) diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index 7e4f3c5e1..4419a77a5 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -49,9 +49,8 @@ struct ReverseTable { } Base::Base(Personality p) : - personality_(p)//, -// crt_(new Outputs::CRT::CRT(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, 4)) - { + personality_(p), + crt_(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, Outputs::Display::InputDataType::Red8Green8Blue8) { switch(p) { case TI::TMS::TMS9918A: @@ -87,19 +86,19 @@ TMS9918::TMS9918(Personality p): Base(p) { // Unimaginatively, this class just passes RGB through to the shader. Investigation is needed // into whether there's a more natural form. -// crt_->set_rgb_sampling_function( +// crt_.set_rgb_sampling_function( // "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)" // "{" // "return texture(sampler, coordinate).rgb / vec3(255.0);" // "}"); // crt_->set_video_signal(Outputs::Display::VideoSignal::RGB); - crt_->set_visible_area(Outputs::Display::Rect(0.055f, 0.025f, 0.9f, 0.9f)); + crt_.set_visible_area(Outputs::Display::Rect(0.055f, 0.025f, 0.9f, 0.9f)); // The TMS remains in-phase with the NTSC colour clock; this is an empirical measurement // intended to produce the correct relationship between the hard edges between pixels and // the colour clock. It was eyeballed rather than derived from any knowledge of the TMS // colour burst generator because I've yet to find any. - crt_->set_immediate_default_phase(0.85f); + crt_.set_immediate_default_phase(0.85f); } void TMS9918::set_tv_standard(TVStandard standard) { @@ -108,18 +107,18 @@ void TMS9918::set_tv_standard(TVStandard standard) { case TVStandard::PAL: mode_timing_.total_lines = 313; mode_timing_.first_vsync_line = 253; - crt_->set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::PAL50); + crt_.set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::PAL50); break; default: mode_timing_.total_lines = 262; mode_timing_.first_vsync_line = 227; - crt_->set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::NTSC60); + crt_.set_new_display_type(CRTCyclesPerLine, Outputs::Display::Type::NTSC60); break; } } -Outputs::CRT::CRT *TMS9918::get_crt() { - return crt_.get(); +void TMS9918::set_scan_target(Outputs::Display::ScanTarget *scan_target) { + crt_.set_scan_target(scan_target); } void Base::LineBuffer::reset_sprite_collection() { @@ -368,7 +367,7 @@ void TMS9918::run_for(const HalfCycles cycles) { if(read_pointer_.row >= mode_timing_.first_vsync_line && read_pointer_.row < mode_timing_.first_vsync_line+4) { // Vertical sync. if(end_column == 342) { - crt_->output_sync(342 * 4); + crt_.output_sync(342 * 4); } } else { // Right border. @@ -378,11 +377,11 @@ void TMS9918::run_for(const HalfCycles cycles) { // and 58+15 = 73. So output the lot when the // cursor passes 73. if(read_pointer_.column < 73 && end_column >= 73) { - crt_->output_blank(8*4); - crt_->output_sync(26*4); - crt_->output_blank(2*4); - crt_->output_default_colour_burst(14*4); - crt_->output_blank(8*4); + crt_.output_blank(8*4); + crt_.output_sync(26*4); + crt_.output_blank(2*4); + crt_.output_default_colour_burst(14*4); + crt_.output_blank(8*4); } // Border colour for the rest of the line. @@ -394,11 +393,11 @@ void TMS9918::run_for(const HalfCycles cycles) { // Blanking region. if(read_pointer_.column < 73 && end_column >= 73) { - crt_->output_blank(8*4); - crt_->output_sync(26*4); - crt_->output_blank(2*4); - crt_->output_default_colour_burst(14*4); - crt_->output_blank(8*4); + crt_.output_blank(8*4); + crt_.output_sync(26*4); + crt_.output_blank(2*4); + crt_.output_default_colour_burst(14*4); + crt_.output_blank(8*4); } // Left border. @@ -411,7 +410,7 @@ void TMS9918::run_for(const HalfCycles cycles) { if(!asked_for_write_area_) { asked_for_write_area_ = true; pixel_origin_ = pixel_target_ = reinterpret_cast( - crt_->begin_data(size_t(line_buffer.next_border_column - line_buffer.first_pixel_output_column)) + crt_.begin_data(size_t(line_buffer.next_border_column - line_buffer.first_pixel_output_column)) ); } @@ -429,7 +428,7 @@ void TMS9918::run_for(const HalfCycles cycles) { if(end == line_buffer.next_border_column) { const int length = line_buffer.next_border_column - line_buffer.first_pixel_output_column; - crt_->output_data(length * 4, size_t(length)); + crt_.output_data(length * 4, size_t(length)); pixel_origin_ = pixel_target_ = nullptr; asked_for_write_area_ = false; } @@ -471,16 +470,16 @@ void Base::output_border(int cycles, uint32_t cram_dot) { palette[background_colour_]; if(cram_dot) { - uint32_t *const pixel_target = reinterpret_cast(crt_->begin_data(1)); + uint32_t *const pixel_target = reinterpret_cast(crt_.begin_data(1)); *pixel_target = border_colour | cram_dot; - crt_->output_level(4); + crt_.output_level(4); cycles -= 4; } if(cycles) { - uint32_t *const pixel_target = reinterpret_cast(crt_->begin_data(1)); + uint32_t *const pixel_target = reinterpret_cast(crt_.begin_data(1)); *pixel_target = border_colour; - crt_->output_level(cycles); + crt_.output_level(cycles); } } diff --git a/Components/9918/9918.hpp b/Components/9918/9918.hpp index e607d9947..d1bcae473 100644 --- a/Components/9918/9918.hpp +++ b/Components/9918/9918.hpp @@ -42,7 +42,7 @@ class TMS9918: public Base { void set_tv_standard(TVStandard standard); /*! Provides the CRT this TMS is connected to. */ - Outputs::CRT::CRT *get_crt(); + void set_scan_target(Outputs::Display::ScanTarget *scan_target); /*! Runs the VCP for the number of cycles indicate; it is an implicit assumption of the code diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index ac712ad1b..842c3336c 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -78,8 +78,8 @@ class Base { Base(Personality p); - Personality personality_; - std::unique_ptr crt_; + const Personality personality_; + Outputs::CRT::CRT crt_; TVStandard tv_standard_ = TVStandard::NTSC; // Holds the contents of this VDP's connected DRAM. diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index 2b83e225d..73730bc1e 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -112,6 +112,7 @@ class ConcreteMachine: public: ConcreteMachine(const Analyser::Static::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : z80_(*this), + vdp_(TI::TMS::TMS9918A), sn76489_(TI::SN76489::Personality::SN76489, audio_queue_, sn76489_divider), ay_(audio_queue_), mixer_(sn76489_, ay_), @@ -170,18 +171,9 @@ class ConcreteMachine: } void set_scan_target(Outputs::Display::ScanTarget *scan_target) override { - vdp_.reset(new TI::TMS::TMS9918(TI::TMS::TMS9918A)); -// get_crt()->set_video_signal(Outputs::Display::VideoSignal::Composite); + vdp_.set_scan_target(scan_target); } -// void close_output() override { -// vdp_.reset(); -// } -// -// Outputs::CRT::CRT *get_crt() override { -// return vdp_->get_crt(); -// } - Outputs::Speaker::Speaker *get_speaker() override { return &speaker_; } @@ -249,9 +241,9 @@ class ConcreteMachine: switch((address >> 5) & 7) { case 5: update_video(); - *cycle.value = vdp_->get_register(address); - z80_.set_non_maskable_interrupt_line(vdp_->get_interrupt_line()); - time_until_interrupt_ = vdp_->get_time_until_interrupt(); + *cycle.value = vdp_.get_register(address); + z80_.set_non_maskable_interrupt_line(vdp_.get_interrupt_line()); + time_until_interrupt_ = vdp_.get_time_until_interrupt(); break; case 7: { @@ -293,9 +285,9 @@ class ConcreteMachine: case 5: update_video(); - vdp_->set_register(address, *cycle.value); - z80_.set_non_maskable_interrupt_line(vdp_->get_interrupt_line()); - time_until_interrupt_ = vdp_->get_time_until_interrupt(); + vdp_.set_register(address, *cycle.value); + z80_.set_non_maskable_interrupt_line(vdp_.get_interrupt_line()); + time_until_interrupt_ = vdp_.get_time_until_interrupt(); break; case 7: @@ -366,11 +358,11 @@ class ConcreteMachine: speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider))); } inline void update_video() { - vdp_->run_for(time_since_vdp_update_.flush()); + vdp_.run_for(time_since_vdp_update_.flush()); } CPU::Z80::Processor z80_; - std::unique_ptr vdp_; + TI::TMS::TMS9918 vdp_; Concurrency::DeferringAsyncTaskQueue audio_queue_; TI::SN76489 sn76489_; diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 940d92019..59d6c631a 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -148,6 +148,7 @@ class ConcreteMachine: public: ConcreteMachine(const Analyser::Static::MSX::Target &target, const ROMMachine::ROMFetcher &rom_fetcher): z80_(*this), + vdp_(TI::TMS::TMS9918A), i8255_(i8255_port_handler_), ay_(audio_queue_), audio_toggle_(audio_queue_), @@ -219,17 +220,9 @@ class ConcreteMachine: } void set_scan_target(Outputs::Display::ScanTarget *scan_target) override { - vdp_.reset(new TI::TMS::TMS9918(TI::TMS::TMS9918A)); + vdp_.set_scan_target(scan_target); } -// void close_output() override { -// vdp_.reset(); -// } -// -// Outputs::CRT::CRT *get_crt() override { -// return vdp_->get_crt(); -// } - Outputs::Speaker::Speaker *get_speaker() override { return &speaker_; } @@ -451,10 +444,10 @@ class ConcreteMachine: case CPU::Z80::PartialMachineCycle::Input: switch(address & 0xff) { case 0x98: case 0x99: - vdp_->run_for(time_since_vdp_update_.flush()); - *cycle.value = vdp_->get_register(address); - z80_.set_interrupt_line(vdp_->get_interrupt_line()); - time_until_interrupt_ = vdp_->get_time_until_interrupt(); + vdp_.run_for(time_since_vdp_update_.flush()); + *cycle.value = vdp_.get_register(address); + z80_.set_interrupt_line(vdp_.get_interrupt_line()); + time_until_interrupt_ = vdp_.get_time_until_interrupt(); break; case 0xa2: @@ -479,10 +472,10 @@ class ConcreteMachine: const int port = address & 0xff; switch(port) { case 0x98: case 0x99: - vdp_->run_for(time_since_vdp_update_.flush()); - vdp_->set_register(address, *cycle.value); - z80_.set_interrupt_line(vdp_->get_interrupt_line()); - time_until_interrupt_ = vdp_->get_time_until_interrupt(); + vdp_.run_for(time_since_vdp_update_.flush()); + vdp_.set_register(address, *cycle.value); + z80_.set_interrupt_line(vdp_.get_interrupt_line()); + time_until_interrupt_ = vdp_.get_time_until_interrupt(); break; case 0xa0: case 0xa1: @@ -555,7 +548,7 @@ class ConcreteMachine: } void flush() { - vdp_->run_for(time_since_vdp_update_.flush()); + vdp_.run_for(time_since_vdp_update_.flush()); update_audio(); audio_queue_.perform(); } @@ -685,7 +678,7 @@ class ConcreteMachine: }; CPU::Z80::Processor z80_; - std::unique_ptr vdp_; + TI::TMS::TMS9918 vdp_; Intel::i8255::i8255 i8255_; Concurrency::DeferringAsyncTaskQueue audio_queue_; diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index 1da0b8003..6d2e3596c 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -94,6 +94,7 @@ class ConcreteMachine: region_(target.region), paging_scheme_(target.paging_scheme), z80_(*this), + vdp_(tms_personality_for_model(target.model)), sn76489_( (target.model == Target::Model::SG1000) ? TI::SN76489::Personality::SN76489 : TI::SN76489::Personality::SMS, audio_queue_, @@ -162,29 +163,21 @@ class ConcreteMachine: } void set_scan_target(Outputs::Display::ScanTarget *scan_target) override { - TI::TMS::Personality personality = TI::TMS::TMS9918A; - switch(model_) { - case Target::Model::SG1000: personality = TI::TMS::TMS9918A; break; - case Target::Model::MasterSystem: personality = TI::TMS::SMSVDP; break; - case Target::Model::MasterSystem2: personality = TI::TMS::SMS2VDP; break; - } - vdp_.reset(new TI::TMS::TMS9918(personality)); - vdp_->set_tv_standard( +// TI::TMS::Personality personality = TI::TMS::TMS9918A; +// switch(model_) { +// case Target::Model::SG1000: personality = TI::TMS::TMS9918A; break; +// case Target::Model::MasterSystem: personality = TI::TMS::SMSVDP; break; +// case Target::Model::MasterSystem2: personality = TI::TMS::SMS2VDP; break; +// } +// vdp_.reset(new TI::TMS::TMS9918(personality)); + vdp_.set_tv_standard( (region_ == Target::Region::Europe) ? TI::TMS::TVStandard::PAL : TI::TMS::TVStandard::NTSC); // get_crt()->set_video_signal(Outputs::Display::VideoSignal::Composite); - time_until_debounce_ = vdp_->get_time_until_line(-1); + time_until_debounce_ = vdp_.get_time_until_line(-1); } -// void close_output() override { -// vdp_.reset(); -// } -// -// Outputs::CRT::CRT *get_crt() override { -// return vdp_->get_crt(); -// } - Outputs::Speaker::Speaker *get_speaker() override { return &speaker_; } @@ -239,16 +232,16 @@ class ConcreteMachine: break; case 0x40: update_video(); - *cycle.value = vdp_->get_current_line(); + *cycle.value = vdp_.get_current_line(); break; case 0x41: - *cycle.value = vdp_->get_latched_horizontal_counter(); + *cycle.value = vdp_.get_latched_horizontal_counter(); break; case 0x80: case 0x81: update_video(); - *cycle.value = vdp_->get_register(address); - z80_.set_interrupt_line(vdp_->get_interrupt_line()); - time_until_interrupt_ = vdp_->get_time_until_interrupt(); + *cycle.value = vdp_.get_register(address); + z80_.set_interrupt_line(vdp_.get_interrupt_line()); + time_until_interrupt_ = vdp_.get_time_until_interrupt(); break; case 0xc0: { Joystick *const joypad1 = static_cast(joysticks_[0].get()); @@ -290,7 +283,7 @@ class ConcreteMachine: // Latch if either TH has newly gone to 1. if((new_ths^previous_ths)&new_ths) { update_video(); - vdp_->latch_horizontal_counter(); + vdp_.latch_horizontal_counter(); } } break; case 0x40: case 0x41: @@ -299,9 +292,9 @@ class ConcreteMachine: break; case 0x80: case 0x81: update_video(); - vdp_->set_register(address, *cycle.value); - z80_.set_interrupt_line(vdp_->get_interrupt_line()); - time_until_interrupt_ = vdp_->get_time_until_interrupt(); + vdp_.set_register(address, *cycle.value); + z80_.set_interrupt_line(vdp_.get_interrupt_line()); + time_until_interrupt_ = vdp_.get_time_until_interrupt(); break; case 0xc0: LOG("TODO: [output] I/O port A/N; " << int(*cycle.value)); @@ -337,7 +330,7 @@ class ConcreteMachine: if(time_until_debounce_ <= HalfCycles(0)) { z80_.set_non_maskable_interrupt_line(pause_is_pressed_); update_video(); - time_until_debounce_ = vdp_->get_time_until_line(-1); + time_until_debounce_ = vdp_.get_time_until_line(-1); } return HalfCycles(0); @@ -395,6 +388,14 @@ class ConcreteMachine: } private: + static TI::TMS::Personality tms_personality_for_model(Analyser::Static::Sega::Target::Model model) { + switch(model) { + case Target::Model::SG1000: return TI::TMS::TMS9918A; + case Target::Model::MasterSystem: return TI::TMS::SMSVDP; + case Target::Model::MasterSystem2: return TI::TMS::SMSVDP; + } + } + inline uint8_t get_th_values() { // Quick not on TH inputs here: if either is setup as an output, then the // currently output level is returned. Otherwise they're fixed at 1. @@ -410,7 +411,7 @@ class ConcreteMachine: speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider))); } inline void update_video() { - vdp_->run_for(time_since_vdp_update_.flush()); + vdp_.run_for(time_since_vdp_update_.flush()); } using Target = Analyser::Static::Sega::Target; @@ -418,7 +419,7 @@ class ConcreteMachine: Target::Region region_; Target::PagingScheme paging_scheme_; CPU::Z80::Processor z80_; - std::unique_ptr vdp_; + TI::TMS::TMS9918 vdp_; Concurrency::DeferringAsyncTaskQueue audio_queue_; TI::SN76489 sn76489_;