/*************************************************************************************

Emulation of the Alpha 8302 microcontroller.

All tables built manually from the analisis of the bootleg set.

The main purpose of the MCU is to control the program flow.
This tables are actually subroutine addresses, wich get pushed
onto the stack one after the other. Basically then the program
runs and when it returns on one of these subroutines, it expects
to land on the proper 'next' subroutine.

Ernesto Corvi - 10/30/98

- 09/12/2004 Pierpaolo Prazzoli
  added Exciting Soccer II protection
  (still at least one issue because you can't control the player)

*************************************************************************************/

#include "driver.h"


#define MCU_KEY_TABLE_SIZE 16

/* These are global */
UINT8 *exctsccr_mcu_ram;
WRITE8_HANDLER( exctsccr_mcu_w );
WRITE8_HANDLER( exctsccr_mcu_control_w );

/* Local stuff */
static int mcu_code_latch;

/* Exciting Soccer */

/* input = 0x6009 - data = 0x6170 */
static UINT8 mcu_table1[MCU_KEY_TABLE_SIZE] = {
	0x23, 0x05, 0xfb, 0x07, 0x4d, 0x3b,	0x7d, 0x03,
	0x9a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x600d - data = 0x61f0 */
static UINT8 mcu_table2[MCU_KEY_TABLE_SIZE] = {
	0x75, 0x25, 0x4b, 0x10, 0xa6, 0x06,	0x9a, 0x02,
	0x04, 0x11, 0x09, 0x09,	0x2a, 0x10, 0x3a, 0x10
};

/* input = ?????? - data = 0x6300 */
static UINT8 mcu_table3[MCU_KEY_TABLE_SIZE*4] = {
	0xba, 0x26,	0x53, 0x0d, 0x01, 0x24, 0x1d, 0x15,
	0xd0, 0x1d, 0x35, 0x1f, 0x32, 0x22,	0xa0, 0x2c,

	0x5e, 0x2e, 0x92, 0x2e,	0xf9, 0x2e, 0x43, 0x2f,
	0x59, 0x2f,	0x6f, 0x2f, 0xd1, 0x38, 0xd8, 0x3e,

	0x9e, 0x0d, 0x4c, 0x47, 0x1f, 0x1f,	0x5a, 0x1f,
	0xbe, 0x22, 0xa2, 0x23,	0x33, 0x35, 0x69, 0x34,

	0x7c, 0x3a,	0x00, 0x00, 0xdc, 0x44, 0x78, 0x0b,
	0x65, 0x0d, 0xc4, 0xb2, 0xc4, 0xb2, 0xc4, 0xb2
};

/* input = 0x6007 - data = 0x629b */
static UINT8 mcu_table4[MCU_KEY_TABLE_SIZE] = {
	0xc5, 0x24, 0xc5, 0x24, 0x27, 0x3f,	0xd0, 0x07,
	0x07, 0x0b, 0xd8, 0x02, 0x9a, 0x08, 0x00, 0x00
};

/* input = 0x6007 - data = 0x629b */
static UINT8 mcu_table5[MCU_KEY_TABLE_SIZE] = {
	0x54, 0x43, 0xd0, 0x07, 0xd8, 0x02, 0x9a, 0x08,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x6007 - data = 0x629b */
static UINT8 mcu_table6[MCU_KEY_TABLE_SIZE] = {
	0x2b, 0x03, 0xd0, 0x07, 0xd8, 0x02, 0x9a, 0x08,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x6007 - data = 0x629b */
static UINT8 mcu_table7[MCU_KEY_TABLE_SIZE] = {
	0xfa, 0x0e, 0x9a, 0x08, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x6011 - data = 0x607f */
static UINT8 mcu_table8[MCU_KEY_TABLE_SIZE*2] = {
	0x0b, 0x78, 0x47, 0x04, 0x36, 0x18, 0x23, 0xf1,
	0x10, 0xee, 0x16, 0x04, 0x11, 0x94, 0x16, 0xdd,

	0x13, 0x4e, 0x06, 0xa6, 0x13, 0x12, 0x08, 0x9a,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static void mcu_sort_list( UINT8 *src, UINT8 *dst, UINT8 *table ) {
	int i;

	for ( i = 0; i < 0x20; i++ ) {
		int where = src[i];

		if ( where < 0x20 ) {
			int offs = ( i << 1 );

			where <<= 1;
			dst[where] = table[offs];
			dst[where+1] = table[offs+1];
		}
	}
}

WRITE8_HANDLER( exctsccr_mcu_control_w ) {

	if ( data == 0xff ) { /* goes around the mcu checks */
		exctsccr_mcu_ram[0x0003] = 0x01; /* mcu state = running */

		exctsccr_mcu_ram[0x0005] = 0x08;
		exctsccr_mcu_ram[0x0380] = 0xf1;
		exctsccr_mcu_ram[0x0381] = 0x01;
		exctsccr_mcu_ram[0x02f8] = 0x1f; /* Selects song to play during gameplay */

		exctsccr_mcu_ram[0x0009] = 0x08;
		memcpy( &exctsccr_mcu_ram[0x0170], mcu_table1, MCU_KEY_TABLE_SIZE );

		if ( exctsccr_mcu_ram[0x000d] == 0x01 ) {
			exctsccr_mcu_ram[0x000d] = 0x08;

			memcpy( &exctsccr_mcu_ram[0x01f0], mcu_table2, MCU_KEY_TABLE_SIZE );
		}

		mcu_sort_list( &exctsccr_mcu_ram[0x03e0], &exctsccr_mcu_ram[0x0300], mcu_table3 );

		exctsccr_mcu_ram[0x02fb] = 0x7e;
		exctsccr_mcu_ram[0x02fd] = 0x7e;

		if ( mcu_code_latch ) {
			exctsccr_mcu_ram[0x02f9] = 0x7f;
			exctsccr_mcu_ram[0x02fa] = 0x0d;
			exctsccr_mcu_ram[0x02fc] = 0x05;
			exctsccr_mcu_ram[0x02fe] = 0x01;
		} else {
			exctsccr_mcu_ram[0x02f9] = 0x81;
			exctsccr_mcu_ram[0x02fa] = 0x2d;
			exctsccr_mcu_ram[0x02fc] = 0x25;
			exctsccr_mcu_ram[0x02fe] = 0x09;
		}

		if ( exctsccr_mcu_ram[0x000f] == 0x02 ) {
			exctsccr_mcu_ram[0x000f] = 0x08;
			exctsccr_mcu_ram[0x02f6] = 0xd6;
			exctsccr_mcu_ram[0x02f7] = 0x39;
		}

		if ( exctsccr_mcu_ram[0x0007] == 0x02 ) {
			exctsccr_mcu_ram[0x0007] = 0x08;

			if ( exctsccr_mcu_ram[0x0204] > 3 )
				exctsccr_mcu_ram[0x0204] = 0;

			switch( exctsccr_mcu_ram[0x0204] ) {
				case 0x00:
					memcpy( &exctsccr_mcu_ram[0x029b], mcu_table4, MCU_KEY_TABLE_SIZE );
				break;

				case 0x01:
					memcpy( &exctsccr_mcu_ram[0x029b], mcu_table5, MCU_KEY_TABLE_SIZE );
				break;

				case 0x02:
					memcpy( &exctsccr_mcu_ram[0x029b], mcu_table6, MCU_KEY_TABLE_SIZE );
				break;

				case 0x03:
					memcpy( &exctsccr_mcu_ram[0x029b], mcu_table7, MCU_KEY_TABLE_SIZE );
				break;
			}

			if ( exctsccr_mcu_ram[0x0204] != 3 )
				exctsccr_mcu_ram[0x0204]++;
		}

		exctsccr_mcu_ram[0x0011] = 0x08;
		memcpy( &exctsccr_mcu_ram[0x007f], mcu_table8, MCU_KEY_TABLE_SIZE*2 );
	}
}

WRITE8_HANDLER( exctsccr_mcu_w ) {

	if ( offset == 0x02f9 )
		mcu_code_latch = data;

	exctsccr_mcu_ram[offset] = data;
}


/* Exciting Soccer II */

/* input = 0x6009 - data = 0x6170 */
static UINT8 exctscc2_mcu_table1[MCU_KEY_TABLE_SIZE] = {
	0x56, 0x05, 0x90, 0x08, 0x19, 0x3e,	0xa8, 0x03,
	0x2f, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x600d - data = 0x61f0 */
static UINT8 exctscc2_mcu_table2[MCU_KEY_TABLE_SIZE] = {
	0xff, 0x27, 0x35, 0x10, 0xd9, 0x06, 0xc3, 0x02,
	0x4d, 0x12, 0x9e, 0x09,	0x14, 0x10, 0x24, 0x10
};

/* input = ?????? - data = 0x6300 */
static UINT8 exctscc2_mcu_table3[MCU_KEY_TABLE_SIZE*4] = {
	0x41, 0x29,	0xb2, 0x12, 0x91, 0x26, 0xa6, 0x16, //0x12b2?
	0x5f, 0x20,	0xc4, 0x21, 0xc1, 0x24, 0x3e, 0x2f,

	0x03, 0x31,	0x37, 0x31, 0x9e, 0x31, 0xe8, 0x31,
	0xfe, 0x31,	0x14, 0x32, 0x93, 0x3b, 0xa4, 0x41,

	0x88, 0x0d,	0x55, 0x4b, 0xae, 0x21, 0xe9, 0x21,
	0x4d, 0x25,	0x32, 0x26, 0xd8, 0x37, 0x0e, 0x37,

	0x48, 0x3d,	0x00, 0x00, 0xd5, 0x48, 0x54, 0x0c,
	0xa0, 0x0c,	0xc4, 0xb2, 0xc4, 0xb2, 0xc4, 0xb2 //0x0ca0? //last 3 couples?
};

/* input = 0x6007 - data = 0x629b */
static UINT8 exctscc2_mcu_table4[MCU_KEY_TABLE_SIZE] = {
	0x55, 0x27, 0x55, 0x27, 0xf3, 0x41, 0x65, 0x08,
	0xe3, 0x0b, 0x01, 0x03, 0x2f, 0x09, 0x00, 0x00
};

/* input = 0x6007 - data = 0x629b */
static UINT8 exctscc2_mcu_table5[MCU_KEY_TABLE_SIZE] = {
	0xdd, 0x45, 0x65, 0x08, 0x01, 0x03, 0x2f, 0x09,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x6007 - data = 0x629b */
static UINT8 exctscc2_mcu_table6[MCU_KEY_TABLE_SIZE] = {
	0x54, 0x03, 0x65, 0x08, 0x01, 0x03, 0x2f, 0x09,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x6007 - data = 0x629b */
static UINT8 exctscc2_mcu_table7[MCU_KEY_TABLE_SIZE] = {
	0xe4, 0x0e, 0x2f, 0x09, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* input = 0x6011 - data = 0x607f */
static UINT8 exctscc2_mcu_table8[MCU_KEY_TABLE_SIZE*2] = {
	0x0c, 0x54, 0x4b, 0x0d, 0x38, 0xbd, 0x26, 0x81,
	0x12, 0x37, 0x18, 0x4a, 0x13, 0x0f, 0x19, 0x23,

	0x14, 0xd6, 0x06, 0xd9, 0x14, 0x9a, 0x09, 0x2f,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

WRITE8_HANDLER( exctscc2_mcu_control_w )
{
	if ( data == 0xff )  /* goes around the mcu checks */
	{
		exctsccr_mcu_ram[0x0003] = 0x01; /* mcu state = running */

		exctsccr_mcu_ram[0x0005] = 0x08;
		exctsccr_mcu_ram[0x0380] = 0x1a;
		exctsccr_mcu_ram[0x0381] = 0x02;
		exctsccr_mcu_ram[0x02f8] = 0x1f; /* Selects song to play during gameplay */

		exctsccr_mcu_ram[0x0009] = 0x08;
		memcpy( &exctsccr_mcu_ram[0x0170], exctscc2_mcu_table1, MCU_KEY_TABLE_SIZE );

		if ( exctsccr_mcu_ram[0x000d] == 0x01 ) {
			exctsccr_mcu_ram[0x000d] = 0x08;

			memcpy( &exctsccr_mcu_ram[0x01f0], exctscc2_mcu_table2, MCU_KEY_TABLE_SIZE );
		}

		mcu_sort_list( &exctsccr_mcu_ram[0x03e0], &exctsccr_mcu_ram[0x0300], exctscc2_mcu_table3 );

/* are these right ? */
		exctsccr_mcu_ram[0x02fb] = 0x7e;
		exctsccr_mcu_ram[0x02fd] = 0x7e;

		if ( mcu_code_latch ) {
			exctsccr_mcu_ram[0x02f9] = 0x7f;
			exctsccr_mcu_ram[0x02fa] = 0x0d;
			exctsccr_mcu_ram[0x02fc] = 0x05;
			exctsccr_mcu_ram[0x02fe] = 0x01;
		} else {
			exctsccr_mcu_ram[0x02f9] = 0x81;
			exctsccr_mcu_ram[0x02fa] = 0x2d;
			exctsccr_mcu_ram[0x02fc] = 0x25;
			exctsccr_mcu_ram[0x02fe] = 0x09;
		}
/*******/

		if ( exctsccr_mcu_ram[0x000f] == 0x02 ) {
			exctsccr_mcu_ram[0x000f] = 0x08;
			exctsccr_mcu_ram[0x02f6] = 0x98;
			exctsccr_mcu_ram[0x02f7] = 0x3c;
		}

		if ( exctsccr_mcu_ram[0x0007] == 0x02 ) {
			exctsccr_mcu_ram[0x0007] = 0x08;

			if ( exctsccr_mcu_ram[0x0204] > 3 )
				exctsccr_mcu_ram[0x0204] = 0;

			switch( exctsccr_mcu_ram[0x0204] ) {
				case 0x00:
					memcpy( &exctsccr_mcu_ram[0x029b], exctscc2_mcu_table4, MCU_KEY_TABLE_SIZE );
				break;

				case 0x01:
					memcpy( &exctsccr_mcu_ram[0x029b], exctscc2_mcu_table5, MCU_KEY_TABLE_SIZE );
				break;

				case 0x02:
					memcpy( &exctsccr_mcu_ram[0x029b], exctscc2_mcu_table6, MCU_KEY_TABLE_SIZE );
				break;

				case 0x03:
					memcpy( &exctsccr_mcu_ram[0x029b], exctscc2_mcu_table7, MCU_KEY_TABLE_SIZE );
				break;
			}

			if ( exctsccr_mcu_ram[0x0204] != 3 )
				exctsccr_mcu_ram[0x0204]++;

		}

		exctsccr_mcu_ram[0x0011] = 0x08;
		memcpy( &exctsccr_mcu_ram[0x007f], exctscc2_mcu_table8, MCU_KEY_TABLE_SIZE*2 );
	}
}
