Annotation of nono/debugger/branchhistory.cpp, revision 1.1.1.13

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.5   root        7: //
1.1       root        8: // ブランチ履歴
1.1.1.5   root        9: //
1.1       root       10: 
                     11: #include "branchhistory.h"
1.1.1.10  root       12: #include "m680x0disasm.h"
1.1       root       13: #include "m88100.h"
1.1.1.10  root       14: #include "monitor.h"
1.1.1.7   root       15: #include "mpu64180.h"
1.1.1.5   root       16: #include "vectortable.h"
1.1       root       17: 
                     18: // コンストラクタ
1.1.1.9   root       19: BranchHistory::BranchHistory(uint objid_)
1.1.1.7   root       20:        : inherited(objid_)
1.1       root       21: {
1.1.1.7   root       22:        int monitor_id;
                     23: 
                     24:        switch (GetId()) {
                     25:         case OBJ_MPU_BRHIST:
                     26:                is_exhist = false;
                     27:                monitor_id = ID_SUBWIN_BRHIST;
                     28:                break;
                     29:         case OBJ_MPU_EXHIST:
                     30:                is_exhist = true;
                     31:                monitor_id = ID_SUBWIN_EXHIST;
                     32:                break;
                     33:         case OBJ_XP_BRHIST:
                     34:                is_exhist = false;
                     35:                monitor_id = ID_SUBWIN_XPBRHIST;
                     36:                break;
                     37:         case OBJ_XP_EXHIST:
                     38:                is_exhist = true;
                     39:                monitor_id = ID_SUBWIN_XPEXHIST;
                     40:                break;
                     41:         default:
                     42:                PANIC("unknown id %s", GetIdStr());
                     43:        }
1.1.1.4   root       44: 
1.1.1.5   root       45:        // ログは不要
                     46:        ClearAlias();
                     47: 
1.1.1.7   root       48:        vectortable = GetVectorTable();
                     49: 
1.1.1.10  root       50:        monitor = gMonitorManager->Regist(monitor_id, this);
1.1.1.13! root       51:        monitor->SetCallback(&BranchHistory::MonitorScreen);
1.1.1.10  root       52:        monitor->SetSize(55, 1 + 32); // ヘッダ1行とエントリ数
                     53:        monitor->SetMaxHeight(1 + 256);
1.1.1.7   root       54: 
                     55:        // hd64180 はこれを上書きする
                     56:        x_count = 45;
1.1       root       57: }
                     58: 
                     59: // デストラクタ
                     60: BranchHistory::~BranchHistory()
                     61: {
                     62: }
                     63: 
                     64: // 初期化
                     65: void
                     66: BranchHistory::Clear()
                     67: {
                     68:        top = 0;
                     69:        for (int i = 0; i < countof(entry); i++) {
                     70:                BranchEntry& e = entry[i];
                     71:                e.count = 0;
                     72:                e.from  = 0xffffffff;
                     73:                e.to    = 0xffffffff;
1.1.1.11  root       74:                e.info  = 0;
1.1       root       75:        }
                     76: }
                     77: 
                     78: // 使用中のエントリ数を取得する
                     79: int
                     80: BranchHistory::GetUsed() const
                     81: {
                     82:        int i = 0;
                     83: 
                     84:        // top の位置から一巡するまで。有効エントリは count > 0。
                     85:        for (; i < 256; i++) {
                     86:                if (entry[(256 + top - i) % 256].count == 0) {
                     87:                        break;
                     88:                }
                     89:        }
                     90:        return i;
                     91: }
                     92: 
                     93: // モニタ更新
                     94: void
