--- nono/vm/device.h 2026/04/29 17:05:10 1.1.1.12 +++ nono/vm/device.h 2026/04/29 17:05:18 1.1.1.13 @@ -22,11 +22,18 @@ #define HLW(addr) (addr) #endif +// 前方参照 +class MPUDevice; +class Scheduler; +class SCSIDevice; +class SCSIDisk; +class SCSITarget; + class Device : public Object { using inherited = Object; protected: - Device(const std::string& objname_); + Device(int objid_); public: virtual ~Device() override; @@ -54,13 +61,18 @@ class Device : public Object // (GUI 版のみ) この時点で Monitor がすべて登録されている必要がある。 // // 5. Init() ... 初期化 - // この時点で Object 由来のオブジェクトはすべて出揃っており、ログレベル - // も確定しているのでこれ以降 putmsg() は使える。 + // この時点で Object 由来のオブジェクトはすべて出揃っているため、他の + // Object はすべてアクセス可能。また、ログレベルも確定しているのでこれ + // 以降 putmsg() は使える。 + // 基底クラスの Device::Init() がログ出力に必要なメンバ変数を初期化して + // いるため、派生クラスで Init() を用意した場合は必ず inherited::Init() + // を呼ぶこと。 // gConfig の設定項目のうち内容によってエラー終了する可能性があるものは // ここで処理する。 - // ここでは Object 同士を相互にアクセス可能。ただしその際の依存関係に - // ついては、vm.cpp (や xiospace.cpp) 内のコンストラクタの順序で調整 - // すること (循環参照不可)。 + // Object 同士は完全に相互アクセス可能だが、Init() 自身の依存関係 + // (A::Init() で設定した値を B::Init() が参照する必要があるケース) に + // ついては vm.cpp (などコンテナデバイス) 内のコンストラクタの順序で + // 手動調整すること (循環参照不可)。 // ホストデバイスの個別ドライバはここで起動する。本来 Create() で行いたい // ところだが、ネットワークドライバの選択などは複雑なので putmsg() を // 使いたい。そうするとここまで遅延せざるを得ない。そのため 3. を過ぎて @@ -105,37 +117,70 @@ class Device : public Object // ログ出力 void putlogn(const char *fmt, ...) const override __printflike(2, 3); + + protected: + // ログに時刻と PPC を出すために必要 + MPUDevice *mpu {}; + Scheduler *scheduler {}; }; class IODevice : public Device { using inherited = Device; protected: - IODevice(const std::string& objname_); + IODevice(int objid_); public: virtual ~IODevice() override; + bool Init() override; + public: // アクセス関数。 // Read*() は読み込んだ値を (uint32) で返す。 // Write*() は書き込めたら 0 を返す。 - // Peek8() はデバッガアクセスで読み込んだ値を (uint32) で返す。 // いずれもバスエラーなら (uint64)-1 を返す。 - // (signed) int64 を使ってないのはノーマルパスで signed/unsigned の - // キャスト事故を防ぐため。 virtual uint64 Read8(uint32 addr); virtual uint64 Read16(uint32 addr); virtual uint64 Read32(uint32 addr); virtual uint64 Write8(uint32 addr, uint32 data); virtual uint64 Write16(uint32 addr, uint32 data); virtual uint64 Write32(uint32 addr, uint32 data); + + // Peek8() はデバッガアクセスで読み込んだ値を (uint32) で返す。 + // バイトアクセスした時に読める値ではなく、現在このアドレスに見えている + // であろう値。バスエラーなら (uint64)-1 を返す。 virtual uint64 Peek8(uint32 addr); - uint32 devaddr {}; // このデバイスの先頭アドレス + // Poke8() はデバッガからこのアドレス(メモリ)へ書き込む。 + // メモリでない領域 (レジスタなど) は書き込み不可。 + // data が (int32 で) 非負なら data (の下位8ビット)を書き込む。 + // 書き込めれば 0、書き込めなければ (uint64)-1 を返す。 + // data が (int32 で) 負なら addr への書き込み可否の問い合わせで、 + // 書き込み可能なら 0、書き込み不可能なら (uint64)-1 を返す。 + virtual uint64 Poke8(uint32 addr, uint32 data); + + protected: + // BusIO インタフェース。 + // BusIO を経由するデバイスはほとんどが Poke 不可なので、 + // ベースクラスに用意しておく。 + virtual uint64 Poke(uint32 addr, uint32 data); +}; + +// コンテナデバイス (複数の IODevice を格納するデバイス)。 +class IOContainerDevice : public IODevice +{ + using inherited = IODevice; + protected: + IOContainerDevice(int objid_); + public: + virtual ~IOContainerDevice() override; + + // このアドレスを担当する IODevice を再帰的に探して返す。 + IODevice *FindDevice(uint32 addr) const; - // (必要なら)このデバイスの占めるバイト数。 - // 今のところ XIOSpace、MuxDevice では必要。それ以外では不要。 - uint32 devlen {}; + protected: + // このアドレスを担当する次段の IODevice を返す。 + virtual IODevice *GetDevice(uint32 addr) const = 0; }; class BusErrDevice : public IODevice @@ -174,16 +219,9 @@ class NopIODevice : public IODevice uint64 Peek8(uint32 addr) override; }; -// 前方参照 -class DMACDevice; -class Human68k; -class InterruptDevice; -class LunafbDevice; -class MK48T02Device; -class MPUDevice; -class SCSIDevice; -class SCSIDisk; -class SCSITarget; - -extern BusErrDevice *gBusErr; -extern NopIODevice *gNopIO; +static inline BusErrDevice *GetBusErrDevice() { + return Object::GetObject(OBJ_BUSERR); +} +static inline NopIODevice *GetNopIODevice() { + return Object::GetObject(OBJ_NOPIO); +}