|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// 基本オブジェクト
//
#pragma once
#include "mystring.h"
#include "object_id.h"
#include <functional>
#include <vector>
class Logger;
class Monitor;
class TextScreen;
// オブジェクト ID
constexpr uint OBJ_BANKRAM(uint n) { return OBJ_BANKRAM0 + n; }
constexpr uint OBJ_DMAC_CH(uint n) { return OBJ_DMAC_CH0 + n; }
constexpr uint OBJ_ETHERNET(uint n) { return OBJ_ETHERNET0 + n; }
constexpr uint OBJ_FDD(uint n) { return OBJ_FDD0 + n; }
constexpr uint OBJ_GFPIC(uint n) { return OBJ_GFPIC0 + n; }
constexpr uint OBJ_HOSTCOM(uint n) { return OBJ_HOSTCOM0 + n; }
constexpr uint OBJ_HOSTNET(uint n) { return OBJ_HOSTNET0 + n; }
constexpr uint OBJ_M88200(uint n) { return OBJ_M88200_0 + n; }
constexpr uint OBJ_MPU_MEMDUMP(uint n) { return OBJ_MPU_MEMDUMP0 + n; }
constexpr uint OBJ_NEREID_BOARD(uint n) { return OBJ_NEREID_BOARD0 + n; }
constexpr uint OBJ_VIRTIO_BLOCK(uint n) { return OBJ_VIRTIO_BLOCK0 + n; }
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_SCREEN(name) void name (Monitor *, TextScreen&)
#define DECLARE_MONITOR_BITMAP(name) void name (Monitor *, BitmapRGBX&)
// 基本オブジェクト
class Object
{
public:
// 引数はオブジェクト 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<std::string>& GetAliases() const { return log_aliases; }
// 指定の id を持つオブジェクトを返す。
// 実体は gMainApp.GetObject() を呼んでいる。
// 隣のデバイスを参照したい人が全員 mainapp.h を include しなくて済む
// ようにするための便宜上のもの。
static Object *GetObject(uint target_id);
// 指定の id を持つオブジェクトを型 T* にして返す版。
template <typename T>
static T *GetObject(uint target_id) {
auto dev = dynamic_cast<T *>(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<std::string> log_aliases {};
// オブジェクト ID からオブジェクト名(ログ名)変換テーブル
static const std::vector<const char *> idname;
// オブジェクト ID を文字列にしたもの
static const std::vector<const char *> idtext;
public:
//
// ログ
//
// ログレベルを設定する
virtual void SetLogLevel(int loglevel_);
// メッセージ出力
// メッセージは仮想時刻も現在の PC も表示しない。Init() など VM 実行前や
// 仮想マシン(特に仮想時刻、PC) に関係ないあたりはこちらを使用。
// レベル指定なし、フォーマット版。(レベルを評価した後で使う)
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<std::string()> msgf) const {
if (__predict_false(loglevel >= lv)) {
putmsgn("%s", msgf().c_str());
}
}
// ログ出力
// ログは仮想時刻と現在の PC も表示する。VM 実行中は基本的にこれで表示。
// レベル指定なし、フォーマット版。(レベルを評価した後で使う)
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<std::string()> msgf) const {
if (__predict_false(loglevel >= lv)) {
putlogn("%s", msgf().c_str());
}
}
// オブジェクト登録時に代入される
Logger *logger {};
// ログレベルの目安
// 0: 未実装動作などのデバッグログではない情報
// 1: 大雑把なデバッグログ
// 2: 詳細なデバッグログ
// 3: うるさいデバッグログ
int loglevel {};
protected:
// ログ直接出力
void WriteLog(const char *) const;
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.