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

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

unix.superglobalmegacorp.com

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