--- nono/vm/iodevstream.h 2026/04/29 17:04:41 1.1.1.3 +++ nono/vm/iodevstream.h 2026/04/29 17:05:42 1.1.1.7 @@ -12,22 +12,31 @@ // Read/Write とも受け渡しはホストバイトオーダの値で行い、 // デバイスへのアクセスはビッグエンディアンで行う。 // アクセス中にバスエラーが起きることは考慮していない。 +// +// addr は基本的には物理アドレスだが、Read()/Write() がアドレスをマスクする +// タイプならオフセットを指定しても等価となる。 +// MainRAM は物理アドレスだが、通常 0 から始まるのでどちらも等価にみえる。 +// ExtRAM なら物理アドレスでなければならない。 +// SubRAM はアドレスをマスクするので、アドレスでもオフセットでもよいが +// XP 視点でいえばオフセットのほうが処理しやすい、などそれぞれ事情が異なる。 +// 指定したデバイスがどっちの振る舞いなのかは把握してから使うこと。 +// どちらにしてもこのクラスでは "アドレス" と呼ぶ。 class IODeviceStream { public: // コンストラクタ - IODeviceStream(IODevice *d) { - dev = d; + explicit IODeviceStream(IODevice *dev_) { + dev = dev_; } - IODeviceStream(IODevice *d, uint32 a) { - dev = d; - addr = a; + IODeviceStream(IODevice *dev_, uint32 addr_) { + dev = dev_; + addr = addr_; } - // デストラクタ不要 + ~IODeviceStream(); // アドレスを設定する - void SetAddr(uint32 a) { - addr = a; + void SetAddr(uint32 addr_) { + addr = addr_; } // アドレスを取得する uint32 GetAddr() const { @@ -35,77 +44,94 @@ class IODeviceStream } // 1バイト読み込んでポインタを進める - uint64 Read8() { - uint64 data = dev->Read8(addr); - addr += 1; - return data; + uint64 Read1() { + return ReadN(BusAddr::Size1); } // 2バイト読み込んでポインタを進める。addr はアラインしなくてよい - uint64 Read16() { - uint64 data; - data = Read8() << 8; - data |= Read8(); - return data; + uint64 Read2() { + return ReadN(BusAddr::Size2); } // 4バイト読み込んでポインタを進める。addr はアラインしなくてよい // データはホストエンディアンで返される。 - uint64 Read32() { - uint64 data; - data = Read16(addr) << 16; - data |= Read16(addr); - return data; + uint64 Read4() { + return ReadN(BusAddr::Size4); } // 1バイト書き込んでポインタを進める - void Write8(uint32 data) + void Write1(uint32 data) { - dev->Write8(addr, data); - addr += 1; + WriteN(BusAddr::Size1, data); } // 2バイト書き込んでポインタを進める。addr はアラインしてなくてよい - void Write16(uint32 data) + void Write2(uint32 data) { - Write8(data >> 8); - Write8(data & 0xff); + WriteN(BusAddr::Size2, data); + } + + // 3バイト書き込んでポインタを進める。addr はアラインしてなくてよい + void Write3(uint32 data) + { + WriteN(BusAddr::Size3, data); } // 4バイト書き込んでポインタを進める。addr はアラインしてなくてよい - void Write32(uint32 data) + void Write4(uint32 data) + { + WriteN(BusAddr::Size4, data); + } + + // LE で2バイト書き込んでポインタを進める。addr はアラインしてなくてよい + void Write2LE(uint32 data) { - Write16(data >> 16); - Write16(data & 0xffff); + Write1(data & 0xff); + Write1(data >> 8); } + // 文字列を書き込んでポインタを進める。 + void WriteString(const char *p) + { + while (*p) { + Write1(*p++); + } + Write1('\0'); + } + + // ホストの src から len バイトを書き込んでポインタを進める。 + void WriteMem(const void *src, uint len); + // アドレスも指定する版。ポインタは同様に進める - uint64 Read8(uint32 a) { - SetAddr(a); - return Read8(); - } - uint64 Read16(uint32 a) { - SetAddr(a); - return Read16(); - } - uint64 Read32(uint32 a) { - SetAddr(a); - return Read32(); - } - void Write8(uint32 a, uint32 data) { - SetAddr(a); - Write8(data); - } - void Write16(uint32 a, uint32 data) { - SetAddr(a); - Write16(data); - } - void Write32(uint32 a, uint32 data) { - SetAddr(a); - Write32(data); + uint64 Read1(uint32 addr_) { + SetAddr(addr_); + return Read1(); + } + uint64 Read2(uint32 addr_) { + SetAddr(addr_); + return Read2(); + } + uint64 Read4(uint32 addr_) { + SetAddr(addr_); + return Read4(); + } + void Write1(uint32 addr_, uint32 data) { + SetAddr(addr_); + Write1(data); + } + void Write2(uint32 addr_, uint32 data) { + SetAddr(addr_); + Write2(data); + } + void Write4(uint32 addr_, uint32 data) { + SetAddr(addr_); + Write4(data); } private: + busdata ReadN(busaddr size); + busdata WriteN(busaddr size, uint32 data); + IODevice *dev {}; uint32 addr {}; };