Annotation of nono/vm/mainbus.cpp, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
1.1.1.3   root        8: // メインバス (共通部分)
1.1       root        9: //
                     10: 
1.1.1.3   root       11: // メインバス付近に必要な機能は次のようになっている。
                     12: //
                     13: //                             Luna    News    X68k    X68kIO  XPbus
                     14: // InitMainbus o               o               o               o               x
                     15: // FC access   o               o               o               o               x
                     16: // SwitchBoot  o               o               o               o               x
                     17: // ResetByMPU  o               o               o               *1              x       (*1:どっちでもいい)
                     18: //
                     19: // Access Map  o               o               o               x               x
1.1.1.6   root       20: // HV access   o               o               o               x               ?
1.1.1.4   root       21: // Peek4               o               o               o               x               x
1.1.1.3   root       22: // Singleton   o               o               o               x               x
                     23: //
                     24: // もともと FC 付きアクセス機能を Mainbus からX68kIO に伸ばすために
                     25: // MainbusDevice を導入したが、一方モニタの登録などでは Mainbus は
                     26: // システムに複数存在してはならないため、これらは同時に成立しない。
                     27: // そのため、表の上半分の機能を MainbusBaseDevice として独立させ、
                     28: // X68kIO はここから派生。表の下半分の機能を MainbusDevice とする。
                     29: //
                     30: // XPbus はどちらも不要なので (XP プロセッサから見ればメインバスだが、
                     31: // ここの Mainbus はそういう意味ではないので) ただの IODevice。
                     32: 
                     33: // IODevice
                     34: //   |
                     35: //   |  +-------------------+
                     36: //   +--| MainbusBaseDevice | (InitMainbus() と FC アクセスを持つ)
                     37: //   |  +-------------------+
                     38: //   |    |
                     39: //   |    |  +---------------+
                     40: //   |    +--| MainbusDevice | (これがメインバス、システムに1つ)
                     41: //   |    |  +---------------+
                     42: //   |    |    |
                     43: //   |    |    |  +-----------------+
                     44: //   |    |    +--| Mainbus24Device | (上位8ビットがテーブルで表せるメインバス)
                     45: //   |    |    |  +-----------------+
                     46: //   |    |    |    |
                     47: //   |    |    |    +-- LunaMainbus
                     48: //   |    |    |    |    +-- Luna1Mainbus
                     49: //   |    |    |    |    +-- Luna88kMainbus
                     50: //   |    |    |    +-- NewsMainbus
                     51: //   |    |    |    +-- Virt68kMainbus
                     52: //   |    |    +-- X68kMainbus (上位8ビットが IODevice で表せないため)
                     53: //   |    |
                     54: //   |    +-- X68kIODevice
                     55: //   |
                     56: //   +-- XPbusDevice (これはただの IODevice)
                     57: 
1.1       root       58: #include "mainbus.h"
1.1.1.5   root       59: #include "monitor.h"
1.1.1.3   root       60: 
                     61: //
                     62: // メインバスの素質を持つ基本クラス
                     63: //
1.1       root       64: 
                     65: // コンストラクタ
1.1.1.4   root       66: MainbusBaseDevice::MainbusBaseDevice(uint objid_)
1.1.1.3   root       67:        : inherited(objid_)
1.1       root       68: {
                     69: }
                     70: 
                     71: // デストラクタ
1.1.1.3   root       72: MainbusBaseDevice::~MainbusBaseDevice()
1.1       root       73: {
                     74: }
                     75: 
1.1.1.3   root       76: // MPU の RESET 命令によるリセット
                     77: void
                     78: MainbusBaseDevice::ResetByMPU()
1.1       root       79: {
1.1.1.3   root       80: }
1.1       root       81: 
1.1.1.3   root       82: // ブートページを切り替える際の共通処理。
                     83: // 派生クラスから呼ぶこと。
                     84: void
                     85: MainbusBaseDevice::SwitchBootPage(bool isrom)
                     86: {
                     87:        // ログ表示
                     88:        if (isrom) {
                     89:                putlog(1, "SwitchBootPage ROM (Boot)");
1.1       root       90:        } else {
1.1.1.3   root       91:                putlog(1, "SwitchBootPage RAM (Normal)");
1.1       root       92:        }
                     93: }
                     94: 
1.1.1.3   root       95: // モニタ表示用にデバイス名を整形。
                     96: // 7文字に切り詰めるのと、括弧があれば取り除いて Disable 色にする。
                     97: /*static*/ std::pair<std::string, TA>
                     98: MainbusBaseDevice::FormatDevName(const Device *dev)
