--- nono/debugger/debugger_private.h 2026/04/29 17:04:43 1.1.1.5 +++ nono/debugger/debugger_private.h 2026/04/29 17:05:09 1.1.1.9 @@ -4,17 +4,27 @@ // Licensed under nono-license.txt // +// +// デバッガ (内部用) +// + #pragma once #include "branchhistory.h" #include "bus.h" -#include "cvprompt.h" +#include "monitor.h" #include "textscreen.h" +#include "thread.h" #include +#include +#include using ConstStringPair = std::pair; using HelpMessages = std::vector; +class HostCOMDevice; +class VectorTable; + // 諸情報付きのアドレス class saddr_t { @@ -101,21 +111,120 @@ enum class MMULookupMode : bool // saddr_t の後で Debugger の前... #include "debugger_memory.h" -class Console; -class DebuggerMD; +class Debugger; class Disasm; -class Debugger final +// デバッガの CPU 依存部分 +class DebuggerMD { - friend class DebuggerMD_m680x0; - friend class DebuggerMD_m88xx0; public: enum class Arch { M680x0, M88xx0, }; + public: + DebuggerMD(Debugger *parent_, Arch arch_) { + parent = parent_; + arch = arch_; + } + virtual ~DebuggerMD(); + + // CPU のリクエストフラグに flag を立てる + virtual void ReqSet(uint32 flag) = 0; + // CPU のリクエストフラグから flag を落とす + virtual void ReqClr(uint32 flag) = 0; + + // 特権モードなら true を返す + virtual bool IsSuper() const = 0; + // MMU が有効なら true を返す + virtual bool MMUEnabled() const = 0; + + // アドレス変換をする。 + // MMUEnabled() が true であることは呼び出し側が確認すること。 + // lookup が true ならテーブルサーチまで行う。 + // 変換できなければ (uint64)-1 を返す。 + virtual uint64 TranslateAddr(saddr_t laddr, bool lookup) const = 0; + + // 現在の命令先頭アドレスを返す + virtual uint32 GetPC() const = 0; + + // ステップアウトを設定する + virtual void SetStepOut() = 0; + // ステップアウトなら true を返す + virtual bool IsStepOut() const = 0; + + // この命令がステップイン出来るなら true を返す (cmd_n 用) + virtual bool IsOpStepIn(DebuggerMemoryStream& mem) = 0; + + // name で示されるのレジスタの値を返す。 + // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは + // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて + // よい。また m680x0 の SRP/CRP は下位32ビットでよい。 + // name が正しくない場合は (uint64)-1 を返す。 + virtual uint64 GetRegAddr(const char *name) const = 0; + + // 現在のレジスタセットを内部にバックアップする + virtual void BackupRegs() = 0; + + // レジスタ表示系のコマンドを実行。処理すれば true を返す。 + virtual bool ShowRegister(FILE *, const std::vector& args) = 0; + // レジスタ表示系コマンドのヘルプ一覧を取得 + virtual const HelpMessages& GetHelpListReg() const = 0; + // レジスタ表示系コマンドのヘルプメッセージを取得 + virtual const HelpMessages& GetHelpReg() const = 0; + + // ブランチ履歴・例外履歴(オブジェクト)を取得 + virtual BranchHistory& GetBrHist() const = 0; + virtual BranchHistory& GetExHist() const = 0; + + // 直近の命令でアクセスした laddr が一致したら true を返す + // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する + virtual bool CheckLEA(uint32 laddr) = 0; + + // 逆アセンブル。 + // mem.laddr の位置の命令を一つ逆アセンブルする。 + // 成功すれば true を返し、失敗すれば(?) false を返す。 + // 成功した場合 mnemonic に逆アセンブルした文字列が、 + // bin にこの命令のバイナリ列が格納されている。 + // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。 + // bin はメモリイメージのバイト順で格納すること。 + virtual bool Disassemble(DebuggerMemoryStream& mem, + std::string& mnemonic, std::vector& bin) = 0; + + // 逆アセンブルをフォーマット。 + // オフライン版は逆アセンブルウィンドウなど、 + // オンライン版(Live) はデバッガプロンプトで表示するやつ。 + virtual std::string FormatDisasm(const std::string& mnemonic, + const std::vector& bin) = 0; + virtual std::string FormatDisasmLive(const std::string& mnemonic, + const std::vector& bin) = 0; + + // 機種 + Arch arch {}; + + // 最短の1命令のバイト数 + uint inst_bytes {}; + // 命令が固定長ならそのバイト数、可変長なら 0 + uint inst_bytes_fixed {}; + + protected: + Debugger *parent {}; // 親クラス +}; + +class Debugger : public ThreadDevice +{ + using inherited = ThreadDevice; + friend class DebuggerMD_m680x0; + friend class DebuggerMD_m88xx0; + private: + // リクエストフラグ + static const uint32 REQUEST_EXIT = 0x0001; // 終了 + static const uint32 REQUEST_RXCHAR = 0x0002; // 1文字受信 + static const uint32 REQUEST_ACCEPT = 0x0004; // 着信通知 + static const uint32 REQUEST_PROMPT = 0x0008; // プロンプト要求 + // 型 enum CommandAction { Stay, // デバッガプロンプトに留まる @@ -123,11 +232,11 @@ class Debugger final Quit, // デバッガとの接続を終了する }; using cmdfunc_t = void (Debugger::*)(); - typedef struct { + struct cmddef_t { const char *name; cmdfunc_t func; CommandAction action; - } cmddef_t; + }; // ブレークポイント種別 enum BreakpointType { @@ -139,7 +248,7 @@ class Debugger final }; // ブレークポイント - typedef struct { + struct breakpoint_t { BreakpointType type {}; // 種別 // 種別ごとのパラメータ union { @@ -162,25 +271,46 @@ class Debugger final // n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。 int32 skip {}; // スキップ回数 (ユーザ指定値) int32 skipremain {}; // 残りスキップ回数 (0 で成立) - } breakpoint_t; + }; static const int MAX_BREAKPOINTS = 8; public: Debugger(); - ~Debugger() { } + ~Debugger() override; - void Init(); - void ThreadRun(); - bool Check(); + void SetLogLevel(int) override; + bool Create() override; + bool Init() override; + void ThreadRun() override; + void Terminate() override; + + void Exec(); void NotifyException(int vector); - // ブレークポイントモニタを更新 - void MonitorBreakpoint(TextScreen& monitor); + // MPU トレースが必要なら true を返す + bool IsTrace() const; + + // FILE コールバック + int ReadFunc(char *, int); + int WriteFunc(const char *, int); + + // メモリダンプモニタ + // GUI 用 (show コマンドでも見れるけど) + std::array memdump_monitor {}; + + // m/M コマンド用のメモリダンプモニタ + Monitor m_monitor { this }; private: - bool Accept(); - bool AcquirePrompt(); - CommandAction MainLoop(); + void Close(); + void RxCallback(); + void AcceptCallback(); + void Input(int); + void EnterPrompt(); + void LeavePrompt(); + void PrintPrompt(); + + CommandAction Command(); bool CheckAllBreakpoints(); bool CheckBreakpointInst(breakpoint_t&); void ParseCmdbuf(); @@ -191,6 +321,7 @@ class Debugger final void cmd_bv(); void cmd_b_list(); void cmd_b_set(BreakpointType); + void cmd_b_delete(); void cmd_brhist(); void cmd_bx(); void cmd_c(); @@ -218,11 +349,12 @@ class Debugger final void cmd_show(); void cmd_t(); + bool Check(); int AddBreakpoint(const breakpoint_t&); void RecalcInstMask(); bool GetAddr(saddr_t *addr, bool); void cmd_d_common(MemoryMode access_mode, MMULookupMode lookup_mode); - void cmd_hist_common(BranchHistory& hist, uint64 flag); + void cmd_hist_common(BranchHistory& hist); void cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode); void cmd_n_common(bool); void cmd_s_common(bool); @@ -240,13 +372,26 @@ class Debugger final std::string HelpConvert(const std::string& msg); // モニターを更新して表示 - void ShowMonitor(IMonitor& monitor); + void ShowMonitor(Monitor& monitor); // テキストスクリーンを表示 void ShowTextScreen(TextScreen& screen); - DebuggerMD *md {}; // 機種依存部分 + std::unique_ptr md {}; // 機種依存部分 + + std::mutex mtx {}; + // このスレッドへのリクエスト + std::condition_variable cv_request {}; + uint32 request {}; + // コマンドモード(プロンプト)なら true + std::condition_variable cv_prompt {}; + bool prompt_released {}; + + bool is_prompt {}; + + // コンソール + std::unique_ptr hostcom /*{}*/; + FILE *cons {}; - Console *cons {}; // 入出力 const char *prompt {}; // プロンプト文字列 std::string cmdbuf {}; // 現在のコマンドライン std::string last_cmdbuf {}; // 直前のコマンドライン @@ -275,110 +420,31 @@ class Debugger final // 一度VMを実行して再びプロンプトに来たら true bool is_continued {}; + // MPU を一時停止するとき true (ワンショット) + bool is_pause {}; + // プロンプトで表示するレジスタ群 std::vector disp_regs {}; - static std::vector cmdtable; -}; - -// デバッガの CPU 依存部分 -class DebuggerMD -{ - public: - DebuggerMD(Debugger *parent_, Debugger::Arch arch_) { - parent = parent_; - arch = arch_; - } - virtual ~DebuggerMD(); - - // CPU のリクエストフラグに flag を立てる - virtual void ReqSet(uint32 flag) = 0; - // CPU のリクエストフラグから flag を落とす - virtual void ReqClr(uint32 flag) = 0; - - // 特権モードなら true を返す - virtual bool IsSuper() const = 0; - // MMU が有効なら true を返す - virtual bool MMUEnabled() const = 0; + // ブレークポイント到達メッセージ + // (コンソールが獲得できるまで保留しておくため) + std::string bpointmsg {}; + + // ブレークポイントモニタ + DECLARE_MONITOR_CALLBACK(MonitorUpdateBpoint); + Monitor bpoint_monitor { this }; - // アドレス変換をする。 - // MMUEnabled() が true であることは呼び出し側が確認すること。 - // lookup が true ならテーブルサーチまで行う。 - // 変換できなければ (uint64)-1 を返す。 - virtual uint64 TranslateAddr(saddr_t laddr, bool lookup) const = 0; + // メモリダンプモニタ + DECLARE_MONITOR_CALLBACK(MonitorUpdateMemdump); - // 現在の命令先頭アドレスを返す - virtual uint32 GetPC() const = 0; + // ベクタテーブル + std::unique_ptr pVectorTable /*{}*/; - // ステップアウトを設定する - virtual void SetStepOut() = 0; - // ステップアウトなら true を返す - virtual bool IsStepOut() const = 0; - - // この命令がステップイン出来るなら true を返す (cmd_n 用) - virtual bool IsOpStepIn(DebuggerMemoryStream& mem) = 0; - - // name で示されるのレジスタの値を返す。 - // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは - // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて - // よい。また m680x0 の SRP/CRP は下位32ビットでよい。 - // name が正しくない場合は (uint64)-1 を返す。 - virtual uint64 GetRegAddr(const char *name) const = 0; - - // 現在のレジスタセットを内部にバックアップする - virtual void BackupRegs() = 0; - - // レジスタ表示系のコマンドを実行。処理すれば true を返す。 - virtual bool ShowRegister(Console *cons, - const std::vector& args) = 0; - // レジスタ表示系コマンドのヘルプ一覧を取得 - virtual const HelpMessages& GetHelpListReg() const = 0; - // レジスタ表示系コマンドのヘルプメッセージを取得 - virtual const HelpMessages& GetHelpReg() const = 0; - - // ブランチ履歴・例外履歴(オブジェクト)を取得 - virtual BranchHistory& GetBrHist() const = 0; - virtual BranchHistory& GetExHist() const = 0; - - // 直近の命令でアクセスした laddr が一致したら true を返す - // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する - virtual bool CheckLEA(uint32 laddr) = 0; - - // 逆アセンブル。 - // mem.laddr の位置の命令を一つ逆アセンブルする。 - // 成功すれば true を返し、失敗すれば(?) false を返す。 - // 成功した場合 mnemonic に逆アセンブルした文字列が、 - // bin にこの命令のバイナリ列が格納されている。 - // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。 - // bin はメモリイメージのバイト順で格納すること。 - virtual bool Disassemble(DebuggerMemoryStream& mem, - std::string& mnemonic, std::vector& bin) = 0; - - // 逆アセンブルをフォーマット。 - // オフライン版は逆アセンブルウィンドウなど、 - // オンライン版(Live) はデバッガプロンプトで表示するやつ。 - virtual std::string FormatDisasm(const std::string& mnemonic, - const std::vector& bin) = 0; - virtual std::string FormatDisasmLive(const std::string& mnemonic, - const std::vector& bin) = 0; - - // 例外のベクタ番号から名前を取得。 - virtual const char *GetExceptionName(int vector) const = 0; - - // 機種 - Debugger::Arch arch {}; - - // ベクタ番号の最大値 (+1) - int vector_max {}; - // 最短の1命令のバイト数 - uint inst_bytes {}; - // 命令が固定長ならそのバイト数、可変長なら 0 - uint inst_bytes_fixed {}; - - protected: - Debugger *parent {}; // 親クラス + static std::vector cmdtable; }; +extern Debugger *gDebugger; + #define NORM "\x1b[0m" #define BOLD "\x1b[1m" #define BOLDIF(n) ((n) ? BOLD : "")