--- nono/vm/mainbus.h 2026/04/29 17:05:17 1.1 +++ nono/vm/mainbus.h 2026/04/29 17:05:33 1.1.1.5 @@ -5,44 +5,188 @@ // // -// メインバス +// メインバス (共通部分) // #pragma once #include "device.h" +#include "bus.h" +#include "textscreen.h" #include +#include -class MainbusDevice : public IOContainerDevice +// メインバスの素質を持つクラス +class MainbusBaseDevice : public IODevice { - using inherited = IOContainerDevice; + using inherited = IODevice; public: - MainbusDevice(); - virtual ~MainbusDevice() override; + explicit MainbusBaseDevice(uint objid_); + ~MainbusBaseDevice() override; - // addr はそれぞれアラインされていること。 - 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; + // メインバスの初期化 + virtual bool InitMainbus() = 0; - uint64 Peek32(uint32 addr); + // MPU からのリセット (ここ?) + virtual void ResetByMPU(); - // デバイスをセットする - static void SetDevice(int idx, IODevice *dev); + // ブートページを ROM に切り替える + void SwitchBootPageToROM() { SwitchBootPage(true); } + // ブートページを RAM に切り替える + void SwitchBootPageToRAM() { SwitchBootPage(false); } - // デバイステーブルをコピーする - static void CopyDevtable(int dst, int src, int len); + // モニタ表示用にデバイス名を整形。 + static std::pair FormatDevName(const Device *dev); - static std::array devtable; + protected: + // ブートページを切り替える (内部用) + virtual void SwitchBootPage(bool isrom) = 0; +}; + +// 定数クラス。本当はインタフェースっぽくしたい +class AccStat +{ + public: + // アクセス状況を記録・表示する際に切り捨てる下位ビット数 + static const uint SHIFT = 21; + + // メイン空間とバンクメモリ(1枚分)の要素数 + static const uint MAINLEN = (1 << (32 - SHIFT)); + static const uint BANKLEN = (1 << (24 - SHIFT)); + + // アクセス状況 + static const uint8 WRITE = 0x01; + static const uint8 READ = 0x02; +}; + +// メインバス (システムに1つ) +class MainbusDevice : public MainbusBaseDevice +{ + using inherited = MainbusBaseDevice; + friend class WXAccStatPanel; + + public: + // ダイナミックバスサイジング処理用のマクロっぽい関数。 + // 使い方は HVReadN()、HVWriteN() を参照。 + + // 読み込み後の処理。 + // addr は読み込みに使ったアドレス、bd は読み込んだデータ。 + // 次の読み込み用にアドレスとサイズを更新して addr に書き戻す。 + static inline uint32 + DYNAMIC_BUS_SIZING_R(busaddr& addr, busdata bd) + { + uint32 reqsize = addr.GetSize(); + uint32 portsize = bd.GetSize(); + uint32 offset = addr.Addr() & (portsize - 1); + uint32 datasize = portsize - offset; + uint32 tmp = bd.Data(); + uint32 mask = 0xffffffffU >> ((4 - datasize) * 8); + tmp &= mask; + if (datasize == reqsize) { + addr += reqsize; + addr.ChangeSize(0); + } else if (datasize > reqsize) { + tmp >>= (datasize - reqsize) * 8; + addr += reqsize; + addr.ChangeSize(0); + } else { + tmp <<= (reqsize - datasize) * 8; + addr += datasize; + addr.ChangeSize(reqsize - datasize); + } + + // 今回読み出した値を所定の位置に左シフトしたものを返す。 + return tmp; + } + + // 書き込み後の処理部分。 + // addr、data は書き込みに使ったアドレスとデータ。r が書き込みの応答。 + // 次の書き込み用に、addr はアドレスとサイズを更新したもの、 + // data も使い終わった上位バイトをクリアしたものを書き戻す。 + static inline void + DYNAMIC_BUS_SIZING_W(busaddr& addr, uint32& data, busdata r) + { + uint32 reqsize = addr.GetSize(); + uint32 portsize = r.GetSize(); + uint32 offset = addr.Addr() & (portsize - 1); + uint32 datasize = std::min(portsize - offset, reqsize); + + addr += datasize; + reqsize -= datasize; + addr.ChangeSize(reqsize); + data &= (1U << (reqsize * 8)) - 1; + } + + public: + explicit MainbusDevice(uint objid_); + ~MainbusDevice() override; + + bool Init() override; + void ResetHard(bool poweron) override; - static int direct_ram_size; + // ハイパーバイザ的アクセスというか、 + // 今となってはミスアライン可能なアクセスというだけかも知れない。 + busdata HVRead1(uint32 addr); + busdata HVRead2(uint32 addr); + busdata HVRead4(uint32 addr); + busdata HVWrite1(uint32 addr, uint32 data); + busdata HVWrite2(uint32 addr, uint32 data); + busdata HVWrite4(uint32 addr, uint32 data); + // サイズを addr で指定する版 + busdata HVReadN(busaddr addr); + busdata HVWriteN(busaddr addr, uint32 data); + + uint64 Peek4(uint32 addr); + + protected: + DECLARE_MONITOR_CALLBACK(MonitorUpdateAccStat); + + // アクセス状況は 32bit 空間全域を 2048 * 2MB ずつ。 + // (NEWS は読み出し時にマージする) + std::array accstat_read {}; + std::array accstat_write {}; + // R, W をマージした表示用(要素数は機種による) + std::vector accstat_rw {}; + // デバイスの存在有無。MSB 側から 1bit = 16MB のビットマップ。 + std::array accstat_avail {}; + // アクセス状況のアドレス表示オフセット。NEWS だけ 0xc0 + uint accstat_baseaddr {}; + // アクセス状況が何ビット空間分か。NEWS だけ 30 + uint accstat_bitlen {}; + + // X68030 バンクメモリの表示用アクセス状況。 + // (GUI からのアクセスの便宜のため共通クラスのこっちに置く) + alignas(8) uint8 accbank[AccStat::BANKLEN * 2] {}; + + Monitor *accstat_monitor {}; +}; + +// 上位8ビットがテーブルで表せる構造のメインバス (共通部分) +class Mainbus24Device : public MainbusDevice +{ + using inherited = MainbusDevice; + public: + Mainbus24Device(); + ~Mainbus24Device() override; + + busdata Read(busaddr addr) override; + busdata Write(busaddr addr, uint32 data) override; + busdata ReadBurst16(busaddr addr, uint32 *dst) override; + busdata WriteBurst16(busaddr addr, const uint32 *src) override; + busdata Peek1(uint32 addr) override; + bool Poke1(uint32 addr, uint32 data) override; protected: - IODevice *GetDevice(uint32 addr) const override; + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + void InitAccStat(); + + std::array devtable {}; + + Monitor *monitor {}; + + private: + inline IODevice *Decoder(uint32 addr) const; }; static inline MainbusDevice *GetMainbusDevice() {