1.1       root       99: {
1.1.1.3   root      100:        std::string name = dev->GetName();
                    101:        TA attr;
                    102: 
                    103:        if (name[0] == '(') {
                    104:                // 括弧付きなら、括弧を取り除いて Disable 色で表示
                    105:                int len = std::min(7, (int)name.size() - 2);
                    106:                name = name.substr(1, len);
                    107:                attr = TA::Disable;
1.1       root      108:        } else {
1.1.1.3   root      109:                name = name.substr(0, 7);
                    110:                attr = TA::Normal;
1.1       root      111:        }
1.1.1.3   root      112: 
                    113:        return std::make_pair(name, attr);
1.1       root      114: }
                    115: 
1.1.1.3   root      116: 
                    117: //
                    118: // メインバス (基本クラス)
                    119: //
                    120: 
                    121: // コンストラクタ
1.1.1.4   root      122: MainbusDevice::MainbusDevice(uint objid_)
1.1.1.3   root      123:        : inherited(objid_)
1.1       root      124: {
1.1.1.5   root      125:        accstat_monitor = gMonitorManager->Regist(ID_MONITOR_ACCSTAT, this);
1.1.1.8 ! root      126:        accstat_monitor->SetCallback(&MainbusDevice::MonitorScreenAccStat);
1.1.1.4   root      127:        // 表示行数が機種ごとに異なるので継承側でセットしている。
                    128: 
                    129:        // 通常は 32bit 空間全体 (そうでない機種はコンストラクタで上書きする)
                    130:        accstat_baseaddr = 0;
                    131:        accstat_bitlen = 32;
1.1.1.3   root      132: }
                    133: 
                    134: // デストラクタ
                    135: MainbusDevice::~MainbusDevice()
                    136: {
                    137: }
1.1       root      138: 
1.1.1.4   root      139: // 初期化
                    140: bool
                    141: MainbusDevice::Init()
                    142: {
                    143:        // アクセス状況の表示用配列。
                    144:        accstat_rw.resize(AccStat::MAINLEN >> (32 - accstat_bitlen));
                    145: 
                    146:        return true;
                    147: }
                    148: 
                    149: // リセット
                    150: void
                    151: MainbusDevice::ResetHard(bool poweron)
                    152: {
                    153:        inherited::ResetHard(poweron);
                    154: 
                    155:        std::fill(accstat_read.begin(), accstat_read.end(), 0);
                    156:        std::fill(accstat_write.begin(), accstat_write.end(), 0);
                    157: }
                    158: 
                    159: // ハイパーバイザ的読み込み (ミスアライン可)。
                    160: // addr はアドレスとサイズを指定すること。
                    161: // バスエラーが起きればその時点で BusData::BusErr を返す。
                    162: busdata
                    163: MainbusDevice::HVReadN(busaddr addr)
                    164: {
                    165:        addr |= BusAddr::SRead;
                    166: 
                    167:        uint32 reqsize = addr.GetSize();
                    168:        busdata data;
                    169:        do {
                    170:                busdata bd = Read(addr);
                    171:                if (__predict_false(bd.IsBusErr())) {
                    172:                        return bd;
                    173:                }
                    174:                data |= DYNAMIC_BUS_SIZING_R(addr, bd);
                    175:        } while (addr.GetSize() != 0);
                    176: 
                    177:        data |= busdata::Size(reqsize);
                    178:        return data;
                    179: }
                    180: 
1.1.1.3   root      181: // ハイパーバイザ的読み込み
                    182: busdata
1.1.1.4   root      183: MainbusDevice::HVRead1(uint32 paddr)
1.1.1.3   root      184: {
1.1.1.4   root      185:        busaddr addr = busaddr(paddr) | BusAddr::Size1;
                    186:        return HVReadN(addr);
1.1.1.3   root      187: }
                    188: 
                    189: // ハイパーバイザ的読み込み (ミスアライン可)
                    190: busdata
1.1.1.4   root      191: MainbusDevice::HVRead2(uint32 paddr)
1.1.1.3   root      192: {
1.1.1.4   root      193:        busaddr addr = busaddr(paddr) | BusAddr::Size2;
                    194:        return HVReadN(addr);
1.1       root      195: }
                    196: 
1.1.1.3   root      197: // ハイパーバイザ的読み込み (ミスアライン可)
                    198: busdata
