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