Annotation of nono/vm/bus.h, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
1.1.1.6   root        3: // Copyright (C) 2024 nono project
1.1.1.3   root        4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.5   root        7: //
1.1.1.6   root        8: // バス
1.1.1.5   root        9: //
                     10: 
1.1       root       11: #pragma once
                     12: 
1.1.1.10! root       13: #include "tick.h"
1.1       root       14: 
1.1.1.6   root       15: // busaddr はアドレスバスにいくつかの情報を追加した構造。
                     16: //
                     17: // :      6        :          5    :              4:              3:3       0
                     18: //  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
                     19: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
1.1.1.10! root       20: // |B| |C|     |T|P|         |Size |               |R|     |S|I|D|S| Address |
        !            21: // |E| |I|     |S|A|         |     |               |W|     |2| | | | (32bit) |
1.1.1.6   root       22: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
1.1.1.10! root       23: //                                                  7 6 5 4 3 2 1 0
        !            24: // BE (BusError, bit63)
        !            25: //     アドレス変換時のバスエラー。
1.1.1.6   root       26: //
1.1.1.10! root       27: // CI (Cache Inhibit, bit61)
        !            28: //
        !            29: // TS (Table Searched, bit57)
        !            30: //     このアドレスを求めるのにテーブルサーチを行ったら%1。デバッガアクセス用。
        !            31: //
        !            32: // PA (Physical Address, bit56)
        !            33: //     このアドレスを物理アドレスとする場合は %1 を指定する。
        !            34: //     論理アドレスまたは区別が不要な場合は %0 にする。
        !            35: //     論理アドレスと物理アドレスの両方を受け取るメモリダンプとかで使う。
        !            36: //
        !            37: // Size (bit50-48)
        !            38: //     要求バイト数で 1 .. 4 で表す。
        !            39: //
        !            40: // RW (Read/Write, bit39)
        !            41: //     Read なら %1。
        !            42: //     上位ワードを >>1 して下位7ビットを取り出すと SSW (の FC と RW) になる。
        !            43: //
        !            44: // S2, I, D, S (bit35-32)
        !            45: //     S と S2 はどちらも S/U で同じ値を入れる。
        !            46: //     D はデータアクセスなら %1 で、m68030 の FC0 に相当。
        !            47: //     I は命令(プログラム)アクセスなら %1 で、m68030 の FC1 に相当。
        !            48: //     この並びは
        !            49: //      o 下位 33 ビットで S/U と32ビットアドレスが表現できる。
        !            50: //      o 下位 35 ビットで FC(順不同) と32ビットアドレスが表現できる。
        !            51: //      o 上位ワードを >>1 すると下位3ビットが FC2-0 (同順) になる。
1.1.1.7   root       52: 
                     53: // 定数
                     54: enum class BusAddr : uint64
                     55: {
                     56:        D                               = 0x0000'0002'0000'0000ULL,     // データ空間
                     57:        I                               = 0x0000'0004'0000'0000ULL,     // 命令空間
                     58:        S                               = 0x0000'0009'0000'0000ULL,     // スーパーバイザ空間
                     59:        U                               = 0x0000'0000'0000'0000ULL,     // ユーザ空間
                     60:        R                               = 0x0000'0080'0000'0000ULL,     // 読み込み
                     61:        W                               = 0x0000'0000'0000'0000ULL,     // 書き込み
                     62: 
                     63:        Fetch                   = I | R,
                     64:        Read                    = D | R,
                     65:        Write                   = D | W,
                     66:        SRead                   = S | Read,
                     67:        SWrite                  = S | Write,
1.1.1.8   root       68:        FCMask                  = 0x0000'000f'0000'0000ULL,
1.1.1.7   root       69: 
                     70:        Size1                   = 0x0001'0000'0000'0000ULL,
                     71:        Size2                   = 0x0002'0000'0000'0000ULL,
                     72:        Size3                   = 0x0003'0000'0000'0000ULL,
                     73:        Size4                   = 0x0004'0000'0000'0000ULL,
                     74:        SizeMask                = 0x0007'0000'0000'0000ULL,
                     75: 
                     76:        // デバッガ用
                     77:        Physical                = 0x0100'0000'0000'0000ULL,
                     78:        Logical                 = 0x0000'0000'0000'0000ULL,
                     79:        TableSearched   = 0x0200'0000'0000'0000ULL,
                     80: 
1.1.1.10! root       81:        CInhibit                = 0x2000'0000'0000'0000ULL,
1.1.1.7   root       82:        BusErr                  = 0x8000'0000'0000'0000ULL,
                     83: };
                     84: 
                     85: // BusAddr に対する OR 演算子 (まだ busaddr は出せない)
