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

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

unix.superglobalmegacorp.com

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