www.pudn.com > ncdzsrc.rar > machine.c


/*************************************************************************** 
 
	machine.c 
 
	NEOGEO CD マシンエミュレーションコア 
 
***************************************************************************/ 
 
#include "neogeocd.h" 
 
#define VERBOSE 0 
#if VERBOSE 
#define LOG(x) logerror x 
#else 
#define LOG(x) 
#endif 
 
 
/**************************************************************************** 
	プロトタイプ 
 ***************************************************************************/ 
 
static void neogeo_run_game(void); 
static void neogeo_run_bios(void); 
 
 
/**************************************************************************** 
	グローバル変数 
 ***************************************************************************/ 
 
int game_index; 
char game_name[16]; 
int driver_type; 
int driver_flag; 
 
 
/**************************************************************************** 
	ローカル変数 
 ***************************************************************************/ 
 
// 外部メモリの転送情報 
static UINT8  exmem[0x100]; 
static UINT8  exmem_latch[0x100]; 
static UINT8  exmem_bank[4]; 
static UINT8  exmem_counter; 
 
// ハードウェア転送情報 
static UINT8  upload_mode; 
static UINT8  upload_type; 
static UINT32 upload_offset1; 
static UINT32 upload_offset2; 
static UINT32 upload_length; 
static UINT16 upload_pattern; 
static int    upload_executing; 
 
#if 1 
static offs_t z80_cdda_offset; 
#endif 
 
static UINT8 neogeo_game_vectors[0x100]; 
 
#if ENABLE_SYSTEM_CHECK 
static int system_check = 1; 
#endif 
 
#include "binary/startup.c" // startup.bin 
 
 
/*************************************************************************** 
	グローバル関数 
 ***************************************************************************/ 
 
