--- nono/lib/object.h 2026/04/29 17:04:31 1.1.1.2 +++ nono/lib/object.h 2026/04/29 17:05:47 1.1.1.15 @@ -1,92 +1,188 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// 基本オブジェクト // #pragma once -#include "header.h" -#include "textscreen.h" +#include "mystring.h" +#include "object_id.h" +#include #include -// +class Logger; +class Monitor; +class TextScreen; + +// オブジェクト ID +static constexpr uint OBJ_BANKRAM(uint n) { return OBJ_BANKRAM0 + n; } +static constexpr uint OBJ_ETHERNET(uint n) { return OBJ_ETHERNET0 + n; } +static constexpr uint OBJ_FDD(uint n) { return OBJ_FDD0 + n; } +static constexpr uint OBJ_GFPIC(uint n) { return OBJ_GFPIC0 + n; } +static constexpr uint OBJ_HOSTCOM(uint n) { return OBJ_HOSTCOM0 + n; } +static constexpr uint OBJ_HOSTNET(uint n) { return OBJ_HOSTNET0 + n; } +static constexpr uint OBJ_M88200(uint n) { return OBJ_M88200_0 + n; } +static constexpr uint OBJ_MPU_MEMDUMP(uint n) { return OBJ_MPU_MEMDUMP0 + n; } +static constexpr uint OBJ_NEREID_BOARD(uint n) { return OBJ_NEREID_BOARD0 + n; } +static constexpr uint OBJ_VIRTIO_BLOCK(uint n) { return OBJ_VIRTIO_BLOCK0 + n; } +static constexpr uint OBJ_XP_MEMDUMP(uint n) { return OBJ_XP_MEMDUMP0 + n; } + +// ログ表示に指定するラムダ式の便利マクロ。 +// fmt 内では __func__ が使えないので代わりに lam_func を使うこと。 +// lstr("%s value=%d", lam_func, value) のようになる。 +// 他のキャプチャ指定子が必要になったらまた考える。 +#define lstr(fmt...) \ + [&, lam_func = __func__] { (void)lam_func; return string_format(fmt); } + +// モニタコールバックを宣言するマクロ。 +// 強制力はないけどヘッダで宣言するところで使うこと。 +// コールバック関数の型が変わった時にコンパイルエラーで検出させるため。 +#define DECLARE_MONITOR_CALLBACK(name) void name (Monitor *, TextScreen&) + // 基本オブジェクト -// -// ログ出力機能を持つ。 -// class Object { public: - Object(); + // 引数はオブジェクト ID。 + // ID と紐付けされたオブジェクト名は、ログ表示名で、ログに前置される。 + // またコンストラクタ指定の場合はエイリアスにも登録する。 + // これは表示名と指示名が同じことが多いための便宜措置。 + // 指示名に表示名を使いたくない場合は ClearAlias() してから + // AddAlias() すること。 + explicit Object(uint objid_); + virtual ~Object(); + // ID を返す + uint GetId() const { return objid; } + const char *GetIdStr() const; + + // ID を文字列で返す + static const char *GetIdStr(uint target_id); + + // オブジェクト名(ログ表示名)を取得する + const std::string& GetName() const { return objname; } + + // エイリアスリストを返す + const std::vector& GetAliases() const { return log_aliases; } + + // 指定の id を持つオブジェクトを返す。 + // 実体は gMainApp.GetObject() を呼んでいる。 + // 隣のデバイスを参照したい人が全員 mainapp.h を include しなくて済む + // ようにするための便宜上のもの。 + static Object *GetObject(uint target_id); + + // 指定の id を持つオブジェクトを型 T* にして返す版。 + template + static T *GetObject(uint target_id) { + auto dev = dynamic_cast(GetObject(target_id)); + assert(dev); + return dev; + } + + protected: + // オブジェクト名を newname に設定(更新)する。 + // 通常、オブジェクト名はコンストラクタで指定するが、コンストラクタ時点 + // ではまだ名前が決まらないような場合にだけ使う。 + // こちらはエイリアスには関与しない。 + virtual void SetName(const std::string& newname) { + objname = newname; + } + + // エイリアスをクリアする。 + // エイリアスは初期値として、コンストラクタで設定したオブジェクト名が + // 1つ入っているが、これを削除したい時に使う。 + void ClearAlias() { + log_aliases.clear(); + } + + // エイリアスを追加する。 + void AddAlias(const std::string& alias) { + log_aliases.emplace_back(alias); + } + + private: + uint objid {}; + + // オブジェクト名。 + // こちらはログの先頭に追加される。 + std::string objname {}; + + // エイリアスのリスト。 + // こちらはログ名を指定する時に使う。 + std::vector log_aliases {}; + + // オブジェクト ID からオブジェクト名(ログ名)変換テーブル + static const std::vector idname; + + // オブジェクト ID を文字列にしたもの + static const std::vector idtext; + + public: // // ログ // - // ログ識別名 - std::string logname; - // ログレベル - // 0: 未実装動作などのデバッグログではない情報 - // 1: 大雑把なデバッグログ - // 2: 詳細なデバッグログ - // 3: うるさいデバッグログ - int loglevel = 0; + // ログレベルを設定する + virtual void SetLogLevel(int loglevel_); // メッセージ出力 - // loglevel が lv 以上の時だけ表示。 - // こちらは仮想時刻、現在の PC を表示しない。Init() など VM 実行前や + // メッセージは仮想時刻も現在の PC も表示しない。Init() など VM 実行前や // 仮想マシン(特に仮想時刻、PC) に関係ないあたりはこちらを使用。 - inline void - putmsg(int lv, const char *fmt, ...) __printflike(3, 4) - { - if (__predict_false(loglevel >= lv)) { - va_list ap; - va_start(ap, fmt); - vputmsg(fmt, ap); - va_end(ap); + // レベル指定なし、フォーマット版。(レベルを評価した後で使う) + void putmsgn(const char *fmt, ...) const __printflike(2, 3); + + // レベル指定あり、フォーマット版。 +#define putmsg(lv, fmt...) do { \ + if (__predict_false(loglevel >= (lv))) { \ + putmsgn(fmt); \ + } \ +} while (0) + + // レベル指定あり、ラムダ式版。 + void putmsgf(int lv, std::function msgf) const { + if (__predict_false(loglevel >= lv)) { + putmsgn("%s", msgf().c_str()); } } - // メッセージ出力 - void putmsg(const char *fmt, ...) const __printflike(2, 3); - void vputmsg(const char *fmt, va_list ap) const __printflike(2, 0); // ログ出力 - // loglevel が lv 以上の時だけ表示。 - // 仮想時刻と現在の PC も表示する。VM 実行中は基本的にこれで表示。 - inline void - putlog(int lv, const char *fmt, ...) const __printflike(3, 4) - { - if (__predict_false(loglevel >= lv)) { - va_list ap; + // ログは仮想時刻と現在の PC も表示する。VM 実行中は基本的にこれで表示。 - va_start(ap, fmt); - vputlog(fmt, ap); - va_end(ap); + // レベル指定なし、フォーマット版。(レベルを評価した後で使う) + virtual void putlogn(const char *fmt, ...) const __printflike(2, 3); + + // レベル指定あり、フォーマット版。 +#define putlog(lv, fmt...) do { \ + if (__predict_false(loglevel >= (lv))) { \ + putlogn(fmt); \ + } \ +} while (0) + + // レベル指定あり、ラムダ式版。 + void putlogf(int lv, std::function msgf) const { + if (__predict_false(loglevel >= lv)) { + putlogn("%s", msgf().c_str()); } } - // ログ出力(ログレベル限定なし) - void putlog(const char *fmt, ...) const __printflike(2, 3); - void vputlog(const char *fmt, va_list ap) const __printflike(2, 0); - - // デバイス名(デバッグ表示用) - // XXX オブジェクトなのにデバイス名とは一体... - const char *devname = NULL; - // - // モニター - // + // オブジェクト登録時に代入される + Logger *logger {}; - // モニター更新 (派生クラス側で用意) - // 戻り値はモニタースクリーンの有無。 - // 基底クラスのこれはモニタースクリーンを提供していないので false を返す。 - // 派生クラス側のは必ず true を返すこと。 - virtual bool MonitorUpdate(); + // ログレベルの目安 + // 0: 未実装動作などのデバッグログではない情報 + // 1: 大雑把なデバッグログ + // 2: 詳細なデバッグログ + // 3: うるさいデバッグログ + int loglevel {}; - // モニター用のテキストスクリーン - TextScreen monitor; + protected: + // ログ直接出力 + void WriteLog(const char *) const; }; - -// 全オブジェクトのリスト -extern std::vector gObjects;