diff options
Diffstat (limited to 'src/mame/machine/arkanoid.c')
-rw-r--r-- | src/mame/machine/arkanoid.c | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/src/mame/machine/arkanoid.c b/src/mame/machine/arkanoid.c new file mode 100644 index 00000000000..1112886118c --- /dev/null +++ b/src/mame/machine/arkanoid.c @@ -0,0 +1,597 @@ +/*************************************************************************** + + machine.c + + Functions to emulate general aspects of the machine (RAM, ROM, interrupts, + I/O ports) + +***************************************************************************/ + +#include "driver.h" +#include "arkanoid.h" + + +/* To log specific reads and writes of the bootlegs */ +#define ARKANOID_BOOTLEG_VERBOSE 1 + + +UINT8 arkanoid_paddle_select; +static UINT8 arkanoid_paddle_value; + +static UINT8 z80write,fromz80,m68705write,toz80; + +static UINT8 portA_in,portA_out,ddrA; +static UINT8 portC_out,ddrC; + + +MACHINE_START( arkanoid ) +{ + state_save_register_global(arkanoid_paddle_select); + state_save_register_global(z80write); + state_save_register_global(fromz80); + state_save_register_global(m68705write); + state_save_register_global(toz80); + + state_save_register_global(portA_in); + state_save_register_global(portA_out); + state_save_register_global(ddrA); + + state_save_register_global(portC_out); + state_save_register_global(ddrC); +} + +MACHINE_RESET( arkanoid ) +{ + portA_in = portA_out = z80write = m68705write = 0; +} + +READ8_HANDLER( arkanoid_Z80_mcu_r ) +{ + /* return the last value the 68705 wrote, and mark that we've read it */ + m68705write = 0; + return toz80; +} + +static TIMER_CALLBACK( test ) +{ + z80write = 1; + fromz80 = param; +} + +WRITE8_HANDLER( arkanoid_Z80_mcu_w ) +{ + timer_call_after_resynch(data, test); + /* boost the interleave for a few usecs to make sure it is read successfully */ + cpu_boost_interleave(attotime_zero, ATTOTIME_IN_USEC(10)); +} + +READ8_HANDLER( arkanoid_68705_portA_r ) +{ + return (portA_out & ddrA) | (portA_in & ~ddrA); +} + +WRITE8_HANDLER( arkanoid_68705_portA_w ) +{ + portA_out = data; +} + +WRITE8_HANDLER( arkanoid_68705_ddrA_w ) +{ + ddrA = data; +} + + +READ8_HANDLER( arkanoid_68705_portC_r ) +{ + int res=0; + + /* bit 0 is high on a write strobe; clear it once we've detected it */ + if (z80write) res |= 0x01; + + /* bit 1 is high if the previous write has been read */ + if (!m68705write) res |= 0x02; + + return (portC_out & ddrC) | (res & ~ddrC); +} + +WRITE8_HANDLER( arkanoid_68705_portC_w ) +{ + if ((ddrC & 0x04) && (~data & 0x04) && (portC_out & 0x04)) + { + /* return the last value the Z80 wrote */ + z80write = 0; + portA_in = fromz80; + } + if ((ddrC & 0x08) && (~data & 0x08) && (portC_out & 0x08)) + { + /* a write from the 68705 to the Z80; remember its value */ + m68705write = 1; + toz80 = portA_out; + } + + portC_out = data; +} + +WRITE8_HANDLER( arkanoid_68705_ddrC_w ) +{ + ddrC = data; +} + + + +READ8_HANDLER( arkanoid_68705_input_0_r ) +{ + int res = input_port_0_r(offset) & 0x3f; + + /* bit 0x40 comes from the sticky bit */ + if (!z80write) res |= 0x40; + + /* bit 0x80 comes from a write latch */ + if (!m68705write) res |= 0x80; + + return res; +} + +READ8_HANDLER( arkanoid_input_2_r ) +{ + if (arkanoid_paddle_select) + { + arkanoid_paddle_value = input_port_3_r(offset); + } + else + { + arkanoid_paddle_value = input_port_2_r(offset); + } + + return arkanoid_paddle_value; +} + + +/* + +Bootlegs stuff + +The bootlegs simulate the missing MCU behaviour with writes to 0xd018 and reads value back from 0xf002. +Fortunately, 'arkangc', 'arkbloc2' and 'arkblock' has patched code not to bother with that. +So I've fixed 'arkbl3' and 'paddle2' to return the expected values (code is strongly similar). + +Some bootlegs also test some bits from 0xd008 after reading the paddle value at 0xd018. +Their effect is completely unknown but I need to set some bits to 1 so the games are playable : + + - 'arkangc' : NO read from 0xd008 ! + - 'arkangc2' : + * bit 1 must be set to 1 or you enter sort of endless "demo mode" when you start : + . you can't select your starting level (it always starts at level 1) + . you can't control the paddle (it automoves by following the ball) + . you can use the "fire" button (the game never shoots) + . you are awarded points as in a normal game + . sounds are played + - 'arkblock' : NO read from 0xd008 ! + - 'arkbloc2' : + * bit 5 must sometimes be set to 1 or you can't reach right side of the screen + nor select all levels at the begining of the game + - 'arkgcbl' : + * bit 1 must be set to 1 or you enter sort of endless "demo mode" when you start : + . you can't select your starting level (it always starts at level 1) + . you can't control the paddle (it automoves by following the ball) + . you can use the "fire" button (the game never shoots) + . you are awarded points as in a normal game + . sounds are played + * bit 5 must sometimes be set to 1 or you can't reach right side of the screen + nor select all levels at the begining of the game + - 'paddle2' : + * bits 0 and 1 must be set to 1 or the paddle goes up (joystick issue ?) + * bits 2 and 3 must be set to 1 or the paddle goes down (joystick issue ?) + * bit 5 must sometimes be set to 1 or you can't reach right side of the screen + nor select all levels at the begining of the game + + +TO DO (2006.09.12) : + + - understand reads from 0xd008 (even if the games are playable) + - try to document writes to 0xd018 with unknown effect + +*/ + + +#if ARKANOID_BOOTLEG_VERBOSE +#define LOG_F002_R logerror("%04x: arkanoid_bootleg_f002_r - cmd = %02x - val = %02x\n",activecpu_get_pc(),arkanoid_bootleg_cmd,arkanoid_bootleg_val); +#define LOG_D018_W logerror("%04x: arkanoid_bootleg_d018_w - data = %02x - cmd = %02x\n",activecpu_get_pc(),data,arkanoid_bootleg_cmd); +#define LOG_D008_R logerror("%04x: arkanoid_bootleg_d008_r - val = %02x\n",activecpu_get_pc(),arkanoid_bootleg_d008_val); +#else +#define LOG_F002_R +#define LOG_D018_W +#define LOG_D008_R +#endif + + +static UINT8 arkanoid_bootleg_cmd; + +/* Kludge for some bootlegs that read this address */ +READ8_HANDLER( arkanoid_bootleg_f002_r ) +{ + UINT8 arkanoid_bootleg_val = 0x00; + + switch (arkanoid_bootleg_id) + { + case ARKANGC: + case ARKBLOCK: + switch (arkanoid_bootleg_cmd) + { + default: + break; + } + LOG_F002_R + break; + case ARKANGC2: /* There are no reads from 0xf002 in this bootleg */ + switch (arkanoid_bootleg_cmd) + { + default: + break; + } + LOG_F002_R + break; + case ARKBLOC2: + switch (arkanoid_bootleg_cmd) + { + default: + break; + } + LOG_F002_R + break; + case ARKGCBL: + switch (arkanoid_bootleg_cmd) + { + case 0x8a: /* Current level (fixed routine) */ + arkanoid_bootleg_val = 0xa5; + break; + case 0xff: /* Avoid "BAD HARDWARE " message (fixed routine) */ + arkanoid_bootleg_val = 0xe2; + break; + default: + break; + } + LOG_F002_R + break; + case PADDLE2: + switch (arkanoid_bootleg_cmd) + { + case 0x24: /* Avoid bad jump to 0x0066 */ + arkanoid_bootleg_val = 0x9b; + break; + case 0x36: /* Avoid "BAD HARDWARE " message */ + arkanoid_bootleg_val = 0x2d; + break; + case 0x38: /* Start of levels table (fixed offset) */ + arkanoid_bootleg_val = 0xf3; + break; + case 0x8a: /* Current level (fixed routine) */ + arkanoid_bootleg_val = 0xa5; + break; + case 0xc3: /* Avoid bad jump to 0xf000 */ + arkanoid_bootleg_val = 0x1d; + break; + case 0xe3: /* Number of bricks left (fixed offset) */ + arkanoid_bootleg_val = 0x61; + break; + case 0xf7: /* Avoid "U69" message */ + arkanoid_bootleg_val = 0x00; + break; + case 0xff: /* Avoid "BAD HARDWARE " message (fixed routine) */ + arkanoid_bootleg_val = 0xe2; + break; + default: + break; + } + LOG_F002_R + break; + default: + logerror("%04x: arkanoid_bootleg_f002_r - cmd = %02x - unknown bootleg !\n",activecpu_get_pc(),arkanoid_bootleg_cmd); + break; + } + + return arkanoid_bootleg_val; +} + +/* Kludge for some bootlegs that write this address */ +WRITE8_HANDLER( arkanoid_bootleg_d018_w ) +{ + arkanoid_bootleg_cmd = 0x00; + + switch (arkanoid_bootleg_id) + { + case ARKANGC: + case ARKBLOCK: + switch (data) + { + case 0x36: /* unneeded value : no call 0x2050, unused A and overwritten HL (0x0313 -> 0x0340) */ + if (activecpu_get_pc() == 0x7c47) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x38: /* unneeded value : no call 0x2050, unused A and fixed HL (0x7bd5) */ + if (activecpu_get_pc() == 0x7b87) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x8a: /* unneeded value : no call 0x2050, unused A and overwritten HL (0x7b77 -> 0x7c1c) */ + if (activecpu_get_pc() == 0x9661) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xe3: /* unneeded value : call 0x2050 but fixed A (0x00) and fixed HL (0xed83) */ + if (activecpu_get_pc() == 0x67e3) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xf7: /* unneeded value : 3 * 'NOP' at 0x034f + 2 * 'NOP' at 0x35b */ + if (activecpu_get_pc() == 0x0349) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xff: /* unneeded value : no call 0x2050, unused A and overwritten HL (0x7c4f -> 0x7d31) */ + if (activecpu_get_pc() == 0x9670) + arkanoid_bootleg_cmd = 0x00; + break; + default: + arkanoid_bootleg_cmd = 0x00; + break; + } + LOG_D018_W + break; + case ARKANGC2: + switch (data) + { + case 0x36: /* unneeded value : call 0x2050 but fixed A (0x2d) */ + if (activecpu_get_pc() == 0x7c4c) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x38: /* unneeded value : call 0x2050 but fixed A (0xf3) */ + if (activecpu_get_pc() == 0x7b87) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x88: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e3) + arkanoid_bootleg_cmd = 0x00; + if (activecpu_get_pc() == 0x7c47) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x89: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e5) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x8a: /* unneeded value : call 0x2050 but fixed A (0xa5) */ + if (activecpu_get_pc() == 0x9661) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xc0: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e7) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xe3: /* unneeded value : call 0x2050 but fixed A (0x61) */ + if (activecpu_get_pc() == 0x67e9) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xff: /* unneeded value : call 0x2050 but fixed A (0xe2) */ + if (activecpu_get_pc() == 0x9670) + arkanoid_bootleg_cmd = 0x00; + break; + default: + arkanoid_bootleg_cmd = 0x00; + break; + } + LOG_D018_W + break; + case ARKBLOC2: + switch (data) + { + case 0x36: /* unneeded value : call 0x2050 but fixed A (0x2d) */ + if (activecpu_get_pc() == 0x7c4c) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x38: /* unneeded value : call 0x2050 but fixed A (0xf3) */ + if (activecpu_get_pc() == 0x7b87) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x88: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e3) + arkanoid_bootleg_cmd = 0x00; + if (activecpu_get_pc() == 0x7c47) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x89: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e5) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x8a: /* unneeded value : call 0x2050 but unused HL and fixed DE (0x7c1c) */ + if (activecpu_get_pc() == 0x9661) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xc0: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e7) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xe3: /* unneeded value : call 0x2050 but fixed A (0x61) */ + if (activecpu_get_pc() == 0x67e9) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xf7: /* unneeded value : call 0x2050 but never called (check code at 0x0340) */ + if (activecpu_get_pc() == 0x0349) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xff: /* unneeded value : no call 0x2050, unused A and fixed HL (0x7d31) */ + if (activecpu_get_pc() == 0x9670) + arkanoid_bootleg_cmd = 0x00; + break; + default: + arkanoid_bootleg_cmd = 0x00; + break; + } + LOG_D018_W + break; + case ARKGCBL: + switch (data) + { + case 0x36: /* unneeded value : call 0x2050 but fixed A (0x2d) */ + if (activecpu_get_pc() == 0x7c4c) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x38: /* unneeded value : call 0x2050 but fixed A (0xf3) */ + if (activecpu_get_pc() == 0x7b87) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x88: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e3) + arkanoid_bootleg_cmd = 0x00; + if (activecpu_get_pc() == 0x7c47) + arkanoid_bootleg_cmd = 0x00; + case 0x89: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e5) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x8a: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x9661) + arkanoid_bootleg_cmd = data; + break; + case 0xc0: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e7) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xe3: /* unneeded value : call 0x2050 but fixed A (0x61) */ + if (activecpu_get_pc() == 0x67e9) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xf7: /* unneeded value : 3 * 'NOP' at 0x034f + 'JR NZ,$035D' at 0x35b */ + if (activecpu_get_pc() == 0x0349) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xff: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x9670) + arkanoid_bootleg_cmd = data; + break; + default: + arkanoid_bootleg_cmd = 0x00; + break; + } + LOG_D018_W + break; + case PADDLE2: + switch (data) + { + case 0x24: /* A read from 0xf002 (expected to be 0x9b) */ + if (activecpu_get_pc() == 0xbd7a) + arkanoid_bootleg_cmd = data; + break; + case 0x36: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x7c4c) + arkanoid_bootleg_cmd = data; + break; + case 0x38: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x7b87) + arkanoid_bootleg_cmd = data; + break; + case 0x88: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e3) + arkanoid_bootleg_cmd = 0x00; + if (activecpu_get_pc() == 0x7c47) + arkanoid_bootleg_cmd = 0x00; + case 0x89: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e5) + arkanoid_bootleg_cmd = 0x00; + break; + case 0x8a: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x9661) + arkanoid_bootleg_cmd = data; + break; + case 0xc0: /* unneeded value : no read back */ + if (activecpu_get_pc() == 0x67e7) + arkanoid_bootleg_cmd = 0x00; + break; + case 0xc3: /* A read from 0xf002 (expected to be 0x1d) */ + if (activecpu_get_pc() == 0xbd8a) + arkanoid_bootleg_cmd = data; + break; + case 0xe3: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x67e9) + arkanoid_bootleg_cmd = data; + break; + case 0xf7: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x0349) + arkanoid_bootleg_cmd = data; + break; + case 0xff: /* call 0x2050 with A read from 0xf002 and wrong HL */ + if (activecpu_get_pc() == 0x9670) + arkanoid_bootleg_cmd = data; + break; + default: + arkanoid_bootleg_cmd = 0x00; + break; + } + LOG_D018_W + break; + default: + logerror("%04x: arkanoid_bootleg_d018_w - data = %02x - unknown bootleg !\n",activecpu_get_pc(),data); + break; + } +} + +/* Kludge for some bootlegs that read this address */ +READ8_HANDLER( arkanoid_bootleg_d008_r ) +{ + UINT8 arkanoid_bootleg_d008_bit[8]; + UINT8 arkanoid_bootleg_d008_val; + int b; + + arkanoid_bootleg_d008_bit[4] = arkanoid_bootleg_d008_bit[6] = arkanoid_bootleg_d008_bit[7] = 0; /* untested bits */ + + switch (arkanoid_bootleg_id) + { + case ARKANGC: + case ARKBLOCK: + arkanoid_bootleg_d008_bit[0] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[1] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[2] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[3] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[5] = 0; /* untested bit */ + break; + case ARKANGC2: + arkanoid_bootleg_d008_bit[0] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[1] = 1; /* check code at 0x0cad */ + arkanoid_bootleg_d008_bit[2] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[3] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[5] = 0; /* untested bit */ + break; + case ARKBLOC2: + arkanoid_bootleg_d008_bit[0] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[1] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[2] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[3] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[5] = (arkanoid_paddle_value < 0x40); /* check code at 0x96b0 */ + break; + case ARKGCBL: + arkanoid_bootleg_d008_bit[0] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[1] = 1; /* check code at 0x0cad */ + arkanoid_bootleg_d008_bit[2] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[3] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[5] = (arkanoid_paddle_value < 0x40); /* check code at 0x96b0 */ + break; + case PADDLE2: + arkanoid_bootleg_d008_bit[0] = 1; /* check code at 0x7d65 */ + arkanoid_bootleg_d008_bit[1] = 1; /* check code at 0x7d65 */ + arkanoid_bootleg_d008_bit[2] = 1; /* check code at 0x7d65 */ + arkanoid_bootleg_d008_bit[3] = 1; /* check code at 0x7d65 */ + arkanoid_bootleg_d008_bit[5] = (arkanoid_paddle_value < 0x40); /* check code at 0x96b0 */ + break; + default: + arkanoid_bootleg_d008_bit[0] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[1] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[2] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[3] = 0; /* untested bit */ + arkanoid_bootleg_d008_bit[5] = 0; /* untested bit */ + logerror("%04x: arkanoid_bootleg_d008_r - unknown bootleg !\n",activecpu_get_pc()); + break; + } + + arkanoid_bootleg_d008_val = 0; + for (b=0; b<8; b++) + arkanoid_bootleg_d008_val |= (arkanoid_bootleg_d008_bit[b] << b); + LOG_D008_R + + return arkanoid_bootleg_d008_val; +} + |