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

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

unix.superglobalmegacorp.com

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