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