From 00e7958a975a779e28f923b6a6bb11035a11ea9b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 23 Oct 2018 22:19:45 -0400 Subject: [PATCH] Separates request for an SMS2 VDP from current graphics mode. Thereby fixes various minor segments of Codemasters games. --- Analyser/Static/Sega/StaticAnalyser.cpp | 1 + Analyser/Static/Sega/Target.hpp | 8 ++++++-- Components/9918/9918.cpp | 13 +++++++------ Components/9918/Implementation/9918Base.hpp | 19 +++++++++++-------- Machines/MasterSystem/MasterSystem.cpp | 14 ++++++++++---- 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Analyser/Static/Sega/StaticAnalyser.cpp b/Analyser/Static/Sega/StaticAnalyser.cpp index 55132d4ea..038be85be 100644 --- a/Analyser/Static/Sega/StaticAnalyser.cpp +++ b/Analyser/Static/Sega/StaticAnalyser.cpp @@ -71,6 +71,7 @@ Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &med !data[0x7fea] && !data[0x7feb] && !data[0x7fec] && !data[0x7fed] && !data[0x7fee] && !data[0x7fef] ) { target->paging_scheme = Target::PagingScheme::Codemasters; + target->model = Target::Model::MasterSystem2; } } } diff --git a/Analyser/Static/Sega/Target.hpp b/Analyser/Static/Sega/Target.hpp index dcab665a1..f95766ab6 100644 --- a/Analyser/Static/Sega/Target.hpp +++ b/Analyser/Static/Sega/Target.hpp @@ -15,14 +15,16 @@ namespace Sega { struct Target: public ::Analyser::Static::Target { enum class Model { + SG1000, MasterSystem, - SG1000 + MasterSystem2, }; enum class Region { Japan, USA, - Europe + Europe, + Brazil }; enum class PagingScheme { @@ -35,6 +37,8 @@ struct Target: public ::Analyser::Static::Target { PagingScheme paging_scheme = PagingScheme::Sega; }; +#define is_master_system(v) v >= Analyser::Static::Sega::Target::Model::MasterSystem + } } } diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index e0cbe9a5e..d7988de60 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -54,6 +54,7 @@ Base::Base(Personality p) : switch(p) { case TI::TMS::TMS9918A: case TI::TMS::SMSVDP: + case TI::TMS::SMS2VDP: case TI::TMS::GGVDP: ram_.resize(16 * 1024); break; @@ -481,17 +482,14 @@ void TMS9918::set_register(int address, uint8_t value) { write_phase_ = false; if(value & 0x80) { - switch(personality_) { - default: - value &= 0x7; - break; - case TI::TMS::SMSVDP: + if(is_sega_vdp(personality_)) { if(value & 0x40) { master_system_.cram_is_selected = true; return; } value &= 0xf; - break; + } else { + value &= 0x7; } // This is a write to a register. @@ -523,6 +521,7 @@ void TMS9918::set_register(int address, uint8_t value) { case 2: pattern_name_address_ = size_t((low_write_ & 0xf) << 10) | 0x3ff; + master_system_.pattern_name_address = pattern_name_address_ | ((personality_ == TMS::SMSVDP) ? 0x000 : 0x400); break; case 3: @@ -535,10 +534,12 @@ void TMS9918::set_register(int address, uint8_t value) { case 5: sprite_attribute_table_address_ = size_t((low_write_ & 0x7f) << 7) | 0x7f; + master_system_.sprite_attribute_table_address = sprite_attribute_table_address_ | ((personality_ == TMS::SMSVDP) ? 0x00 : 0x80); break; case 6: sprite_generator_table_address_ = size_t((low_write_ & 0x07) << 11) | 0x7ff; + master_system_.sprite_generator_table_address = sprite_generator_table_address_ | ((personality_ == TMS::SMSVDP) ? 0x0000 : 0x1800); break; case 7: diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index c42c0733a..6417b0837 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -24,6 +24,7 @@ enum Personality { V9938, V9958, SMSVDP, + SMS2VDP, GGVDP, }; @@ -270,6 +271,10 @@ class Base { // Holds the vertical scroll position for this frame; this is latched // once and cannot dynamically be changed until the next frame. uint8_t latched_vertical_scroll = 0; + + size_t pattern_name_address; + size_t sprite_attribute_table_address; + size_t sprite_generator_table_address; } master_system_; void set_current_screen_mode() { @@ -644,12 +649,12 @@ class Base { #define sprite_fetch(sprite) {\ line_buffer.active_sprites[sprite].x = \ ram_[\ - sprite_attribute_table_address & size_t(0x3f80 | (line_buffer.active_sprites[sprite].index << 1))\ + master_system_.sprite_attribute_table_address & size_t(0x3f80 | (line_buffer.active_sprites[sprite].index << 1))\ ] - (master_system_.shift_sprites_8px_left ? 8 : 0); \ const uint8_t name = ram_[\ - sprite_attribute_table_address & size_t(0x3f81 | (line_buffer.active_sprites[sprite].index << 1))\ + master_system_.sprite_attribute_table_address & size_t(0x3f81 | (line_buffer.active_sprites[sprite].index << 1))\ ] & (sprites_16x16_ ? ~1 : ~0);\ - const size_t graphic_location = sprite_generator_table_address & size_t(0x2000 | (name << 5) | (line_buffer.active_sprites[sprite].row << 2)); \ + const size_t graphic_location = master_system_.sprite_generator_table_address & size_t(0x2000 | (name << 5) | (line_buffer.active_sprites[sprite].row << 2)); \ line_buffer.active_sprites[sprite].image[0] = ram_[graphic_location]; \ line_buffer.active_sprites[sprite].image[1] = ram_[graphic_location+1]; \ line_buffer.active_sprites[sprite].image[2] = ram_[graphic_location+2]; \ @@ -668,8 +673,8 @@ class Base { #define sprite_y_read(location, sprite) \ slot(location): \ - posit_sprite(sprite_selection_buffer, sprite, ram_[sprite_attribute_table_address & ((sprite) | 0x3f00)], write_pointer_.row); \ - posit_sprite(sprite_selection_buffer, sprite+1, ram_[sprite_attribute_table_address & ((sprite + 1) | 0x3f00)], write_pointer_.row); \ + posit_sprite(sprite_selection_buffer, sprite, ram_[master_system_.sprite_attribute_table_address & ((sprite) | 0x3f00)], write_pointer_.row); \ + posit_sprite(sprite_selection_buffer, sprite+1, ram_[master_system_.sprite_attribute_table_address & ((sprite + 1) | 0x3f00)], write_pointer_.row); \ #define fetch_tile_name(column, row_info) {\ const size_t scrolled_column = (column - horizontal_offset) & 0x1f;\ @@ -717,10 +722,8 @@ class Base { // Limit address bits in use if this is a SMS2 mode. const bool is_tall_mode = mode_timing_.pixel_lines != 192; - const size_t pattern_name_address = pattern_name_address_ | (is_tall_mode ? 0xc00 : 0); + const size_t pattern_name_address = master_system_.pattern_name_address | (is_tall_mode ? 0x800 : 0); const size_t pattern_name_offset = is_tall_mode ? 0x100 : 0; - const size_t sprite_attribute_table_address = sprite_attribute_table_address_ | (is_tall_mode ? 0x80 : 0); - const size_t sprite_generator_table_address = sprite_generator_table_address_ | (is_tall_mode ? 0x1800 : 0); // Determine row info for the screen both (i) if vertical scrolling is applied; and (ii) if it isn't. // The programmer can opt out of applying vertical scrolling to the right-hand portion of the display. diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index cc73a2e90..e3e921b03 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -129,7 +129,7 @@ class ConcreteMachine: } // Map RAM. - if(model_ == Target::Model::MasterSystem) { + if(is_master_system(model_)) { map(read_pointers_, ram_, 8*1024, 0xc000, 0x10000); map(write_pointers_, ram_, 8*1024, 0xc000, 0x10000); } else { @@ -146,7 +146,13 @@ class ConcreteMachine: } void setup_output(float aspect_ratio) override { - vdp_.reset(new TI::TMS::TMS9918(model_ == Target::Model::SG1000 ? TI::TMS::TMS9918A : TI::TMS::SMSVDP)); + 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); @@ -249,7 +255,7 @@ class ConcreteMachine: case CPU::Z80::PartialMachineCycle::Output: switch(address & 0xc1) { case 0x00: - if(model_ == Target::Model::MasterSystem) { + if(is_master_system(model_)) { // TODO: Obey the RAM enable. memory_control_ = *cycle.value; page_cartridge(); @@ -401,7 +407,7 @@ class ConcreteMachine: } } bool has_bios() { - return model_ == Target::Model::MasterSystem && region_ != Target::Region::Japan; + return is_master_system(model_) && region_ != Target::Region::Japan; } };