diff --git a/src/devices/video/315_5124.cpp b/src/devices/video/315_5124.cpp index c08082d54c5..fc237f42124 100644 --- a/src/devices/video/315_5124.cpp +++ b/src/devices/video/315_5124.cpp @@ -621,7 +621,7 @@ READ8_MEMBER( sega315_5124_device::data_read ) if ( !machine().side_effects_disabled() ) { - /* Load read buffer */ + /* Load data buffer */ m_buffer = this->space().read_byte(m_addr & 0x3fff); /* Bump internal address register */ @@ -910,30 +910,35 @@ uint16_t sega315_5246_device::name_table_row_mode4(int row) } -void sega315_5124_device::draw_column0_x_scroll_mode4(int *line_buffer, int *priority_selected, int x_scroll_fine_adjust, int palette_selected, int tile_line) +void sega315_5124_device::draw_leftmost_pixels_mode4(int *line_buffer, int *priority_selected, int fine_x_scroll, int palette_selected, int tile_line) { - // To draw the leftmost column when it is incomplete on screen due to - // scrolling, Sega Master System has a weird behaviour to select which - // palette will be used to obtain the color in entry 0, that depends - // on the content of sprite 0. + // To draw the leftmost pixels when they aren't part of a tile column + // due to scrolling, Sega Master System has a weird behaviour to select + // which palette will be used to obtain the color in entry 0, that + // depends on the content of tile 0x100. // This implementation mimics the behaviour of the Emulicious emulator, // seen with the test ROM provided by sverx here: // // http://www.smspower.org/forums/15653-CommunityEffortRequestHelpDiscoverHowTheVDPHandlesTheLeftmostPixelsWhenScrolling // - // From the sprite 0 tile, it uses bit 1 of the plane that would + // From the tile 0x100, it uses bit 1 of the plane that would // select the color for the pixel 4 at the current line. const int pixel_x = 4; + // The parsing seems to occur before the line counter is incremented + // to the number of the line to be drawn. + int parse_line = tile_line - 1; - // Locate the tile number for sprite 0. - const int sprite_tile_selected = select_sprite_tile_mode4(0, tile_line & 0x07); + // Select tile 0x100. + // Tried before with the number stored in m_sprite_tile_selected[0], + // but with it the expected behaviour only occurs with some BIOSes. + const int tile_selected = 0x100; - // Load data of bit plane 1 for the sprite tile. - const int tmp_bit_plane_1 = space().read_byte((sprite_tile_selected << 5) + ((tile_line & 0x07) << 2) + 0x01); + // Load data of bit plane 1 for the selected tile. + const int tmp_bit_plane_1 = space().read_byte((tile_selected << 5) + ((parse_line & 0x07) << 2) + 0x01); const uint8_t pen_bit_1 = BIT(tmp_bit_plane_1, 7 - pixel_x); - for (int pixel_plot_x = 0; pixel_plot_x < x_scroll_fine_adjust; pixel_plot_x++) + for (int pixel_plot_x = 0; pixel_plot_x < fine_x_scroll; pixel_plot_x++) { line_buffer[pixel_plot_x] = m_current_palette[pen_bit_1 ? 0x10 : 0x00]; priority_selected[pixel_plot_x] = 0; @@ -941,13 +946,13 @@ void sega315_5124_device::draw_column0_x_scroll_mode4(int *line_buffer, int *pri } -void sega315_5313_mode4_device::draw_column0_x_scroll_mode4(int *line_buffer, int *priority_selected, int x_scroll_fine_adjust, int palette_selected, int tile_line) +void sega315_5313_mode4_device::draw_leftmost_pixels_mode4(int *line_buffer, int *priority_selected, int fine_x_scroll, int palette_selected, int tile_line) { - // To draw the leftmost column when it is incomplete on screen due to - // scrolling, Sega Genesis/Mega Drive seems to use entry #0 of the - // palette selected by the next background tile to be drawn on screen. + // To draw the leftmost pixels when they aren't part of a tile column + // due to scrolling, Sega Genesis/Mega Drive seems to use entry #0 of + // the palette selected by the next background tile to be drawn on screen. - for (int pixel_plot_x = 0; pixel_plot_x < x_scroll_fine_adjust; pixel_plot_x++) + for (int pixel_plot_x = 0; pixel_plot_x < fine_x_scroll; pixel_plot_x++) { line_buffer[pixel_plot_x] = m_current_palette[palette_selected ? 0x10 : 0x00]; priority_selected[pixel_plot_x] = 0; @@ -965,7 +970,7 @@ void sega315_5124_device::draw_scanline_mode4( int *line_buffer, int *priority_s const int x_scroll = ((BIT(m_reg[0x00], 6) && (line < 16)) ? 0 : m_reg8copy); const int x_scroll_start_column = 32 - (x_scroll >> 3); /* x starting column tile */ - const int x_scroll_fine_adjust = (x_scroll & 0x07); + const int fine_x_scroll = (x_scroll & 0x07); if ( m_y_pixels != 192 ) { @@ -1008,9 +1013,9 @@ void sega315_5124_device::draw_scanline_mode4( int *line_buffer, int *priority_s /* Column 0 is the leftmost tile column that completely entered in the screen. If the leftmost pixels aren't part of a complete tile, due to horizontal scrolling, they are drawn only with color #0 of the selected palette. */ - if (tile_column == 0 && x_scroll_fine_adjust > 0) + if (tile_column == 0 && fine_x_scroll > 0) { - draw_column0_x_scroll_mode4(line_buffer, priority_selected, x_scroll_fine_adjust, palette_selected, tile_line); + draw_leftmost_pixels_mode4(line_buffer, priority_selected, fine_x_scroll, palette_selected, tile_line); } for (int pixel_x = 0; pixel_x < 8; pixel_x++) @@ -1036,7 +1041,7 @@ void sega315_5124_device::draw_scanline_mode4( int *line_buffer, int *priority_s pixel_plot_x = 7 - pixel_x; } - pixel_plot_x = x_scroll_fine_adjust + (tile_column << 3) + pixel_plot_x; + pixel_plot_x = fine_x_scroll + (tile_column << 3) + pixel_plot_x; if (pixel_plot_x < 256) { line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; @@ -1071,31 +1076,6 @@ uint8_t sega315_5246_device::sprite_tile_mask_mode4(uint8_t tile_number) } -int sega315_5124_device::select_sprite_tile_mode4(int sprite_index, int sprite_line) -{ - int sprite_tile_selected = space().read_byte( sprite_attributes_addr_mode4(m_sprite_base + 0x81) + (sprite_index << 1) ); - - sprite_tile_selected = sprite_tile_mask_mode4(sprite_tile_selected); - - if (BIT(m_reg[0x06], 2)) - { - sprite_tile_selected += 256; /* pattern table select */ - } - - if (m_sprite_height == 16) - { - sprite_tile_selected &= 0x01fe; /* force even index */ - } - - if (sprite_line > 0x07) - { - sprite_tile_selected += 1; - } - - return sprite_tile_selected; -} - - void sega315_5124_device::sprite_count_overflow(int line, int sprite_index) { /* Overflow is flagged only on active display and when VINT isn't active */ @@ -1154,7 +1134,7 @@ void sega315_5124_device::select_sprites( int line ) sprite_y -= 256; /* wrap from top if y position is >= 240 */ } - if (m_sprite_zoom_scale > 1 && m_sprite_count <= m_max_sprite_zoom_vcount) + if (m_sprite_zoom_scale > 1 && m_sprite_count < m_max_sprite_zoom_vcount) { /* Divide before use the value for comparison, or else an off-by-one bug could occur, as seen with Tarzan, for Game Gear */ @@ -1220,7 +1200,7 @@ void sega315_5124_device::select_sprites( int line ) sprite_y -= 256; /* wrap from top if y position is >= 240 */ } - if (m_sprite_zoom_scale > 1 && m_sprite_count <= m_max_sprite_zoom_vcount) + if (m_sprite_zoom_scale > 1 && m_sprite_count < m_max_sprite_zoom_vcount) { /* Divide before use the value for comparison, or else an off-by-one bug could occur, as seen with Tarzan, for Game Gear */ @@ -1233,14 +1213,31 @@ void sega315_5124_device::select_sprites( int line ) if (m_sprite_count < max_sprites) { const int sprite_line = parse_line - sprite_y; - const int sprite_tile_selected = select_sprite_tile_mode4(sprite_index, sprite_line); int sprite_x = space().read_byte( sprite_attributes_addr_mode4(m_sprite_base + 0x80) + (sprite_index << 1) ); + int sprite_tile_selected = space().read_byte( sprite_attributes_addr_mode4(m_sprite_base + 0x81) + (sprite_index << 1) ); + + sprite_tile_selected = sprite_tile_mask_mode4(sprite_tile_selected); if (BIT(m_reg[0x00], 3)) { sprite_x -= 0x08; /* sprite shift */ } + if (BIT(m_reg[0x06], 2)) + { + sprite_tile_selected += 256; /* pattern table select */ + } + + if (m_sprite_height == 16) + { + sprite_tile_selected &= 0x01fe; /* force even index */ + } + + if (sprite_line > 0x07) + { + sprite_tile_selected += 1; + } + m_sprite_x[m_sprite_count] = sprite_x; m_sprite_tile_selected[m_sprite_count] = sprite_tile_selected; m_sprite_pattern_line[m_sprite_count] = ((sprite_line & 0x07) << 2); @@ -1309,8 +1306,13 @@ void sega315_5313_mode4_device::sprite_collision(int line, int sprite_col_x) { if (line >= 0 && line < m_frame_timing[ACTIVE_DISPLAY_V]) { - m_pending_status |= STATUS_SPRCOL; - m_pending_sprcol_x = m_line_timing[SPRCOL_BASEHPOS]; + // This function is been used to check for sprite collision of + // the 315-5313 VDP, that occurs before the active screen is + // drawn, so it must not flag a collision again when drawing. + if (screen().hpos() < m_draw_time) { + m_pending_status |= STATUS_SPRCOL; + m_pending_sprcol_x = m_line_timing[SPRCOL_BASEHPOS]; + } } } @@ -1332,7 +1334,7 @@ void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_se const int sprite_x = m_sprite_x[sprite_buffer_index]; const int sprite_tile_selected = m_sprite_tile_selected[sprite_buffer_index]; const uint16_t sprite_pattern_line = m_sprite_pattern_line[sprite_buffer_index]; - const int zoom_scale = sprite_buffer_index <= m_max_sprite_zoom_hcount ? m_sprite_zoom_scale : 1; + const int zoom_scale = sprite_buffer_index < m_max_sprite_zoom_hcount ? m_sprite_zoom_scale : 1; const uint8_t bit_plane_0 = space().read_byte((sprite_tile_selected << 5) + sprite_pattern_line + 0x00); const uint8_t bit_plane_1 = space().read_byte((sprite_tile_selected << 5) + sprite_pattern_line + 0x01); @@ -1429,7 +1431,7 @@ void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int line const uint16_t sprite_pattern_line = m_sprite_pattern_line[sprite_buffer_index]; const uint8_t flags = m_sprite_flags[sprite_buffer_index]; const int pen_selected = m_palette_offset + ( flags & 0x0f ); - const int zoom_scale = sprite_buffer_index <= m_max_sprite_zoom_hcount ? m_sprite_zoom_scale : 1; + const int zoom_scale = sprite_buffer_index < m_max_sprite_zoom_hcount ? m_sprite_zoom_scale : 1; if (BIT(flags, 7)) sprite_x -= 32; diff --git a/src/devices/video/315_5124.h b/src/devices/video/315_5124.h index 962d2c917d6..2daa2f15910 100644 --- a/src/devices/video/315_5124.h +++ b/src/devices/video/315_5124.h @@ -107,11 +107,10 @@ protected: virtual void sprite_count_overflow(int line, int sprite_index); virtual void draw_scanline(int pixel_offset_x, int pixel_plot_y, int line); virtual void blit_scanline(int *line_buffer, int *priority_selected, int pixel_offset_x, int pixel_plot_y, int line); - virtual void draw_column0_x_scroll_mode4(int *line_buffer, int *priority_selected, int x_scroll_fine_adjust, int palette_selected, int tile_line); + virtual void draw_leftmost_pixels_mode4(int *line_buffer, int *priority_selected, int fine_x_scroll, int palette_selected, int tile_line); virtual uint16_t name_table_row_mode4(int row); virtual uint16_t sprite_attributes_addr_mode4(uint16_t base); virtual uint8_t sprite_tile_mask_mode4(uint8_t tile_number); - virtual int select_sprite_tile_mode4(int sprite_index, int sprite_line); void process_line_timer(); void draw_scanline_mode4(int *line_buffer, int *priority_selected, int line); void draw_sprites_mode4(int *line_buffer, int *priority_selected, int line); @@ -246,7 +245,7 @@ protected: virtual void sprite_count_overflow(int line, int sprite_index) override; virtual void select_display_mode() override; virtual void select_extended_res_mode4(bool M1, bool M2, bool M3) override; - virtual void draw_column0_x_scroll_mode4(int *line_buffer, int *priority_selected, int x_scroll_fine_adjust, int palette_selected, int tile_line) override; + virtual void draw_leftmost_pixels_mode4(int *line_buffer, int *priority_selected, int fine_x_scroll, int palette_selected, int tile_line) override; };