1.1.1.10! root       86: inline BusAddr operator|(const BusAddr& lhs, const BusAddr& rhs) {
1.1.1.7   root       87:        return (BusAddr)((uint64)lhs | (uint64)rhs);
                     88: }
1.1.1.10! root       89: inline BusAddr operator|(const BusAddr& lhs, const uint64& rhs) {
1.1.1.7   root       90:        return (BusAddr)((uint64)lhs | rhs);
                     91: }
1.1.1.10! root       92: inline BusAddr operator|(const uint64& lhs, const BusAddr& rhs) {
1.1.1.7   root       93:        return (BusAddr)(lhs | (uint64)rhs);
                     94: }
1.1.1.2   root       95: 
1.1.1.6   root       96: class busaddr
1.1.1.2   root       97: {
1.1.1.6   root       98:  private:
                     99:        uint64 value {};
                    100: 
                    101:  public:
                    102:        // ファンクションコードから busaddr を作成。fc_ は 0-7 にすること。
1.1.1.7   root      103:        static constexpr BusAddr FC(uint32 fc_) noexcept {
                    104:                return (BusAddr)(((uint64)fc_ << 33) | ((uint64)(fc_ & 4) << 30));
                    105:        }
                    106:        // アクセスサイズ
                    107:        static constexpr BusAddr Size(uint n) noexcept {
                    108:                return (BusAddr)((uint64)n << 48);
                    109:        }
                    110:        // S/U
                    111:        static constexpr BusAddr SU(bool super_) noexcept {
                    112:                return super_ ? BusAddr::S : BusAddr::U;
1.1.1.6   root      113:        }
                    114: 
                    115:  public:
1.1.1.7   root      116:        busaddr() noexcept {
1.1.1.6   root      117:        }
1.1.1.2   root      118: 
1.1.1.7   root      119:        explicit busaddr(uint64 value_) noexcept {
                    120:                value = value_;
1.1.1.6   root      121:        }
1.1.1.7   root      122: 
1.1.1.9   root      123:        // enum からの自動変換のため explicit つけない。
1.1.1.7   root      124:        busaddr(BusAddr value_) noexcept {
                    125:                value = (uint64)value_;
1.1.1.6   root      126:        }
                    127: 
                    128:        // コピーコンストラクタを自前で定義すると、
                    129:        // このクラスがレジスタ渡しから参照渡しになるようなので、
                    130:        // コピーコンストラクタはデフォルトのまま使う。
                    131: 
1.1.1.7   root      132:        uint64 Get() const noexcept             { return value; }
                    133:        uint32 GetH() const noexcept    { return (uint32)(value >> 32); }
                    134:        uint32 GetL() const noexcept    { return (uint32)value; }
                    135:        uint32 Addr() const noexcept    { return (uint32)value; }
1.1.1.6   root      136:        // S/U ビットを足した計33ビット
1.1.1.7   root      137:        uint64 GetSAddr() const noexcept
                    138:                                                                        { return value & 0x1'ffff'ffffULL; }
                    139:        uint32 GetFC() const noexcept   { return (value >> 33) & 7; }
                    140:        uint32 GetSize() const noexcept { return (value >> 48) & 7; }
                    141:        bool IsSuper() const noexcept   { return (value & (uint64)BusAddr::S); }
                    142:        bool IsData() const noexcept    { return (value & (uint64)BusAddr::D); }
1.1.1.10! root      143:        bool IsRead() const noexcept    { return (value & (uint64)BusAddr::R); }
        !           144:        bool IsWrite() const noexcept   { return !IsRead(); }
1.1.1.7   root      145:        bool IsPhysical() const noexcept
                    146:                                                        { return (value & (uint64)BusAddr::Physical); }
                    147:        bool IsTableSearched() const noexcept
                    148:                                                        { return (value & (uint64)BusAddr::TableSearched); }
1.1.1.10! root      149:        bool IsCInhibit() const noexcept
        !           150:                                                        { return (value & (uint64)BusAddr::CInhibit); }
        !           151:        bool IsOK() const noexcept              { return !IsBusErr(); }
1.1.1.7   root      152:        bool IsBusErr() const noexcept
                    153:                                                        { return (value & (uint64)BusAddr::BusErr); }
                    154: 
                    155:        // Change*() は特定のフィールドだけ差し替える
                    156: 
                    157:        void ChangeAddr(uint32 addr_) noexcept {
1.1.1.6   root      158:                value &= 0xffffffff'00000000;
                    159:                value |= addr_;
                    160:        }
1.1.1.7   root      161:        void ChangeSuper(bool super_) noexcept {
1.1.1.6   root      162:                if (super_) {
1.1.1.7   root      163:                        value |= (uint64)BusAddr::S;
1.1.1.6   root      164:                } else {
1.1.1.7   root      165:                        value &= ~(uint64)BusAddr::S;
1.1.1.6   root      166:                }
                    167:        }
1.1.1.8   root      168:        void ChangeFC(uint32 fc_) noexcept {
                    169:                value &= ~(uint64)BusAddr::FCMask;
                    170:                value |= (uint64)busaddr::FC(fc_);
                    171:        }
1.1.1.7   root      172:        void ChangeData(bool data_) noexcept {
                    173:                value &= ~(uint64)(BusAddr::I | BusAddr::D);
1.1.1.6   root      174:                if (data_) {
1.1.1.7   root      175:                        value |= (uint64)BusAddr::D;
1.1.1.6   root      176:                } else {
1.1.1.7   root      177:                        value |= (uint64)BusAddr::I;
1.1.1.6   root      178:                }
                    179:        }
1.1.1.7   root      180:        void ChangeWrite(bool write_) noexcept {
1.1.1.6   root      181:                if (write_) {
1.1.1.7   root      182:                        value &= ~(uint64)BusAddr::R;
1.1.1.6   root      183:                } else {
1.1.1.7   root      184:                        value |= (uint64)BusAddr::R;
1.1.1.6   root      185:                }
                    186:        }
1.1.1.7   root      187:        void ChangeSize(uint32 n) noexcept {
                    188:                value &= ~(uint64)BusAddr::SizeMask;
                    189:                value |= (uint64)Size(n);
1.1.1.6   root      190:        }
                    191: 
1.1.1.7   root      192:  public:
1.1.1.6   root      193:        // addr |= (busaddr) で FC とかのビットが足せると楽。
                    194:        busaddr& operator|=(const busaddr& rhs) {
                    195:                value |= rhs.value;
                    196:                return *this;
                    197:        }
1.1.1.7   root      198:        busaddr& operator|=(const uint32& mask_) {
                    199:                ChangeAddr(Addr() | mask_);
                    200:                return *this;
                    201:        }
1.1.1.6   root      202:        // addr &= mask でマスクが適用できると楽。
1.1.1.7   root      203:        busaddr& operator&=(const uint32& mask_) {
                    204:                ChangeAddr(Addr() & mask_);
                    205:                return *this;
                    206:        }
                    207:        busaddr& operator|=(const BusAddr& rhs) {
                    208:                value |= (uint64)rhs;
                    209:                return *this;
                    210:        }
                    211:        busaddr& operator&=(const BusAddr& rhs) {
                    212:                value &= (uint64)rhs;
1.1.1.6   root      213:                return *this;
                    214:        }
                    215: 
                    216:        // addr += n, -= n でアドレス進められると楽。
1.1.1.7   root      217:        busaddr& operator+=(const uint32& val) {
                    218:                ChangeAddr(Addr() + val);
1.1.1.6   root      219:                return *this;
                    220:        }
1.1.1.7   root      221:        busaddr& operator-=(const uint32& val) {
                    222:                ChangeAddr(Addr() - val);
1.1.1.6   root      223:                return *this;
                    224:        }
                    225:        // addr++ でアドレス進められると楽。
                    226:        busaddr operator++(int n) {
                    227:                busaddr old(value);
1.1.1.7   root      228:                ChangeAddr(Addr() + 1);
1.1.1.6   root      229:                return old;
                    230:        }
                    231:        // ++addr でアドレス進められると楽。
                    232:        busaddr& operator++() {
1.1.1.7   root      233:                ChangeAddr(Addr() + 1);
1.1.1.6   root      234:                return *this;
                    235:        }
                    236: };
                    237: 
