mirror of
https://github.com/holub/mame
synced 2025-07-06 02:18:09 +03:00
315_5124.c: Improved triggering of IRQs. [Enik Land]
(MESS) sms.c: [Enik Land] - Fixed master clock speed for PAL machines. - Improved hcount handling resulting in better results from Flubba's VDP timing checks.
This commit is contained in:
parent
6e9b9f9edb
commit
fe3e4d8640
@ -54,13 +54,13 @@ PAL frame timing
|
||||
#define STATUS_SPRCOL 0x20 /* Object collision flag */
|
||||
#define STATUS_HINT 0x02 /* Pending horizontal interrupt flag */
|
||||
|
||||
#define VINT_HPOS 23
|
||||
#define HINT_HPOS 23
|
||||
#define VCOUNT_CHANGE_HPOS 22
|
||||
#define VINT_FLAG_HPOS 7
|
||||
#define SPROVR_HPOS 6
|
||||
#define SPRCOL_BASEHPOS 42
|
||||
#define DISPLAY_CB_HPOS 5 /* fix X-Scroll latchtime (Flubba's VDPTest) */
|
||||
#define VINT_HPOS 24
|
||||
#define VINT_FLAG_HPOS 23
|
||||
#define HINT_HPOS 25
|
||||
#define VCOUNT_CHANGE_HPOS 23
|
||||
#define SPROVR_HPOS 23
|
||||
#define SPRCOL_BASEHPOS 59
|
||||
#define DISPLAY_CB_HPOS 6 /* fix X-Scroll latchtime (Flubba's VDPTest) */
|
||||
|
||||
#define DRAW_TIME_GG 86 /* 1 + 2 + 14 +8 + 96/2 */
|
||||
#define DRAW_TIME_SMS 0
|
||||
@ -294,45 +294,29 @@ void sega315_5124_device::device_timer(emu_timer &timer, device_timer_id id, int
|
||||
draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, param, m_screen->vpos() - param );
|
||||
break;
|
||||
|
||||
case TIMER_SET_STATUS_VINT:
|
||||
m_status |= STATUS_VINT;
|
||||
break;
|
||||
|
||||
case TIMER_SET_STATUS_SPROVR:
|
||||
m_status |= STATUS_SPROVR;
|
||||
break;
|
||||
|
||||
case TIMER_SET_STATUS_SPRCOL:
|
||||
m_status |= STATUS_SPRCOL;
|
||||
break;
|
||||
|
||||
case TIMER_CHECK_HINT:
|
||||
if (m_line_counter == 0x00)
|
||||
if ((m_pending_status & STATUS_HINT) || (m_status & STATUS_HINT))
|
||||
{
|
||||
m_line_counter = m_reg[0x0a];
|
||||
m_status |= STATUS_HINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_line_counter--;
|
||||
}
|
||||
if ((m_reg[0x00] & 0x10))
|
||||
{
|
||||
m_irq_state = 1;
|
||||
|
||||
if ((m_status & STATUS_HINT) && (m_reg[0x00] & 0x10))
|
||||
{
|
||||
m_irq_state = 1;
|
||||
|
||||
if ( !m_cb_int.isnull() )
|
||||
m_cb_int(ASSERT_LINE);
|
||||
if ( !m_cb_int.isnull() )
|
||||
m_cb_int(ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIMER_CHECK_VINT:
|
||||
if ((m_status & STATUS_VINT) && (m_reg[0x01] & 0x20))
|
||||
if ((m_pending_status & STATUS_VINT) || (m_status & STATUS_VINT))
|
||||
{
|
||||
m_irq_state = 1;
|
||||
if ((m_reg[0x01] & 0x20))
|
||||
{
|
||||
m_irq_state = 1;
|
||||
|
||||
if ( !m_cb_int.isnull() )
|
||||
m_cb_int(ASSERT_LINE);
|
||||
if ( !m_cb_int.isnull() )
|
||||
m_cb_int(ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -349,6 +333,9 @@ void sega315_5124_device::process_line_timer()
|
||||
|
||||
rec.min_y = rec.max_y = vpos;
|
||||
|
||||
/* Activate flags that were pending until the end of previous line. */
|
||||
check_pending_flags(m_screen->width());
|
||||
|
||||
/* Check if we're on the last line of a frame */
|
||||
if (vpos == vpos_limit - 1)
|
||||
{
|
||||
@ -375,7 +362,16 @@ void sega315_5124_device::process_line_timer()
|
||||
{
|
||||
if (vpos == vpos_limit)
|
||||
{
|
||||
m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) );
|
||||
if (m_line_counter == 0x00)
|
||||
{
|
||||
m_line_counter = m_reg[0x0a];
|
||||
m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) );
|
||||
m_pending_status |= STATUS_HINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_line_counter--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -384,8 +380,8 @@ void sega315_5124_device::process_line_timer()
|
||||
|
||||
if (vpos == vpos_limit + 1)
|
||||
{
|
||||
m_set_status_vint_timer->adjust( m_screen->time_until_pos( vpos, VINT_FLAG_HPOS ) );
|
||||
m_check_vint_timer->adjust( m_screen->time_until_pos( vpos, VINT_HPOS ) );
|
||||
m_pending_status |= STATUS_VINT;
|
||||
}
|
||||
|
||||
update_palette();
|
||||
@ -419,7 +415,16 @@ void sega315_5124_device::process_line_timer()
|
||||
m_reg9copy = m_reg[0x09];
|
||||
}
|
||||
|
||||
m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) );
|
||||
if (m_line_counter == 0x00)
|
||||
{
|
||||
m_line_counter = m_reg[0x0a];
|
||||
m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) );
|
||||
m_pending_status |= STATUS_HINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_line_counter--;
|
||||
}
|
||||
|
||||
update_palette();
|
||||
|
||||
@ -488,7 +493,7 @@ READ8_MEMBER( sega315_5124_device::vram_read )
|
||||
/* to the address register when in the middle of doing a command. */
|
||||
/* Cosmic Spacehead needs this, among others */
|
||||
/* Clear pending write flag */
|
||||
m_pending = 0;
|
||||
m_pending_reg_write = 0;
|
||||
|
||||
/* Return read buffer contents */
|
||||
temp = m_buffer;
|
||||
@ -505,14 +510,43 @@ READ8_MEMBER( sega315_5124_device::vram_read )
|
||||
}
|
||||
|
||||
|
||||
void sega315_5124_device::check_pending_flags( int hpos )
|
||||
{
|
||||
if ((m_pending_status & STATUS_HINT) && hpos >= HINT_HPOS)
|
||||
{
|
||||
m_pending_status &= ~STATUS_HINT;
|
||||
m_status |= STATUS_HINT;
|
||||
}
|
||||
if ((m_pending_status & STATUS_VINT) && hpos >= VINT_FLAG_HPOS)
|
||||
{
|
||||
m_pending_status &= ~STATUS_VINT;
|
||||
m_status |= STATUS_VINT;
|
||||
}
|
||||
if ((m_pending_status & STATUS_SPROVR) && hpos >= SPROVR_HPOS)
|
||||
{
|
||||
m_pending_status &= ~STATUS_SPROVR;
|
||||
m_status |= STATUS_SPROVR;
|
||||
}
|
||||
if ((m_pending_status & STATUS_SPRCOL) && hpos >= m_pending_sprcol_x)
|
||||
{
|
||||
m_pending_status &= ~STATUS_SPRCOL;
|
||||
m_status |= STATUS_SPRCOL;
|
||||
m_pending_sprcol_x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
READ8_MEMBER( sega315_5124_device::register_read )
|
||||
{
|
||||
UINT8 temp = m_status;
|
||||
UINT8 temp;
|
||||
|
||||
check_pending_flags(m_screen->hpos());
|
||||
temp = m_status;
|
||||
|
||||
if ( !space.debugger_access() )
|
||||
{
|
||||
/* Clear pending write flag */
|
||||
m_pending = 0;
|
||||
m_pending_reg_write = 0;
|
||||
|
||||
m_status &= ~(STATUS_VINT | STATUS_SPROVR | STATUS_SPRCOL | STATUS_HINT);
|
||||
|
||||
@ -536,7 +570,7 @@ WRITE8_MEMBER( sega315_5124_device::vram_write )
|
||||
/* to the address register when in the middle of doing a command. */
|
||||
/* Cosmic Spacehead needs this, among others */
|
||||
/* Clear pending write flag */
|
||||
m_pending = 0;
|
||||
m_pending_reg_write = 0;
|
||||
|
||||
switch(m_addrmode)
|
||||
{
|
||||
@ -567,15 +601,17 @@ WRITE8_MEMBER( sega315_5124_device::register_write )
|
||||
{
|
||||
int reg_num;
|
||||
|
||||
if (m_pending == 0)
|
||||
check_pending_flags(m_screen->hpos());
|
||||
|
||||
if (m_pending_reg_write == 0)
|
||||
{
|
||||
m_addr = (m_addr & 0xff00) | data;
|
||||
m_pending = 1;
|
||||
m_pending_reg_write = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear pending write flag */
|
||||
m_pending = 0;
|
||||
m_pending_reg_write = 0;
|
||||
|
||||
m_addrmode = (data >> 6) & 0x03;
|
||||
m_addr = (data << 8) | (m_addr & 0xff);
|
||||
@ -599,17 +635,22 @@ WRITE8_MEMBER( sega315_5124_device::register_write )
|
||||
if (reg_num == 0 || reg_num == 1)
|
||||
set_display_settings();
|
||||
|
||||
if (reg_num == 1)
|
||||
if ( ( reg_num == 0 && (m_status & STATUS_HINT) ) ||
|
||||
( reg_num == 1 && (m_status & STATUS_VINT) ) )
|
||||
{
|
||||
m_check_vint_timer->adjust( m_screen->time_until_pos( m_screen->vpos(), VINT_HPOS) );
|
||||
|
||||
// For HINT disabling through register 00:
|
||||
// "Line IRQ VCount" test, of Flubba's VDPTest ROM, disables HINT to wait
|
||||
// for next VINT, but HINT occurs when the operation is about to execute.
|
||||
// So here, where the setting is done, the irq_state needs to be cleared.
|
||||
//
|
||||
// When running eagles5 on the ssm2kr driver the irq_state is 1 because of some
|
||||
// For VINT disabling through register 01:
|
||||
// When running eagles5 on the sms2kr driver the irq_state is 1 because of some
|
||||
// previos HINTs that occured. eagles5 sets register 01 to 0x02 and expects
|
||||
// the irq state to be cleared after that.
|
||||
// The following bit of code takes care of that.
|
||||
//
|
||||
if ((m_status & STATUS_VINT) && !(m_reg[0x01] & 0x20))
|
||||
if ( ( (m_status & STATUS_HINT) && !(m_reg[0x00] & 0x10) ) ||
|
||||
( (m_status & STATUS_VINT) && !(m_reg[0x01] & 0x20) ) )
|
||||
{
|
||||
if (m_irq_state == 1)
|
||||
{
|
||||
@ -621,7 +662,19 @@ WRITE8_MEMBER( sega315_5124_device::register_write )
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For register 01 and VINT enabling:
|
||||
// Assert the IRQ line for the scoreboard of robocop3,
|
||||
// on the sms/smspal driver, be displayed correctly.
|
||||
//
|
||||
// Assume the same behavior for reg0+HINT.
|
||||
//
|
||||
m_irq_state = 1;
|
||||
|
||||
if ( !m_cb_int.isnull() )
|
||||
m_cb_int(ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
m_addrmode = 0;
|
||||
break;
|
||||
@ -842,7 +895,7 @@ void sega315_5124_device::select_sprites( int pixel_plot_y, int line )
|
||||
|
||||
if (line >= 0 && line < m_frame_timing[ACTIVE_DISPLAY_V])
|
||||
{
|
||||
m_set_status_sprovr_timer->adjust( m_screen->time_until_pos( pixel_plot_y + line, SPROVR_HPOS ) );
|
||||
m_pending_status |= STATUS_SPROVR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -999,7 +1052,8 @@ void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_se
|
||||
}
|
||||
if (sprite_col_occurred)
|
||||
{
|
||||
m_set_status_sprcol_timer->adjust( m_screen->time_until_pos( pixel_plot_y + line, SPRCOL_BASEHPOS + sprite_col_x ) );
|
||||
m_pending_status |= STATUS_SPRCOL;
|
||||
m_pending_sprcol_x = SPRCOL_BASEHPOS + sprite_col_x;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1188,7 +1242,8 @@ void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int pixel
|
||||
}
|
||||
if (sprite_col_occurred)
|
||||
{
|
||||
m_set_status_sprcol_timer->adjust( m_screen->time_until_pos( pixel_plot_y + line, SPRCOL_BASEHPOS + sprite_col_x ) );
|
||||
m_pending_status |= STATUS_SPRCOL;
|
||||
m_pending_sprcol_x = SPRCOL_BASEHPOS + sprite_col_x;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1644,19 +1699,18 @@ void sega315_5124_device::device_start()
|
||||
m_display_timer = timer_alloc(TIMER_LINE);
|
||||
m_display_timer->adjust(m_screen->time_until_pos(0, DISPLAY_CB_HPOS), 0, m_screen->scan_period());
|
||||
m_draw_timer = timer_alloc(TIMER_DRAW);
|
||||
m_set_status_vint_timer = timer_alloc( TIMER_SET_STATUS_VINT );
|
||||
m_set_status_sprovr_timer = timer_alloc( TIMER_SET_STATUS_SPROVR );
|
||||
m_set_status_sprcol_timer = timer_alloc( TIMER_SET_STATUS_SPRCOL );
|
||||
m_check_hint_timer = timer_alloc( TIMER_CHECK_HINT );
|
||||
m_check_vint_timer = timer_alloc( TIMER_CHECK_VINT );
|
||||
m_check_hint_timer = timer_alloc(TIMER_CHECK_HINT);
|
||||
m_check_vint_timer = timer_alloc(TIMER_CHECK_VINT);
|
||||
|
||||
save_item(NAME(m_status));
|
||||
save_item(NAME(m_pending_status));
|
||||
save_item(NAME(m_pending_sprcol_x));
|
||||
save_item(NAME(m_reg9copy));
|
||||
save_item(NAME(m_addrmode));
|
||||
save_item(NAME(m_addr));
|
||||
save_item(NAME(m_cram_mask));
|
||||
save_item(NAME(m_cram_dirty));
|
||||
save_item(NAME(m_pending));
|
||||
save_item(NAME(m_pending_reg_write));
|
||||
save_item(NAME(m_buffer));
|
||||
save_item(NAME(m_sega315_5124_compatibility_mode));
|
||||
save_item(NAME(m_irq_state));
|
||||
@ -1686,13 +1740,15 @@ void sega315_5124_device::device_reset()
|
||||
m_reg[0x0a] = 0xff;
|
||||
|
||||
m_status = 0;
|
||||
m_pending_status = 0;
|
||||
m_pending_sprcol_x = 0;
|
||||
m_pending_reg_write = 0;
|
||||
m_reg9copy = 0;
|
||||
m_addrmode = 0;
|
||||
m_addr = 0;
|
||||
m_sega315_5124_compatibility_mode = false;
|
||||
m_cram_mask = m_cram_size - 1;
|
||||
m_cram_dirty = 1;
|
||||
m_pending = 0;
|
||||
m_buffer = 0;
|
||||
m_irq_state = 0;
|
||||
m_line_counter = 0;
|
||||
|
@ -103,6 +103,7 @@ protected:
|
||||
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 check_pending_flags( int hpos );
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_config_complete();
|
||||
@ -114,13 +115,15 @@ protected:
|
||||
|
||||
UINT8 m_reg[16]; /* All the registers */
|
||||
UINT8 m_status; /* Status register */
|
||||
UINT8 m_pending_status; /* Pending status flags */
|
||||
UINT8 m_reg9copy; /* Internal copy of register 9 */
|
||||
UINT8 m_addrmode; /* Type of VDP action */
|
||||
UINT16 m_addr; /* Contents of internal VDP address register */
|
||||
UINT8 m_cram_size; /* CRAM size */
|
||||
UINT8 m_cram_mask; /* Mask to switch between SMS and GG CRAM sizes */
|
||||
int m_cram_dirty; /* Have there been any changes to the CRAM area */
|
||||
int m_pending;
|
||||
int m_pending_reg_write;
|
||||
int m_pending_sprcol_x;
|
||||
UINT8 m_buffer;
|
||||
bool m_sega315_5124_compatibility_mode; /* Shrunk SMS screen on GG lcd mode flag */
|
||||
int m_irq_state; /* The status of the IRQ line of the VDP */
|
||||
@ -132,7 +135,7 @@ protected:
|
||||
memory_region *m_CRAM; /* Pointer to CRAM */
|
||||
const UINT8 *m_frame_timing;
|
||||
bitmap_rgb32 m_tmpbitmap;
|
||||
bitmap_ind8 m_y1_bitmap;
|
||||
bitmap_ind8 m_y1_bitmap;
|
||||
UINT8 m_collision_buffer[SEGA315_5124_WIDTH];
|
||||
UINT8 m_palette_offset;
|
||||
bool m_supports_224_240;
|
||||
@ -150,9 +153,6 @@ protected:
|
||||
devcb_resolved_write_line m_cb_int;
|
||||
devcb_resolved_write_line m_cb_pause;
|
||||
emu_timer *m_display_timer;
|
||||
emu_timer *m_set_status_vint_timer;
|
||||
emu_timer *m_set_status_sprovr_timer;
|
||||
emu_timer *m_set_status_sprcol_timer;
|
||||
emu_timer *m_check_hint_timer;
|
||||
emu_timer *m_check_vint_timer;
|
||||
emu_timer *m_draw_timer;
|
||||
@ -162,12 +162,9 @@ protected:
|
||||
|
||||
/* Timers */
|
||||
static const device_timer_id TIMER_LINE = 0;
|
||||
static const device_timer_id TIMER_SET_STATUS_VINT = 1;
|
||||
static const device_timer_id TIMER_SET_STATUS_SPROVR = 2;
|
||||
static const device_timer_id TIMER_CHECK_HINT = 3;
|
||||
static const device_timer_id TIMER_CHECK_VINT = 4;
|
||||
static const device_timer_id TIMER_SET_STATUS_SPRCOL = 5;
|
||||
static const device_timer_id TIMER_DRAW = 6;
|
||||
static const device_timer_id TIMER_DRAW = 1;
|
||||
static const device_timer_id TIMER_CHECK_HINT = 2;
|
||||
static const device_timer_id TIMER_CHECK_VINT = 3;
|
||||
};
|
||||
|
||||
|
||||
|
@ -70,7 +70,7 @@ DC00 - Selection buttons #2, 9-16 (R)
|
||||
|
||||
#include "sms1.lh"
|
||||
|
||||
#define MASTER_CLOCK_PAL 53203400 /* This might be a tiny bit too low */
|
||||
#define MASTER_CLOCK_PAL 53203425 /* 12 * subcarrier freq. (4.43361875MHz) */
|
||||
|
||||
|
||||
static ADDRESS_MAP_START( sms1_mem, AS_PROGRAM, 8, sms_state )
|
||||
|
@ -391,30 +391,28 @@ int sms_state::lgun_bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y )
|
||||
|
||||
UINT8 sms_state::sms_vdp_hcount()
|
||||
{
|
||||
UINT8 tmp;
|
||||
int hpos = m_main_scr->hpos();
|
||||
UINT64 cycles_per_line;
|
||||
attotime line_remaining_time;
|
||||
UINT64 line_remaining_cycles;
|
||||
UINT64 line_elapsed_cycles;
|
||||
|
||||
/* alternative method: pass HCounter test, but some others fail */
|
||||
//int hpos_tmp = hpos;
|
||||
//if ((hpos + 2) % 6 == 0) hpos_tmp--;
|
||||
//tmp = ((hpos_tmp - 46) >> 1) & 0xff;
|
||||
/* 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;
|
||||
|
||||
UINT64 calc_cycles;
|
||||
attotime time_end;
|
||||
int vpos = m_main_scr->vpos();
|
||||
int max_hpos = m_main_scr->width() - 1;
|
||||
/* 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;
|
||||
|
||||
if (hpos == max_hpos)
|
||||
time_end = attotime::zero;
|
||||
else
|
||||
time_end = m_main_scr->time_until_pos(vpos, max_hpos);
|
||||
calc_cycles = m_main_cpu->attotime_to_clocks(time_end);
|
||||
|
||||
/* equation got from SMSPower forum, posted by Flubba. */
|
||||
tmp = ((590 - (calc_cycles * 3)) / 4) & 0xff;
|
||||
|
||||
//printf ("sms_vdp_hcount: hpos %3d => hcount %2X\n", hpos, tmp);
|
||||
return tmp;
|
||||
/* Alternative hcount equation, restricted to the SMS clock:
|
||||
"(590 - (line_remaining_cycles * 3)) / 4"
|
||||
Posted by Flubba on SMSPower forum. */
|
||||
}
|
||||
|
||||
|
||||
@ -1927,11 +1925,8 @@ MACHINE_START_MEMBER(sms_state,sms)
|
||||
// the "call $4010" without a following RET statement. That is basically
|
||||
// a bug in the program code. The only way this cartridge could have run
|
||||
// successfully on a real unit is if the RAM would be initialized with
|
||||
// a F0 pattern on power up; F0 = RET P.
|
||||
//
|
||||
// alibaba and blockhol SMS cartridges rely on uninitialized RAM,
|
||||
// then fill it with a F0 pattern ("RET P"), but only for consoles
|
||||
// in Japan region (including KR), until confirmed on other consoles.
|
||||
// a F0 pattern on power up; F0 = RET P. Do that only for consoles in
|
||||
// Japan region (including KR), until confirmed on other consoles.
|
||||
if (m_is_region_japan)
|
||||
{
|
||||
memset((UINT8*)m_space->get_write_ptr(0xc000), 0xf0, 0x1FFF);
|
||||
|
Loading…
Reference in New Issue
Block a user