k054000.cpp: fix OTG hitboxes in Vendetta (#8454)

* k054000.cpp: fixes MT 06393, MT 07839;

* k054000.cpp: convert access to address map;

* Convert all drivers using k054000 to access with address map, fix gaiapols and bucky ranges;

* vendetta.cpp: fix overdriven sound (noticeable on first boss);

* tmnt.cpp: fix Thunder Cross II overdriven sound;

* k054000.cpp: initialize variables at machine_reset time;

* k054000.cpp: move collision dump to a debug compile switch;

* tmnt.cpp: make thndrx2 to bypass protection checks via ROM patch, acknowledge it with 14D bad, demote it to MUP, describe rationale;

* k054000.cpp: srcclean;
This commit is contained in:
Angelo Salese 2021-12-10 23:47:05 +01:00 committed by GitHub
parent a1d6697546
commit 4d1fdd250c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 231 additions and 77 deletions

View File

@ -365,7 +365,7 @@ void lethal_state::bank4000_map(address_map &map)
{
// VRD = 0 or 1, CBNK = 0
map(0x0840, 0x084f).mirror(0x8000).rw(m_k053244, FUNC(k05324x_device::k053244_r), FUNC(k05324x_device::k053244_w));
map(0x0880, 0x089f).mirror(0x8000).rw("k054000", FUNC(k054000_device::read), FUNC(k054000_device::write));
map(0x0880, 0x089f).mirror(0x8000).m("k054000", FUNC(k054000_device::map));
map(0x08c0, 0x08cf).m(m_k054321, FUNC(k054321_device::main_map));
map(0x1000, 0x17ff).mirror(0x8000).rw(m_k053244, FUNC(k05324x_device::k053245_r), FUNC(k05324x_device::k053245_w));

View File

@ -374,7 +374,7 @@ void moo_state::bucky_map(address_map &map)
map(0x0cc000, 0x0cc01f).w(m_k053251, FUNC(k053251_device::write)).umask16(0x00ff);
map(0x0ce000, 0x0ce01f).w(FUNC(moo_state::moo_prot_w));
map(0x0d0000, 0x0d001f).rw(m_k053252, FUNC(k053252_device::read), FUNC(k053252_device::write)).umask16(0x00ff); /* CCU regs (ignored) */
map(0x0d2000, 0x0d20ff).rw("k054000", FUNC(k054000_device::read), FUNC(k054000_device::write)).umask16(0x00ff);
map(0x0d2000, 0x0d203f).m("k054000", FUNC(k054000_device::map)).umask16(0x00ff);
map(0x0d4000, 0x0d4001).w(FUNC(moo_state::sound_irq_w));
map(0x0d6000, 0x0d601f).m(m_k054321, FUNC(k054321_device::main_map)).umask16(0x00ff);
map(0x0d8000, 0x0d8007).w(m_k056832, FUNC(k056832_device::b_word_w)); /* VSCCS regs */

View File

@ -535,7 +535,7 @@ void mystwarr_state::gaiapols_map(address_map &map)
map(0x48e000, 0x48e001).portr("IN0_P1"); // bit 3 (0x8) is test switch
map(0x48e020, 0x48e021).r(FUNC(mystwarr_state::dddeeprom_r));
map(0x600000, 0x60ffff).ram().share("gx_workram");
map(0x660000, 0x6600ff).rw("k054000", FUNC(k054000_device::read), FUNC(k054000_device::write)).umask16(0x00ff);
map(0x660000, 0x66003f).m("k054000", FUNC(k054000_device::map)).umask16(0x00ff);
map(0x6a0000, 0x6a0001).w(FUNC(mystwarr_state::mmeeprom_w));
map(0x6c0000, 0x6c0001).w(FUNC(mystwarr_state::ddd_053936_enable_w));
map(0x6e0000, 0x6e0001).w(FUNC(mystwarr_state::sound_irq_w));

View File

@ -578,7 +578,7 @@ void tmnt_state::blswhstl_main_map(address_map &map)
map(0x204000, 0x207fff).ram(); /* main RAM */
map(0x300000, 0x303fff).rw(FUNC(tmnt_state::k053245_scattered_word_r), FUNC(tmnt_state::k053245_scattered_word_w)).share("spriteram");
map(0x400000, 0x400fff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x500000, 0x50003f).rw(m_k054000, FUNC(k054000_device::read), FUNC(k054000_device::write)).umask16(0x00ff);
map(0x500000, 0x50003f).m(m_k054000, FUNC(k054000_device::map)).umask16(0x00ff);
map(0x680000, 0x68001f).rw(FUNC(tmnt_state::k053244_word_noA1_r), FUNC(tmnt_state::k053244_word_noA1_w));
map(0x700000, 0x700001).portr("P1");
map(0x700002, 0x700003).portr("P2");
@ -982,7 +982,7 @@ void tmnt_state::thndrx2_main_map(address_map &map)
map(0x200000, 0x200fff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x300000, 0x30001f).w(m_k053251, FUNC(k053251_device::write)).umask16(0x00ff);
map(0x400000, 0x400003).rw(m_k053260, FUNC(k053260_device::main_read), FUNC(k053260_device::main_write)).umask16(0x00ff);
map(0x500000, 0x50003f).rw(m_k054000, FUNC(k054000_device::read), FUNC(k054000_device::write)).umask16(0x00ff);
map(0x500000, 0x50003f).m(m_k054000, FUNC(k054000_device::map)).umask16(0x00ff);
map(0x500100, 0x500101).w(FUNC(tmnt_state::thndrx2_eeprom_w));
map(0x500200, 0x500201).portr("P1_COINS");
map(0x500202, 0x500203).r(FUNC(tmnt_state::thndrx2_eeprom_r));
@ -2587,18 +2587,18 @@ void tmnt_state::thndrx2(machine_config &config)
m_k051960->set_sprite_callback(FUNC(tmnt_state::thndrx2_sprite_callback));
K053251(config, m_k053251, 0);
K054000(config, m_k054000, 0);
/* sound hardware */
// NB: game defaults in mono
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
YM2151(config, "ymsnd", XTAL(3'579'545)).add_route(0, "lspeaker", 1.0).add_route(1, "rspeaker", 1.0);
YM2151(config, "ymsnd", XTAL(3'579'545)).add_route(0, "lspeaker", 0.25).add_route(1, "rspeaker", 0.25);
K053260(config, m_k053260, XTAL(3'579'545));
m_k053260->add_route(0, "lspeaker", 0.75);
m_k053260->add_route(1, "rspeaker", 0.75);
m_k053260->add_route(0, "lspeaker", 0.50);
m_k053260->add_route(1, "rspeaker", 0.50);
}
@ -4297,6 +4297,16 @@ void tmnt_state::init_cuebrick()
save_item(NAME(m_cuebrick_nvram));
}
void tmnt_state::init_thndrx2()
{
u16 *ROM = (u16 *)memregion("maincpu")->base();
// cfr. notes in k054000 device
// this makes 11C / 12C to return bad (for ROM checksum)
// but goes on instead of halting for 14D (the protection chip device)
ROM[0x16c0 / 2] = 0x4e71;
}
// YEAR NAME PARENT MACHINE INPUT STATE INIT MONITOR COMPANY FULLNAME,FLAGS
GAME( 1989, cuebrick, 0, cuebrick, cuebrick, tmnt_state, init_cuebrick,ROT0, "Konami", "Cue Brick (World, version D)", MACHINE_SUPPORTS_SAVE )
@ -4361,9 +4371,9 @@ GAME( 1991, ssridersjbd, ssriders, ssriders, ssriders, tmnt_state, empty_init,
GAME( 1991, ssridersb, ssriders, sunsetbl, sunsetbl, tmnt_state, empty_init, ROT0, "bootleg", "Sunset Riders (bootleg 4 Players ver ADD)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
GAME( 1991, ssriders2, ssriders, sunsetbl, sunsetbl, tmnt_state, empty_init, ROT0, "bootleg", "Sunset Riders 2 (bootleg 4 Players ver ADD)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
GAME( 1991, thndrx2, 0, thndrx2, thndrx2, tmnt_state, empty_init, ROT0, "Konami", "Thunder Cross II (World)", MACHINE_SUPPORTS_SAVE )
GAME( 1991, thndrx2a, thndrx2, thndrx2, thndrx2, tmnt_state, empty_init, ROT0, "Konami", "Thunder Cross II (Asia)", MACHINE_SUPPORTS_SAVE )
GAME( 1991, thndrx2j, thndrx2, thndrx2, thndrx2, tmnt_state, empty_init, ROT0, "Konami", "Thunder Cross II (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1991, thndrx2, 0, thndrx2, thndrx2, tmnt_state, init_thndrx2, ROT0, "Konami", "Thunder Cross II (World)", MACHINE_SUPPORTS_SAVE | MACHINE_UNEMULATED_PROTECTION ) // Fails k054000 unit tests, cfr. driver_init & device
GAME( 1991, thndrx2a, thndrx2, thndrx2, thndrx2, tmnt_state, init_thndrx2, ROT0, "Konami", "Thunder Cross II (Asia)", MACHINE_SUPPORTS_SAVE | MACHINE_UNEMULATED_PROTECTION ) // ^
GAME( 1991, thndrx2j, thndrx2, thndrx2, thndrx2, tmnt_state, init_thndrx2, ROT0, "Konami", "Thunder Cross II (Japan)", MACHINE_SUPPORTS_SAVE | MACHINE_UNEMULATED_PROTECTION ) // ^
GAME( 1993, prmrsocr, 0, prmrsocr, prmrsocr, prmrsocr_state, empty_init, ROT0, "Konami", "Premier Soccer (ver EAB)", MACHINE_SUPPORTS_SAVE )
GAME( 1993, prmrsocrj, prmrsocr, prmrsocr, prmrsocr, prmrsocr_state, empty_init, ROT0, "Konami", "Premier Soccer (ver JAB)", MACHINE_SUPPORTS_SAVE )

View File

@ -208,7 +208,7 @@ void vendetta_state::main_map(address_map &map)
map(0x4000, 0x4fff).view(m_videoview0);
m_videoview0[0](0x4000, 0x4fff).rw(m_k052109, FUNC(k052109_device::read), FUNC(k052109_device::write));
m_videoview0[1](0x4000, 0x4fff).rw(m_k053246, FUNC(k053247_device::k053247_r), FUNC(k053247_device::k053247_w));
map(0x5f80, 0x5f9f).rw(m_k054000, FUNC(k054000_device::read), FUNC(k054000_device::write));
map(0x5f80, 0x5f9f).m(m_k054000, FUNC(k054000_device::map));
map(0x5fa0, 0x5faf).w(m_k053251, FUNC(k053251_device::write));
map(0x5fb0, 0x5fb7).w(m_k053246, FUNC(k053247_device::k053246_w));
map(0x5fc0, 0x5fc0).portr("P1");
@ -457,14 +457,13 @@ void vendetta_state::vendetta(machine_config &config)
m_k053246->set_palette(m_palette);
K053251(config, m_k053251, 0);
K054000(config, m_k054000, 0);
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
YM2151(config, "ymsnd", XTAL(3'579'545)).add_route(0, "lspeaker", 1.0).add_route(1, "rspeaker", 1.0); /* verified with PCB */
YM2151(config, "ymsnd", XTAL(3'579'545)).add_route(0, "lspeaker", 0.5).add_route(1, "rspeaker", 0.5); /* verified with PCB */
k053260_device &k053260(K053260(config, "k053260", XTAL(3'579'545))); /* verified with PCB */
k053260.add_route(0, "lspeaker", 0.75);

View File

@ -60,6 +60,7 @@ public:
void init_mia();
void init_tmnt();
void init_cuebrick();
void init_thndrx2();
protected:
virtual void machine_start() override;

View File

@ -1,57 +1,52 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
// copyright-holders:David Haywood, Angelo Salese
/**************************************************************************************************
Konami K054000 hitbox/math custom chip
Sort of a protection device, used for collision detection.
It is passed a few parameters, and returns a boolean telling if collision
happened. It has no access to gfx data, it only does arithmetical operations
on the parameters.
TODO:
- Thunder Cross II POST checks of this chip, we currently bypass that with a ROM patch in
driver. It literally tests the chip in an unit test fashion:
1. zeroing all ports;
2. test that status returns 0;
3. ping ACX reg 0 with 0xff;
4. test status = 1;
5. ping BCX reg 0 with 0xff;
6. test status = 0;
7. ping ACX reg 1 with 0xff;
8. test status = 1;
9. rinse and repeat until all registers are exausted.
Assertion eventually fails when testing the "delta" registers:
ACX ffffffff|ACY ffffff00|AAX 01 AAY 01
BCX ffffff00|BCY ffffff00|BAX 01 BAY 01
Result: actual 0 (yes), expected 1 (no)
The fun part is that game doesn't even access the chip at all during gameplay
(or at least not until stage 6, where game disallows continues) while the specific
"delta" registers are instead challenged by Vendetta OTG attacks (cfr. MT#06393, MT#07839).
We currently pay the technical debt inside thndrx2 itself, by notifying that "14D" returns
bad but still making it to boot anyway while marking these games with MUP.
Any attempt to fix it here without real HW tests goes into wild speculations unfortunately.
**************************************************************************************************/
#include "emu.h"
#include "k054000.h"
#define LIVE_HITBOX_VIEW 0
#include <cstring>
#define VERBOSE 0
#include "logmacro.h"
//#define VERBOSE 0
//#include "logmacro.h"
/***************************************************************************/
/* */
/* 054000 */
/* */
/***************************************************************************/
/*
054000
------
Sort of a protection device, used for collision detection.
It is passed a few parameters, and returns a boolean telling if collision
happened. It has no access to gfx data, it only does arithmetical operations
on the parameters.
Memory map:
00 unused
01-03 W A center X
04 W unknown, needed by thndrx2 to pass the startup check, we use a hack
05 unused
06 W A semiaxis X
07 W A semiaxis Y
08 unused
09-0b W A center Y
0c W unknown, needed by thndrx2 to pass the startup check, we use a hack
0d unused
0e W B semiaxis X
0f W B semiaxis Y
10 unused
11-13 W B center Y
14 unused
15-17 W B center X
18 R 0 = collision, 1 = no collision
*/
/***************************************************************************/
/* */
/* 054000 */
/* */
/***************************************************************************/
DEFINE_DEVICE_TYPE(K054000, k054000_device, "k054000", "K054000 Protection")
@ -66,7 +61,18 @@ k054000_device::k054000_device(const machine_config &mconfig, const char *tag, d
void k054000_device::device_start()
{
save_item(NAME(m_regs));
save_item(NAME(m_Acx));
save_item(NAME(m_Acy));
save_item(NAME(m_Aax));
save_item(NAME(m_Aay));
save_item(NAME(m_Bcx));
save_item(NAME(m_Bcy));
save_item(NAME(m_Bax));
save_item(NAME(m_Bay));
save_pointer(NAME(m_raw_Acx), 4);
save_pointer(NAME(m_raw_Acy), 4);
save_pointer(NAME(m_raw_Bcx), 4);
save_pointer(NAME(m_raw_Bcy), 4);
}
//-------------------------------------------------
@ -75,22 +81,136 @@ void k054000_device::device_start()
void k054000_device::device_reset()
{
int i;
for (i = 0; i < 0x20; i++)
m_regs[i] = 0;
// TODO: verify initial state (very unlikely to be all zeroes)
std::fill(std::begin(m_raw_Acx), std::end(m_raw_Acx), 0);
std::fill(std::begin(m_raw_Acy), std::end(m_raw_Acy), 0);
std::fill(std::begin(m_raw_Bcx), std::end(m_raw_Bcx), 0);
std::fill(std::begin(m_raw_Bcy), std::end(m_raw_Bcy), 0);
m_Aax = 1;
m_Aay = 1;
m_Bax = 1;
m_Bay = 1;
}
/*****************************************************************************
DEVICE HANDLERS
*****************************************************************************/
void k054000_device::write(offs_t offset, u8 data)
/*
Memory map:
00 unused
01-03 W A center X
04 W A delta correction X?
05 unused
06 W A semiaxis X
07 W A semiaxis Y
08 unused
09-0b W A center Y
0c W A delta correction Y?
0d unused
0e W B semiaxis X
0f W B semiaxis Y
10 unused
11-13 W B center Y
14 unused
15-17 W B center X
18 R 0 = collision, 1 = no collision
*/
void k054000_device::map(address_map &map)
{
//logerror("%s: write %02x to 054000 address %02x\n",m_maincpu->pc(),data,offset);
m_regs[offset] = data;
map.unmap_value_low();
map(0x01, 0x04).w(FUNC(k054000_device::acx_w));
map(0x06, 0x06).lw8(NAME([this] (u8 data) { m_Aax = data + 1; }));
map(0x07, 0x07).lw8(NAME([this] (u8 data) { m_Aay = data + 1; }));
map(0x09, 0x0c).w(FUNC(k054000_device::acy_w));
map(0x0e, 0x0e).lw8(NAME([this] (u8 data) { m_Bax = data + 1; }));
map(0x0f, 0x0f).lw8(NAME([this] (u8 data) { m_Bay = data + 1; }));
map(0x11, 0x13).w(FUNC(k054000_device::bcy_w));
map(0x15, 0x17).w(FUNC(k054000_device::bcx_w));
map(0x18, 0x18).r(FUNC(k054000_device::status_r));
}
inline int k054000_device::convert_raw_to_result(u8 *buf)
{
int res = (buf[0] << 16) | (buf[1] << 8) | buf[2];
//if (buf[0] & 0x80)
// res = (0x1000000 - res);
// last value in the buffer is used as OTG correction in Vendetta
if (buf[3] & 0x80)
res -= (0x100 - buf[3]);
else
res += buf[3];
return res;
}
void k054000_device::acx_w(offs_t offset, u8 data)
{
m_raw_Acx[offset] = data;
m_Acx = convert_raw_to_result(m_raw_Acx);
}
void k054000_device::acy_w(offs_t offset, u8 data)
{
m_raw_Acy[offset] = data;
m_Acy = convert_raw_to_result(m_raw_Acy);
}
void k054000_device::bcx_w(offs_t offset, u8 data)
{
m_raw_Bcx[offset] = data;
m_Bcx = convert_raw_to_result(m_raw_Bcx);
}
void k054000_device::bcy_w(offs_t offset, u8 data)
{
m_raw_Bcy[offset] = data;
m_Bcy = convert_raw_to_result(m_raw_Bcy);
}
u8 k054000_device::status_r()
{
u8 res = 0;
if (m_Acx + m_Aax < m_Bcx - m_Bax)
res |= 1;
if (m_Bcx + m_Bax < m_Acx - m_Aax)
res |= 1;
if (m_Acy + m_Aay < m_Bcy - m_Bay)
res |= 1;
if (m_Bcy + m_Bay < m_Acy - m_Aay)
res |= 1;
if (LIVE_HITBOX_VIEW)
logerror(print_hitbox_state(res));
return res;
}
// debugging
std::string k054000_device::print_hitbox_state(bool result)
{
std::ostringstream outbuffer;
util::stream_format(outbuffer, "%s collision check:\n", machine().describe_context());
util::stream_format(outbuffer, "ACX %02x%02x%02x%02x|", m_raw_Acx[0], m_raw_Acx[1], m_raw_Acx[2], m_raw_Acx[3]);
util::stream_format(outbuffer, "ACY %02x%02x%02x%02x|", m_raw_Acy[0], m_raw_Acy[1], m_raw_Acy[2], m_raw_Acy[3]);
util::stream_format(outbuffer, "AAX %02x AAY %02x\n", m_Aax, m_Aay);
util::stream_format(outbuffer, "BCX %02x%02x%02x%02x|", m_raw_Bcx[0], m_raw_Bcx[1], m_raw_Bcx[2], m_raw_Bcx[3]);
util::stream_format(outbuffer, "BCY %02x%02x%02x%02x|", m_raw_Bcy[0], m_raw_Bcy[1], m_raw_Bcy[2], m_raw_Bcy[3]);
util::stream_format(outbuffer, "BAX %02x BAY %02x\n", m_Bax, m_Bay);
util::stream_format(outbuffer, "Result: %d (%s)\n", result, result ? "no" : "yes");
util::stream_format(outbuffer, "===\n");
return outbuffer.str();
}
// old code, left as documentation reasons
#if 0
u8 k054000_device::read(offs_t offset)
{
int Acx, Acy, Aax, Aay;
@ -104,11 +224,21 @@ u8 k054000_device::read(offs_t offset)
Acx = (m_regs[0x01] << 16) | (m_regs[0x02] << 8) | m_regs[0x03];
Acy = (m_regs[0x09] << 16) | (m_regs[0x0a] << 8) | m_regs[0x0b];
/* TODO: this is a hack to make thndrx2 pass the startup check. It is certainly wrong. */
if (m_regs[0x04] == 0xff)
Acx+=3;
if (m_regs[0x0c] == 0xff)
Acy+=3;
// TODO: this is a hack to make thndrx2 pass the startup check. It is certainly wrong.
// if (m_regs[0x04] == 0xff)
// Acx+=3;
// if (m_regs[0x0c] == 0xff)
// Acy+=3;
// Used as OTG correction in Vendetta
if (m_regs[0x04] & 0x80)
Acx -= (0x100 - m_regs[0x04]);
else
Acx += m_regs[0x04];
if (m_regs[0x0c] & 0x80)
Acy -= (0x100 - m_regs[0x0c]);
else
Acy += m_regs[0x0c];
Aax = m_regs[0x06] + 1;
Aay = m_regs[0x07] + 1;
@ -118,6 +248,9 @@ u8 k054000_device::read(offs_t offset)
Bax = m_regs[0x0e] + 1;
Bay = m_regs[0x0f] + 1;
//if (m_regs[0x04] || m_regs[0x0c])
//printf("%d %d %d %d (%d|%d)|%d %d %d %d\n", Acx, Acy, Aax, Aay, m_regs[0x04], m_regs[0x0c], Bcx, Bcy, Bax, Bay);
if (Acx + Aax < Bcx - Bax)
return 1;
@ -132,3 +265,4 @@ u8 k054000_device::read(offs_t offset)
return 0;
}
#endif

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
// copyright-holders:David Haywood, Angelo Salese
#ifndef MAME_VIDEO_K054000_H
#define MAME_VIDEO_K054000_H
@ -12,8 +12,7 @@ public:
k054000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
~k054000_device() {}
void write(offs_t offset, u8 data);
u8 read(offs_t offset);
void map(address_map &map);
protected:
// device-level overrides
@ -22,7 +21,18 @@ protected:
private:
// internal state
uint8_t m_regs[0x20];
void acx_w(offs_t offset, u8 data);
void acy_w(offs_t offset, u8 data);
void bcx_w(offs_t offset, u8 data);
void bcy_w(offs_t offset, u8 data);
int convert_raw_to_result(u8 *buf);
u8 status_r();
u8 m_raw_Acx[4], m_raw_Acy[4], m_raw_Bcx[4], m_raw_Bcy[4];
int m_Acx, m_Acy, m_Bcx, m_Bcy;
int m_Aax, m_Aay, m_Bax, m_Bay;
std::string print_hitbox_state(bool result);
};
DECLARE_DEVICE_TYPE(K054000, k054000_device)