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

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

unix.superglobalmegacorp.com

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