--- nono/vm/busio.h 2026/04/29 17:05:25 1.1.1.8 +++ nono/vm/busio.h 2026/04/29 17:05:42 1.1.1.10 @@ -7,36 +7,101 @@ // バスとデバイスとのインタフェース。 // バスに対し、デバイスがどのように接続されているかを記述する。 +// Poke1() はここで定義しなければ基底クラスの Device::Poke1() が呼ばれて +// 全域編集不可になる。BusIO を経由する必要があるデバイスはたいていは全域が +// 編集不可なので、通常この基底の動作でよく、Poke1() を再定義する必要はない。 +// MK48T02Device のみ BusIO 経由で編集可能な領域を持っているため、これを +// 受け取る BusIO_B と BusIO_BFFF だけ Poke1() を持っている。 +// 従って BusIO_B、BusIO_BFFF の親になるデバイスは全員 PokePort() も実装する +// 必要がある。うーん。 + #pragma once #if !defined(SELFTEST) #include "device.h" #endif +// テンプレート外のヘルパー関数。 +class BusIO +{ + static inline uint32 M4(uint32 a, uint32 b, uint32 c, uint32 d) { + return ((a << 24) | (b << 16) | (c << 8) | d); + } + + public: + // アドレス(とサイズ情報からなる) addr と書き込みデータ data から + // m68030 のバスに出るはずのデータを構成する。68030UM.pdf p7-11。 + // m88200 ではこのうち7つ(reqsize==2 なら offset==0 か 2 のみ、等) + // しか使わないが、そのケースに限れば m68030 と同じ動作になる。 + static inline uint32 + DataMultiplexer_Write_L(const busaddr addr, uint32 data) + { + uint32 reqsize = addr.GetSize(); + uint32 offset = addr.Addr() & 3U; + + uint32 op0 = (data >> 24) & 0xff; + uint32 op1 = (data >> 16) & 0xff; + uint32 op2 = (data >> 8) & 0xff; + uint32 op3 = data & 0xff; + if (reqsize == 4) { + switch (offset) { + case 0: data = M4(op0, op1, op2, op3); break; + case 1: data = M4(op0, op0, op1, op2); break; + case 2: data = M4(op0, op1, op0, op1); break; + case 3: data = M4(op0, op0, op1, op0); break; + default: + __unreachable(); + } + } else if (reqsize == 3) { + switch (offset) { + case 0: data = M4(op1, op2, op3, op0); break; + case 1: data = M4(op1, op1, op2, op3); break; + case 2: data = M4(op1, op2, op1, op2); break; + case 3: data = M4(op1, op1, op2, op1); break; + default: + __unreachable(); + } + } else if (reqsize == 2) { + if ((offset & 1U) == 0) { + data = M4(op2, op3, op2, op3); + } else { + data = M4(op2, op2, op3, op2); + } + } else { + data = M4(op3, op3, op3, op3); + } + return data; + } +}; + // バイトデバイスをバイト、ワード、ロングワードポートにミラー配置する共通部 template class BusIO_B_Base : public T { - protected: - inline uint32 Decoder(uint32 addr) { + private: + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { return (addr >> rshift) & (T::NPORT - 1); } public: - busdata Read8(uint32 addr) override { - return T::Read(Decoder(addr)); + busdata Read(busaddr addr) override { + return T::ReadPort(Decoder(addr)); } - busdata Write8(uint32 addr, uint32 data) override { - return T::Write(Decoder(addr), data); + busdata Write(busaddr addr, uint32 data) override { + data >>= (addr.GetSize() - 1) * 8; + return T::WritePort(Decoder(addr), data); } - busdata Peek8(uint32 addr) override { - return T::Peek(Decoder(addr)); + busdata Peek1(uint32 addr) override { + return T::PeekPort(Decoder(addr)); } - bool Poke8(uint32 addr, uint32 data) override { - return T::Poke(Decoder(addr), data); + bool Poke1(uint32 addr, uint32 data) override { + return T::PokePort(Decoder(addr), data); } }; @@ -57,132 +122,178 @@ template class BusIO_W : public T { private: - inline uint32 Decoder(uint32 addr) { + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { return (addr >> 1) & (T::NPORT - 1); } + static inline uint32 M2(uint32 a, uint32 b) { + return ((a) << 8) | b; + } public: - // ワードポートからのバイト読み込みはワードで読んだ後必要な方を取る。 - busdata Read8(uint32 addr) override { - if ((addr & 1) == 0) { - busdata data = T::Read(Decoder(addr)); - data >>= 8; - return data; - } else { - busdata data = T::Read(Decoder(addr)); - data &= 0xff; - return data; - } - } - busdata Read16(uint32 addr) override { - return T::Read(Decoder(addr)); + busdata Read(busaddr addr) override { + return T::ReadPort(Decoder(addr)); } - // ワードポートにバイト書き込みするとデータバスは OP3 OP3 OP3 OP3。 - busdata Write8(uint32 addr, uint32 data) override { - data |= data << 8; - return T::Write(Decoder(addr), data); - } - busdata Write16(uint32 addr, uint32 data) override { - return T::Write(Decoder(addr), data); + busdata Write(busaddr addr, uint32 data) override { + uint32 reqsize = addr.GetSize(); + uint32 offset = addr.Addr() & 1; + + uint32 op0 = (data >> 24) & 0xff; + uint32 op1 = (data >> 16) & 0xff; + uint32 op2 = (data >> 8) & 0xff; + uint32 op3 = data & 0xff; + if (reqsize == 1) { + data = M2(op3, op3); + } else if (reqsize == 2) { + if (offset == 0) { + data = M2(op2, op3); + } else { + data = M2(op2, op2); + } + } else if (reqsize == 3) { + if (offset == 0) { + data = M2(op1, op2); + } else { + data = M2(op1, op1); + } + } else { + if (offset == 0) { + data = M2(op0, op1); + } else { + data = M2(op0, op0); + } + } + return T::WritePort(Decoder(addr), data); } - busdata Peek8(uint32 addr) override { + busdata Peek1(uint32 addr) override { if ((addr & 1) == 0) { - return T::Peek(Decoder(addr)) >> 8; + return T::PeekPort(Decoder(addr)) >> 8; } else { - return T::Peek(Decoder(addr)) & 0xff; + return T::PeekPort(Decoder(addr)) & 0xff; } } }; -/* XXX: stub -class BusIO_L : public T -*/ - -// バイトデバイスを偶数アドレスに配置し、奇数アドレスはバスエラー。 +// ロングワードデバイスをロングワードのまま m68k バスに配置する。 template -class BusIO_BE : public T +class BusIO_L : public T { private: - inline uint32 Decoder(uint32 addr) { - return (addr >> 1) & (T::NPORT - 1); + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { + return (addr >> 2) & (T::NPORT - 1); } public: - busdata Read8(uint32 addr) override { - if ((addr & 1) == 0) { - return T::Read(Decoder(addr)); - } else { - return busdata::BusErr; - } + BusIO_L() + : T() + { } - busdata Read16(uint32 addr) override { - busdata data = T::Read(Decoder(addr)); - data <<= 8; - data |= 0xff; - return data; + explicit BusIO_L(uint arg1) + : T(arg1) + { + } + BusIO_L(uint arg1, uint arg2) + : T(arg1, arg2) + { } - busdata Write8(uint32 addr, uint32 data) override { - if ((addr & 1) == 0) { - return T::Write(Decoder(addr), data); - } else { - return busdata::BusErr; - } + busdata Read(busaddr addr) override { + return T::ReadPort(Decoder(addr)); } - busdata Write16(uint32 addr, uint32 data) override { - return T::Write(Decoder(addr), data >> 8); + + busdata Write(busaddr addr, uint32 data) override { + data = BusIO::DataMultiplexer_Write_L(addr, data); + return T::WritePort(Decoder(addr), data); } - busdata Peek8(uint32 addr) override { - if ((addr & 1) == 0) { - return T::Peek(Decoder(addr)); - } else { - return busdata::BusErr; + busdata Peek1(uint32 addr) override { + busdata data = T::PeekPort(Decoder(addr)); + if (data.IsBusErr()) { + return data; } + data >>= (3 - (addr & 3U)) * 8; + data &= 0xff; + return data; } }; +// バイトデバイスを偶数アドレスに配置し、奇数アドレスはバスエラー。 +//class BusIO_BE + // バイトデバイスを奇数アドレスに配置し、偶数アドレスはバスエラー。 template class BusIO_EB : public T { private: - inline uint32 Decoder(uint32 addr) { + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { return (addr >> 1) & (T::NPORT - 1); } public: - busdata Read8(uint32 addr) override { - if ((addr & 1) == 0) { - return busdata::BusErr; - } else { - return T::Read(Decoder(addr)); - } - } - busdata Read16(uint32 addr) override { - busdata data = T::Read(Decoder(addr)); - data |= 0xff00; - return data; - } - - busdata Write8(uint32 addr, uint32 data) override { - if ((addr & 1) == 0) { - return busdata::BusErr; + busdata Read(busaddr addr) override { + if (addr.GetSize() == 1 && (addr.Addr() & 1) == 0) { + return BusData::BusErr; + } + busdata bd = T::ReadPort(Decoder(addr)); + bd |= 0xff00; + bd.ChangeSize(2); + return bd; + } + + busdata Write(busaddr addr, uint32 data) override { + busdata r; + uint32 reqsize = addr.GetSize(); + uint32 offset = addr.Addr() & 1; + + uint32 op0 = (data >> 24) & 0xff; + uint32 op1 = (data >> 16) & 0xff; + uint32 op2 = (data >> 8) & 0xff; + uint32 op3 = data & 0xff; + if (reqsize == 1) { + if (offset == 0) { + return BusData::BusErr; + } else { + data = op3; + } + } else if (reqsize == 2) { + if (offset == 0) { + data = op3; + } else { + data = op2; + } + } else if (reqsize == 3) { + if (offset == 0) { + data = op2; + } else { + data = op1; + } } else { - return T::Write(Decoder(addr), data); + if (offset == 0) { + data = op1; + } else { + data = op0; + } } - } - busdata Write16(uint32 addr, uint32 data) override { - return T::Write(Decoder(addr), data & 0xff); + r = T::WritePort(Decoder(addr), data); + r.ChangeSize(2); + return r; } - busdata Peek8(uint32 addr) override { + busdata Peek1(uint32 addr) override { if ((addr & 1) == 0) { - return busdata::BusErr; + return BusData::BusErr; } else { - return T::Peek(Decoder(addr)); + return T::PeekPort(Decoder(addr)); } } }; @@ -192,40 +303,71 @@ template class BusIO_FB : public T { private: - inline uint32 Decoder(uint32 addr) { + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { return (addr >> 1) & (T::NPORT - 1); } public: - busdata Read8(uint32 addr) override { - if ((addr & 1) == 0) { - return 0xff; - } else { - return T::Read(Decoder(addr)); - } - } - busdata Read16(uint32 addr) override { - busdata data = T::Read(Decoder(addr)); - data |= 0xff00; - return data; - } - - busdata Write8(uint32 addr, uint32 data) override { - if ((addr & 1) == 0) { - return 0; + busdata Read(busaddr addr) override { + busdata bd; + if (addr.GetSize() == 1 && (addr.Addr() & 1) == 0) { + bd = 0xff; + } else { + bd = T::ReadPort(Decoder(addr)); + } + bd |= 0xff00; + bd.ChangeSize(2); + return bd; + } + + busdata Write(busaddr addr, uint32 data) override { + busdata r; + uint32 reqsize = addr.GetSize(); + uint32 offset = addr.Addr() & 1; + + uint32 op0 = (data >> 24) & 0xff; + uint32 op1 = (data >> 16) & 0xff; + uint32 op2 = (data >> 8) & 0xff; + uint32 op3 = data & 0xff; + if (reqsize == 1) { + if (offset == 0) { + r.ChangeSize(2); + return r; + } else { + data = op3; + } + } else if (reqsize == 2) { + if (offset == 0) { + data = op3; + } else { + data = op2; + } + } else if (reqsize == 3) { + if (offset == 0) { + data = op2; + } else { + data = op1; + } } else { - return T::Write(Decoder(addr), data); + if (offset == 0) { + data = op1; + } else { + data = op0; + } } - } - busdata Write16(uint32 addr, uint32 data) override { - return T::Write(Decoder(addr), data & 0xff); + r = T::WritePort(Decoder(addr), data); + r.ChangeSize(2); + return r; } - busdata Peek8(uint32 addr) override { + busdata Peek1(uint32 addr) override { if ((addr & 1) == 0) { return 0xff; } else { - return T::Peek(Decoder(addr)); + return T::PeekPort(Decoder(addr)); } } }; @@ -234,65 +376,41 @@ class BusIO_FB : public T template class BusIO_BFFF : public T { - protected: - inline uint32 Decoder(uint32 addr) { + private: + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { return (addr >> 2) & (T::NPORT - 1); } public: - busdata Read8(uint32 addr) override { - if ((addr & 3) == 0) { - return T::Read(Decoder(addr)); - } else { - return 0xff; - } - } - busdata Read16(uint32 addr) override { - if ((addr & 2) == 0) { - busdata data = T::Read(Decoder(addr)); - data <<= 8; - data |= 0xff; - return data; - } else { - return 0xffff; - } - } - busdata Read32(uint32 addr) override { - busdata data = T::Read(Decoder(addr)); - data <<= 24; - data |= 0x00ffffff; - return data; - } - - busdata Write8(uint32 addr, uint32 data) override { - if ((addr & 3) == 0) { - return T::Write(Decoder(addr), data); - } else { - return 0; - } - } - busdata Write16(uint32 addr, uint32 data) override { - if ((addr & 2) == 0) { - return T::Write(Decoder(addr), data >> 8); - } else { - return 0; - } - } - busdata Write32(uint32 addr, uint32 data) override { - return T::Write(Decoder(addr), data >> 24); + busdata Read(busaddr addr) override { + busdata bd = T::ReadPort(Decoder(addr)); + bd <<= 24; + bd |= 0x00ffffff; + bd.ChangeSize(4); + return bd; + } + + busdata Write(busaddr addr, uint32 data) override { + data >>= (addr.GetSize() - 1) * 8; + busdata r = T::WritePort(Decoder(addr), data); + r.ChangeSize(4); + return r; } - busdata Peek8(uint32 addr) override { + busdata Peek1(uint32 addr) override { if ((addr & 3) == 0) { - return T::Peek(Decoder(addr)); + return T::PeekPort(Decoder(addr)); } else { return 0xff; } } - bool Poke8(uint32 addr, uint32 data) override { + bool Poke1(uint32 addr, uint32 data) override { if ((addr & 3) == 0) { - return T::Poke(Decoder(addr), data); + return T::PokePort(Decoder(addr), data); } else { // 非接続なので、書き換えようとしてもエラーも起きず何も起きない。 return true; @@ -305,57 +423,41 @@ template class BusIO_WF : public T { private: - inline uint32 Decoder(uint32 addr) { + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { return (addr >> 2) & (T::NPORT - 1); } public: - busdata Read8(uint32 addr) override { - busdata data; - switch (addr & 3) { - case 0: - data = T::Read(Decoder(addr)); - data >>= 8; - return data; - case 1: - data = T::Read(Decoder(addr)); - data &= 0xff; - return data; - case 2: - case 3: - return 0xff; - } - __unreachable(); - } - busdata Read16(uint32 addr) override { - if ((addr & 2) == 0) { - return T::Read(Decoder(addr)); - } else { - return 0xffff; - } + busdata Read(busaddr addr) override { + busdata bd = T::ReadPort(Decoder(addr)); + bd <<= 16; + bd |= 0xffff; + bd.ChangeSize(4); + return bd; } - // バイト書き込みならデータバスは OP3 OP3 OP3 OP3。 - busdata Write8(uint32 addr, uint32 data) override { - if ((addr & 2) == 0) { - data |= data << 8; - return T::Write(Decoder(addr), data); - } else { - return 0; - } - } - busdata Write16(uint32 addr, uint32 data) override { - if ((addr & 2) == 0) { - return T::Write(Decoder(addr), data); + busdata Write(busaddr addr, uint32 data) override { + if (addr.GetSize() == 4) { + data >>= 16; + } else if (addr.GetSize() == 2) { + // ワード書き込みならデータバスは MSB LSB MSB LSB。(88200 p5-27) } else { - return 0; + // バイト書き込みなら全バイトがコピー。 + data |= data << 8; } + busdata r = T::WritePort(Decoder(addr), data); + r.ChangeSize(4); + return r; } - busdata Peek8(uint32 addr) override { + + busdata Peek1(uint32 addr) override { switch (addr & 3) { case 0: - return T::Peek(Decoder(addr)) >> 8; + return T::PeekPort(Decoder(addr)) >> 8; case 1: - return T::Peek(Decoder(addr)) & 0xff; + return T::PeekPort(Decoder(addr)) & 0xff; case 2: case 3: return 0xff; @@ -373,68 +475,81 @@ template class BusIO_X68kSPC : public T { private: - inline uint32 Decoder(uint32 addr) { + inline uint32 Decoder(busaddr addr) const { + return Decoder(addr.Addr()); + } + inline uint32 Decoder(uint32 addr) const { // SASI 跡地と SCSI を合わせて 0x40 バイトでミラーしている return (addr >> 1) & (0x20 - 1); } public: - busdata Read8(uint32 addr) override { - if ((addr & 1) == 0) { - return busdata::BusErr; + busdata Read(busaddr addr) override { + if (addr.GetSize() == 1 && (addr.Addr() & 1) == 0) { + return BusData::BusErr; + } + uint32 offset = Decoder(addr); + busdata bd; + if (offset < 0x10) { + // 前半16ポートは SASI 跡地。 + bd = 0xff; } else { - addr = Decoder(addr); - if (addr < 0x10) { - // 前半16ポートは SASI 跡地。 - return 0xff; + // 後半16ポートは SCSI。 + bd = T::ReadPort(offset - 0x10); + } + bd |= 0xff00; + bd.ChangeSize(2); + return bd; + } + + busdata Write(busaddr addr, uint32 data) override { + busdata r; + uint32 reqsize = addr.GetSize(); + uint32 offset = addr.Addr() & 1; + + uint32 op0 = (data >> 24) & 0xff; + uint32 op1 = (data >> 16) & 0xff; + uint32 op2 = (data >> 8) & 0xff; + uint32 op3 = data & 0xff; + if (reqsize == 1) { + if (offset == 0) { + return BusData::BusErr; } else { - // 後半16ポートは SCSI。 - return T::Read(addr - 0x10); + data = op3; + } + } else if (reqsize == 2) { + if (offset == 0) { + data = op3; + } else { + data = op2; + } + } else if (reqsize == 3) { + if (offset == 0) { + data = op2; + } else { + data = op1; } - } - } - busdata Read16(uint32 addr) override { - addr = Decoder(addr); - if (addr < 0x10) { - // 前半16ポートは SASI 跡地 - return 0xffff; - } else { - busdata data = T::Read(addr - 0x10); - data |= 0xff00; - return data; - } - } - - busdata Write8(uint32 addr, uint32 data) override { - if ((addr & 1) == 0) { - return busdata::BusErr; } else { - addr = Decoder(addr); - if (addr < 0x10) { - // 前半16ポートは SASI 跡地。 - // XXX 書き込みはどうなる? - return 0; + if (offset == 0) { + data = op1; } else { - // 後半16ポートは SCSI。 - return T::Write(addr - 0x10, data); + data = op0; } } - } - busdata Write16(uint32 addr, uint32 data) override { - addr = Decoder(addr); - if (addr < 0x10) { + uint32 pa = Decoder(addr); + if (pa < 0x10) { // 前半16ポートは SASI 跡地。 // XXX 書き込みはどうなる? - return 0; } else { - // 後半16ポートは SCSI。 - return T::Write(addr - 0x10, data & 0xff); + r = T::WritePort(pa - 0x10, data); } + r.ChangeSize(2); + return r; } - busdata Peek8(uint32 addr) override { + busdata Peek1(uint32 addr) override { if ((addr & 1) == 0) { - return busdata::BusErr; + return BusData::BusErr; } else { addr = Decoder(addr); if (addr < 0x10) { @@ -442,7 +557,7 @@ class BusIO_X68kSPC : public T return 0xff; } else { // 後半16ポートは SCSI。 - return T::Peek(addr - 0x10); + return T::PeekPort(addr - 0x10); } } }