1.1.1.4   root      199: MainbusDevice::HVRead4(uint32 paddr)
1.1       root      200: {
1.1.1.4   root      201:        busaddr addr = busaddr(paddr) | BusAddr::Size4;
                    202:        return HVReadN(addr);
                    203: }
                    204: 
                    205: // ハイパーバイザ的書き込み (ミスアライン可)。
                    206: // addr はアドレスとサイズを指定すること。属性は SRead 固定。
                    207: // バスエラーが起きればその時点で busdata::BusErr を返す。
                    208: busdata
                    209: MainbusDevice::HVWriteN(busaddr addr, uint32 data)
                    210: {
                    211:        addr |= BusAddr::SWrite;
                    212:        do {
                    213:                busdata r = Write(addr, data);
                    214:                if (__predict_false(r.IsBusErr())) {
                    215:                        return r;
                    216:                }
                    217:                DYNAMIC_BUS_SIZING_W(addr, data, r);
                    218:        } while (addr.GetSize() != 0);
                    219: 
                    220:        return 0;
1.1       root      221: }
                    222: 
1.1.1.3   root      223: // ハイパーバイザ的書き込み
                    224: busdata
1.1.1.4   root      225: MainbusDevice::HVWrite1(uint32 paddr, uint32 data)
1.1       root      226: {
1.1.1.4   root      227:        busaddr addr = busaddr(paddr) | BusAddr::Size1;
                    228:        return HVWriteN(addr, data);
1.1.1.3   root      229: }
1.1       root      230: 
1.1.1.3   root      231: // ハイパーバイザ的書き込み (ミスアライン可)
                    232: busdata
1.1.1.4   root      233: MainbusDevice::HVWrite2(uint32 paddr, uint32 data)
1.1.1.3   root      234: {
1.1.1.4   root      235:        busaddr addr = busaddr(paddr) | BusAddr::Size2;
                    236:        return HVWriteN(addr, data);
1.1.1.3   root      237: }
                    238: 
                    239: // ハイパーバイザ的書き込み (ミスアライン可)
                    240: busdata
1.1.1.4   root      241: MainbusDevice::HVWrite4(uint32 paddr, uint32 data)
1.1.1.3   root      242: {
1.1.1.4   root      243:        busaddr addr = busaddr(paddr) | BusAddr::Size4;
                    244:        return HVWriteN(addr, data);
1.1       root      245: }
                    246: 
1.1.1.8 ! root      247: // 連続する4バイトを Peek する。(ミスアライン可)
1.1       root      248: uint64
1.1.1.4   root      249: MainbusDevice::Peek4(uint32 addr)
1.1       root      250: {
                    251:        uint64 data;
                    252: 
1.1.1.4   root      253:        data  = Peek1(addr++) << 24;
                    254:        data |= Peek1(addr++) << 16;
                    255:        data |= Peek1(addr++) << 8;
                    256:        data |= Peek1(addr);
1.1       root      257:        return data;
                    258: }
                    259: 