1.1.1.7   root      238: // busaddr の等価演算子
1.1.1.10! root      239: inline bool operator==(const busaddr& lhs, const busaddr& rhs) {
1.1.1.7   root      240:        return (lhs.Get() == rhs.Get());
1.1.1.6   root      241: }
1.1.1.10! root      242: inline bool operator!=(const busaddr& lhs, const busaddr& rhs) {
1.1.1.7   root      243:        return !(lhs == rhs);
                    244: }
                    245: 
                    246: // busaddr に対する OR 演算子
1.1.1.10! root      247: inline busaddr operator|(const busaddr& lhs, const uint64& rhs) {
1.1.1.7   root      248:        return busaddr(lhs.Get() | rhs);
                    249: }
1.1.1.10! root      250: inline busaddr operator|(const busaddr& lhs, const busaddr& rhs) {
1.1.1.7   root      251:        return lhs | rhs.Get();
                    252: }
1.1.1.10! root      253: inline busaddr operator|(const busaddr& lhs, const BusAddr& rhs) {
1.1.1.7   root      254:        return lhs | (busaddr)rhs;
                    255: }
1.1.1.10! root      256: inline busaddr operator|(const BusAddr& lhs, const busaddr& rhs) {
1.1.1.7   root      257:        return (busaddr)lhs | rhs;
1.1.1.2   root      258: }
1.1       root      259: 
1.1.1.6   root      260: 
                    261: // busdata はデータバスにいくつかの応答情報を追加した構造。
                    262: //
                    263: // :      6        :          5    :              4:              3:3       0
                    264: //  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
                    265: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
