--- nono/lib/mainapp.cpp 2026/04/29 17:05:22 1.1.1.16 +++ nono/lib/mainapp.cpp 2026/04/29 17:05:47 1.1.1.22 @@ -16,17 +16,17 @@ #include "monitor.h" #include "mystring.h" #include "mythread.h" -#include "sram.h" +#include "uimessage.h" #include "vm_luna.h" #include "vm_news.h" #include "vm_virt68k.h" #include "vm_x68k.h" -#include #include #include #include #include #include +#include #if defined(__linux__) #include #endif @@ -52,6 +52,8 @@ MainApp::~MainApp() pMonitorManager.reset(); gMonitorManager = NULL; + hostcpu.reset(); + #if 0 // 確認用 if (objects.empty() == false) { printf("~MainApp: undead objects are:"); @@ -85,6 +87,8 @@ MainApp::ShowHelp(bool all) const printf("usage: %s []\n", getprogname()); p("-c vm directory or configuration file"); p("-f fast mode (same as '-V fast-mode=1')"); + p("--fd[01] specify floppy image (same as '-V fdN-image=' except"); + p(" base directory)"); if (IsGUI()) p("--fontsize fontsize (same as '-V monitor-fontsize=')"); p("-h show brief help message"); @@ -100,11 +104,15 @@ MainApp::ShowHelp(bool all) const if (all) { printf("\n(options for developers)\n"); - p("-b [,][,]"); + p("--b [,][,] (or -b)"); p(" set breakpoint. is either 'main'(default) or 'xp'"); + p("--bi [,][:][,]"); + p(" set instruction breakpoint."); p("--bi-exg set instruction breakpoint on 'exg sp,sp'"); - p("-B benchmark mode"); + p("--bv [,][-][,]"); + p(" set vector breakpoint."); p("-C output log to console"); + p("--console-log specify the console output log"); p("-d debugger prompt on startup"); p("-D same as '-V debugger-driver=stdio'"); p("-H human68k console emulation"); @@ -121,8 +129,12 @@ MainApp::ShowHelp(bool all) const // 0x80 から始めておく。 enum { OPTstart = 0x80 - 1, + OPT_bi, OPT_bi_exg, - OPT_create_sram, + OPT_bv, + OPT_console_log, + OPT_fd0, + OPT_fd1, OPT_fontsize, OPT_help, OPT_initrd, @@ -132,8 +144,13 @@ enum { OPT_show_hostnet, }; static struct option longopts[] = { + { "b", required_argument, NULL, 'b' }, + { "bi", required_argument, NULL, OPT_bi }, { "bi-exg", no_argument, NULL, OPT_bi_exg }, - { "create-sram", no_argument, NULL, OPT_create_sram }, + { "bv", required_argument, NULL, OPT_bv }, + { "console-log", required_argument, NULL, OPT_console_log }, + { "fd0", required_argument, NULL, OPT_fd0 }, + { "fd1", required_argument, NULL, OPT_fd1 }, { "fontsize", required_argument, NULL, OPT_fontsize }, { "help", no_argument, NULL, OPT_help }, { "initrd", required_argument, NULL, OPT_initrd }, @@ -152,13 +169,13 @@ static struct option longopts[] = { // MainApp::PASS .. 実行を継続(通常パス) // EXIT_SUCCESS / EXIT_FAILURE .. この終了コードでアプリケーションを終了 int -MainApp::Init1(bool is_cli_, int ac, char *av[]) +MainApp::Init1(int ac, char *av[], std::string (*conv)(const std::string&)) { int rv; - is_cli = is_cli_; + is_cli = (conv == NULL); - rv = Init1a(ac, av); + rv = Init1a(ac, av, conv); if (rv != MainApp::PASS) { return rv; } @@ -170,7 +187,7 @@ MainApp::Init1(bool is_cli_, int ac, cha // VM の初期化、ステージ1 の前半。 // Config.Fix まで。 int -MainApp::Init1a(int ac, char *av[]) +MainApp::Init1a(int ac, char *av[], std::string (*conv)(const std::string&)) { int rv; @@ -185,15 +202,24 @@ MainApp::Init1a(int ac, char *av[]) return rv; } - // ログ機構は引数処理後なるはや + // モニタマネージャ (VM 作成より前、もしかしたら Config より前?) + pMonitorManager.reset(new MonitorManager()); + gMonitorManager = pMonitorManager.get(); + + // ログ機構は引数処理後なるはや…にしたいがモニタマネージャは必要。 // CLI ならログは常に標準出力へ(も)出力。 // GUI なら -C で指定。 logger.reset(new Logger()); - logger->UseStdout(IsCLI() ? true : log_to_console); + if (IsCLI()) { + logger->UseStdout(true); + } else { + logger->UseStdout(log_to_console); + logger->SetConverter(conv); + } + logger->StartThread(); - // モニタマネージャ (VM 作成より前、もしかしたら Config より前?) - pMonitorManager.reset(new MonitorManager()); - gMonitorManager = pMonitorManager.get(); + // UIMessage は VM 起動前ならどこでもいいはず。 + uimessage.reset(new UIMessage()); // 設定を作成。 // c0. コンストラクタで初期値を用意。 @@ -216,10 +242,11 @@ MainApp::Init1a(int ac, char *av[]) // c2. VM ディレクトリに設定ファイルがあれば読み込んで設定を更新。 // vmfile が存在するかどうかはここで調べるまで分からない。 ConfigFile cfgfile(vmfile, ConfigItem::FromConfig); - if (cfgfile.Load()) { - if (gConfig->Update(cfgfile) == false) { - return EXIT_FAILURE; - } + if (cfgfile.Load() == false) { + return EXIT_FAILURE; + } + if (gConfig->Update(cfgfile) == false) { + return EXIT_FAILURE; } // c3. 最後にコマンドライン引数で更新 @@ -240,17 +267,26 @@ MainApp::Init1a(int ac, char *av[]) const ConfigItem& itemarg = gConfig->Find("exec-arg"); exec_arg = itemarg.AsString(); - // MSX-DOS モードならここでいくつかパラメータを強制的に変更。 + // Human68k/MSX-DOS モードならここでいくつかパラメータを強制的に変更。 + if (human_mode) { + // X68030 最小構成でいい。 + gConfig->Update("vmtype=x68030", "-H"); + } if (msxdos_mode) { - // LUNA-I 最小構成でいい + // LUNA-I 最小構成でいい。 gConfig->Update("vmtype=luna", "-S"); gConfig->Update("ram-size=16", "-S"); gConfig->Update("luna-video-plane=1", "-S"); // ホスト側には干渉しない。 - gConfig->Update("hostcom-driver=none", "-S"); + gConfig->Update("hostcom0-driver=none", "-S"); + gConfig->Update("hostcom1-driver=none", "-S"); + gConfig->Update("hostcom2-driver=none", "-S"); gConfig->Update("hostnet-driver=none", "-S"); } + // ログ表示のためだけのオブジェクト + hostcpu.reset(new Object(OBJ_HOSTCPU)); + // ホスト CPU の機能チェック。 if (CheckCPU() == false) { return EXIT_FAILURE; @@ -268,7 +304,7 @@ MainApp::Init1a(int ac, char *av[]) vmtype = VMType::LUNA88K; } else if (vmstr == "news") { vmtype = VMType::NEWS; - } else if (vmstr == "virt68k") { + } else if (vmstr == "virt-m68k" || vmstr == "virt68k") { vmtype = VMType::VIRT68K; } else { if (item.GetFrom() == ConfigItem::FromInitial) { @@ -281,16 +317,6 @@ MainApp::Init1a(int ac, char *av[]) return EXIT_FAILURE; } - // 0.5. VM が確定したところで SRAM 作成。 - if (create_sram) { - if (vmtype == VMType::X68030) { - return CreateSRAM(); - } else { - warnx("--create-sram is only for X68030 mode"); - return EXIT_FAILURE; - } - } - // 1. VM 作成 switch (vmtype) { case VMType::X68030: @@ -317,13 +343,14 @@ MainApp::Init1a(int ac, char *av[]) PANIC("vmtype=%s not configured", vmstr.c_str()); } - // 2. 動的なコンストラクション - if (!pVM->Create()) { + // 2. 動的なコンストラクションその1 + // 3. ログ出力用の EarlyInit + if (!pVM->Create(VM::CreationPhase::First)) { pVM.reset(); return EXIT_FAILURE; } - // 3. 設定を確定。 + // 4. 設定を確定。 // (VM コンストラクタで変数の増減があるのでそれより後、 // Create() でも SCSI パラメータを減らすので、それより後) if (gConfig->Fix() == false) { @@ -344,21 +371,21 @@ MainApp::Init1a(int ac, char *av[]) int MainApp::Init1b() { - // 3.1 設定が確定したので --show-config なら設定内容を表示して終了。 + // 4.1 設定が確定したので --show-config なら設定内容を表示して終了。 if (show_config) { gConfig->Show(show_config - 1); pVM.reset(); return EXIT_SUCCESS; } - // 3.2 ログレベルを設定。コンストラクト後すぐに行う。 + // 4.2 ログレベルを設定。コンストラクト後すぐに行う。 // -L help もここで処理。 if (!ParseLogopt()) { pVM.reset(); return EXIT_FAILURE; } - // 3.3 -X のチェック。 + // 4.3 -X のチェック。 // -L help より後にしないとヘルプが表示できない。 const ConfigItem& itemexec = gConfig->Find("exec-file"); if (exec_file == NULL) { @@ -393,6 +420,13 @@ MainApp::Init1b() } } + // 5. 動的コンストラクションその2 + // ログ出力が出来る代わりにログクラスはもう増やせない。 + if (!pVM->Create(VM::CreationPhase::Second)) { + pVM.reset(); + return EXIT_FAILURE; + } + return PASS; } @@ -403,7 +437,7 @@ MainApp::Init1b() bool MainApp::Init2() { - // 5. VM 初期化。 + // 7. VM 初期化。 if (!pVM->Init()) { return false; } @@ -411,16 +445,11 @@ MainApp::Init2() // メインスレッド名を設定 PTHREAD_SETNAME("Main"); - // 6. スレッド開始 + // 8. スレッド開始 if (!pVM->StartThread()) { return false; } - // 7. 起動時設定の適用 - if (!pVM->Apply()) { - return false; - } - return true; } @@ -433,32 +462,22 @@ MainApp::ParseOpt(int ac, char *av[]) { struct stat st; const char *cpath; - int b; int c; - cpath = "."; + cpath = NULL; - while ((c = getopt_long(ac, av, "b:B:c:CdDfhHL:M:s:SvV:X:", + while ((c = getopt_long(ac, av, "b:c:CdDfhHL:M:s:SvV:X:", longopts, NULL)) != -1) { switch (c) { case 'b': debug_breakaddr.push_back(optarg); break; - case 'B': - b = atoi(optarg); - if (b < 2 || b > 6) { - fprintf(stderr, "-B : 2..6\n"); - return EXIT_FAILURE; - } - benchmark_mode = b; - break; - case 'c': cpath = optarg; // 空文字列なら再び初期値に if (cpath[0] == '\0') { - cpath = "."; + cpath = NULL; } break; @@ -480,6 +499,18 @@ MainApp::ParseOpt(int ac, char *av[]) config_options.emplace_back("fast-mode=1", "-f"); break; + case OPT_fd0: + case OPT_fd1: + { + int fd = c - OPT_fd0; + // 相対パスはカレントディレクトリを起点とする。 + std::string line = string_format("fd%u-image=%s", fd, + AbsPath(optarg).c_str()); + std::string from = string_format("--fd%u", fd); + config_options.emplace_back(line, from); + break; + } + case 'H': human_mode = true; break; @@ -509,10 +540,7 @@ MainApp::ParseOpt(int ac, char *av[]) case 'X': { // 相対パスはカレントディレクトリ起点とする。 - char cwd[PATH_MAX]; - getcwd(cwd, sizeof(cwd)); - std::string path = NormalizePath(optarg, std::string(cwd)); - std::string line = "exec-file=" + path; + std::string line = "exec-file=" + AbsPath(optarg); config_options.emplace_back(line, "-X"); // Human68k モードなら後続を引数にする。 @@ -540,12 +568,22 @@ MainApp::ParseOpt(int ac, char *av[]) config_options.emplace_back(optarg, "-V"); break; + case OPT_bi: + debug_breakinst.push_back(optarg); + break; + case OPT_bi_exg: debug_breakinst_exg = true; break; - case OPT_create_sram: - create_sram = true; + case OPT_bv: + debug_breakvec.push_back(optarg); + break; + + case OPT_console_log: + // この時点ではコンソールを持つ VM かどうかが分からないので + // コンソールのない設定でもエラーを出さない(出せない)。 + console_logfile = optarg; break; case OPT_fontsize: @@ -562,39 +600,16 @@ MainApp::ParseOpt(int ac, char *av[]) case OPT_initrd: { // 相対パスはカレントディレクトリを起点とする。 - char cwd[PATH_MAX]; - getcwd(cwd, sizeof(cwd)); - std::string path = NormalizePath(optarg, std::string(cwd)); - std::string line = "exec-initrd=" + path; + std::string line = "exec-initrd=" + AbsPath(optarg); config_options.emplace_back(line, "--initrd"); break; } case OPT_perf: - { - // パフォーマンス確認用。 - // -Vprom-image=PROM.DAT はパスの問題があるので各自で追加指定 - // する必要がある。 - std::string where = "--perf -V"; - config_options.emplace_back(".rtc-force-fixed=1", where); - config_options.emplace_back("clock-sync=virtual", where); - config_options.emplace_back("ethernet-macaddr=02:00:00:00:00:01", - where); - config_options.emplace_back("hostcom-driver=none", where); - config_options.emplace_back("hostnet-driver=none", where); - config_options.emplace_back("luna-dipsw1=11110111", where); - config_options.emplace_back("spc0-id0-writeignore=1", where); - config_options.emplace_back("spc0-id1-writeignore=1", where); - config_options.emplace_back("spc0-id2-writeignore=1", where); - config_options.emplace_back("spc0-id3-writeignore=1", where); - config_options.emplace_back("spc0-id4-writeignore=1", where); - config_options.emplace_back("spc0-id5-writeignore=1", where); - config_options.emplace_back("spc0-id6-writeignore=1", where); - config_options.emplace_back("fast-mode=1", where); - // -C + // パフォーマンス確認用。(Config::Update() 側で展開する) + config_options.emplace_back("--perf", ""); log_to_console = true; break; - } case OPT_show_config: show_config = 1; @@ -618,33 +633,45 @@ MainApp::ParseOpt(int ac, char *av[]) } } - // 引数がディレクトリなら、それを VM ディレクトリとし、その中の - // nono.cfg を設定ファイルとする。 - // 引数がファイルなら、それを設定ファイルとし、そのファイルがある - // ディレクトリを VM ディレクトリとする。 - // -c DIR => vmdir = DIR, vmfile = DIR/nono.cfg - // -c DIR/FILE => vmdir = DIR, vmfile = FILE - if (stat(cpath, &st) < 0) { - warn("stat %s", cpath); - return EXIT_FAILURE; + if (human_mode) { + // Human モードで -c ありなら、VM ディレクトリ指定。 + // Human モードで -c 省略なら、VM ディレクトリなし (cpath==NULL)。 + } else { + // Human モードでなければ、-c 省略は -c . と同義。 + if (cpath == NULL) { + cpath = "."; + } } - if (S_ISDIR(st.st_mode)) { - vmdir = std::string(cpath); - if (vmdir.back() != '/') { - vmdir += '/'; - } - vmfile = vmdir + "nono.cfg"; - } else if (S_ISREG(st.st_mode)) { - vmfile = std::string(cpath); - auto pos = vmfile.rfind('/'); - if (pos != std::string::npos) { - vmdir = vmfile.substr(0, pos + 1); + + if (cpath != NULL) { + // 引数がディレクトリなら、それを VM ディレクトリとし、その中の + // nono.cfg を設定ファイルとする。 + // 引数がファイルなら、それを設定ファイルとし、そのファイルがある + // ディレクトリを VM ディレクトリとする。 + // -c DIR => vmdir = DIR, vmfile = DIR/nono.cfg + // -c DIR/FILE => vmdir = DIR, vmfile = FILE + if (stat(cpath, &st) < 0) { + warn("stat %s", cpath); + return EXIT_FAILURE; + } + if (S_ISDIR(st.st_mode)) { + vmdir = std::string(cpath); + if (vmdir.back() != '/') { + vmdir += '/'; + } + vmfile = vmdir + "nono.cfg"; + } else if (S_ISREG(st.st_mode)) { + vmfile = std::string(cpath); + auto pos = vmfile.rfind('/'); + if (pos != std::string::npos) { + vmdir = vmfile.substr(0, pos + 1); + } else { + vmdir = "./"; + } } else { - vmdir = "./"; + warnx("-c %s: path must be file or directory", cpath); + return EXIT_FAILURE; } - } else { - warnx("-c %s: path must be file or directory", cpath); - return EXIT_FAILURE; } // CLI 版で -Mhelp つけても黙って起動するのはさすがにどうかと思う。 @@ -665,10 +692,64 @@ MainApp::ParseOpt(int ac, char *av[]) return MainApp::PASS; } +// path を絶対パスにして返す。 +// 相対パスならカレントディレクトリからのパスとする。 +/*static*/ std::string +MainApp::AbsPath(const char *path) +{ + char cwd[PATH_MAX]; + + getcwd(cwd, sizeof(cwd)); + return NormalizePath(optarg, std::string(cwd)); +} + // CPU の機能とかをチェック。 bool MainApp::CheckCPU() { + const ConfigItem& item_aff = gConfig->Find(".host-cpu-affinity"); + std::string cfg_aff = item_aff.AsString(); + + if (cfg_aff.empty() || cfg_aff == "auto") { + // 指定なし + // (auto も今の所指定なしと同じ) + cpu_affinity = CPUAffinity::None; + } else if (cfg_aff.find(':') == std::string::npos) { + item_aff.Err(); + } else { + // 書式は ":"。 + // は "low", "high", "perf" のいずれか。 + // は "0,3-5,7" みたいな感じ。 + std::vector vals = string_split(cfg_aff, ':'); + std::string key = string_trim(vals[0]); + std::string csv = vals[1]; + if (key == "low") { + cpu_affinity = CPUAffinity::Low; + } else if (key == "high") { + cpu_affinity = CPUAffinity::High; + } else if (key == "perf") { + cpu_affinity = CPUAffinity::Perf; + } else { + item_aff.Err("Invalid affinity keyword"); + } + cpu_list.resize(std::thread::hardware_concurrency()); + auto errmsg = ParseCPUList(cpu_list, csv); + if (errmsg.empty() == false) { + item_aff.Err(errmsg); + return false; + } + + // 全部 true/false なら、これは意味がないのでクリアする。 + uint num = std::count(cpu_list.begin(), cpu_list.end(), true); + if (num == 0) { + item_aff.Err("No valid cores specified (Ignoring it)"); + cpu_affinity = CPUAffinity::None; + } else if (num == cpu_list.size()) { + item_aff.Err("All cores specified (Ignoring it)"); + cpu_affinity = CPUAffinity::None; + } + } + #if defined(HAVE_AVX2) // AVX2 detect_avx2 = ::DetectAVX2(); @@ -685,10 +766,114 @@ MainApp::CheckCPU() return false; } #endif - // AVX2 以外は何もしない。設定のチェックもしないほうがいい。 + +#if defined(HAVE_NEON) + // NEON は aarch64 なら必ずある? + detect_neon = true; + + const ConfigItem& item_neon = gConfig->Find("host-neon"); + std::string cfg_neon = item_neon.AsString(); + + if (cfg_neon == "auto") { + enable_neon = detect_neon; + } else if (cfg_neon == "no") { + enable_neon = false; + } else { + item_neon.Err("must be either \"auto\" or \"no\"."); + return false; + } +#endif + + // 何もしない。設定のチェックもしないほうがいい。 return true; } +// CPU 番号リストの文字列からビット配列を作って返す。 +// cpulist は CPU コア数で初期化(resize)しておくこと。 +// 成功すれば string.empty を返す。 +// 失敗すればエラーメッセージを返す。 +std::string +MainApp::ParseCPUList(std::vector& cpulist, const std::string& input) +{ + if (input.empty()) { + return " must be specified"; + } + + // 設定は "0,3-5,7,10-" のような書式 + std::vector csv = string_split(input, ','); + for (auto& r : csv) { + const char *str; + char *endp; + uint start, last; + + if (r.empty()) { + // 空なら無視する? + continue; + } else if (r.find('-') == std::string::npos) { + // '-' がなければ単独 + str = &r[0]; + errno = 0; + start = strtoul(str, &endp, 10); + if (endp == str || *endp != '\0' || errno == ERANGE) { + return "syntax error"; + } + last = start; + } else if (r[0] == '-') { + // "-a" なら範囲 [0, a] + str = &r[1]; + errno = 0; + last = strtoul(str, &endp, 10); + if (endp == str || *endp != '\0' || errno == ERANGE) { + return "syntax error"; + } + start = 0; + } else if (r[r.size() - 1] == '-') { + // "a-" なら範囲 [a, MAX] + str = &r[0]; + errno = 0; + start = strtoul(str, &endp, 10); + if (endp == str || endp != &r[r.size() - 1] || errno == ERANGE) { + return "syntax error"; + } + last = cpulist.size(); + } else { + // "a-b" なら範囲 [a, b] + str = &r[0]; + errno = 0; + start = strtoul(str, &endp, 10); + if (endp == str || *endp != '-' || errno == ERANGE) { + return "syntax error"; + } + + str = endp + 1; + last = strtoul(str, &endp, 10); + if (endp == str || *endp != '\0' || errno == ERANGE) { + return "syntax error"; + } + + if (start > last) { + uint tmp = start; + start = last; + last = tmp; + } + } + + if (start >= cpulist.size()) { + return string_format("cpu number %u exceeds number of cores(%zu)", + start, cpulist.size()); + } + if (last >= cpulist.size()) { + return string_format("cpu number %u exceeds number of cores(%zu)", + start, cpulist.size()); + } + for (uint n = start; n <= last; n++) { + cpulist[n] = true; + } + } + + return ""; +} + // バージョンを表示 void MainApp::ShowVersion() const @@ -811,33 +996,22 @@ MainApp::SetLogopt1(const std::string& i } return true; } - // "fdd" なら "fdd*" 全部にする - if (name == "fdd") { - for (auto obj : gMainApp.GetObjects()) { - if (strncasecmp(obj->GetName().c_str(), "fdd", 3) == 0) { - obj->SetLogLevel(level); - } - } - return true; - } - // "bankram" も "bankram[01]" 両方にする - if (name == "bankram") { - for (auto obj : gMainApp.GetObjects()) { - if (strncasecmp(obj->GetName().c_str(), "bankram", 7) == 0) { - obj->SetLogLevel(level); - } - } - return true; - } - // "gfpic" も "gfpic*" 全部にする - if (name == "gfpic") { - for (auto obj : gMainApp.GetObjects()) { - if (strncasecmp(obj->GetName().c_str(), "gfpic", 5) == 0) { - obj->SetLogLevel(level); - } - } - return true; - } + + // "" なら "*" 全部に展開する。 +#define EXPAND(key) do { \ + if (name == key) { \ + for (auto obj : gMainApp.GetObjects()) { \ + if (strncasecmp(obj->GetName().c_str(), key, strlen(key)) == 0) \ + obj->SetLogLevel(level); \ + } \ + return true; \ + } \ +} while (0) + EXPAND("bankram"); + EXPAND("fdd"); + EXPAND("gfpic"); + EXPAND("hostcom"); + EXPAND("hostnet"); // エイリアスリストを作る using aliaslist_t = std::vector>; @@ -997,9 +1171,8 @@ MainApp::NormalizePath(const std::string // path を必要なら絶対パスに展開して返す。 // 相対パスは basedir を起点とする。 -std::string -MainApp::NormalizePath(const std::string& path, - const std::string& basedir) const +/*static*/ std::string +MainApp::NormalizePath(const std::string& path, const std::string& basedir) { // 絶対パスならそのまま返す。 if (path[0] == '/') { @@ -1030,48 +1203,6 @@ MainApp::NormalizePath(const std::string return newpath; } -// 初回起動時用に SRAM.DAT を作成する。 -// 戻り値は EXIT_SUCCESS / EXIT_FAILURE。 -int -MainApp::CreateSRAM() -{ - char buf[16 * 1024]; - std::string filename; - autofd fd; - int r; - - filename = GetVMDir() + "SRAM.DAT"; - - // 存在確認のため一旦読み込み専用で開いてみる。 - // オープン出来たら何もしない。 - fd = open(filename.c_str(), O_RDONLY); - if (fd >= 0) { - warnx("%s: Already exists", filename.c_str()); - return EXIT_FAILURE; - } - - fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) { - warn("%s: open failed", filename.c_str()); - return EXIT_FAILURE; - } - - memset(&buf[0], 0, sizeof(buf)); - for (int i = 0; i < SRAMDevice::InitialData.size(); i++) { - buf[i] = SRAMDevice::InitialData[i]; - } - - r = write(fd, buf, sizeof(buf)); - if (r < 0) { - warn("%s: write failed", filename.c_str()); - return EXIT_FAILURE; - } - - fd.Close(); - warnx("created %s", filename.c_str()); - return EXIT_SUCCESS; -} - // 現在の VM が指定のケーパビリティを持っているか? bool MainApp::Has(VMCap cap) const @@ -1133,7 +1264,7 @@ MainApp::UnregistObject(Object *obj) // 指定された id を持つオブジェクトを返す。なければ NULL を返す。 Object * -MainApp::FindObject(int id) const +MainApp::FindObject(uint id) const { // NONE はここで検索しない (SCSI デバイスなど、そっちで検索する) if (id == OBJ_NONE) { @@ -1149,7 +1280,7 @@ MainApp::FindObject(int id) const // 指定された id を持つオブジェクトを探す。なければ assert する。 Object * -MainApp::GetObject(int id) const +MainApp::GetObject(uint id) const { Object *obj = FindObject(id); if (__predict_false(obj == NULL)) {