|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
1.1.1.3 ! root 9: #include "branchhistory.h"
1.1 root 10: #include "bus.h"
11: #include "cvprompt.h"
12: #include "textscreen.h"
1.1.1.2 root 13: #include <array>
14:
15: using ConstStringPair = std::pair<const std::string, const std::string>;
16: using HelpMessages = std::vector<ConstStringPair>;
1.1 root 17:
18: // 諸情報付きのアドレス
19: struct saddr_t
20: {
21: uint32 addr = 0; // アドレス(32bit)
22:
23: // addr が論理アドレスなら true。
24: // MMU の有効/無効状態はここにセットするのではなく、メモリアクセスに
25: // 際してアドレス変換を行う側がその時点で改めてチェックするので、
26: // ここはどちらかというと物理アドレスなら false くらいの意味合い。
27: bool logical = false;
28:
29: // addr が論理アドレスの場合に、テーブルサーチも行うなら true。
30: // false なら TT、ATC のみ検索する。
31: bool search = false;
32:
33: // addr がスーパバイザアクセスなら true。
34: bool super = false;
35:
36: // addr がデータアクセスなら true。
37: bool data = false;
38:
39: bool IsLogical() const { return logical; }
40: bool IsSearch() const { return search; }
41: bool IsSuper() const { return super; }
42: bool IsData() const { return data; }
43: bool IsInst() const { return !data; }
44:
45: // (論理)アドレスと Super/User ビットを合わせた 33bit アドレスを返す
46: uint64 GetSaddr() const {
47: uint64 sa = addr;
48: if (IsSuper()) {
49: sa |= 0x100000000ULL;
50: }
51: return sa;
52: }
53: };
54:
55: enum MemdumpMode {
56: Physical = 0, // 物理アドレス
57: Logical_atc, // 論理アドレス (ただし TT、ATC のみ検索)
58: Logical_search, // 論理アドレス (TT、ATC、テーブルサーチすべて行う)
59: };
60:
61: class Console;
62: class DebuggerMD;
63: class Disasm;
64:
1.1.1.2 root 65: class Debugger final
1.1 root 66: {
67: friend class DebuggerMD_m680x0;
68: friend class DebuggerMD_m88xx0;
69: private:
70: // 型
1.1.1.2 root 71: enum CommandAction {
72: Stay, // デバッガプロンプトに留まる
73: Leave, // デバッガプロンプトを抜けて VM を実行する
74: Quit, // デバッガとの接続を終了する
75: };
76: using cmdfunc_t = void (Debugger::*)();
1.1 root 77: typedef struct {
78: const char *name;
79: cmdfunc_t func;
1.1.1.2 root 80: CommandAction action;
1.1 root 81: } cmddef_t;
82:
1.1.1.3 ! root 83: // ブレークポイント種別
! 84: enum BreakpointType {
! 85: Unused = 0,
! 86: Address, // このアドレスに来る直前
! 87: Memory, // このアドレスをアクセスした直後
! 88: Exception, // この例外を検出した直後
! 89: Instruction, // この命令を実行する直前
! 90: };
! 91:
1.1 root 92: // ブレークポイント
93: typedef struct {
1.1.1.3 ! root 94: BreakpointType type {}; // 種別
! 95: // 種別ごとのパラメータ
! 96: union {
! 97: uint32 addr {}; // ターゲットアドレス (Address/Memory)
! 98: struct {
! 99: int vec1; // ベクタ番号 (開始)
! 100: int vec2; // ベクタ番号 (終了)
! 101: };
! 102: struct {
! 103: uint32 inst; // 命令ワード
! 104: uint32 mask; // マスク
! 105: };
! 106: };
! 107:
! 108: uint32 matched {}; // 成立回数 (積算)
! 109:
! 110: // skip はユーザ指定値。ただし
! 111: // -1 なら常にスキップ、つまりブレークせずカウントのみ行う、
! 112: // 0 ならスキップなし、つまり成立ごとにブレーク(これがデフォルト)、
! 113: // n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。
! 114: int32 skip {}; // スキップ回数 (ユーザ指定値)
! 115: int32 skipremain {}; // 残りスキップ回数 (0 で成立)
1.1 root 116: } breakpoint_t;
117: static const int MAX_BREAKPOINTS = 8;
118:
119: public:
120: Debugger();
1.1.1.2 root 121: ~Debugger() { }
1.1 root 122:
123: void Init();
124: void ThreadRun();
125: bool Check();
1.1.1.3 ! root 126: void NotifyException(int vector);
! 127:
! 128: // ブレークポイントモニタを更新
! 129: void MonitorBreakpoint(TextScreen& monitor);
1.1 root 130:
131: private:
1.1.1.2 root 132: bool Accept();
133: bool AcquirePrompt();
134: CommandAction MainLoop();
1.1.1.3 ! root 135: bool CheckAllBreakpoints();
! 136: bool CheckBreakpointInst(breakpoint_t&);
1.1.1.2 root 137: void ParseCmdbuf();
1.1 root 138: // コマンド名は大文字小文字を区別する関係でスネークスタイル。
139: void cmd_b();
1.1.1.3 ! root 140: void cmd_bi();
! 141: void cmd_bm();
! 142: void cmd_bv();
1.1 root 143: void cmd_b_list();
1.1.1.3 ! root 144: void cmd_b_set(BreakpointType);
1.1 root 145: void cmd_brhist();
146: void cmd_bx();
147: void cmd_c();
148: void cmd_d();
149: void cmd_dt();
150: void cmd_D();
1.1.1.3 ! root 151: void cmd_exhist();
1.1 root 152: void cmd_h();
153: void cmd_L();
154: void cmd_m();
155: void cmd_mt();
156: void cmd_M();
157: void cmd_minus();
158: void cmd_n();
159: void cmd_q();
160: void cmd_s();
161: void cmd_so();
162: void cmd_show();
163: void cmd_t();
164:
1.1.1.3 ! root 165: int AddBreakpoint(const breakpoint_t&);
! 166: void RecalcInstMask();
1.1 root 167: bool GetAddr(uint32& addr, uint32& lastaddr);
168: void cmd_d_common(MemdumpMode mode);
1.1.1.3 ! root 169: void cmd_hist_common(BranchHistory& hist, uint64 flag);
1.1 root 170: void cmd_m_common(MemdumpMode mode);
1.1.1.3 ! root 171: bool ParseVerbHex(const char *arg, uint32 *valp);
1.1 root 172: bool ParseAddr(const char *arg, uint32_t *addrp);
173: bool SetNBreakpoint();
174:
1.1.1.2 root 175: static const HelpMessages HelpMsgMain;
176: void Help(const HelpMessages msgs);
177:
178: // モニターを更新して表示
1.1.1.3 ! root 179: void ShowMonitor(IMonitor& monitor);
1.1.1.2 root 180: // テキストスクリーンを表示
181: void ShowTextScreen(TextScreen& screen);
1.1 root 182:
183: // アドレスをダンプ表示用に整形して返す
184: bool FormatDumpAddr(saddr_t addr, std::string& addrstr);
185:
186: DebuggerMD *md = NULL; // 機種依存部分
187:
188: Console *cons = NULL; // 入出力
189: const char *prompt; // プロンプト文字列
190: std::string cmdbuf {}; // 現在のコマンドライン
191: std::string last_cmdbuf {}; // 直前のコマンドライン
1.1.1.2 root 192: std::vector<std::string> args {};
1.1 root 193:
194: uint32 pc = 0;
195: uint32 nextpc = 0;
196: std::vector<uint8> ir {}; // この後実行する命令のバイナリ列
1.1.1.2 root 197: std::array<breakpoint_t, MAX_BREAKPOINTS> bpoint {};
1.1 root 198: bool bc_enable = false;
199: uint32 bc_addr = 0;
1.1.1.3 ! root 200: uint32 bi_inst = 0;
! 201: int bi_inst_bytes = 0;
! 202: int bi_need_bytes = 0;
! 203: int bv_vector = -1;
1.1 root 204: uint32 d_last_addr = 0;
205: uint32 m_last_addr = 0;
206: bool n_enable = false;
207: bool n_breakenable = false;
208: uint32 n_breakaddr = 0;
209: uint32 n_count = 0;
210: bool s_enable = false;
211: uint32 s_count = 0;
212: bool so_enable = false;
213: bool t_enable = false;
214: uint32 t_count = 0;
215:
216: // 一度VMを実行して再びプロンプトに来たら true
217: bool is_continued = false;
218:
1.1.1.2 root 219: static std::vector<cmddef_t> cmdtable;
1.1 root 220: };
221:
222: // デバッガの CPU 依存部分
223: class DebuggerMD
224: {
225: public:
226: DebuggerMD(Debugger *arg) {
227: parent = arg;
228: }
229: virtual ~DebuggerMD() { }
230:
231: // CPU のリクエストフラグに flag を立てる
232: virtual void ReqSet(uint32 flag) = 0;
233: // CPU のリクエストフラグから flag を落とす
234: virtual void ReqClr(uint32 flag) = 0;
235:
236: // 特権モードなら true を返す
237: virtual bool IsSuper() const = 0;
238: // MMU が有効なら true を返す
239: virtual bool MMUEnabled() const = 0;
240:
241: // アドレス変換をする。
242: // MMUEnabled() が true であることは呼び出し側が確認すること。
243: // 変換できなければ (uint64)-1 を返す。
244: virtual uint64 TranslateAddr(saddr_t laddr) = 0;
245:
246: // 現在の命令先頭アドレスを返す
247: virtual uint32 GetPC() const = 0;
248:
249: // ステップアウトを設定する
250: virtual void SetStepOut() = 0;
251: // ステップアウトなら true を返す
252: virtual bool IsStepOut() const = 0;
253:
254: // name で示されるのレジスタの値を返す。
255: // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは
256: // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて
257: // よい。また m680x0 の SRP/CRP は下位32ビットでよい。
258: // name が正しくない場合は (uint64)-1 を返す。
259: virtual uint64 GetRegAddr(const char *name) const = 0;
260:
261: // 現在のレジスタセットを内部にバックアップする
262: virtual void BackupRegs() = 0;
263:
1.1.1.2 root 264: // レジスタ表示系のコマンドを実行。処理すれば true を返す。
265: virtual bool ShowRegister(Console *cons,
266: const std::vector<std::string>& args) = 0;
267: // レジスタ表示系コマンドのヘルプメッセージを取得
268: virtual const HelpMessages& GetRegisterHelp() const = 0;
269:
1.1.1.3 ! root 270: // ブランチ履歴・例外履歴(オブジェクト)を取得
! 271: virtual BranchHistory& GetBrHist() const = 0;
! 272: virtual BranchHistory& GetExHist() const = 0;
1.1 root 273:
274: // 直近の命令でアクセスした laddr が一致したら true を返す
275: // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する
276: virtual bool CheckLEA(uint32 laddr) = 0;
277:
278: // 逆アセンブル。
279: // laddr の位置の命令を一つ逆アセンブルする。
280: // 成功すれば true を返し、失敗すれば(?) false を返す。
281: // 成功した場合 mnemonic に逆アセンブルした文字列が、
282: // bin にこの命令のバイナリ列が格納されている。
283: // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。
284: // bin はメモリイメージのバイト順で格納すること。
285: virtual bool Disassemble(saddr_t laddr,
286: std::string& mnemonic, std::vector<uint8>& bin) = 0;
287:
288: // 逆アセンブルをフォーマット。
289: // オフライン版は逆アセンブルウィンドウなど、
290: // オンライン版(Live) はデバッガプロンプトで表示するやつ。
291: virtual std::string FormatDisasm(const std::string& mnemonic,
292: const std::vector<uint8>& bin) = 0;
293: virtual std::string FormatDisasmLive(const std::string& mnemonic,
294: const std::vector<uint8>& bin) = 0;
295:
1.1.1.3 ! root 296: // ベクタ番号の最大値 (+1)
! 297: int vector_max = 0;
! 298: // 1命令の最小ビット数
! 299: uint inst_bits = 0;
! 300:
1.1 root 301: protected:
302: Debugger *parent; // 親クラス
303: };
304:
305: #define NORM "\x1b[0m"
306: #define BOLD "\x1b[1m"
307: #define BOLDIF(n) ((n) ? BOLD : "")
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.