1.1.1.13! root       95: BranchHistory::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root       96: {
                     97:        uint8 t;
                     98:        int y;
                     99:        int ydelta;
                    100:        int row;
                    101: 
                    102:        // userdata は表示開始位置と各種フラグ。
                    103:        // 下位 32bit が表示開始位置で、0 なら先頭のエントリから、1 なら先頭の
1.1.1.4   root      104:        // 一つ次のエントリから、…を表す (表示行数は screen の高さ分)。
1.1       root      105:        // BottomToTop が %1 なら並び順を下から上に変える (コンソール用)。
1.1.1.4   root      106:        bool bottom_to_top = (screen.userdata & BottomToTop);
                    107:        int pos = (int)screen.userdata;
1.1       root      108: 
                    109:        // 0         1         2         3         4         5         6
                    110:        // 0123456789012345678901234567890123456789012345678901234567890123456789
                    111:        // No. FromAddr  Instruction          ToAddr    Iteration
                    112:        // 001 U:01234567(01234567:bcnd.n) -> $01234567 x123456789
                    113:        // 001 U:01234567(0123:trap )      -> $01234567 x123456789
                    114:        // 002 S:01234567<  2> Bus Error
                    115:        // 002 S:01234567< 69> MFP Timer-C
                    116:        //                     01234567890123456789012
                    117: 
1.1.1.4   root      118:        screen.Clear();
                    119:        row = screen.GetRow();
1.1       root      120: 
                    121:        // 最初の1行は常にヘッダ
1.1.1.7   root      122:        std::string header = FormatHeader();
                    123:        screen.Puts(0, 0, header.c_str());
1.1       root      124: 
                    125:        // pos は最新を 0 とした通し番号。(スクロールしてたら開始が 0 とは限らない)
                    126:        // t が entry[] 上の現在位置。
                    127:        // y は表示座標。(上から表示か下から表示かが変わる)
                    128:        t = top - pos;
                    129:        int pos_end = pos + row - 1;
                    130:        if (bottom_to_top == false) {
                    131:                y = 1;
                    132:                ydelta = 1;
                    133:        } else {
                    134:                y = row - 1;
                    135:                ydelta = -1;
                    136:        }
                    137:        for (; pos < pos_end; pos++, y += ydelta) {
                    138:                BranchEntry& e = entry[t--];
                    139:                if (e.count == 0) {
                    140:                        continue;
                    141:                }
                    142:                std::string str = FormatEntry(e);
1.1.1.9   root      143:                screen.Print(0, y, "%3u %s", pos, str.c_str());
1.1       root      144:                if (e.count > 1) {
1.1.1.7   root      145:                        screen.Print(x_count, y, "x%9u", e.count);
1.1       root      146:                }
                    147:        }
                    148: }
                    149: 
1.1.1.7   root      150: // ヘッダ文字列を返す。(m68k, m88k 共通)
                    151: std::string
                    152: BranchHistory::FormatHeader() const
                    153: {
                    154:        if (is_exhist) {
                    155:                //      012345678901234567890123456789012345678901234567890123456789
                    156:                return "No. FromAddr   Vec. Exception                Iteration";
                    157:        } else {
                    158:                //      012345678901234567890123456789012345678901234567890123456789
                    159:                return "No. FromAddr  Instruction          ToAddr    Iteration";
                    160:        }
                    161: }
1.1       root      162: 
                    163: 
                    164: //
1.1.1.11  root      165: // m680x0 ブランチ履歴
1.1       root      166: //
                    167: 
1.1.1.8   root      168: // m680x0 ブランチ履歴では、通常ブランチ、例外発生 (IOCS コールと
                    169: // それ以外)、例外ベクタによるジャンプの4つを区別する。
1.1       root      170: //
1.1.1.8   root      171: // 1. 通常の分岐:
                    172: //     from は上位31ビットが分岐元 PC、最下位ビットが S/U。
                    173: //     to   は32ビット全体が分岐先 PC。
1.1.1.11  root      174: //     info は上位2ビットが %00 (Normal)、下位16ビットに分岐元命令の1ワード目。
1.1.1.8   root      175: //
1.1.1.11  root      176: //        3                   2                   1                   0
                    177: //      1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
                    178: //     +-+-+-----------+---------------+---------------+---------------+
                    179: //     |0 0|           0               |       Instruction Word        |
                    180: //     +-+-+-----------+---------------+---------------+---------------+
1.1.1.8   root      181: //
1.1.1.11  root      182: // 2. 例外発生 (IOCS/DOS コール以外の場合):
1.1.1.8   root      183: //     from は上位31ビットが例外発生時の PC、最下位ビットが S/U。
                    184: //     to   は不問だが 0 にすること。
