mirror of
https://github.com/holub/mame
synced 2025-04-22 08:22:15 +03:00
snk/ngp.cpp: Improved real-time clock behavior - fixes MT05279. (#12855)
This commit is contained in:
parent
b4587b38ac
commit
17d7b7cf3c
@ -4,6 +4,10 @@
|
||||
|
||||
SNK NeoGeo Pocket driver
|
||||
|
||||
After setting the initial console settings power cycle the unit at least once,
|
||||
otherwise the settings will not be saved properly.
|
||||
|
||||
|
||||
The NeoGeo Pocket (Color) contains one big chip which contains the following
|
||||
components:
|
||||
- Toshiba TLCS-900/H cpu core with 64KB ROM
|
||||
@ -98,6 +102,7 @@ the Neogeo Pocket.
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "k1ge.h"
|
||||
|
||||
#include "bus/generic/slot.h"
|
||||
#include "bus/generic/carts.h"
|
||||
@ -106,7 +111,7 @@ the Neogeo Pocket.
|
||||
#include "sound/t6w28.h"
|
||||
#include "sound/dac.h"
|
||||
|
||||
#include "k1ge.h"
|
||||
#include "dirtc.h"
|
||||
#include "screen.h"
|
||||
#include "softlist_dev.h"
|
||||
#include "speaker.h"
|
||||
@ -128,13 +133,15 @@ enum flash_state
|
||||
};
|
||||
|
||||
|
||||
class ngp_state : public driver_device, public device_nvram_interface
|
||||
class ngp_state : public driver_device, public device_nvram_interface, device_rtc_interface
|
||||
{
|
||||
public:
|
||||
ngp_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
driver_device(mconfig, type, tag),
|
||||
device_nvram_interface(mconfig, *this),
|
||||
device_rtc_interface(mconfig, *this),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_screen(*this, "screen"),
|
||||
m_z80(*this, "soundcpu"),
|
||||
m_t6w28(*this, "t6w28"),
|
||||
m_ldac(*this, "ldac"),
|
||||
@ -155,6 +162,7 @@ public:
|
||||
protected:
|
||||
virtual void machine_start() override ATTR_COLD;
|
||||
virtual void machine_reset() override ATTR_COLD;
|
||||
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override ATTR_COLD;
|
||||
|
||||
private:
|
||||
|
||||
@ -173,6 +181,7 @@ private:
|
||||
} m_flash_chip[2];
|
||||
|
||||
required_device<tmp95c061_device> m_maincpu;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<cpu_device> m_z80;
|
||||
required_device<t6w28_device> m_t6w28;
|
||||
required_device<dac_byte_interface> m_ldac;
|
||||
@ -219,34 +228,7 @@ private:
|
||||
|
||||
TIMER_CALLBACK_MEMBER(ngp_state::ngp_seconds_callback)
|
||||
{
|
||||
m_io_reg[0x16] += 1;
|
||||
if ((m_io_reg[0x16] & 0x0f) == 0x0a)
|
||||
{
|
||||
m_io_reg[0x16] += 0x06;
|
||||
}
|
||||
|
||||
if (m_io_reg[0x16] >= 0x60)
|
||||
{
|
||||
m_io_reg[0x16] = 0;
|
||||
m_io_reg[0x15] += 1;
|
||||
if ((m_io_reg[0x15] & 0x0f) == 0x0a) {
|
||||
m_io_reg[0x15] += 0x06;
|
||||
}
|
||||
|
||||
if (m_io_reg[0x15] >= 0x60)
|
||||
{
|
||||
m_io_reg[0x15] = 0;
|
||||
m_io_reg[0x14] += 1;
|
||||
if ((m_io_reg[0x14] & 0x0f) == 0x0a) {
|
||||
m_io_reg[0x14] += 0x06;
|
||||
}
|
||||
|
||||
if (m_io_reg[0x14] == 0x24)
|
||||
{
|
||||
m_io_reg[0x14] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
advance_seconds();
|
||||
}
|
||||
|
||||
|
||||
@ -256,12 +238,23 @@ uint8_t ngp_state::ngp_io_r(offs_t offset)
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case 0x30: /* Read controls */
|
||||
data = m_io_controls->read();
|
||||
break;
|
||||
case 0x11: // year
|
||||
return convert_to_bcd(get_clock_register(RTC_YEAR) % 100);
|
||||
case 0x12: // month
|
||||
return convert_to_bcd(get_clock_register(RTC_MONTH));
|
||||
case 0x13: // day
|
||||
return convert_to_bcd(get_clock_register(RTC_DAY));
|
||||
case 0x14: // hour
|
||||
return convert_to_bcd(get_clock_register(RTC_HOUR));
|
||||
case 0x15: // minute
|
||||
return convert_to_bcd(get_clock_register(RTC_MINUTE));
|
||||
case 0x16: // second
|
||||
return convert_to_bcd(get_clock_register(RTC_SECOND));
|
||||
case 0x30: // Read controls
|
||||
return m_io_controls->read();
|
||||
case 0x31:
|
||||
data = m_io_power->read() & 0x01;
|
||||
/* Sub-battery OK */
|
||||
// Sub-battery OK
|
||||
data |= 0x02;
|
||||
break;
|
||||
}
|
||||
@ -273,52 +266,67 @@ void ngp_state::ngp_io_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x20: /* t6w28 "right" */
|
||||
case 0x21: /* t6w28 "left" */
|
||||
case 0x11: // year
|
||||
set_clock_register(RTC_YEAR, bcd_to_integer(data));
|
||||
break;
|
||||
case 0x12: // month
|
||||
set_clock_register(RTC_MONTH, bcd_to_integer(data));
|
||||
break;
|
||||
case 0x13: // day
|
||||
set_clock_register(RTC_DAY, bcd_to_integer(data));
|
||||
break;
|
||||
case 0x14: // hour
|
||||
set_clock_register(RTC_HOUR, bcd_to_integer(data));
|
||||
break;
|
||||
case 0x15: // minute
|
||||
set_clock_register(RTC_MINUTE, bcd_to_integer(data));
|
||||
break;
|
||||
case 0x16: // second
|
||||
set_clock_register(RTC_SECOND, bcd_to_integer(data));
|
||||
break;
|
||||
case 0x20: // t6w28 "right"
|
||||
case 0x21: // t6w28 "left"
|
||||
if (m_io_reg[0x38] == 0x55 && m_io_reg[0x39] == 0xAA)
|
||||
{
|
||||
m_t6w28->write(0, data);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x22: /* DAC right */
|
||||
case 0x22: // DAC right
|
||||
m_rdac->write(data);
|
||||
break;
|
||||
case 0x23: /* DAC left */
|
||||
case 0x23: // DAC left
|
||||
m_ldac->write(data);
|
||||
break;
|
||||
|
||||
/* Internal eeprom related? */
|
||||
case 0x36:
|
||||
case 0x36: // 50 written when system powers down, 05 written when system starts up
|
||||
case 0x37:
|
||||
break;
|
||||
case 0x38: /* Sound enable/disable. */
|
||||
case 0x38: // Sound enable/disable.
|
||||
switch (data)
|
||||
{
|
||||
case 0x55: /* Enabled sound */
|
||||
case 0x55: // Enabled sound
|
||||
m_t6w28->set_enable(true);
|
||||
break;
|
||||
case 0xAA: /* Disable sound */
|
||||
case 0xAA: // Disable sound
|
||||
m_t6w28->set_enable(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x39: /* Z80 enable/disable. */
|
||||
case 0x39: // Z80 enable/disable.
|
||||
switch (data)
|
||||
{
|
||||
case 0x55: /* Enable Z80 */
|
||||
case 0x55: // Enable Z80
|
||||
m_z80->resume(SUSPEND_REASON_HALT);
|
||||
m_z80->reset();
|
||||
m_z80->set_input_line(0, CLEAR_LINE);
|
||||
break;
|
||||
case 0xAA: /* Disable Z80 */
|
||||
case 0xAA: // Disable Z80
|
||||
m_z80->suspend(SUSPEND_REASON_HALT, 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3a: /* Trigger Z80 NMI */
|
||||
case 0x3a: // Trigger Z80 NMI
|
||||
m_z80->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
|
||||
break;
|
||||
}
|
||||
@ -605,10 +613,8 @@ void ngp_state::z80_io(address_map &map)
|
||||
|
||||
INPUT_CHANGED_MEMBER(ngp_state::power_callback)
|
||||
{
|
||||
if (m_io_reg[0x33] & 0x04)
|
||||
{
|
||||
m_maincpu->set_input_line(TLCS900_NMI, (m_io_power->read() & 0x01) ? CLEAR_LINE : ASSERT_LINE);
|
||||
}
|
||||
if (BIT(m_io_reg[0x33], 2))
|
||||
m_maincpu->set_input_line(TLCS900_NMI, (BIT(m_io_power->read(), 0) ? CLEAR_LINE : ASSERT_LINE));
|
||||
}
|
||||
|
||||
|
||||
@ -643,7 +649,8 @@ void ngp_state::ngp_hblank_pin_w(int state)
|
||||
void ngp_state::ngp_tlcs900_porta(offs_t offset, uint8_t data)
|
||||
{
|
||||
int to3 = BIT(data,3);
|
||||
if (to3 && ! m_old_to3)
|
||||
|
||||
if (to3 && !m_old_to3)
|
||||
m_z80->set_input_line(0, ASSERT_LINE);
|
||||
|
||||
m_old_to3 = to3;
|
||||
@ -805,9 +812,20 @@ void ngp_state::nvram_default()
|
||||
|
||||
bool ngp_state::nvram_read(util::read_stream &file)
|
||||
{
|
||||
auto const [err, actual] = read(file, m_mainram, 0x3000);
|
||||
if (!err && (actual == 0x3000))
|
||||
u8 data[0x3000 + 0x20];
|
||||
|
||||
auto const [err, actual] = read(file, data, 0x3000 + 0x20);
|
||||
if (!err && (actual == 0x3000 + 0x20))
|
||||
{
|
||||
for (int i = 0; i < 0x3000; i++)
|
||||
m_mainram[i] = data[i];
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
m_io_reg[i] = data[0x3000 + i];
|
||||
|
||||
system_time curtime;
|
||||
machine().current_datetime(curtime);
|
||||
set_current_time(curtime);
|
||||
|
||||
m_nvram_loaded = true;
|
||||
return true;
|
||||
}
|
||||
@ -817,11 +835,29 @@ bool ngp_state::nvram_read(util::read_stream &file)
|
||||
|
||||
bool ngp_state::nvram_write(util::write_stream &file)
|
||||
{
|
||||
auto const [err, actual] = write(file, m_mainram, 0x3000);
|
||||
u8 data[0x3000 + 0x20];
|
||||
|
||||
for (int i = 0; i < 0x3000; i++)
|
||||
data[i] = m_mainram[i];
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
data[0x3000 + i] = m_io_reg[i];
|
||||
|
||||
auto const [err, actual] = write(file, data, 0x3000 + 0x20);
|
||||
return !err;
|
||||
}
|
||||
|
||||
|
||||
void ngp_state::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
|
||||
{
|
||||
m_io_reg[0x16] = convert_to_bcd(second);
|
||||
m_io_reg[0x15] = convert_to_bcd(minute);
|
||||
m_io_reg[0x14] = convert_to_bcd(hour);
|
||||
m_io_reg[0x13] = convert_to_bcd(day);
|
||||
m_io_reg[0x12] = convert_to_bcd(month);
|
||||
m_io_reg[0x11] = convert_to_bcd(year % 100);
|
||||
}
|
||||
|
||||
|
||||
void ngp_state::ngp_common(machine_config &config)
|
||||
{
|
||||
TMP95C061(config, m_maincpu, 6.144_MHz_XTAL);
|
||||
@ -834,9 +870,9 @@ void ngp_state::ngp_common(machine_config &config)
|
||||
soundcpu.set_addrmap(AS_PROGRAM, &ngp_state::z80_mem);
|
||||
soundcpu.set_addrmap(AS_IO, &ngp_state::z80_io);
|
||||
|
||||
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
|
||||
screen.set_raw(6.144_MHz_XTAL, 515, 0, 160 /*480*/, 199, 0, 152);
|
||||
screen.set_screen_update(FUNC(ngp_state::screen_update_ngp));
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_LCD);
|
||||
m_screen->set_raw(6.144_MHz_XTAL, 515, 0, 160 /*480*/, 199, 0, 152);
|
||||
m_screen->set_screen_update(FUNC(ngp_state::screen_update_ngp));
|
||||
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "lspeaker").front_left();
|
||||
@ -855,17 +891,16 @@ void ngp_state::ngp(machine_config &config)
|
||||
{
|
||||
ngp_common(config);
|
||||
|
||||
K1GE(config, m_k1ge, 6.144_MHz_XTAL, "screen");
|
||||
K1GE(config, m_k1ge, 6.144_MHz_XTAL, m_screen);
|
||||
m_k1ge->vblank_callback().set(FUNC(ngp_state::ngp_vblank_pin_w));
|
||||
m_k1ge->hblank_callback().set(FUNC(ngp_state::ngp_hblank_pin_w));
|
||||
|
||||
subdevice<screen_device>("screen")->set_palette("k1ge:palette");
|
||||
m_screen->set_palette("k1ge:palette");
|
||||
|
||||
generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "ngp_cart", "bin,ngp,npc,ngc"));
|
||||
cartslot.set_device_load(FUNC(ngp_state::load_ngp_cart));
|
||||
cartslot.set_device_unload(FUNC(ngp_state::unload_ngp_cart));
|
||||
|
||||
/* software lists */
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("ngp");
|
||||
SOFTWARE_LIST(config, "ngpc_list").set_compatible("ngpc");
|
||||
}
|
||||
@ -874,17 +909,16 @@ void ngp_state::ngp(machine_config &config)
|
||||
void ngp_state::ngpc(machine_config &config)
|
||||
{
|
||||
ngp_common(config);
|
||||
K2GE(config, m_k1ge, 6.144_MHz_XTAL, "screen");
|
||||
K2GE(config, m_k1ge, 6.144_MHz_XTAL, m_screen);
|
||||
m_k1ge->vblank_callback().set(FUNC(ngp_state::ngp_vblank_pin_w));
|
||||
m_k1ge->hblank_callback().set(FUNC(ngp_state::ngp_hblank_pin_w));
|
||||
|
||||
subdevice<screen_device>("screen")->set_palette("k1ge:palette");
|
||||
m_screen->set_palette("k1ge:palette");
|
||||
|
||||
generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "ngp_cart", "bin,ngp,npc,ngc"));
|
||||
cartslot.set_device_load(FUNC(ngp_state::load_ngp_cart));
|
||||
cartslot.set_device_unload(FUNC(ngp_state::unload_ngp_cart));
|
||||
|
||||
/* software lists */
|
||||
SOFTWARE_LIST(config, "cart_list").set_original("ngpc");
|
||||
SOFTWARE_LIST(config, "ngp_list").set_compatible("ngp");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user