|
|
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.10! root 198: explicit BusIO_L<T>(uint arg1)
1.1.1.9 root 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.