|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.