/*------------------------------------------------------ 
 
	NEOGEO CDのエミュレーションを実行 
 
	引  数: なし 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
void neogeo_run(void) 
{ 
	FILE *fp; 
	UINT16 *mem16; 
	time_t ltime; 
	struct tm *today; 
	int region = options.region & 0x03; 
 
	// CPUのメモリ初期化 
	memset(memory_region(REGION_CPU1), 0, memory_region_length(REGION_CPU1)); 
	memset(memory_region(REGION_CPU2), 0, memory_region_length(REGION_CPU2)); 
	memset(memory_region(REGION_USER3), 0, memory_region_length(REGION_USER3)); 
 
	// 起動時のメモリ状態データ書き込み 
	swab(startup_bin, memory_region(REGION_CPU1) + 0x10f300, 0x0d00); 
 
	// 外部メモリの転送情報をクリア 
	memset(exmem, 0xff, 0x100); 
	memset(exmem_latch, 0xff, 0x100); 
	memset(exmem_bank, 0, 4); 
	exmem_counter = 0; 
 
	// ハードウェア転送情報をクリア 
	upload_mode      = UPLOAD_IMMIDIATE; 
	upload_type      = UNKNOWN_TYPE; 
	upload_offset1   = 0; 
	upload_offset2   = 0; 
	upload_length    = 0; 
	upload_pattern   = 0; 
	upload_executing = 0; 
 
#if 1 
	z80_cdda_offset = 0; 
#endif 
 
	// BIOSにパッチを当てて動作をフックする 
	mem16 = (UINT16 *)memory_region(REGION_USER1); 
 
	// ファイル読み込み 
	mem16[0xdb70 >> 1] = 0xfac0; 
	mem16[0xdb72 >> 1] = 0x4e75; 
 
	// 入力受付フラグのクリアを無効に 
	mem16[0xb040 >> 1] = 0x4e71; 
	mem16[0xb042 >> 1] = 0x4e71; 
 
	// CDDAチェック 
	mem16[0x056a >> 1] = 0xfac1; 
	mem16[0x056c >> 1] = 0x4e75; 
 
	// リセット 
	mem16[0xa87a >> 1] = 0x4239; 
	mem16[0xa87c >> 1] = 0x0010; 
	mem16[0xa87e >> 1] = 0xfdae; 
 
#if ENABLE_SYSTEM_CHECK 
	// システムチェック 
	mem16[0xab5e >> 1] = 0x4e71; 
	mem16[0xab60 >> 1] = 0x4e71; 
	m68000_write_memory_8(0x108000 + 0x73d8, 0x05); 
#endif 
 
	// カレンダ設定 (設定しても意味なし) 
	time(<ime); 
	today = localtime(<ime); 
	pd4990a.seconds = ((today->tm_sec/10)<<4) + (today->tm_sec%10); 
	pd4990a.minutes = ((today->tm_min/10)<<4) + (today->tm_min%10); 
	pd4990a.hours   = ((today->tm_hour/10)<<4) + (today->tm_hour%10); 
	pd4990a.days    = ((today->tm_mday/10)<<4) + (today->tm_mday%10); 
	pd4990a.month   = (today->tm_mon + 1); 
	pd4990a.year    = (((today->tm_year%100)/10)<<4) + (today->tm_year%10); 
	pd4990a.weekday = today->tm_wday; 
 
	// 言語設定を初期化 
	m68000_write_memory_16(0xff011c, ~(region << 8)); 
 
	// VRAMクリア 
	neogeo_clear_vram(); 
 
	// バックアップメモリ読み込み 
	fp = fopen("backup.bin", "rb"); 
	if (fp != NULL) 
	{ 
		fread(memory_region(REGION_USER2), 1, 0x2000, fp); 
		fclose(fp); 
		logerror("Backup memory loaded.\n"); 
	} 
 
	if (game_index >= 0) 
	{ 
		// ゲームを起動 
		neogeo_run_game(); 
	} 
 
	if (game_index < 0) 
	{ 
		// BIOS起動かゲームの実行失敗 
		neogeo_run_bios(); 
	} 
 
	// バックアップメモリ書き込み 
	fp = fopen("backup.bin", "wb"); 
	if (fp != NULL) 
	{ 
		fwrite(memory_region(REGION_USER2), 1, 0x2000, fp); 
		fclose(fp); 
		logerror("Backup memory saved.\n"); 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	NEOGEO CDのゲームを起動 
 
	引  数: なし 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static void neogeo_run_game(void) 
{ 
	int result; 
	UINT16 *mem16 = (UINT16 *)memory_region(REGION_CPU1); 
 
	// ゲーム番号が0以上のときはゲーム起動 
	strcpy(game_name, games[game_index].name); 
	driver_type = games[game_index].driver; 
	driver_flag = games[game_index].flag; 
 
	options.raster = (driver_type > 1) ? 1 : 0; 
 
	// 初期値設定 
	m68000_write_memory_32(0x120002, 0xffffffff); 
	m68000_write_memory_32(0x11c808, 0xc0c760);	// 初期化 
	m68000_write_memory_32(0x11c80c, 0xc0c814);	// プログレスバー 
	m68000_write_memory_32(0x11c810, 0xc190e2);	// アニメデータ 
 
	// IPL.TXTを処理 
	if ((result = cdrom_process_ipl()) == 1) 
	{ 
		options_type save_options; 
 
		// デフォルトの設定保存 
		memcpy(&save_options, &options, sizeof(options_type)); 
 
		// 個別設定読み込み 
		load_game_config(); 
 
		// 入力デバイスの個別設定を反映 
		input_reset(); 
 
		// ベクタテーブル保存 
		memcpy(neogeo_game_vectors, memory_region(REGION_CPU1), 0x100); 
 
		if (driver_flag & PATCH_SSRPG) 
		{ 
			// 真説サムライスピリッツ専用 
			// EXT_SYS.PRGにパッチを当てる 
 
			// 標準のファイル読み込みルーチンに変更 
			mem16[0x132020 >> 1] = 0x4ef9; 
			mem16[0x132022 >> 1] = 0x00c0; 
			mem16[0x132024 >> 1] = 0xdb60; 
 
			mem16[0x132026 >> 1] = 0x4ef9; 
			mem16[0x132028 >> 1] = 0x00c0; 
			mem16[0x13202a >> 1] = 0xdb6a; 
		} 
 
		// CDDAを初期化 
		neogeo_cdda_init(); 
 
		//------------- ゲーム起動 ----------------- 
		cpu_run(); 
		//------------- ゲーム終了 ----------------- 
 
		// CDDAを終了 
		neogeo_cdda_exit(); 
 
		// 個別設定保存 
		save_game_config(); 
 
		// デフォルトの設定に戻す 
		memcpy(&options.key, &save_options.key, sizeof(options.key)); 
		memcpy(&options.joyid, &save_options.joyid, sizeof(options.joyid)); 
		memcpy(&options.joy, &save_options.joy, sizeof(options.joy)); 
		memcpy(&options.hotkey, &save_options.hotkey, sizeof(options.hotkey)); 
 
		// 入力デバイスのデフォルトの設定を反映 
		input_reset(); 
	} 
	else 
	{ 
		// 失敗したらBIOSを起動 
		if (result == 0) 
		{ 
			// 中断でない時はメッセージ表示 
			osd_show_message("ERROR: could not to process IPL.TXT."); 
		} 
		game_index = -1; 
		cdrom_current_drive = -1; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	NEOGEO CDのBIOSを起動 
 
	引  数: なし 
	戻り値: なし 
 
   ※ BIOS起動時はCDDAを初期化しません 
 
 -----------------------------------------------------*/ 
 
