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

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

unix.superglobalmegacorp.com

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