1.1.1.11  root      185: //     info は上位2ビットが %11 (Exception)、最下位バイトがベクタ番号 (0-255)。
                    186: //     例外が TRAP#15 だが IOCS コールっぽくない場合と、
                    187: //     例外が F ライン例外だが DOS コールっぽくない場合もこちら。
                    188: //
                    189: //     +-+-+-----------+---------------+---------------+---------------+
                    190: //     |1 1|           0               |       0       |   Vector No.  |
                    191: //     +-+-+-----------+---------------+---------------+---------------+
1.1.1.8   root      192: //
1.1.1.13! root      193: // 3. 例外発生 (各種サービスコールの場合):
1.1.1.8   root      194: //     from, to は同じ。
1.1.1.11  root      195: //     info は上位2ビットが %10 (ServiceCall)。
1.1.1.13! root      196: //     info の上位ワードが OS 種別。
        !           197: //       $0 なら Human68k
        !           198: //       $1 なら NetBSD/m68k
        !           199: //     Human68k なら下位ワードは
        !           200: //       IOCS コールなら、b8 が %0 で b7-b0 に IOCS コール番号。
        !           201: //       DOS  コールなら、b8 が %1 で b7-b0 に DOS コール番号。
        !           202: //     NetBSD/m68k なら下位ワードはシステムコール番号。
        !           203: //
        !           204: //     +-+-+-----------+-------------+-+---------------+---------------+
        !           205: //     |1 0|                         $0|      0      |0| IOCS Call No. |
        !           206: //     +-+-+-----------+-------------+-+---------------+---------------+
        !           207: //     +-+-+-----------+-------------+-+---------------+---------------+
        !           208: //     |1 0|                         $0|      -      |1|  DOS Call No. |
        !           209: //     +-+-+-----------+-------------+-+---------------+---------------+
        !           210: //     +-+-+-----------+-------------+-+---------------+---------------+
        !           211: //     |1 0|                         $1|        System Call No.        |
        !           212: //     +-+-+-----------+-------------+-+---------------+---------------+
1.1       root      213: //
1.1.1.8   root      214: // 4. 例外ベクタによる分岐 (例外処理の最後に起きる):
1.1.1.3   root      215: //     from はベクタアドレス、
                    216: //     to   は分岐先 (0 も起こりえる)、
1.1.1.11  root      217: //     info は上位2ビットが %01 (VectorJump)。
1.1.1.8   root      218: //
1.1.1.11  root      219: //     +-+-+-----------+---------------+---------------+---------------+
                    220: //     |0 1|                           0                               |
                    221: //     +-+-+-----------+---------------+---------------+---------------+
1.1       root      222: 
                    223: // コンストラクタ
