Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

snk/ngp.cpp: Improve rtc behavior. Fixes MT05279. #12855

Merged
merged 2 commits into from
Oct 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 100 additions & 66 deletions src/mame/snk/ngp.cpp
Original file line number Diff line number Diff line change
@@ -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 @@ class ngp_state : public driver_device, public device_nvram_interface
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 @@ class ngp_state : public driver_device, public device_nvram_interface
} 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 @@ class ngp_state : public driver_device, public device_nvram_interface

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");
}