--- nono/vm/bus.h 2026/04/29 17:05:25 1.1.1.6 +++ nono/vm/bus.h 2026/04/29 17:05:29 1.1.1.7 @@ -10,15 +10,15 @@ #pragma once -#include "header.h" +#include "nono.h" // busaddr はアドレスバスにいくつかの情報を追加した構造。 // // : 6 : 5 : 4: 3:3 0 // 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+ -// |B|T| |P| |R| |S|I|D|S| Address | -// |E|S| |A| |W| |U| | |U| (32bit) | +// |B| |T|P| |Size | |R| |S|I|D|S| Address | +// |E| |S|A| | | |W| |U| | |U| (32bit) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+ // // 32ビット目と35ビット目はどちらも S/U で同じ値を入れる。m68k の FC2 に相当。 @@ -32,13 +32,57 @@ // 39ビット目は R/W (Read なら 1)。これは SSW で使う。 // 上位ワードを >>1 して下位 7 ビットを取り出すと SSW (の FC と R/W) になる。 // +// 48,49,50ビット目は要求バイトサイズ (1 - 4)。 +// +// 63ビット目 (BE) は (アドレス変換時の) バスエラーを示す。 +// // 以下はデバッガなどで使用する追加のビットで、実行系では使わない。 -// 55ビット目 (PA) はこのアドレスを物理アドレスとする場合は %1 を指定する。 +// 56ビット目 (PA) はこのアドレスを物理アドレスとする場合は %1 を指定する。 // 論理アドレスまたは区別が不要な場合は %0 にする。 // 論理アドレスと物理アドレスの両方を受け取るメモリダンプとかで使う。 -// 62ビット目 (TS: Table Search Result) は、このアドレスを求めるのに +// 57ビット目 (TS: Table Search Result) は、このアドレスを求めるのに // テーブルサーチを行った場合は %1。 -// 63ビット目 (BE) は (アドレス変換時の) バスエラーを示す。 + +// 定数 +enum class BusAddr : uint64 +{ + D = 0x0000'0002'0000'0000ULL, // データ空間 + I = 0x0000'0004'0000'0000ULL, // 命令空間 + S = 0x0000'0009'0000'0000ULL, // スーパーバイザ空間 + U = 0x0000'0000'0000'0000ULL, // ユーザ空間 + R = 0x0000'0080'0000'0000ULL, // 読み込み + W = 0x0000'0000'0000'0000ULL, // 書き込み + + Fetch = I | R, + Read = D | R, + Write = D | W, + SRead = S | Read, + SWrite = S | Write, + + Size1 = 0x0001'0000'0000'0000ULL, + Size2 = 0x0002'0000'0000'0000ULL, + Size3 = 0x0003'0000'0000'0000ULL, + Size4 = 0x0004'0000'0000'0000ULL, + SizeMask = 0x0007'0000'0000'0000ULL, + + // デバッガ用 + Physical = 0x0100'0000'0000'0000ULL, + Logical = 0x0000'0000'0000'0000ULL, + TableSearched = 0x0200'0000'0000'0000ULL, + + BusErr = 0x8000'0000'0000'0000ULL, +}; + +// BusAddr に対する OR 演算子 (まだ busaddr は出せない) +static __unused BusAddr operator|(const BusAddr& lhs, const BusAddr& rhs) { + return (BusAddr)((uint64)lhs | (uint64)rhs); +} +static __unused BusAddr operator|(const BusAddr& lhs, const uint64& rhs) { + return (BusAddr)((uint64)lhs | rhs); +} +static __unused BusAddr operator|(const uint64& lhs, const BusAddr& rhs) { + return (BusAddr)(lhs | (uint64)rhs); +} class busaddr { @@ -46,157 +90,155 @@ class busaddr uint64 value {}; public: - static const uint64 D = 0x0000'0002'0000'0000ULL; // データ空間 - static const uint64 I = 0x0000'0004'0000'0000ULL; // 命令空間 - static const uint64 S = 0x0000'0009'0000'0000ULL; // スーパーバイザ - static const uint64 U = 0x0000'0000'0000'0000ULL; // ユーザ - static const uint64 R = 0x0000'0080'0000'0000ULL; // 読み込み - static const uint64 W = 0x0000'0000'0000'0000ULL; // 書き込み - - static const uint64 Fetch = I | R; - static const uint64 Read = D | R; - static const uint64 Write = D | W; - - // 以下デバッガ用のビット - static const uint64 Physical = 0x0080'0000'0000'0000ULL; - static const uint64 Logical = 0x0000'0000'0000'0000ULL; - static const uint64 TableSearched = 0x4000'0000'0000'0000ULL; - static const uint64 BusErr = 0x8000'0000'0000'0000ULL; - // ファンクションコードから busaddr を作成。fc_ は 0-7 にすること。 - static constexpr uint64 FC(uint32 fc_) { - return ((uint64)fc_ << 33) | ((uint64)(fc_ & 4) << 30); + static constexpr BusAddr FC(uint32 fc_) noexcept { + return (BusAddr)(((uint64)fc_ << 33) | ((uint64)(fc_ & 4) << 30)); + } + // アクセスサイズ + static constexpr BusAddr Size(uint n) noexcept { + return (BusAddr)((uint64)n << 48); + } + // S/U + static constexpr BusAddr SU(bool super_) noexcept { + return super_ ? BusAddr::S : BusAddr::U; } public: - busaddr() { - } - busaddr(uint64 value_) { - Set(value_); + busaddr() noexcept { } - // 32ビットアドレスと属性を代入したいことはよくある。 - busaddr(uint32 addr_, const busaddr& busaddr_) { - Set(addr_, busaddr_); + explicit busaddr(uint64 value_) noexcept { + value = value_; } - // 32ビットアドレス、アクセス方法、権限が別々なこともよくある。 - busaddr(uint32 addr_, const busaddr& busaddr_, bool super_) { - Set(addr_, busaddr_, super_); + + busaddr(BusAddr value_) noexcept { + value = (uint64)value_; } // コピーコンストラクタを自前で定義すると、 // このクラスがレジスタ渡しから参照渡しになるようなので、 // コピーコンストラクタはデフォルトのまま使う。 - // 代入演算子 (全体のみ) - busaddr& operator=(const busaddr& rhs) & { - Set(rhs.value); - return *this; - } - busaddr& operator=(const uint64& rhs) & { - Set(rhs); - return *this; - } - - uint64 Get() const { return value; } - uint32 Addr() const { return (uint32)value; } + uint64 Get() const noexcept { return value; } + uint32 GetH() const noexcept { return (uint32)(value >> 32); } + uint32 GetL() const noexcept { return (uint32)value; } + uint32 Addr() const noexcept { return (uint32)value; } // S/U ビットを足した計33ビット - uint64 GetSAddr() const { return value & 0x1'ffff'ffffULL; } - uint32 GetFC() const { return (value >> 33) & 7; } - uint32 GetSSW() const { return (value >> 33) & 0x47; } - bool IsSuper() const { return (value & S); } - bool IsData() const { return (value & D); } - bool IsWrite() const { return (value & R) == 0; } - bool IsPhysical() const { return (value & Physical); } - bool IsTableSearched() const { return (value & TableSearched); } - bool IsBusErr() const { return (value & BusErr); } - - void Clear() { value = 0; } - void Set(uint64 value_) { value = value_; } - // 32ビットアドレスと属性を代入したいことはよくある。 - void Set(uint32 addr_, const busaddr& busaddr_) { - Set((uint64)addr_ | busaddr_); - } - void Set(uint32 addr_, const busaddr& busaddr_, bool super_) { - Set((uint64)addr_ | busaddr_ | (super_ ? busaddr::S : busaddr::U)); - } - // FC 等は変えずにアドレスだけセットする。 - void SetAddr(uint32 addr_) { + uint64 GetSAddr() const noexcept + { return value & 0x1'ffff'ffffULL; } + uint32 GetFC() const noexcept { return (value >> 33) & 7; } + uint32 GetSSW() const noexcept { return (value >> 33) & 0x47; } + uint32 GetSize() const noexcept { return (value >> 48) & 7; } + bool IsSuper() const noexcept { return (value & (uint64)BusAddr::S); } + bool IsData() const noexcept { return (value & (uint64)BusAddr::D); } + bool IsWrite() const noexcept + { return (value & (uint64)BusAddr::R) == 0; } + bool IsPhysical() const noexcept + { return (value & (uint64)BusAddr::Physical); } + bool IsTableSearched() const noexcept + { return (value & (uint64)BusAddr::TableSearched); } + bool IsBusErr() const noexcept + { return (value & (uint64)BusAddr::BusErr); } + + // Change*() は特定のフィールドだけ差し替える + + void ChangeAddr(uint32 addr_) noexcept { value &= 0xffffffff'00000000; value |= addr_; } - void SetSuper(bool super_) { + void ChangeSuper(bool super_) noexcept { if (super_) { - value |= S; + value |= (uint64)BusAddr::S; } else { - value &= ~S; + value &= ~(uint64)BusAddr::S; } } - void SetData(bool data_) { - value &= ~(I|D); + void ChangeData(bool data_) noexcept { + value &= ~(uint64)(BusAddr::I | BusAddr::D); if (data_) { - value |= D; + value |= (uint64)BusAddr::D; } else { - value |= I; + value |= (uint64)BusAddr::I; } } - void SetWrite(bool write_) { + void ChangeWrite(bool write_) noexcept { if (write_) { - value &= ~R; + value &= ~(uint64)BusAddr::R; } else { - value |= R; + value |= (uint64)BusAddr::R; } } - void SetPhysical(bool physical_) { - if (physical_) { - value |= Physical; - } else { - value &= ~Physical; - } + void ChangeSize(uint32 n) noexcept { + value &= ~(uint64)BusAddr::SizeMask; + value |= (uint64)Size(n); } - operator uint64() const { return Get(); } - + public: // addr |= (busaddr) で FC とかのビットが足せると楽。 busaddr& operator|=(const busaddr& rhs) { value |= rhs.value; return *this; } + busaddr& operator|=(const uint32& mask_) { + ChangeAddr(Addr() | mask_); + return *this; + } // addr &= mask でマスクが適用できると楽。 - busaddr& operator&=(const uint32 mask_) { - SetAddr(Addr() & mask_); + busaddr& operator&=(const uint32& mask_) { + ChangeAddr(Addr() & mask_); + return *this; + } + busaddr& operator|=(const BusAddr& rhs) { + value |= (uint64)rhs; + return *this; + } + busaddr& operator&=(const BusAddr& rhs) { + value &= (uint64)rhs; return *this; } // addr += n, -= n でアドレス進められると楽。 - busaddr& operator+=(uint32 val) { - SetAddr(Addr() + val); + busaddr& operator+=(const uint32& val) { + ChangeAddr(Addr() + val); return *this; } - busaddr& operator-=(uint32 val) { - SetAddr(Addr() - val); + busaddr& operator-=(const uint32& val) { + ChangeAddr(Addr() - val); return *this; } // addr++ でアドレス進められると楽。 busaddr operator++(int n) { busaddr old(value); - SetAddr(Addr() + 1); + ChangeAddr(Addr() + 1); return old; } // ++addr でアドレス進められると楽。 busaddr& operator++() { - SetAddr(Addr() + 1); + ChangeAddr(Addr() + 1); return *this; } }; -// busaddr と uint32 の AND 演算子。 -// busaddr & val だけでアドレスがマスクして取り出せると楽。 -static __unused uint32 operator&(const busaddr& addr_, const uint32& mask_) { - return addr_.Addr() & mask_; +// busaddr の等価演算子 +static __unused bool operator==(const busaddr& lhs, const busaddr& rhs) { + return (lhs.Get() == rhs.Get()); } -static __unused uint32 operator&(const busaddr& addr_, int mask_) { - return addr_.Addr() & (uint32)mask_; +static __unused bool operator!=(const busaddr& lhs, const busaddr& rhs) { + return !(lhs == rhs); +} + +// busaddr に対する OR 演算子 +static __unused busaddr operator|(const busaddr& lhs, const uint64& rhs) { + return busaddr(lhs.Get() | rhs); +} +static __unused busaddr operator|(const busaddr& lhs, const busaddr& rhs) { + return lhs | rhs.Get(); +} +static __unused busaddr operator|(const busaddr& lhs, const BusAddr& rhs) { + return lhs | (busaddr)rhs; +} +static __unused busaddr operator|(const BusAddr& lhs, const busaddr& rhs) { + return (busaddr)lhs | rhs; } @@ -205,80 +247,109 @@ static __unused uint32 operator&(const b // : 6 : 5 : 4: 3:3 0 // 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+ -// |B|R| | Wait [nsec] | Data | -// |E|T| | | (32bit) | +// |B|R| |Size | Wait [nsec] | Data | +// |E|T| | | | (32bit) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+ // // BE (63ビット目) はバスエラー。 // RT (62ビット目) はリトライ。SPC で使う。 +// 48,49,50ビット目は応答サイズ。デバイスが処理したバイト数を 1 - 4 で返す。 + +// 定数 +enum class BusData : uint64 +{ + OK = 0, + // BusErr は Data() 部分を $ffffffff に見せておく。Peek*() でも使う。 + BusErr = 0x8000'0000'ffff'ffffULL, + Retry = 0x4000'0000'0000'0000ULL, + + Size1 = (uint64)BusAddr::Size1, + Size2 = (uint64)BusAddr::Size2, + Size3 = (uint64)BusAddr::Size3, + Size4 = (uint64)BusAddr::Size4, + SizeMask = (uint64)BusAddr::SizeMask, +}; + +// BusData に対する OR 演算子 (まだ busdata は出せない) +static __unused BusData operator|(const BusData& lhs, const BusData& rhs) { + return (BusData)((uint64)lhs | (uint64)rhs); +} +static __unused BusData operator|(const BusData& lhs, const uint64& rhs) { + return (BusData)((uint64)lhs | rhs); +} +static __unused BusData operator|(const uint64& lhs, const BusData& rhs) { + return (BusData)(lhs | (uint64)rhs); +} + class busdata { private: uint64 value {}; public: - // BusErr は Data() 部分を $ffffffff に見せておく。Peek*() でも使う。 - static const uint64 OK = 0; - static const uint64 BusErr = 0x8000'0000'ffff'ffffULL; - static const uint64 Retry = 0x4000'0000'0000'0000ULL; - - static constexpr uint64 Wait(uint32 nsec) { - return (uint64)nsec << 32; + // ウェイト + static constexpr BusData Wait(uint32 nsec) noexcept { + return (BusData)((uint64)nsec << 32); + } + // データサイズ + static constexpr BusData Size(uint n) noexcept { + return (BusData)((uint64)n << 48); } private: // バスエラーかどうか判定するのに使うのは BusErrBit のほう。 - static const uint64 BusErrBit = 0x8000'0000'0000'0000ULL; - static const uint64 RetryBit = Retry; - static const uint64 Mask = BusErrBit | RetryBit; + enum : uint64 { + BusErrBit = 0x8000'0000'0000'0000ULL, + RetryBit = (uint64)BusData::Retry, + Mask = BusErrBit | RetryBit, + }; public: - busdata() { - Clear(); + busdata() noexcept { } - busdata(uint64 value_) { - Set(value_); + + // uint32 の値をそのまま busdata 型に代入したいので explicit はつけない。 + busdata(uint64 value_) noexcept { + value = value_; + } + + busdata(BusData value_) noexcept { + value = (uint64)value_; } // コピーコンストラクタを自前で定義すると、 // このクラスがレジスタ渡しから参照渡しになるようなので、 // コピーコンストラクタはデフォルトのまま使う。 - // 代入演算子 (全体のみ) - busdata& operator=(const busdata& rhs) & { - Set(rhs.value); - return *this; - } - busdata& operator=(const uint64& rhs) & { - Set(rhs); - return *this; - } + // uint64 にキャストできる + operator uint64() const noexcept { return Get(); } - uint64 Get() const { return value; } - uint32 Data() const { return (uint32)value; } - uint32 GetWait() const { - uint32 wait = (value >> 32) & 0xffff; - return wait; - } - bool IsOK() const { return (value & Mask) == 0; } - bool IsBusErr() const { return (value & BusErrBit); } - bool IsRetry() const { return (value & RetryBit); } + uint64 Get() const noexcept { return value; } + uint32 GetH() const noexcept { return (uint32)(value >> 32); } + uint32 GetL() const noexcept { return (uint32)value; } + uint32 Data() const noexcept { return (uint32)value; } + uint32 GetWait() const noexcept { return (uint32)((value >> 32) & 0xffff); } + uint32 GetSize() const noexcept { return (uint32)((value >> 48) & 7); } + bool IsOK() const noexcept { return (value & Mask) == 0; } + bool IsBusErr() const noexcept { return (value & BusErrBit); } + bool IsRetry() const noexcept { return (value & RetryBit); } - void Clear() { value = 0; } - void Set(uint64 value_) { value = value_; } - void SetData(uint32 data_) { + void ChangeData(uint32 data_) noexcept { value &= 0xffffffff'00000000; value |= data_; } - void SetWait(uint32 wait) { + void ChangeWait(uint32 wait) noexcept { value &= 0xffff0000'ffffffff; - value |= (uint64)wait << 32; + value |= (uint64)Wait(wait); } - void SetBusErr() { value |= BusErr; } - void SetRetry() { value |= Retry; } - - operator uint64() const { return Get(); } + void ChangeSize(uint32 n) noexcept { + value &= ~(uint64)BusData::SizeMask; + value |= (uint64)Size(n); + } + void SetBusErr() noexcept { value |= (uint64)BusData::BusErr; } + void SetRetry() noexcept { value |= (uint64)BusData::Retry; } + public: // data |= (busdata) で別途用意してあるウェイトが足せると楽。 busdata& operator|=(const busdata& rhs) { value |= rhs.value; @@ -287,19 +358,36 @@ class busdata // data &= (uint32) でデータ部分のみ演算できると楽。 busdata& operator&=(const uint32& rhs) { - SetData(Data() & rhs); + ChangeData(Data() & rhs); return *this; } // data <<= (uint32) でデータ部分のみシフトできると楽。 busdata& operator<<=(const uint32& rhs) { - SetData(Data() << rhs); + ChangeData(Data() << rhs); return *this; } // data >>= (uint32) でデータ部分のみシフトできると楽。 busdata& operator>>=(const uint32& rhs) { - SetData(Data() >> rhs); + ChangeData(Data() >> rhs); return *this; } }; + +// busdata に対する OR 演算子 +static __unused busdata operator|(const busdata& lhs, const uint64& rhs) { + return busdata(lhs.Get() | rhs); +} +static __unused busdata operator|(const busdata& lhs, const busdata& rhs) { + return lhs | rhs.Get(); +} +static __unused busdata operator|(const busdata& lhs, const BusData& rhs) { + return lhs | (busdata)rhs; +} +static __unused busdata operator|(const BusData& lhs, const busdata& rhs) { + return (busdata)lhs | rhs; +} +static __unused busdata operator|(const uint64& lhs, const busdata& rhs) { + return busdata(lhs | rhs.Get()); +}