static void neogeo_run_bios(void) 
{ 
	// BIOSシミュレーションを再初期化 
	bios_init(); 
 
	neogeo_set_title(); 
 
	// ドライバ設定初期化 
	strcpy(game_name, "neogeocd"); 
	driver_type = NEOGEO; 
	driver_flag = 0; 
 
	// ベクタテーブル保存 (テストモード用) 
	memcpy(neogeo_game_vectors, memory_region(REGION_USER1), 0x100); 
 
	//------------- BIOS起動 ----------------- 
	cpu_run(); 
	//------------- BIOS終了 ----------------- 
 
	// 念の為CDDAを終了 
	osd_cdda_exit(); 
} 
 
 
/*------------------------------------------------------ 
 
	NEOGEO CDのハードウェアをリセット 
 
	引  数: なし 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
void neogeo_reset(void) 
{ 
	if (cdrom_loading_state == CDROM_LOADING) 
	{ 
		// ロード中の場合は強制停止 
		cdrom_abort_loading(); 
		cdrom_loading_state = CDROM_IDLE; 
	} 
 
	// ゲーム起動中の場合 
	if (game_index >= 0) 
	{ 
		if (cpu_reset_flag == 0) 
		{ 
			m68000_set_reg(M68K_PC, 0xc0a822); 
 
			m68000_write_memory_32(0x108000 + 0x76ee, m68000_read_memory_32(0x68)); 
 
//			m68000_write_memory_32(0x108000 + 0x767c, 0xffffd642); //不明:餓狼スペシャル修正 
			m68000_write_memory_8(0x108000 + 0x76d9, 0x01); 
			m68000_write_memory_8(0x108000 + 0x76c3, 0x01); 
			m68000_write_memory_8(0x108000 + 0x764b, 0xff); 
			m68000_write_memory_8(0x108000 + 0x76f6, 0xff); 
			m68000_write_memory_8(0x108000 + 0x7e85, 0x01); 
			m68000_write_memory_8(0x108000 + 0x7d83, options.region & 0x03); 
		} 
		else 
		{ 
			m68000_set_reg(M68K_PC, 0x000122); 
 
			// メモリをリセット 
			m68000_write_memory_8(0x108000 + 0x7d80, 0x82); 
			m68000_write_memory_8(0x108000 + 0x7daf, 0x01); 
			m68000_write_memory_8(0x108000 + 0x7ee1, 0x0a); 
			m68000_write_memory_8(0x108000 + 0x7675, 0x01); 
			m68000_write_memory_8(0x108000 + 0x7ebf, 0x00); 
			m68000_write_memory_32(0x108000 + 0x7db6, 0); 
			m68000_write_memory_32(0x108000 + 0x7dba, 0); 
 
#if ENABLE_SYSTEM_CHECK 
			if (m68000_read_memory_8(0x108000 + 0x73d8) != 0x05) 
			{ 
				m68000_write_memory_8(0x108000 + 0x73d8, 0x00); 
				system_check = 0; 
			} 
#endif 
		} 
	} 
 
	// ドライバをリセット 
	neogeo_driver_reset(); 
 
	// 画面処理をリセット 
	neogeo_video_reset(); 
 
	// CDDAをリセット 
	neogeo_cdda_reset(); 
 
	// BIOSシミュレートを初期化 
	if (game_index < 0) 
		bios_init(); 
 
	neogeo_set_title(); 
} 
 
 
/*------------------------------------------------------ 
 
	スプライトのデコード 
 
	引  数: UINT8 *mem     SPRのメモリ 
	        offs_t offset  デコード開始オフセット 
	        UINT32 length  データ長(バイト) 
	        int usage_no   透過フラグの番号 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
#define decode_spr(n, s)						\ 
{												\ 
	*dst |= (*(s) & 0x01) << ((n +  0) - 0);	\ 
	*dst |= (*(s) & 0x02) << ((n +  4) - 1);	\ 
	*dst |= (*(s) & 0x04) << ((n +  8) - 2);	\ 
	*dst |= (*(s) & 0x08) << ((n + 12) - 3);	\ 
	*dst |= (*(s) & 0x10) << ((n + 16) - 4);	\ 
	*dst |= (*(s) & 0x20) << ((n + 20) - 5);	\ 
	*dst |= (*(s) & 0x40) << ((n + 24) - 6);	\ 
	*dst |= (*(s) & 0x80) << ((n + 28) - 7);	\ 
	(s)++;										\ 
} 
 
void neogeo_decode_spr(UINT8 *mem, offs_t offset, UINT32 length) 
{ 
	UINT8 buf[128], *usage; 
	UINT32 *dst; 
	int i, j, k; 
 
	dst = (UINT32 *)(mem + offset); 
 
	usage = video_spr_usage + (offset >> 7); 
 
	for (i = 0; i < length; i += 128) 
	{ 
		int opaque = 0; 
		UINT8 *src, *src2; 
 
		memcpy(buf, dst, 128); 
 
		src = buf; 
		src2 = buf + 64; 
 
		for (j = 0; j < 16; j++) 
		{ 
			*dst = 0; 
			decode_spr(1, src2); 
			decode_spr(0, src2); 
			decode_spr(3, src2); 
			decode_spr(2, src2); 
			for (k = 0; k < 32; k += 4) 
				opaque += (*dst & (0x0f << k)) != 0; 
			dst++; 
 
			*dst = 0; 
			decode_spr(1, src); 
			decode_spr(0, src); 
			decode_spr(3, src); 
			decode_spr(2, src); 
			for (k = 0; k < 32; k += 4) 
				opaque += (*dst & (0x0f << k)) != 0; 
			dst++; 
		} 
 
		if (opaque) 
			*usage = (opaque == 256) ? 1 : 2; 
		else 
			*usage = 0; 
		usage++; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	固定スプライトのデコード 
 
	引  数: UINT8 *mem     FIXのメモリ 
	        offs_t offset  デコード開始オフセット 
	        UINT32 length  データ長 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
#define decode_fix(n)				\ 
{									\ 
	tile = buf[n];					\ 
	*mem++ = tile;					\ 
	opaque += (tile & 0x0f) != 0;	\ 
	opaque += (tile >> 4) != 0;		\ 
} 
 
void neogeo_decode_fix(UINT8 *mem, offs_t offset, UINT32 length) 
{ 
	int i, j; 
	UINT8 tile, opaque; 
	UINT8 buf[32], *usage; 
 
	mem += (offset >> 1); 
	usage = video_fix_usage + (offset >> 6); 
 
	for (i = 0; i < length; i += 32) 
	{ 
		opaque  = 0; 
 
		memcpy(buf, mem, 32); 
 
		for (j = 0; j < 8; j++) 
		{ 
			decode_fix(j + 16); 
			decode_fix(j + 24); 
			decode_fix(j +  0); 
			decode_fix(j +  8); 
		} 
 
		if (opaque) 
			*usage = (opaque == 64) ? 1 : 2; 
		else 
			*usage = 0; 
		*usage++; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	固定スプライトの復元 
 
	引  数: UINT8 *mem     FIXのメモリ 
	        offs_t offset  デコード開始オフセット 
	        UINT32 length  データ長 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
#define undecode_fix(n)				\ 
{									\ 
	tile = *(mem2 + (ofs++));		\ 
	buf[n] = tile;					\ 
} 
 
void neogeo_undecode_fix(UINT8 *mem, offs_t offset, UINT32 length) 
{ 
	int i, j, ofs; 
	UINT8 tile; 
	UINT8 buf[32]; 
	UINT8 *mem2 = mem + offset; 
 
	for (i = 0; i < length; i += 32) 
	{ 
		ofs = 0; 
 
		for (j = 0; j < 8; j++) 
		{ 
			undecode_fix(j + 16); 
			undecode_fix(j + 24); 
			undecode_fix(j +  0); 
			undecode_fix(j +  8); 
		} 
 
		memcpy(mem2, buf, 32); 
 
		mem2 += 32; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	Z80のパッチ反映 
 
	引  数: UINT16 *src    PATファイルを読み込んだメモリ 
	        int bank       バンク 
	        offs_t offset  オフセット 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
#define PATCH_Z80(a, b)					\ 
{										\ 
	dst[((a) + 0)] =  (b)       & 0xff;	\ 
	dst[((a) + 1)] = ((b) >> 8) & 0xff;	\ 
} 
 
void neogeo_apply_patch(UINT16 *src, int bank, offs_t offset) 
{ 
	UINT8 *dst = memory_region(REGION_CPU2); 
 
	offset = (((bank * 0x100000) + offset) >> 8) & 0xffff; 
 
	while (*src) 
	{ 
		PATCH_Z80(src[0] + 0,  (src[1] + offset) >> 1); 
		PATCH_Z80(src[0] + 2, ((src[2] + offset) >> 1) - 1); 
 
		if (src[3] && src[4]) 
		{ 
			PATCH_Z80(src[0] + 5,  (src[3] + offset) >> 1); 
			PATCH_Z80(src[0] + 7, ((src[4] + offset) >> 1) - 1); 
		} 
 
		src += 5; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	ベクタテーブル書き換え(BIOS) 
 
	引  数: offs_t offset  オフセット(未使用) 
			UINT16 datat   データ(未使用) 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
WRITE16_HANDLER( neogeo_select_bios_vectors ) 
{ 
	UINT8 *gamerom = memory_region(REGION_CPU1); 
	UINT8 *biosrom = memory_region(REGION_USER1); 
 
	memcpy(gamerom, biosrom, 0x100); 
} 
 
 
/*------------------------------------------------------ 
 
	ベクタテーブル書き換え(ゲーム) 
 
	引  数: offs_t offset  オフセット(未使用) 
			UINT16 datat   データ(未使用) 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
WRITE16_HANDLER( neogeo_select_game_vectors ) 
{ 
	UINT8 *gamerom = memory_region(REGION_CPU1); 
 
	memcpy(gamerom, neogeo_game_vectors, 0x100); 
} 
 
 
/*------------------------------------------------------ 
 
	バックアップメモリリード ($800000 - $803fff) 
 
	引  数: offs_t offset  読み込むオフセット 
	戻り値: 読み込んだデータ 
 
 -----------------------------------------------------*/ 
 