1.1.1.7   root      266: // |B|R|                     |Size |        Wait [nsec]            | Data    |
                    267: // |E|T|                     |     |                               | (32bit) |
1.1.1.6   root      268: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
                    269: //
1.1.1.10! root      270: // BE (BusError, bit63)
        !           271: //     バスエラー。
        !           272: //
        !           273: // RT (Retry, bit62)
        !           274: //     リトライ。SPC で使う。
        !           275: //
        !           276: // Size (bit50-48)
        !           277: //     デバイスが処理したバイト数で、1 .. 4 で表す。
        !           278: //
        !           279: // Wait (bit47-32)
        !           280: //     ウェイトは [tsec] で設定・取得するが、ここに格納するときは [nsec] にする。
        !           281: //     XXX あとで Size を移動してから [tsec] に統一するかも。
1.1.1.7   root      282: 
                    283: // 定数
                    284: enum class BusData : uint64
                    285: {
                    286:        OK                              = 0,
                    287:        // BusErr は Data() 部分を $ffffffff に見せておく。Peek*() でも使う。
                    288:        BusErr                  = 0x8000'0000'ffff'ffffULL,
                    289:        Retry                   = 0x4000'0000'0000'0000ULL,
                    290: 
                    291:        Size1                   = (uint64)BusAddr::Size1,
                    292:        Size2                   = (uint64)BusAddr::Size2,
                    293:        Size3                   = (uint64)BusAddr::Size3,
                    294:        Size4                   = (uint64)BusAddr::Size4,
                    295:        SizeMask                = (uint64)BusAddr::SizeMask,
                    296: };
                    297: 
                    298: // BusData に対する OR 演算子 (まだ busdata は出せない)
1.1.1.10! root      299: inline BusData operator|(const BusData& lhs, const BusData& rhs) {
1.1.1.7   root      300:        return (BusData)((uint64)lhs | (uint64)rhs);
                    301: }
1.1.1.10! root      302: inline BusData operator|(const BusData& lhs, const uint64& rhs) {
1.1.1.7   root      303:        return (BusData)((uint64)lhs | rhs);
                    304: }
1.1.1.10! root      305: inline BusData operator|(const uint64& lhs, const BusData& rhs) {
1.1.1.7   root      306:        return (BusData)(lhs | (uint64)rhs);
                    307: }
                    308: 
