/************************************************************************* Williams/Midway Y/Z-unit system **************************************************************************/ #include "driver.h" #include "cpu/tms34010/tms34010.h" #include "cpu/m6809/m6809.h" #include "machine/6821pia.h" #include "audio/williams.h" #include "midyunit.h" /* constant definitions */ #define SOUND_NARC 1 #define SOUND_CVSD_SMALL 2 #define SOUND_CVSD 3 #define SOUND_ADPCM 4 #define SOUND_YAWDIM 5 /* protection data types */ struct protection_data { UINT16 reset_sequence[3]; UINT16 data_sequence[100]; }; static const struct protection_data *prot_data; static UINT16 prot_result; static UINT16 prot_sequence[3]; static UINT8 prot_index; /* input-related variables */ static UINT8 term2_analog_select; /* CMOS-related variables */ UINT16 *midyunit_cmos_ram; UINT32 midyunit_cmos_page; static UINT8 cmos_w_enable; /* sound-related variables */ static UINT8 chip_type; /* hack-related variables */ static UINT16 *t2_hack_mem; /************************************* * * CMOS reads/writes * *************************************/ WRITE16_HANDLER( midyunit_cmos_w ) { logerror("%08x:CMOS Write @ %05X\n", activecpu_get_pc(), offset); COMBINE_DATA(&midyunit_cmos_ram[offset + midyunit_cmos_page]); } READ16_HANDLER( midyunit_cmos_r ) { return midyunit_cmos_ram[offset + midyunit_cmos_page]; } /************************************* * * CMOS enable and protection * *************************************/ WRITE16_HANDLER( midyunit_cmos_enable_w ) { cmos_w_enable = (~data >> 9) & 1; logerror("%08x:Protection write = %04X\n", activecpu_get_pc(), data); /* only go down this path if we have a data structure */ if (prot_data) { /* mask off the data */ data &= 0x0f00; /* update the FIFO */ prot_sequence[0] = prot_sequence[1]; prot_sequence[1] = prot_sequence[2]; prot_sequence[2] = data; /* special case: sequence entry 1234 means Strike Force, which is different */ if (prot_data->reset_sequence[0] == 0x1234) { if (data == 0x500) { prot_result = program_read_word(TOBYTE(0x10a4390)) << 4; logerror(" desired result = %04X\n", prot_result); } } /* all other games use the same pattern */ else { /* look for a reset */ if (prot_sequence[0] == prot_data->reset_sequence[0] && prot_sequence[1] == prot_data->reset_sequence[1] && prot_sequence[2] == prot_data->reset_sequence[2]) { logerror("Protection reset\n"); prot_index = 0; } /* look for a clock */ if ((prot_sequence[1] & 0x0800) != 0 && (prot_sequence[2] & 0x0800) == 0) { prot_result = prot_data->data_sequence[prot_index++]; logerror("Protection clock (new data = %04X)\n", prot_result); } } } } READ16_HANDLER( midyunit_protection_r ) { /* return the most recently clocked value */ logerror("%08X:Protection read = %04X\n", activecpu_get_pc(), prot_result); return prot_result; } /************************************* * * Generic input ports * *************************************/ READ16_HANDLER( midyunit_input_r ) { return readinputport(offset); } /************************************* * * Special Terminator 2 input ports * *************************************/ static READ16_HANDLER( term2_input_r ) { if (offset != 2) return readinputport(offset); switch (term2_analog_select) { default: case 0: return readinputport(2); break; case 1: return readinputport(6); break; case 2: return readinputport(7); break; case 3: return readinputport(8); break; } } static WRITE16_HANDLER( term2_sound_w ) { if (offset == 0) term2_analog_select = (data >> 0x0c) & 0x03; williams_adpcm_data_w(data); } /************************************* * * Special Terminator 2 hack * *************************************/ static WRITE16_HANDLER( term2_hack_w ) { if (offset == 0 && activecpu_get_pc() == 0xffce5230) { t2_hack_mem[offset] = 0; return; } COMBINE_DATA(&t2_hack_mem[offset]); } static WRITE16_HANDLER( term2la2_hack_w ) { if (offset == 0 && activecpu_get_pc() == 0xffce4b80) { t2_hack_mem[offset] = 0; return; } COMBINE_DATA(&t2_hack_mem[offset]); } static WRITE16_HANDLER( term2la1_hack_w ) { if (offset == 0 && activecpu_get_pc() == 0xffce33f0) { t2_hack_mem[offset] = 0; return; } COMBINE_DATA(&t2_hack_mem[offset]); } /************************************* * * Generic driver init * *************************************/ static UINT8 *cvsd_protection_base; static WRITE8_HANDLER( cvsd_protection_w ) { /* because the entire CVSD ROM is banked, we have to make sure that writes */ /* go to the proper location (i.e., bank 0); currently bank 0 always lives */ /* in the 0x10000-0x17fff space, so we just need to add 0x8000 to get the */ /* proper offset */ cvsd_protection_base[offset] = data; } static void init_generic(int bpp, int sound, int prot_start, int prot_end) { offs_t gfx_chunk = midyunit_gfx_rom_size / 4; UINT8 d1, d2, d3, d4, d5, d6; UINT8 *base; int i; /* load graphics ROMs */ base = memory_region(REGION_GFX1); switch (bpp) { case 4: for (i = 0; i < midyunit_gfx_rom_size; i += 2) { d1 = ((base[0 * gfx_chunk + (i + 0) / 4]) >> (2 * ((i + 0) % 4))) & 3; d2 = ((base[1 * gfx_chunk + (i + 0) / 4]) >> (2 * ((i + 0) % 4))) & 3; d3 = ((base[0 * gfx_chunk + (i + 1) / 4]) >> (2 * ((i + 1) % 4))) & 3; d4 = ((base[1 * gfx_chunk + (i + 1) / 4]) >> (2 * ((i + 1) % 4))) & 3; midyunit_gfx_rom[i + 0] = d1 | (d2 << 2); midyunit_gfx_rom[i + 1] = d3 | (d4 << 2); } break; case 6: for (i = 0; i < midyunit_gfx_rom_size; i += 2) { d1 = ((base[0 * gfx_chunk + (i + 0) / 4]) >> (2 * ((i + 0) % 4))) & 3; d2 = ((base[1 * gfx_chunk + (i + 0) / 4]) >> (2 * ((i + 0) % 4))) & 3; d3 = ((base[2 * gfx_chunk + (i + 0) / 4]) >> (2 * ((i + 0) % 4))) & 3; d4 = ((base[0 * gfx_chunk + (i + 1) / 4]) >> (2 * ((i + 1) % 4))) & 3; d5 = ((base[1 * gfx_chunk + (i + 1) / 4]) >> (2 * ((i + 1) % 4))) & 3; d6 = ((base[2 * gfx_chunk + (i + 1) / 4]) >> (2 * ((i + 1) % 4))) & 3; midyunit_gfx_rom[i + 0] = d1 | (d2 << 2) | (d3 << 4); midyunit_gfx_rom[i + 1] = d4 | (d5 << 2) | (d6 << 4); } break; case 8: for (i = 0; i < midyunit_gfx_rom_size; i += 4) { midyunit_gfx_rom[i + 0] = base[0 * gfx_chunk + i / 4]; midyunit_gfx_rom[i + 1] = base[1 * gfx_chunk + i / 4]; midyunit_gfx_rom[i + 2] = base[2 * gfx_chunk + i / 4]; midyunit_gfx_rom[i + 3] = base[3 * gfx_chunk + i / 4]; } break; } /* load sound ROMs and set up sound handlers */ chip_type = sound; switch (sound) { case SOUND_CVSD_SMALL: williams_cvsd_init(0); memory_install_write8_handler(1, ADDRESS_SPACE_PROGRAM, prot_start, prot_end, 0, 0, cvsd_protection_w); cvsd_protection_base = memory_region(REGION_CPU2) + 0x10000 + (prot_start - 0x8000); break; case SOUND_CVSD: williams_cvsd_init(0); memory_install_write8_handler(1, ADDRESS_SPACE_PROGRAM, prot_start, prot_end, 0, 0, MWA8_RAM); break; case SOUND_ADPCM: williams_adpcm_init(); memory_install_write8_handler(1, ADDRESS_SPACE_PROGRAM, prot_start, prot_end, 0, 0, MWA8_RAM); break; case SOUND_NARC: williams_narc_init(); memory_install_write8_handler(1, ADDRESS_SPACE_PROGRAM, prot_start, prot_end, 0, 0, MWA8_RAM); break; case SOUND_YAWDIM: break; } } /************************************* * * Z-unit init * * music: 6809 driving YM2151, DAC * effects: 6809 driving CVSD, DAC * *************************************/ DRIVER_INIT( narc ) { /* common init */ init_generic(8, SOUND_NARC, 0xcdff, 0xce29); } /************************************* * * Y-unit init (CVSD) * * music: 6809 driving YM2151, DAC, and CVSD * *************************************/ /********************** Trog **************************/ DRIVER_INIT( trog ) { /* protection */ static const struct protection_data trog_protection_data = { { 0x0f00, 0x0f00, 0x0f00 }, { 0x3000, 0x1000, 0x2000, 0x0000, 0x2000, 0x3000, 0x3000, 0x1000, 0x0000, 0x0000, 0x2000, 0x3000, 0x1000, 0x1000, 0x2000 } }; prot_data = &trog_protection_data; /* common init */ init_generic(4, SOUND_CVSD_SMALL, 0x9eaf, 0x9ed9); } /********************** Smash TV **********************/ DRIVER_INIT( smashtv ) { /* common init */ init_generic(6, SOUND_CVSD_SMALL, 0x9cf6, 0x9d21); } /********************** High Impact Football **********************/ DRIVER_INIT( hiimpact ) { /* protection */ static const struct protection_data hiimpact_protection_data = { { 0x0b00, 0x0b00, 0x0b00 }, { 0x2000, 0x4000, 0x4000, 0x0000, 0x6000, 0x6000, 0x2000, 0x4000, 0x2000, 0x4000, 0x2000, 0x0000, 0x4000, 0x6000, 0x2000 } }; prot_data = &hiimpact_protection_data; /* common init */ init_generic(6, SOUND_CVSD, 0x9b79, 0x9ba3); } /********************** Super High Impact Football **********************/ DRIVER_INIT( shimpact ) { /* protection */ static const struct protection_data shimpact_protection_data = { { 0x0f00, 0x0e00, 0x0d00 }, { 0x0000, 0x4000, 0x2000, 0x5000, 0x2000, 0x1000, 0x4000, 0x6000, 0x3000, 0x0000, 0x2000, 0x5000, 0x5000, 0x5000, 0x2000 } }; prot_data = &shimpact_protection_data; /* common init */ init_generic(6, SOUND_CVSD, 0x9c06, 0x9c15); } /********************** Strike Force **********************/ DRIVER_INIT( strkforc ) { /* protection */ static const struct protection_data strkforc_protection_data = { { 0x1234 } }; prot_data = &strkforc_protection_data; /* common init */ init_generic(4, SOUND_CVSD_SMALL, 0x9f7d, 0x9fa7); } /************************************* * * Y-unit init (ADPCM) * * music: 6809 driving YM2151, DAC, and OKIM6295 * *************************************/ /********************** Mortal Kombat **********************/ DRIVER_INIT( mkyunit ) { /* protection */ static const struct protection_data mk_protection_data = { { 0x0d00, 0x0c00, 0x0900 }, { 0x4600, 0xf600, 0xa600, 0x0600, 0x2600, 0x9600, 0xc600, 0xe600, 0x8600, 0x7600, 0x8600, 0x8600, 0x9600, 0xd600, 0x6600, 0xb600, 0xd600, 0xe600, 0xf600, 0x7600, 0xb600, 0xa600, 0x3600 } }; prot_data = &mk_protection_data; /* common init */ init_generic(6, SOUND_ADPCM, 0xfb9c, 0xfbc6); } DRIVER_INIT( mkyawdim ) { /* common init */ init_generic(6, SOUND_YAWDIM, 0, 0); } /********************** Terminator 2 **********************/ static void term2_init_common(write16_handler hack_w) { /* protection */ static const struct protection_data term2_protection_data = { { 0x0f00, 0x0f00, 0x0f00 }, { 0x4000, 0xf000, 0xa000 } }; prot_data = &term2_protection_data; /* common init */ init_generic(6, SOUND_ADPCM, 0xfa8d, 0xfa9c); /* special inputs */ memory_install_read16_handler(0, ADDRESS_SPACE_PROGRAM, 0x01c00000, 0x01c0005f, 0, 0, term2_input_r); memory_install_write16_handler(0, ADDRESS_SPACE_PROGRAM, 0x01e00000, 0x01e0001f, 0, 0, term2_sound_w); /* HACK: this prevents the freeze on the movies */ /* until we figure whats causing it, this is better than nothing */ t2_hack_mem = memory_install_write16_handler(0, ADDRESS_SPACE_PROGRAM, 0x010aa0e0, 0x010aa0ff, 0, 0, hack_w); } DRIVER_INIT( term2 ) { term2_init_common(term2_hack_w); } DRIVER_INIT( term2la2 ) { term2_init_common(term2la2_hack_w); } DRIVER_INIT( term2la1 ) { term2_init_common(term2la1_hack_w); } /********************** Total Carnage **********************/ DRIVER_INIT( totcarn ) { /* protection */ static const struct protection_data totcarn_protection_data = { { 0x0f00, 0x0f00, 0x0f00 }, { 0x4a00, 0x6a00, 0xda00, 0x6a00, 0x9a00, 0x4a00, 0x2a00, 0x9a00, 0x1a00, 0x8a00, 0xaa00 } }; prot_data = &totcarn_protection_data; /* common init */ init_generic(6, SOUND_ADPCM, 0xfc04, 0xfc2e); } /************************************* * * Machine init * *************************************/ MACHINE_RESET( midyunit ) { /* reset sound */ switch (chip_type) { case SOUND_NARC: williams_narc_reset_w(1); williams_narc_reset_w(0); break; case SOUND_CVSD: case SOUND_CVSD_SMALL: williams_cvsd_reset_w(1); williams_cvsd_reset_w(0); break; case SOUND_ADPCM: williams_adpcm_reset_w(1); williams_adpcm_reset_w(0); break; case SOUND_YAWDIM: break; } } /************************************* * * Sound write handlers * *************************************/ WRITE16_HANDLER( midyunit_sound_w ) { /* check for out-of-bounds accesses */ if (offset) { logerror("%08X:Unexpected write to sound (hi) = %04X\n", activecpu_get_pc(), data); return; } /* call through based on the sound type */ if (ACCESSING_LSB && ACCESSING_MSB) switch (chip_type) { case SOUND_NARC: williams_narc_data_w(data); break; case SOUND_CVSD_SMALL: case SOUND_CVSD: williams_cvsd_data_w((data & 0xff) | ((data & 0x200) >> 1)); break; case SOUND_ADPCM: williams_adpcm_data_w(data); break; case SOUND_YAWDIM: soundlatch_w(0, data); cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE); break; } }