diff --git a/src/mame/konami/hexion.cpp b/src/mame/konami/hexion.cpp index afa5b31ab55..36d830a48fa 100644 --- a/src/mame/konami/hexion.cpp +++ b/src/mame/konami/hexion.cpp @@ -10,71 +10,81 @@ Notes: - The board has a 052591, which is used for protection in Thunder Cross and S.P.Y. In this game, however, the only thing it seems to do is clear the screen. - This is the program for the 052591: -00: 5f 80 01 e0 08 -01: df 80 00 e0 0c -02: df 90 02 e0 0c -03: df a0 03 e0 0c -04: df b0 0f e0 0c -05: df c0 ff bf 0c -06: 5c 02 00 33 0c -07: 5f 80 04 80 0c + +This is the 052591 PMC code loaded at startup, it contains a RAM/VRAM filling program. +See https://github.com/furrtek/SiliconRE/tree/master/Konami/052591 for details + +00: 5f 80 01 e0 08 Entry point, set OUT0 high +01: df 80 00 e0 0c r0 = 0 +02: df 90 02 e0 0c r1 = 2 +03: df a0 03 e0 0c r2 = 3 +04: df b0 0f e0 0c r3 = f +05: df c0 ff bf 0c ExtAddr = 1fff, r4 = ffff +06: 5c 02 00 33 0c +07: 5f 80 04 80 0c Write 2 to RAM (1fff) m_bankctrl, select pmcram 08: 5c 0e 00 2b 0c -09: df 70 00 cb 08 -0a: 5f 80 00 80 0c +09: df 70 00 cb 08 r7 = RAM(4) +0a: 5f 80 00 80 0c ExtAddr = 0 0b: 5c 04 00 2b 0c -0c: df 60 00 cb 08 -0d: 5c 0c 1f e9 0c -0e: 4c 0c 2d e9 08 -0f: 5f 80 03 80 0c +0c: df 60 00 cb 08 r6 = RAM(0) (commands 0, 1 and 30 are used) +0d: 5c 0c 1f e9 0c JP 1F if r6 == 0 +0e: 4c 0c 2d e9 08 JP 2D if r6 == 1 + +Command anything other than 00 or 01: Set bank to r7, then clear 16 bytes starting from r5.w +0f: 5f 80 03 80 0c ExtAddr = 3 10: 5c 04 00 2b 0c -11: 5f 00 00 cb 00 -12: 5f 80 02 a0 0c -13: df d0 00 c0 04 -14: 01 3a 00 f3 0a +11: 5f 00 00 cb 00 Read MSB from RAM[3] +12: 5f 80 02 a0 0c ExtAddr = 2 +13: df d0 00 c0 04 r5.w = RAM[3], RAM[2] +14: 01 3a 00 f3 0a acc = r5 + r3 = r5 + f 15: 5c 08 00 b3 0c -16: 5c 0e 00 13 0c +16: 5c 0e 00 13 0c Write 3 to RAM[1fff] m_bankctrl 17: 5f 80 00 a0 0c -18: 5c 00 00 13 0c +18: 5c 00 00 13 0c Write r7 to RAM[0] 19: 5c 08 00 b3 0c -1a: 5c 00 00 13 0c +1a: 5c 00 00 13 0c Write 0 to RAM[1fff] m_bankctrl, select vram 1b: 84 5a 00 b3 0c -1c: 48 0a 5b d1 0c -1d: 5f 80 00 e0 08 -1e: 5f 00 1e fd 0c +1c: 48 0a 5b d1 0c Write 0 to RAM[r5++] until r5 > acc (16 times) +1d: 5f 80 00 e0 08 Set OUT0 low +1e: 5f 00 1e fd 0c JP 1E, infinite loop + +Command is 00: Set bank to 0 and fill from 0 to 0x1fff with r2.b 1f: 5f 80 01 a0 0c -20: df 20 00 cb 08 +20: df 20 00 cb 08 r2 = RAM[1] 21: 5c 08 00 b3 0c -22: 5f 80 03 00 0c +22: 5f 80 03 00 0c Write 3 to RAM[1fff] m_bankctrl 23: 5c 08 00 b3 0c -24: 5f 80 00 80 0c +24: 5f 80 00 80 0c Write 3 to RAM[1fff] m_bankctrl 25: 5c 00 00 33 0c -26: 5c 08 00 93 0c -27: 9f 91 ff cf 0e +26: 5c 08 00 93 0c Write 0 to RAM[0] +27: 9f 91 ff cf 0e Write 0 to RAM[1fff] m_bankctrl, select vram, r1 = fff << 1 = 1ffe 28: 5c 84 00 20 0c -29: 84 00 00 b3 0c -2a: 49 10 69 d1 0c -2b: 5f 80 00 e0 08 -2c: 5f 00 2c fd 0c +29: 84 00 00 b3 0c ExtAddr = r0 +2a: 49 10 69 d1 0c Write r2 to RAM[r0++] while r0 < r1 +2b: 5f 80 00 e0 08 Set OUT0 low +2c: 5f 00 2c fd 0c JP 2C, infinite loop + +Command is 01: Set banks to 1 and fill from 0 to 0x1fff with r2.b 2d: 5f 80 01 a0 0c -2e: df 20 00 cb 08 +2e: df 20 00 cb 08 r2 = RAM(1) 2f: 5c 08 00 b3 0c -30: 5f 80 03 00 0c +30: 5f 80 03 00 0c Write 3 to RAM[1fff] m_bankctrl 31: 5c 00 00 b3 0c -32: 5f 80 01 00 0c +32: 5f 80 01 00 0c Write 3 to RAM[0] 33: 5c 08 00 b3 0c -34: 5f 80 00 80 0c +34: 5f 80 00 80 0c Write 1 to RAM[1fff] m_bankctrl 35: 5c 00 00 33 0c -36: 5c 08 00 93 0c -37: 9f 91 ff cf 0e +36: 5c 08 00 93 0c Write 0 to RAM[0] +37: 9f 91 ff cf 0e Write 0 to RAM[1fff] m_bankctrl, select vram, r1 = fff << 1 = 1ffe 38: 5c 84 00 20 0c 39: 84 00 00 b3 0c -3a: 49 10 79 d1 0c -3b: 5f 80 00 e0 08 -3c: 5f 00 3c fd 0c -3d: ff ff ff ff ff -3e: ff ff ff ff ff -3f: ff ff ff ff ff +3a: 49 10 79 d1 0c Write r2 to RAM[r0++] while r0 < r1 +3b: 5f 80 00 e0 08 Set OUT0 low +3c: 5f 00 3c fd 0c JP 3C, infinite loop + +3d: ff ff ff ff ff Garbage +3e: ff ff ff ff ff Garbage +3f: ff ff ff ff ff Garbage ***************************************************************************/ @@ -92,6 +102,7 @@ Notes: #include "emupal.h" #include "speaker.h" #include "tilemap.h" +#include "multibyte.h" // configurable logging @@ -120,7 +131,7 @@ public: m_gfxdecode(*this, "gfxdecode"), m_palette(*this, "palette"), m_vram(*this, "vram%u", 0U, 0x2000U, ENDIANNESS_LITTLE), - m_unkram(*this, "unkram", 0x800, ENDIANNESS_LITTLE), + m_pmcram(*this, "pmcram", 0x800, ENDIANNESS_LITTLE), // Might be an unused area of VRAM m_rombank(*this, "rombank"), m_tilesrom(*this, "tiles") { } @@ -138,7 +149,7 @@ private: required_device m_palette; memory_share_array_creator m_vram; - memory_share_creator m_unkram; + memory_share_creator m_pmcram; required_memory_bank m_rombank; required_region_ptr m_tilesrom; @@ -231,12 +242,21 @@ void hexion_state::bankswitch_w(uint8_t data) // bits 0-3 select ROM bank m_rombank->set_entry(data & 0x0f); - // does bit 6 trigger the 052591? + // bit 6 triggers the 052591 if (data & 0x40) { - int bank = m_unkram[0] & 1; - memset(m_vram[bank], m_unkram[1], 0x2000); - m_bg_tilemap[bank]->mark_all_dirty(); + uint8_t command = m_pmcram[0]; + if (command <= 1) + { + memset(m_vram[command], m_pmcram[1], 0x2000); + m_bg_tilemap[command]->mark_all_dirty(); + } + else + { + uint8_t bank = m_pmcram[4] & 1; + memset(m_vram[bank] + (get_u16le(&m_pmcram[2]) & 0x1fff), 0, 16); + m_bg_tilemap[bank]->mark_all_dirty(); + } } // bit 7 = PMC-BK m_pmcbank = (data & 0x80) >> 7; @@ -258,7 +278,7 @@ uint8_t hexion_state::bankedram_r(offs_t offset) } else if (m_bankctrl == 2 && offset < 0x800) { - return m_unkram[offset]; + return m_pmcram[offset]; } else { @@ -289,8 +309,8 @@ void hexion_state::bankedram_w(offs_t offset, uint8_t data) { if (m_pmcbank) { - LOGBANKEDRAM("%s: unkram_w offset %04x, data %02x, bankctrl = %02x\n", m_maincpu->pc(), offset, data, m_bankctrl); - m_unkram[offset] = data; + LOGBANKEDRAM("%s: pmcram_w offset %04x, data %02x, bankctrl = %02x\n", m_maincpu->pc(), offset, data, m_bankctrl); + m_pmcram[offset] = data; } else LOGBANKEDRAM("%04x pmc internal ram %04x = %02x\n", m_maincpu->pc(), offset, data); diff --git a/src/mame/konami/spy.cpp b/src/mame/konami/spy.cpp index 691a0a70c36..adbff571245 100644 --- a/src/mame/konami/spy.cpp +++ b/src/mame/konami/spy.cpp @@ -11,6 +11,9 @@ Revisions: + 31-01-2024 Furrtek + - updated PMCU collision check code to match what the original program does + 05-10-2002 Acho A. Tang - simulated PMCU protection(guess only) - changed priority scheme to fix graphics in 3D levels @@ -34,6 +37,7 @@ #include "sound/ymopl.h" #include "emupal.h" #include "speaker.h" +#include "multibyte.h" namespace { @@ -63,6 +67,7 @@ private: /* misc */ int m_rambank = 0; int m_pmcbank = 0; + uint8_t m_pmcpc = 0; int m_video_enable = 0; int m_old_3f90 = 0; @@ -85,7 +90,7 @@ private: virtual void machine_start() override; virtual void machine_reset() override; uint32_t screen_update_spy(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - void spy_collision( ); + void pmc_run( ); void volume_callback0(uint8_t data); void volume_callback1(uint8_t data); K052109_CB_MEMBER(tile_callback); @@ -172,8 +177,7 @@ uint8_t spy_state::spy_bankedram1_r(offs_t offset) } else { - //logerror("%04x read pmc internal ram %04x\n", m_maincpu->pc(), offset); - return 0; + return 0; // PMC internal RAM can't be read back } } else @@ -193,79 +197,90 @@ void spy_state::spy_bankedram1_w(offs_t offset, uint8_t data) //logerror("%04x pmcram %04x = %02x\n", m_maincpu->pc(), offset, data); m_pmcram[offset] = data; } - //else - //logerror("%04x pmc internal ram %04x = %02x\n", m_maincpu->pc(), offset, data); + else + { + // Set initial PMC PC + m_pmcpc = data & 0x3f; + } } else m_ram[offset] = data; } /* -this is the data written to internal ram on startup: -00: e7 7e 38 fc 08 -01: df 36 38 dc 00 -02: df 12 3a dc 00 -03: df 00 38 dc 08 +This is the 052591 PMC code loaded at startup, it contains both projection and collision check programs. +See https://github.com/furrtek/SiliconRE/tree/master/Konami/052591 for details + +Coordinate projection routine: +00: e7 7e 38 fc 08 Clear r7 +01: df 36 38 dc 00 r3.w = RAM[0] +02: df 12 3a dc 00 r1.w = RAM[2] +03: df 00 38 dc 08 r0 = RAM[4] 04: 1f 7e 00 db 00 -05: 26 fe 00 ff 0c -06: 89 03 34 fc 0d -07: 81 03 34 fc 09 -08: 81 03 34 fc 09 -09: 81 03 34 fc 09 -0a: 81 03 2f fc 09 -0b: cc 36 0e d9 08 +05: 26 fe 00 ff 0c Acc.w = RAM[5],00 +06: 89 03 34 fc 0d 1+16 division steps, CALL 34... +07: 81 03 34 fc 09 add/sub, CALL 34 +08: 81 03 34 fc 09 add/sub, CALL 34 +09: 81 03 34 fc 09 add/sub, CALL 34 +0a: 81 03 2f fc 09 add/sub, CALL 34 +0b: cc 36 0e d9 08 r3--, JP 0e if 0 0c: 84 7e 00 ab 0c -0d: 5f 7e 03 cd 08 -0e: 7f 80 fe ef 08 -0f: 5f 7e 0f fd 08 -10: e7 7e 38 fc 08 +0d: 5f 7e 03 cd 08 JP 03 + +0e: 7f 80 fe ef 08 Set OUT0 low +0f: 5f 7e 0f fd 08 JP 0f, infinite loop + +Collision check routine: +10: e7 7e 38 fc 08 r0.w = RAM[0] 11: df 00 3a dc 00 -12: df 12 0e d9 08 -13: df ec 10 e0 0c -14: 1f fe 03 e0 0c -15: df fe 03 e0 0c -16: dc 5e 3e fc 08 -17: df 12 2b d9 08 -18: 67 25 38 fc 0c +12: df 12 0e d9 08 r1 = RAM[2], JP 0e if 0 +13: df ec 10 e0 0c r6 = 10 +14: 1f fe 03 e0 0c Acc = 3 +15: df fe 03 e0 0c r7 = 3 +16: dc 5e 3e fc 08 r5 = 3 +17: df 12 2b d9 08 r1 = RAM[r6++], JP 2b if 0 +18: 67 25 38 fc 0c r2 = 8000 ? 19: df 12 3c dc 00 1a: df 36 00 db 00 -1b: c1 14 00 fb 08 -1c: c1 34 38 fc 08 +1b: c1 14 00 fb 08 r1 += r2 +1c: c1 34 38 fc 08 r3 += r2 1d: c5 22 37 dc 00 1e: cd 12 3c dc 04 1f: c5 46 3b dc 00 20: cd 36 00 db 04 -21: 49 16 ed f9 0c -22: c9 18 ea f9 0c +21: 49 16 ed f9 0c JP 2d if r1 < r3 +22: c9 18 ea f9 0c JP 2a if r1 < r4 23: dc 12 2a f9 08 -24: cc 5a 26 f9 08 -25: 5f 7e 18 fd 08 -26: 5a 7e 32 f8 08 -27: 84 6c 33 9c 0c -28: cc 00 0e d9 08 +24: cc 5a 26 f9 08 r5--, JP 26 if 0 +25: 5f 7e 18 fd 08 JP 18 +26: 5a 7e 32 f8 08 Clear RAM(r7++) if Acc is 0 +27: 84 6c 33 9c 0c RAM(r6++) = Acc +28: cc 00 0e d9 08 r0--, JP 0e if 0 29: 5f 7e 14 fd 08 2a: 0a 7e 24 fd 08 -2b: c5 ec 0d e0 0c +2b: c5 ec 0d e0 0c r6 += d, next object 2c: 5f 7e 28 fd 08 -2d: dc 16 00 fb 08 -2e: dc 44 22 fd 08 -2f: cd fe 02 e0 0c +2d: dc 16 00 fb 08 r1 = r3 +2e: dc 44 22 fd 08 r4 = r2 +2f: cd fe 02 e0 0c r7 -= 3 30: 84 7e 00 bb 0c 31: 5a 7e 00 73 08 32: 84 7e 00 9b 0c 33: 5a 7e 00 36 08 -34: 81 03 00 fb 09 -35: 81 03 00 fb 09 -36: 81 03 00 fe 09 -37: cd fe 01 e0 0c + +34: 81 03 00 fb 09 add/sub +35: 81 03 00 fb 09 add/sub +36: 81 03 00 fe 09 add/sub, ret + +37: cd fe 01 e0 0c r7 -= 2 38: 84 7e 00 ab 0c -39: 5f 7e 00 db 00 +39: 5f 7e 00 db 00 Set MSB as RAM(r7) 3a: 84 7e 3f ad 0c -3b: cd ec 01 e0 0c +3b: cd ec 01 e0 0c r6 -= 2 3c: 84 6c 00 ab 0c -3d: 5f 7e 00 db 00 +3d: 5f 7e 00 db 00 Set MSB as RAM(r6) 3e: 84 6c 00 ab 0c -3f: 5f 7e 00 ce 08 +3f: 5f 7e 00 ce 08 ret */ void spy_state::bankswitch_w(uint8_t data) @@ -285,66 +300,20 @@ void spy_state::bankswitch_w(uint8_t data) membank("bank1")->set_entry(bank); } -void spy_state::spy_collision( ) +void spy_state::pmc_run( ) { -#define MAX_SPRITES 64 -#define DEF_NEAR_PLANE 0x6400 -#define NEAR_PLANE_ZOOM 0x0100 -#define FAR_PLANE_ZOOM 0x0000 - - int op1, x1, w1, z1, d1, y1, h1; - int op2, x2, w2, z2, d2, y2, h2; - int mode, i, loopend, nearplane; - - mode = m_pmcram[0x1]; - op1 = m_pmcram[0x2]; - if (op1 == 1) + constexpr uint16_t MAX_SPRITES = 64; + constexpr uint16_t DEF_NEAR_PLANE = 0x6400; + + if (m_pmcpc == 0x00) { - x1 = (m_pmcram[0x3] << 8) + m_pmcram[0x4]; - w1 = (m_pmcram[0x5] << 8) + m_pmcram[0x6]; - z1 = (m_pmcram[0x7] << 8) + m_pmcram[0x8]; - d1 = (m_pmcram[0x9] << 8) + m_pmcram[0xa]; - y1 = (m_pmcram[0xb] << 8) + m_pmcram[0xc]; - h1 = (m_pmcram[0xd] << 8) + m_pmcram[0xe]; - - for (i = 16; i < 14 * MAX_SPRITES + 2; i += 14) - { - op2 = m_pmcram[i]; - if (op2 || mode == 0x0c) - { - x2 = (m_pmcram[i + 0x1] << 8) + m_pmcram[i + 0x2]; - w2 = (m_pmcram[i + 0x3] << 8) + m_pmcram[i + 0x4]; - z2 = (m_pmcram[i + 0x5] << 8) + m_pmcram[i + 0x6]; - d2 = (m_pmcram[i + 0x7] << 8) + m_pmcram[i + 0x8]; - y2 = (m_pmcram[i + 0x9] << 8) + m_pmcram[i + 0xa]; - h2 = (m_pmcram[i + 0xb] << 8) + m_pmcram[i + 0xc]; -/* - The mad scientist's laser truck has both a high sprite center and a small height value. - It has to be measured from the ground to detect correctly. -*/ - if (w2 == 0x58 && d2 == 0x04 && h2 == 0x10 && y2 == 0x30) - h2 = y2; - - // what other sprites fall into: - if ((abs(x1 - x2) < w1 + w2) && (abs(z1 - z2) < d1 + d2) && (abs(y1 - y2) < h1 + h2)) - { - m_pmcram[0xf] = 0; - m_pmcram[i + 0xd] = 0; - } - else - m_pmcram[i + 0xd] = 1; - } - } - } - else if (op1 > 1) - { -/* - The PMCU also projects geometries to screen coordinates. Unfortunately I'm unable to figure - the scale factors from the PMCU code. Plugging 0 and 0x100 to the far and near planes seems - to do the trick though. -*/ - loopend = (m_pmcram[0] << 8) + m_pmcram[1]; - nearplane = (m_pmcram[2] << 8) + m_pmcram[3]; + // Projection program + // Basically divides a list of 16-bit words by a constant, results are 8.8 fixed point + uint16_t loopend, nearplane; + uint32_t op; + + loopend = get_u16be(&m_pmcram[0]); + nearplane = get_u16be(&m_pmcram[2]); // fail safe if (loopend > MAX_SPRITES) @@ -354,16 +323,65 @@ void spy_state::spy_collision( ) loopend = (loopend << 1) + 4; - for (i = 4; i < loopend; i += 2) + for (uint16_t i = 4; i < loopend; i += 2) { - op2 = (m_pmcram[i] << 8) + m_pmcram[i + 1]; - op2 = (op2 * (NEAR_PLANE_ZOOM - FAR_PLANE_ZOOM)) / nearplane + FAR_PLANE_ZOOM; - m_pmcram[i] = op2 >> 8; - m_pmcram[i + 1] = op2 & 0xff; + op = get_u16be(&m_pmcram[i]); + op = (op << 8) / nearplane; + put_u16be(&m_pmcram[i], op); } memset(m_pmcram + loopend, 0, 0x800 - loopend); // clean up for next frame } + else + { + // Collision check program + + if (!m_pmcram[0x2]) + return; + + const uint16_t count = get_u16be(&m_pmcram[0]); + + for (uint16_t i = 16; i < 16 + (14 * count); i += 14) + { + if (!m_pmcram[i]) + continue; + + // Check all 3 dimensions + uint8_t tests_failed = 3; + for (uint16_t j = 0; j < 3 * 4; j += 4) + { + const int16_t a_pos = get_s16be(&m_pmcram[j + 3]); // Object A center position + const int16_t a_size = get_s16be(&m_pmcram[j + 5]); // Object A half size + + const int16_t b_pos = get_s16be(&m_pmcram[i + j + 1]); // Object B center position + const int16_t b_size = get_s16be(&m_pmcram[i + j + 3]); // Object B half size + + const int16_t a_max = a_pos + a_size; // Object A right edge + const int16_t a_min = a_pos - a_size; // Object A left edge + const int16_t b_max = b_pos + b_size; // Object B right edge + const int16_t b_min = b_pos - b_size; // Object B left edge + + if (b_min > a_min) + { + // Object B left edge is > object A left edge + // Checks if A.left < B.left <= A.right + if (a_max >= b_min) + tests_failed--; + } + else + { + // Object B left edge is <= object A left edge + // Checks if B.left <= A.left <= B.right + if (b_max >= a_min) + tests_failed--; + } + } + + // Mark objects as collided or not + if (!tests_failed) m_pmcram[0xf] = 0; + m_pmcram[i + 0xd] = tests_failed; + } + } } @@ -423,26 +441,10 @@ void spy_state::spy_3f90_w(uint8_t data) /* bit 7 = PMC-BK */ m_pmcbank = (data & 0x80) >> 7; -//logerror("%04x: 3f90_w %02x\n", m_maincpu->pc(), data); /* bit 6 = PMC-START */ if ((data & 0x40) && !(m_old_3f90 & 0x40)) { - /* we should handle collision here */ -//AT - if (0) - { - int i; - - logerror("collision test:\n"); - for (i = 0; i < 0xfe; i++) - { - logerror("%02x ", m_pmcram[i]); - if (i == 0x0f || (i > 0x10 && (i - 0x10) % 14 == 13)) - logerror("\n"); - } - } - spy_collision(); -//ZT + pmc_run(); m_maincpu->set_input_line(M6809_FIRQ_LINE, HOLD_LINE); } @@ -601,6 +603,7 @@ void spy_state::machine_start() save_item(NAME(m_paletteram)); save_item(NAME(m_rambank)); save_item(NAME(m_pmcbank)); + save_item(NAME(m_pmcpc)); save_item(NAME(m_video_enable)); save_item(NAME(m_old_3f90)); save_item(NAME(m_pmcram)); @@ -610,6 +613,7 @@ void spy_state::machine_reset() { m_rambank = 0; m_pmcbank = 0; + m_pmcpc = 0; m_video_enable = 0; m_old_3f90 = -1; } diff --git a/src/mame/konami/thunderx.cpp b/src/mame/konami/thunderx.cpp index 7c4ec1360c5..172a7282a5d 100644 --- a/src/mame/konami/thunderx.cpp +++ b/src/mame/konami/thunderx.cpp @@ -49,6 +49,7 @@ #include "emupal.h" #include "screen.h" #include "speaker.h" +#include "multibyte.h" //#define VERBOSE 1 #include "logmacro.h" @@ -164,8 +165,8 @@ private: void thunderx_videobank_w(uint8_t data); void thunderx_1f98_w(uint8_t data); - void run_collisions(int s0, int e0, int s1, int e1, int cm, int hm); - void calculate_collisions(); + //void run_collisions(int s0, int e0, int s1, int e1, int cm, int hm); + void pmc_run(); void thunderx_map(address_map &map) ATTR_COLD; }; @@ -258,8 +259,7 @@ uint8_t thunderx_state::pmc_r(offs_t offset) } else { - LOG("%04x read pmc internal ram %04x\n", m_audiocpu->pc(), offset); - return 0; + return 0; // PMC internal RAM can't be read back } } @@ -272,141 +272,86 @@ void thunderx_state::pmc_w(offs_t offset, uint8_t data) } else { - LOG("%04x pmc internal ram %04x = %02x\n", m_audiocpu->pc(), offset, data); + LOG("%04x pmc set initial PC %04x = %02x\n", m_audiocpu->pc(), offset, data); + // thunderx only uses one PMC program which has its entry point at address 01 } } /* -this is the data written to internal ram on startup: +This is the 052591 PMC code loaded at startup, it contains a collision check program. +See https://github.com/furrtek/SiliconRE/tree/master/Konami/052591 for details Japan version US version -00: e7 00 00 ad 08 e7 00 00 ad 08 -01: 5f 80 05 a0 0c 1f 80 05 a0 0c LDW ACC,RAM+05 -02: 42 7e 00 8b 04 regE -03: df 00 e2 8b 08 df 8e 00 cb 04 regE -04: 5f 80 06 a0 0c 5f 80 07 a0 0c LDB ACC,RAM+07 -05: df 7e 00 cb 08 df 7e 00 cb 08 LDB R7,[Rx] -06: 1b 80 00 a0 0c 1b 80 00 a0 0c LDPTR #0 PTR2,RAM+00 -07: df 10 00 cb 08 df 10 00 cb 08 LDB R1,[PTR] (fl) LDB R1,[Rx] (flags) -08: 5f 80 03 a0 0c 5f 80 03 a0 0c LDB R0,[3] (cm) LDB ACC,RAM+03 load collide mask -09: 1f 20 00 cb 08 1f 20 00 cb 08 LD CMP2,R0 test (AND) R1 vs ACC -0a: c4 00 00 ab 0c c4 00 00 ab 0c INC PTR LEA Rx,[++PTR2] -0b: df 20 00 cb 08 df 20 00 cb 08 LDB R2,[PTR] (w) LDB R2,[Rx] (width) -0c: c4 00 00 ab 0c c4 00 00 ab 0c INC PTR LEA Rx,[++PTR2] -0d: df 30 00 cb 08 df 30 00 cb 08 LDB R3,[PTR] (h) LDB R3,[Rx] (height) -0e: c4 00 00 ab 0c c4 00 00 ab 0c INC PTR LEA Rx,[++PTR2] -0f: df 40 00 cb 08 df 40 00 cb 08 LDB R4,[PTR] (x) LDB R4,[Rx] (x) -10: c4 00 00 ab 0c c4 00 00 ab 0c INC PTR LEA Rx,[++PTR2] -11: df 50 00 cb 08 df 50 00 cb 08 LDB R5,[PTR] (y) LDB R5,[Rx] (y) -12: 60 22 35 e9 08 60 22 36 e9 08 BANDZ CMP2,R1,36 R2/R1, BEQ 36 -13: 44 0e 00 ab 08 44 0e 00 ab 08 MOVE PTR,INNER LEA Rx,[PTR,0] load flags -14: df 60 00 cb 08 df 60 00 cb 08 LDB R6,[PTR] (fl) LDB R6,[Rx] -15: 5f 80 04 a0 0c 5f 80 04 a0 0c LDB R0,[4] (hm) LDB ACC,RAM+04 load hit mask -16: 1f 60 00 cb 08 1f 60 00 cb 08 LD CMP6,R0 test R6 and ACC (AND) -17: 60 6c 31 e9 08 60 6c 32 e9 08 BANDZ CMP6,R6,32 R6, BEQ 32 -18: 45 8e 01 a0 0c 45 8e 01 a0 0c LDB R0,[INNER+1] LDB Ry,[PTR,1] (width) -19: c5 64 00 cb 08 c5 64 00 cb 08 ADD ACC,R0,R2 R6 = ADD Ry,R2 -1a: 45 8e 03 a0 0c 45 8e 03 a0 0c LDB R0,[INNER+3] LDB Ry,[PTR,3] (x) -1b: 67 00 00 cb 0c 67 00 00 cb 0c MOV CMP,R0 ??? DEC Ry -1c: 15 48 5d c9 0c 15 48 5e c9 0c SUB CMP,R4 ; BGE 1E SUB R4,Ry; Bcc 1E -1d: 12 00 00 eb 0c 12 00 00 eb 0c NEG CMP ??? NEG Ry -1e: 48 6c 71 e9 0c 48 6c 72 e9 0c B (CMP > ACC) 32 R6, BLO 32 -1f: 45 8e 02 a0 0c 45 8e 02 a0 0c LDB R0,[INNER+2] LDB Ry,[PTR,2] (height) -20: c5 66 00 cb 08 c5 66 00 cb 08 ADD ACC,R0,R3 R6 = ADD Ry,R3 -21: 45 8e 04 a0 0c 45 8e 04 a0 0c LDB R0,[INNER+4] LDB Ry,[PTR,4] (y) -22: 67 00 00 cb 0c 67 00 00 cb 0c MOV CMP,R0 ??? DEC Ry -23: 15 5a 64 c9 0c 15 5a 65 c9 0c SUB CMP,R5 ; BGE 25 SUB R5,Ry; Bcc 25 -24: 12 00 00 eb 0c 12 00 00 eb 0c NEG CMP ??? NEG Ry -25: 48 6c 71 e9 0c 48 6c 72 e9 0c B (CMP > ACC) 32 R6, BLO 32 -26: e5 92 9b e0 0c e5 92 9b e0 0c AND R1,#$9B -27: dd 92 10 e0 0c dd 92 10 e0 0c OR R1,#$10 -28: 5c fe 00 a0 0c 5c fe 00 a0 0c ??? STB [PTR,0] -29: df 60 00 d3 08 df 60 00 d3 08 LDB R6, -2a: e5 ec 9f e0 0c e5 ec 9f e0 0c AND R6,#$9F -2b: dd ec 10 00 0c dd ec 10 00 0c OR R6,#$10 -2c: 25 ec 04 c0 0c 25 ec 04 c0 0c STB R6,[PTR2,-4] -2d: 18 82 00 00 0c 18 82 00 00 0c -2e: 4d 80 03 a0 0c 4d 80 03 a0 0c RAM+03 -2f: df e0 e6 e0 0c df e0 36 e1 0c -30: 49 60 75 f1 08 49 60 76 f1 08 Jcc 36 -31: 67 00 35 cd 08 67 00 36 cd 08 Jcc 36 -32: c5 fe 05 e0 0c c5 fe 05 e0 0c ADD R7,R7,5 ADD regE,#5 -33: 5f 80 02 a0 0c 5f 80 02 a0 0c LDB R0, [2] LDB ACC,RAM+02 -34: 1f 00 00 cb 08 1f 00 00 cb 08 LCMP CMP0,R0 -35: 48 6e 52 c9 0c 48 6e 53 c9 0c BNEQ CMP0,R7, 33 R6/R7, BLO 13 -36: c4 00 00 ab 0c c4 00 00 ab 0c INC PTR LEA Rx,[++PTR2] -37: 27 00 00 ab 0c 27 00 00 ab 0c -38: 42 00 00 8b 04 42 00 00 8b 04 MOVE PTR, OUTER -39: 1f 00 00 cb 00 1f 00 00 cb 00 LCMP CMP0 ?? test PTR2 vs ACC -3a: 48 00 43 c9 00 48 00 44 c9 00 BLT 4 BLT 04 next in set 0 -3b: 5f fe 00 e0 08 5f fe 00 e0 08 -3c: 5f 7e 00 ed 08 5f 7e 00 ed 08 -3d: ff 04 00 ff 06 ff 04 00 ff 06 STOP STOP -3e: 05 07 ff 02 03 05 07 ff 02 03 -3f: 01 01 e0 02 6c 01 00 60 00 a0 +00: e7 00 00 ad 08 e7 00 00 ad 08 JP 00, infinite loop +01: 5f 80 05 a0 0c 1f 80 05 a0 0c Set ext address to 5 +02: 42 7e 00 8b 04 +03: df 00 e2 8b 08 df 8e 00 cb 04 r0.b or r0.w = RAM[5] +04: 5f 80 06 a0 0c 5f 80 07 a0 0c Set ext address to 6 or 7 +05: df 7e 00 cb 08 df 7e 00 cb 08 r7.b = RAM[6 or 7] +06: 1b 80 00 a0 0c 1b 80 00 a0 0c Set ext address to r0 +07: df 10 00 cb 08 df 10 00 cb 08 r1.b = RAM[r0] (flags) +08: 5f 80 03 a0 0c 5f 80 03 a0 0c Set ext address to 3 +09: 1f 20 00 cb 08 1f 20 00 cb 08 acc.b = RAM[3] (collide mask) +0a: c4 00 00 ab 0c c4 00 00 ab 0c INC r0, set ext address to r0 +0b: df 20 00 cb 08 df 20 00 cb 08 r2.b = RAM[r0] (width) +0c: c4 00 00 ab 0c c4 00 00 ab 0c INC r0, set ext address to r0 +0d: df 30 00 cb 08 df 30 00 cb 08 r3.b = RAM[r0] (height) +0e: c4 00 00 ab 0c c4 00 00 ab 0c INC r0, set ext address to r0 +0f: df 40 00 cb 08 df 40 00 cb 08 r4.b = RAM[r0] (x) +10: c4 00 00 ab 0c c4 00 00 ab 0c INC r0, set ext address to r0 +11: df 50 00 cb 08 df 50 00 cb 08 r5.b = RAM[r0] (y) +12: 60 22 35 e9 08 60 22 36 e9 08 JP 35 or 36 if r1 AND acc == 0 +13: 44 0e 00 ab 08 44 0e 00 ab 08 Set ext address to r7 +14: df 60 00 cb 08 df 60 00 cb 08 r6.b = RAM[r7] (flags) +15: 5f 80 04 a0 0c 5f 80 04 a0 0c Set ext address to 4 +16: 1f 60 00 cb 08 1f 60 00 cb 08 acc.b = RAM[4] (hit mask) +17: 60 6c 31 e9 08 60 6c 32 e9 08 JP 32 if r6 AND acc == 0 +18: 45 8e 01 a0 0c 45 8e 01 a0 0c Set ext address to r7 + 1 +19: c5 64 00 cb 08 c5 64 00 cb 08 r6.b = RAM[r7 + 1] + r2 (add widths together) +1a: 45 8e 03 a0 0c 45 8e 03 a0 0c Set ext address to r7 + 3 +1b: 67 00 00 cb 0c 67 00 00 cb 0c acc = RAM[r7 + 3] - r4 (x1 - x0) +1c: 15 48 5d c9 0c 15 48 5e c9 0c JP 1D or 1E if positive +1d: 12 00 00 eb 0c 12 00 00 eb 0c NEG acc +1e: 48 6c 71 e9 0c 48 6c 72 e9 0c JP 31 or 32 if r6 < acc +1f: 45 8e 02 a0 0c 45 8e 02 a0 0c Set ext address to r7 + 2 +20: c5 66 00 cb 08 c5 66 00 cb 08 r6.b = RAM[r7 + 2] + r3 (add heights together) +21: 45 8e 04 a0 0c 45 8e 04 a0 0c Set ext address to r7 + 4 +22: 67 00 00 cb 0c 67 00 00 cb 0c acc = RAM[r7 + 4] - r5 (y1 - y0) +23: 15 5a 64 c9 0c 15 5a 65 c9 0c JP 24 or 25 if positive +24: 12 00 00 eb 0c 12 00 00 eb 0c NEG acc +25: 48 6c 71 e9 0c 48 6c 72 e9 0c JP 31 or 32 if r6 < acc +26: e5 92 9b e0 0c e5 92 9b e0 0c AND R1,#$9B +27: dd 92 10 e0 0c dd 92 10 e0 0c OR R1,#$10 +28: 5c fe 00 a0 0c 5c fe 00 a0 0c Set ext address to r7 +29: df 60 00 d3 08 df 60 00 d3 08 r6.b = RAM[r7] (flags) +2a: e5 ec 9f e0 0c e5 ec 9f e0 0c AND r6,#$9F +2b: dd ec 10 00 0c dd ec 10 00 0c RAM[r7] = r6 | #$10 +2c: 25 ec 04 c0 0c 25 ec 04 c0 0c acc = r6 & 4 +2d: 18 82 00 00 0c 18 82 00 00 0c OR acc,r1 +2e: 4d 80 03 a0 0c 4d 80 03 a0 0c Set ext address to r7 - 4 +2f: df e0 e6 e0 0c df e0 36 e1 0c r6 = #$E6 +30: 49 60 75 f1 08 49 60 76 f1 08 JP 35 or 36 if r0 < r6 +31: 67 00 35 cd 08 67 00 36 cd 08 Write acc to [r7 - 4], JP 35 +32: c5 fe 05 e0 0c c5 fe 05 e0 0c r7 += 5, next object in set 1 +33: 5f 80 02 a0 0c 5f 80 02 a0 0c Set ext address to 2 +34: 1f 00 00 cb 08 1f 00 00 cb 08 acc.b = RAM[2] +35: 48 6e 52 c9 0c 48 6e 53 c9 0c JP 12 or 13 if r7 < acc +36: c4 00 00 ab 0c c4 00 00 ab 0c INC r0, next object in set 0 +37: 27 00 00 ab 0c 27 00 00 ab 0c Set ext address to 0 +38: 42 00 00 8b 04 42 00 00 8b 04 acc.w = RAM[0] +39: 1f 00 00 cb 00 1f 00 00 cb 00 +3a: 48 00 43 c9 00 48 00 44 c9 00 JP 3 or 4 if r0 < acc +3b: 5f fe 00 e0 08 5f fe 00 e0 08 Set OUT0 low +3c: 5f 7e 00 ed 08 5f 7e 00 ed 08 JP 0 +3d: ff 04 00 ff 06 ff 04 00 ff 06 Garbage +3e: 05 07 ff 02 03 05 07 ff 02 03 Garbage +3f: 01 01 e0 02 6c 01 00 60 00 a0 Garbage 03 6c 04 40 04 */ -// run_collisions -// -// collide objects from s0 to e0 against -// objects from s1 to e1 -// -// only compare objects with the specified bits (cm) set in their flags -// only set object 0's hit bit if (hm & 0x40) is true -// -// the data format is: -// -// +0 : flags -// +1 : width (4 pixel units) -// +2 : height (4 pixel units) -// +3 : x (2 pixel units) of center of object -// +4 : y (2 pixel units) of center of object - -void thunderx_state::run_collisions( int s0, int e0, int s1, int e1, int cm, int hm ) -{ - for (uint8_t *p0 = &m_pmcram[s0]; p0 < &m_pmcram[e0]; p0 += 5) - { - // check valid - if (!(p0[0] & cm)) - continue; - - // get area - const int l0 = p0[3] - p0[1]; - const int r0 = p0[3] + p0[1]; - const int t0 = p0[4] - p0[2]; - const int b0 = p0[4] + p0[2]; - - for (uint8_t *p1 = &m_pmcram[s1]; p1 < &m_pmcram[e1]; p1 += 5) - { - // check valid - if (!(p1[0] & hm)) - continue; - - // get area - const int l1 = p1[3] - p1[1]; - const int r1 = p1[3] + p1[1]; - const int t1 = p1[4] - p1[2]; - const int b1 = p1[4] + p1[2]; - - // overlap check - if (l1 >= r0) continue; - if (l0 >= r1) continue; - if (t1 >= b0) continue; - if (t0 >= b1) continue; - - // set flags - p0[0] = (p0[0] & 0x8f) | (p1[0] & 0x04) | 0x10; - p1[0] = (p1[0] & 0x8f) | 0x10; - } - } -} - -// calculate_collisions -// // emulates K052591 collision detection -void thunderx_state::calculate_collisions() +void thunderx_state::pmc_run() { // the data at 0x00 to 0x06 defines the operation // @@ -423,18 +368,17 @@ void thunderx_state::calculate_collisions() // 0x07 : byte : first byte of set 1 // // the operation is to intersect set 0 with set 1 - // collide mask specifies objects to ignore - // hit mask is 40 to set bit on object 0 and object 1 - // hit mask is 20 to set bit on object 1 only + // masks specify objects to ignore - const int e0 = (m_pmcram[0] << 8) | m_pmcram[1]; - const int e1 = m_pmcram[2]; + const uint16_t e0 = get_u16be(&m_pmcram[0]); + const uint8_t e1 = m_pmcram[2]; - int s0, s1; + uint16_t s0, s1; + // Heuristic to determine version of program based on byte at 0x05 if (m_pmcram[5] < 16) { // US Thunder Cross uses this form - s0 = (m_pmcram[5] << 8) + m_pmcram[6]; + s0 = get_u16be(&m_pmcram[5]); s1 = m_pmcram[7]; } else @@ -444,10 +388,44 @@ void thunderx_state::calculate_collisions() s1 = m_pmcram[6]; } - const int cm = m_pmcram[3]; - const int hm = m_pmcram[4]; + const uint8_t cm = m_pmcram[3]; + const uint8_t hm = m_pmcram[4]; - run_collisions(s0, e0, s1, e1, cm, hm); + // collide objects from s0 to e0 against objects from s1 to e1 + // only process objects with the specified bits (cm/hm) set in their flags + // + // the data format for each object is: + // + // +0 : flags + // +1 : width (4 pixel units) + // +2 : height (4 pixel units) + // +3 : x (2 pixel units) of center of object + // +4 : y (2 pixel units) of center of object + for (uint8_t *p0 = &m_pmcram[s0]; p0 < &m_pmcram[e0]; p0 += 5) + { + // check object 0 flags + if (!(p0[0] & cm)) + continue; + + for (uint8_t *p1 = &m_pmcram[s1]; p1 < &m_pmcram[e1]; p1 += 5) + { + // check object 1 flags + if (!(p1[0] & hm)) + continue; + + if (p1[1] + p0[1] < abs(p1[3] - p0[3])) continue; + if (p1[2] + p0[2] < abs(p1[4] - p0[4])) continue; + + // set flags + p1[0] = (p1[0] & 0x8f) | 0x10; + if (p1 > (uint8_t*)0xe6) // This address value is hardcoded in the PMC program + p0[0] = (p0[0] & 0x9b) | (p1[0] & 0x04) | 0x10; + break; + } + } + + // 100 cycle delay is arbitrary + m_thunderx_firq_timer->adjust(m_maincpu->cycles_to_attotime(100)); } void thunderx_state_base::scontra_1f98_w(uint8_t data) @@ -475,10 +453,7 @@ void thunderx_state::thunderx_1f98_w(uint8_t data) // bit 2 = PMC START (do collision detection when 0->1) if ((data & 4) && !(m_1f98_latch & 4)) { - calculate_collisions(); - - // 100 cycle delay is arbitrary - m_thunderx_firq_timer->adjust(m_maincpu->cycles_to_attotime(100)); + pmc_run(); } scontra_1f98_w(data);