1.1.1.6   root      309: class busdata
                    310: {
                    311:  private:
                    312:        uint64 value {};
                    313: 
                    314:  public:
1.1.1.10! root      315:        // ウェイトを [tsec] で指定する
        !           316:        static constexpr BusData Wait(uint64 tsec) noexcept {
        !           317:                return (BusData)(tsec_to_nsec(tsec) << 32);
1.1.1.7   root      318:        }
                    319:        // データサイズ
                    320:        static constexpr BusData Size(uint n) noexcept {
                    321:                return (BusData)((uint64)n << 48);
1.1.1.6   root      322:        }
                    323: 
                    324:  private:
                    325:        // バスエラーかどうか判定するのに使うのは BusErrBit のほう。
1.1.1.7   root      326:        enum : uint64 {
                    327:                BusErrBit       = 0x8000'0000'0000'0000ULL,
                    328:                RetryBit        = (uint64)BusData::Retry,
                    329:                Mask            = BusErrBit | RetryBit,
                    330:        };
1.1.1.6   root      331: 
                    332:  public:
1.1.1.7   root      333:        busdata() noexcept {
1.1.1.6   root      334:        }
1.1.1.7   root      335: 
                    336:        // uint32 の値をそのまま busdata 型に代入したいので explicit はつけない。
                    337:        busdata(uint64 value_) noexcept {
                    338:                value = value_;
                    339:        }
                    340: 
1.1.1.9   root      341:        // enum からの自動変換のため explicit つけない。
1.1.1.7   root      342:        busdata(BusData value_) noexcept {
                    343:                value = (uint64)value_;
1.1.1.6   root      344:        }
                    345: 
                    346:        // コピーコンストラクタを自前で定義すると、
                    347:        // このクラスがレジスタ渡しから参照渡しになるようなので、
                    348:        // コピーコンストラクタはデフォルトのまま使う。
                    349: 
1.1.1.7   root      350:        // uint64 にキャストできる
                    351:        operator uint64() const noexcept { return Get(); }
1.1.1.6   root      352: 
1.1.1.7   root      353:        uint64 Get() const noexcept             { return value; }
                    354:        uint32 GetH() const noexcept    { return (uint32)(value >> 32); }
                    355:        uint32 GetL() const noexcept    { return (uint32)value; }
                    356:        uint32 Data() const noexcept    { return (uint32)value; }
1.1.1.10! root      357:        // ウェイトを [tsec] で取得。
        !           358:        uint64 GetWait() const noexcept {
        !           359:                return nsec_to_tsec((value >> 32) & 0xffff);
        !           360:        }
1.1.1.7   root      361:        uint32 GetSize() const noexcept { return (uint32)((value >> 48) & 7); }
                    362:        bool IsOK() const noexcept              { return (value & Mask) == 0; }
                    363:        bool IsBusErr() const noexcept  { return (value & BusErrBit); }
                    364:        bool IsRetry() const noexcept   { return (value & RetryBit); }
1.1.1.6   root      365: 
1.1.1.7   root      366:        void ChangeData(uint32 data_) noexcept {
1.1.1.6   root      367:                value &= 0xffffffff'00000000;
                    368:                value |= data_;
                    369:        }
1.1.1.10! root      370:        // ウェイトを tsec に変更。
        !           371:        void ChangeWait(uint64 tsec) noexcept {
1.1.1.6   root      372:                value &= 0xffff0000'ffffffff;
1.1.1.10! root      373:                value |= (uint64)Wait(tsec);
1.1.1.6   root      374:        }
1.1.1.7   root      375:        void ChangeSize(uint32 n) noexcept {
                    376:                value &= ~(uint64)BusData::SizeMask;
                    377:                value |= (uint64)Size(n);
                    378:        }
                    379:        void SetBusErr() noexcept               { value |= (uint64)BusData::BusErr; }
                    380:        void SetRetry() noexcept                { value |= (uint64)BusData::Retry; }
1.1.1.6   root      381: 
1.1.1.7   root      382:  public:
1.1.1.6   root      383:        // data |= (busdata) で別途用意してあるウェイトが足せると楽。
                    384:        busdata& operator|=(const busdata& rhs) {
                    385:                value |= rhs.value;
                    386:                return *this;
                    387:        }
                    388: 
                    389:        // data &= (uint32) でデータ部分のみ演算できると楽。
                    390:        busdata& operator&=(const uint32& rhs) {
1.1.1.7   root      391:                ChangeData(Data() & rhs);
1.1.1.6   root      392:                return *this;
                    393:        }
                    394: 
                    395:        // data <<= (uint32) でデータ部分のみシフトできると楽。
                    396:        busdata& operator<<=(const uint32& rhs) {
1.1.1.7   root      397:                ChangeData(Data() << rhs);
1.1.1.6   root      398:                return *this;
                    399:        }
                    400: 
                    401:        // data >>= (uint32) でデータ部分のみシフトできると楽。
                    402:        busdata& operator>>=(const uint32& rhs) {
1.1.1.7   root      403:                ChangeData(Data() >> rhs);
1.1.1.6   root      404:                return *this;
                    405:        }
                    406: };
1.1.1.7   root      407: 
                    408: // busdata に対する OR 演算子
1.1.1.10! root      409: inline busdata operator|(const busdata& lhs, const uint64& rhs) {
1.1.1.7   root      410:        return busdata(lhs.Get() | rhs);
                    411: }
1.1.1.10! root      412: inline busdata operator|(const busdata& lhs, const busdata& rhs) {
1.1.1.7   root      413:        return lhs | rhs.Get();
                    414: }
1.1.1.10! root      415: inline busdata operator|(const busdata& lhs, const BusData& rhs) {
1.1.1.7   root      416:        return lhs | (busdata)rhs;
                    417: }
1.1.1.10! root      418: inline busdata operator|(const BusData& lhs, const busdata& rhs) {
1.1.1.7   root      419:        return (busdata)lhs | rhs;
                    420: }
1.1.1.10! root      421: inline busdata operator|(const uint64& lhs, const busdata& rhs) {
1.1.1.7   root      422:        return busdata(lhs | rhs.Get());
                    423: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.