www.pudn.com > ncdzsrc.rar > cdrom.c
/***************************************************************************
cdrom.c
NEOGEO CD CD-ROM制御
***************************************************************************/
#include "neogeocd.h"
#ifndef LOG
#define VERBOSE 0
#if VERBOSE
#define LOG(x) logerror x
#else
#define LOG(x)
#endif
#endif /* LOG */
#define MAX_FILELIST 32
/****************************************************************************
プロトタイプ
***************************************************************************/
static int load_file(int fileno);
static void init_loading_progress(void);
static int get_filetype(const char *ext);
/****************************************************************************
グローバル変数
***************************************************************************/
int cdrom_current_drive; // 使用するCD-ROMドライブ番号
int cdrom_loading_state; // CD-ROMの状態
int cdrom_ipl_loading; // IPL.TXT処理中
/****************************************************************************
Internal valiables
***************************************************************************/
static int cdrom_drive_state[MAX_DRIVE];
static UINT8 *cdrom_cache;
static FILE *cdrom_fp = NULL;
static int current_fileno = 0;
static int total_sectors = 0;
static int disable_tray_check;
/****************************************************************************
Internal structure
***************************************************************************/
static struct filelist_t
{
UINT8 name[16];
int bank;
offs_t offset;
UINT32 length;
int type;
offs_t next;
UINT32 left;
int sectors;
} filelist[MAX_FILELIST];
/***************************************************************************
グローバル関数
***************************************************************************/
/*------------------------------------------------------
CD-ROM処理の初期化
引 数: なし
戻り値: とりあえず常に1
-----------------------------------------------------*/
int cdrom_init(void)
{
int i, tray;
cdrom_abort_loading();
cdrom_cache = memory_region(REGION_CPU1) + 0x111204;
cdrom_loading_state = CDROM_IDLE;
cdrom_ipl_loading = 0;
disable_tray_check = 0;
for (i = 0; i < MAX_DRIVE; i++)
{
if (osd_get_drive_type(i) == OSD_DRIVE_CDROM)
{
cdrom_drive_state[i] = CDROM_NOTREADY;
tray = osd_get_tray_state(i);
if (tray == -1)
disable_tray_check = 1;
else
cdrom_drive_state[i] |= tray << 4;
}
else
cdrom_drive_state[i] = CDROM_NOTEXIST;
}
return 1;
}
/*------------------------------------------------------
CD-ROM処理の終了
引 数: なし
戻り値: なし
-----------------------------------------------------*/
void cdrom_shutdown(void)
{
cdrom_abort_loading();
}
/*------------------------------------------------------
CD-ROM状態チェック
引 数: int drive ドライブ番号
戻り値: 変化があればドライブの状態の値
-----------------------------------------------------*/
int cdrom_check_state(int drive)
{
int status;
if (cdrom_drive_state[drive] == CDROM_NOTEXIST)
return CDROM_NOTEXIST;
if (osd_drive_is_ready(drive) == OSD_OK)
status = CDROM_READY;
else
status = CDROM_NOTREADY;
if (!disable_tray_check)
{
int tray = osd_get_tray_state(drive);
if (tray != -1)
status |= tray << 4;
}
if (status != cdrom_drive_state[drive])
{
cdrom_drive_state[drive] = status;
return status;
}
return 0;
}
/*------------------------------------------------------
CD-ROM状態取得
引 数: int drive ドライブ番号
戻り値: ドライブの状態の値
-----------------------------------------------------*/
int cdrom_get_state(int drive)
{
return cdrom_drive_state[drive];
}
/*------------------------------------------------------
CD-ROM読み込みの強制終了
引 数: なし
戻り値: なし
-----------------------------------------------------*/
void cdrom_abort_loading(void)
{
current_fileno = 0;
total_sectors = 0;
cdrom_loading_state = CDROM_DONE;
if (cdrom_fp != NULL)
{
fclose(cdrom_fp);
cdrom_fp = NULL;
}
}
/*------------------------------------------------------
IPL.TXT処理
引 数: なし
戻り値: エラー=0, 成功==1
-----------------------------------------------------*/
int cdrom_process_ipl(void)
{
struct filelist_t *file = &filelist[0];
UINT8 path[MAX_PATH], readbuf[32];
UINT8 *fname, *ext, *str_offs, *str_bank, *start_p, *p;
char region_chr[3] = { 'j','u','e' };
UINT32 length;
int i;
FILE *fp;
// LOGO_x.PRG読み込み
for (i = options.region & 3; i >= 0; i--)
{
sprintf(path, "%c:/LOGO_%c.PRG", 'A' + cdrom_current_drive, region_chr[i]);
if ((length = osd_file_exist(path)) != 0)
{
UINT8 *mem = memory_region(REGION_CPU1) + 0x120000;
fp = fopen(path, "rb");
if (fp != NULL)
{
fread(mem, length, 1, fp);
fclose(fp);
swab(mem, mem, length);
break;
}
}
}
total_sectors = 0;
sprintf(path, "%c:\\IPL.TXT", cdrom_current_drive + 'A');
length = osd_file_exist(path);
if (length == 0)
{
logerror("CD-ROM: IPL.TXT not exist.\n");
return 0;
}
fp = fopen(path, "rb");
if (fp == NULL)
{
logerror("CD-ROM: could not open IPL.TXT.\n");
return 0;
}
fread(cdrom_cache, length, 1, fp);
fclose(fp);
cdrom_ipl_loading = 1;
p = cdrom_cache;
logerror("Processing IPL.TXT...\n");
while (*p && *p != 0x1a) // EOFまでループ
{
start_p = p;
// 改行コードを0に置き換え
p = strchr(start_p, 0x0d);
*p++ = '\0';
*p++ = '\0';
strcpy(readbuf, start_p);
// 1行展開 - IPL.TXTはCSV形式
fname = strtok(readbuf, ",\r\n"); // ファイル名
str_bank = strtok(NULL, ",\r\n"); // バンク
str_offs = strtok(NULL, ",\r\n"); // オフセット
if (fname == NULL || str_offs == NULL || str_bank == NULL)
break;
// ファイル名
for (i = 0; i <= strlen(fname); i++)
file->name[i] = toupper(fname[i]);
// バンクナンバー
sscanf(str_bank, "%d", &file->bank);
file->bank &= 3;
// オフセット
sscanf(str_offs, "%x", &file->offset);
// ファイルタイプ
ext = strrchr(file->name, '.') + 1;
if (ext[0] == 'O') strcpy(ext, "SPR");
file->type = get_filetype(ext);
// ファイルサイズ
sprintf(path, "%c:\\%s", cdrom_current_drive + 'A', file->name);
file->length = osd_file_exist(path);
file->sectors = (file->length + 0x7ff) / 0x800;
// 分割ロード用設定
file->next = 0;
// トータルセクタ数計算
total_sectors += file->sectors;
logerror("entry: %s,%d,%06x,%06x,%x\n", file->name, file->bank, file->offset, file->length, file->sectors);
file++;
}
file->name[0] = '\0';
m68000_write_memory_8(0x108000 + 0x7ddc, 0x01); // ロード画面の有無
init_loading_progress();
loading_screen_start();
cdrom_loading_state = CDROM_LOADING;
while (cdrom_loading_state != CDROM_IDLE)
{
if (osd_get_app_state())
return -1;
update_input_port();
loading_updatescreen();
}
loading_screen_stop();
m68000_write_memory_8(0x108000 + 0x7ddc, 0x00); // ロード画面の有無
m68000_write_memory_32(0x108000 + 0x7690, 0);
cdrom_ipl_loading = 0;
return 1;
}
/*------------------------------------------------------
CD-ROM読み込み開始
引 数: なし
戻り値: なし
-----------------------------------------------------*/
static UINT8 save1, save2;
void cdrom_load_files(void)
{
struct filelist_t *file = &filelist[0];
UINT8 *mem, path[32], *ext;
int i;
offs_t offset, src, dst;
UINT32 data;
if (m68000_read_memory_8(m68000_get_reg(M68K_A0)) == 0)
return;
neogeo_cdda_stop();
save1 = m68000_read_memory_8(0x108000 + 0x7d80);
save2 = m68000_read_memory_8(0x108000 + 0x7dc2);
if (with_image())
logerror("CD-ROM: load with image\n");
else
logerror("CD-ROM: load without image\n");
mem = memory_region(REGION_CPU1);
// ファイル情報領域をクリア
offset = 0x115a06;
for (i = 0; i < 0x20; i++)
{
memset(mem + offset, 0, 0x20);
m68000_write_memory_16(offset + 0x1c, 0xffff);
offset += 0x20;
}
// ファイル情報領域を設定
offset = 0x115a06;
src = m68000_get_reg(M68K_A0);
while (1)
{
if (m68000_read_memory_8(src) == 0)
break;
dst = offset;
// ファイル名取得
while (1)
{
data = m68000_read_memory_8(src++);
if (data == 0) break;
// 小文字の場合は大文字に変換
if (data >= 'a') data -= 0x20;
m68000_write_memory_8(dst++, data);
}
// 拡張子がOBJの場合はSPRに変更
if (m68000_read_memory_8(dst - 3) == 'O')
{
m68000_write_memory_8(dst - 3, 'S');
m68000_write_memory_8(dst - 2, 'P');
m68000_write_memory_8(dst - 1, 'R');
}
// バンク番号取得
dst = offset + 0x10;
data = m68000_read_memory_8(src++) & 0x03;
m68000_write_memory_8(dst++, data);
// アドレスを調整
src = (src + 1) & 0xfffffe;
dst = (dst + 1) & 0xfffffe;
// オフセットを取得
m68000_write_memory_32(dst, m68000_read_memory_32(src));
// 次のファイル情報の位置を設定
src += 4;
offset += 0x20;
}
total_sectors = 0;
offset = 0x115a06;
do
{
char *p;
swab(mem + offset, file->name, 16);
p = strchr(file->name, ';');
if (p != NULL) *p = '\0';
ext = strrchr(file->name, '.') + 1;
file->type = get_filetype(ext);
file->bank = m68000_read_memory_8(offset + 0x10);
file->offset = m68000_read_memory_32(offset + 0x12);
sprintf(path, "%c:/%s", cdrom_current_drive + 'A', file->name);
file->length = osd_file_exist(path);
file->sectors = (file->length + 0x7ff) / 0x800;
file->next = 0;
// トータルブロック数計算
total_sectors += file->sectors;
logerror("entry: %s,%d,%06x,%06x,%d\n", file->name, file->bank, file->offset, file->length, file->sectors);
offset += 0x20;
file++;
} while (mem[offset] != 0);
file->name[0] = '\0';
#if FAST_SPRITE_DRAW
if (GAME_NAME("ngcdsp"))
{
char *ext = strrchr(filelist[0].name, '.') + 1;
if (get_filetype(ext) == FIX_TYPE)
{
if (strcmp(filelist[0].name, "G046.FIX") == 0)
neogeo_change_sprite_func(1, 0);
else
neogeo_change_sprite_func(0, 0);
}
}
#endif
// ロード情報書き込み
// m68000_write_memory_8(0x108000 + 0x7657, 0x01); // CD-ROM読み込み中フラグ
// m68000_write_memory_8(0x108000 + 0x76c3, 0x00); // CDDAイネーブル
init_loading_progress();
loading_screen_start();
cdrom_loading_state = CDROM_LOADING;
if (driver_flag & LOADING_TYPE1)
{
while (cdrom_loading_state != CDROM_IDLE)
{
if (osd_get_app_state())
return;
update_input_port();
loading_updatescreen();
}
cdrom_finish_load_files();
}
}
/*------------------------------------------------------
CD-ROM読み込み終了
引 数: なし
戻り値: なし
-----------------------------------------------------*/
void cdrom_finish_load_files(void)
{
loading_screen_stop();
// 終了状態のデータ書き込み
m68000_write_memory_8(0x108000 + 0x7e88, 0x00);
m68000_write_memory_8(0x108000 + 0x7ddd, 0x00);
m68000_write_memory_8(0x108000 + 0x76db, 0x01);
m68000_write_memory_8(0x108000 + 0x7ec4, 0x01);
m68000_write_memory_32(0x10f742, 0);
m68000_write_memory_32(0x10f746, 0);
m68000_write_memory_32(0x108000 + 0x768c, 0); // ファイルのブロック数
m68000_write_memory_32(0x108000 + 0x7690, 0); // 読み込み進行度
m68000_write_memory_32(0x108000 + 0x7694, 0); // 読み込みセクタ数
m68000_write_memory_8(0x108000 + 0x7657, 0x00); // CD-ROM読み込み中フラグ
m68000_write_memory_8(0x108000 + 0x76d9, 0x01);
m68000_write_memory_8(0x108000 + 0x76c3, 0x01); // CDDAイネーブル
m68000_write_memory_8(0x108000 + 0x76f6, 0xff); // CDDAコマンド1
m68000_write_memory_8(0x108000 + 0x764b, 0xff); // CDDAトラック1
m68000_write_memory_8(0x108000 + 0x7ddc, 0x00); // ロード画面の有無
m68000_write_memory_8(0x108000 + 0x7e85, 0xff);
m68000_write_memory_8(0x108000 + 0x7dc2, save2);
m68000_write_memory_8(0x108000 + 0x7d80, save1);
}
/*------------------------------------------------------
CD-ROMからファイルを読み込みメモリに転送する
引 数: なし
戻り値: なし
-----------------------------------------------------*/
void cdrom_load_next_data(void)
{
struct filelist_t *file = &filelist[current_fileno];
if (load_file(current_fileno) == 0)
{
// 読み込み終了
current_fileno++;
file = &filelist[current_fileno];
if (strlen(file->name) == 0)
{
current_fileno = 0;
cdrom_loading_state = CDROM_DONE;
}
}
}
/*------------------------------------------------------
CDのチェック
引 数: int drive チェックするドライブ
戻り値: game構造体のインデックス番号
※ゲームを判別するためのものですが、一応簡易
コピー対策にもなってます。
丸ごとバックアップしたディスクの場合は問題なく
動いてしまうと思いますが、ISO + WAVで焼いたりした
場合は引っかかるかと。
判別だけなら固有のファイル名をチェックしたほうが
いいです。(かぶるものもありますが)
-----------------------------------------------------*/
int cdrom_verify_disc(int drive)
{
int i, j, num_tracks, cdda_status, index = -1;
UINT32 leadout;
UINT8 path[MAX_PATH]="";
UINT32 length;
if (cdrom_drive_state[drive] & CDROM_NOTEXIST)
{
// ドライブがCD-ROMドライブではない
return -1;
}
if ((cdda_status = osd_cdda_get_status()) == CDDA_NOTREADY)
{
// 初期化していない場合は初期化する
if (osd_cdda_init(drive) == OSD_ERROR)
{
// MCIを初期化できなかった
// LOG(("OSD_CDDA: could not initialize.\n"));
return -1;
}
}
// トラック数
num_tracks = osd_cdda_get_num_tracks();
// リードアウトLBA
leadout = osd_cdda_get_track_lba(0);
i = 0;
while (games[i].name && index == -1)
{
// トラック数を比較
if (games[i].cdrom->num_tracks == num_tracks)
{
for (j = 0; j < games[i].cdrom->num_trackdata; j++)
{
// リードアウトのLBAを比較
if (leadout == games[i].cdrom->tracks[j][0])
{
int track;
const UINT32 *tracks = games[i].cdrom->tracks[j];
// 仮にゲーム番号を設定
index = i;
// 各トラックのLBAを比較
for (track = 1; track <= games[i].cdrom->num_tracks; track++)
{
if (osd_cdda_get_track_lba(track) != tracks[track])
{
// トラック構造が違うのでNEOGEO CDのディスクではない
index = -1;
break;
}
}
}
if (index != -1)
{
// NEOGEO CDのディスク
logerror("\"%s\" found.\n", games[index].name);
break;
}
}
}
i++;
}
if (index == -1)
{
sprintf(path, "%c:\\IPL.TXT", drive+ 'A');
length = osd_file_exist(path);
if (length != 0)
{
index = 98;
}
else if (osd_cdda_has_audio_track())
{
// オーディオトラックがあればオーディオCD
index = -2;
}
}
if (cdda_status == CDDA_NOTREADY)
{
// チェック開始時に初期化されてなかった場合は、CDDA処理を終了
osd_cdda_exit();
}
return index;
}
/***************************************************************************
ローカル関数
***************************************************************************/
/*------------------------------------------------------
CD-ROMからファイルを読み込みメモリに転送する
引 数: int fileno ファイル番号
戻り値: 読み込んだデータ長
-----------------------------------------------------*/
static void upload_file(int fileno, offs_t offset, UINT32 length)
{
UINT8 *mem;
offs_t base;
struct filelist_t *file = &filelist[fileno];
switch (file->type)
{
case PRG_TYPE:
case AXX_TYPE:
mem = memory_region(REGION_CPU1);
swab(cdrom_cache, mem + file->offset + offset, length);
break;
case FIX_TYPE:
if (with_image())
{
offs_t offset1, offset2, start, end;
UINT32 length1, length2;
start = (file->offset >> 1) + offset;
end = (start + length) - 1;
if (start >= 0x6000)
{
offset1 = 0;
length1 = 0;
offset2 = start << 1;
length2 = length;
}
else if (end < 0x6000)
{
offset1 = start << 1;
length1 = length;
offset2 = 0;
length2 = 0;
}
else
{
offset1 = start << 1;
length1 = 0x6000 - start;
offset2 = 0x6000 << 1;
length2 = length - length1;
}
if (length1)
{
mem = memory_region(REGION_CPU1) + 0x115e06;
memcpy(mem + (offset1 >> 1), cdrom_cache, length1);
}
if (length2)
{
mem = memory_region(REGION_GFX1);
memcpy(mem + (offset2 >> 1), cdrom_cache + length1, length2);
#if ENABLE_SYSTEM_CHECK
mem = memory_region(REGION_GFX5);
memcpy(mem + (offset2 >> 1), cdrom_cache + length1, length2);
#endif
neogeo_decode_fix(mem, offset2, length2);
}
}
else
{
mem = memory_region(REGION_GFX1);
base = file->offset >> 1;
memcpy(mem + base + offset, cdrom_cache, length);
#if ENABLE_SYSTEM_CHECK
mem = memory_region(REGION_GFX5);
memcpy(mem + base + offset, cdrom_cache, length);
#endif
neogeo_decode_fix(mem, file->offset + (offset << 1), length);
}
break;
case SPR_TYPE:
mem = memory_region(REGION_GFX2);
base = (file->bank << 20) + file->offset;
memcpy(mem + base + offset, cdrom_cache, length);
#if ENABLE_SYSTEM_CHECK
mem = memory_region(REGION_GFX6);
memcpy(mem + base + offset, cdrom_cache, length);
#endif
neogeo_decode_spr(mem, base + offset, length);
break;
case Z80_TYPE:
mem = memory_region(REGION_CPU2);
base = (file->bank << 16) + (file->offset >> 1);
memcpy(mem + base + offset, cdrom_cache, length);
break;
case PAT_TYPE:
swab(cdrom_cache, cdrom_cache, length);
neogeo_apply_patch((UINT16 *)cdrom_cache, file->bank, file->offset);
break;
case PCM_TYPE:
mem = memory_region(REGION_SOUND1);
base = (file->bank << 19) + (file->offset >> 1);
memcpy(mem + base + offset, cdrom_cache, length);
break;
}
}
/*------------------------------------------------------
CD-ROMからファイルを読み込みメモリに転送する
引 数: int fileno ファイル番号
戻り値: 読み込んだブロック数
-----------------------------------------------------*/
static int load_file(int fileno)
{
struct filelist_t *file = &filelist[fileno];
if (file->next == 0)
{
char path[MAX_PATH];
osd_set_title("Loading %s", file->name);
logerror("loading: %s,%d,%06x\n", file->name, file->bank, file->offset);
sprintf(path, "%c:\\%s", cdrom_current_drive + 'A', file->name);
cdrom_fp = fopen(path, "rb");
if (!cdrom_fp)
{
logerror("CD-ROM: %s Could not open.\n", path);
return 0;
}
if (file->type == Z80_TYPE)
m68000_write_memory_8(0xff0183, 0x00);
}
if (options.cdspeed)
{
int read_sectors = 1 << options.cdspeed;
if (file->sectors > read_sectors)
{
UINT32 left = read_sectors;
while (left)
{
if (file->length - file->next < 0x800)
{
fread(cdrom_cache, file->length - file->next, 1, cdrom_fp);
upload_file(fileno, file->next, file->length - file->next);
}
else
{
fread(cdrom_cache, 0x800, 1, cdrom_fp);
upload_file(fileno, file->next, 0x800);
}
file->next += 0x800;
file->sectors--;
left--;
loading_update_progress();
}
return file->sectors;
}
}
while (file->sectors)
{
if (file->length - file->next < 0x800)
{
fread(cdrom_cache, file->length - file->next, 1, cdrom_fp);
upload_file(fileno, file->next, file->length - file->next);
}
else
{
fread(cdrom_cache, 0x800, 1, cdrom_fp);
upload_file(fileno, file->next, 0x800);
}
file->next += 0x800;
file->sectors--;
loading_update_progress();
}
fclose(cdrom_fp);
cdrom_fp = NULL;
if (file->type == Z80_TYPE)
m68000_write_memory_8(0xff0183, 0xff);
return file->sectors;
}
/*------------------------------------------------------
読み込み進行度更新
引 数: なし
戻り値: 画面更新フラグ
-----------------------------------------------------*/
static void init_loading_progress(void)
{
m68000_write_memory_32(0x108000 + 0x7694, total_sectors);
total_sectors = ((0x8000 / total_sectors) << 8) | 0x80;
m68000_write_memory_32(0x108000 + 0x768c, total_sectors);
m68000_write_memory_32(0x108000 + 0x7690, 0);
}
/*------------------------------------------------------
拡張子からデータの形式を判別
引 数: const char *ext 拡張子の文字列
戻り値: データ形式の番号
-----------------------------------------------------*/
static int get_filetype(const char *ext)
{
int type = UNKNOWN_TYPE;
if (strlen(ext) == 3)
{
if (stricmp(ext, "PRG") == 0) type = PRG_TYPE;
if (stricmp(ext, "FIX") == 0) type = FIX_TYPE;
if (stricmp(ext, "SPR") == 0) type = SPR_TYPE;
if (stricmp(ext, "Z80") == 0) type = Z80_TYPE;
if (stricmp(ext, "PCM") == 0) type = PCM_TYPE;
if (stricmp(ext, "PAT") == 0) type = PAT_TYPE;
if (ext[0] == 'A') type = AXX_TYPE;
}
return type;
}