Annotation of nono/vm/busio.h, revision 1.1.1.10

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.