--- nono/lib/mainapp.h 2026/04/29 17:04:28 1.1 +++ nono/lib/mainapp.h 2026/04/29 17:05:39 1.1.1.17 @@ -1,93 +1,283 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// CLI/GUI 共通のメイン部分 // #pragma once -#include "configfile.h" -#include "debugger.h" -#include "logger.h" -#include "scheduler.h" -#include "vm.h" - -extern bool console_log; -extern bool fast_mode; -extern char logopt[256]; -extern const char *human68k_file; -extern char human68k_arg[256]; - -extern std::string vmdir; - -extern bool parse_logopt(const char *arg, u_int vmtype); - -// 起動時の処理 は CLI と GUI でよく似ているので共通化する。 -// ただし地味に異なるところがあるのでテンプレートでコンパイル時処理。 -// log_to_stdout はログをコンソールに(も)出力するなら true。 -template bool -main_init(bool log_to_stdout) +#include "object.h" + +class Config; +class Logger; +class MonitorManager; +class VM; + +// VM 種別 +enum class VMType { + NONE = 0, + X68030, + LUNA1, + LUNA88K, + NEWS, + VIRT68K, +}; + +// VM ケーパビリティ (ビットマスク表現) +enum class VMCap : uint32 { + NONE = 0, + X68030 = (1U << (int)VMType::X68030), + LUNA1 = (1U << (int)VMType::LUNA1), + LUNA88K = (1U << (int)VMType::LUNA88K), + NEWS = (1U << (int)VMType::NEWS), + VIRT68K = (1U << (int)VMType::VIRT68K), + + LUNA = VMCap::LUNA1 | VMCap::LUNA88K, + M68K = VMCap::X68030 | VMCap::LUNA1 | VMCap::NEWS | VMCap::VIRT68K, + M88K = VMCap::LUNA88K, + ALL = 0xffffffff, +}; +static inline VMCap operator|(VMCap a, VMCap b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +class MainApp { - // ログ機構は引数処理後なるはや - logger_init(); - gLogger->UseStdout(log_to_stdout); - - // 引数で指定されたディレクトリの設定ファイルを読む - gConfig = new Config(vmdir); - if (!gConfig->Load()) { - return false; - } + public: + // Init() の戻り値 + static const int PASS = -1; // 実行を継続 - // VM 種別を決定 - u_int vm_type; - if (is_cli && human68k_file) { - vm_type = VM::TYPE_RXZ; - } else { - vm_type = gConfig->ReadInt("vm_type"); - } + enum class CPUAffinity { + None, // 指定なし + Low, // 低電力コアを列挙 + High, // 高性能コアを列挙 + Perf, // 高性能コアを列挙 (パフォーマンス測定用) + }; - // VM 作成 - if (vm_type == VM::TYPE_X68030) { - gVM = new VM_X68030(); - - } else if (vm_type == VM::TYPE_LUNA) { - gVM = new VM_LUNA(); - - } else if (vm_type == VM::TYPE_RXZ && is_cli) { - gVM = new VM_RXZ(human68k_file, human68k_arg); - - } else { - warnx("%s: invalid vm_type %d", - gConfig->GetFilename().c_str(), vm_type); - return false; - } + public: + MainApp(); + ~MainApp(); - // 動的なコンストラクション - if (!gVM->Create()) { - return false; - } + void Dispose(); - // ログレベルを設定。コンストラクト後すぐに行う。 - // -L help もここで処理。 - if (!parse_logopt(logopt, vm_type)) { - return false; - } + // 初期化 (ステージ1) + int Init1(bool is_cli_, int ac, char *av[]); + + // 初期化 (ステージ2) + bool Init2(); + + // VM 種別を返す。 + // (Config が持っているのは文字列) + VMType GetVMType() const { return vmtype; } + + // VM 種別を文字列で返す。"luna" とか。 + const std::string& GetVMTypeStr() const { return vmstr; } + + // たいていは、この機種か?で調べたいことが多いので。 + bool IsX68030() const { return (GetVMType() == VMType::X68030); } + bool IsLUNA1() const { return (GetVMType() == VMType::LUNA1); } + bool IsLUNA88K() const { return (GetVMType() == VMType::LUNA88K); } + bool IsNEWS() const { return (GetVMType() == VMType::NEWS); } + bool IsVIRT68K() const { return (GetVMType() == VMType::VIRT68K); } + + // 現在の VM が指定のケーパビリティを持っているか? + bool Has(VMCap cap) const; + + // VM 機種名を返す。こっちが "LUNA-I" とかで表示用。 + const char *GetVMName() const; + + // VM ディレクトリを返す + const std::string& GetVMDir() const { return vmdir; } - // VM 初期化 - // (デバッガは VM オブジェクトリストに入っていない) - if (!gVM->Init()) { - return false; + // ファイル名から適切なフルパスを検索。 + std::string SearchFile(const std::string& name) const; + + // 指定の path を正規化(展開)して返す。 + // path が絶対パスならそのまま返す。 + // path が '~' から始まっていればホームディレクトリからの相対パス、 + // それ以外なら VM ディレクトリからの相対パスとみなして展開する。 + std::string NormalizePath(const std::string& path) const; + + // オブジェクト登録 + void RegistObject(Object *obj); + + // オブジェクト削除 + void UnregistObject(Object *obj); + + // オブジェクトのリストを返す + const std::vector& GetObjects() const { return objects; } + + // 指定のオブジェクトを返す。こっちは、なければ NULL を返す。 + Object *FindObject(uint id) const; + + // 指定のオブジェクトを返す。こっちは、なければ assert する。 + Object *GetObject(uint id) const; + + // 指定のオブジェクトを型 T* にキャストして返す。 + // オブジェクトがないかキャストできなければ NULL を返す。 + template + T *FindObject(uint id) const { + return dynamic_cast(FindObject(id)); } - debugger_init(); - // 起動時設定の適用 - if (!gVM->Apply()) { - return false; + // 指定のオブジェクトを型 T* にキャストして返す。 + // オブジェクトがないかキャストできなければ assert する。 + template + T *GetObject(uint id) const { + auto dev = FindObject(id); + assert(dev); + return dev; } - // ここで引数を VM に適用? - // XXX これは設定ファイルのオーバーライド方向にするべき - gScheduler->SetFullSpeed(fast_mode); + // ログレベルを設定する。 + static bool SetLogopt(const std::vector&, std::string *errmsg); - return true; -} + // ログ名の一覧を表示する + static std::vector GetLogNames(); + + // Logger を返す + Logger *GetLogger() const { return logger.get(); } + + public: + // CLI/GUI 区別 + bool IsCLI() const { return is_cli; } + bool IsGUI() const { return !is_cli; } + + // -b: ブレークポイント "[,][,]" + std::vector debug_breakaddr {}; + + // --bi-exg (とりあえず) + bool debug_breakinst_exg {}; + + // --console-log: コンソールデバイスの出力ログ。 + const char *console_logfile {}; + + // -d: 起動時にデバッガで停止 + bool debug_on_start {}; + + // -H: 内蔵 Human68k 風を組み込む。-X による実行ファイル名が必要。 + bool human_mode {}; + + // -M: モニタ名 + std::string monitor_opt {}; + + // -M: 内蔵 MSX-DOS 風を組み込む。-X による実行ファイル名が必要。 + bool msxdos_mode {}; + + // -X: ホスト実行ファイル名とその引数 + const char *exec_file {}; + std::string exec_arg {}; + + // AVX2 を使うかどうか。ホスト CPU 調査と設定ファイル反映後の値。 + bool enable_avx2 {}; + + // AVX2 をホストがサポートしているかどうか。(こっちは情報表示用) + bool detect_avx2 {}; + + // NEON を使うかどうか。ホスト CPU 調査の設定ファイル反映後の値。 + bool enable_neon {}; + + // NEON をホストがサポートしているかどうか。(こっちは情報表示用) + bool detect_neon {}; + + // CPU コアのアフィニティ。 + CPUAffinity cpu_affinity {}; + + // 要素数がコア数。true のところが cpu_affinity で指定した性質のコアを示す。 + std::vector cpu_list {}; + + // ログ表示用 + std::unique_ptr hostcpu /*{}*/; + + private: + // 初期化ステージ1 の下請け。 + int Init1a(int, char *[]); + int Init1b(); + + // path を絶対パスにして返す。 + // 相対パスならカレントディレクトリからのパスとする。 + static std::string AbsPath(const char *path); + + // path を正規化して返す (下請け)。 + // path が相対パスなら basedir を起点とする。 + static std::string NormalizePath(const std::string& path, + const std::string& basedir); + + // ヘルプメッセージを表示する + void ShowHelp(bool all) const; + + // バージョンを表示する + void ShowVersion() const; + + // 引数を処理する + int ParseOpt(int ac, char *av[]); + + // CPU の機能をチェックする。 + bool CheckCPU(); + + // CPU 番号リスト文字列を処理する。 + std::string ParseCPUList(std::vector& dst, const std::string& input); + + // opt を logopt に追加する (-L オプション用) + void AddLogopt(const char *opt); + + // -L オプションを処理する + bool ParseLogopt(); + + // ログレベル1つを設定する。 + static bool SetLogopt1(const std::string&, std::string *errmsg); + + // 初回起動時用に SRAM.DAT を作成する。 + int CreateSRAM(); + + // コンパイルされている host netdriver の一覧を表示 + void ShowHostnet() const; + + // CLI/GUI 区別 + bool is_cli {}; + + // ログ + std::unique_ptr logger /*{}*/; + + // 全オブジェクトへのポインタのリスト (所有はしていない) + std::vector objects {}; + + // VM + std::unique_ptr pVM /*{}*/; + + // 設定項目 + std::unique_ptr pConfig /*{}*/; + + // VM 種別 + VMType vmtype {}; + std::string vmstr {}; + + // モニタマネージャ + std::unique_ptr pMonitorManager /*{}*/; + + // -c: VM ディレクトリ or 設定ファイル + std::string vmdir {}; + std::string vmfile {}; + + // -C: ログをコンソールに出力 + bool log_to_console {}; + + // -L: ログ指定文字列 + std::string logopt {}; + + // --show-config: 設定内容を表示 (1なら通常、2ならall) + int show_config {}; + + // -V: パラメータ指定 + std::vector> config_options {}; + + // --create-sram オプション + bool create_sram {}; +}; +// グローバルインスタンス +extern MainApp gMainApp;