1.1.1.4   root      260: void
1.1.1.8 ! root      261: MainbusDevice::MonitorScreenAccStat(Monitor *, TextScreen& screen)
1.1.1.4   root      262: {
                    263:        std::array<char, 64 + 5> buf;
                    264: 
                    265: #define UPDATE_RW(rw_ptr)      do {                    \
                    266:        uint64 dst = *(uint64 *)(rw_ptr);               \
                    267:        dst <<= 2;                                                              \
                    268:        dst &= 0xfcfcfcfc'fcfcfcfc;                             \
                    269:        dst |= src;                                                             \
                    270:        *(uint64 *)(rw_ptr) = dst;                              \
                    271: } while (0)
                    272: 
                    273:        // R|W をマージしながらコピー。
                    274:        if (__predict_true(accstat_rw.size() == AccStat::MAINLEN)) {
                    275:                // 全域。
                    276:                for (int i = 0; i < AccStat::MAINLEN; i += 8) {
                    277:                        uint64 src = *(uint64 *)&accstat_read[i]
                    278:                                           | *(uint64 *)&accstat_write[i];
                    279:                        UPDATE_RW(&accstat_rw[i]);
                    280:                }
                    281:        } else {
                    282:                // NEWS なら表示に使うのは前 1/4 のみで、後ろはミラー。
                    283:                // ただしアドレス表記は $c000'0000 以降(後ろの 1/4)。
                    284:                uint offset = accstat_rw.size();
                    285:                uint ndiv = accstat_read.size() / offset;
                    286:                for (int i = 0, iend = accstat_rw.size(); i < iend; i += 8) {
                    287:                        uint64 src = 0;
                    288:                        for (int j = 0; j < ndiv; j++) {
                    289:                                src |= *(uint64 *)&accstat_read[i + j * offset];
                    290:                                src |= *(uint64 *)&accstat_write[i + j * offset];
                    291:                        }
                    292:                        UPDATE_RW(&accstat_rw[i]);
                    293:                }
                    294:        }
                    295: 
                    296:        // 読んだのでリセット。
                    297:        std::fill(accstat_read.begin(), accstat_read.end(), 0);
                    298:        std::fill(accstat_write.begin(), accstat_write.end(), 0);
                    299: 
                    300:        screen.Clear();
                    301: 
                    302:        static_assert(AccStat::SHIFT >= 20, "");
                    303:        screen.Print(0, 0,
                    304:                "Shows %ubit space. %uMB/char. 'R':Read, 'W':Write, 'A':Read+Write",
                    305:                accstat_bitlen, 1U << (AccStat::SHIFT - 20));
                    306:        screen.Print(12, 1,
                    307:                "+$00    +$01     +$02    +$03     +$04    +$05     +$06    +$07");
                    308: 
                    309:        uint32 baseaddr = accstat_baseaddr;
                    310:        for (int y = 0, yend = accstat_rw.size() / 64; y < yend; y++) {
                    311:                const uint8 *a = &accstat_rw[y * 64];
                    312:                uint8 avail = accstat_avail[y];
                    313:                char *d = &buf[0];
                    314:                std::fill(buf.begin(), buf.end() - 1, ' ');
                    315:                for (int i = 0; i < 8; i++) {
                    316:                        // 先頭に空白を入れといて、参照時は buf+1 から参照する。
                    317:                        if ((i & 1) == 0) {
                    318:                                d++;
                    319:                        }
                    320:                        if ((int8)avail < 0) {
                    321:                                // 何かしらデバイスがある。16MB、8文字分。
                    322:                                for (int j = 0; j < 8; j++) {
                    323:                                        uint op = *a & 3;
                    324:                                        *d++ = ".RWA"[op];
                    325:                                        a++;
                    326:                                }
                    327:                        } else {
                    328:                                // この 16MB には何のデバイスもない。
                    329:                                d += 8;
                    330:                                a += 8;
                    331:                        }
                    332:                        avail <<= 1;
                    333:                }
                    334:                *d = '\0';
                    335:                screen.Print(0, y + 2, "$%02x00'0000: %s",
                    336:                        baseaddr + y * 0x08, &buf[1]);
                    337:        }
                    338: }
                    339: 
1.1.1.3   root      340: 
                    341: //
                    342: // 上位8ビットがテーブルで表せる構造のメインバス。
                    343: //
                    344: 
                    345: // コンストラクタ (オブジェクト名指定なし)
                    346: Mainbus24Device::Mainbus24Device()
                    347:        : MainbusDevice(OBJ_MAINBUS)
                    348: {
1.1.1.5   root      349:        monitor = gMonitorManager->Regist(ID_MONITOR_MAINBUS, this);
1.1.1.8 ! root      350:        monitor->SetCallback(&Mainbus24Device::MonitorScreen);
1.1.1.5   root      351:        monitor->SetSize(75, 33);
1.1.1.3   root      352: }
                    353: 
                    354: Mainbus24Device::~Mainbus24Device()
                    355: {
                    356: }
                    357: 
                    358: // アクセス状況のエリア情報初期化。
                    359: // 継承側の InitMainbus() の終わりで呼ぶこと。
                    360: void
                    361: Mainbus24Device::InitAccStat()
                    362: {
1.1.1.4   root      363:        for (int i = 0; i < accstat_avail.size(); i++) {
1.1.1.3   root      364:                uint bits = 0;
                    365:                for (int j = 0; j < 8; j++) {
                    366:                        int n = i * 8 + j;
                    367:                        int id = devtable[n]->GetId();
                    368:                        bits <<= 1;
                    369:                        if (id != OBJ_BUSERR && id != OBJ_NOPIO) {
                    370:                                bits |= 1;
                    371:                        }
                    372:                }
1.1.1.4   root      373:                accstat_avail[i] = bits;
1.1.1.3   root      374:        }
                    375: 
                    376:        // デバッグ用
                    377:        if (0) {
1.1.1.4   root      378:                for (int i = 0; i < accstat_avail.size(); i++) {
1.1.1.3   root      379:                        printf("%02x: ", i);
1.1.1.4   root      380:                        uint8 a = accstat_avail[i];
1.1.1.3   root      381:                        for (int j = 0; j < 8; j++) {
                    382:                                if ((int8)a < 0) {
                    383:                                        printf("1");
                    384:                                } else {
                    385:                                        printf("0");
                    386:                                }
                    387:                                a <<= 1;
                    388:                        }
                    389:                        printf("\n");
                    390:                }
                    391:        }
                    392: }
                    393: 
                    394: inline IODevice *
                    395: Mainbus24Device::Decoder(uint32 addr) const
