(MESS) Virtual Boy: correct timer handling, gives proper sound/music. [R. Belmont]

This commit is contained in:
R. Belmont 2012-08-24 03:13:51 +00:00
parent 35dd8a910d
commit b863cf56b5

View File

@ -81,9 +81,11 @@ class vboy_state : public driver_device
public: public:
vboy_state(const machine_config &mconfig, device_type type, const char *tag) vboy_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag), : driver_device(mconfig, type, tag),
m_maintimer(*this, "timer_main"),
m_maincpu(*this, "maincpu") m_maincpu(*this, "maincpu")
{ } { }
required_device<timer_device> m_maintimer;
required_device<cpu_device> m_maincpu; required_device<cpu_device> m_maincpu;
DECLARE_READ32_MEMBER(io_r); DECLARE_READ32_MEMBER(io_r);
@ -128,7 +130,7 @@ public:
UINT8 m_drawfb; UINT8 m_drawfb;
UINT8 m_row_num; UINT8 m_row_num;
attotime m_input_latch_time; attotime m_input_latch_time;
void m_timer_tick(UINT8 setting); void m_timer_tick(void);
void m_scanline_tick(int scanline, UINT8 screen_type); void m_scanline_tick(int scanline, UINT8 screen_type);
void m_set_irq(UINT16 irq_vector); void m_set_irq(UINT16 irq_vector);
@ -594,7 +596,7 @@ WRITE32_MEMBER( vboy_state::io_w )
case 0x14: // KHB (Keypad High Byte) case 0x14: // KHB (Keypad High Byte)
//logerror("Ilegal write: offset %02x should be only read\n", offset); //logerror("Ilegal write: offset %02x should be only read\n", offset);
break; break;
case 0x18: // TLB (Timer Low Byte) case 0x18: // TLB (Timer Low Byte)
m_vboy_regs.tlb = data; m_vboy_regs.tlb = data;
m_vboy_timer.latch = m_vboy_regs.tlb | (m_vboy_timer.latch & 0xff00); m_vboy_timer.latch = m_vboy_regs.tlb | (m_vboy_timer.latch & 0xff00);
break; break;
@ -611,16 +613,35 @@ WRITE32_MEMBER( vboy_state::io_w )
---- --x- timer is zero flag ---- --x- timer is zero flag
---- ---x enables timer ---- ---x enables timer
*/ */
if(data & 1) if (!(data & 0x08))
{ {
m_vboy_regs.tlb = m_vboy_timer.latch & 0xff; device_set_input_line(m_maincpu, 1, CLEAR_LINE);
m_vboy_regs.thb = m_vboy_timer.latch >> 8; }
m_vboy_timer.count = m_vboy_timer.latch;
}
m_vboy_regs.tcr = (data & 0xfd) | (0xe4) | (m_vboy_regs.tcr & 2); // according to docs: bits 5, 6 & 7 are unused and set to 1, bit 1 is read only. if (data & 1)
if(data & 4) {
m_vboy_regs.tcr &= 0xfd; m_vboy_regs.tlb = m_vboy_timer.latch & 0xff;
m_vboy_regs.thb = m_vboy_timer.latch >> 8;
m_vboy_timer.count = m_vboy_timer.latch;
// only start timer if tcr & 1 is 1 and wasn't before?
if (!(m_vboy_regs.tcr & 1))
{
if (data & 0x10)
{
m_maintimer->adjust(attotime::from_hz(50000));
}
else
{
m_maintimer->adjust(attotime::from_hz(10000));
}
}
}
m_vboy_regs.tcr = (data & 0xfd) | (0xe4) | (m_vboy_regs.tcr & 2); // according to docs: bits 5, 6 & 7 are unused and set to 1, bit 1 is read only.
if(data & 4)
m_vboy_regs.tcr &= 0xfd;
break; break;
case 0x24: // WCR (Wait State Control Reg) case 0x24: // WCR (Wait State Control Reg)
m_vboy_regs.wcr = data | 0xfc; // according to docs: bits 2 to 7 are unused and set to 1. m_vboy_regs.wcr = data | 0xfc; // according to docs: bits 2 to 7 are unused and set to 1.
@ -1137,42 +1158,53 @@ static MACHINE_RESET(vboy)
state->m_vip_regs.DPCTRL = 2; // ssquash relies on this at boot otherwise no frame_start irq is fired state->m_vip_regs.DPCTRL = 2; // ssquash relies on this at boot otherwise no frame_start irq is fired
state->m_displayfb = 0; state->m_displayfb = 0;
state->m_drawfb = 0; state->m_drawfb = 0;
state->m_vboy_timer.count = 0;
state->m_maintimer->adjust(attotime::never);
} }
void vboy_state::m_timer_tick(UINT8 setting) void vboy_state::m_timer_tick()
{ {
if(m_vboy_regs.tcr & 1 && ((m_vboy_regs.tcr & 0x10) == setting)) if(m_vboy_timer.count > 0)
{ {
if(m_vboy_timer.count != 0) m_vboy_timer.count--;
{ m_vboy_regs.tlb = m_vboy_timer.count & 0xff;
m_vboy_timer.count--; m_vboy_regs.thb = m_vboy_timer.count >> 8;
m_vboy_regs.tlb = m_vboy_timer.count & 0xff; }
m_vboy_regs.thb = m_vboy_timer.count >> 8;
} if (m_vboy_timer.count == 0)
else {
{ m_vboy_timer.count = m_vboy_timer.latch;
m_vboy_timer.count = m_vboy_timer.latch; m_vboy_regs.tcr |= 0x02;
//printf("Zero timer trigger\n"); if(m_vboy_regs.tcr & 8)
m_vboy_regs.tcr |= 0x02; {
if(m_vboy_regs.tcr & 8) device_set_input_line(m_maincpu, 1, ASSERT_LINE);
device_set_input_line(m_maincpu, 1, HOLD_LINE); }
} }
}
if (m_vboy_regs.tcr & 0x10)
{
m_maintimer->adjust(attotime::from_hz(50000));
}
else
{
m_maintimer->adjust(attotime::from_hz(10000));
}
} }
static TIMER_DEVICE_CALLBACK( timer_100us_tick ) static TIMER_DEVICE_CALLBACK( timer_main_tick )
{ {
vboy_state *state = timer.machine().driver_data<vboy_state>(); vboy_state *state = timer.machine().driver_data<vboy_state>();
state->m_timer_tick(0x00); state->m_timer_tick();
} }
static TIMER_DEVICE_CALLBACK( timer_20us_tick ) static TIMER_DEVICE_CALLBACK( timer_pad_tick )
{ {
vboy_state *state = timer.machine().driver_data<vboy_state>(); vboy_state *state = timer.machine().driver_data<vboy_state>();
state->m_timer_tick(0x10); device_set_input_line(state->m_maincpu, 0, HOLD_LINE);
} }
static PALETTE_INIT( vboy ) static PALETTE_INIT( vboy )
@ -1293,8 +1325,11 @@ static MACHINE_CONFIG_START( vboy, vboy_state )
MCFG_MACHINE_RESET(vboy) MCFG_MACHINE_RESET(vboy)
MCFG_TIMER_ADD_PERIODIC("timer_100us", timer_100us_tick, attotime::from_usec(1000)) // programmable timer
MCFG_TIMER_ADD_PERIODIC("timer_20us", timer_20us_tick, attotime::from_msec(20)) MCFG_TIMER_ADD("timer_main", timer_main_tick)
// pad ready, which should be once per VBL
MCFG_TIMER_ADD_PERIODIC("timer_pad", timer_pad_tick, attotime::from_hz(50.038029f))
/* video hardware */ /* video hardware */
MCFG_DEFAULT_LAYOUT(layout_vboy) MCFG_DEFAULT_LAYOUT(layout_vboy)