summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/nix/pirates.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/nix/pirates.cpp')
-rw-r--r--src/mame/nix/pirates.cpp643
1 files changed, 643 insertions, 0 deletions
diff --git a/src/mame/nix/pirates.cpp b/src/mame/nix/pirates.cpp
new file mode 100644
index 00000000000..e9f6b22f31a
--- /dev/null
+++ b/src/mame/nix/pirates.cpp
@@ -0,0 +1,643 @@
+// license:BSD-3-Clause
+// copyright-holders: David Haywood, Nicola Salmoria, Paul Priest
+
+/*---
+
+Pirates (c)1994 NIX (DEC 14 1994 17:32:29) displayed in cabinet test mode
+Genix Family (c)1994 NIX (MAY 10 1994 14:21:20) displayed in cabinet test mode
+driver by David Haywood and Nicola Salmoria
+
+TODO:
+- EEPROM doesn't work. I'm not sure what the program is trying to do.
+ The EEPROM handling might actually be related to the protection which
+ makes the game hang.
+ See prot_r() for code which would work around the protection,
+ but makes the game periodically hang for a couple of seconds; therefore,
+ for now I'm just patching out the protection check.
+
+- Protection is the same in Genix Family
+
+-----
+
+Here's some info about the dump:
+
+Name: Pirates
+Manufacturer: NIX
+Year: 1994
+Date Dumped: 14-07-2002 (DD-MM-YYYY)
+
+CPU: 68000, possibly at 12mhz (prototype board does have a 16mhz one)
+SOUND: OKIM6295
+GFX: Unknown
+
+CPU ROMs at least are the same on the prototype board (the rest of the ROMs probably are too)
+
+-----
+
+Program ROMs are Scrambled (Data + Address Lines)
+P Graphic ROMs (Tilemap Tiles) are Scrambled (Data + Address Lines)
+S Graphic ROMs (Sprite Tiles) are Scrambled (Data + Address Lines)
+OKI Samples ROM is Scrambled (Data + Address Lines)
+
+68k interrupts (pirates)
+lev 1 : 0x64 : 0000 bf84 - vbl?
+lev 2 : 0x68 : 0000 4bc6 -
+lev 3 : 0x6c : 0000 3bda -
+lev 4 : 0x70 : 0000 3bf0 -
+lev 5 : 0x74 : 0000 3c06 -
+lev 6 : 0x78 : 0000 3c1c -
+lev 7 : 0x7c : 0000 3c32 -
+
+Inputs mapped by Stephh
+
+The game hanging is an interesting issue, the board owner has 2 copies of this game, one a prototype,
+one the final released version. The ROMs on both boards are the same, however the prototype locks up
+just as it does in MAME at the moment. The final board does not. It would appear the prototype
+board does not have the protection hardware correctly in place
+
+
+PCB Layout (Genix Family) (by Guru)
+----------
+
+|------------------------------------------------|
+| 0.31 6116 6116 3.72 |
+| M6295 6116 6116 4.71 |
+| 5.70 |
+| 6264 6116 6.69 |
+| 6264 6116 |
+| |
+| |
+| 93C46 Altera 24MHz Altera |
+| EPM7064 EPM7064 |
+| |
+| |
+| Altera Altera 7.34 9.35 |
+| EPM7064 EPM7064 8.48 10.49 |
+| |
+| PAL |
+| |
+| 68000 1.15 62256 6264 |
+| 32MHz 2.16 62256 6264 |
+| * |
+|------------------------------------------------|
+
+Notes:
+ 68000 clock: 16.000MHz
+ M6295 clock: 1.33333MHz, Sample Rate: /165
+ VSync: 60Hz
+ HSync: 15.69kHz
+ * : unknown IC (18 pin DIP, surface scratched off)
+
+---*/
+
+#include "emu.h"
+
+#include "cpu/m68000/m68000.h"
+#include "machine/eepromser.h"
+#include "sound/okim6295.h"
+
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+#include "tilemap.h"
+
+
+// configurable logging
+#define LOG_OUT (1U << 1)
+#define LOG_PROT (1U << 2)
+
+//#define VERBOSE (LOG_GENERAL | LOG_OUT | LOG_PROT)
+
+#include "logmacro.h"
+
+#define LOGOUT(...) LOGMASKED(LOG_OUT, __VA_ARGS__)
+#define LOGPROT(...) LOGMASKED(LOG_OUT, __VA_ARGS__)
+
+
+namespace {
+
+class pirates_state : public driver_device
+{
+public:
+ pirates_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_eeprom(*this, "eeprom"),
+ m_oki(*this, "oki"),
+ m_gfxdecode(*this, "gfxdecode"),
+ m_palette(*this, "palette"),
+ m_spriteram(*this, "spriteram"),
+ m_scroll(*this, "scroll"),
+ m_tx_tileram(*this, "tx_tileram"),
+ m_fg_tileram(*this, "fg_tileram"),
+ m_bg_tileram(*this, "bg_tileram")
+ { }
+
+ void pirates(machine_config &config);
+
+ void init_pirates();
+ void init_genix();
+
+ int prot_r();
+
+protected:
+ virtual void video_start() override ATTR_COLD;
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<eeprom_serial_93cxx_device> m_eeprom;
+ required_device<okim6295_device> m_oki;
+ required_device<gfxdecode_device> m_gfxdecode;
+ required_device<palette_device> m_palette;
+
+ required_shared_ptr<uint16_t> m_spriteram;
+ required_shared_ptr<uint16_t> m_scroll;
+ required_shared_ptr<uint16_t> m_tx_tileram;
+ required_shared_ptr<uint16_t> m_fg_tileram;
+ required_shared_ptr<uint16_t> m_bg_tileram;
+
+ tilemap_t *m_tx_tilemap = nullptr;
+ tilemap_t *m_fg_tilemap = nullptr;
+ tilemap_t *m_bg_tilemap = nullptr;
+
+ void out_w(uint8_t data);
+ void tx_tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void fg_tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ void bg_tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t genix_prot_r(offs_t offset);
+
+ TILE_GET_INFO_MEMBER(get_tx_tile_info);
+ TILE_GET_INFO_MEMBER(get_fg_tile_info);
+ TILE_GET_INFO_MEMBER(get_bg_tile_info);
+
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ void decrypt_68k();
+ void decrypt_p();
+ void decrypt_s();
+ void decrypt_oki();
+ void prg_map(address_map &map) ATTR_COLD;
+};
+
+
+// tilemaps
+
+TILE_GET_INFO_MEMBER(pirates_state::get_tx_tile_info)
+{
+ int const code = m_tx_tileram[tile_index * 2];
+ int const colr = m_tx_tileram[tile_index * 2 + 1];
+
+ tileinfo.set(0, code, colr, 0);
+}
+
+TILE_GET_INFO_MEMBER(pirates_state::get_fg_tile_info)
+{
+ int const code = m_fg_tileram[tile_index * 2];
+ int const colr = m_fg_tileram[tile_index * 2 + 1] + 0x80;
+
+ tileinfo.set(0, code, colr, 0);
+}
+
+TILE_GET_INFO_MEMBER(pirates_state::get_bg_tile_info)
+{
+ int const code = m_bg_tileram[tile_index * 2];
+ int const colr = m_bg_tileram[tile_index * 2 + 1] + 0x100;
+
+ tileinfo.set(0, code, colr, 0);
+}
+
+
+// video start / update
+
+void pirates_state::video_start()
+{
+ m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(pirates_state::get_tx_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 36, 32);
+
+ // Not sure how big they can be, Pirates uses only 32 columns, Genix 44
+ m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(pirates_state::get_fg_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 64, 32);
+ m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(pirates_state::get_bg_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 64, 32);
+
+ m_tx_tilemap->set_transparent_pen(0);
+ m_fg_tilemap->set_transparent_pen(0);
+}
+
+
+
+void pirates_state::tx_tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(m_tx_tileram + offset);
+ m_tx_tilemap->mark_tile_dirty(offset / 2);
+}
+
+void pirates_state::fg_tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(m_fg_tileram + offset);
+ m_fg_tilemap->mark_tile_dirty(offset / 2);
+}
+
+void pirates_state::bg_tileram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(m_bg_tileram + offset);
+ m_bg_tilemap->mark_tile_dirty(offset / 2);
+}
+
+
+
+void pirates_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ gfx_element *gfx = m_gfxdecode->gfx(1);
+ uint16_t const *source = m_spriteram + 4;
+ uint16_t const *finish = source + 0x800 / 2 - 4;
+
+ while (source < finish)
+ {
+ int const xpos = source[1] - 32;
+ int ypos = source[-1]; // indeed...
+
+ if (ypos & 0x8000) break; // end-of-list marker
+
+ int const code = source[2] >> 2;
+ int const color = source[0] & 0xff;
+ int const flipx = source[2] & 2;
+ int const flipy = source[2] & 1;
+
+ ypos = 0xf2 - ypos;
+
+ gfx->transpen(bitmap, cliprect,
+ code,
+ color,
+ flipx, flipy,
+ xpos, ypos, 0);
+
+ source += 4;
+ }
+}
+
+uint32_t pirates_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ m_bg_tilemap->set_scrollx(0, m_scroll[0]);
+ m_fg_tilemap->set_scrollx(0, m_scroll[0]);
+ m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ draw_sprites(bitmap, cliprect);
+ m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+
+void pirates_state::out_w(uint8_t data)
+{
+ // bits 0-2 control EEPROM
+ m_eeprom->di_write((data & 0x04) >> 2);
+ m_eeprom->cs_write((data & 0x01) ? ASSERT_LINE : CLEAR_LINE);
+ m_eeprom->clk_write((data & 0x02) ? ASSERT_LINE : CLEAR_LINE);
+
+ // bit 6 selects oki bank
+ m_oki->set_rom_bank((data >> 6) & 1);
+
+ // bit 7 used (function unknown)
+
+ LOGOUT("%06x: out_w %04x\n", m_maincpu->pc(), data);
+}
+
+int pirates_state::prot_r()
+{
+// static int prot = 0xa3;
+// offs_t pc;
+ int bit;
+
+ LOGPROT("%s: IN1_r\n", machine().describe_context());
+
+#if 0
+ /* Pirates protection workaround. It's more complicated than this... see code at
+ 602e and 62a6
+ For Genix, see 6576 for setting values and 67c2,d3b4 and dbc2 for tests. */
+
+ pc = m_maincpu->pc();
+ if (pc == 0x6134)
+ {
+ bit = prot & 1;
+ prot = (prot >> 1) | (bit << 7);
+ }
+ else if (pc == 0x6020)
+ bit = 0;
+ else if (pc == 0x6168)
+ bit = 0;
+ else if (pc == 0x61cc)
+ bit = 1;
+ else
+#endif
+ bit = 1;
+
+ return bit;
+}
+
+
+
+// Memory Maps
+
+void pirates_state::prg_map(address_map &map)
+{
+ map(0x000000, 0x0fffff).rom();
+ map(0x100000, 0x10ffff).ram(); // main
+ map(0x300000, 0x300001).portr("INPUTS");
+ map(0x400000, 0x400001).portr("SYSTEM");
+// map(0x500000, 0x5007ff).ram();
+ map(0x500000, 0x5007ff).writeonly().share(m_spriteram);
+// map(0x500800, 0x50080f).nopw();
+ map(0x600001, 0x600001).w(FUNC(pirates_state::out_w));
+ map(0x700000, 0x700001).writeonly().share(m_scroll);
+ map(0x800000, 0x803fff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
+ map(0x900000, 0x90017f).ram(); // more of tilemaps ?
+ map(0x900180, 0x90137f).ram().w(FUNC(pirates_state::tx_tileram_w)).share(m_tx_tileram);
+ map(0x901380, 0x902a7f).ram().w(FUNC(pirates_state::fg_tileram_w)).share(m_fg_tileram);
+// map(0x902580, 0x902a7f).ram(); // more of tilemaps ?
+ map(0x902a80, 0x904187).ram().w(FUNC(pirates_state::bg_tileram_w)).share(m_bg_tileram);
+// map(0x903c80, 0x904187).ram(); // more of tilemaps ?
+ map(0xa00001, 0xa00001).rw(m_oki, FUNC(okim6295_device::read), FUNC(okim6295_device::write));
+}
+
+
+// Input Ports
+
+static INPUT_PORTS_START( pirates )
+ PORT_START("INPUTS") // 0x300000.w
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("SYSTEM") // 0x400000.w
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_COIN2 )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SERVICE1 )
+ PORT_SERVICE_NO_TOGGLE( 0x0008, IP_ACTIVE_LOW )
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH,IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("eeprom", FUNC(eeprom_serial_93cxx_device::do_read)) // EEPROM data
+ PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // seems checked in "test mode"
+ PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // seems checked in "test mode"
+ PORT_BIT( 0x0080, IP_ACTIVE_HIGH,IPT_CUSTOM ) PORT_READ_LINE_MEMBER(FUNC(pirates_state::prot_r)) // protection
+ // What do these bits do ?
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+ PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_UNKNOWN )
+INPUT_PORTS_END
+
+
+
+static const gfx_layout charlayout =
+{
+ 8,8,
+ RGN_FRAC(1,4),
+ 4,
+ { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
+ { 7, 6, 5, 4, 3, 2, 1, 0 },
+ { 8*0, 8*1, 8*2, 8*3, 8*4, 8*5, 8*6, 8*7 },
+ 8*8
+};
+
+static const gfx_layout spritelayout =
+{
+ 16,16,
+ RGN_FRAC(1,4),
+ 4,
+ { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) },
+ { 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8 },
+ { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16,
+ 8*16, 9*16,10*16,11*16,12*16,13*16,14*16,15*16 },
+ 16*16
+};
+
+static GFXDECODE_START( gfx_pirates )
+ GFXDECODE_ENTRY( "tiles", 0, charlayout, 0x0000, 3*128 )
+ GFXDECODE_ENTRY( "sprites", 0, spritelayout, 0x1800, 128 )
+GFXDECODE_END
+
+
+
+// Machine Driver + Related bits
+
+void pirates_state::pirates(machine_config &config)
+{
+ M68000(config, m_maincpu, 32_MHz_XTAL / 2); // 16MHz verified on PCB
+ m_maincpu->set_addrmap(AS_PROGRAM, &pirates_state::prg_map);
+ m_maincpu->set_vblank_int("screen", FUNC(pirates_state::irq1_line_hold));
+
+ EEPROM_93C46_16BIT(config, "eeprom");
+
+ GFXDECODE(config, m_gfxdecode, m_palette, gfx_pirates);
+
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_refresh_hz(60);
+ screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ screen.set_size(36*8, 32*8);
+ screen.set_visarea(0*8, 36*8-1, 2*8, 30*8-1);
+ screen.set_screen_update(FUNC(pirates_state::screen_update));
+ screen.set_palette(m_palette);
+
+ PALETTE(config, m_palette).set_format(palette_device::xRGB_555, 0x2000);
+
+ SPEAKER(config, "mono").front_center();
+
+ OKIM6295(config, m_oki, 24_MHz_XTAL / 18, okim6295_device::PIN7_LOW).add_route(ALL_OUTPUTS, "mono", 1.0); // 1.3333333MHz verified on PCB
+}
+
+
+// ROM Loading
+
+ROM_START( pirates )
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 Code (encrypted)
+ ROM_LOAD16_BYTE( "r_449b.bin", 0x00000, 0x80000, CRC(224aeeda) SHA1(5b7e47a106af0debf8b07f120571f437ad6ab5c3) )
+ ROM_LOAD16_BYTE( "l_5c1e.bin", 0x00001, 0x80000, CRC(46740204) SHA1(6f1da3b2cbea25bbfdec74c625c5fb23459b83b6) )
+
+ ROM_REGION( 0x200000, "tiles", 0 ) // encrypted
+ ROM_LOAD( "p4_4d48.bin", 0x000000, 0x080000, CRC(89fda216) SHA1(ea31e750460e67a24972b04171230633eb2b6d9d) )
+ ROM_LOAD( "p2_5d74.bin", 0x080000, 0x080000, CRC(40e069b4) SHA1(515d12cbb29bdbf3f3016e5bbe14941209978095) )
+ ROM_LOAD( "p1_7b30.bin", 0x100000, 0x080000, CRC(26d78518) SHA1(c293f1194f8ef38241d149cf1db1a511a7fb4936) )
+ ROM_LOAD( "p8_9f4f.bin", 0x180000, 0x080000, CRC(f31696ea) SHA1(f5ab59e441317b02b615a1cdc6d075c5bdcdea73) )
+
+ ROM_REGION( 0x200000, "sprites", 0 ) // encrypted
+ ROM_LOAD( "s1_6e89.bin", 0x000000, 0x080000, CRC(c78a276f) SHA1(d5127593e68f9e8f2878803c652a35a1c6d82b2c) )
+ ROM_LOAD( "s2_6df3.bin", 0x080000, 0x080000, CRC(9f0bad96) SHA1(b8f910aa259192e261815392f5d7c9c7dabe0b4d) )
+ ROM_LOAD( "s4_fdcc.bin", 0x100000, 0x080000, CRC(8916ddb5) SHA1(f4f7da831ef929eb7575bbe69eae317f15cfd648) )
+ ROM_LOAD( "s8_4b7c.bin", 0x180000, 0x080000, CRC(1c41bd2c) SHA1(fba264a3c195f303337223a74cbad5eec5c457ec) )
+
+ ROM_REGION( 0x080000, "oki", 0) // encrypted
+ ROM_LOAD( "s89_49d4.bin", 0x000000, 0x080000, CRC(63a739ec) SHA1(c57f657225e62b3c9c5f0c7185ad7a87794d55f4) )
+ROM_END
+
+ROM_START( piratesb )
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 Code (encrypted)
+ ROM_LOAD16_BYTE( "u15", 0x00000, 0x80000, CRC(0cfd6415) SHA1(ff5d3631702f64351afa3b7435a6977ae856dff7) )
+ ROM_LOAD16_BYTE( "u16", 0x00001, 0x80000, CRC(98cece02) SHA1(79858623a2b6ae24067e0ba1af009444bafba490) )
+
+ ROM_REGION( 0x200000, "tiles", 0 ) // encrypted
+ ROM_LOAD( "u34", 0x000000, 0x080000, CRC(89fda216) SHA1(ea31e750460e67a24972b04171230633eb2b6d9d) )
+ ROM_LOAD( "u35", 0x080000, 0x080000, CRC(40e069b4) SHA1(515d12cbb29bdbf3f3016e5bbe14941209978095) )
+ ROM_LOAD( "u48", 0x100000, 0x080000, CRC(26d78518) SHA1(c293f1194f8ef38241d149cf1db1a511a7fb4936) )
+ ROM_LOAD( "u49", 0x180000, 0x080000, CRC(f31696ea) SHA1(f5ab59e441317b02b615a1cdc6d075c5bdcdea73) )
+
+ ROM_REGION( 0x200000, "sprites", 0 ) // encrypted
+ ROM_LOAD( "u69", 0x000000, 0x080000, CRC(c78a276f) SHA1(d5127593e68f9e8f2878803c652a35a1c6d82b2c) )
+ ROM_LOAD( "u70", 0x080000, 0x080000, CRC(9f0bad96) SHA1(b8f910aa259192e261815392f5d7c9c7dabe0b4d) )
+ ROM_LOAD( "u71", 0x100000, 0x080000, CRC(0bb7c816) SHA1(bc786b6d04ae964f0ea5d6dd314fd7b18f8872e8) ) // 1 bit different, is one of them bad?
+ ROM_LOAD( "u72", 0x180000, 0x080000, CRC(1c41bd2c) SHA1(fba264a3c195f303337223a74cbad5eec5c457ec) )
+
+ ROM_REGION( 0x080000, "oki", 0) // encrypted
+ ROM_LOAD( "u31", 0x000000, 0x080000, CRC(63a739ec) SHA1(c57f657225e62b3c9c5f0c7185ad7a87794d55f4) )
+ROM_END
+
+
+ROM_START( genix )
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code (encrypted)
+ ROM_LOAD16_BYTE( "11.u15.15c", 0x00000, 0x80000, CRC(d26abfb0) SHA1(4a89ba7504f86cb612796c376f359ab61ec3d902) )
+ ROM_LOAD16_BYTE( "12.u16.16c", 0x00001, 0x80000, CRC(a14a25b4) SHA1(9fa64c6514bdee56b5654b001f8367283b461e8a) )
+
+ ROM_REGION( 0x200000, "tiles", 0 ) // encrypted
+ ROM_LOAD( "17.u34.12g", 0x000000, 0x040000, CRC(58da8aac) SHA1(bfc8449ba842f8ceac62ebdf6005d8f19d96afa6) )
+ ROM_LOAD( "19.u35.12h", 0x080000, 0x040000, CRC(96bad9a8) SHA1(4e757cca0ab157f0c935087c9702c88741bf7a79) )
+ ROM_LOAD( "18.u48.13g", 0x100000, 0x040000, CRC(0ddc58b6) SHA1(d52437607695ddebfe8494fd214efd20ba72d549) )
+ ROM_LOAD( "20.u49.13h", 0x180000, 0x040000, CRC(2be308c5) SHA1(22fc0991557643c22f6763f186b74900a33a39e0) )
+
+ ROM_REGION( 0x200000, "sprites", 0 ) // encrypted
+ ROM_LOAD( "16.u69.6g", 0x000000, 0x040000, CRC(b8422af7) SHA1(d3290fc6ea2670c445731e2b493205874dc4b319) )
+ ROM_LOAD( "15.u70.4g", 0x080000, 0x040000, CRC(e46125c5) SHA1(73d9a51f30a9c1a8397145d2a4397696ef37f4e5) )
+ ROM_LOAD( "14.u71.3g", 0x100000, 0x040000, CRC(7a8ed21b) SHA1(f380156c44de2fc316f390adee09b6a3cd404dec) )
+ ROM_LOAD( "13.u72.1g", 0x180000, 0x040000, CRC(f78bd6ca) SHA1(c70857b8053f9a6e3e15bbc9f7d13354b0966b30) )
+
+ ROM_REGION( 0x080000, "oki", 0) // encrypted
+ ROM_LOAD( "10.u31.1b", 0x000000, 0x080000, CRC(80d087bc) SHA1(04d1aacc273c7ffa57b48bd043d55b5b3d993f74) )
+ROM_END
+
+// Init
+
+void pirates_state::decrypt_68k()
+{
+ uint16_t *rom = (uint16_t *)memregion("maincpu")->base();
+ size_t rom_size = memregion("maincpu")->bytes();
+ std::vector<uint16_t> buf(rom_size / 2);
+
+ memcpy(&buf[0], rom, rom_size);
+
+ for (int i = 0; i < rom_size / 2; i++)
+ {
+ int adrl = bitswap<24>(i, 23, 22, 21, 20, 19, 18, 4, 8, 3, 14, 2, 15, 17, 0, 9, 13, 10, 5, 16, 7, 12, 6, 1, 11);
+ uint8_t vl = bitswap<8>(buf[adrl], 4, 2, 7, 1, 6, 5, 0, 3);
+
+ int adrr = bitswap<24>(i,23, 22, 21, 20, 19, 18, 4, 10, 1, 11, 12, 5, 9, 17, 14, 0, 13, 6, 15, 8, 3, 16, 7, 2);
+ uint8_t vr = bitswap<8>(buf[adrr] >> 8, 1, 4, 7, 0, 3, 5, 6, 2);
+
+ rom[i] = (vr << 8) | vl;
+ }
+}
+
+void pirates_state::decrypt_p()
+{
+ int rom_size = memregion("tiles")->bytes();
+
+ std::vector<uint8_t> buf(rom_size);
+
+ uint8_t *rom = memregion("tiles")->base();
+ memcpy(&buf[0], rom, rom_size);
+
+ for (int i = 0; i < rom_size / 4; i++)
+ {
+ int adr = bitswap<24>(i, 23, 22, 21, 20, 19, 18, 10, 2, 5, 9, 7, 13, 16, 14, 11, 4, 1, 6, 12, 17, 3, 0, 15, 8);
+ rom[adr + 0 * (rom_size / 4)] = bitswap<8>(buf[i + 0 * (rom_size / 4)], 2, 3, 4, 0, 7, 5, 1, 6);
+ rom[adr + 1 * (rom_size / 4)] = bitswap<8>(buf[i + 1 * (rom_size / 4)], 4, 2, 7, 1, 6, 5, 0, 3);
+ rom[adr + 2 * (rom_size / 4)] = bitswap<8>(buf[i + 2 * (rom_size / 4)], 1, 4, 7, 0, 3, 5, 6, 2);
+ rom[adr + 3 * (rom_size / 4)] = bitswap<8>(buf[i + 3 * (rom_size / 4)], 2, 3, 4, 0, 7, 5, 1, 6);
+ }
+}
+
+void pirates_state::decrypt_s()
+{
+ int rom_size = memregion("sprites")->bytes();
+
+ std::vector<uint8_t> buf(rom_size);
+
+ uint8_t *rom = memregion("sprites")->base();
+ memcpy(&buf[0], rom, rom_size);
+
+ for (int i = 0; i < rom_size / 4; i++)
+ {
+ int adr = bitswap<24>(i, 23, 22, 21, 20, 19, 18, 17, 5, 12, 14, 8, 3, 0, 7, 9, 16, 4, 2, 6, 11, 13, 1, 10, 15);
+ rom[adr + 0*(rom_size / 4)] = bitswap<8>(buf[i + 0 * (rom_size / 4)], 4, 2, 7, 1, 6, 5, 0, 3);
+ rom[adr + 1*(rom_size / 4)] = bitswap<8>(buf[i + 1 * (rom_size / 4)], 1, 4, 7, 0, 3, 5, 6, 2);
+ rom[adr + 2*(rom_size / 4)] = bitswap<8>(buf[i + 2 * (rom_size / 4)], 2, 3, 4, 0, 7, 5, 1, 6);
+ rom[adr + 3*(rom_size / 4)] = bitswap<8>(buf[i + 3 * (rom_size / 4)], 4, 2, 7, 1, 6, 5, 0, 3);
+ }
+}
+
+
+void pirates_state::decrypt_oki()
+{
+ int rom_size = memregion("oki")->bytes();
+
+ std::vector<uint8_t> buf(rom_size);
+
+ uint8_t *rom = memregion("oki")->base();
+ memcpy(&buf[0], rom, rom_size);
+
+ for (int i = 0; i < rom_size; i++)
+ {
+ int adr = bitswap<24>(i, 23, 22, 21, 20, 19, 10, 16, 13, 8, 4, 7, 11, 14, 17, 12, 6, 2, 0, 5, 18, 15, 3, 1, 9);
+ rom[adr] = bitswap<8>(buf[i], 2, 3, 4, 0, 7, 5, 1, 6);
+ }
+}
+
+
+void pirates_state::init_pirates()
+{
+ uint16_t *rom = (uint16_t *)memregion("maincpu")->base();
+
+ decrypt_68k();
+ decrypt_p();
+ decrypt_s();
+ decrypt_oki();
+
+ // patch out protection check
+ rom[0x62c0 / 2] = 0x6006; // beq -> bra
+}
+
+uint16_t pirates_state::genix_prot_r(offs_t offset){ if(!offset) return 0x0004; else return 0x0000; }
+
+void pirates_state::init_genix()
+{
+ decrypt_68k();
+ decrypt_p();
+ decrypt_s();
+ decrypt_oki();
+
+ /* If this value is increased then something has gone wrong and the protection failed
+ Write-protect it for now */
+ m_maincpu->space(AS_PROGRAM).install_read_handler(0x109e98, 0x109e9b, read16sm_delegate(*this, FUNC(pirates_state::genix_prot_r)));
+}
+
+} // anonymous namespace
+
+
+// GAME
+
+GAME( 1994, pirates, 0, pirates, pirates, pirates_state, init_pirates, 0, "NIX", "Pirates (set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1995, piratesb, pirates, pirates, pirates, pirates_state, init_pirates, 0, "NIX", "Pirates (set 2)", MACHINE_SUPPORTS_SAVE ) // shows 'Copyright 1995' instead of (c)1994 Nix, but isn't unprotected, various changes to the names in the credits + a few other minor alterations
+
+GAME( 1994, genix, 0, pirates, pirates, pirates_state, init_genix, 0, "NIX", "Genix Family", MACHINE_SUPPORTS_SAVE )