READ16_HANDLER( neogeo_memcard16_r ) 
{ 
	UINT8 *mem = memory_region(REGION_USER2); 
 
	offset &= 0x1fff; 
	return mem[offset] | 0xff00; 
} 
 
 
/*------------------------------------------------------ 
 
	バックアップメモリライト ($800000 - $803fff) 
 
	引  数: offs_t offset  書き込むオフセット 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
WRITE16_HANDLER( neogeo_memcard16_w ) 
{ 
	if (ACCESSING_LSB) 
	{ 
		UINT8 *mem = memory_region(REGION_USER2); 
 
		offset &= 0x1fff; 
		mem[offset] = data & 0xff; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	外部メモリリード  ($e000000 - $efffff) 
 
	引  数: offs_t offset  読み込むオフセット 
	戻り値: 各メモリのデータ 
 
 -----------------------------------------------------*/ 
 
READ16_HANDLER( neogeo_externalmem_16_r ) 
{ 
	UINT8 *src; 
	UINT16 retdata = 0xffff; 
 
	offset -= (0xe00000 >> 1); 
 
	switch (exmem[exmem_counter]) 
	{ 
	case EXMEM_OBJ: 
		src = memory_region(REGION_GFX2); 
		offset  = (offset << 1) + (exmem_bank[EXMEM_OBJ] << 20); 
		retdata = (src[offset] << 8) | src[offset + 1]; 
		break; 
 
	case EXMEM_PCMA: 
		src = memory_region(REGION_SOUND1); 
		offset  = offset + (exmem_bank[EXMEM_PCMA] << 19); 
		retdata = src[offset] | 0xff00; 
		break; 
 
	case EXMEM_Z80: 
#if 1 
		if (z80_cdda_offset) 
		{ 
			if (offset == z80_cdda_offset || offset == z80_cdda_offset + 1) 
			{ 
				// 読み込むと問題が起こる場合があるので、とりあえず無視 
				return 0; 
			} 
		} 
#endif 
		src = memory_region(REGION_CPU2); 
		retdata = src[offset] | 0xff00; 
		break; 
 
	case EXMEM_FIX: 
		src = memory_region(REGION_GFX1); 
		retdata = src[offset] | 0xff00; 
		break; 
	} 
 
	return retdata; 
} 
 
 
/*------------------------------------------------------ 
 
	外部メモリライト  ($e000000 - $efffff) 
 
	引  数: offs_t offset  書き込むオフセット 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
WRITE16_HANDLER( neogeo_externalmem_16_w ) 
{ 
	UINT8 *dst; 
 
	offset -= (0xe00000 >> 1); 
 
	switch (exmem[exmem_counter]) 
	{ 
	case EXMEM_OBJ: 
		offset = (offset << 1) + (exmem_bank[EXMEM_OBJ] << 20); 
		data = (data << 8) | (data >> 8); 
		dst = memory_region(REGION_GFX2); 
		COMBINE_SWABDATA((UINT16 *)(dst + offset)); 
#if ENABLE_SYSTEM_CHECK 
		dst = memory_region(REGION_GFX6); 
		COMBINE_SWABDATA((UINT16 *)(dst + offset)); 
#endif 
		if ((offset & 0x7f) == 0x7e) 
			neogeo_decode_spr(dst, (offset & ~0x7f), 128); 
		return; 
 
	case EXMEM_PCMA: 
		dst = memory_region(REGION_SOUND1); 
		offset += exmem_bank[EXMEM_PCMA] << 19; 
		dst[offset] = data & 0xff; 
		return; 
 
	case EXMEM_Z80: 
#if 1 
		if (z80_cdda_offset) 
		{ 
			if (offset == z80_cdda_offset || offset == z80_cdda_offset + 1) 
			{ 
				// 書き込むと問題が起こる場合があるので、とりあえず無視 
				return; 
			} 
		} 
#endif 
		dst = memory_region(REGION_CPU2); 
		dst[offset] = data & 0xff; 
		return; 
 
	case EXMEM_FIX: 
		dst = memory_region(REGION_GFX1); 
		dst[offset] = data & 0xff; 
#if ENABLE_SYSTEM_CHECK 
		dst = memory_region(REGION_GFX5); 
		dst[offset] = data & 0xff; 
#endif 
		if ((offset & 0x1f) == 0x1f) 
			neogeo_decode_fix(dst, (offset & ~0x1f) << 1, 32); 
		return; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	ハードウェア制御データ読み込み 
 
	引  数: offs_t offset  読み込むオフセット 
	戻り値: 各メモリのデータ 
 
 -----------------------------------------------------*/ 
 
