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