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

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

unix.superglobalmegacorp.com

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