|
|
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.6 ! root 13: #include "header.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: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
! 20: // |B|T| |P| |R| |S|I|D|S| Address |
! 21: // |E|S| |A| |W| |U| | |U| (32bit) |
! 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: //
! 35: // 以下はデバッガなどで使用する追加のビットで、実行系では使わない。
! 36: // 55ビット目 (PA) はこのアドレスを物理アドレスとする場合は %1 を指定する。
! 37: // 論理アドレスまたは区別が不要な場合は %0 にする。
! 38: // 論理アドレスと物理アドレスの両方を受け取るメモリダンプとかで使う。
! 39: // 62ビット目 (TS: Table Search Result) は、このアドレスを求めるのに
! 40: // テーブルサーチを行った場合は %1。
! 41: // 63ビット目 (BE) は (アドレス変換時の) バスエラーを示す。
1.1.1.2 root 42:
1.1.1.6 ! root 43: class busaddr
1.1.1.2 root 44: {
1.1.1.6 ! root 45: private:
! 46: uint64 value {};
! 47:
! 48: public:
! 49: static const uint64 D = 0x0000'0002'0000'0000ULL; // データ空間
! 50: static const uint64 I = 0x0000'0004'0000'0000ULL; // 命令空間
! 51: static const uint64 S = 0x0000'0009'0000'0000ULL; // スーパーバイザ
! 52: static const uint64 U = 0x0000'0000'0000'0000ULL; // ユーザ
! 53: static const uint64 R = 0x0000'0080'0000'0000ULL; // 読み込み
! 54: static const uint64 W = 0x0000'0000'0000'0000ULL; // 書き込み
! 55:
! 56: static const uint64 Fetch = I | R;
! 57: static const uint64 Read = D | R;
! 58: static const uint64 Write = D | W;
! 59:
! 60: // 以下デバッガ用のビット
! 61: static const uint64 Physical = 0x0080'0000'0000'0000ULL;
! 62: static const uint64 Logical = 0x0000'0000'0000'0000ULL;
! 63: static const uint64 TableSearched = 0x4000'0000'0000'0000ULL;
! 64: static const uint64 BusErr = 0x8000'0000'0000'0000ULL;
! 65:
! 66: // ファンクションコードから busaddr を作成。fc_ は 0-7 にすること。
! 67: static constexpr uint64 FC(uint32 fc_) {
! 68: return ((uint64)fc_ << 33) | ((uint64)(fc_ & 4) << 30);
! 69: }
! 70:
! 71: public:
! 72: busaddr() {
! 73: }
! 74: busaddr(uint64 value_) {
! 75: Set(value_);
! 76: }
1.1.1.2 root 77:
1.1.1.6 ! root 78: // 32ビットアドレスと属性を代入したいことはよくある。
! 79: busaddr(uint32 addr_, const busaddr& busaddr_) {
! 80: Set(addr_, busaddr_);
! 81: }
! 82: // 32ビットアドレス、アクセス方法、権限が別々なこともよくある。
! 83: busaddr(uint32 addr_, const busaddr& busaddr_, bool super_) {
! 84: Set(addr_, busaddr_, super_);
! 85: }
! 86:
! 87: // コピーコンストラクタを自前で定義すると、
! 88: // このクラスがレジスタ渡しから参照渡しになるようなので、
! 89: // コピーコンストラクタはデフォルトのまま使う。
! 90:
! 91: // 代入演算子 (全体のみ)
! 92: busaddr& operator=(const busaddr& rhs) & {
! 93: Set(rhs.value);
! 94: return *this;
! 95: }
! 96: busaddr& operator=(const uint64& rhs) & {
! 97: Set(rhs);
! 98: return *this;
! 99: }
! 100:
! 101: uint64 Get() const { return value; }
! 102: uint32 Addr() const { return (uint32)value; }
! 103: // S/U ビットを足した計33ビット
! 104: uint64 GetSAddr() const { return value & 0x1'ffff'ffffULL; }
! 105: uint32 GetFC() const { return (value >> 33) & 7; }
! 106: uint32 GetSSW() const { return (value >> 33) & 0x47; }
! 107: bool IsSuper() const { return (value & S); }
! 108: bool IsData() const { return (value & D); }
! 109: bool IsWrite() const { return (value & R) == 0; }
! 110: bool IsPhysical() const { return (value & Physical); }
! 111: bool IsTableSearched() const { return (value & TableSearched); }
! 112: bool IsBusErr() const { return (value & BusErr); }
! 113:
! 114: void Clear() { value = 0; }
! 115: void Set(uint64 value_) { value = value_; }
! 116: // 32ビットアドレスと属性を代入したいことはよくある。
! 117: void Set(uint32 addr_, const busaddr& busaddr_) {
! 118: Set((uint64)addr_ | busaddr_);
! 119: }
! 120: void Set(uint32 addr_, const busaddr& busaddr_, bool super_) {
! 121: Set((uint64)addr_ | busaddr_ | (super_ ? busaddr::S : busaddr::U));
! 122: }
! 123: // FC 等は変えずにアドレスだけセットする。
! 124: void SetAddr(uint32 addr_) {
! 125: value &= 0xffffffff'00000000;
! 126: value |= addr_;
! 127: }
! 128: void SetSuper(bool super_) {
! 129: if (super_) {
! 130: value |= S;
! 131: } else {
! 132: value &= ~S;
! 133: }
! 134: }
! 135: void SetData(bool data_) {
! 136: value &= ~(I|D);
! 137: if (data_) {
! 138: value |= D;
! 139: } else {
! 140: value |= I;
! 141: }
! 142: }
! 143: void SetWrite(bool write_) {
! 144: if (write_) {
! 145: value &= ~R;
! 146: } else {
! 147: value |= R;
! 148: }
! 149: }
! 150: void SetPhysical(bool physical_) {
! 151: if (physical_) {
! 152: value |= Physical;
! 153: } else {
! 154: value &= ~Physical;
! 155: }
! 156: }
! 157:
! 158: operator uint64() const { return Get(); }
! 159:
! 160: // addr |= (busaddr) で FC とかのビットが足せると楽。
! 161: busaddr& operator|=(const busaddr& rhs) {
! 162: value |= rhs.value;
! 163: return *this;
! 164: }
! 165: // addr &= mask でマスクが適用できると楽。
! 166: busaddr& operator&=(const uint32 mask_) {
! 167: SetAddr(Addr() & mask_);
! 168: return *this;
! 169: }
! 170:
! 171: // addr += n, -= n でアドレス進められると楽。
! 172: busaddr& operator+=(uint32 val) {
! 173: SetAddr(Addr() + val);
! 174: return *this;
! 175: }
! 176: busaddr& operator-=(uint32 val) {
! 177: SetAddr(Addr() - val);
! 178: return *this;
! 179: }
! 180: // addr++ でアドレス進められると楽。
! 181: busaddr operator++(int n) {
! 182: busaddr old(value);
! 183: SetAddr(Addr() + 1);
! 184: return old;
! 185: }
! 186: // ++addr でアドレス進められると楽。
! 187: busaddr& operator++() {
! 188: SetAddr(Addr() + 1);
! 189: return *this;
! 190: }
! 191: };
! 192:
! 193: // busaddr と uint32 の AND 演算子。
! 194: // busaddr & val だけでアドレスがマスクして取り出せると楽。
! 195: static __unused uint32 operator&(const busaddr& addr_, const uint32& mask_) {
! 196: return addr_.Addr() & mask_;
! 197: }
! 198: static __unused uint32 operator&(const busaddr& addr_, int mask_) {
! 199: return addr_.Addr() & (uint32)mask_;
1.1.1.2 root 200: }
1.1 root 201:
1.1.1.6 ! root 202:
! 203: // busdata はデータバスにいくつかの応答情報を追加した構造。
! 204: //
! 205: // : 6 : 5 : 4: 3:3 0
! 206: // 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
! 207: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
! 208: // |B|R| | Wait [nsec] | Data |
! 209: // |E|T| | | (32bit) |
! 210: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-- ... --+
! 211: //
! 212: // BE (63ビット目) はバスエラー。
! 213: // RT (62ビット目) はリトライ。SPC で使う。
! 214: class busdata
! 215: {
! 216: private:
! 217: uint64 value {};
! 218:
! 219: public:
! 220: // BusErr は Data() 部分を $ffffffff に見せておく。Peek*() でも使う。
! 221: static const uint64 OK = 0;
! 222: static const uint64 BusErr = 0x8000'0000'ffff'ffffULL;
! 223: static const uint64 Retry = 0x4000'0000'0000'0000ULL;
! 224:
! 225: static constexpr uint64 Wait(uint32 nsec) {
! 226: return (uint64)nsec << 32;
! 227: }
! 228:
! 229: private:
! 230: // バスエラーかどうか判定するのに使うのは BusErrBit のほう。
! 231: static const uint64 BusErrBit = 0x8000'0000'0000'0000ULL;
! 232: static const uint64 RetryBit = Retry;
! 233: static const uint64 Mask = BusErrBit | RetryBit;
! 234:
! 235: public:
! 236: busdata() {
! 237: Clear();
! 238: }
! 239: busdata(uint64 value_) {
! 240: Set(value_);
! 241: }
! 242:
! 243: // コピーコンストラクタを自前で定義すると、
! 244: // このクラスがレジスタ渡しから参照渡しになるようなので、
! 245: // コピーコンストラクタはデフォルトのまま使う。
! 246:
! 247: // 代入演算子 (全体のみ)
! 248: busdata& operator=(const busdata& rhs) & {
! 249: Set(rhs.value);
! 250: return *this;
! 251: }
! 252: busdata& operator=(const uint64& rhs) & {
! 253: Set(rhs);
! 254: return *this;
! 255: }
! 256:
! 257: uint64 Get() const { return value; }
! 258: uint32 Data() const { return (uint32)value; }
! 259: uint32 GetWait() const {
! 260: uint32 wait = (value >> 32) & 0xffff;
! 261: return wait;
! 262: }
! 263: bool IsOK() const { return (value & Mask) == 0; }
! 264: bool IsBusErr() const { return (value & BusErrBit); }
! 265: bool IsRetry() const { return (value & RetryBit); }
! 266:
! 267: void Clear() { value = 0; }
! 268: void Set(uint64 value_) { value = value_; }
! 269: void SetData(uint32 data_) {
! 270: value &= 0xffffffff'00000000;
! 271: value |= data_;
! 272: }
! 273: void SetWait(uint32 wait) {
! 274: value &= 0xffff0000'ffffffff;
! 275: value |= (uint64)wait << 32;
! 276: }
! 277: void SetBusErr() { value |= BusErr; }
! 278: void SetRetry() { value |= Retry; }
! 279:
! 280: operator uint64() const { return Get(); }
! 281:
! 282: // data |= (busdata) で別途用意してあるウェイトが足せると楽。
! 283: busdata& operator|=(const busdata& rhs) {
! 284: value |= rhs.value;
! 285: return *this;
! 286: }
! 287:
! 288: // data &= (uint32) でデータ部分のみ演算できると楽。
! 289: busdata& operator&=(const uint32& rhs) {
! 290: SetData(Data() & rhs);
! 291: return *this;
! 292: }
! 293:
! 294: // data <<= (uint32) でデータ部分のみシフトできると楽。
! 295: busdata& operator<<=(const uint32& rhs) {
! 296: SetData(Data() << rhs);
! 297: return *this;
! 298: }
! 299:
! 300: // data >>= (uint32) でデータ部分のみシフトできると楽。
! 301: busdata& operator>>=(const uint32& rhs) {
! 302: SetData(Data() >> rhs);
! 303: return *this;
! 304: }
! 305: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.