--- nono/vm/device.h 2026/04/29 17:05:10 1.1.1.12 +++ nono/vm/device.h 2026/04/29 17:05:29 1.1.1.16 @@ -11,6 +11,7 @@ #pragma once #include "object.h" +#include "bus.h" #if BYTE_ORDER == LITTLE_ENDIAN #define HB(addr) ((addr) ^ 1) @@ -22,13 +23,24 @@ #define HLW(addr) (addr) #endif +// デバイスを作成して代入するマクロ。 +// …だったが今となってはあまり意味がなくなっている。 +#define NEWDV(NAME, NEW_CTOR) do { \ + __CONCAT(p,NAME).reset(NEW_CTOR); \ + assert((bool)__CONCAT(p,NAME)); \ +} while (0) + +// 前方参照 +class MainMPUDevice; +class Scheduler; + class Device : public Object { using inherited = Object; protected: - Device(const std::string& objname_); + explicit Device(uint objid_); public: - virtual ~Device() override; + ~Device() override; public: // 初期化は以下の手順で行う。 @@ -36,13 +48,18 @@ class Device : public Object // メンバ変数の初期値代入などを行う。失敗するケースは考慮していない。 // gConfig の内部変数の追加はここ(か2.の動的コンストラクション)で // 行うこと。この時点ですでに gConfig の設定内容の参照は可能だが、 - // エラーが出るものはここではなく Init() で処理すること。 + // エラーが出るものはここではなく Create() か Init() で処理すること。 // putmsg() は使えない。 // // 2. Create() ... 動的コンストラクション // 必要なら設定ファイルによって可変なオブジェクトのコンストラクトを行う。 - // 例えば SCSI ドライブなどが該当する。ここでも gConfig の参照および - // 内部変数の登録は可能、putmsg() は使えない。 + // 例えば SCSI ドライブなどが該当する。Create() で作成したインスタンスの + // Create() もこのフェーズで呼ばれる。 + // ここでも gConfig の参照および内部変数の登録は可能、エラー終了する + // 可能性のあるものも処理できる。 + // Init() とは異なりこちらは、継承クラスの Create() が Device::Create() + // を呼ぶ必要はない + // putmsg() は使えない。 // // 3. parse_logopt() ... -L オプションの処理 // この時点でログの割り当てを受ける Object 由来のオブジェクトはすべて @@ -54,13 +71,20 @@ 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 +129,64 @@ class Device : public Object // ログ出力 void putlogn(const char *fmt, ...) const override __printflike(2, 3); + + protected: + // ログに時刻と PPC を出すために必要 + MainMPUDevice *mpu {}; + Scheduler *scheduler {}; }; class IODevice : public Device { using inherited = Device; protected: - IODevice(const std::string& objname_); + explicit IODevice(uint objid_); public: - virtual ~IODevice() override; + ~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); - virtual uint64 Peek8(uint32 addr); - - uint32 devaddr {}; // このデバイスの先頭アドレス - - // (必要なら)このデバイスの占めるバイト数。 - // 今のところ XIOSpace、MuxDevice では必要。それ以外では不要。 - uint32 devlen {}; + // メイン CPU からのデバイスの読み込み。 + // busaddr.Addr にアドレス、busaddr.Size に要求バイト数がセットされている。 + // busdata.Size にはポートサイズ (応答バイト数) を返す。 + // 戻り値 busdata.Data は下詰めし、不要な上位バイトはクリアして返すこと。 + virtual busdata Read(busaddr addr); + + // メイン CPU からのデバイスへの書き込み。 + // busaddr.Addr にアドレス、busaddr.Size に要求バイト数がセットされている。 + // data は Size バイト分が下詰めされており、上位の不要バイトはクリア済み。 + // 戻り値の busdata.Size にはポートサイズを返すこと。 + virtual busdata Write(busaddr addr, uint32 data); + + // メイン CPU からのバーストアクセス。 + // addr (16バイト境界) からの 16 バイトを転送してウェイトと OK を返す。 + // dst/src の uint32 はホストエンディアン。 + // バースト転送をサポートしてなければ BusData::BusErr を返す。 + virtual busdata ReadBurst16(busaddr addr, uint32 *dst); + virtual busdata WriteBurst16(busaddr addr, const uint32 *src); + + // XP からのデバイスの読み込み。 + // 戻り値は busdata.Data の1バイトと必要なら Wait。他は使用しない。 + virtual busdata Read1(uint32 addr); + + // XP からのデバイスへの書き込み。 + // data は1バイト。 + // 戻り値は busdata.Wait のみ。他は使用しない。 + virtual busdata Write1(uint32 addr, uint32 data); + + // Peek1() はデバッガアクセスで読み込んだ値を (uint32) で返す。 + // バイトアクセスした時に読める値ではなく、現在このアドレスに見えている + // であろう値。バスエラーなら BusData::BusErr を返す。 + virtual busdata Peek1(uint32 addr); + + // Poke1() はデバッガからこのアドレス(メモリ)へ書き込む。 + // メモリでない領域 (レジスタなど) は書き込み不可。 + // data が (int32 で) 非負なら data の下位8ビットを書き込む。 + // 書き込めれば true、書き込めなければ false を返す。 + // data が (int32 で) 負なら addr への書き込み可否の問い合わせで、 + // 書き込み可能なら true、書き込み不可能なら false を返す。 + virtual bool Poke1(uint32 addr, uint32 data); }; class BusErrDevice : public IODevice @@ -143,16 +194,12 @@ class BusErrDevice : public IODevice using inherited = IODevice; public: BusErrDevice(); - virtual ~BusErrDevice() override; + ~BusErrDevice() override; public: - uint64 Read8(uint32 addr) override; - uint64 Read16(uint32 addr) override; - uint64 Read32(uint32 addr) override; - uint64 Write8(uint32 addr, uint32 data) override; - uint64 Write16(uint32 addr, uint32 data) override; - uint64 Write32(uint32 addr, uint32 data) override; - uint64 Peek8(uint32 addr) override; + busdata Read(busaddr addr) override; + busdata Write(busaddr addr, uint32 data) override; + busdata Peek1(uint32 addr) override; }; // 何もしないデバイス。 @@ -162,28 +209,19 @@ class NopIODevice : public IODevice using inherited = IODevice; public: NopIODevice(); - virtual ~NopIODevice() override; + ~NopIODevice() override; public: - uint64 Read8(uint32 addr) override; - uint64 Read16(uint32 addr) override; - uint64 Read32(uint32 addr) override; - uint64 Write8(uint32 addr, uint32 data) override; - uint64 Write16(uint32 addr, uint32 data) override; - uint64 Write32(uint32 addr, uint32 data) override; - uint64 Peek8(uint32 addr) override; + busdata Read(busaddr addr) override; + busdata Write(busaddr addr, uint32 data) override; + busdata Read1(uint32 addr) override; + busdata Write1(uint32 addr, uint32 data) override; + busdata Peek1(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); +}