1.1       root      396: {
                    397:        return devtable[addr >> 24];
                    398: }
                    399: 
1.1.1.3   root      400: busdata
1.1.1.4   root      401: Mainbus24Device::Read(busaddr addr)
1.1.1.3   root      402: {
1.1.1.4   root      403:        uint32 pa = addr.Addr();
1.1.1.8 ! root      404:        lastaddr = pa;
1.1.1.4   root      405:        accstat_read[pa >> AccStat::SHIFT] = AccStat::READ;
                    406:        IODevice *dev = Decoder(pa);
                    407:        return dev->Read(addr);
1.1.1.3   root      408: }
                    409: 
                    410: busdata
1.1.1.4   root      411: Mainbus24Device::Write(busaddr addr, uint32 data)
1.1       root      412: {
1.1.1.4   root      413:        uint32 pa = addr.Addr();
1.1.1.8 ! root      414:        lastaddr = pa;
1.1.1.4   root      415:        accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE;
                    416:        IODevice *dev = Decoder(pa);
                    417:        return dev->Write(addr, data);
1.1.1.3   root      418: }
                    419: 
                    420: busdata
1.1.1.4   root      421: Mainbus24Device::ReadBurst16(busaddr addr, uint32 *dst)
1.1.1.3   root      422: {
1.1.1.4   root      423:        uint32 pa = addr.Addr();
1.1.1.8 ! root      424:        lastaddr = pa;  // 開始アドレスしか残らない…
1.1.1.4   root      425:        IODevice *dev = Decoder(pa);
                    426:        busdata r = dev->ReadBurst16(addr, dst);
                    427:        if (__predict_true(r.IsBusErr() == false)) {
                    428:                accstat_read[pa >> AccStat::SHIFT] = AccStat::READ;
                    429:        }
                    430:        return r;
1.1.1.3   root      431: }
                    432: 
                    433: busdata
1.1.1.4   root      434: Mainbus24Device::WriteBurst16(busaddr addr, const uint32 *src)
1.1.1.3   root      435: {
1.1.1.4   root      436:        uint32 pa = addr.Addr();
1.1.1.8 ! root      437:        lastaddr = pa;  // 開始アドレスしか残らない…
1.1.1.4   root      438:        IODevice *dev = Decoder(pa);
                    439:        busdata r = dev->WriteBurst16(addr, src);
                    440:        if (__predict_true(r.IsBusErr() == false)) {
                    441:                accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE;
                    442:        }
                    443:        return r;
1.1.1.3   root      444: }
1.1       root      445: 
1.1.1.3   root      446: busdata
1.1.1.4   root      447: Mainbus24Device::Peek1(uint32 addr)
1.1.1.3   root      448: {
                    449:        IODevice *dev = Decoder(addr);
1.1.1.4   root      450:        return dev->Peek1(addr);
1.1       root      451: }
                    452: 
1.1.1.3   root      453: bool
1.1.1.4   root      454: Mainbus24Device::Poke1(uint32 addr, uint32 data)
1.1       root      455: {
1.1.1.3   root      456:        IODevice *dev = Decoder(addr);
1.1.1.4   root      457:        return dev->Poke1(addr, data);
1.1       root      458: }
                    459: 
1.1.1.2   root      460: void
1.1.1.8 ! root      461: Mainbus24Device::MonitorScreen(Monitor *, TextScreen& screen)
1.1.1.2   root      462: {
                    463:        screen.Clear();
                    464: 
                    465:        // 012345678901234567890
                    466:        // $0000'0000: 1234567
                    467: 
                    468:        for (int i = 0; i < 8; i++) {
                    469:                screen.Print(12 + i * 8, 0, "+$0%x", i);
                    470:        }
                    471: 
                    472:        int idx = 0;
                    473:        for (int i = 0; i < devtable.size() / 8; i++) {
                    474:                screen.Print(0, i + 1, "$%02x00'0000:", idx);
                    475:                for (int j = 0; j < 8; j++) {
                    476:                        auto pair = FormatDevName(devtable[idx]);
                    477:                        const std::string& name = pair.first;
                    478:                        TA attr = pair.second;
                    479:                        screen.Print(12 + j * 8, i + 1, attr, "%s", name.c_str());
                    480:                        idx++;
                    481:                }
                    482:        }
                    483: }

unix.superglobalmegacorp.com

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