diff --git a/gdemu/SConstruct b/gdemu/SConstruct index 1e89c22..12fd3bb 100644 --- a/gdemu/SConstruct +++ b/gdemu/SConstruct @@ -4,7 +4,7 @@ import sys opts = Variables([], ARGUMENTS) -emu_array = ["", "x1", "x1t", "msx", "pc88ma"] +emu_array = ["", "x1", "x1t", "msx", "pc88ma", "pc80mk2"] opts.Add(EnumVariable("emu", "Target emulator", "", emu_array)) @@ -31,6 +31,8 @@ if lenv["emu"] == "msx": env.Append(CPPDEFINES=['_MSX1']) elif lenv["emu"] == "pc88ma": env.Append(CPPDEFINES=['_PC8801MA']) +elif lenv["emu"] == "pc80mk2": + env.Append(CPPDEFINES=['_PC8001MK2']) elif lenv["emu"] == "x1t": env.Append(CPPDEFINES=['_X1','_X1TURBO']) else: @@ -101,6 +103,32 @@ elif lenv["emu"] == "pc88ma": sources.append("src/emulator/vm/pc8801/pc88.cpp") sources.append("src/emulator/vm/pc8801/pc8801.cpp") sources.append("src/emulator/vm/pc8801/diskio.cpp") +elif lenv["emu"] == "pc80mk2": + sources.append("src/emulator/vm/disk.cpp") + sources.append("src/emulator/vm/harddisk.cpp") + sources.append("src/emulator/vm/event.cpp") + sources.append("src/emulator/vm/prnfile.cpp") + sources.append("src/emulator/vm/i8251.cpp") + sources.append("src/emulator/vm/i8255.cpp") + sources.append("src/emulator/vm/upd1990a.cpp") + sources.append("src/emulator/vm/ym2203.cpp") + sources.append("src/emulator/vm/z80.cpp") + sources.append("src/emulator/vm/noise.cpp") + sources.append("src/emulator/vm/pc80s31k.cpp") + sources.append("src/emulator/vm/upd765a.cpp") + sources.append("src/emulator/vm/scsi_dev.cpp") + sources.append("src/emulator/vm/scsi_hdd.cpp") + sources.append("src/emulator/vm/scsi_host.cpp") + sources.append("src/emulator/vm/scsi_cdrom.cpp") + sources.append("src/emulator/vm/ym2151.cpp") + sources.append("src/emulator/vm/ay_3_891x.cpp") + sources.append("src/emulator/vm/i8253.cpp") + sources.append("src/emulator/vm/pcm1bit.cpp") + sources.append("src/emulator/vm/pcm8bit.cpp") + sources.append("src/emulator/vm/pc8801/pc88.cpp") + sources.append("src/emulator/vm/pc8801/pc8801.cpp") + sources.append("src/emulator/vm/pc8801/diskio.cpp") + sources.append("src/emulator/vm/pc80sd.cpp") else: sources.append("src/emulator/vm/ay_3_891x.cpp") sources.append("src/emulator/vm/event.cpp") diff --git a/gdemu/src/emulator/vm/pc80sd.cpp b/gdemu/src/emulator/vm/pc80sd.cpp new file mode 100644 index 0000000..4c87355 --- /dev/null +++ b/gdemu/src/emulator/vm/pc80sd.cpp @@ -0,0 +1,2087 @@ +/* + Skelton for retropc emulator + + Date : 2023.07.30- + + [ PC-8001(mk2)_SD ] +*/ + + +#include "pc80sd.h" +#include "../fileio.h" + + +#define EVENT_TIMER 1 + +#define SIG_I8255_PORT_A 0 +#define SIG_I8255_PORT_B 1 +#define SIG_I8255_PORT_C 2 + +PC80SD *current_pc80sd; + +static uint8_t cr_data[2] = {0x0d,0x00}; +static uint8_t end_data[2] = {0xff,0x00}; + +enum pc80sd_state +{ + PC80SD_INITIALIZE = 0, + PC80SD_WAIT_COMMAND, + + PC80SD_RCV4BIT, + PC80SD_RCV1BYTE, + PC80SD_SND1BYTE, + PC80SD_RCVBYTES, + PC80SD_SNDBYTES, + PC80SD_RCVNAME, + PC80SD_WBODY, + + PC80SD_DIRLIST = 0x83, + PC80SD_CMT_SAVE = 0x70, + PC80SD_CMT_LOAD = 0x71, + PC80SD_CMT_5F9E = 0x72, + PC80SD_BAS_LOAD = 0x73, + PC80SD_BAS_SAVE = 0x74, + PC80SD_BAS_KILL = 0x75, + PC80SD_SD_ROPEN = 0x76, + PC80SD_SD_WAOPEN = 0x77, + PC80SD_SD_W1BYTE = 0x78, + PC80SD_SD_WNOPEN = 0x79, + PC80SD_SD_WDIRECT = 0x7A, + PC80SD_SD_WCLOSE = 0x7B, + + PC80SD_WAIT, +}; + +// 保存フォルダ +const _TCHAR *sd_folder_name = _T("SD"); + +unsigned long r_count = 0; +unsigned long f_length = 0; +char m_name[40]; +char f_name[40]; +char c_name[40]; +char new_name[40]; +char w_name[40]; +bool eflg = false; +unsigned int s_adrs, e_adrs, w_length, w_len1, w_len2, s_adrs1, s_adrs2, b_length; + +FILEIO *file = nullptr, *w_file = nullptr; + +const _TCHAR *create_sd_path(const char *path) +{ + static _TCHAR file_path[8][_MAX_PATH]; + static unsigned int table_index = 0; + unsigned int output_index = (table_index++) & 7; + + const _TCHAR *dir_path = create_local_path(sd_folder_name); + + // 上記dir_pathにpathを連結してフルパスを作る +#if defined(_WIN32) || defined(_WIN64) + _stprintf(file_path[output_index], _T("%s\\%s"), dir_path, path); +#else + _stprintf(file_path[output_index], _T("%s/%s"), dir_path, path); +#endif + + return (const _TCHAR *)file_path[output_index]; +} + +bool SDFile::exists(const char *path) +{ + FILE *file = fopen(create_sd_path(path), "r"); + if (file != NULL) + { + fclose(file); + return true; + } + + return false; +} + +bool SDFile::remove(const char *path) +{ + return ::remove(create_sd_path(path)); +} + +void SDFile::rewindDirectory() +{ + close(); + open(base_path); +} + +SDFileEntry SDFile::openNextFile() +{ + SDFileEntry result; + if (currentEntry.isValid()) + { + result = currentEntry; + } +#if defined(_WIN32) || defined(_WIN64) + bool updated = false; + while (FindNextFile(hFind, &ffd) != 0) + { + TCHAR *wpFileName = ffd.cFileName; + /* + L"."とL".."はスキップ + */ + if (L'.' == wpFileName[0]) + { + if ((L'\0' == wpFileName[1]) || (L'.' == wpFileName[1] && L'\0' == wpFileName[2])) + { + continue; + } + } + // フォルダはスキップ + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + continue; + } + + currentEntry = SDFileEntry(ffd.cFileName); + updated = true; + break; + } + + // currentEntryを更新出来なかった場合、ここで終了となる + if (!updated) + { + SDFileEntry invalidEntry; + currentEntry = invalidEntry; + } + +#else + bool updated = false; + char full_path[PATH_MAX]; + if(dir != nullptr) + { + struct stat st; + while ((ent = readdir(dir)) != NULL) + { + snprintf(full_path, sizeof(full_path), "%s/%s", base_path, ent->d_name); + stat(full_path, &st); + if (S_ISDIR(st.st_mode)) { + continue; + } else if(S_ISREG(st.st_mode)) { + // ファイル名を取得 + currentEntry = SDFileEntry(ent->d_name); + updated = true; + break; + } + } + } + + // currentEntryを更新出来なかった場合、ここで終了となる + if (!updated) + { + SDFileEntry invalidEntry; + currentEntry = invalidEntry; + if(dir != nullptr) + { + closedir(dir); + dir = nullptr; + } + } +#endif + return result; +} + +bool SDFile::open(const char *path) +{ + strcpy(base_path, path); +#if defined(_WIN32) || defined(_WIN64) + strncpy(szDir, path, strlen(path) + 1); + strncat(szDir, "\\*", 3); + + hFind = FindFirstFile(szDir, &ffd); + if (INVALID_HANDLE_VALUE == hFind) + { + return false; + } + + do + { + TCHAR *wpFileName = ffd.cFileName; + /* + L"."とL".."はスキップ + */ + if (L'.' == wpFileName[0]) + { + if ((L'\0' == wpFileName[1]) || (L'.' == wpFileName[1] && L'\0' == wpFileName[2])) + { + continue; + } + } + // 一つ目のEntryを作っておく + currentEntry = SDFileEntry(ffd.cFileName); + break; + } while (FindNextFile(hFind, &ffd) != 0); +#else + char full_path[PATH_MAX]; + if ((dir = opendir(path)) != NULL) + { + struct stat st; + while ((ent = readdir(dir)) != NULL) + { + snprintf(full_path, sizeof(full_path), "%s/%s", path, ent->d_name); + stat(full_path, &st); + if (S_ISDIR(st.st_mode)) { + continue; + } else if(S_ISREG(st.st_mode)) { + // ファイル名を取得 + currentEntry = SDFileEntry(ent->d_name); + break; + } + } + } +#endif + return true; +} + +void SDFile::close() +{ +#if defined(_WIN32) || defined(_WIN64) + if(hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + hFind = INVALID_HANDLE_VALUE; + } +#else + if(dir != nullptr) + { + closedir(dir); + dir = nullptr; + } +#endif +} + +// 小文字->大文字 +char upper(char c) +{ + if ('a' <= c && c <= 'z') + { + c = c - ('a' - 'A'); + } + return c; +} + +// f_nameとc_nameをc_nameに0x00が出るまで比較 +// FILENAME COMPARE +bool f_match(char *f_name, char *c_name) +{ + bool flg1 = true; + unsigned int lp1 = 0; + while (lp1 <= 32 && c_name[0] != 0x00 && flg1 == true) + { + if (upper(f_name[lp1]) != c_name[lp1]) + { + flg1 = false; + } + lp1++; + if (c_name[lp1] == 0x00) + { + break; + } + } + return flg1; +} + +void addcmt(char *f_name, char *m_name) +{ + unsigned int lp1 = 0; + while (f_name[lp1] != 0x00) + { + m_name[lp1] = f_name[lp1]; + lp1++; + } + if (f_name[lp1 - 4] != '.' || + (f_name[lp1 - 3] != 'C' && + f_name[lp1 - 3] != 'c') || + (f_name[lp1 - 2] != 'M' && + f_name[lp1 - 2] != 'm') || + (f_name[lp1 - 1] != 'T' && + f_name[lp1 - 1] != 't')) + { + m_name[lp1++] = '.'; + m_name[lp1++] = 'c'; + m_name[lp1++] = 'm'; + m_name[lp1++] = 't'; + } + m_name[lp1] = 0x00; +} + +PC80SD::~PC80SD() +{ + release(); +} + +void PC80SD::initialize() +{ + strcpy(w_name, "default.dat"); + + // 時間はテキトー(1.6MHz) + register_event(this, EVENT_TIMER, 0.625, true, ®ister_id); + + stateStack.clear(); + state = PC80SD_INITIALIZE; + sub_state = 0; + memset(m_name, 0, sizeof(m_name)); + memset(f_name, 0, sizeof(f_name)); + memset(c_name, 0, sizeof(c_name)); + memset(new_name, 0, sizeof(new_name)); + memset(w_name, 0, sizeof(w_name)); + r_count = f_length = 0; +} + +void PC80SD::release() +{ + if (w_file) + { + w_file->Fclose(); + w_file = nullptr; + } + if (file) + { + file->Fclose(); + file = nullptr; + } + sd_file.close(); +} + +void PC80SD::reset() +{ + release(); + + initialize(); +} + +void PC80SD::write_signal(int id, uint32_t data, uint32_t mask) +{ + // printf("write signal(from Z80) %d %x %x\n", id, data, mask); + port[id].reg = (port[id].reg & ~mask) | (data & mask); +} + +void PC80SD::sendbytes(const uint8_t*data, int sz) +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_SNDBYTES; + sub_state = 0; + memcpy(send_datas, data, sz); + send_datas_count = sz; + send_datas_index = 0; +} + +void PC80SD::receivebytes(int count) +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_RCVBYTES; + sub_state = 0; + receive_datas_count = count; + receive_datas_index = 0; +} + +void PC80SD::receive1byte() +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_RCV1BYTE; + sub_state = 0; + result_value = 0; +} + +void PC80SD::receive4bit() +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_RCV4BIT; + sub_state = 0; +} + +void PC80SD::popstate() +{ + sub_state = stateStack.top(); + stateStack.pop(); + state = stateStack.top(); + stateStack.pop(); +} + +void PC80SD::proc_command() +{ +} + +void PC80SD::send1byte(uint8_t data) +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_SND1BYTE; + sub_state = 0; + send_value = data; +} + +void PC80SD::loopend() +{ + state = PC80SD_INITIALIZE; + sub_state = 0; +} + +void PC80SD::receivename(char *f_name) +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_RCVNAME; + sub_state = 0; + target_data = f_name; +} + +void PC80SD::w_body(void) +{ + stateStack.push(state); + stateStack.push(sub_state); + state = PC80SD_WBODY; + sub_state = 0; +} + +void PC80SD::w_body_proc() +{ + switch(sub_state) + { + case 0: + { + // ヘッダー 0x3A書き込み + w_file->FputUint8(char(0x3A)); + + sub_state++; + receivebytes(2); + break; + } + case 1: + { + // スタートアドレス取得、書き込み + s_adrs1 = receive_datas[0]; + s_adrs2 = receive_datas[1]; + w_file->FputUint8(s_adrs2); + w_file->FputUint8(s_adrs1); + // CHECK SUM計算、書き込み + csum = 0 - (s_adrs1 + s_adrs2); + w_file->FputUint8(csum); + // スタートアドレス算出 + s_adrs = s_adrs1 + s_adrs2 * 256; + + sub_state++; + receivebytes(2); + break; + } + case 2: + { + // エンドアドレス取得 + s_adrs1 = receive_datas[0]; + s_adrs2 = receive_datas[1]; + // エンドアドレス算出 + e_adrs = s_adrs1 + s_adrs2 * 256; + // ファイル長算出、ブロック数算出 + w_length = e_adrs - s_adrs + 1; + w_len1 = w_length / 255; + w_len2 = w_length % 255; + + sub_state++; + break; + } + case 3: + { + // 実データ受信、書き込み + // 0xFFブロック + if(w_len1 == 0) + { + sub_state = 100; + break; + } + w_file->FputUint8(char(0x3A)); + w_file->FputUint8(char(0xFF)); + csum = 0xff; + lp1 = 1; + sub_state++; + break; + } + case 4: + { + if(lp1 > 255) + { + sub_state = 6; + break; + } + sub_state++; + receive1byte(); + break; + } + case 5: + { + r_data = result_value; + w_file->FputUint8(r_data); + csum = csum + r_data; + lp1++; + sub_state = 4; + break; + } + case 6: + { + // CHECK SUM計算、書き込み + csum = 0 - csum; + w_file->FputUint8(csum); + w_len1--; + sub_state = 3; + break; + } + case 100: + { + // 端数ブロック処理 + if(w_len2 == 0) + { + sub_state = 200; + break; + } + w_file->FputUint8(char(0x3A)); + w_file->FputUint8(w_len2); + csum = w_len2; + lp1 = 1; + sub_state++; + break; + } + case 101: + { + if(lp1 > w_len2) + { + sub_state = 103; + break; + } + sub_state++; + receive1byte(); + break; + } + case 102: + { + r_data = result_value; + w_file->FputUint8(r_data); + csum = csum + r_data; + lp1++; + sub_state = 101; + break; + } + case 103: + { + // CHECK SUM計算、書き込み + csum = 0 - csum; + w_file->FputUint8(csum); + sub_state = 200; + break; + } + case 200: + { + w_file->FputUint8(char(0x3A)); + w_file->FputUint8(char(0x00)); + w_file->FputUint8(char(0x00)); + sub_state = 1000; + break; + } + case 1000: + { + popstate(); + break; + } + } +} + +void PC80SD::cmt_save_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + sub_state++; + receivename(m_name); + break; + } + case 2: + { + if(m_name[0] != 0x00) + { + addcmt(m_name, f_name); + + if(w_file) + { + w_file->Fclose(); + } + + // ファイルが存在すればdelete + if(SDFile::exists(f_name)) + { + SDFile::remove(f_name); + } + + // ファイルオープン + w_file = new FILEIO(); + if (w_file->Fopen(create_sd_path(f_name), FILEIO_WRITE_BINARY)) + { + sub_state++; + send1byte(0x00); + break; + } else{ + sub_state = 1000; + send1byte(0xf0); + break; + } + } else { + sub_state = 1000; + send1byte(0xf6); + break; + } + break; + } + case 3: + { + sub_state++; + w_body(); + break; + } + case 4: + { + w_file->Fclose(); + delete w_file; + w_file = nullptr; + sub_state = 1000; + break; + } + case 100: + { + break; + } + + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::cmt_load_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state=123; + send1byte(0x00); + break; + } + case 123: + { + flg = false; + sub_state=1; + receivename(m_name); + break; + } + case 1: + { + if(m_name[0] != 0x00) + { + addcmt(m_name, f_name); + + // 指定があった場合 + // ファイルが存在しなければERROR + if (SDFile::exists(f_name) == true) + { + // ファイルオープン + file = new FILEIO(); + if (file->Fopen(create_local_path("%s/%s", sd_folder_name, f_name), FILEIO_READ_BINARY)) + { + // f_length設定、r_count初期化 + f_length = file->FileLength(); + r_count = 0; + // 状態コード送信(OK) + flg = true; + sub_state++; + send1byte(0x00); + } + else + { + sub_state++; + send1byte(0xf0); + flg = false; + } + } + else + { + sub_state++; + send1byte(0xf1); + flg = false; + } + } else { + sub_state = 100; + } + break; + } + case 2: + { + if(flg == false) + { + sub_state = 1000; + break; + } + rdata = 0; + + // ヘッダーが出てくるまで読み飛ばし + while (rdata != 0x3a && rdata != 0xd3) + { + rdata = file->FgetUint8(); + r_count++; + } + sub_state++; + send1byte(rdata); + break; + } + case 3: + { + // ヘッダーが0x3aなら続行、違えばエラー + if (rdata == 0x3a) + { + // START ADDRESS HIを送信 + s_adrs1 = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(s_adrs1); + } else { + file->Fclose(); + delete file; + file = nullptr; + sub_state = 1000; + break; + } + break; + } + case 4: + { + // START ADDRESS LOを送信 + s_adrs2 = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(s_adrs2); + s_adrs = s_adrs1 * 256 + s_adrs2; + break; + } + case 5: + { + // CHECK SUMを送信 + rdata = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(rdata); + break; + } + case 6: + { + // HEADERを送信 + rdata = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(rdata); + break; + } + case 7: + { + // データ長を送信 + b_length = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(b_length); + break; + } + case 8: + { + // データ長が0x00でない間ループする + if (b_length == 0x00) + { + sub_state = 70; + break; + } + lp1 = 0; + sub_state++; + break; + } + case 9: + { + if(lp1 > b_length) + { + sub_state = 10; + break; + } + rdata = file->FgetUint8(); + r_count++; + send1byte(rdata); + lp1++; + break; + } + case 10: + { + // CHECK SUMを送信 + rdata = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(rdata); + break; + } + case 11: + { + // データ長を送信 + b_length = file->FgetUint8(); + r_count++; + sub_state=8; + send1byte(b_length); + break; + } + case 70: + { + // データ長が0x00だった時の後処理 + // CHECK SUMを送信 + rdata = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(rdata); + break; + } + case 71: + { + // ファイルエンドに達していたらFILE CLOSE + if (f_length == r_count) + { + file->Fclose(); + delete file; + file = nullptr; + } + sub_state = 1000; + break; + } + + case 100: + { + // ファイル名の指定がなかった場合 + // ファイルエンドになっていないか + if (f_length > r_count) + { + sub_state++; + send1byte(0x00); + flg = true; + } + else + { + sub_state++; + send1byte(0xf1); + flg = false; + } + break; + } + case 101: + { + sub_state = 2; + break; + } + + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::cmt_5f9e_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + if(file == nullptr) + { + // ファイルが末尾まで行っているか開いていない場合0xffを返す + sub_state++; + send1byte(0xff); + break; + } + rdata = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(rdata); + break; + } + case 2: + { + // ファイルエンドまで達していればFILE CLOSE + if (f_length == r_count && file != nullptr) + { + file->Fclose(); + delete file; + file = nullptr; + } + sub_state = 1000; + break; + } + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::bas_load_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + flg = false; + sub_state++; + receivename(m_name); + break; + } + case 2: + { + if(m_name[0] != 0x00) + { + addcmt(m_name, f_name); + + // 指定があった場合 + // ファイルが存在しなければERROR + if (SDFile::exists(f_name) == true) + { + // ファイルオープン + file = new FILEIO(); + if (file->Fopen(create_local_path("%s/%s", sd_folder_name, f_name), FILEIO_READ_BINARY)) + { + // f_length設定、r_count初期化 + f_length = file->FileLength(); + r_count = 0; + // 状態コード送信(OK) + flg = true; + sub_state++; + send1byte(0x00); + } + else + { + sub_state++; + send1byte(0xf0); + flg = false; + } + } + else + { + sub_state++; + send1byte(0xf1); + flg = false; + } + } else { + sub_state = 100; + } + break; + } + case 3: + { + if(flg == false) + { + sub_state = 1000; + break; + } + rdata = 0; + + // ヘッダーが出てくるまで読み飛ばし + while (rdata != 0x3a && rdata != 0xd3) + { + rdata = file->FgetUint8(); + r_count++; + } + sub_state++; + // ヘッダー送信 + send1byte(rdata); + break; + } + case 4: + { + // ヘッダーが0xd3なら続行、違えばエラー + if (rdata == 0xd3) + { + while (rdata == 0xd3) + { + rdata = file->FgetUint8(); + r_count++; + } + + // 実データ送信 + zcnt = 0; + zdata = 1; + + sub_state++; + send1byte(rdata); + } else { + file->Fclose(); + delete file; + file = nullptr; + sub_state = 1000; + break; + } + break; + } + case 5: + { + // 0x00が11個続くまで読み込み、送信 + if(zcnt >= 11) + { + sub_state = 50; + break; + } + + rdata = file->FgetUint8(); + r_count++; + sub_state++; + send1byte(rdata); + break; + } + case 6: + { + if (rdata == 0x00) + { + zcnt++; + if (zdata != 0) + { + zcnt = 0; + } + } + zdata = rdata; + sub_state = 5; + break; + } + case 50: + { + // ファイルエンドに達していたらFILE CLOSE + if (f_length == r_count) + { + file->Fclose(); + delete file; + file = nullptr; + } + sub_state = 1000; + break; + } + + case 100: + { + // ファイル名の指定がなかった場V合 + // ファイルエンドになっていないか + if (f_length > r_count) + { + sub_state=3; + send1byte(0x00); + flg = true; + } + else + { + sub_state=3; + send1byte(0xf1); + flg = false; + } + break; + } + + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::bas_save_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + flg = false; + sub_state++; + receivename(m_name); + break; + } + case 2: + { + if(m_name[0] != 0x00) + { + addcmt(m_name, f_name); + + if(w_file) + { + w_file->Fclose(); + } + + // ファイルが存在すればdelete + if(SDFile::exists(f_name)) + { + SDFile::remove(f_name); + } + + // ファイルオープン + w_file = new FILEIO(); + if (w_file->Fopen(create_sd_path(f_name), FILEIO_WRITE_BINARY)) + { + sub_state++; + send1byte(0x00); + break; + } else{ + sub_state = 1000; + send1byte(0xf0); + break; + } + } else { + sub_state = 100; + } + break; + } + case 3: + { + sub_state++; + // スタートアドレス取得 + receivebytes(2); + break; + } + case 4: + { + s_adrs1 = receive_datas[0]; + s_adrs2 = receive_datas[1]; + // スタートアドレス算出 + s_adrs = s_adrs1 + s_adrs2 * 256; + + sub_state++; + // エンドアドレス取得 + receivebytes(2); + break; + } + case 5: + { + s_adrs1 = receive_datas[0]; + s_adrs2 = receive_datas[1]; + // エンドアドレス算出 + e_adrs = s_adrs1 + s_adrs2 * 256; + // ヘッダー 0xD3 x 9回書き込み + for (lp1 = 0; lp1 <= 9; lp1++) + { + w_file->FputUint8(char(0xD3)); + } + // DOSファイル名の先頭6文字をファイルネームとして書き込み + for (lp1 = 0; lp1 <= 5; lp1++) + { + w_file->FputUint8(m_name[lp1]); + } + lp1 = s_adrs; + sub_state++; + break; + } + case 6: + { + if(lp1 > e_adrs) + { + sub_state = 8; + break; + } + sub_state++; + receive1byte(); + break; + } + case 7: + { + w_file->FputUint8(result_value); + lp1++; + sub_state = 6; + break; + } + case 8: + { + // 終了 0x00 x 9回書き込み + for (lp1 = 1; lp1 <= 9; lp1++) + { + w_file->FputUint8(char(0x00)); + } + w_file->Fclose(); + delete w_file; + w_file = nullptr; + sub_state = 1000; + break; + } + case 100: + { + sub_state = 1000; + send1byte(0xf1); + break; + } + + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::bas_kill_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + flg = false; + sub_state++; + receivename(m_name); + break; + } + case 2: + { + if(m_name[0] != 0x00) + { + addcmt(m_name, f_name); + + // 状態コード送信(OK) + sub_state++; + send1byte(0x00); + } else { + sub_state = 100; + } + break; + } + case 3: + { + // ファイルが存在すればdelete + if(SDFile::exists(f_name)) + { + SDFile::remove(f_name); + sub_state = 1000; + send1byte(0x00); + break; + } else { + sub_state = 1000; + send1byte(0xf1); + break; + } + } + case 100: + { + sub_state = 1000; + send1byte(0xf1); + break; + } + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::sd_ropen_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + flg = false; + sub_state++; + receivename(f_name); + break; + } + case 2: + { + // ファイルが存在しなければERROR + if (SDFile::exists(f_name) == true) + { + file = new FILEIO(); + if (file->Fopen(create_sd_path(f_name), FILEIO_READ_BINARY)) + { + // f_length設定、r_count初期化 + f_length = file->FileLength(); + r_count = 0; + // 状態コード送信(OK) + sub_state=1000; + send1byte(0x00); + break; + } else { + sub_state=1000; + send1byte(0xf0); + break; + } + } else { + sub_state=1000; + send1byte(0xf1); + break; + } + } + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::sd_waopen_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + flg = false; + sub_state++; + receivename(m_name); + break; + } + case 2: + { + // ファイルオープン + if (w_file != nullptr) + { + w_file->Fclose(); + } + + w_file = new FILEIO(); + if (w_file->Fopen(create_sd_path(w_name), FILEIO_WRITE_BINARY)) + { + // Appendなのでこれでいいのかな……? + w_file->Fseek(0, FILEIO_SEEK_END); + + sub_state = 1000; + // 状態コード送信(OK) + send1byte(0x00); + } + else + { + sub_state = 1000; + send1byte(0xf0); + } + break; + } + case 1000: + { + loopend(); + break; + } + } +} + + +void PC80SD::sd_w1byte_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + sub_state++; + receive1byte(); + break; + } + case 2: + { + int rdata = result_value; + if (w_file != nullptr) + { + w_file->FputUint8(rdata); + sub_state = 1000; + // 状態コード送信(OK) + send1byte(0x00); + } + else + { + sub_state = 1000; + send1byte(0xf0); + } + break; + } + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::sd_wnopen_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + flg = false; + sub_state++; + receivename(m_name); + break; + } + case 2: + { + if (w_file != nullptr) + { + w_file->Fclose(); + } + + // ファイルが存在すればdelete + if (SDFile::exists(w_name)) + { + SDFile::remove(w_name); + } + + // ファイルオープン + w_file = new FILEIO(); + if (w_file->Fopen(create_sd_path(w_name), FILEIO_WRITE_BINARY)) + { + sub_state = 1000; + // 状態コード送信(OK) + send1byte(0x00); + } + else + { + sub_state = 1000; + send1byte(0xf0); + } + break; + } + case 1000: + { + loopend(); + break; + } + } +} + +// 5ED9H代替 +void PC80SD::sd_wdirect_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + if (w_file != nullptr) + { + sub_state++; + w_body(); + } + else + { + sub_state = 1000; + send1byte(0xf0); + break; + } + break; + } + case 2: + { + w_file->Fclose(); + delete w_file; + w_file = nullptr; + // 状態コード送信(OK) + sub_state = 1000; + send1byte(0x00); + break; + } + case 1000: + { + loopend(); + break; + } + } +} + +// write file close +void PC80SD::sd_wclose_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0x00); + break; + } + case 1: + { + w_file->Fclose(); + delete w_file; + w_file = nullptr; + sub_state = 1000; + break; + } + case 1000: + { + loopend(); + break; + } + } +} + +void PC80SD::dirlist_proc() +{ + switch(sub_state) + { + case 0: + { + sub_state++; + send1byte(0); + break; + } + case 1: + { + // 32+1文字を受信 + sub_state++; + receivebytes(33); + + break; + } + case 2: + { + // OK + memcpy(c_name, receive_datas, 33); + sub_state++; + bool result = sd_file.open(create_local_path(sd_folder_name)); + if (result) + { + // OK + send1byte(0); + } else { + // error + sub_state = 11; + send1byte(0xf1); + } + break; + } + case 3: + { + sd_entry = sd_file.openNextFile(); + cntl2 = 0; + br_chk = 0; + page = 1; + sub_state++; + } + case 4: + { + if(br_chk != 0) + { + sub_state = 10; + break; + } else if (sd_entry.isValid()) + { + sd_entry.getName(f_name, 36); + unsigned int lp1 = 0; + // 一件送信 + // 比較文字列でファイルネームを/re先頭10文字まで比較して一致するものだけを出力 + if (f_match(f_name, c_name)) + { + // 最大36文字 or 0になるまで送信 + int len = 36; + int slen = strlen(f_name); + len = min(len, slen); + sub_state++; + sendbytes((uint8_t*)f_name, len); + break; + } + else { + sub_state = 6; + break; + } + } + sub_state = 6; + break; + } + case 5: + { + sub_state++; + sendbytes(cr_data, 2); + cntl2++; + break; + } + case 6: + { + if (!sd_entry.isValid() || cntl2 > 15) + { + // 継続・打ち切り選択指示要求 + sub_state++; + send1byte(0xfe); + } else { + sub_state = 9; + } + break; + } + case 7: + { + sub_state++; + receive1byte(); + break; + } + case 8: + { + sub_state++; + br_chk = result_value; + // 前ページ処理 + if (br_chk == 0x42) + { + // 先頭ファイルへ + sd_file.rewindDirectory(); + // entry値更新 + sd_entry = sd_file.openNextFile(); + // もう一度先頭ファイルへ + sd_file.rewindDirectory(); + if (page <= 2) + { + // 現在ページが1ページ又は2ページなら1ページ目に戻る処理 + page = 0; + } + else + { + // 現在ページが3ページ以降なら前々ページまでのファイルを読み飛ばす + page = page - 2; + cntl2 = 0; + while (cntl2 < page * 16) + { + sd_entry = sd_file.openNextFile(); + if (f_match(f_name, c_name)) + { + cntl2++; + } + } + } + br_chk = 0; + } + page++; + cntl2 = 0; + } + case 9: + { + // ファイルがまだあるなら次読み込み、なければ打ち切り指示 + if (sd_entry.isValid()) + { + sd_entry = sd_file.openNextFile(); + } + else + { + br_chk = 1; + } + // FDLの結果が18件未満なら継続指示要求せずにそのまま終了 + if (!sd_entry.isValid() && cntl2 < 16 && page == 1) + { + sub_state++; + } else { + sub_state = 4; + } + break; + } + case 10: + { + sub_state++; + sendbytes(end_data, 2); + break; + } + case 11: + { + loopend(); + break; + } + } +} + +void PC80SD::proc_state() +{ + + switch(state) + { + case PC80SD_INITIALIZE: + { + switch (sub_state) + { + case 0: + { + write_signals(&port[1].outputs, 0); + sub_state++; + wait_count = 0; + // break; + } + case 1: + { + wait_count++; + if (wait_count > 1000) + { + sub_state++; + } + break; + } + case 2: + { + write_signals(&port[2].outputs, 0x00); + state = PC80SD_WAIT_COMMAND; + sub_state = 0; + } + } + break; + } + case PC80SD_WAIT_COMMAND: + { + switch(sub_state) + { + case 0: + sub_state++; + receive1byte(); + break; + case 1: + { + state = result_value; + sub_state = 0; + break; + } + } + break; + } + case PC80SD_CMT_SAVE: + { + cmt_save_proc(); + break; + } + case PC80SD_CMT_LOAD: + { + cmt_load_proc(); + break; + } + case PC80SD_CMT_5F9E: + { + cmt_5f9e_proc(); + break; + } + case PC80SD_BAS_LOAD: + { + bas_load_proc(); + break; + } + case PC80SD_BAS_SAVE: + { + bas_save_proc(); + break; + } + case PC80SD_BAS_KILL: + { + bas_kill_proc(); + break; + } + case PC80SD_SD_ROPEN: + { + sd_ropen_proc(); + break; + } + case PC80SD_SD_WAOPEN: + { + sd_waopen_proc(); + break; + } + case PC80SD_SD_W1BYTE: + { + sd_w1byte_proc(); + break; + } + case PC80SD_SD_WNOPEN: + { + sd_wnopen_proc(); + break; + } + case PC80SD_SD_WDIRECT: + { + sd_wdirect_proc(); + break; + } + case PC80SD_SD_WCLOSE: + { + sd_wclose_proc(); + break; + } + case PC80SD_DIRLIST: + { + dirlist_proc(); + break; + } + case PC80SD_RCV1BYTE: + { + switch(sub_state) + { + case 0: + { + result_value = 0; + sub_state++; + receive4bit(); + break; + } + case 1: + { + result_value *= 16; + sub_state++; + receive4bit(); + break; + } + case 2: + { + popstate(); + break; + } + } + break; + } + case PC80SD_RCV4BIT: + { + switch(sub_state) + { + case 0: + { + if((port[2].reg & 0x4) == 0) + { + return; + } + sub_state = 1; + } + case 1: + { + result_value += port[0].reg & 0xf; + sub_state = 2; + break; + } + case 2: + { + write_signals(&port[2].outputs, 0x80 ); + sub_state = 3; + break; + } + case 3: + { + if((port[2].reg & 0x4) != 0) + { + return; + } + sub_state = 4; + break; + } + case 4: + { + write_signals(&port[2].outputs, 0x00); + popstate(); +// wait_count = 0; +// sub_state = 5; + break; + } +// case 5: +// { +// wait_count++; +// if(wait_count > 1000) +// { +// popstate(); +// } +// break; +// } + } + break; + case PC80SD_SND1BYTE: + { + switch(sub_state) + { + case 0: + { + write_signals(&port[1].outputs, send_value); + wait_count = 0; + sub_state++; + break; + } + case 1: + { + wait_count++; + if (wait_count > 700) + { + sub_state++; + } + break; + } + case 2: + { + write_signals(&port[2].outputs, 0x80 ); + sub_state++; + break; + } + case 3: + { + if((port[2].reg & 0x4) == 0) + { + return; + } + + write_signals(&port[2].outputs, 0x00); + sub_state++; + break; + } + case 4: + { + if((port[2].reg & 0x4) != 0) + { + return; + } + popstate(); + break; + } + } + break; + } + case PC80SD_RCVBYTES: + { + if(receive_datas_count == 0) + { + popstate(); + return; + } + if(sub_state == 0) + { + sub_state++; + receive1byte(); + } + else + { + receive_datas[receive_datas_index] = result_value; + receive_datas_index++; + receive_datas_count--; + sub_state = 0; + } + break; + } + case PC80SD_SNDBYTES: + { + if(send_datas_count == 0) + { + popstate(); + return; + } + if(sub_state == 0) + { + sub_state++; + send1byte(send_datas[send_datas_index]); + } + else + { + send_datas_index++; + send_datas_count--; + sub_state = 0; + } + break; + } + case PC80SD_RCVNAME: + { + switch(sub_state) + { + case 0: + { + lp2 = 0; + sub_state++; + } + case 1: + { + sub_state++; + receive1byte(); + break; + } + case 2: + { + char r_data = result_value; + if(r_data != 0x22) + { + target_data[lp2] = r_data; + lp2++; + } + if(lp2 == 33) + { + popstate(); + break; + } else { + sub_state = 1; + } + break; + } + } + break; + } + case PC80SD_WBODY: + { + w_body_proc(); + break; + } + } + } +} + +void PC80SD::event_callback(int event_id, int error) +{ + switch (event_id) + { + case EVENT_TIMER: + proc_state(); + break; + } +} \ No newline at end of file diff --git a/gdemu/src/emulator/vm/pc80sd.h b/gdemu/src/emulator/vm/pc80sd.h new file mode 100644 index 0000000..40e9b8d --- /dev/null +++ b/gdemu/src/emulator/vm/pc80sd.h @@ -0,0 +1,248 @@ +/* + Skelton for retropc emulator + + Author : Takeda.Toshiya + Date : 2009.03.08- + + [ PC-8001(mk2)_SD ] +*/ + +#ifndef _PC80SD_H_ +#define _PC80SD_H_ + +#include "vm.h" +#include "../emu.h" +#include "device.h" + +#if !(defined(_WIN32) || defined(_WIN64)) +#include +#include +#endif + +#if !(defined(_WIN32) || defined(_WIN64)) +#include +#endif + +class SDFileEntry +{ +private: + bool _isValid; + char name[1024]; + +public: + SDFileEntry() + { + invalidate(); + } + void invalidate() + { + _isValid = false; + } + SDFileEntry(const char *name) + { + strncpy(this->name, name, strlen(name) + 1); + _isValid = true; + } + + bool getName(char *name, int len) + { + if (!_isValid) + { + return false; + } + strncpy(name, this->name, len); + return true; + } + + bool isValid() { return _isValid; } +}; + +class SDFile +{ +private: + char base_path[1024]; + +#if defined(_WIN32) || defined(_WIN64) + WIN32_FIND_DATA ffd; + char szDir[MAX_PATH]; + HANDLE hFind = INVALID_HANDLE_VALUE; +#else + DIR *dir; + struct dirent *ent; +#endif + SDFileEntry currentEntry; + +public: + SDFile() + { + memset(base_path, 0, sizeof(base_path)); + } + ~SDFile() + { + close(); + } + bool open(const char *path); + SDFileEntry openNextFile(); + void rewindDirectory(); + void close(); + static bool exists(const char *path); + static bool remove(const char *path); +}; + +class StackNode { +public: + int data; + StackNode* next; +}; + +class Stack { +private: + StackNode* top_node; +public: + Stack() : top_node(nullptr) {} + + ~Stack() { + while (!empty()) { + pop(); + } + } + + void push(int value) { + StackNode* new_node = new StackNode(); + new_node->data = value; + new_node->next = top_node; + top_node = new_node; + } + + void pop() { + if (empty()) { + // std::cerr << "Stack is empty, cannot pop a value\n"; + return; + } + StackNode* temp = top_node; + top_node = top_node->next; + delete temp; + } + + int top() const { + if (empty()) { + // std::cerr << "Stack is empty, cannot get top\n"; + return -1; + } + return top_node->data; + } + + bool empty() const { + return top_node == nullptr; + } + + void clear() { + while (!empty()) { + pop(); + } + } +}; + +class PC80SD : public DEVICE +{ +private: + void proc_state(); + void proc_command(); + void sendbytes(const uint8_t*data, int sz); + void receivebytes(int count); + void receive1byte(); + void receive4bit(); + void popstate(); + void send1byte(uint8_t data); + void loopend(); + void receivename(char *f_name); + void w_body(); + void w_body_proc(); + + void dirlist_proc(); + void cmt_save_proc(); + void cmt_load_proc(); + void cmt_5f9e_proc(); + void bas_load_proc(); + void bas_save_proc(); + void bas_kill_proc(); + void sd_ropen_proc(); + void sd_waopen_proc(); + void sd_w1byte_proc(); + void sd_wnopen_proc(); + void sd_wdirect_proc(); + void sd_wclose_proc(); + + int state; + int sub_state; + int result_value; + int send_value; + int sd_command; + uint8_t receive_datas[256]; + uint8_t send_datas[65536]; + int send_datas_count; + int send_datas_index; + int receive_datas_count; + int receive_datas_index; + int wait_count; + char* target_data; + Stack stateStack; + SDFile sd_file; + SDFileEntry sd_entry; + int cntl2; + unsigned int br_chk; + int page; + bool flg; + unsigned int lp1; + unsigned int lp2; + int rdata; + uint8_t r_data; + uint8_t csum; + int zcnt; + int zdata; +public: + int register_id; + + struct { + uint8_t reg; + // output signals + outputs_t outputs; + } port[3]; + + PC80SD(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) + { + for(int i = 0; i < 3; i++) { + initialize_output_signals(&port[i].outputs); + port[i].reg = 0;//0xff; + } + state = sub_state = 0; + + set_device_name(_T("PC8001(mk2)_SD")); + } + ~PC80SD(); + + // common functions + void initialize(); + void release(); + void reset(); + void write_signal(int id, uint32_t data, uint32_t mask); + void event_callback(int event_id, int error); + + void write_signals_thread(int id, uint32_t data); + + void set_context_port_a(DEVICE* device, int id, uint32_t mask, int shift) + { + register_output_signal(&port[0].outputs, device, id, mask, shift); + } + void set_context_port_b(DEVICE* device, int id, uint32_t mask, int shift) + { + register_output_signal(&port[1].outputs, device, id, mask, shift); + } + void set_context_port_c(DEVICE* device, int id, uint32_t mask, int shift) + { + register_output_signal(&port[2].outputs, device, id, mask, shift); + } +}; + +#endif + diff --git a/gdemu/src/emulator/vm/pc8801/diskio.cpp b/gdemu/src/emulator/vm/pc8801/diskio.cpp index 30256cb..58d71de 100644 --- a/gdemu/src/emulator/vm/pc8801/diskio.cpp +++ b/gdemu/src/emulator/vm/pc8801/diskio.cpp @@ -179,7 +179,7 @@ void DiskIO::CmdReadFile() if (file->Fopen(create_absolute_path(char_to_tchar((char*) filename)), FILEIO_READ_BINARY)) { file->Fseek(0, FILEIO_SEEK_END); - size = min(0xffff, file->Ftell()); + size = min((unsigned int)0xffff, (unsigned int)file->Ftell()); file->Fseek(0, FILEIO_SEEK_SET); buf[0] = size & 0xff; buf[1] = (size >> 8) & 0xff; diff --git a/gdemu/src/emulator/vm/pc8801/diskio.h b/gdemu/src/emulator/vm/pc8801/diskio.h index 363d03b..59c0f38 100644 --- a/gdemu/src/emulator/vm/pc8801/diskio.h +++ b/gdemu/src/emulator/vm/pc8801/diskio.h @@ -27,6 +27,10 @@ class FILEIO; +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + // --------------------------------------------------------------------------- class DiskIO : public DEVICE diff --git a/gdemu/src/emulator/vm/pc8801/pc88.cpp b/gdemu/src/emulator/vm/pc8801/pc88.cpp index f0b9392..babde32 100644 --- a/gdemu/src/emulator/vm/pc8801/pc88.cpp +++ b/gdemu/src/emulator/vm/pc8801/pc88.cpp @@ -264,7 +264,14 @@ static const int key_conv_table[][3] = { }; static const uint8_t intr_mask2_table[8] = { - ~7, ~3, ~5, ~1, ~6, ~2, ~4, ~0 + (uint8_t)~7, + (uint8_t)~3, + (uint8_t)~5, + (uint8_t)~1, + (uint8_t)~6, + (uint8_t)~2, + (uint8_t)~4, + (uint8_t)~0 }; void PC88::initialize() @@ -351,6 +358,28 @@ void PC88::initialize() fio->Fclose(); } #endif + +#if defined(SUPPORT_PC80_SDCARD) + if(config.dipswitch & DIPSWITCH_PC8001_SD) { + if(fio->Fopen(create_local_path(_T("EXT_ROM_SHIFT_OFF.bin")), FILEIO_READ_BINARY)) { + fio->Fread(n80sdrom, 0x2000, 1); + fio->Fclose(); + } else if(fio->Fopen(create_local_path(_T("EXT_ROM_SHIFT_ON.bin")), FILEIO_READ_BINARY)) { + fio->Fread(n80sdrom, 0x2000, 1); + fio->Fclose(); + } else if(fio->Fopen(create_local_path(_T("EXT_ROM_A_OFF.bin")), FILEIO_READ_BINARY)) { + fio->Fread(n80sdrom, 0x2000, 1); + fio->Fclose(); + } else if(fio->Fopen(create_local_path(_T("EXT_ROM_A_ON.bin")), FILEIO_READ_BINARY)) { + fio->Fread(n80sdrom, 0x2000, 1); + fio->Fclose(); + } else if(fio->Fopen(create_local_path(_T("EXT_ROM.bin")), FILEIO_READ_BINARY)) { + fio->Fread(n80sdrom, 0x2000, 1); + fio->Fclose(); + } + } +#endif + #if defined(_PC8001SR) if(fio->Fopen(create_local_path(_T("N80_3.ROM")), FILEIO_READ_BINARY)) { fio->Fread(n80srrom, 0xa000, 1); @@ -525,7 +554,7 @@ void PC88::initialize() // initialize cmt cmt_fio = new FILEIO(); cmt_play = cmt_rec = false; - + register_frame_event(this); register_vline_event(this); register_event(this, EVENT_TIMER, 1000000.0 / 600.0, true, NULL); @@ -617,7 +646,16 @@ void PC88::reset() update_tvram_memmap(); // XM8 version 1.10 #endif #endif - + +#if defined(_PC8001) +#ifdef SUPPORT_PC80_SDCARD + if (config.dipswitch & DIPSWITCH_PC8001_SD) { + memcpy(n80rom + 0x6000, n80sdrom, 0x2000); + } +#endif +#endif + + // misc usart_dcd = false; opn_busy = true; @@ -1270,6 +1308,49 @@ void PC88::write_io8(uint32_t addr, uint32_t data) } break; #endif +#ifdef SUPPORT_PC80_SDCARD + // for PC-8001mk2_SD +#if defined(_PC8001MK2) + case 0x7c: // PPI_A +#else + case 0xfc: // PPI_A +#endif + if(d_sdcard != NULL) + { + d_sdcard->write_io8(0, data); + } + break; +#if defined(_PC8001MK2) + case 0x7d: // PPI_B +#else + case 0xfd: // PPI_B +#endif + if(d_sdcard != NULL) + { + d_sdcard->write_io8(1, data); + } + break; +#if defined(_PC8001MK2) + case 0x7e: // PPI_C +#else + case 0xfe: // PPI_C +#endif + if(d_sdcard != NULL) + { + d_sdcard->write_io8(2, data); + } + break; +#if defined(_PC8001MK2) + case 0x7f: // PPI_R +#else + case 0xff: // PPI_R +#endif + if(d_sdcard != NULL) + { + d_sdcard->write_io8(3, data); + } + break; +#endif #else case 0x71: if(mod & 0x03) { @@ -1523,12 +1604,15 @@ void PC88::write_io8(uint32_t addr, uint32_t data) } break; #endif + +#if !(defined(SUPPORT_PC80_SDCARD) && defined(_PC8001)) case 0xfc: case 0xfd: case 0xfe: case 0xff: d_pio->write_io8(addr, data); break; +#endif } } @@ -1762,6 +1846,49 @@ uint32_t PC88::read_io8_debug(uint32_t addr) } break; #endif + +#ifdef SUPPORT_PC80_SDCARD + // for PC-8001mk2_SD +#if defined(_PC8001MK2) + case 0x7c: // PPI_A +#else + case 0xfc: // PPI_A +#endif + if(d_sdcard != NULL) + { + return d_sdcard->read_io8(0); + } +#if defined(_PC8001MK2) + case 0x7d: // PPI_B +#else + case 0xfd: // PPI_B +#endif + if(d_sdcard != NULL) + { + return d_sdcard->read_io8(1); + } +#if defined(_PC8001MK2) + case 0x7e: // PPI_C +#else + case 0xfe: // PPI_C +#endif + if(d_sdcard != NULL) + { + return d_sdcard->read_io8(2); + } +#if defined(_PC8001MK2) + case 0x7f: // PPI_R +#else + case 0xff: // PPI_R +#endif + if(d_sdcard != NULL) + { + return d_sdcard->read_io8(3); + } + break; +#endif + + #ifdef SUPPORT_PC88_HMB20 // case 0x88: case 0x89: @@ -1944,10 +2071,13 @@ uint32_t PC88::read_io8_debug(uint32_t addr) } break; #endif + +#if !(defined(SUPPORT_PC80_SDCARD) && defined(_PC8001)) case 0xfc: case 0xfd: case 0xfe: return d_pio->read_io8(addr); +#endif } return 0xff; } @@ -2240,6 +2370,13 @@ void PC88::update_n80_read() if(d_diskio != NULL) { SET_BANK_R(0x6000, 0x7fff, n80erom); } else +#endif +#ifdef SUPPORT_PC80_SDCARD + if(config.dipswitch & DIPSWITCH_PC8001_SD) + { + SET_BANK_R(0x6000, 0x7fff, n80sdrom); + return; + } #endif SET_BANK_R(0x6000, 0x7fff, rdmy); return; diff --git a/gdemu/src/emulator/vm/pc8801/pc88.h b/gdemu/src/emulator/vm/pc8801/pc88.h index f634b62..ee8de46 100644 --- a/gdemu/src/emulator/vm/pc8801/pc88.h +++ b/gdemu/src/emulator/vm/pc8801/pc88.h @@ -161,6 +161,9 @@ class PC88 : public DEVICE #ifdef SUPPORT_M88_DISKDRV DEVICE *d_diskio; #endif +#ifdef SUPPORT_PC80_SDCARD + DEVICE *d_sdcard; +#endif uint8_t* rbank[16]; uint8_t* wbank[16]; @@ -183,6 +186,9 @@ class PC88 : public DEVICE #if defined(_PC8001MK2) || defined(_PC8001SR) uint8_t n80erom[0x2000]; #endif +#if defined(SUPPORT_PC80_SDCARD) + uint8_t n80sdrom[0x2000]; +#endif #if defined(_PC8001SR) uint8_t n80srrom[0xa000]; uint8_t hiragana[0x200]; @@ -352,6 +358,12 @@ class PC88 : public DEVICE void release_tape(); bool check_data_carrier(); + +#ifdef SUPPORT_PC80_SDCARD + FILEIO *sdcard_fio; + _TCHAR sd_file_path[_MAX_PATH]; + uint8_t sd_buffer[CMT_BUFFER_SIZE]; +#endif // beep/sing bool beep_on, beep_signal, sing_signal; @@ -416,6 +428,9 @@ class PC88 : public DEVICE set_device_name(_T("PC-8001 Core")); #else set_device_name(_T("PC-8801 Core")); +#endif +#ifdef SUPPORT_PC80_SDCARD + d_sdcard = NULL; #endif } ~PC88() {} @@ -562,6 +577,12 @@ class PC88 : public DEVICE { d_diskio = device; } +#endif +#ifdef SUPPORT_PC80_SDCARD + void set_context_sdcard(DEVICE* device) + { + d_sdcard = device; + } #endif void key_down(int code, bool repeat); bool get_caps_locked() diff --git a/gdemu/src/emulator/vm/pc8801/pc8801.cpp b/gdemu/src/emulator/vm/pc8801/pc8801.cpp index f7b59d4..e6cb05a 100644 --- a/gdemu/src/emulator/vm/pc8801/pc8801.cpp +++ b/gdemu/src/emulator/vm/pc8801/pc8801.cpp @@ -69,6 +69,10 @@ #include "diskio.h" #endif +#ifdef SUPPORT_PC80_SDCARD +#include "../pc80sd.h" +#endif + #include "pc88.h" // ---------------------------------------------------------------------------- @@ -369,6 +373,17 @@ VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu) pc88diskio = NULL; } #endif + +#ifdef SUPPORT_PC80_SDCARD + if(config.dipswitch & DIPSWITCH_PC8001_SD) { + pc80sd_pio = new I8255(this, emu); + pc80sd_pio->set_device_name(_T("8255 PIO (PC-8001(mkII)_SD board)")); + pc80sd_dev = new PC80SD(this, emu); + } else { + pc80sd_pio = NULL; + pc80sd_dev = NULL; + } +#endif // set cpu device contexts #ifdef SUPPORT_PC88_HIGH_CLOCK @@ -495,6 +510,17 @@ VM::VM(EMU* parent_emu) : VM_TEMPLATE(parent_emu) if(config.dipswitch & DIPSWITCH_M88_DISKDRV) { pc88->set_context_diskio(pc88diskio); } +#endif +#ifdef SUPPORT_PC80_SDCARD + if(config.dipswitch & DIPSWITCH_PC8001_SD) { + pc88->set_context_sdcard(pc80sd_pio); + pc80sd_pio->clear_ports_by_cmdreg = true; + pc80sd_pio->set_context_port_a(pc80sd_dev, SIG_I8255_PORT_A, 0xFF, 0); + pc80sd_pio->set_context_port_c(pc80sd_dev, SIG_I8255_PORT_C, 0x0F, 0); + + pc80sd_dev->set_context_port_b(pc80sd_pio, SIG_I8255_PORT_B, 0xFF, 0); + pc80sd_dev->set_context_port_c(pc80sd_pio, SIG_I8255_PORT_C, 0xF0, 0); + } #endif pc88cpu->set_context_mem(pc88); pc88cpu->set_context_io(pc88); @@ -677,6 +703,12 @@ void VM::reset() pc88pio_sub->write_signal(SIG_I8255_PORT_C, 0, 0xff); } pc88pio->write_signal(SIG_I8255_PORT_C, 0, 0xff); + +#ifdef SUPPORT_PC80_SDCARD + if(config.dipswitch & DIPSWITCH_PC8001_SD) { + pc80sd_pio->write_signal(SIG_I8255_PORT_C, 0, 0xff); + } +#endif } void VM::run() diff --git a/gdemu/src/emulator/vm/pc8801/pc8801.h b/gdemu/src/emulator/vm/pc8801/pc8801.h index d89cc7f..5aa0e7c 100644 --- a/gdemu/src/emulator/vm/pc8801/pc8801.h +++ b/gdemu/src/emulator/vm/pc8801/pc8801.h @@ -112,11 +112,13 @@ #define PC88_EXRAM_BANKS 1 #define SUPPORT_PC88_FDD_8INCH #define SUPPORT_M88_DISKDRV + #define SUPPORT_PC80_SDCARD #elif defined(_PC8001) // #define SUPPORT_PC88_KANJI1 // #define SUPPORT_PC88_KANJI2 // #define SUPPORT_PC88_FDD_8INCH // #define SUPPORT_M88_DISKDRV + #define SUPPORT_PC80_SDCARD #endif #define SUPPORT_PC88_GSX8800 #define SUPPORT_PC88_PCG8100 @@ -165,7 +167,8 @@ #define DIPSWITCH_M88_DISKDRV 0x100 #define DIPSWITCH_QUASIS88_CMT 0x200 #define DIPSWITCH_16BIT 0x400 -#define DIPSWITCH_DEFAULT (DIPSWITCH_HMB20 + DIPSWITCH_GSX8800 + DIPSWITCH_PCG8100 + DIPSWITCH_CMDSING + DIPSWITCH_FDD_5INCH) +#define DIPSWITCH_PC8001_SD 0x800 +#define DIPSWITCH_DEFAULT (DIPSWITCH_HMB20 + DIPSWITCH_GSX8800 + DIPSWITCH_PCG8100 + DIPSWITCH_CMDSING + DIPSWITCH_FDD_5INCH + DIPSWITCH_PC8001_SD) #define USE_JOYSTICK_TYPE 2 #if defined(SUPPORT_PC88_FDD_8INCH) #define USE_FLOPPY_DISK 4 @@ -178,7 +181,7 @@ #define USE_COMPACT_DISC 1 #endif #define USE_KEY_LOCKED -// slow enough for N88-日本語BASIC +// slow enough for N88-ソスソスソス{ソスソスBASIC #define USE_AUTO_KEY 8 #define USE_AUTO_KEY_RELEASE 10 #define USE_AUTO_KEY_NUMPAD @@ -244,7 +247,9 @@ #else #define USE_PRINTER_TYPE 3 #endif +#if !defined(_GDNATIVE_) #define USE_DEBUGGER +#endif #define USE_STATE #include "../../common.h" @@ -342,6 +347,10 @@ class MEMORY; class DiskIO; #endif +#ifdef SUPPORT_PC80_SDCARD +class PC80SD; +#endif + class PC88; class VM : public VM_TEMPLATE @@ -418,6 +427,11 @@ class VM : public VM_TEMPLATE #ifdef SUPPORT_M88_DISKDRV DiskIO* pc88diskio; #endif + +#ifdef SUPPORT_PC80_SDCARD + I8255* pc80sd_pio; + PC80SD* pc80sd_dev; +#endif PC88* pc88; diff --git a/gdemu/src/gdemu.cpp b/gdemu/src/gdemu.cpp index 3f3a025..bc55d94 100644 --- a/gdemu/src/gdemu.cpp +++ b/gdemu/src/gdemu.cpp @@ -81,6 +81,38 @@ static void file_copy(String from, String to) } } +static void folder_copy(String folder_name) +{ + Ref dir = DirAccess::open("user://"); + if(!dir->dir_exists(folder_name)) + { + dir->make_dir(folder_name); + } + // from繝輔か繝ォ繝蜀縺ョ蜈ィ縺ヲ縺ョ繝輔ぃ繧、繝ォ繧稚o繝輔か繝ォ繝縺ォ繧ウ繝斐シ縺吶k + dir = DirAccess::open("res://" + folder_name); + if(dir->get_open_error() == Error::OK) + { + dir->list_dir_begin(); + String file = dir->get_next(); + while(file != "") + { + String from_file = "res://" + folder_name + "/" + file; + String to_file = "user://" + folder_name + "/" + file; + if(dir->current_is_dir()) + { + // 繝輔か繝ォ繝縺ッ辟。隕 + file = dir->get_next(); + continue; + } + else + { + // 繝輔ぃ繧、繝ォ縺ェ繧峨さ繝斐シ + dir->copy(from_file, to_file); + } + file = dir->get_next(); + } + } +} void GDEmu::setup() { @@ -147,6 +179,20 @@ void GDEmu::init() { file_copy("res://N80.ROM", "user://N80.ROM"); #endif +#if defined(_PC8001MK2) + file_copy("res://N80_2.ROM", "user://N80_2.ROM"); + file_copy("res://N80_3.ROM", "user://N80_3.ROM"); + file_copy("res://KANJI1.ROM", "user://KANJI1.ROM"); +#endif + +#ifdef SUPPORT_PC80_SDCARD + file_copy("res://EXT_ROM_SHIFT_OFF.bin", "user://EXT_ROM_SHIFT_OFF.bin"); + file_copy("res://EXT_ROM_SHIFT_ON.bin", "user://EXT_ROM_SHIFT_ON.bin"); + file_copy("res://EXT_ROM_A_OFF.bin", "user://EXT_ROM_A_OFF.bin"); + file_copy("res://EXT_ROM_A_ON.bin", "user://EXT_ROM_A_ON.bin"); + folder_copy("SD"); +#endif + // 繝輔Ο繝繝斐シ繧「繧ッ繧サ繧ケ髻ウ file_copy("res://FDDSEEK.BIN", "user://FDDSEEK.WAV");