|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: // バスとデバイスとのインタフェース。
8: // バスに対し、デバイスがどのように接続されているかを記述する。
9:
1.1.1.9 ! root 10: // Poke1() はここで定義しなければ基底クラスの Device::Poke1() が呼ばれて
! 11: // 全域編集不可になる。BusIO を経由する必要があるデバイスはたいていは全域が
! 12: // 編集不可なので、通常この基底の動作でよく、Poke1() を再定義する必要はない。
! 13: // MK48T02Device のみ BusIO 経由で編集可能な領域を持っているため、これを
! 14: // 受け取る BusIO_B と BusIO_BFFF だけ Poke1() を持っている。
! 15: // 従って BusIO_B、BusIO_BFFF の親になるデバイスは全員 PokePort() も実装する
! 16: // 必要がある。うーん。
! 17:
1.1.1.3 root 18: #pragma once
19:
1.1 root 20: #if !defined(SELFTEST)
21: #include "device.h"
22: #endif
23:
1.1.1.9 ! root 24: // テンプレート外のヘルパー関数。
! 25: class BusIO
! 26: {
! 27: static inline uint32 M4(uint32 a, uint32 b, uint32 c, uint32 d) {
! 28: return ((a << 24) | (b << 16) | (c << 8) | d);
! 29: }
! 30:
! 31: public:
! 32: // アドレス(とサイズ情報からなる) addr と書き込みデータ data から
! 33: // m68030 のバスに出るはずのデータを構成する。68030UM.pdf p7-11。
! 34: // m88200 ではこのうち7つ(reqsize==2 なら offset==0 か 2 のみ、等)
! 35: // しか使わないが、そのケースに限れば m68030 と同じ動作になる。
! 36: static inline uint32
! 37: DataMultiplexer_Write_L(const busaddr addr, uint32 data)
! 38: {
! 39: uint32 reqsize = addr.GetSize();
! 40: uint32 offset = addr.Addr() & 3U;
! 41:
! 42: uint32 op0 = (data >> 24) & 0xff;
! 43: uint32 op1 = (data >> 16) & 0xff;
! 44: uint32 op2 = (data >> 8) & 0xff;
! 45: uint32 op3 = data & 0xff;
! 46: if (reqsize == 4) {
! 47: switch (offset) {
! 48: case 0: data = M4(op0, op1, op2, op3); break;
! 49: case 1: data = M4(op0, op0, op1, op2); break;
! 50: case 2: data = M4(op0, op1, op0, op1); break;
! 51: case 3: data = M4(op0, op0, op1, op0); break;
! 52: default:
! 53: __unreachable();
! 54: }
! 55: } else if (reqsize == 3) {
! 56: switch (offset) {
! 57: case 0: data = M4(op1, op2, op3, op0); break;
! 58: case 1: data = M4(op1, op1, op2, op3); break;
! 59: case 2: data = M4(op1, op2, op1, op2); break;
! 60: case 3: data = M4(op1, op1, op2, op1); break;
! 61: default:
! 62: __unreachable();
! 63: }
! 64: } else if (reqsize == 2) {
! 65: if ((offset & 1U) == 0) {
! 66: data = M4(op2, op3, op2, op3);
! 67: } else {
! 68: data = M4(op2, op2, op3, op2);
! 69: }
! 70: } else {
! 71: data = M4(op3, op3, op3, op3);
! 72: }
! 73: return data;
! 74: }
! 75: };
! 76:
1.1 root 77: // バイトデバイスをバイト、ワード、ロングワードポートにミラー配置する共通部
78: template <class T, int rshift>
1.1.1.4 root 79: class BusIO_B_Base : public T
1.1 root 80: {
1.1.1.9 ! root 81: private:
! 82: inline uint32 Decoder(busaddr addr) const {
! 83: return Decoder(addr.Addr());
! 84: }
! 85: inline uint32 Decoder(uint32 addr) const {
1.1 root 86: return (addr >> rshift) & (T::NPORT - 1);
87: }
88:
89: public:
1.1.1.9 ! root 90: busdata Read(busaddr addr) override {
! 91: return T::ReadPort(Decoder(addr));
1.1 root 92: }
93:
1.1.1.9 ! root 94: busdata Write(busaddr addr, uint32 data) override {
! 95: data >>= (addr.GetSize() - 1) * 8;
! 96: return T::WritePort(Decoder(addr), data);
1.1 root 97: }
98:
1.1.1.9 ! root 99: busdata Peek1(uint32 addr) override {
! 100: return T::PeekPort(Decoder(addr));
1.1 root 101: }
1.1.1.7 root 102:
1.1.1.9 ! root 103: bool Poke1(uint32 addr, uint32 data) override {
! 104: return T::PokePort(Decoder(addr), data);
1.1.1.7 root 105: }
1.1 root 106: };
107:
108: // バイトデバイスをバイトのまま配置する。
109: // NPORT によるミラーを行う以外はこれを使わないのと何も変わらない。
110: template <class T>
1.1.1.4 root 111: class BusIO_B : public BusIO_B_Base<T, 0> { };
1.1 root 112: // バイトデバイスをワードにミラー配置する。
113: template <class T>
1.1.1.4 root 114: class BusIO_BB : public BusIO_B_Base<T, 1> { };
1.1 root 115: // バイトデバイスをロングワードにミラー配置する。
116: template <class T>
1.1.1.4 root 117: class BusIO_BBBB : public BusIO_B_Base<T, 2> { };
1.1 root 118:
119: // ワードデバイスをワードのまま配置する。
120: // NPORT によるミラーを行う以外はこれを使わないのと何も変わらない。
121: template <class T>
1.1.1.4 root 122: class BusIO_W : public T
1.1 root 123: {
124: private:
1.1.1.9 ! root 125: inline uint32 Decoder(busaddr addr) const {
! 126: return Decoder(addr.Addr());
! 127: }
! 128: inline uint32 Decoder(uint32 addr) const {
1.1 root 129: return (addr >> 1) & (T::NPORT - 1);
130: }
1.1.1.9 ! root 131: static inline uint32 M2(uint32 a, uint32 b) {
! 132: return ((a) << 8) | b;
! 133: }
1.1 root 134:
135: public:
1.1.1.9 ! root 136: busdata Read(busaddr addr) override {
! 137: return T::ReadPort(Decoder(addr));
1.1 root 138: }
139:
1.1.1.9 ! root 140: busdata Write(busaddr addr, uint32 data) override {
! 141: uint32 reqsize = addr.GetSize();
! 142: uint32 offset = addr.Addr() & 1;
! 143:
! 144: uint32 op0 = (data >> 24) & 0xff;
! 145: uint32 op1 = (data >> 16) & 0xff;
! 146: uint32 op2 = (data >> 8) & 0xff;
! 147: uint32 op3 = data & 0xff;
! 148: if (reqsize == 1) {
! 149: data = M2(op3, op3);
! 150: } else if (reqsize == 2) {
! 151: if (offset == 0) {
! 152: data = M2(op2, op3);
! 153: } else {
! 154: data = M2(op2, op2);
! 155: }
! 156: } else if (reqsize == 3) {
! 157: if (offset == 0) {
! 158: data = M2(op1, op2);
! 159: } else {
! 160: data = M2(op1, op1);
! 161: }
! 162: } else {
! 163: if (offset == 0) {
! 164: data = M2(op0, op1);
! 165: } else {
! 166: data = M2(op0, op0);
! 167: }
! 168: }
! 169: return T::WritePort(Decoder(addr), data);
1.1 root 170: }
171:
1.1.1.9 ! root 172: busdata Peek1(uint32 addr) override {
1.1 root 173: if ((addr & 1) == 0) {
1.1.1.9 ! root 174: return T::PeekPort(Decoder(addr)) >> 8;
1.1 root 175: } else {
1.1.1.9 ! root 176: return T::PeekPort(Decoder(addr)) & 0xff;
1.1 root 177: }
178: }
179: };
180:
1.1.1.9 ! root 181: // ロングワードデバイスをロングワードのまま m68k バスに配置する。
1.1 root 182: template <class T>
1.1.1.9 ! root 183: class BusIO_L : public T
1.1 root 184: {
185: private:
1.1.1.9 ! root 186: inline uint32 Decoder(busaddr addr) const {
! 187: return Decoder(addr.Addr());
! 188: }
! 189: inline uint32 Decoder(uint32 addr) const {
! 190: return (addr >> 2) & (T::NPORT - 1);
1.1 root 191: }
192:
193: public:
1.1.1.9 ! root 194: BusIO_L<T>()
! 195: : T()
! 196: {
1.1 root 197: }
1.1.1.9 ! root 198: BusIO_L<T>(uint arg1)
! 199: : T(arg1)
! 200: {
! 201: }
! 202: BusIO_L<T>(uint arg1, uint arg2)
! 203: : T(arg1, arg2)
! 204: {
1.1 root 205: }
206:
1.1.1.9 ! root 207: busdata Read(busaddr addr) override {
! 208: return T::ReadPort(Decoder(addr));
1.1 root 209: }
1.1.1.9 ! root 210:
! 211: busdata Write(busaddr addr, uint32 data) override {
! 212: data = BusIO::DataMultiplexer_Write_L(addr, data);
! 213: return T::WritePort(Decoder(addr), data);
1.1 root 214: }
215:
1.1.1.9 ! root 216: busdata Peek1(uint32 addr) override {
! 217: busdata data = T::PeekPort(Decoder(addr));
! 218: if (data.IsBusErr()) {
! 219: return data;
1.1 root 220: }
1.1.1.9 ! root 221: data >>= (3 - (addr & 3U)) * 8;
! 222: data &= 0xff;
! 223: return data;
1.1 root 224: }
225: };
226:
1.1.1.9 ! root 227: // バイトデバイスを偶数アドレスに配置し、奇数アドレスはバスエラー。
! 228: //class BusIO_BE
! 229:
1.1 root 230: // バイトデバイスを奇数アドレスに配置し、偶数アドレスはバスエラー。
231: template <class T>
1.1.1.4 root 232: class BusIO_EB : public T
1.1 root 233: {
234: private:
1.1.1.9 ! root 235: inline uint32 Decoder(busaddr addr) const {
! 236: return Decoder(addr.Addr());
! 237: }
! 238: inline uint32 Decoder(uint32 addr) const {
1.1 root 239: return (addr >> 1) & (T::NPORT - 1);
240: }
241:
242: public:
1.1.1.9 ! root 243: busdata Read(busaddr addr) override {
! 244: if (addr.GetSize() == 1 && (addr.Addr() & 1) == 0) {
! 245: return BusData::BusErr;
! 246: }
! 247: busdata bd = T::ReadPort(Decoder(addr));
! 248: bd |= 0xff00;
! 249: bd.ChangeSize(2);
! 250: return bd;
! 251: }
! 252:
! 253: busdata Write(busaddr addr, uint32 data) override {
! 254: busdata r;
! 255: uint32 reqsize = addr.GetSize();
! 256: uint32 offset = addr.Addr() & 1;
! 257:
! 258: uint32 op0 = (data >> 24) & 0xff;
! 259: uint32 op1 = (data >> 16) & 0xff;
! 260: uint32 op2 = (data >> 8) & 0xff;
! 261: uint32 op3 = data & 0xff;
! 262: if (reqsize == 1) {
! 263: if (offset == 0) {
! 264: return BusData::BusErr;
! 265: } else {
! 266: data = op3;
! 267: }
! 268: } else if (reqsize == 2) {
! 269: if (offset == 0) {
! 270: data = op3;
! 271: } else {
! 272: data = op2;
! 273: }
! 274: } else if (reqsize == 3) {
! 275: if (offset == 0) {
! 276: data = op2;
! 277: } else {
! 278: data = op1;
! 279: }
1.1 root 280: } else {
1.1.1.9 ! root 281: if (offset == 0) {
! 282: data = op1;
! 283: } else {
! 284: data = op0;
! 285: }
1.1 root 286: }
1.1.1.9 ! root 287: r = T::WritePort(Decoder(addr), data);
! 288: r.ChangeSize(2);
! 289: return r;
1.1 root 290: }
291:
1.1.1.9 ! root 292: busdata Peek1(uint32 addr) override {
1.1 root 293: if ((addr & 1) == 0) {
1.1.1.9 ! root 294: return BusData::BusErr;
1.1 root 295: } else {
1.1.1.9 ! root 296: return T::PeekPort(Decoder(addr));
1.1 root 297: }
298: }
299: };
300:
1.1.1.2 root 301: // バイトデバイスを奇数アドレスに配置し、偶数アドレスは非接続。
302: template <class T>
1.1.1.4 root 303: class BusIO_FB : public T
1.1.1.2 root 304: {
305: private:
1.1.1.9 ! root 306: inline uint32 Decoder(busaddr addr) const {
! 307: return Decoder(addr.Addr());
! 308: }
! 309: inline uint32 Decoder(uint32 addr) const {
1.1.1.2 root 310: return (addr >> 1) & (T::NPORT - 1);
311: }
312:
313: public:
1.1.1.9 ! root 314: busdata Read(busaddr addr) override {
! 315: busdata bd;
! 316: if (addr.GetSize() == 1 && (addr.Addr() & 1) == 0) {
! 317: bd = 0xff;
! 318: } else {
! 319: bd = T::ReadPort(Decoder(addr));
! 320: }
! 321: bd |= 0xff00;
! 322: bd.ChangeSize(2);
! 323: return bd;
! 324: }
! 325:
! 326: busdata Write(busaddr addr, uint32 data) override {
! 327: busdata r;
! 328: uint32 reqsize = addr.GetSize();
! 329: uint32 offset = addr.Addr() & 1;
! 330:
! 331: uint32 op0 = (data >> 24) & 0xff;
! 332: uint32 op1 = (data >> 16) & 0xff;
! 333: uint32 op2 = (data >> 8) & 0xff;
! 334: uint32 op3 = data & 0xff;
! 335: if (reqsize == 1) {
! 336: if (offset == 0) {
! 337: r.ChangeSize(2);
! 338: return r;
! 339: } else {
! 340: data = op3;
! 341: }
! 342: } else if (reqsize == 2) {
! 343: if (offset == 0) {
! 344: data = op3;
! 345: } else {
! 346: data = op2;
! 347: }
! 348: } else if (reqsize == 3) {
! 349: if (offset == 0) {
! 350: data = op2;
! 351: } else {
! 352: data = op1;
! 353: }
1.1.1.2 root 354: } else {
1.1.1.9 ! root 355: if (offset == 0) {
! 356: data = op1;
! 357: } else {
! 358: data = op0;
! 359: }
1.1.1.2 root 360: }
1.1.1.9 ! root 361: r = T::WritePort(Decoder(addr), data);
! 362: r.ChangeSize(2);
! 363: return r;
1.1.1.2 root 364: }
365:
1.1.1.9 ! root 366: busdata Peek1(uint32 addr) override {
1.1.1.2 root 367: if ((addr & 1) == 0) {
368: return 0xff;
369: } else {
1.1.1.9 ! root 370: return T::PeekPort(Decoder(addr));
1.1.1.2 root 371: }
372: }
373: };
374:
1.1 root 375: // バイトデバイスをロングワードの先頭に配置し、他は非接続。
376: template <class T>
1.1.1.4 root 377: class BusIO_BFFF : public T
1.1 root 378: {
1.1.1.9 ! root 379: private:
! 380: inline uint32 Decoder(busaddr addr) const {
! 381: return Decoder(addr.Addr());
! 382: }
! 383: inline uint32 Decoder(uint32 addr) const {
1.1 root 384: return (addr >> 2) & (T::NPORT - 1);
385: }
386:
387: public:
1.1.1.9 ! root 388: busdata Read(busaddr addr) override {
! 389: busdata bd = T::ReadPort(Decoder(addr));
! 390: bd <<= 24;
! 391: bd |= 0x00ffffff;
! 392: bd.ChangeSize(4);
! 393: return bd;
! 394: }
! 395:
! 396: busdata Write(busaddr addr, uint32 data) override {
! 397: data >>= (addr.GetSize() - 1) * 8;
! 398: busdata r = T::WritePort(Decoder(addr), data);
! 399: r.ChangeSize(4);
! 400: return r;
1.1 root 401: }
402:
1.1.1.9 ! root 403: busdata Peek1(uint32 addr) override {
1.1 root 404: if ((addr & 3) == 0) {
1.1.1.9 ! root 405: return T::PeekPort(Decoder(addr));
1.1 root 406: } else {
407: return 0xff;
408: }
409: }
1.1.1.7 root 410:
1.1.1.9 ! root 411: bool Poke1(uint32 addr, uint32 data) override {
1.1.1.7 root 412: if ((addr & 3) == 0) {
1.1.1.9 ! root 413: return T::PokePort(Decoder(addr), data);
1.1.1.7 root 414: } else {
415: // 非接続なので、書き換えようとしてもエラーも起きず何も起きない。
1.1.1.8 root 416: return true;
1.1 root 417: }
418: }
419: };
420:
421: // ワードデバイスをロングワード先頭に配置し、他は非接続。
422: template <class T>
1.1.1.4 root 423: class BusIO_WF : public T
1.1 root 424: {
425: private:
1.1.1.9 ! root 426: inline uint32 Decoder(busaddr addr) const {
! 427: return Decoder(addr.Addr());
! 428: }
! 429: inline uint32 Decoder(uint32 addr) const {
1.1 root 430: return (addr >> 2) & (T::NPORT - 1);
431: }
432: public:
1.1.1.9 ! root 433: busdata Read(busaddr addr) override {
! 434: busdata bd = T::ReadPort(Decoder(addr));
! 435: bd <<= 16;
! 436: bd |= 0xffff;
! 437: bd.ChangeSize(4);
! 438: return bd;
1.1 root 439: }
440:
1.1.1.9 ! root 441: busdata Write(busaddr addr, uint32 data) override {
! 442: if (addr.GetSize() == 4) {
! 443: data >>= 16;
! 444: } else if (addr.GetSize() == 2) {
! 445: // ワード書き込みならデータバスは MSB LSB MSB LSB。(88200 p5-27)
1.1 root 446: } else {
1.1.1.9 ! root 447: // バイト書き込みなら全バイトがコピー。
! 448: data |= data << 8;
1.1 root 449: }
1.1.1.9 ! root 450: busdata r = T::WritePort(Decoder(addr), data);
! 451: r.ChangeSize(4);
! 452: return r;
1.1 root 453: }
1.1.1.9 ! root 454:
! 455: busdata Peek1(uint32 addr) override {
1.1 root 456: switch (addr & 3) {
457: case 0:
1.1.1.9 ! root 458: return T::PeekPort(Decoder(addr)) >> 8;
1.1 root 459: case 1:
1.1.1.9 ! root 460: return T::PeekPort(Decoder(addr)) & 0xff;
1.1 root 461: case 2:
462: case 3:
463: return 0xff;
464: }
465: __unreachable();
466: }
467: };
468:
469: // X680x0 の SPC を収容するための専用バスアダプタ。
470: // ここは SASI 跡地 32バイト分と SCSI 用地 32バイト分を合わせた 64 バイト
471: // (0x40 バイト) でのミラーになっているため、BusIO_EB では表現できない。
472: // SASI 跡地は実際には読み出しパターンがあるようだが、本題ではないので
473: // とりあえず全部 0xff を返しておく。
474: template <class T>
475: class BusIO_X68kSPC : public T
476: {
477: private:
1.1.1.9 ! root 478: inline uint32 Decoder(busaddr addr) const {
! 479: return Decoder(addr.Addr());
! 480: }
! 481: inline uint32 Decoder(uint32 addr) const {
1.1 root 482: // SASI 跡地と SCSI を合わせて 0x40 バイトでミラーしている
483: return (addr >> 1) & (0x20 - 1);
484: }
485:
486: public:
1.1.1.9 ! root 487: busdata Read(busaddr addr) override {
! 488: if (addr.GetSize() == 1 && (addr.Addr() & 1) == 0) {
! 489: return BusData::BusErr;
! 490: }
! 491: uint32 offset = Decoder(addr);
! 492: busdata bd;
! 493: if (offset < 0x10) {
! 494: // 前半16ポートは SASI 跡地。
! 495: bd = 0xff;
1.1 root 496: } else {
1.1.1.9 ! root 497: // 後半16ポートは SCSI。
! 498: bd = T::ReadPort(offset - 0x10);
! 499: }
! 500: bd |= 0xff00;
! 501: bd.ChangeSize(2);
! 502: return bd;
! 503: }
! 504:
! 505: busdata Write(busaddr addr, uint32 data) override {
! 506: busdata r;
! 507: uint32 reqsize = addr.GetSize();
! 508: uint32 offset = addr.Addr() & 1;
! 509:
! 510: uint32 op0 = (data >> 24) & 0xff;
! 511: uint32 op1 = (data >> 16) & 0xff;
! 512: uint32 op2 = (data >> 8) & 0xff;
! 513: uint32 op3 = data & 0xff;
! 514: if (reqsize == 1) {
! 515: if (offset == 0) {
! 516: return BusData::BusErr;
1.1 root 517: } else {
1.1.1.9 ! root 518: data = op3;
! 519: }
! 520: } else if (reqsize == 2) {
! 521: if (offset == 0) {
! 522: data = op3;
! 523: } else {
! 524: data = op2;
! 525: }
! 526: } else if (reqsize == 3) {
! 527: if (offset == 0) {
! 528: data = op2;
! 529: } else {
! 530: data = op1;
1.1 root 531: }
532: } else {
1.1.1.9 ! root 533: if (offset == 0) {
! 534: data = op1;
1.1 root 535: } else {
1.1.1.9 ! root 536: data = op0;
1.1 root 537: }
538: }
1.1.1.9 ! root 539: uint32 pa = Decoder(addr);
! 540: if (pa < 0x10) {
1.1 root 541: // 前半16ポートは SASI 跡地。
542: // XXX 書き込みはどうなる?
543: } else {
1.1.1.9 ! root 544: r = T::WritePort(pa - 0x10, data);
1.1 root 545: }
1.1.1.9 ! root 546: r.ChangeSize(2);
! 547: return r;
1.1 root 548: }
549:
1.1.1.9 ! root 550: busdata Peek1(uint32 addr) override {
1.1 root 551: if ((addr & 1) == 0) {
1.1.1.9 ! root 552: return BusData::BusErr;
1.1 root 553: } else {
554: addr = Decoder(addr);
555: if (addr < 0x10) {
556: // 前半16ポートは SASI 跡地。
557: return 0xff;
558: } else {
559: // 後半16ポートは SCSI。
1.1.1.9 ! root 560: return T::PeekPort(addr - 0x10);
1.1 root 561: }
562: }
563: }
564: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.