From 335de9f804f6665d2ffbc20fa6d2bb4a14b8bdee Mon Sep 17 00:00:00 2001 From: Wilbert Pol Date: Tue, 14 May 2013 20:56:54 +0000 Subject: [PATCH] (MESS) sms.c: Change hcount calculation to use screen timings and move it to the VDP. [Enik Land] --- src/emu/video/315_5124.c | 43 +++++++----- src/emu/video/315_5124.h | 12 ++-- src/mess/drivers/sms.c | 2 +- src/mess/includes/sms.h | 4 +- src/mess/machine/sms.c | 142 +++++++++++++++++---------------------- 5 files changed, 94 insertions(+), 109 deletions(-) diff --git a/src/emu/video/315_5124.c b/src/emu/video/315_5124.c index 7dc412eacdc..844d8ebf9c4 100644 --- a/src/emu/video/315_5124.c +++ b/src/emu/video/315_5124.c @@ -56,7 +56,7 @@ PAL frame timing #define VINT_HPOS 24 #define VINT_FLAG_HPOS 23 -#define HINT_HPOS 25 +#define HINT_HPOS 26 #define VCOUNT_CHANGE_HPOS 23 #define SPROVR_HPOS 23 #define SPRCOL_BASEHPOS 59 @@ -261,15 +261,22 @@ READ8_MEMBER( sega315_5124_device::vcount_read ) } -READ8_MEMBER( sega315_5124_device::hcount_latch_read ) +READ8_MEMBER( sega315_5124_device::hcount_read ) { return m_hcounter; } -WRITE8_MEMBER( sega315_5124_device::hcount_latch_write ) +void sega315_5124_device::hcount_latch_at_hpos( int hpos ) { - m_hcounter = data; + /* The emulation core returns a screen hpos that is one position ahead in comparison + with the expected VDP hclock value, if the same range is used (from 0 to width-1). */ + int hclock = hpos - 1; + if (hclock < 0) + hclock += m_screen->width(); + + /* Calculate and write the new hcount. */ + m_hcounter = ((hclock - 46) >> 1) & 0xff; } @@ -440,7 +447,7 @@ void sega315_5124_device::process_line_timer() m_tmpbitmap.fill(machine().pens[m_current_palette[BACKDROP_COLOR]], rec); m_y1_bitmap.fill(1, rec); - select_sprites( vpos_limit, vpos - vpos_limit ); + select_sprites( vpos - vpos_limit ); if ( m_draw_time > 0 ) { m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit ); @@ -475,7 +482,7 @@ void sega315_5124_device::process_line_timer() /* Draw middle of the border */ /* We need to do this through the regular drawing function so it will */ /* be included in the gamegear scaling functions */ - select_sprites( vpos_limit + m_frame_timing[TOP_BORDER], vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); + select_sprites( vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, vpos_limit + m_frame_timing[TOP_BORDER], vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); return; } @@ -807,7 +814,7 @@ void sega315_5124_device::draw_scanline_mode4( int *line_buffer, int *priority_s pixel_plot_x = (0 - (x_scroll & 0x07) + (tile_column << 3) + pixel_plot_x); if (pixel_plot_x >= 0 && pixel_plot_x < 256) { -// logerror("%x %x\n", pixel_plot_x + pixel_offset_x, pixel_plot_y); + //logerror("%x %x\n", pixel_plot_x, line); line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; priority_selected[pixel_plot_x] = priority_select | (pen_selected & 0x0f); } @@ -816,7 +823,7 @@ void sega315_5124_device::draw_scanline_mode4( int *line_buffer, int *priority_s } -void sega315_5124_device::select_sprites( int pixel_plot_y, int line ) +void sega315_5124_device::select_sprites( int line ) { int sprite_index = 0; int max_sprites = 0; @@ -901,10 +908,10 @@ void sega315_5124_device::select_sprites( int pixel_plot_y, int line ) } -void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_selected, int pixel_plot_y, int line ) +void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_selected, int line ) { bool sprite_col_occurred = false; - int sprite_col_x = 1000; + int sprite_col_x = m_screen->width(); /* Draw sprite layer */ @@ -1059,10 +1066,10 @@ void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_se } -void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int pixel_plot_y, int line ) +void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int line ) { bool sprite_col_occurred = false; - int sprite_col_x = 1000; + int sprite_col_x = m_screen->width(); UINT16 sprite_pattern_base = ((m_reg[0x06] & 0x07) << 11); /* Draw sprite layer */ @@ -1355,7 +1362,7 @@ void sega315_5124_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, i } if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) { - draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); + draw_sprites_tms9918_mode( blitline_buffer, line ); } break; @@ -1367,7 +1374,7 @@ void sega315_5124_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, i } if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) { - draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); + draw_sprites_tms9918_mode( blitline_buffer, line ); } break; @@ -1380,7 +1387,7 @@ void sega315_5124_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, i } if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) { - draw_sprites_mode4( blitline_buffer, priority_selected, pixel_plot_y, line ); + draw_sprites_mode4( blitline_buffer, priority_selected, line ); if ( line >= 0 ) { /* Fill column 0 with overscan color from m_reg[0x07] */ @@ -1449,7 +1456,7 @@ void sega315_5378_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, i } if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) { - draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); + draw_sprites_tms9918_mode( blitline_buffer, line ); } break; @@ -1460,7 +1467,7 @@ void sega315_5378_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, i } if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) { - draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); + draw_sprites_tms9918_mode( blitline_buffer, line ); } break; @@ -1473,7 +1480,7 @@ void sega315_5378_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, i } if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) { - draw_sprites_mode4( blitline_buffer, priority_selected, pixel_plot_y, line ); + draw_sprites_mode4( blitline_buffer, priority_selected, line ); if ( line >= 0 ) { /* Fill column 0 with overscan color from m_reg[0x07] */ diff --git a/src/emu/video/315_5124.h b/src/emu/video/315_5124.h index e64c1ac9679..45bc7d539ce 100644 --- a/src/emu/video/315_5124.h +++ b/src/emu/video/315_5124.h @@ -80,8 +80,10 @@ public: DECLARE_READ8_MEMBER( register_read ); DECLARE_WRITE8_MEMBER( register_write ); DECLARE_READ8_MEMBER( vcount_read ); - DECLARE_READ8_MEMBER( hcount_latch_read ); - DECLARE_WRITE8_MEMBER( hcount_latch_write ); + DECLARE_READ8_MEMBER( hcount_read ); + + void hcount_latch() { hcount_latch_at_hpos( m_screen->hpos() ); }; + void hcount_latch_at_hpos( int hpos ); bitmap_rgb32 &get_bitmap() { return m_tmpbitmap; }; bitmap_ind8 &get_y1_bitmap() { return m_y1_bitmap; }; @@ -98,11 +100,11 @@ protected: virtual UINT16 get_name_table_address(); 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 pixel_plot_y, int line ); - void draw_sprites_tms9918_mode( int *line_buffer, int pixel_plot_y, int line ); + void draw_sprites_mode4( int *line_buffer, int *priority_selected, int line ); + void draw_sprites_tms9918_mode( int *line_buffer, int line ); void draw_scanline_mode2( int *line_buffer, int line ); void draw_scanline_mode0( int *line_buffer, int line ); - void select_sprites( int pixel_plot_y, int line ); + void select_sprites( int line ); void check_pending_flags( int hpos ); // device-level overrides diff --git a/src/mess/drivers/sms.c b/src/mess/drivers/sms.c index 0a0ad8ae79b..e373b9b07a0 100644 --- a/src/mess/drivers/sms.c +++ b/src/mess/drivers/sms.c @@ -243,7 +243,7 @@ static INPUT_PORTS_START( sms ) PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR( X, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_state, lgun2_changed, NULL) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10) PORT_START("LPHASER3") /* Light phaser Y - player 2 */ - PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR( Y, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(25) PORT_PLAYER(2) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_state, lgun2_changed, NULL) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10) + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR( Y, 1.0, 0.0, 0 ) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_state, lgun2_changed, NULL) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10) PORT_START("RFU") /* Rapid Fire Unit */ PORT_CONFNAME( 0x03, 0x00, "Rapid Fire Unit - Player 1" ) diff --git a/src/mess/includes/sms.h b/src/mess/includes/sms.h index 29f795942c4..0da6c19efe3 100644 --- a/src/mess/includes/sms.h +++ b/src/mess/includes/sms.h @@ -216,14 +216,12 @@ protected: required_shared_ptr m_mainram; void setup_rom(); - void vdp_hcount_lphaser(int hpos); + void lphaser_hcount_latch(int hpos); void lphaser1_sensor_check(); void lphaser2_sensor_check(); UINT16 screen_hpos_nonscaled(int scaled_hpos); UINT16 screen_vpos_nonscaled(int scaled_vpos); int lgun_bright_aim_area(emu_timer *timer, int lgun_x, int lgun_y); - void sms_vdp_hcount_latch(address_space &space); - UINT8 sms_vdp_hcount(); void setup_cart_banks(); void setup_banks(); void sms_get_inputs(address_space &space); diff --git a/src/mess/machine/sms.c b/src/mess/machine/sms.c index 2048b981479..c4b3134c616 100644 --- a/src/mess/machine/sms.c +++ b/src/mess/machine/sms.c @@ -279,18 +279,6 @@ WRITE8_MEMBER(sms_state::sms_input_write) } } -/* FIXME: this function is a hack for Light Phaser emulation. Theoretically - sms_vdp_hcount_latch() should be used instead, but it returns incorrect - position for unknown reason (timing?) */ -void sms_state::vdp_hcount_lphaser( int hpos ) -{ - int hpos_tmp = hpos + m_lphaser_x_offs; - UINT8 tmp = ((hpos_tmp - 46) >> 1) & 0xff; - - //printf ("sms_vdp_hcount_lphaser: hpos %3d hpos_tmp %3d => hcount %2X\n", hpos, hpos_tmp, tmp); - m_vdp->hcount_latch_write(*m_space, 0, tmp); -} - /* Light Phaser (light gun) emulation notes: @@ -323,12 +311,13 @@ int sms_state::lgun_bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y ) int dx, dy; int result = 0; int pos_changed = 0; - double dx_circ; + double dx_radius; while (1) { + /* If beam's y isn't at a line where the aim area is, change it + the next line it enters that area. */ dy = abs(beam_y - lgun_y); - if (dy > LGUN_RADIUS || beam_y < visarea.min_y || beam_y > visarea.max_y) { beam_y = lgun_y - LGUN_RADIUS; @@ -337,21 +326,38 @@ int sms_state::lgun_bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y ) dy = abs(beam_y - lgun_y); pos_changed = 1; } - /* step 1: r^2 = dx^2 + dy^2 */ - /* step 2: dx^2 = r^2 - dy^2 */ - /* step 3: dx = sqrt(r^2 - dy^2) */ - dx_circ = ceil((float) sqrt((float) (r_x_r - (dy * dy)))); - dx = abs(beam_x - lgun_x); - if (dx > dx_circ || beam_x < visarea.min_x || beam_x > visarea.max_x) + /* Caculate distance in x of the radius, relative to beam's y distance. + First try some shortcuts. */ + switch (dy) + { + case LGUN_RADIUS: + dx_radius = 0; + break; + case 0: + dx_radius = LGUN_RADIUS; + break; + default: + /* step 1: r^2 = dx^2 + dy^2 */ + /* step 2: dx^2 = r^2 - dy^2 */ + /* step 3: dx = sqrt(r^2 - dy^2) */ + dx_radius = ceil((float) sqrt((float) (r_x_r - (dy * dy)))); + } + + /* If beam's x isn't in the circular aim area, change it + to the next point it enters that area. */ + dx = abs(beam_x - lgun_x); + if (dx > dx_radius || beam_x < visarea.min_x || beam_x > visarea.max_x) { + /* If beam's x has passed the aim area, advance to + next line and recheck y/x coordinates. */ if (beam_x > lgun_x) { beam_x = 0; beam_y++; continue; } - beam_x = lgun_x - dx_circ; + beam_x = lgun_x - dx_radius; if (beam_x < visarea.min_x) beam_x = visarea.min_x; pos_changed = 1; @@ -389,45 +395,19 @@ int sms_state::lgun_bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y ) return result; } -UINT8 sms_state::sms_vdp_hcount() + +void sms_state::lphaser_hcount_latch( int hpos ) { - UINT64 cycles_per_line; - attotime line_remaining_time; - UINT64 line_remaining_cycles; - UINT64 line_elapsed_cycles; - - /* Calculate amount of CPU cycles according to screen references. - If some day the screen become always synced to the CPU, in the - proportion of their speeds, this may be replaced by the screen - hpos position only and the function be moved to the VDP file. */ - cycles_per_line = m_main_cpu->attotime_to_clocks(m_main_scr->scan_period()); - line_remaining_time = m_main_scr->time_until_pos(m_main_scr->vpos(), m_main_scr->width()); - line_remaining_cycles = m_main_cpu->attotime_to_clocks(line_remaining_time) % cycles_per_line; - line_elapsed_cycles = cycles_per_line - line_remaining_cycles; - - /* HCount equation, being hpos = VDP hclocks: "(hpos - 47) / 2" - Screen hpos based on CPU cycles: "cycles * width / cycles per line" - Do both in same line for one-step rounding only (required). */ - return ((line_elapsed_cycles * m_main_scr->width() / cycles_per_line) - 47) / 2; - - /* Alternative hcount equation, restricted to the SMS clock: - "(590 - (line_remaining_cycles * 3)) / 4" - Posted by Flubba on SMSPower forum. */ -} - - -void sms_state::sms_vdp_hcount_latch( address_space &space ) -{ - UINT8 value = sms_vdp_hcount(); - - m_vdp->hcount_latch_write(space, 0, value); + /* A delay seems to occur when the Light Phaser latches the + VDP hcount, then an offset is added here to the hpos. */ + m_vdp->hcount_latch_at_hpos(hpos + m_lphaser_x_offs); } UINT16 sms_state::screen_hpos_nonscaled(int scaled_hpos) { const rectangle &visarea = m_main_scr->visible_area(); - int offset_x = (scaled_hpos * visarea.width()) / 255; + int offset_x = (scaled_hpos * (visarea.max_x - visarea.min_x)) / 255; return visarea.min_x + offset_x; } @@ -450,7 +430,7 @@ void sms_state::lphaser1_sensor_check() if (m_lphaser_1_latch == 0) { m_lphaser_1_latch = 1; - vdp_hcount_lphaser(x); + lphaser_hcount_latch(x); } } } @@ -465,7 +445,7 @@ void sms_state::lphaser2_sensor_check() if (m_lphaser_2_latch == 0) { m_lphaser_2_latch = 1; - vdp_hcount_lphaser(x); + lphaser_hcount_latch(x); } } } @@ -573,13 +553,13 @@ void sms_state::sms_get_inputs( address_space &space ) case 0x01: /* Light Phaser */ data = (ioport("CTRLIPT")->read() & 0x01) << 4; - if (!(data & 0x10)) - { - if (ioport("RFU")->read() & 0x01) - data |= m_rapid_fire_state_1 & 0x10; - } - /* just consider the button (trigger) bit */ + /* Check Rapid Fire setting for Trigger */ + if (!(data & 0x10) && (ioport("RFU")->read() & 0x01)) + data |= m_rapid_fire_state_1 & 0x10; + + /* just consider the trigger (button) bit */ data |= ~0x10; + m_input_port0 = (m_input_port0 & 0xc0) | (data & 0x3f); break; @@ -635,13 +615,13 @@ void sms_state::sms_get_inputs( address_space &space ) case 0x10: /* Light Phaser */ data = (ioport("CTRLIPT")->read() & 0x10) >> 2; - if (!(data & 0x04)) - { - if (ioport("RFU")->read() & 0x04) - data |= m_rapid_fire_state_2 & 0x04; - } - /* just consider the button (trigger) bit */ + /* Check Rapid Fire setting for Trigger */ + if (!(data & 0x04) && (ioport("RFU")->read() & 0x04)) + data |= m_rapid_fire_state_2 & 0x04; + + /* just consider the trigger (button) bit */ data |= ~0x04; + m_input_port1 = (m_input_port1 & 0xf0) | (data & 0x0f); break; @@ -708,14 +688,14 @@ READ8_MEMBER(sms_state::sms_fm_detect_r) WRITE8_MEMBER(sms_state::sms_io_control_w) { - bool hcount_latch = false; + bool latch_hcount = false; if (data & 0x08) { /* check if TH pin level is high (1) and was low last time */ if (data & 0x80 && !(m_ctrl_reg & 0x80)) { - hcount_latch = true; + latch_hcount = true; } sms_input_write(space, 0, (data & 0x20) >> 5); } @@ -724,14 +704,14 @@ WRITE8_MEMBER(sms_state::sms_io_control_w) { if (data & 0x20 && !(m_ctrl_reg & 0x20)) { - hcount_latch = true; + latch_hcount = true; } sms_input_write(space, 1, (data & 0x80) >> 7); } - if (hcount_latch) + if (latch_hcount) { - sms_vdp_hcount_latch(space); + m_vdp->hcount_latch(); } m_ctrl_reg = data; @@ -741,7 +721,7 @@ WRITE8_MEMBER(sms_state::sms_io_control_w) READ8_MEMBER(sms_state::sms_count_r) { if (offset & 0x01) - return m_vdp->hcount_latch_read(*m_space, offset); + return m_vdp->hcount_read(*m_space, offset); else return m_vdp->vcount_read(*m_space, offset); } @@ -1531,22 +1511,22 @@ int sms_state::detect_lphaser_xoffset( UINT8 *rom ) if (!(m_bios_port & IO_CARTRIDGE) && m_cartridge[m_current_cartridge].size >= 0x8000) { if (!memcmp(&rom[0x7ff0], signatures[0], 16) || !memcmp(&rom[0x7ff0], signatures[1], 16)) - return 40; + return 41; if (!memcmp(&rom[0x7ff0], signatures[2], 16)) - return 49; + return 50; if (!memcmp(&rom[0x7ff0], signatures[3], 16)) - return 47; + return 48; if (!memcmp(&rom[0x7ff0], signatures[4], 16)) - return 44; + return 45; if (!memcmp(&rom[0x7ff0], signatures[5], 16)) - return 53; + return 54; } - return 50; + return 51; } @@ -2260,9 +2240,7 @@ UINT32 sms_state::screen_update_sms(screen_device &screen, bitmap_rgb32 &bitmap, VIDEO_START_MEMBER(sms_state,gamegear) { - screen_device *screen = machine().first_screen(); - - screen->register_screen_bitmap(m_prev_bitmap); + m_main_scr->register_screen_bitmap(m_prev_bitmap); save_item(NAME(m_prev_bitmap)); }