READ16_HANDLER( neogeo_hardcontrol_16_r ) 
{ 
	UINT16 *mem = (UINT16 *)memory_region(REGION_USER3); 
 
	LOG(("neogeo_hardcontrol_16_r(): offset = %06x\n", offset << 1)); 
 
	offset &= 0xff; 
 
	return mem[offset]; 
} 
 
 
/*------------------------------------------------------ 
 
	ハードウェアデータ転送  ($ff0060 - $ff0061) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( hardware_upload_16_w ) 
{ 
	if (data == 0x00)	// ハードウェア転送情報クリア 
	{ 
		upload_mode    = UPLOAD_IMMIDIATE; 
		upload_offset1 = 0; 
		upload_offset2 = 0; 
		upload_length  = 0; 
	} 
	else if (data == 0x40)	// ハードウェア転送実行 
	{ 
		int i; 
		UINT8 *src, *dst; 
 
		if (upload_mode == UPLOAD_MEMORY) 
		{ 
			upload_type = upload_get_type() & 0x0f; 
		} 
		else 
		{ 
			if (upload_offset1 >= 0x000000 && upload_offset1 < 0x200000) 
			{ 
				upload_type = PRG_TYPE; 
			} 
			else if (upload_offset1 >= 0x400000 && upload_offset1 < 0x500000) 
			{ 
				upload_type = PAL_TYPE; 
			} 
			else if (upload_offset1 >= 0x800000 && upload_offset1 < 0x804000) 
			{ 
				upload_type = BACKUP_RAM; 
			} 
			else	// 0xe00000 
			{ 
				switch (exmem[exmem_counter]) 
				{ 
				case EXMEM_OBJ:  upload_type = SPR_TYPE; break; 
				case EXMEM_PCMA: upload_type = PCM_TYPE; break; 
				case EXMEM_Z80:  upload_type = Z80_TYPE; break; 
				case EXMEM_FIX:  upload_type = FIX_TYPE; break; 
				} 
			} 
		} 
 
#if 0 
		logerror("\nhardware upload\n"); 
 
		logerror(" mode = "); 
		switch (upload_mode) 
		{ 
		case UPLOAD_IMMIDIATE: logerror("IMMIDIATE\n"); break; 
		case UPLOAD_PATTERN: logerror("PATTERN\n"); break; 
		case UPLOAD_MEMORY: logerror("MEMORY\n"); break; 
		case UPLOAD_FILE: logerror("FILE\n"); break; 
		} 
 
		logerror(" type = "); 
		switch (upload_type) 
		{ 
		case PRG_TYPE: logerror("MAIN\n"); break; 
		case FIX_TYPE: logerror("FIX\n"); break; 
		case SPR_TYPE: logerror("OBJ\n"); break; 
		case Z80_TYPE: logerror("Z80\n"); break; 
		case PCM_TYPE: logerror("PCM-A\n"); break; 
		case PAL_TYPE: logerror("PALETTE\n"); break; 
		case BACKUP_RAM: logerror("BACKUP\n"); break; 
		default: logerror("UNKNOWN\n"); break; 
		} 
 
		if (upload_mode == UPLOAD_MEMORY) 
		{ 
			logerror(" offset1(src) = %06x\n", upload_offset1); 
			logerror(" offset2(dst) = %06x\n", upload_offset2); 
 
			if (upload_type == SPR_TYPE || upload_type == PCM_TYPE) 
				logerror(" bank = %x\n", upload_get_bank()); 
		} 
		else 
		{ 
			logerror(" offset(dst) = %06x\n", upload_offset1); 
 
			if (upload_type == SPR_TYPE) logerror(" bank = %x\n", exmem_bank[EXMEM_OBJ]); 
			if (upload_type == PCM_TYPE) logerror(" bank = %x\n", exmem_bank[EXMEM_PCMA]); 
		} 
 
		logerror(" length = %x\n", upload_length); 
 
		if (upload_mode == UPLOAD_PATTERN) 
			logerror(" pattern = %04x\n", upload_pattern); 
 
		logerror("\n"); 
#endif 
 
		switch (upload_mode) 
		{ 
#if ENABLE_SYSTEM_CHECK 
		case UPLOAD_IMMIDIATE: 
			{ 
				// 即値(アドレスの値のみっぽい)転送モード 
				// テストモードで使用、ゲームでは使用されていないと思われる 
 
				switch (upload_type) 
				{ 
				case FIX_TYPE: 
				case Z80_TYPE: 
				case PCM_TYPE: 
				case BACKUP_RAM: 
					for (i = 0; i < upload_length; i++) 
					{ 
						offset = upload_offset1 + (i * 8); 
						m68000_write_memory_16(offset + 0, ((offset >> 24) & 0xff) | 0xff00); 
						m68000_write_memory_16(offset + 2, ((offset >> 16) & 0xff) | 0xff00); 
						m68000_write_memory_16(offset + 4, ((offset >>  8) & 0xff) | 0xff00); 
						m68000_write_memory_16(offset + 6, ((offset >>  0) & 0xff) | 0xff00); 
					} 
					break; 
 
				case PRG_TYPE: 
				case PAL_TYPE: 
				case SPR_TYPE: 
					for (i = 0; i < upload_length; i++) 
					{ 
						offset = upload_offset1 + (i * 4); 
						m68000_write_memory_32(offset, offset); 
					} 
					break; 
				} 
			} 
			break; 
#endif 
 
		case UPLOAD_PATTERN: 
			{ 
				// パターン転送モード 
				// テストモードとパレットのクリアで使用 
 
				switch (upload_type) 
				{ 
				case FIX_TYPE: 
				case Z80_TYPE: 
				case PCM_TYPE: 
				case BACKUP_RAM: 
					for (i = 0; i < upload_length; i++) 
					{ 
						offset = upload_offset1 + (i * 2); 
						m68000_write_memory_16(offset, (upload_pattern & 0xff) | 0xff00); 
					} 
					break; 
 
				case PRG_TYPE: 
				case PAL_TYPE: 
				case SPR_TYPE: 
					for (i = 0; i < upload_length; i++) 
					{ 
						offset = upload_offset1 + (i * 2); 
						m68000_write_memory_16(offset, upload_pattern); 
					} 
					break; 
				} 
			} 
			break; 
 
		case UPLOAD_MEMORY: 
			{ 
				// メモリ転送モード 
				UINT32 length; 
 
				length = upload_length << 1; 
				src = memory_region(REGION_CPU1) + upload_offset1; 
 
				switch (upload_type & 0x0f) 
				{ 
				case PRG_TYPE: 
					dst = memory_region(REGION_CPU1); 
					memcpy(dst + upload_offset2, src, length); 
					break; 
 
				case FIX_TYPE: 
					dst = memory_region(REGION_GFX1); 
					offset = upload_offset2 - 0xe00000; 
					swab(src, dst + (offset >> 1), length); 
#if ENABLE_SYSTEM_CHECK 
					dst = memory_region(REGION_GFX5); 
					swab(src, dst + (offset >> 1), length); 
#endif 
					neogeo_decode_fix(dst, offset, length); 
					break; 
 
				case SPR_TYPE: 
					dst = memory_region(REGION_GFX2); 
					offset = (upload_offset2 - 0xe00000) + (upload_get_bank() << 20); 
					swab(src, dst + offset, length); 
#if ENABLE_SYSTEM_CHECK 
					dst = memory_region(REGION_GFX6); 
					swab(src, dst + offset, length); 
#endif 
					neogeo_decode_spr(dst, offset, length); 
					exmem_bank[EXMEM_OBJ] = ((offset + upload_get_length()) >> 20) & 0x03; 
					break; 
 
				case Z80_TYPE: 
					dst = memory_region(REGION_CPU2); 
					offset = upload_offset2 - 0xe00000; 
					swab(src, dst + (offset >> 1), length); 
					break; 
 
				case PAL_TYPE: 
					for (i = 0; i < length; i++) 
					{ 
						data = m68000_read_memory_16(upload_offset1 + i * 2); 
						m68000_write_memory_16(upload_offset2 + i * 2, data); 
					} 
					break; 
				} 
			} 
			break; 
 
		case UPLOAD_FILE: 
			// ファイル転送モード 
			// 現状はcdrom_load_files()で処理 
			break; 
		} 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	転送オフセット1設定   ($ff0064 - $ff0065) 
	                      ($ff0066 - $ff0067) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
  ※ 転送モードが即値、パターンの場合は転送先オフセット 
     メモリ転送の場合は転送元オフセット 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( upload_offset1_16_w ) 
{ 
	if (offset) 
		upload_offset1 = (upload_offset1 & 0xffff0000) | (UINT32)data; 
	else 
		upload_offset1 = (upload_offset1 & 0x0000ffff) | ((UINT32)data << 16); 
} 
 
 
/*------------------------------------------------------ 
 
	転送オフセット2設定   ($ff0068 - $ff0069) 
	                      ($ff006a - $ff006b) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
   ※ メモリ転送モードの転送先オフセット 
      この値が設定された場合は、メモリ転送モード 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( upload_offset2_16_w ) 
{ 
	if (offset) 
		upload_offset2 = (upload_offset2 & 0xffff0000) | (UINT32)data; 
	else 
		upload_offset2 = (upload_offset2 & 0x0000ffff) | ((UINT32)data << 16); 
 
	upload_mode = UPLOAD_MEMORY; 
} 
 
 
/*------------------------------------------------------ 
 
	転送パターン設定 ($ff006c - $ff006d) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
   ※ この値が設定された場合は、パターン転送モード 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( upload_pattern_16_w ) 
{ 
	upload_pattern = data; 
	upload_mode = UPLOAD_PATTERN; 
} 
 
 
/*------------------------------------------------------ 
 
	転送データ長設定 ($ff0070 - $ff0071) 
	                 ($ff0072 - $ff0073) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( upload_length_16_w ) 
{ 
	if (offset) 
		upload_length = (upload_length & 0xffff0000) | (UINT32)data; 
	else 
		upload_length = (upload_length & 0x0000ffff) | ((UINT32)data << 16); 
} 
 
 
/*------------------------------------------------------ 
 
	外部メモリ転送タイプ設定 ($ff0105) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( exmem_type_16_w ) 
{ 
	exmem[exmem_counter] = data; 
 
#if 1 
	if (exmem[exmem_counter] == EXMEM_Z80) 
	{ 
		z80_cdda_offset = m68000_read_memory_32(0x108000 + 0x76ea); 
		if (z80_cdda_offset) 
			z80_cdda_offset = (z80_cdda_offset - 0xe00000) >> 1; 
	} 
#endif 
 
	if (exmem[exmem_counter] == EXMEM_OBJ) exmem_bank[EXMEM_OBJ] = 0; 
	if (exmem[exmem_counter] == EXMEM_PCMA) exmem_bank[EXMEM_PCMA] = 0; 
} 
 
 
/*------------------------------------------------------ 
 
	SPR描画停止 ($ff0111) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( spr_disable_16_w ) 
{ 
	spr_disable = data & 0xff; 
} 
 
 
/*------------------------------------------------------ 
 
	FIX描画停止 ($ff0115) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( fix_disable_16_w ) 
{ 
	fix_disable = data & 0xff; 
} 
 
 
/*------------------------------------------------------ 
 
	ビデオ出力有効 ($ff0119) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( video_enable_16_w ) 
{ 
	video_enable = data & 0xff; 
} 
 
 
/*------------------------------------------------------ 
 
	外部メモリ転送番号設定  ($ff0121) - OBJ RAM 
	                        ($ff0123) - PCM-A RAM 
	                        ($ff0127) - Z80 RAM 
	                        ($ff0129) - FIX RAM 
 
	引  数: offs_t offset  書き込むオフセット 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
  ※本来であれば、該当するメモリのアクセスを無効に 
    しているはず 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( exmem_latch_16_w ) 
{ 
	exmem_counter++; 
	exmem_latch[exmem_counter] = offset & 0x0f; 
 
#if ENABLE_SYSTEM_CHECK 
	if (system_check && exmem_latch[exmem_counter] == 0x03) 
		z80_reset(0); 
#endif 
} 
 
 
/*------------------------------------------------------ 
 
	外部メモリ転送番号消去  ($ff0141) - OBJ RAM 
	                        ($ff0143) - PCM-A RAM 
	                        ($ff0147) - Z80 RAM 
	                        ($ff0149) - FIX RAM 
 
	引  数: offs_t offset  書き込むオフセット 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
  ※本来であれば、該当するメモリのアクセス無効を 
    解除しているはず 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( exmem_latch_clear_16_w ) 
{ 
	offset &= 0x0f; 
 
	if (exmem_latch[exmem_counter] == offset) 
	{ 
#if ENABLE_SYSTEM_CHECK 
		if (system_check && exmem_latch[exmem_counter] == 0x03) 
			z80_enable(1); 
#endif 
		exmem_latch[exmem_counter] = EXMEM_UNKNOWN; 
		exmem_counter--; 
	} 
} 
 
 
/*------------------------------------------------------ 
 
	転送フラグ設定 ($ff0161) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( upload_executing_16_w ) 
{ 
	upload_executing = data & 0xff; 
} 
 
 
/*------------------------------------------------------ 
 
	Z80リセット/イネーブル ($ff0183) 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( z80_enable_16_w ) 
{ 
	if (data & 0xff) 
		z80_enable(1); 
	else 
		z80_reset(0); 
} 
 
 
/*------------------------------------------------------ 
 
	外部メモリ転送バンク設定   ($ff01a1) - OBJ RAM 
	                           ($ff01a3) - PCM-A RAM 
 
	引  数: offs_t offset  書き込むオフセット (未使用) 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
static WRITE16_HANDLER( exmem_bank_16_w ) 
{ 
	offset &= 0x0f; 
	exmem_bank[offset] = data & 0x03; 
} 
 
 
/*------------------------------------------------------ 
 
	ハードウェア制御データ書き込み 
 
	引  数: offs_t offset  書き込むオフセット 
			UINT16 datat   書き込むデータ 
	戻り値: なし 
 
 -----------------------------------------------------*/ 
 
