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

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

unix.superglobalmegacorp.com

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