1.1.1.9   root      224: BranchHistory_m680x0::BranchHistory_m680x0(uint objid_)
1.1.1.7   root      225:        : inherited(objid_)
1.1       root      226: {
                    227: }
                    228: 
                    229: // デストラクタ
                    230: BranchHistory_m680x0::~BranchHistory_m680x0()
                    231: {
                    232: }
                    233: 
                    234: // 1エントリ分の表示内容作成
                    235: std::string
                    236: BranchHistory_m680x0::FormatEntry(const BranchEntry& e)
                    237: {
                    238:        // m68k では from の最下位1ビットを S/U として使う
1.1.1.13! root      239:        std::string desc = string_format("%c.%08x",
1.1       root      240:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
                    241: 
1.1.1.11  root      242:        switch (e.info >> 30) {
1.1.1.8   root      243:         case 0:        // 通常分岐
                    244:         {
1.1       root      245:                const char *mnemonic;
1.1.1.11  root      246:                uint32 inst = e.info & 0xffff;
1.1       root      247:                if (inst == 0x4e73) {
                    248:                        mnemonic = ":rte";
                    249:                } else if (inst == 0x4e75) {
                    250:                        mnemonic = ":rts";
                    251:                } else if (inst == 0x4e77) {
                    252:                        mnemonic = ":rtr";
                    253:                } else if ((inst & 0xffc0) == 0x4e80) {
                    254:                        mnemonic = ":jsr";
                    255:                } else if ((inst & 0xffc0) == 0x4ec0) {
                    256:                        mnemonic = ":jmp";
                    257:                } else if ((inst & 0xfff8) == 0x51c8) {
                    258:                        mnemonic = ":dbra";
                    259:                } else if ((inst & 0xf0f8) == 0x50c8) {
                    260:                        mnemonic = ":dbcc";
                    261:                } else if ((inst & 0xff00) == 0x6000) {
                    262:                        mnemonic = ":bra";
                    263:                } else if ((inst & 0xff00) == 0x6100) {
                    264:                        mnemonic = ":bsr";
                    265:                } else if ((inst & 0xf000) == 0x6000) {
                    266:                        mnemonic = ":bcc";
                    267:                } else if ((inst & 0xfff8) == 0xf248) {
                    268:                        mnemonic = ":fdbcc";
                    269:                } else if ((inst & 0xff80) == 0xf280) {
                    270:                        mnemonic = ":fbcc";
                    271:                } else {
                    272:                        mnemonic = "";
                    273:                }
                    274:                desc += string_format("(%04x%-6s)      -> $%08x", inst, mnemonic, e.to);
1.1.1.8   root      275:                break;
                    276:         }
                    277: 
                    278:         case 1:        // 例外ベクタフェッチによるジャンプ
                    279:                // 例外ベクタフェッチしてジャンプ
                    280:                desc += string_format("(vector fetch)    -> $%08x", e.to);
                    281:                break;
                    282: 
1.1.1.11  root      283:         case 2:        // 例外発生 (IOCS/DOS コール)
1.1.1.8   root      284:         {
1.1.1.11  root      285:                uint vector;
1.1.1.13! root      286:                if (((e.info >> 16) & 0x01) == 0) {
        !           287:                        // Human68k、IOCS/DOS コール
        !           288:                        const char *call;
        !           289:                        const char *name;
        !           290:                        uint num = e.info & 0xff;
        !           291:                        if ((e.info & 0x0100) == 0) {
        !           292:                                call = "IOCS";
        !           293:                                name = m680x0disasm::GetIOCSName(num);
        !           294:                                vector = M68K::EXCEP_TRAP15;
        !           295:                        } else {
        !           296:                                call = "DOS";
        !           297:                                name = m680x0disasm::GetDOSName(num);
        !           298:                                vector = M68K::EXCEP_FLINE;
        !           299:                        }
        !           300:                        if (name != NULL) {
        !           301:                                desc += string_format("<%3u> %s %s", vector, call, name);
        !           302:                        } else {
        !           303:                                desc += string_format("<%3u> %s $%02x", vector, call, num);
        !           304:                        }
1.1.1.8   root      305:                } else {
1.1.1.13! root      306:                        // NetBSD/m68k システムコール
        !           307:                        vector = M68K::EXCEP_TRAP0;
        !           308:                        const char *name = vectortable->GetExceptionName(vector);
        !           309:                        uint num = e.info & 0xffff;
        !           310:                        desc += string_format("<%3u> %s (syscall %u)", vector, name, num);
1.1.1.8   root      311:                }
                    312:                break;
                    313:         }
                    314: 
1.1.1.11  root      315:         case 3:        // 例外発生 (IOCS/DOS コール以外)
1.1.1.8   root      316:         {
1.1.1.11  root      317:                uint32 vector = e.info & 0xff;
1.1.1.8   root      318:                const char *name = vectortable->GetExceptionName(vector);
1.1.1.9   root      319:                desc += string_format("<%3u> %s", vector, name ?: "");
1.1.1.8   root      320:                break;
                    321:         }
                    322: 
                    323:         default:
                    324:                __unreachable();
1.1       root      325:        }
                    326:        return desc;
                    327: }
                    328: 
                    329: 
                    330: //
1.1.1.11  root      331: // m88xx0 ブランチ履歴
1.1       root      332: //
                    333: 
                    334: // m88xx0 ブランチ履歴では、通常ブランチ、例外発生の2つを区別する。
                    335: // m68k は例外ベクタに書いてあるアドレスに飛ぶのでもう1種類分けてあったが、
                    336: // m88k は例外ベクタを直接実行するのでそれは不要。
                    337: //
                    338: // 通常の分岐:
1.1.1.3   root      339: //     from は上位30ビットが分岐元 XIP、最下位ビットが S/U、
                    340: //     to   は32ビット全体が分岐先アドレス、
1.1.1.11  root      341: //     info は命令ワード。
1.1       root      342: //
                    343: // 例外発生:
1.1.1.3   root      344: //     from は上位30ビットが例外発生時の XIP、最下位ビットが S/U、
1.1.1.12  root      345: //     to   は不問。
1.1.1.11  root      346: //     info は、9 ビットのベクタ番号と、ベクタが OpenBSD/m88k システムコール
                    347: //     の場合はシステムコール番号を含む。
                    348: //        3                   2                   1                   0
                    349: //      1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
                    350: //     +---------------+---------------+-------+-----+-+---------------+
                    351: //     |1 1 0 0 0 0 0 0|   System Call No.     |0 0 0|  Vector Number  |
                    352: //     +---------------+---------------+-------+-----+-+---------------+
1.1.1.3   root      353: //     命令ワードとは衝突しない (instruction.txt 参照)。
1.1       root      354: 
                    355: // コンストラクタ
1.1.1.9   root      356: BranchHistory_m88xx0::BranchHistory_m88xx0(uint objid_)
1.1.1.7   root      357:        : inherited(objid_)
1.1       root      358: {
                    359: }
                    360: 
                    361: // デストラクタ
                    362: BranchHistory_m88xx0::~BranchHistory_m88xx0()
                    363: {
                    364: }
                    365: 
                    366: // 1エントリ分の表示内容作成
                    367: std::string
                    368: BranchHistory_m88xx0::FormatEntry(const BranchEntry& e)
                    369: {
                    370:        // m88k では from の最下位1ビットを S/U として使う
1.1.1.13! root      371:        std::string desc = string_format("%c.%08x",
1.1       root      372:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
                    373: 
1.1.1.12  root      374:        if (e.info >= 0xfc000000) {
1.1       root      375:                // 例外発生記録
                    376:                // 発生アドレスとベクタを表示
1.1.1.11  root      377:                uint32 vector = e.info & 0x1ff;
1.1.1.7   root      378:                const char *name = vectortable->GetExceptionName(vector);
1.1.1.9   root      379:                desc += string_format("<%3u> %s", vector, name ?: "");
1.1.1.7   root      380:                if (vector == 128 || vector == 450) {
                    381:                        // 450 なら OpenBSD のシステムコール番号を追加。
                    382:                        // 非公式 NetBSD/luna88k は(今の所?) 128 を使ってるようだ。
1.1.1.11  root      383:                        desc += string_format("(%u)", (e.info >> 12) & 0xfff);
1.1       root      384:                }
1.1.1.11  root      385:        } else if (e.info >= 0xc0000000) {
1.1       root      386:                // ブランチ
                    387:                const char *mnemonic = "";
1.1.1.11  root      388:                uint32 up4 = (e.info >> 26) & 0xf;
1.1       root      389:                switch (up4) {
                    390:                 case 0:        mnemonic = ":br";               break;
                    391:                 case 1:        mnemonic = ":br.n";             break;
                    392:                 case 2:        mnemonic = ":bsr";              break;
                    393:                 case 3:        mnemonic = ":bsr.n";    break;
                    394:                 case 4:        mnemonic = ":bb0";              break;
                    395:                 case 5:        mnemonic = ":bb0.n";    break;
1.1.1.2   root      396:                 case 6:        mnemonic = ":bb1";              break;
1.1       root      397:                 case 7:        mnemonic = ":bb1.n";    break;
                    398: 
                    399:                 case 0xa:      mnemonic = ":bcnd";             break;
                    400:                 case 0xb:      mnemonic = ":bcnd.n";   break;
                    401:                 case 0xc: {
1.1.1.11  root      402:                        uint32 lo6 = (e.info >> 10) & 0x3f;
1.1       root      403:                        if (lo6 == 0x34) {
                    404:                                mnemonic = ":tb0";
                    405:                        } else if (lo6 == 0x36) {
                    406:                                mnemonic = ":tb1";
                    407:                        } else if (lo6 == 0x3a) {
                    408:                                mnemonic = ":tcnd";
                    409:                        }
                    410:                        break;
                    411:                 }
                    412:                 case 0xd: {
1.1.1.11  root      413:                        uint32 lo6 = (e.info >> 10) & 0x3f;
1.1       root      414:                        if (lo6 == 0x30) {
1.1.1.11  root      415:                                if ((e.info & 0x1f) == 1) {
1.1       root      416:                                        mnemonic = ":jmp r1";
                    417:                                } else {
                    418:                                        mnemonic = ":jmp";
                    419:                                }
                    420:                        } else if (lo6 == 0x31) {
                    421:                                mnemonic = ":jmp.n";
                    422:                        } else if (lo6 == 0x32) {
                    423:                                mnemonic = ":jsr";
                    424:                        } else if (lo6 == 0x33) {
                    425:                                mnemonic = ":jsr.n";
                    426:                        } else if (lo6 == 0x3f) {
                    427:                                mnemonic = ":rte";
                    428:                        }
                    429:                        break;
                    430:                 }
                    431:                 case 0xe:      mnemonic = ":tbnd";     break;
                    432:                 default:
                    433:                        break;
                    434:                }
1.1.1.11  root      435:                desc += string_format("(%08x%-7s) -> $%08x", e.info, mnemonic, e.to);
1.1       root      436:        }
                    437:        return desc;
                    438: }
1.1.1.7   root      439: 
                    440: 
                    441: //
                    442: // XP ブランチ履歴
                    443: //
                    444: 
                    445: // XP ブランチ履歴では、通常ブランチ、例外発生、例外ベクタによるジャンプの
                    446: // 3つを区別する。
                    447: //
                    448: // 通常の分岐
                    449: //     from は下位 16 ビットが分岐元 PC
                    450: //     to   は下位 16 ビットが分岐先 PC
1.1.1.11  root      451: //     info の最上位ビットが %0 で区別する。
                    452: //     info の下位 16 ビットに命令を上詰めで。例えば
1.1.1.7   root      453: //     CALL (1バイト命令 CD nn nn) なら $0000'cd00、
                    454: //     RETI (2バイト命令 ED 4D) なら $0000'ed4d。
                    455: //
                    456: // 例外発生
                    457: //     from は下位 16 ビットが例外発生時の PC
                    458: //     to   は $ffffffff ならこのエントリはベクタ方式の例外発生時側を示す、
                    459: //             そうでなければダイレクト方式で下位 16 ビットが分岐先 PC
1.1.1.11  root      460: //     info の最上位ビットが %1 で info が $ffffffff でなければ
1.1.1.7   root      461: //     下位に優先度(0-15)。
                    462: //
                    463: // 例外ベクタジャンプの場合
                    464: //     from はベクタアドレス
                    465: //     to   は分岐先 PC、
1.1.1.11  root      466: //     info が $ffffffff で区別する。
1.1.1.7   root      467: 
                    468: // コンストラクタ
1.1.1.9   root      469: BranchHistory_hd64180::BranchHistory_hd64180(uint objid_)
1.1.1.7   root      470:        : inherited(objid_)
                    471: {
1.1.1.10  root      472:        monitor->SetSize(48, 1 + 32); // ヘッダ1行とエントリ数
1.1.1.7   root      473:        x_count = 38;
                    474: }
                    475: 
                    476: // デストラクタ
                    477: BranchHistory_hd64180::~BranchHistory_hd64180()
                    478: {
                    479: }
                    480: 
                    481: // ヘッダ文字列を返す。
                    482: std::string
                    483: BranchHistory_hd64180::FormatHeader() const
                    484: {
                    485:        if (is_exhist) {
                    486:                //      01234567890123456789012345678901234567890123456789
                    487:                return "No. From  Exception                   Iteration";
                    488:        } else {
                    489:                //      01234567890123456789012345678901234567890123456789
                    490:                return "No. From Instruction           ToAddr Iteration";
                    491:        }
                    492: }
                    493: 
                    494: // 1エントリ分の表示内容作成
                    495: std::string
                    496: BranchHistory_hd64180::FormatEntry(const BranchEntry& e)
                    497: {
                    498:        // 0         1         2         3         4         5
                    499:        // 012345678901234567890123456789012345678901234567890
                    500:        // No. From Instruction           ToAddr Iteration
                    501:        // 001 0123(0000:CALL NZ)      -> $0234 x123456899
                    502:        // No. From Exception
                    503:        // 002 0123<00> Timer Overflow
                    504:        // 003 0038(vector fetch)      -> $0000
                    505: 
                    506:        std::string desc = strhex(e.from, 4);
                    507: 
1.1.1.11  root      508:        if (e.info == 0xffffffff) {
1.1.1.7   root      509:                // 例外ベクタフェッチしてジャンプ
                    510:                desc += string_format("(vector fetch)      -> $%04x", e.to);
1.1.1.11  root      511:        } else if ((int32)e.info < 0) {
1.1.1.7   root      512:                // 例外発生
1.1.1.11  root      513:                uint32 vector = e.info & 0xff;
1.1.1.9   root      514:                desc += string_format("<%2u>%-15s",
1.1.1.7   root      515:                        vector, MPU64180Device::InterruptName[vector]);
                    516:                // 例外履歴には宛先は出さないほうに統一。
                    517:                // ブランチ履歴でも、ベクタ方式なら宛先不要。
                    518:                if (is_exhist == false && e.to != -1) {
                    519:                        desc += string_format(" -> $%04x", e.to);
                    520:                }
                    521:        } else {
                    522:                // ブランチ
                    523:                std::string mnemonic;
1.1.1.11  root      524:                uint32 inst = e.info & 0xffff;
1.1.1.7   root      525:                if (inst == 0x1000) {
                    526:                        mnemonic = ":DJNZ";
                    527:                } else if (inst == 0x1800) {
                    528:                        mnemonic = ":JR";
                    529:                } else if (inst == 0xc300) {
                    530:                        mnemonic = ":JP";
                    531:                } else if (inst == 0xc900) {
                    532:                        mnemonic = ":RET";
                    533:                } else if (inst == 0xcd00) {
                    534:                        mnemonic = ":CALL";
                    535:                } else if (inst == 0xe900) {
                    536:                        mnemonic = ":JP (HL)";
                    537:                } else if (inst == 0xed45) {
                    538:                        mnemonic = ":RETN";
                    539:                } else if (inst == 0xed4d) {
                    540:                        mnemonic = ":RETI";
                    541:                } else if (inst == 0xdde9) {
                    542:                        mnemonic = ":JP (IX)";
                    543:                } else if (inst == 0xfde9) {
                    544:                        mnemonic = ":JP (IY)";
                    545:                } else if ((inst & 0xe700) == 0x2000) {
                    546:                        mnemonic = ":JR " + fstr((inst >> 11) & 3);
                    547:                } else if ((inst & 0xc700) == 0xc000) {
                    548:                        mnemonic = ":RET " + fstr((inst >> 11) & 7);
                    549:                } else if ((inst & 0xc700) == 0xc200) {
                    550:                        mnemonic = ":JP " + fstr((inst >> 11) & 7);
                    551:                } else if ((inst & 0xc700) == 0xc400) {
                    552:                        mnemonic = ":CALL " + fstr((inst >> 11) & 7);
                    553:                } else if ((inst & 0xc700) == 0xc700) {
                    554:                        mnemonic = string_format(":RST %02xH", (inst >> 8) & 0x38);
                    555:                }
                    556:                desc += string_format("(%04x%-8s)      -> $%04x",
                    557:                        inst, mnemonic.c_str(), e.to);
                    558:        }
                    559:        return desc;
                    560: }
                    561: 
                    562: /*static*/ std::string
                    563: BranchHistory_hd64180::fstr(int f)
                    564: {
                    565:        static const char fff[] =
                    566:                "NZ\0\0"
                    567:                "Z\0\0\0"
                    568:                "NC\0\0"
                    569:                "C\0\0\0"
                    570:                "PO\0\0"
                    571:                "PE\0\0"
                    572:                "P\0\0\0"
                    573:                "M";
                    574: 
                    575:        return &fff[f * 4];
                    576: }

unix.superglobalmegacorp.com

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