diff --git a/Components/9918/9918.cpp b/Components/9918/9918.cpp index 2bd417f6f..e0cbe9a5e 100644 --- a/Components/9918/9918.cpp +++ b/Components/9918/9918.cpp @@ -138,7 +138,7 @@ void Base::posit_sprite(LineBuffer &buffer, int sprite_number, int sprite_positi return; // A sprite Y of 208 means "don't scan the list any further". - if(mode_timing_.allow_sprite_terminator && sprite_position == 208) { + if(mode_timing_.allow_sprite_terminator && sprite_position == mode_timing_.sprite_terminator) { buffer.sprites_stopped = true; return; } @@ -191,11 +191,27 @@ void TMS9918::run_for(const HalfCycles cycles) { // --------------------------------------- // Latch scrolling position, if necessary. // --------------------------------------- - if(write_pointer_.column < 61 && end_column >= 61) { - if(!write_pointer_.row) { - master_system_.latched_vertical_scroll = master_system_.vertical_scroll; + if(is_sega_vdp(personality_)) { + if(write_pointer_.column < 61 && end_column >= 61) { + if(!write_pointer_.row) { + master_system_.latched_vertical_scroll = master_system_.vertical_scroll; + + if(master_system_.mode4_enable) { + mode_timing_.pixel_lines = 192; + if(mode2_enable_ && mode1_enable_) mode_timing_.pixel_lines = 224; + if(mode2_enable_ && mode3_enable_) mode_timing_.pixel_lines = 240; + + mode_timing_.sprite_terminator = 0xd0; + if(mode_timing_.pixel_lines != 192) { + mode_timing_.sprite_terminator = 0xf0; + } + mode_timing_.first_vsync_line = (mode_timing_.total_lines + mode_timing_.pixel_lines) >> 1; + + mode_timing_.end_of_frame_interrupt_position.row = mode_timing_.pixel_lines + 1; + } + } + line_buffer.latched_horizontal_scroll = master_system_.horizontal_scroll; } - line_buffer.latched_horizontal_scroll = master_system_.horizontal_scroll; } diff --git a/Components/9918/Implementation/9918Base.hpp b/Components/9918/Implementation/9918Base.hpp index 6a5f8fa02..c42c0733a 100644 --- a/Components/9918/Implementation/9918Base.hpp +++ b/Components/9918/Implementation/9918Base.hpp @@ -155,9 +155,10 @@ class Base { } end_of_frame_interrupt_position; int line_interrupt_position = -1; - // Enables or disabled the recognition of 0xd0 as a sprite - // list terminator. + // Enables or disabled the recognition of the sprite + // list terminator, and sets the terminator value. bool allow_sprite_terminator = true; + uint8_t sprite_terminator = 0xd0; } mode_timing_; uint8_t line_interrupt_target = 0xff; @@ -279,9 +280,6 @@ class Base { if(is_sega_vdp(personality_) && master_system_.mode4_enable) { screen_mode_ = ScreenMode::SMSMode4; - mode_timing_.pixel_lines = 192; - if(mode2_enable_ && mode1_enable_) mode_timing_.pixel_lines = 224; - if(mode2_enable_ && mode3_enable_) mode_timing_.pixel_lines = 240; mode_timing_.maximum_visible_sprites = 8; return; } @@ -646,12 +644,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))\ + 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))\ + 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 = 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]; \ @@ -670,8 +668,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_[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); \ #define fetch_tile_name(column, row_info) {\ const size_t scrolled_column = (column - horizontal_offset) & 0x1f;\ @@ -717,20 +715,27 @@ class Base { LineBuffer &sprite_selection_buffer = line_buffers_[(write_pointer_.row + 1) % mode_timing_.total_lines]; const int horizontal_offset = (write_pointer_.row >= 16 || !master_system_.horizontal_scroll_lock) ? (line_buffer.latched_horizontal_scroll >> 3) : 0; + // 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_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. - const int scrolled_row = (write_pointer_.row + master_system_.latched_vertical_scroll) % 224; + const int scrolled_row = (write_pointer_.row + master_system_.latched_vertical_scroll) % (is_tall_mode ? 256 : 224); struct RowInfo { size_t pattern_address_base; size_t sub_row[2]; }; const RowInfo scrolled_row_info = { - pattern_name_address_ & static_cast(((scrolled_row & ~7) << 3) | 0x3800), + pattern_name_address & size_t(((scrolled_row & ~7) << 3) | 0x3800) - pattern_name_offset, {static_cast((scrolled_row & 7) << 2), 28 ^ static_cast((scrolled_row & 7) << 2)} }; RowInfo row_info; if(master_system_.vertical_scroll_lock) { - row_info.pattern_address_base = pattern_name_address_ & static_cast(((write_pointer_.row & ~7) << 3) | 0x3800); + row_info.pattern_address_base = pattern_name_address & size_t(((write_pointer_.row & ~7) << 3) | 0x3800) - pattern_name_offset; row_info.sub_row[0] = size_t((write_pointer_.row & 7) << 2); row_info.sub_row[1] = 28 ^ size_t((write_pointer_.row & 7) << 2); } else row_info = scrolled_row_info;