|
|
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.3 root 10: #pragma once
11:
1.1 root 12: #if !defined(SELFTEST)
13: #include "device.h"
14: #endif
15:
16: // バイトデバイスをバイト、ワード、ロングワードポートにミラー配置する共通部
17: template <class T, int rshift>
1.1.1.4 root 18: class BusIO_B_Base : public T
1.1 root 19: {
1.1.1.7 root 20: protected:
1.1 root 21: inline uint32 Decoder(uint32 addr) {
22: return (addr >> rshift) & (T::NPORT - 1);
23: }
24:
25: public:
1.1.1.8 ! root 26: busdata Read8(uint32 addr) override {
1.1 root 27: return T::Read(Decoder(addr));
28: }
29:
1.1.1.8 ! root 30: busdata Write8(uint32 addr, uint32 data) override {
1.1 root 31: return T::Write(Decoder(addr), data);
32: }
33:
1.1.1.8 ! root 34: busdata Peek8(uint32 addr) override {
1.1 root 35: return T::Peek(Decoder(addr));
36: }
1.1.1.7 root 37:
1.1.1.8 ! root 38: bool Poke8(uint32 addr, uint32 data) override {
1.1.1.7 root 39: return T::Poke(Decoder(addr), data);
40: }
1.1 root 41: };
42:
43: // バイトデバイスをバイトのまま配置する。
44: // NPORT によるミラーを行う以外はこれを使わないのと何も変わらない。
45: template <class T>
1.1.1.4 root 46: class BusIO_B : public BusIO_B_Base<T, 0> { };
1.1 root 47: // バイトデバイスをワードにミラー配置する。
48: template <class T>
1.1.1.4 root 49: class BusIO_BB : public BusIO_B_Base<T, 1> { };
1.1 root 50: // バイトデバイスをロングワードにミラー配置する。
51: template <class T>
1.1.1.4 root 52: class BusIO_BBBB : public BusIO_B_Base<T, 2> { };
1.1 root 53:
54: // ワードデバイスをワードのまま配置する。
55: // NPORT によるミラーを行う以外はこれを使わないのと何も変わらない。
56: template <class T>
1.1.1.4 root 57: class BusIO_W : public T
1.1 root 58: {
59: private:
60: inline uint32 Decoder(uint32 addr) {
61: return (addr >> 1) & (T::NPORT - 1);
62: }
63:
64: public:
1.1.1.8 ! root 65: // ワードポートからのバイト読み込みはワードで読んだ後必要な方を取る。
! 66: busdata Read8(uint32 addr) override {
1.1 root 67: if ((addr & 1) == 0) {
1.1.1.8 ! root 68: busdata data = T::Read(Decoder(addr));
! 69: data >>= 8;
! 70: return data;
1.1 root 71: } else {
1.1.1.8 ! root 72: busdata data = T::Read(Decoder(addr));
! 73: data &= 0xff;
! 74: return data;
1.1 root 75: }
76: }
1.1.1.8 ! root 77: busdata Read16(uint32 addr) override {
1.1 root 78: return T::Read(Decoder(addr));
79: }
80:
1.1.1.8 ! root 81: // ワードポートにバイト書き込みするとデータバスは OP3 OP3 OP3 OP3。
! 82: busdata Write8(uint32 addr, uint32 data) override {
! 83: data |= data << 8;
! 84: return T::Write(Decoder(addr), data);
1.1 root 85: }
1.1.1.8 ! root 86: busdata Write16(uint32 addr, uint32 data) override {
1.1 root 87: return T::Write(Decoder(addr), data);
88: }
89:
1.1.1.8 ! root 90: busdata Peek8(uint32 addr) override {
1.1 root 91: if ((addr & 1) == 0) {
92: return T::Peek(Decoder(addr)) >> 8;
93: } else {
94: return T::Peek(Decoder(addr)) & 0xff;
95: }
96: }
97: };
98:
99: /* XXX: stub
1.1.1.4 root 100: class BusIO_L : public T
1.1 root 101: */
102:
103: // バイトデバイスを偶数アドレスに配置し、奇数アドレスはバスエラー。
104: template <class T>
1.1.1.4 root 105: class BusIO_BE : public T
1.1 root 106: {
107: private:
108: inline uint32 Decoder(uint32 addr) {
109: return (addr >> 1) & (T::NPORT - 1);
110: }
111:
112: public:
1.1.1.8 ! root 113: busdata Read8(uint32 addr) override {
1.1 root 114: if ((addr & 1) == 0) {
115: return T::Read(Decoder(addr));
116: } else {
1.1.1.8 ! root 117: return busdata::BusErr;
1.1 root 118: }
119: }
1.1.1.8 ! root 120: busdata Read16(uint32 addr) override {
! 121: busdata data = T::Read(Decoder(addr));
! 122: data <<= 8;
! 123: data |= 0xff;
! 124: return data;
1.1 root 125: }
126:
1.1.1.8 ! root 127: busdata Write8(uint32 addr, uint32 data) override {
1.1 root 128: if ((addr & 1) == 0) {
129: return T::Write(Decoder(addr), data);
130: } else {
1.1.1.8 ! root 131: return busdata::BusErr;
1.1 root 132: }
133: }
1.1.1.8 ! root 134: busdata Write16(uint32 addr, uint32 data) override {
1.1 root 135: return T::Write(Decoder(addr), data >> 8);
136: }
137:
1.1.1.8 ! root 138: busdata Peek8(uint32 addr) override {
1.1 root 139: if ((addr & 1) == 0) {
140: return T::Peek(Decoder(addr));
141: } else {
1.1.1.8 ! root 142: return busdata::BusErr;
1.1 root 143: }
144: }
145: };
146:
147: // バイトデバイスを奇数アドレスに配置し、偶数アドレスはバスエラー。
148: template <class T>
1.1.1.4 root 149: class BusIO_EB : public T
1.1 root 150: {
151: private:
152: inline uint32 Decoder(uint32 addr) {
153: return (addr >> 1) & (T::NPORT - 1);
154: }
155:
156: public:
1.1.1.8 ! root 157: busdata Read8(uint32 addr) override {
1.1 root 158: if ((addr & 1) == 0) {
1.1.1.8 ! root 159: return busdata::BusErr;
1.1 root 160: } else {
161: return T::Read(Decoder(addr));
162: }
163: }
1.1.1.8 ! root 164: busdata Read16(uint32 addr) override {
! 165: busdata data = T::Read(Decoder(addr));
! 166: data |= 0xff00;
! 167: return data;
1.1 root 168: }
169:
1.1.1.8 ! root 170: busdata Write8(uint32 addr, uint32 data) override {
1.1 root 171: if ((addr & 1) == 0) {
1.1.1.8 ! root 172: return busdata::BusErr;
1.1 root 173: } else {
174: return T::Write(Decoder(addr), data);
175: }
176: }
1.1.1.8 ! root 177: busdata Write16(uint32 addr, uint32 data) override {
1.1 root 178: return T::Write(Decoder(addr), data & 0xff);
179: }
180:
1.1.1.8 ! root 181: busdata Peek8(uint32 addr) override {
1.1 root 182: if ((addr & 1) == 0) {
1.1.1.8 ! root 183: return busdata::BusErr;
1.1 root 184: } else {
185: return T::Peek(Decoder(addr));
186: }
187: }
188: };
189:
1.1.1.2 root 190: // バイトデバイスを奇数アドレスに配置し、偶数アドレスは非接続。
191: template <class T>
1.1.1.4 root 192: class BusIO_FB : public T
1.1.1.2 root 193: {
194: private:
195: inline uint32 Decoder(uint32 addr) {
196: return (addr >> 1) & (T::NPORT - 1);
197: }
198:
199: public:
1.1.1.8 ! root 200: busdata Read8(uint32 addr) override {
1.1.1.2 root 201: if ((addr & 1) == 0) {
202: return 0xff;
203: } else {
204: return T::Read(Decoder(addr));
205: }
206: }
1.1.1.8 ! root 207: busdata Read16(uint32 addr) override {
! 208: busdata data = T::Read(Decoder(addr));
! 209: data |= 0xff00;
! 210: return data;
1.1.1.2 root 211: }
212:
1.1.1.8 ! root 213: busdata Write8(uint32 addr, uint32 data) override {
1.1.1.2 root 214: if ((addr & 1) == 0) {
215: return 0;
216: } else {
217: return T::Write(Decoder(addr), data);
218: }
219: }
1.1.1.8 ! root 220: busdata Write16(uint32 addr, uint32 data) override {
1.1.1.2 root 221: return T::Write(Decoder(addr), data & 0xff);
222: }
223:
1.1.1.8 ! root 224: busdata Peek8(uint32 addr) override {
1.1.1.2 root 225: if ((addr & 1) == 0) {
226: return 0xff;
227: } else {
228: return T::Peek(Decoder(addr));
229: }
230: }
231: };
232:
1.1 root 233: // バイトデバイスをロングワードの先頭に配置し、他は非接続。
234: template <class T>
1.1.1.4 root 235: class BusIO_BFFF : public T
1.1 root 236: {
1.1.1.7 root 237: protected:
1.1 root 238: inline uint32 Decoder(uint32 addr) {
239: return (addr >> 2) & (T::NPORT - 1);
240: }
241:
242: public:
1.1.1.8 ! root 243: busdata Read8(uint32 addr) override {
1.1 root 244: if ((addr & 3) == 0) {
245: return T::Read(Decoder(addr));
246: } else {
247: return 0xff;
248: }
249: }
1.1.1.8 ! root 250: busdata Read16(uint32 addr) override {
1.1 root 251: if ((addr & 2) == 0) {
1.1.1.8 ! root 252: busdata data = T::Read(Decoder(addr));
! 253: data <<= 8;
! 254: data |= 0xff;
! 255: return data;
1.1 root 256: } else {
257: return 0xffff;
258: }
259: }
1.1.1.8 ! root 260: busdata Read32(uint32 addr) override {
! 261: busdata data = T::Read(Decoder(addr));
! 262: data <<= 24;
! 263: data |= 0x00ffffff;
! 264: return data;
1.1 root 265: }
266:
1.1.1.8 ! root 267: busdata Write8(uint32 addr, uint32 data) override {
1.1 root 268: if ((addr & 3) == 0) {
269: return T::Write(Decoder(addr), data);
270: } else {
271: return 0;
272: }
273: }
1.1.1.8 ! root 274: busdata Write16(uint32 addr, uint32 data) override {
1.1 root 275: if ((addr & 2) == 0) {
276: return T::Write(Decoder(addr), data >> 8);
277: } else {
278: return 0;
279: }
280: }
1.1.1.8 ! root 281: busdata Write32(uint32 addr, uint32 data) override {
1.1 root 282: return T::Write(Decoder(addr), data >> 24);
283: }
284:
1.1.1.8 ! root 285: busdata Peek8(uint32 addr) override {
1.1 root 286: if ((addr & 3) == 0) {
287: return T::Peek(Decoder(addr));
288: } else {
289: return 0xff;
290: }
291: }
1.1.1.7 root 292:
1.1.1.8 ! root 293: bool Poke8(uint32 addr, uint32 data) override {
1.1.1.7 root 294: if ((addr & 3) == 0) {
295: return T::Poke(Decoder(addr), data);
296: } else {
297: // 非接続なので、書き換えようとしてもエラーも起きず何も起きない。
1.1.1.8 ! root 298: return true;
1.1 root 299: }
300: }
301: };
302:
303: // ワードデバイスをロングワード先頭に配置し、他は非接続。
304: template <class T>
1.1.1.4 root 305: class BusIO_WF : public T
1.1 root 306: {
307: private:
308: inline uint32 Decoder(uint32 addr) {
309: return (addr >> 2) & (T::NPORT - 1);
310: }
311: public:
1.1.1.8 ! root 312: busdata Read8(uint32 addr) override {
! 313: busdata data;
1.1 root 314: switch (addr & 3) {
315: case 0:
1.1.1.8 ! root 316: data = T::Read(Decoder(addr));
! 317: data >>= 8;
! 318: return data;
1.1 root 319: case 1:
1.1.1.8 ! root 320: data = T::Read(Decoder(addr));
! 321: data &= 0xff;
! 322: return data;
1.1 root 323: case 2:
324: case 3:
325: return 0xff;
326: }
327: __unreachable();
328: }
1.1.1.8 ! root 329: busdata Read16(uint32 addr) override {
1.1 root 330: if ((addr & 2) == 0) {
331: return T::Read(Decoder(addr));
332: } else {
333: return 0xffff;
334: }
335: }
336:
1.1.1.8 ! root 337: // バイト書き込みならデータバスは OP3 OP3 OP3 OP3。
! 338: busdata Write8(uint32 addr, uint32 data) override {
! 339: if ((addr & 2) == 0) {
! 340: data |= data << 8;
! 341: return T::Write(Decoder(addr), data);
! 342: } else {
! 343: return 0;
! 344: }
1.1 root 345: }
1.1.1.8 ! root 346: busdata Write16(uint32 addr, uint32 data) override {
1.1 root 347: if ((addr & 2) == 0) {
348: return T::Write(Decoder(addr), data);
349: } else {
350: return 0;
351: }
352: }
1.1.1.8 ! root 353: busdata Peek8(uint32 addr) override {
1.1 root 354: switch (addr & 3) {
355: case 0:
356: return T::Peek(Decoder(addr)) >> 8;
357: case 1:
358: return T::Peek(Decoder(addr)) & 0xff;
359: case 2:
360: case 3:
361: return 0xff;
362: }
363: __unreachable();
364: }
365: };
366:
367: // X680x0 の SPC を収容するための専用バスアダプタ。
368: // ここは SASI 跡地 32バイト分と SCSI 用地 32バイト分を合わせた 64 バイト
369: // (0x40 バイト) でのミラーになっているため、BusIO_EB では表現できない。
370: // SASI 跡地は実際には読み出しパターンがあるようだが、本題ではないので
371: // とりあえず全部 0xff を返しておく。
372: template <class T>
373: class BusIO_X68kSPC : public T
374: {
375: private:
1.1.1.8 ! root 376: inline uint32 Decoder(uint32 addr) {
1.1 root 377: // SASI 跡地と SCSI を合わせて 0x40 バイトでミラーしている
378: return (addr >> 1) & (0x20 - 1);
379: }
380:
381: public:
1.1.1.8 ! root 382: busdata Read8(uint32 addr) override {
1.1 root 383: if ((addr & 1) == 0) {
1.1.1.8 ! root 384: return busdata::BusErr;
1.1 root 385: } else {
386: addr = Decoder(addr);
387: if (addr < 0x10) {
388: // 前半16ポートは SASI 跡地。
389: return 0xff;
390: } else {
391: // 後半16ポートは SCSI。
392: return T::Read(addr - 0x10);
393: }
394: }
395: }
1.1.1.8 ! root 396: busdata Read16(uint32 addr) override {
1.1 root 397: addr = Decoder(addr);
398: if (addr < 0x10) {
399: // 前半16ポートは SASI 跡地
400: return 0xffff;
401: } else {
1.1.1.8 ! root 402: busdata data = T::Read(addr - 0x10);
! 403: data |= 0xff00;
! 404: return data;
1.1 root 405: }
406: }
407:
1.1.1.8 ! root 408: busdata Write8(uint32 addr, uint32 data) override {
1.1 root 409: if ((addr & 1) == 0) {
1.1.1.8 ! root 410: return busdata::BusErr;
1.1 root 411: } else {
412: addr = Decoder(addr);
413: if (addr < 0x10) {
414: // 前半16ポートは SASI 跡地。
415: // XXX 書き込みはどうなる?
416: return 0;
417: } else {
418: // 後半16ポートは SCSI。
419: return T::Write(addr - 0x10, data);
420: }
421: }
422: }
1.1.1.8 ! root 423: busdata Write16(uint32 addr, uint32 data) override {
1.1 root 424: addr = Decoder(addr);
425: if (addr < 0x10) {
426: // 前半16ポートは SASI 跡地。
427: // XXX 書き込みはどうなる?
428: return 0;
429: } else {
430: // 後半16ポートは SCSI。
431: return T::Write(addr - 0x10, data & 0xff);
432: }
433: }
434:
1.1.1.8 ! root 435: busdata Peek8(uint32 addr) override {
1.1 root 436: if ((addr & 1) == 0) {
1.1.1.8 ! root 437: return busdata::BusErr;
1.1 root 438: } else {
439: addr = Decoder(addr);
440: if (addr < 0x10) {
441: // 前半16ポートは SASI 跡地。
442: return 0xff;
443: } else {
444: // 後半16ポートは SCSI。
445: return T::Peek(addr - 0x10);
446: }
447: }
448: }
449: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.