WRITE16_HANDLER( neogeo_hardcontrol_16_w ) 
{ 
	UINT16 *mem = (UINT16 *)memory_region(REGION_USER3); 
 
	offset &= 0xff; 
 
	switch (offset << 1) 
	{ 
	case 0x00: break; // unknown 
	case 0x02: break; // unknown 
	case 0x04: break; // unknown 
	case 0x06: break; // unknown 
 
	case 0x60: hardware_upload_16_w(0, data, mem_mask); break; 
	case 0x64: upload_offset1_16_w(0, data, mem_mask); break; 
	case 0x66: upload_offset1_16_w(1, data, mem_mask); break; 
	case 0x68: upload_offset2_16_w(0, data, mem_mask); break; 
	case 0x6a: upload_offset2_16_w(1, data, mem_mask); break; 
	case 0x6c: upload_pattern_16_w(0, data, mem_mask); break; 
	case 0x70: upload_length_16_w(0, data, mem_mask); break; 
	case 0x72: upload_length_16_w(1, data, mem_mask); break; 
 
	case 0x7e: break;	// unknown 
	case 0x80: break;	// unknown 
	case 0x82: break;	// unknown 
	case 0x84: break;	// unknown 
	case 0x86: break;	// unknown 
	case 0x88: break;	// unknown 
	case 0x8a: break;	// unknown 
	case 0x8c: break;	// unknown 
	case 0x8e: break;	// unknown 
 
	case 0x104: exmem_type_16_w(0, data, mem_mask); break; 
 
	case 0x110: spr_disable_16_w(0, data, mem_mask); break; 
	case 0x114: fix_disable_16_w(0, data, mem_mask); break; 
	case 0x118: video_enable_16_w(0, data, mem_mask); break; 
	case 0x11c: break;	// machine settings (read only) 
 
	case 0x120:	// OBJ RAM latch 
	case 0x122: // PCM-A RAM latch 
	case 0x126: // Z80 RAM latch 
	case 0x128: // FIX RAM latch 
		 exmem_latch_16_w(offset, data, mem_mask); 
		 break; 
 
	case 0x140:	// OBJ RAM latch clear 
	case 0x142:	// PCM-A RAM latch clear 
	case 0x146:	// Z80 RAM latch clear 
	case 0x148:	// FIX RAM latch clear 
		 exmem_latch_clear_16_w(offset, data, mem_mask); 
		 break; 
 
	case 0x180: break;	// unknown 
	case 0x182: z80_enable_16_w(0, data, mem_mask); break; 
 
	case 0x1a0:	// OBJ RAM bank 
	case 0x1a2: // PCM-A RAM bank 
	case 0x1a6: // unknown (PAT bank?) 
		exmem_bank_16_w(offset, data, mem_mask); 
		break; 
 
	default: 
		LOG(("neogeo_hardcontrol_16_w(): offset = %06x, data = %04x\n", offset << 1, data)); 
		break; 
	} 
 
	COMBINE_DATA(&mem[offset]); 
} 
 
 
/*------------------------------------------------------ 
 
	ゲーム名をウィンドウタイトルに設定 
 
	引  数: なし 
	戻り値: なし 
 
	メモリから取得するタイトルは正確ではないです 
	(KOF96 NEOGEO Collectionが得点王3だったり) 
	ウィンドウタイトルのゲーム名はgames構造体に 
	登録してあります 
 
 -----------------------------------------------------*/ 
 
void neogeo_set_title(void) 
{ 
	int index = game_index; 
 
	if (index < 0) 
		index = next_game_index; 
 
	if (index < 0) 
	{ 
		if (options.region) 
			osd_set_title(APPNAME); 
		else 
			osd_set_title("NEOGEO CDZ Emulator"); 
	} 
	else 
	{ 
		int i = options.region & 3; 
 
		while (i >= 0) 
		{ 
			if (games[index].title[i]) 
			{ 
				osd_set_title("%s", games[index].title[i]); 
				break; 
			} 
			i--; 
		} 
	} 
}