// license:BSD-3-Clause
// copyright-holders:David Haywood, Xing Xing, Andreas Naive
/* PGM 2 hardware.
Motherboard is bare bones stuff, and does not contain any ROMs.
The IGS036 used by the games is an ARM based CPU, like IGS027A used on PGM1 it has internal ROM.
Decryption should be correct in most cases.
The ARM appears to be ARMv5T, probably an ARM9.
PGM2 Motherboard Components:
IS61LV25616AL(SRAM)
IGS037(GFX PROCESSOR)
YMZ774-S(SOUND)
R5F21256SN(extra MCU for ICcard communication)
- Appears to be referred to by the games as MPU
Cartridges
IGS036 (MAIN CPU) (differs per game, internal code)
ROMs
Custom program ROM module (KOV3 only)
- on some games ROM socket contains Flash ROM + SRAM
QFP100 chip (Xlinx CPLD)
Single PCB versions of some of the titles were also available
Only 5 Games were released for this platform, 3 of which are just updates / re-releases of older titles!
The platform has since been superseded by PGM3, see pgm3.cpp
Oriental Legend 2
The King of Fighters '98 - Ultimate Match - Hero
Knights of Valour 2 New Legend
Dodonpachi Daioujou Tamashii
Knights of Valour 3
These were only released as single board PGM2 based hardware, seen for sale in Japan for around $250-$300
Jigsaw World Arena
Puzzle of Ocha / Ochainu No Pazuru
ToDo (emulation issues):
Support remaining games (need IGS036 dumps)
Identify which regions each game was released in and either dump alt. internal ROMs for each region, or
create them until that can be done.
properly implement RTC (integrated into the CPU)
Verify Sprite Zoom (check exactly which pixels are doubled / missed on hardware for flipped , non-flipped cases etc.)
Fix Save States (is this a driver problem or an ARM core problem, they don't work unless you get through the startup tests)
Determine motherboard card reader MCU internal ROM size and add as NO_DUMP to the sets
See if kov2nl needs another idle skip, after Game Over there is a period where the current one is ineffective
Debug features (require DIP SW1:8 On and SW1:1 Off):
- QC TEST mode: hold P1 A+B during boot
- Debug/Cheat mode: hold P1 B+C during boot
orleg2 and kov2nl: when ingame pressing P1 Start skips to next location, where might be more unknown debug features.
Holographic Stickers
The IGS036 CPUs have holographic stickers on them, there is a number printed on each sticker but it doesn't seem connected to the
game code / revision contained within, it might just be to mark the date the board was produced as it seems to coincide with the
design of the hologram. For reference the ones being used for dumping are
Dodonpachi Daioujou Tamashi (China) - W10
King of Fighter 98 UMH (China) - C11
Knights of Valour 2 (China) - V21
Knights of Valour 3 (China) - V21
Oriental Legend 2 (Oversea) - V21
Oriental Legend 2 (China) - A8
GPU registers, located at 301200xx, 16bit access.
00 - bg scroll x
02 - bg scroll y
04 - zoom something, 0F-7F, default 1F
06 - zoom something, 0F-7F, default 1F
08 - fg scroll x
0a - fg scroll y
0e - resolution, 0 - low (kof98umh), 1 - high (rest of games), 2 - higher (kov3)
10 - ? orleg2 - 0x13, kov2nl, kov3, kof98umh, ddpdojt - 0x14 at init
14 - sprite enable ? set to 0 before spriteram update, to 1 after
16 - set to 1 before access to vrams/palettes, reset after. bits: 0 - bg RAM and palette, 1 - fg RAM and palette, 2 - sprite palette.
18 - vblank ack
1a - ? 0 at init
1c - ? orleg2 - 5, kov2nl, kov3, kof98umh, ddpdojt - 7 at init
1e - ? 2 at init
32 - shared RAM bank
34, 36 - ? 0 at init
38, 3a - sprite mask xor key
*/
#include "emu.h"
#include "includes/pgm2.h"
// checked on startup, or doesn't boot
READ32_MEMBER(pgm2_state::unk_startup_r)
{
logerror("%s: unk_startup_r\n", machine().describe_context().c_str());
return 0x00000180;
}
READ32_MEMBER(pgm2_state::rtc_r)
{
// write to FFFFFD20 if bit 18 set (0x40000) probably reset this RTC timer
// TODO: somehow hook here current time/date, which is a bit complicated because value is relative, later to it added "base time" stored in SRAM
return machine().time().seconds();
}
READ8_MEMBER(pgm2_state::encryption_r)
{
return m_encryption_table[offset];
}
WRITE8_MEMBER(pgm2_state::encryption_w)
{
m_encryption_table[offset] = data;
}
WRITE32_MEMBER(pgm2_state::sprite_encryption_w)
{
COMBINE_DATA(&m_spritekey);
if (!m_sprite_predecrypted)
m_realspritekey = bitswap<32>(m_spritekey ^ 0x90055555, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
}
void pgm2_state::device_post_load()
{
// make sure the encrypted area is in the correct state after we load a savestate because we don't want to have to save the whole rom.
memcpy(m_mainrom->base(), &m_encrypted_copy[0], m_mainrom->bytes());
if (m_has_decrypted_kov3_module)
{
decrypt_kov3_module(module_key->addr_xor, module_key->data_xor);
}
if (m_has_decrypted)
{
igs036_decryptor decrypter(m_encryption_table);
if (m_romboard_ram)
{
decrypter.decrypter_rom((u16*)m_mainrom->base(), m_mainrom->bytes(), m_romboard_ram.bytes());
}
else
{
decrypter.decrypter_rom((u16*)m_mainrom->base(), m_mainrom->bytes(), 0);
}
}
}
WRITE32_MEMBER(pgm2_state::encryption_do_w)
{
igs036_decryptor decrypter(m_encryption_table);
if (m_romboard_ram)
{
decrypter.decrypter_rom((u16*)&m_romboard_ram[0], m_romboard_ram.bytes(), 0);
decrypter.decrypter_rom((u16*)m_mainrom->base(), m_mainrom->bytes(), m_romboard_ram.bytes()); // assume the rom at 0x0200000 also gets decrypted as if it was at 0x0200000 even if it isn't used (the game has already copied it to RAM where it properly decrypted)
}
else
{
decrypter.decrypter_rom((u16*)m_mainrom->base(), m_mainrom->bytes(), 0);
}
m_has_decrypted = true;
}
WRITE16_MEMBER(pgm2_state::share_bank_w)
{
COMBINE_DATA(&m_share_bank);
}
READ8_MEMBER(pgm2_state::shareram_r)
{
return m_shareram[offset + (m_share_bank & 1) * 128];
}
WRITE8_MEMBER(pgm2_state::shareram_w)
{
m_shareram[offset + (m_share_bank & 1) * 128] = data;
}
TIMER_DEVICE_CALLBACK_MEMBER(pgm2_state::mcu_interrupt)
{
m_arm_aic->set_irq(3, ASSERT_LINE);
}
// "MPU" MCU HLE starts here
// command delays are far from correct, might not work in other games
// command results probably incorrect (except for explicit checked bytes)
void pgm2_state::mcu_command(bool is_command)
{
u8 const cmd = m_mcu_regs[0] & 0xff;
// if (is_command && cmd != 0xf6)
// logerror("MCU command %08x %08x\n", m_mcu_regs[0], m_mcu_regs[1]);
if (is_command)
{
m_mcu_last_cmd = cmd;
u8 status = 0xf7; // "command accepted" status
int delay = 1;
u8 arg1 = m_mcu_regs[0] >> 8;
u8 arg2 = m_mcu_regs[0] >> 16;
u8 arg3 = m_mcu_regs[0] >> 24;
switch (cmd)
{
case 0xf6: // get result
m_mcu_regs[3] = m_mcu_result0;
m_mcu_regs[4] = m_mcu_result1;
m_mcu_last_cmd = 0;
break;
case 0xe0: // command port test
m_mcu_result0 = m_mcu_regs[0];
m_mcu_result1 = m_mcu_regs[1];
break;
case 0xe1: // shared RAM access (unimplemented)
{
// MCU access to RAM shared at 0x30100000, 2x banks, in the same time CPU and MCU access different banks
u8 mode = m_mcu_regs[0] >> 16; // 0 - ???, 1 - read, 2 - write
u8 data = m_mcu_regs[0] >> 24;
if (mode == 2)
{
// where is offset ? so far assume this command fill whole page
memset(&m_shareram[(~m_share_bank & 1) * 128], data, 128);
}
m_mcu_result0 = cmd;
m_mcu_result1 = 0;
}
break;
// C0-C9 commands is IC Card RW comms
case 0xc0: // insert card or/and check card presence. result: F7 - ok, F4 - no card
if (m_memcard[arg1 & 3]->present() == -1)
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc1: // check ready/busy ?
if (m_memcard[arg1 & 3]->present() == -1)
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc2: // read data to shared RAM
for (int i = 0; i < arg3; i++)
{
if (m_memcard[arg1 & 3]->present() != -1)
m_shareram[i + (~m_share_bank & 1) * 128] = m_memcard[arg1 & 3]->read(arg2 + i);
else
status = 0xf4;
}
m_mcu_result0 = cmd;
break;
case 0xc3: // save data from shared RAM
for (int i = 0; i < arg3; i++)
{
if (m_memcard[arg1 & 3]->present() != -1)
m_memcard[arg1 & 3]->write(arg2 + i, m_shareram[i + (~m_share_bank & 1) * 128]);
else
status = 0xf4;
}
m_mcu_result0 = cmd;
break;
case 0xc4: // presumable read security mem (password only?)
if (m_memcard[arg1 & 3]->present() != -1)
{
m_mcu_result1 = m_memcard[arg1 & 3]->read_sec(1) |
(m_memcard[arg1 & 3]->read_sec(2) << 8) |
(m_memcard[arg1 & 3]->read_sec(3) << 16);
}
else
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc5: // write security mem
if (m_memcard[arg1 & 3]->present() != -1)
m_memcard[arg1 & 3]->write_sec(arg2 & 3, arg3);
else
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc6: // presumable write protection mem
if (m_memcard[arg1 & 3]->present() != -1)
m_memcard[arg1 & 3]->write_prot(arg2 & 3, arg3);
else
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc7: // read protection mem
if (m_memcard[arg1 & 3]->present() != -1)
{
m_mcu_result1 = m_memcard[arg1 & 3]->read_prot(0) |
(m_memcard[arg1 & 3]->read_prot(1) << 8) |
(m_memcard[arg1 & 3]->read_prot(2) << 16) |
(m_memcard[arg1 & 3]->read_prot(3) << 24);
}
else
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc8: // write data mem
if (m_memcard[arg1 & 3]->present() != -1)
m_memcard[arg1 & 3]->write(arg2, arg3);
else
status = 0xf4;
m_mcu_result0 = cmd;
break;
case 0xc9: // card authentication
if (m_memcard[arg1 & 3]->present() != -1)
m_memcard[arg1 & 3]->auth(arg2, arg3, m_mcu_regs[1] & 0xff);
else
status = 0xf4;
m_mcu_result0 = cmd;
break;
default:
logerror("MCU unknown command %08x %08x\n", m_mcu_regs[0], m_mcu_regs[1]);
status = 0xf4; // error
break;
}
m_mcu_regs[3] = (m_mcu_regs[3] & 0xff00ffff) | (status << 16);
m_mcu_timer->adjust(attotime::from_msec(delay));
}
else // next step
{
if (m_mcu_last_cmd)
{
m_mcu_regs[3] = (m_mcu_regs[3] & 0xff00ffff) | 0x00F20000; // set "command done and return data" status
m_mcu_timer->adjust(attotime::from_usec(100));
m_mcu_last_cmd = 0;
}
}
}
READ32_MEMBER(pgm2_state::mcu_r)
{
return m_mcu_regs[(offset >> 15) & 7];
}
WRITE32_MEMBER(pgm2_state::mcu_w)
{
int reg = (offset >> 15) & 7;
COMBINE_DATA(&m_mcu_regs[reg]);
if (reg == 2 && m_mcu_regs[2]) // irq to mcu
mcu_command(true);
if (reg == 5 && m_mcu_regs[5]) // ack to mcu (written at the end of irq handler routine)
{
mcu_command(false);
m_arm_aic->set_irq(3, CLEAR_LINE);
}
}
WRITE16_MEMBER(pgm2_state::vbl_ack_w)
{
m_arm_aic->set_irq(12, CLEAR_LINE);
}
WRITE16_MEMBER(pgm2_state::unk30120014_w)
{
if (offset == 0)
{
// 0/1 toggles (maybe sprite dma triggers?)
}
else
{
// interesting data
//logerror("unk30120014_w %d %04x\n", offset, data);
}
}
/*
KOV3 ROM board uses special module intead of program ROM, tiny PCB with IC stamped "HW1" (might be FPGA, CPLD or ASIC) and BGA Flash ROM stamped "IG-L".
This module uses few pins for serial comms (wired to IGS036 GPIO), it can not be dumped as regular ROM until special unlock procedure (return weird data pattern while locked).
In case of KOV3 unlock sequence is:
1) send via serial 0x0d and 64bit xor_value, result must be A3A3A3A36D6D6D6D
2) send via serial 0x25 and 64bit xor_value, result is 64bit key^xor_value
3) read first 10h bytes from ROM area (at this point ROM area read as scrambled or random data)
4) write "key" to ROM area, using 2x 16bit writes, offsets and data is bitfields of 64bit key:
u32 key0, key1;
u16 *rom = (u16*)0x10000000;
rom[((key0 & 0x3f) << 16) | (key1 >> 16)] = key1 & 0xffff;
rom[key0 >> 22] = (key0 >> 6) & 0xffff;
it is possible, 22bit address xor value derived from 1st write offset.
meaning of other 10bit offset and 2x data words is not clear - each of them can be either "key bits" or "magic word" expected by security device.
5) write static sequence of 4x words to ROM area, which switch module to special mode - next 4x reads will return checksum^key parts instead of rom data.
6) read checksum from ROM area 10000002-10000009
7) read first 10h bytes from ROM area and check they are not same as was at step 3)
8) perform whole ROM summing, result must match key^checksum read at step 6)
It is not clear if/how real address/data xor values derived from written "key",
or security chip just waiting to be be written magic value at specific address in ROM area, and if this happen enable descrambling using hardcoded values.
*/
int pgm2_state::module_data_r()
{
return module_out_latch ? ASSERT_LINE : CLEAR_LINE;
}
void pgm2_state::module_data_w(int state)
{
module_in_latch = (state == ASSERT_LINE) ? 1 : 0;
}
void pgm2_state::module_clk_w(int state)
{
if (module_prev_state != state && state == CLEAR_LINE)
{
if (module_clk_cnt < 80)
{
s8 const offs = module_clk_cnt / 8;
u8 const bit = (module_clk_cnt & 7) ^ 7;
module_rcv_buf[offs] &= ~(1 << bit);
module_rcv_buf[offs] |= module_in_latch << bit;
++module_clk_cnt;
if (module_clk_cnt >= 80)
{
switch (module_rcv_buf[0])
{
case 0x0d: // init or status check
module_send_buf[0] = module_send_buf[1] = module_send_buf[2] = module_send_buf[3] = 0xa3;
module_send_buf[4] = module_send_buf[5] = module_send_buf[6] = module_send_buf[7] = 0x6d;
break;
case 0x25: // get key
for (int i = 0; i < 8; i++)
module_send_buf[i] = module_key->key[i ^ 3] ^ module_rcv_buf[i + 1];
break;
default:
logerror("unknown FPGA command %02X!\n", module_rcv_buf[0]);
break;
}
module_send_buf[8] = 0;
for (int i = 0; i < 8; i++) // sum reply bytes
module_send_buf[8] += module_send_buf[i];
}
}
else
{
s8 const offs = (module_clk_cnt - 80) / 8;
u8 const bit = (module_clk_cnt & 7) ^ 7;
module_out_latch = BIT(module_send_buf[offs], bit);
++module_clk_cnt;
if (module_clk_cnt >= 152)
module_clk_cnt = 0;
}
}
module_prev_state = state;
}
READ16_MEMBER(pgm2_state::module_rom_r)
{
if (module_sum_read && offset > 0 && offset < 5) // checksum read mode
{
if (offset == 4)
module_sum_read = false;
u32 const offs = ((offset - 1) * 2) ^ 2;
return (module_key->sum[offs] ^ module_key->key[offs]) | ((module_key->sum[offs + 1] ^ module_key->key[offs + 1]) << 8);
}
return ((u16 *)m_mainrom->base())[offset];
}
WRITE16_MEMBER(pgm2_state::module_rom_w)
{
//logerror("module write %04X at %08X\n", data, offset);
u32 const dec_val = ((module_key->key[0] | (module_key->key[1] << 8) | (module_key->key[2] << 16)) >> 6) & 0xffff;
if (data == dec_val)
{
// might be wrong and normal data access enabled only after whole sequence complete
decrypt_kov3_module(module_key->addr_xor, module_key->data_xor);
}
else
switch (data)
{
// following might be wrong, and trigger is address or both
case 0x00c2: // checksum read mode enable, step 1 and 4
module_sum_read = true;
if (offset != 0xe5a7 && offset != 0xa521)
popmessage("module write %04X at %08X\n", data, offset);
break;
case 0x0084: // checksum read mode enable, step 2 and 3
if (offset != 0x5e7a && offset != 0x5a12)
popmessage("module write %04X at %08X\n", data, offset);
break;
default:
logerror("module write %04X at %08X\n", data, offset);
break;
}
}
// very primitive Atmel ARM PIO simulation, should be improved and devicified
WRITE32_MEMBER(pgm2_state::pio_sodr_w)
{
m_pio_out_data |= data & mem_mask;
module_data_w((m_pio_out_data & 0x100) ? ASSERT_LINE : CLEAR_LINE);
module_clk_w((m_pio_out_data & 0x200) ? ASSERT_LINE : CLEAR_LINE);
}
WRITE32_MEMBER(pgm2_state::pio_codr_w)
{
m_pio_out_data &= ~(data & mem_mask);
module_data_w((m_pio_out_data & 0x100) ? ASSERT_LINE : CLEAR_LINE);
module_clk_w((m_pio_out_data & 0x200) ? ASSERT_LINE : CLEAR_LINE);
}
READ32_MEMBER(pgm2_state::pio_pdsr_r)
{
return (module_data_r() == ASSERT_LINE ? 1 : 0) << 8; // fpga data read and status (bit 7, must be 0)
}
void pgm2_state::pgm2_map(address_map &map)
{
map(0x00000000, 0x00003fff).rom(); //AM_REGION("mainrom", 0x00000) // internal ROM
map(0x02000000, 0x0200ffff).ram().share("sram"); // 'battery RAM' (in CPU?)
map(0x03600000, 0x036bffff).rw(FUNC(pgm2_state::mcu_r), FUNC(pgm2_state::mcu_w));
map(0x03900000, 0x03900003).portr("INPUTS0");
map(0x03a00000, 0x03a00003).portr("INPUTS1");
map(0x20000000, 0x2007ffff).ram().share("mainram");
map(0x30000000, 0x30001fff).ram().share("sp_videoram"); // spriteram ('move' RAM in test mode)
map(0x30020000, 0x30021fff).ram().w(FUNC(pgm2_state::bg_videoram_w)).share("bg_videoram");
map(0x30040000, 0x30045fff).ram().w(FUNC(pgm2_state::fg_videoram_w)).share("fg_videoram");
map(0x30060000, 0x30063fff).ram().w(m_sp_palette, FUNC(palette_device::write32)).share("sp_palette");
map(0x30080000, 0x30081fff).ram().w(m_bg_palette, FUNC(palette_device::write32)).share("bg_palette");
map(0x300a0000, 0x300a07ff).ram().w(m_tx_palette, FUNC(palette_device::write32)).share("tx_palette");
map(0x300c0000, 0x300c01ff).ram().share("sp_zoom"); // sprite zoom table - it uploads the same data 4x, maybe xshrink,xgrow,yshrink,ygrow or just redundant mirrors
/* linescroll RAM - it clears to 0x3bf on startup which is enough bytes for 240 lines if each rowscroll value was 8 bytes, but each row is 4,
so only half of this is used? or tx can do it too (unlikely, as orl2 writes 256 lines of data) maybe just bad mem check bounds on orleg2.
It reports pass even if it fails the first byte but if the first byte passes it attempts to test 0x10000 bytes, which is far too big so
what is the real size? */
map(0x300e0000, 0x300e03ff).ram().share("lineram").mirror(0x000fc00);
map(0x30100000, 0x301000ff).rw(FUNC(pgm2_state::shareram_r), FUNC(pgm2_state::shareram_w)).umask32(0x00ff00ff);
map(0x30120000, 0x30120003).ram().share("bgscroll"); // scroll
map(0x30120008, 0x3012000b).ram().share("fgscroll");
map(0x3012000c, 0x3012000f).ram().share("vidmode");
map(0x30120014, 0x30120017).w(FUNC(pgm2_state::unk30120014_w));
map(0x30120018, 0x30120019).w(FUNC(pgm2_state::vbl_ack_w));
map(0x30120032, 0x30120033).w(FUNC(pgm2_state::share_bank_w));
map(0x30120038, 0x3012003b).w(FUNC(pgm2_state::sprite_encryption_w));
// there are other 0x301200xx regs
map(0x40000000, 0x40000003).r("ymz774", FUNC(ymz774_device::read)).w("ymz774", FUNC(ymz774_device::write));
// internal IGS036 - most of them is standard ATMEL peripherals followed by custom bits
// AM_RANGE(0xfffa0000, 0xfffa00ff) TC (Timer Counter) not used, mentioned in disabled / unused code
// AM_RANGE(0xffffec00, 0xffffec7f) SMC (Static Memory Controller)
// AM_RANGE(0xffffee00, 0xffffee57) MATRIX (Bus Matrix)
map(0xfffff000, 0xfffff14b).m(m_arm_aic, FUNC(arm_aic_device::regs_map));
// AM_RANGE(0xfffff200, 0xfffff247) DBGU (Debug Unit)
// AM_RANGE(0xfffff400, 0xfffff4af) PIO (Parallel Input Output Controller)
map(0xfffff430, 0xfffff437).nopw(); // often
// AM_RANGE(0xfffffd00, 0xfffffd0b) RSTC (Reset Controller)
// AM_RANGE(0xfffffd20, 0xfffffd2f) RTTC (Real Time Timer)
map(0xfffffd28, 0xfffffd2b).r(FUNC(pgm2_state::rtc_r));
// AM_RANGE(0xfffffd40, 0xfffffd4b) WDTC (Watch Dog Timer)
// custom IGS036 stuff starts here
map(0xfffffa08, 0xfffffa0b).w(FUNC(pgm2_state::encryption_do_w)); // after uploading encryption? table might actually send it or enable external ROM? when read bits0-1 called FUSE 0 and 1, must be 0
map(0xfffffa0c, 0xfffffa0f).r(FUNC(pgm2_state::unk_startup_r)); // written 0, then 0x1c, then expected to return (result&0x180)==0x180, then written 0x7c
map(0xfffffc00, 0xfffffcff).rw(FUNC(pgm2_state::encryption_r), FUNC(pgm2_state::encryption_w));
}
void pgm2_state::pgm2_rom_map(address_map &map)
{
pgm2_map(map);
map(0x10000000, 0x10ffffff).rom().region("mainrom", 0); // external ROM
}
void pgm2_state::pgm2_ram_rom_map(address_map &map)
{
pgm2_map(map);
map(0x10000000, 0x101fffff).ram().share("romboard_ram"); // we should also probably decrypt writes once the encryption is enabled, but the game never writes with it turned on anyway
map(0x10200000, 0x103fffff).rom().region("mainrom", 0); // external ROM
}
void pgm2_state::pgm2_module_rom_map(address_map &map)
{
pgm2_rom_map(map);
map(0x10000000, 0x107fffff).w(FUNC(pgm2_state::module_rom_w));
map(0x10000000, 0x1000000f).r(FUNC(pgm2_state::module_rom_r));
map(0xfffff430, 0xfffff433).w(FUNC(pgm2_state::pio_sodr_w));
map(0xfffff434, 0xfffff437).w(FUNC(pgm2_state::pio_codr_w));
map(0xfffff43c, 0xfffff43f).r(FUNC(pgm2_state::pio_pdsr_r));
}
static INPUT_PORTS_START( pgm2 )
PORT_START("INPUTS0")
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
PORT_BIT( 0x00000800, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
PORT_BIT( 0x00001000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
PORT_BIT( 0x00002000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
PORT_BIT( 0x00004000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x00008000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)
PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3)
PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3)
PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3)
PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3)
PORT_BIT( 0x01000000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
PORT_BIT( 0x02000000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
PORT_BIT( 0x04000000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3)
PORT_BIT( 0x08000000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(3)
PORT_BIT( 0x10000000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x20000000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x40000000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x80000000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("INPUTS1")
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4)
PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4)
PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4)
PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4)
PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4)
PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4)
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(4)
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x00000800, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x00001000, IP_ACTIVE_LOW, IPT_START3 )
PORT_BIT( 0x00002000, IP_ACTIVE_LOW, IPT_START4 )
PORT_BIT( 0x00004000, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x00008000, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_COIN3 )
PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_COIN4 )
PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Test Key P1 & P2") // test key p1+p2
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_SERVICE2 ) PORT_NAME("Test Key P3 & P4") // test key p3+p4
PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_SERVICE3 ) PORT_NAME("Service P1 & P2") // service key p1+p2
PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_SERVICE4 ) PORT_NAME("Service P3 & P4") // service key p3+p4
PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_SERVICE( 0x01000000, IP_ACTIVE_LOW ) PORT_DIPLOCATION("SW1:1")
PORT_DIPNAME( 0x02000000, 0x02000000, "Music" ) PORT_DIPLOCATION("SW1:2")
PORT_DIPSETTING( 0x00000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x02000000, DEF_STR( On ) )
PORT_DIPNAME( 0x04000000, 0x04000000, "Voice" ) PORT_DIPLOCATION("SW1:3")
PORT_DIPSETTING( 0x00000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x04000000, DEF_STR( On ) )
PORT_DIPNAME( 0x08000000, 0x08000000, "Free" ) PORT_DIPLOCATION("SW1:4")
PORT_DIPSETTING( 0x08000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00000000, DEF_STR( On ) )
PORT_DIPNAME( 0x10000000, 0x10000000, "Stop" ) PORT_DIPLOCATION("SW1:5")
PORT_DIPSETTING( 0x10000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00000000, DEF_STR( On ) )
PORT_DIPNAME( 0x20000000, 0x20000000, DEF_STR( Unused ) ) PORT_DIPLOCATION("SW1:6")
PORT_DIPSETTING( 0x20000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00000000, DEF_STR( On ) )
PORT_DIPNAME( 0x40000000, 0x40000000, DEF_STR( Unused ) ) PORT_DIPLOCATION("SW1:7")
PORT_DIPSETTING( 0x40000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00000000, DEF_STR( On ) )
PORT_DIPNAME( 0x80000000, 0x80000000, "Debug" ) PORT_DIPLOCATION("SW1:8")
PORT_DIPSETTING( 0x80000000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00000000, DEF_STR( On ) )
INPUT_PORTS_END
WRITE_LINE_MEMBER(pgm2_state::irq)
{
// logerror("irq\n");
if (state == ASSERT_LINE) m_maincpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE);
else m_maincpu->set_input_line(ARM7_IRQ_LINE, CLEAR_LINE);
}
void pgm2_state::machine_start()
{
save_item(NAME(m_encryption_table));
save_item(NAME(m_has_decrypted));
save_item(NAME(m_has_decrypted_kov3_module));
save_item(NAME(m_spritekey));
save_item(NAME(m_realspritekey));
save_item(NAME(m_mcu_regs));
save_item(NAME(m_mcu_result0));
save_item(NAME(m_mcu_result1));
save_item(NAME(m_mcu_last_cmd));
save_item(NAME(m_shareram));
save_item(NAME(m_share_bank));
save_item(NAME(m_pio_out_data));
save_item(NAME(module_in_latch));
save_item(NAME(module_sum_read));
save_item(NAME(module_out_latch));
save_item(NAME(module_prev_state));
save_item(NAME(module_clk_cnt));
save_item(NAME(module_rcv_buf));
save_item(NAME(module_send_buf));
}
void pgm2_state::machine_reset()
{
m_spritekey = 0;
m_realspritekey = 0;
m_mcu_last_cmd = 0;
m_share_bank = 0;
// as the decryption is dynamic controlled by the program, restore the encrypted copy
memcpy(m_mainrom->base(), &m_encrypted_copy[0], m_mainrom->bytes());
m_has_decrypted = false;
m_has_decrypted_kov3_module = false;
m_pio_out_data = 0;
module_prev_state = 0;
module_sum_read = false;
module_clk_cnt = 151; // this needed because of "false" clock pulse happen during gpio init
}
static const gfx_layout tiles8x8_layout =
{
8,8,
RGN_FRAC(1,1),
4,
{ STEP4(0,1) },
{ 4, 0, 12, 8, 20, 16, 28, 24 },
{ STEP8(0,4*8) },
32*8
};
static const gfx_layout tiles32x32x8_layout =
{
32,32,
RGN_FRAC(1,1),
7,
{ 1, 2, 3, 4, 5, 6, 7 },
{ STEP32(0,8) },
{ STEP32(0,8*32) },
256*32
};
static GFXDECODE_START( pgm2_tx )
GFXDECODE_ENTRY( "tiles", 0, tiles8x8_layout, 0, 0x800/4/0x10 )
GFXDECODE_END
static GFXDECODE_START( pgm2_bg )
GFXDECODE_ENTRY( "bgtile", 0, tiles32x32x8_layout, 0, 0x2000/4/0x80 )
GFXDECODE_END
void pgm2_state::pgm2(machine_config &config)
{
/* basic machine hardware */
IGS036(config, m_maincpu, 100000000); // Unknown clock / divider
m_maincpu->set_addrmap(AS_PROGRAM, &pgm2_state::pgm2_rom_map);
TIMER(config, m_mcu_timer, 0).configure_generic(timer_device::expired_delegate(FUNC(pgm2_state::mcu_interrupt), this));
ARM_AIC(config, m_arm_aic, 0).irq_callback().set(FUNC(pgm2_state::irq));
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh(HZ_TO_ATTOSECONDS(60));
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0));
m_screen->set_size(64*8, 32*8);
m_screen->set_visarea(0, 448-1, 0, 224-1);
m_screen->set_screen_update(FUNC(pgm2_state::screen_update));
m_screen->screen_vblank().set(FUNC(pgm2_state::screen_vblank));
GFXDECODE(config, m_gfxdecode2, m_tx_palette, pgm2_tx);
GFXDECODE(config, m_gfxdecode3, m_bg_palette, pgm2_bg);
PALETTE(config, m_sp_palette).set_format(palette_device::xRGB_888, 0x4000 / 4); // sprites
PALETTE(config, m_tx_palette).set_format(palette_device::xRGB_888, 0x800 / 4); // text
PALETTE(config, m_bg_palette).set_format(palette_device::xRGB_888, 0x2000 / 4); // bg
NVRAM(config, "sram", nvram_device::DEFAULT_ALL_0);
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
ymz774_device &ymz774(YMZ774(config, "ymz774", 16384000)); // is clock correct ?
ymz774.add_route(0, "lspeaker", 1.0);
ymz774.add_route(1, "rspeaker", 1.0);
PGM2_MEMCARD(config, m_memcard[0], 0);
PGM2_MEMCARD(config, m_memcard[1], 0);
PGM2_MEMCARD(config, m_memcard[2], 0);
PGM2_MEMCARD(config, m_memcard[3], 0);
}
// not strictly needed as the video code supports changing on the fly, but makes recording easier etc.
void pgm2_state::pgm2_lores(machine_config &config)
{
pgm2(config);
m_screen->set_visarea(0, 320-1, 0, 240-1);
}
void pgm2_state::pgm2_hires(machine_config &config)
{
pgm2(config);
m_maincpu->set_addrmap(AS_PROGRAM, &pgm2_state::pgm2_module_rom_map);
m_screen->set_visarea(0, 512-1, 0, 240-1);
}
void pgm2_state::pgm2_ramrom(machine_config &config)
{
pgm2(config);
m_maincpu->set_addrmap(AS_PROGRAM, &pgm2_state::pgm2_ram_rom_map);
}
/* using macros for the video / sound roms because the locations never change between sets, and
we're going to have a LOT of clones to cover all the internal rom regions and external rom revision
combinations, so it keeps things readable */
// Oriental Legend 2
#define ORLEG2_VIDEO_SOUND_ROMS \
ROM_REGION( 0x200000, "tiles", ROMREGION_ERASE00 ) \
ROM_LOAD( "ig-a_text.u4", 0x00000000, 0x0200000, CRC(fa444c32) SHA1(31e5e3efa92d52bf9ab97a0ece51e3b77f52ce8a) ) \
\
ROM_REGION( 0x1000000, "bgtile", 0 ) \
ROM_LOAD32_WORD( "ig-a_bgl.u35", 0x00000000, 0x0800000, CRC(083a8315) SHA1(0dba25e132fbb12faa59ced648c27b881dc73478) ) \
ROM_LOAD32_WORD( "ig-a_bgh.u36", 0x00000002, 0x0800000, CRC(e197221d) SHA1(5574b1e3da4b202db725be906dd868edc2fd4634) ) \
\
ROM_REGION( 0x2000000, "sprites_mask", 0 ) /* 1bpp sprite mask data (packed) */ \
ROM_LOAD32_WORD( "ig-a_bml.u12", 0x00000000, 0x1000000, CRC(113a331c) SHA1(ee6b31bb2b052cc8799573de0d2f0a83f0ab4f6a) ) \
ROM_LOAD32_WORD( "ig-a_bmh.u16", 0x00000002, 0x1000000, CRC(fbf411c8) SHA1(5089b5cc9bbf6496ef1367c6255e63e9ab895117) ) \
\
ROM_REGION( 0x4000000, "sprites_colour", 0 ) /* sprite colour data (6bpp data, 2 bits unused except for 4 bytes that are randomly 0xff - check dump?) */ \
ROM_LOAD32_WORD( "ig-a_cgl.u18", 0x00000000, 0x2000000, CRC(43501fa6) SHA1(58ccce6d393964b771fec3f5c583e3ede57482a3) ) \
ROM_LOAD32_WORD( "ig-a_cgh.u26", 0x00000002, 0x2000000, CRC(7051d020) SHA1(3d9b24c6fda4c9699bb9f00742e0888059b623e1) ) \
\
ROM_REGION( 0x1000000, "ymz774", ROMREGION_ERASEFF ) /* ymz774 */ \
ROM_LOAD16_WORD_SWAP( "ig-a_sp.u2", 0x00000000, 0x1000000, CRC(8250688c) SHA1(d2488477afc528aeee96826065deba2bce4f0a7d) ) \
\
ROM_REGION( 0x10000, "sram", 0 ) \
ROM_LOAD( "xyj2_nvram", 0x00000000, 0x10000, CRC(ccccc71c) SHA1(585b5ccbf89dd28d8532da785d7c8af12f31c6d6) )
/*
External program revisions are CONFIRMED to be the same between regions, even if the label changes (localized game title + country specific extension code)
Confirmed country codes used on labels
FA = Oversea
CN = China
JP = Japan
TW = Taiwan
*/
#define ORLEG2_PROGRAM_104(prefix, extension) \
ROM_REGION( 0x1000000, "mainrom", 0 ) \
ROM_LOAD( #prefix "_v104" #extension ".u7", 0x000000, 0x800000, CRC(7c24a4f5) SHA1(3cd9f9264ef2aad0869afdf096e88eb8d74b2570) ) // V104 08-03-03 13:25:37
#define ORLEG2_PROGRAM_103(prefix, extension) \
ROM_REGION( 0x1000000, "mainrom", 0 ) \
ROM_LOAD( #prefix "_v103" #extension ".u7", 0x000000, 0x800000, CRC(21c1fae8) SHA1(36eeb7a5e8dc8ee7c834f3ff1173c28cf6c2f1a3) ) // V103 08-01-30 14:45:17
#define ORLEG2_PROGRAM_101(prefix, extension) \
ROM_REGION( 0x1000000, "mainrom", 0 ) \
ROM_LOAD( #prefix "_v101" #extension ".u7", 0x000000, 0x800000, CRC(45805b53) SHA1(f2a8399c821b75fadc53e914f6f318707e70787c) ) // V101 07-12-24 09:32:32
/*
Internal ROMs for CHINA, JAPAN and OVERSEA are confirmed to differ by just the region byte, other regions not yet verified.
label is a localized version of the game title and the country code (see above)
For OVERSEA this is "O/L2", but we omit the / due to naming rules
For the CHINA version this uses the Chinese characters
*/
#define ORLEG2_INTERNAL_CHINA \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "xyj2_cn.igs036", 0x00000000, 0x0004000, CRC(bcce7641) SHA1(c3b5cf6e9f6eae09b6785314777a52b34c3c7657) ) /* Core V100 China */ \
ROM_REGION( 0x108, "default_card", 0 ) \
ROM_LOAD( "blank_orleg2_china_card.pg2", 0x000, 0x108, CRC(dc29556f) SHA1(2335cc7af25d4dd9763c6944d3f0eb50276de80a) )
#define ORLEG2_INTERNAL_OVERSEAS \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "ol2_fa.igs036", 0x00000000, 0x0004000, CRC(cc4d398a) SHA1(c50bcc81f02cd5aa8ad157d73209dc53bdedc023) ) // Core V100 Oversea
#define ORLEG2_INTERNAL_JAPAN \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "ol2_a10.igs036", 0x00000000, 0x0004000, CRC(69375284) SHA1(a120c6a3d8d7898cc3ca508abea78e5e54090c66) ) // Core V100 Japan
ROM_START( orleg2 )
ORLEG2_INTERNAL_OVERSEAS
ORLEG2_PROGRAM_104(ol2,fa)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_103 )
ORLEG2_INTERNAL_OVERSEAS
ORLEG2_PROGRAM_103(ol2,fa)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_101 )
ORLEG2_INTERNAL_OVERSEAS
ORLEG2_PROGRAM_101(ol2,fa)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_104cn )
ORLEG2_INTERNAL_CHINA
ORLEG2_PROGRAM_104(xyj2,cn)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_103cn )
ORLEG2_INTERNAL_CHINA
ORLEG2_PROGRAM_103(xyj2,cn)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_101cn )
ORLEG2_INTERNAL_CHINA
ORLEG2_PROGRAM_101(xyj2,cn)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_104jp )
ORLEG2_INTERNAL_JAPAN
ORLEG2_PROGRAM_104(ol2,a10)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_103jp )
ORLEG2_INTERNAL_JAPAN
ORLEG2_PROGRAM_103(ol2,a10)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
ROM_START( orleg2_101jp )
ORLEG2_INTERNAL_JAPAN
ORLEG2_PROGRAM_101(ol2,a10)
ORLEG2_VIDEO_SOUND_ROMS
ROM_END
// Knights of Valour 2 New Legend
#define KOV2NL_VIDEO_SOUND_ROMS \
ROM_REGION( 0x200000, "tiles", ROMREGION_ERASE00 ) \
ROM_LOAD( "ig-a3_text.u4", 0x00000000, 0x0200000, CRC(214530ff) SHA1(4231a02054b0345392a077042b95779fd45d6c22) ) \
\
ROM_REGION( 0x1000000, "bgtile", 0 ) \
ROM_LOAD32_WORD( "ig-a3_bgl.u35", 0x00000000, 0x0800000, CRC(2d46b1f6) SHA1(ea8c805eda6292e86a642e9633d8fee7054d10b1) ) \
ROM_LOAD32_WORD( "ig-a3_bgh.u36", 0x00000002, 0x0800000, CRC(df710c36) SHA1(f826c3f496c4f17b46d18af1d8e02cac7b7027ac) ) \
\
ROM_REGION( 0x2000000, "sprites_mask", 0 ) /* 1bpp sprite mask data */ \
ROM_LOAD32_WORD( "ig-a3_bml.u12", 0x00000000, 0x1000000, CRC(0bf63836) SHA1(b8e4f1951f8074b475b795bd7840c5a375b6f5ef) ) \
ROM_LOAD32_WORD( "ig-a3_bmh.u16", 0x00000002, 0x1000000, CRC(4a378542) SHA1(5d06a8a8796285a786ebb690c34610f923ef5570) ) \
\
ROM_REGION( 0x4000000, "sprites_colour", 0 ) /* sprite colour data */ \
ROM_LOAD32_WORD( "ig-a3_cgl.u18", 0x00000000, 0x2000000, CRC(8d923e1f) SHA1(14371cf385dd8857017d3111cd4710f4291b1ae2) ) \
ROM_LOAD32_WORD( "ig-a3_cgh.u26", 0x00000002, 0x2000000, CRC(5b6fbf3f) SHA1(d1f52e230b91ee6cde939d7c2b74da7fd6527e73) ) \
\
ROM_REGION( 0x2000000, "ymz774", ROMREGION_ERASEFF ) /* ymz774 */ \
ROM_LOAD16_WORD_SWAP( "ig-a3_sp.u37", 0x00000000, 0x2000000, CRC(45cdf422) SHA1(8005d284bcee73cff37a147fcd1c3e9f039a7203) ) \
\
ROM_REGION(0x10000, "sram", 0) \
ROM_LOAD("gsyx_nvram", 0x00000000, 0x10000, CRC(22400c16) SHA1(f775a16299c30f2ce23d683161b910e06eff37c1) )
#define KOV2NL_PROGRAM_302(prefix, extension) \
ROM_REGION( 0x1000000, "mainrom", 0 ) \
ROM_LOAD( #prefix "_v302" #extension ".u7", 0x00000000, 0x0800000, CRC(b19cf540) SHA1(25da5804bbfd7ef2cdf5cc5aabaa803d18b98929) ) // V302 08-12-03 15:27:34
#define KOV2NL_PROGRAM_301(prefix, extension) \
ROM_REGION( 0x1000000, "mainrom", 0 ) \
ROM_LOAD( #prefix "_v301" #extension ".u7", 0x000000, 0x800000, CRC(c4595c2c) SHA1(09e379556ef76f81a63664f46d3f1415b315f384) ) // V301 08-09-09 09:44:53
#define KOV2NL_PROGRAM_300(prefix, extension) \
ROM_REGION( 0x1000000, "mainrom", 0 ) \
ROM_LOAD( #prefix "_v300" #extension ".u7", 0x000000, 0x800000, CRC(08da7552) SHA1(303b97d7694405474c8133a259303ccb49db48b1) ) // V300 08-08-06 18:21:23
// Region 0x00 - China
#define KOV2NL_INTERNAL_CHINA \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "gsyx_igs036_china.rom", 0x00000000, 0x0004000, CRC(e09fe4ce) SHA1(c0cac64ef8727cbe79d503ec4df66ddb6f2c925e) ) /* Core V100 China */ \
ROM_REGION( 0x108, "default_card", 0 ) \
ROM_LOAD( "blank_gsyx_china.pg2", 0x000, 0x108, CRC(02842ae8) SHA1(a6cda633b09a706039a79b73db2c258094826f85) )
// Region 0x01 - Taiwan CRC(b3ca3124) SHA1(793d3bdc4bfccb892eb51c351c4ccd103ee9b7ce)
// uses cards with CRC(1155f01f) SHA1(60f7bed1461b362a3da687503cd72ed2d5e96f30) (same as Oversea, Korea)
// Region 0x02 - Japan CRC(46344f1a) SHA1(fbe846be4a39e8a4c41417858311faaaebf67cb9)
// uses cards with CRC(0d63cb64) SHA1(957cce2d47f3369bc4f98b1652ba8639c08fb9bd) (unique)
// Region 0x03 - Korea CRC(15619af0) SHA1(619e58e13c4d4351e8a4359a1df1eb9952326e84)
// uses cards with CRC(1155f01f) SHA1(60f7bed1461b362a3da687503cd72ed2d5e96f30) (same as Oversea, Taiwan)
// (incomplete / partial translation, shows Oversea disclaimer and corrupt text on some screens, so likely unreleased or needs newer mainprg)
// Region 0x04 - Hong Kong CRC(76b9b527) SHA1(e77a7b59aca221b5d04dcd1ffc632114be7e5647)
// uses cards with CRC(02842ae8) SHA1(a6cda633b09a706039a79b73db2c258094826f85) (same as China)
// Region 0x05 - Overseas
#define KOV2NL_INTERNAL_OVERSEA \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "kov2nl_igs036_oversea.rom", 0x00000000, 0x0004000, CRC(25ec60cd) SHA1(7dd12d2bc642bfa79520676fe5de458ce7d08ef6) ) /* Core V100 oversea */ \
ROM_REGION( 0x108, "default_card", 0 ) \
ROM_LOAD( "blank_kov2nl_overseas_card.pg2", 0x000, 0x108, CRC(1155f01f) SHA1(60f7bed1461b362a3da687503cd72ed2d5e96f30) )
ROM_START( kov2nl )
KOV2NL_INTERNAL_OVERSEA
KOV2NL_PROGRAM_302(kov2nl, fa)
KOV2NL_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov2nl_301 )
KOV2NL_INTERNAL_OVERSEA
KOV2NL_PROGRAM_301(kov2nl, fa)
KOV2NL_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov2nl_300 )
KOV2NL_INTERNAL_OVERSEA
KOV2NL_PROGRAM_300(kov2nl, fa)
KOV2NL_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov2nl_302cn )
KOV2NL_INTERNAL_CHINA
KOV2NL_PROGRAM_302(gsyx, cn)
KOV2NL_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov2nl_301cn )
KOV2NL_INTERNAL_CHINA
KOV2NL_PROGRAM_301(gsyx, cn)
KOV2NL_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov2nl_300cn )
KOV2NL_INTERNAL_CHINA
KOV2NL_PROGRAM_300(gsyx, cn)
KOV2NL_VIDEO_SOUND_ROMS
ROM_END
// Dodonpachi Daioujou Tamashii
#define DDPDOJT_VIDEO_SOUND_ROMS \
ROM_REGION( 0x200000, "tiles", ROMREGION_ERASE00 ) \
ROM_LOAD( "ddpdoj_text.u1", 0x00000000, 0x0200000, CRC(f18141d1) SHA1(a16e0a76bc926a158bb92dfd35aca749c569ef50) ) \
\
ROM_REGION( 0x2000000, "bgtile", 0 ) \
ROM_LOAD32_WORD( "ddpdoj_bgl.u23", 0x00000000, 0x1000000, CRC(ff65fdab) SHA1(abdd5ca43599a2daa722547a999119123dd9bb28) ) \
ROM_LOAD32_WORD( "ddpdoj_bgh.u24", 0x00000002, 0x1000000, CRC(bb84d2a6) SHA1(a576a729831b5946287fa8f0d923016f43a9bedb) ) \
\
ROM_REGION( 0x1000000, "sprites_mask", 0 ) /* 1bpp sprite mask data */ \
ROM_LOAD32_WORD( "ddpdoj_mapl0.u13", 0x00000000, 0x800000, CRC(bcfbb0fc) SHA1(9ec478eba9905913cf997bd9b46c70c1ad383630) ) \
ROM_LOAD32_WORD( "ddpdoj_maph0.u15", 0x00000002, 0x800000, CRC(0cc75d4e) SHA1(6d1b5ef0fdebf1e84fa199b939ffa07b810b12c9) ) \
\
ROM_REGION( 0x2000000, "sprites_colour", 0 ) /* sprite colour data */ \
ROM_LOAD32_WORD( "ddpdoj_spa0.u9", 0x00000000, 0x1000000, CRC(1232c1b4) SHA1(ecc1c549ae19d2f052a85fe4a993608aedf49a25) ) \
ROM_LOAD32_WORD( "ddpdoj_spb0.u18", 0x00000002, 0x1000000, CRC(6a9e2cbf) SHA1(8e0a4ea90f5ef534820303d62f0873f8ac9f080e) ) \
\
ROM_REGION( 0x1000000, "ymz774", ROMREGION_ERASEFF ) /* ymz774 */ \
ROM_LOAD16_WORD_SWAP( "ddpdoj_wave0.u12", 0x00000000, 0x1000000, CRC(2b71a324) SHA1(f69076cc561f40ca564d804bc7bd455066f8d77c) ) \
\
ROM_REGION( 0x10000, "sram", 0 ) \
ROM_LOAD( "ddpdojt_sram", 0x00000000, 0x10000, CRC(af99e304) SHA1(e44fed22b902431298748eca84533f8685926afd) )
ROM_START( ddpdojt )
ROM_REGION( 0x04000, "maincpu", 0 )
ROM_LOAD( "ddpdoj_igs036_china.rom", 0x00000000, 0x0004000, CRC(5db91464) SHA1(723d8086285805bd815e62120dfa9a4269bcd932) ) // Core V100 China
ROM_REGION( 0x0200000, "mainrom", 0 )
ROM_LOAD( "ddpdoj_v201cn.u4", 0x00000000, 0x0200000, CRC(89e4b760) SHA1(9fad1309da31d12a413731b416a8bbfdb304ed9e) ) // V201 10-03-27 17:45:12
DDPDOJT_VIDEO_SOUND_ROMS
ROM_END
// Knights of Valour 3
/*
The Kov3 Program rom is a module consisting of a NOR flash and a FPGA, this provides an extra layer of encryption on top of the usual
that is only unlocked when the correct sequence is recieved from the ARM MCU (IGS036)
Newer gambling games use the same modules.
*/
#define KOV3_VIDEO_SOUND_ROMS \
ROM_REGION( 0x200000, "tiles", ROMREGION_ERASE00 ) \
ROM_LOAD( "kov3_text.u1", 0x00000000, 0x0200000, CRC(198b52d6) SHA1(e4502abe7ba01053d16c02114f0c88a3f52f6f40) ) \
\
ROM_REGION( 0x2000000, "bgtile", 0 ) \
ROM_LOAD32_WORD( "kov3_bgl.u6", 0x00000000, 0x1000000, CRC(49a4c5bc) SHA1(26b7da91067bda196252520e9b4893361c2fc675) ) \
ROM_LOAD32_WORD( "kov3_bgh.u7", 0x00000002, 0x1000000, CRC(adc1aff1) SHA1(b10490f0dbef9905cdb064168c529f0b5a2b28b8) ) \
\
ROM_REGION( 0x4000000, "sprites_mask", 0 ) /* 1bpp sprite mask data */ \
ROM_LOAD32_WORD( "kov3_mapl0.u15", 0x00000000, 0x2000000, CRC(9e569bf7) SHA1(03d26e000e9d8e744546be9649628d2130f2ec4c) ) \
ROM_LOAD32_WORD( "kov3_maph0.u16", 0x00000002, 0x2000000, CRC(6f200ad8) SHA1(cd12c136d4f5d424bd7daeeacd5c4127beb3d565) ) \
\
ROM_REGION( 0x8000000, "sprites_colour", 0 ) /* sprite colour data */ \
ROM_LOAD32_WORD( "kov3_spa0.u17", 0x00000000, 0x4000000, CRC(3a1e58a9) SHA1(6ba251407c69ee62f7ea0baae91bc133acc70c6f) ) \
ROM_LOAD32_WORD( "kov3_spb0.u10", 0x00000002, 0x4000000, CRC(90396065) SHA1(01bf9f69d77a792d5b39afbba70fbfa098e194f1) ) \
\
ROM_REGION( 0x4000000, "ymz774", ROMREGION_ERASEFF ) /* ymz774 */ \
ROM_LOAD16_WORD_SWAP( "kov3_wave0.u13", 0x00000000, 0x4000000, CRC(aa639152) SHA1(2314c6bd05524525a31a2a4668a36a938b924ba4) ) \
\
ROM_REGION( 0x10000, "sram", 0 ) \
ROM_LOAD( "kov3_sram", 0x00000000, 0x10000, CRC(d9608102) SHA1(dec5631642393f4ec76912c81fd60249bb45aa13) )
#define KOV3_INTERNAL_CHINA \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "kov3_igs036_china.rom", 0x00000000, 0x0004000, CRC(c7d33764) SHA1(5cd48f876e637d60391d39ac6e40bf243300cc75) ) /* Core V100 China */ \
ROM_REGION( 0x108, "default_card", 0 ) \
ROM_LOAD( "blank_kov3_china_card.pg2", 0x000, 0x108, CRC(bd5a968f) SHA1(b9045eb70e02afda7810431c592208053d863980) )
ROM_START( kov3 )
KOV3_INTERNAL_CHINA
ROM_REGION( 0x1000000, "mainrom", 0 )
ROM_LOAD( "kov3_v104cn_raw.bin", 0x00000000, 0x0800000, CRC(1b5cbd24) SHA1(6471d4842a08f404420dea2bd1c8b88798c80fd5) ) // V104 11-12-09 14:29:14
KOV3_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov3_102 )
KOV3_INTERNAL_CHINA
ROM_REGION( 0x1000000, "mainrom", 0 )
ROM_LOAD( "kov3_v102cn_raw.bin", 0x00000000, 0x0800000, CRC(61d0dabd) SHA1(959b22ef4e342ca39c2386549ac7274f9d580ab8) ) // V102 11-11-01 18:56:07
KOV3_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov3_101 )
KOV3_INTERNAL_CHINA
ROM_REGION( 0x1000000, "mainrom", 0 )
ROM_LOAD( "kov3_v101.bin", 0x00000000, 0x0800000, BAD_DUMP CRC(d6664449) SHA1(64d912425f018c3531951019b33e909657724547) ) // V101 11-10-03 14:37:29; dump was not raw, manually xored with fake value
KOV3_VIDEO_SOUND_ROMS
ROM_END
ROM_START( kov3_100 )
KOV3_INTERNAL_CHINA
ROM_REGION( 0x1000000, "mainrom", 0 )
ROM_LOAD( "kov3_v100cn_raw.bin", 0x00000000, 0x0800000, CRC(93bca924) SHA1(ecaf2c4676eb3d9f5e4fdbd9388be41e51afa0e4) ) // V100 11-09-14 15:13:14
KOV3_VIDEO_SOUND_ROMS
ROM_END
/* King of Fighters '98: Ultimate Match HERO
device types were as follows
kof98umh_v100cn.u4 SAMSUNG K8Q2815UQB
ig-d3_text.u1 cFeon EN29LV160AB
all others: SPANSION S99-50070
*/
#define KOF98UMH_VIDEO_SOUND_ROMS \
ROM_REGION( 0x200000, "tiles", ROMREGION_ERASE00 ) \
ROM_LOAD( "ig-d3_text.u1", 0x00000000, 0x0200000, CRC(9a0ea82e) SHA1(7844fd7e46c3fbb2164060f160da528254fd177e) ) \
\
ROM_REGION( 0x2000000, "bgtile", ROMREGION_ERASE00 ) \
/* bgl/bgh unpopulated (no background tilemap) */ \
\
ROM_REGION( 0x08000000, "sprites_mask", 0 ) /* 1bpp sprite mask data */ \
ROM_LOAD32_WORD( "ig-d3_mapl0.u13", 0x00000000, 0x4000000, CRC(5571d63e) SHA1(dad73797a35738013d82e3b8ca96fa001ec56f69) ) \
ROM_LOAD32_WORD( "ig-d3_maph0.u15", 0x00000002, 0x4000000, CRC(0da7b1b8) SHA1(87741242bd827eca3788b490df6dcb65f7a89733) ) \
\
ROM_REGION( 0x20000000, "sprites_colour", 0 ) /* sprite colour data - some byte are 0x40 or even 0xff, but verified on 2 boards */ \
ROM_LOAD32_WORD( "ig-d3_spa0.u9", 0x00000000, 0x4000000, CRC(cfef8f7d) SHA1(54f58d1b9eb7d2e4bbe13fbdfd98f5b14ce2086b) ) \
ROM_LOAD32_WORD( "ig-d3_spb0.u18", 0x00000002, 0x4000000, CRC(f199d5c8) SHA1(91f5e8efd1f6a9e5aada51afdf5a8f52bac24185) ) \
/* spa1/spb1 unpopulated */ \
ROM_LOAD32_WORD( "ig-d3_spa2.u10", 0x10000000, 0x4000000, CRC(03bfd35c) SHA1(814998cd5ee01c9da775b73f7a0ba4216fe4970e) ) \
ROM_LOAD32_WORD( "ig-d3_spb2.u20", 0x10000002, 0x4000000, CRC(9aaa840b) SHA1(3c6078d53bb5eca5c501540214287dd102102ea1) ) \
/* spa3/spb3 unpopulated */ \
\
ROM_REGION( 0x08000000, "ymz774", ROMREGION_ERASEFF ) /* ymz774 */ \
ROM_LOAD16_WORD_SWAP( "ig-d3_wave0.u12", 0x00000000, 0x4000000, CRC(edf2332d) SHA1(7e01c7e03e515814d7de117c265c3668d32842fa) ) \
ROM_LOAD16_WORD_SWAP( "ig-d3_wave1.u11", 0x04000000, 0x4000000, CRC(62321b20) SHA1(a388c8a2489430fbe92fb26b3ef81c66ce97f318) ) \
\
ROM_REGION( 0x10000, "sram", 0 ) \
ROM_LOAD( "kof98umh_sram", 0x00000000, 0x10000, CRC(60460ed9) SHA1(55cd8de37cee04ff7ad940fb52f8fb8db042c26e) )
ROM_START( kof98umh )
ROM_REGION( 0x04000, "maincpu", 0 )
ROM_LOAD( "kof98umh_internal_rom.bin", 0x00000000, 0x0004000, CRC(3ed2e50f) SHA1(35310045d375d9dda36c325e35257123a7b5b8c7) ) // Core V100 China
ROM_REGION( 0x1000000, "mainrom", 0 )
ROM_LOAD( "kof98umh_v100cn.u4", 0x00000000, 0x1000000, CRC(2ea91e3b) SHA1(5a586bb99cc4f1b02e0db462d5aff721512e0640) ) // V100 09-08-23 17:52:03
KOF98UMH_VIDEO_SOUND_ROMS
ROM_END
static void iga_u16_decode(u16 *rom, int len, int ixor)
{
int i;
for (i = 1; i < len / 2; i+=2)
{
u16 x = ixor;
if ( (i>>1) & 0x000001) x ^= 0x0010;
if ( (i>>1) & 0x000002) x ^= 0x2004;
if ( (i>>1) & 0x000004) x ^= 0x0801;
if ( (i>>1) & 0x000008) x ^= 0x0300;
if ( (i>>1) & 0x000010) x ^= 0x0080;
if ( (i>>1) & 0x000020) x ^= 0x0020;
if ( (i>>1) & 0x000040) x ^= 0x4008;
if ( (i>>1) & 0x000080) x ^= 0x1002;
if ( (i>>1) & 0x000100) x ^= 0x0400;
if ( (i>>1) & 0x000200) x ^= 0x0040;
if ( (i>>1) & 0x000400) x ^= 0x8000;
rom[i] ^= x;
rom[i] = bitswap<16>(rom[i], 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7);
}
}
static void iga_u12_decode(u16* rom, int len, int ixor)
{
int i;
for (i = 0; i < len / 2; i+=2)
{
u16 x = ixor;
if ( (i>>1) & 0x000001) x ^= 0x9004;
if ( (i>>1) & 0x000002) x ^= 0x0028;
if ( (i>>1) & 0x000004) x ^= 0x0182;
if ( (i>>1) & 0x000008) x ^= 0x0010;
if ( (i>>1) & 0x000010) x ^= 0x2040;
if ( (i>>1) & 0x000020) x ^= 0x0801;
if ( (i>>1) & 0x000040) x ^= 0x0000;
if ( (i>>1) & 0x000080) x ^= 0x0000;
if ( (i>>1) & 0x000100) x ^= 0x4000;
if ( (i>>1) & 0x000200) x ^= 0x0600;
if ( (i>>1) & 0x000400) x ^= 0x0000;
rom[i] ^= x;
rom[i] = bitswap<16>(rom[i], 8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7);
}
}
static void sprite_colour_decode(u16* rom, int len)
{
int i;
for (i = 0; i < len / 2; i++)
{
rom[i] = bitswap<16>(rom[i], 15, 14, /* unused - 6bpp */
13, 12, 11,
5, 4, 3,
7, 6, /* unused - 6bpp */
10, 9, 8,
2, 1, 0 );
}
}
READ32_MEMBER(pgm2_state::orleg2_speedup_r)
{
u32 const pc = m_maincpu->pc();
if ((pc == 0x1002faec) || (pc == 0x1002f9b8))
{
if ((m_mainram[0x20114 / 4] == 0x00) && (m_mainram[0x20118 / 4] == 0x00))
m_maincpu->spin_until_interrupt();
}
/*else
{
logerror("pc is %08x\n", pc);
}*/
return m_mainram[0x20114 / 4];
}
READ32_MEMBER(pgm2_state::kov2nl_speedup_r)
{
u32 const pc = m_maincpu->pc();
if ((pc == 0x10053a94) || (pc == 0x1005332c) || (pc == 0x1005327c))
{
if ((m_mainram[0x20470 / 4] == 0x00) && (m_mainram[0x20474 / 4] == 0x00))
m_maincpu->spin_until_interrupt();
}
/*
else
{
logerror("pc is %08x\n", pc);
}
*/
return m_mainram[0x20470 / 4];
}
READ32_MEMBER(pgm2_state::kof98umh_speedup_r)
{
u32 const pc = m_maincpu->pc();
if (pc == 0x100028f6)
{
if ((m_mainram[0x00060 / 4] == 0x00) && (m_mainram[0x00064 / 4] == 0x00))
m_maincpu->spin_until_interrupt();
}
/*
else
{
logerror("pc is %08x\n", pc);
}
*/
return m_mainram[0x00060 / 4];
}
READ32_MEMBER(pgm2_state::kov3_speedup_r)
{
u32 const pc = m_maincpu->pc();
if ((pc == 0x1000729a) || (pc == 0x1000729e))
{
if ((m_mainram[0x000b4 / 4] == 0x00) && (m_mainram[0x000b8 / 4] == 0x00))
m_maincpu->spin_until_interrupt();
}
/*
else
{
logerror("pc is %08x\n", pc);
}
*/
return m_mainram[0x000b4 / 4];
}
READ32_MEMBER(pgm2_state::ddpdojt_speedup_r)
{
u32 const pc = m_maincpu->pc();
if (pc == 0x10001a7e)
{
if ((m_mainram[0x00060 / 4] == 0x00) && (m_mainram[0x00064 / 4] == 0x00))
m_maincpu->spin_until_interrupt();
}
/*
else
{
logerror("pc is %08x\n", pc);
}
*/
return m_mainram[0x00060 / 4];
}
READ32_MEMBER(pgm2_state::ddpdojt_speedup2_r)
{
u32 const pc = m_maincpu->pc();
if (pc == 0x1008fefe || pc == 0x1008fbe8)
{
if ((m_mainram[0x21e04 / 4] & 0x00ff0000) != 0) // not sure if this endian safe ?
m_maincpu->spin_until_interrupt();
}
/*
else
{
logerror("pc is %08x\n", pc);
}
*/
return m_mainram[0x21e04 / 4];
}
// for games with the internal ROMs fully dumped that provide the sprite key and program rom key at runtime
void pgm2_state::common_encryption_init()
{
// store off a copy of the encrypted rom so we can restore it later when needed
m_encrypted_copy.resize(m_mainrom->bytes());
memcpy(&m_encrypted_copy[0], m_mainrom->base(), m_mainrom->bytes());
u16 *src = (u16 *)memregion("sprites_mask")->base();
iga_u12_decode(src, memregion("sprites_mask")->bytes(), 0x0000);
iga_u16_decode(src, memregion("sprites_mask")->bytes(), 0x0000);
m_sprite_predecrypted = false;
src = (u16 *)memregion("sprites_colour")->base();
sprite_colour_decode(src, memregion("sprites_colour")->bytes());
m_has_decrypted = false;
}
void pgm2_state::init_orleg2()
{
common_encryption_init();
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20020114, 0x20020117, read32_delegate(FUNC(pgm2_state::orleg2_speedup_r),this));
}
void pgm2_state::init_kov2nl()
{
common_encryption_init();
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20020470, 0x20020473, read32_delegate(FUNC(pgm2_state::kov2nl_speedup_r), this));
}
void pgm2_state::init_ddpdojt()
{
common_encryption_init();
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20000060, 0x20000063, read32_delegate(FUNC(pgm2_state::ddpdojt_speedup_r), this));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20021e04, 0x20021e07, read32_delegate(FUNC(pgm2_state::ddpdojt_speedup2_r), this));
}
// currently we don't know how to derive address/data xor values from real keys, so we need both
static const kov3_module_key kov3_104_key = { { 0x40,0xac,0x30,0x00,0x47,0x49,0x00,0x00 } ,{ 0xeb,0x7d,0x8d,0x90,0x2c,0xf4,0x09,0x82 }, 0x18ec71, 0xb89d }; // fake zero-key
static const kov3_module_key kov3_102_key = { { 0x49,0xac,0xb0,0xec,0x47,0x49,0x95,0x38 } ,{ 0x09,0xbd,0xf1,0x31,0xe6,0xf0,0x65,0x2b }, 0x021d37, 0x81d0 };
static const kov3_module_key kov3_101_key = { { 0xc1,0x2c,0xc1,0xe5,0x3c,0xc1,0x59,0x9e } ,{ 0xf2,0xb2,0xf0,0x89,0x37,0xf2,0xc7,0x0b }, 0, 0xffff }; // real xor values is unknown
static const kov3_module_key kov3_100_key = { { 0x40,0xac,0x30,0x00,0x47,0x49,0x00,0x00 } ,{ 0x96,0xf0,0x91,0xe1,0xb3,0xf1,0xef,0x90 }, 0x3e8aa8, 0xc530 }; // fake zero-key
void pgm2_state::init_kov3()
{
common_encryption_init();
m_maincpu->space(AS_PROGRAM).install_read_handler(0x200000b4, 0x200000b7, read32_delegate(FUNC(pgm2_state::kov3_speedup_r),this));
}
void pgm2_state::decrypt_kov3_module(u32 addrxor, u16 dataxor)
{
u16 *src = (u16 *)m_mainrom->base();
u32 size = m_mainrom->bytes();
std::vector<u16> buffer(size/2);
for (int i = 0; i < size/2; i++)
buffer[i] = src[i^addrxor]^dataxor;
memcpy(src, &buffer[0], size);
m_has_decrypted_kov3_module = true;
}
void pgm2_state::init_kov3_104()
{
module_key = &kov3_104_key;
init_kov3();
}
void pgm2_state::init_kov3_102()
{
module_key = &kov3_102_key;
init_kov3();
}
void pgm2_state::init_kov3_101()
{
module_key = &kov3_101_key;
init_kov3();
}
void pgm2_state::init_kov3_100()
{
module_key = &kov3_100_key;
init_kov3();
}
void pgm2_state::init_kof98umh()
{
common_encryption_init();
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20000060, 0x20000063, read32_delegate(FUNC(pgm2_state::kof98umh_speedup_r),this));
}
/* PGM2 */
//华通电子/Huatong Electronics (distributor of orleg2, kov2nl in china) = 华通科技/Huatong Technology (distributor of kov3 in china),
//Same company but they changed name.
// Oriental Legend 2 - should be a V102 and V100 too
//西游释厄传2/Xīyóu shì è chuán 2 (China; Simplified Chinese)
//西遊釋厄傳2/Saiyū Shakuyakuden 2 (Japan; Traditional Chinese - Taiwan(undumped) too?)
GAME( 2007, orleg2, 0, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS", "Oriental Legend 2 (V104, Oversea)", MACHINE_SUPPORTS_SAVE ) /* Overseas sets of OL2 do not use the card reader */
GAME( 2007, orleg2_103, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS", "Oriental Legend 2 (V103, Oversea)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_101, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS", "Oriental Legend 2 (V101, Oversea)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_104cn, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS (Huatong license)", "Xiyou Shi E Chuan 2 (V104, China)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_103cn, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS (Huatong license)", "Xiyou Shi E Chuan 2 (V103, China)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_101cn, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS (Huatong license)", "Xiyou Shi E Chuan 2 (V101, China)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_104jp, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS (Alta license)", "Saiyuu Shakuyakuden 2 (V104, Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_103jp, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS (Alta license)", "Saiyuu Shakuyakuden 2 (V103, Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 2007, orleg2_101jp, orleg2, pgm2, pgm2, pgm2_state, init_orleg2, ROT0, "IGS (Alta license)", "Saiyuu Shakuyakuden 2 (V101, Japan)", MACHINE_SUPPORTS_SAVE )
// Knights of Valour 2 New Legend
//三國戰紀2撗掃于軍 New Legend/Sānguó zhàn jì 2 Guàng sǎo yú jūn New Legend (Oversea; Mixed Traditional and Simplified Chinese)
//三國戰紀2盖世英雄/Sānguó zhàn jì 2 Gàishì yīngxióng (China; Mixed Traditional and Simplified Chinese)
//三國戰紀2乱世英雄/Sangoku-Senki 2 Ranse Eiyū (Japan; Mixed Traditional and Simplified Chinese - Undumped)
GAME( 2008, kov2nl, 0, pgm2, pgm2, pgm2_state, init_kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend / Sanguo Zhan Ji 2 Guang Sao Yu Jun (V302, Oversea)", MACHINE_SUPPORTS_SAVE )
GAME( 2008, kov2nl_301, kov2nl, pgm2, pgm2, pgm2_state, init_kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend / Sanguo Zhan Ji 2 Guang Sao Yu Jun (V301, Oversea)", MACHINE_SUPPORTS_SAVE )
GAME( 2008, kov2nl_300, kov2nl, pgm2, pgm2, pgm2_state, init_kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend / Sanguo Zhan Ji 2 Guang Sao Yu Jun (V300, Oversea)", MACHINE_SUPPORTS_SAVE )
GAME( 2008, kov2nl_302cn, kov2nl, pgm2, pgm2, pgm2_state, init_kov2nl, ROT0, "IGS (Huatong license)", "Sanguo Zhan Ji 2 Gaishi Yingxiong (V302, China)", MACHINE_SUPPORTS_SAVE )
GAME( 2008, kov2nl_301cn, kov2nl, pgm2, pgm2, pgm2_state, init_kov2nl, ROT0, "IGS (Huatong license)", "Sanguo Zhan Ji 2 Gaishi Yingxiong (V301, China)", MACHINE_SUPPORTS_SAVE )
GAME( 2008, kov2nl_300cn, kov2nl, pgm2, pgm2, pgm2_state, init_kov2nl, ROT0, "IGS (Huatong license)", "Sanguo Zhan Ji 2 Gaishi Yingxiong (V300, China)", MACHINE_SUPPORTS_SAVE )
// Dodonpachi Daioujou Tamashii - should be a V200 too
GAME( 2010, ddpdojt, 0, pgm2_ramrom, pgm2, pgm2_state, init_ddpdojt, ROT270, "IGS / Cave (Tong Li Animation license)", "DoDonPachi Dai-Ou-Jou Tamashii (V201, China)", MACHINE_SUPPORTS_SAVE )
// Knights of Valour 3 - should be a V103 and V101 too
//三国战纪3/Sānguó zhàn jì 3 (Simplified Chinese)
GAME( 2011, kov3, 0, pgm2_hires, pgm2, pgm2_state, init_kov3_104, ROT0, "IGS (Huatong license)", "Knights of Valour 3 / Sanguo Zhan Ji 3 (V104, China, Hong Kong, Taiwan)", MACHINE_SUPPORTS_SAVE )
GAME( 2011, kov3_102, kov3, pgm2_hires, pgm2, pgm2_state, init_kov3_102, ROT0, "IGS (Huatong license)", "Knights of Valour 3 / Sanguo Zhan Ji 3 (V102, China, Hong Kong, Taiwan)", MACHINE_SUPPORTS_SAVE )
GAME( 2011, kov3_101, kov3, pgm2_hires, pgm2, pgm2_state, init_kov3_101, ROT0, "IGS (Huatong license)", "Knights of Valour 3 / Sanguo Zhan Ji 3 (V101, China, Hong Kong, Taiwan)", MACHINE_SUPPORTS_SAVE )
GAME( 2011, kov3_100, kov3, pgm2_hires, pgm2, pgm2_state, init_kov3_100, ROT0, "IGS (Huatong license)", "Knights of Valour 3 / Sanguo Zhan Ji 3 (V100, China, Hong Kong, Taiwan)", MACHINE_SUPPORTS_SAVE )
// King of Fighters '98: Ultimate Match Hero
GAME( 2009, kof98umh, 0, pgm2_lores, pgm2, pgm2_state, init_kof98umh, ROT0, "IGS / SNK Playmore / New Channel", "The King of Fighters '98: Ultimate Match HERO (China, V100, 09-08-23)", MACHINE_SUPPORTS_SAVE )
// Jigsaw World Arena
// お茶犬のパズル/Ochaken no Puzzle (V101JP exists but undumped, Puzzle game of Japanese お茶犬/Ochaken franchises)