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

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

unix.superglobalmegacorp.com

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