--- nono/debugger/debugger_private.h 2026/04/29 17:04:54 1.1.1.7 +++ nono/debugger/debugger_private.h 2026/04/29 17:05:49 1.1.1.14 @@ -4,315 +4,33 @@ // Licensed under nono-license.txt // +// +// デバッガ (内部用) +// + #pragma once -#include "branchhistory.h" +#include "debugger_defs.h" #include "bus.h" -#include "cvprompt.h" -#include "monitor.h" -#include "textscreen.h" -#include - -using ConstStringPair = std::pair; -using HelpMessages = std::vector; - -// 諸情報付きのアドレス -class saddr_t -{ - public: - // コンストラクタ - saddr_t() { } - - saddr_t(uint32 addr_, bool super_) - : saddr_t(addr_, super_, false) { } - - saddr_t(uint32 addr_, bool super_, bool data_) { - Set(addr_, super_, data_); - } - // コピーコンストラクタ - saddr_t(const saddr_t& rhs) { - Set(rhs); - } - // 代入演算子 - saddr_t& operator=(const saddr_t& rhs) { - Set(rhs); - return *this; - } - - // 代入演算子 (uint32 を代入するとアドレスだけ差し替える) - saddr_t& operator=(uint32 rhs) { - SetAddr(rhs); - return *this; - } - - // 代入 - void Set(uint32 addr_, bool super_, bool data_) { - addr = addr_; - super = super_; - data = data_; - } - - uint32 GetAddr() const { return addr; } - bool IsSuper() const { return super; } - bool IsData() const { return data; } - void SetAddr(uint32 addr_) { addr = addr_; } - void SetSuper(bool super_) { super = super_; } - void SetData(bool data_) { data = data_; } - - // (uint32)saddr でアドレスだけ取り出せると楽 - explicit operator uint32() const { return GetAddr(); } - - // saddr += n でアドレス進められると楽 - uint32 operator+=(uint32 val) { - addr += val; - return addr; - } - // saddr++ でアドレス進められると楽 - void operator++(int n) { - addr++; - } - - private: - void Set(const saddr_t& rhs) { - addr = rhs.addr; - super = rhs.super; - data = rhs.data; - } - - uint32 addr {}; // アドレス (32bit) - bool super {}; // スーパーバイザアクセスなら true - bool data {}; // データ空間アクセスなら true -}; - -enum class MemoryMode : bool -{ - Logical = false, - Physical = true, -}; - -enum class MMULookupMode : bool -{ - False = false, - True = true, - // MemoryMode::Physical ならこの項は意味を持たないので、 - // True でも False でもないと言いたい。 - None = false, -}; - -// saddr_t の後で Debugger の前... -#include "debugger_memory.h" -class Console; -class DebuggerMD; -class Disasm; +class IODevice; -class Debugger final : public Object +enum class CPUState { - using inherited = Object; - friend class DebuggerMD_m680x0; - friend class DebuggerMD_m88xx0; - public: - enum class Arch { - M680x0, - M88xx0, - }; - - private: - // 型 - enum CommandAction { - Stay, // デバッガプロンプトに留まる - Leave, // デバッガプロンプトを抜けて VM を実行する - Quit, // デバッガとの接続を終了する - }; - using cmdfunc_t = void (Debugger::*)(); - typedef struct { - const char *name; - cmdfunc_t func; - CommandAction action; - } cmddef_t; - - // ブレークポイント種別 - enum BreakpointType { - Unused = 0, - Address, // このアドレスに来る直前 - Memory, // このアドレスをアクセスした直後 - Exception, // この例外を検出した直後 - Instruction, // この命令を実行する直前 - }; - - // ブレークポイント - typedef struct { - BreakpointType type {}; // 種別 - // 種別ごとのパラメータ - union { - uint32 addr {}; // ターゲットアドレス (Address/Memory) - struct { - int vec1; // ベクタ番号 (開始) - int vec2; // ベクタ番号 (終了) - }; - struct { - uint32 inst; // 命令ワード - uint32 mask; // マスク - }; - }; - - uint32 matched {}; // 成立回数 (積算) - - // skip はユーザ指定値。ただし - // -1 なら常にスキップ、つまりブレークせずカウントのみ行う、 - // 0 ならスキップなし、つまり成立ごとにブレーク(これがデフォルト)、 - // n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。 - int32 skip {}; // スキップ回数 (ユーザ指定値) - int32 skipremain {}; // 残りスキップ回数 (0 で成立) - } breakpoint_t; - static const int MAX_BREAKPOINTS = 8; - - public: - Debugger(); - ~Debugger() { } - - void Init(); - void ThreadRun(); - bool Check(); - void NotifyException(int vector); - - // メモリダンプモニタ - // GUI 用 (show コマンドでも見れるけど) - std::array memdump_monitor; - - // m/M コマンド用のメモリダンプモニタ - Monitor m_monitor { this }; - - private: - bool Accept(); - bool AcquirePrompt(); - CommandAction MainLoop(); - bool CheckAllBreakpoints(); - bool CheckBreakpointInst(breakpoint_t&); - void ParseCmdbuf(); - // コマンド名は大文字小文字を区別する関係でスネークスタイル。 - void cmd_b(); - void cmd_bi(); - void cmd_bm(); - void cmd_bv(); - void cmd_b_list(); - void cmd_b_set(BreakpointType); - void cmd_brhist(); - void cmd_bx(); - void cmd_c(); - void cmd_d(); - void cmd_dt(); - void cmd_D(); - void cmd_disp(); - void cmd_exhist(); - void cmd_h(); - void cmd_hb(); - void cmd_hr(); - void cmd_L(); - void cmd_m(); - void cmd_mt(); - void cmd_M(); - void cmd_minus(); - void cmd_n(); - void cmd_nt(); - void cmd_q(); - void cmd_reset(); - void cmd_s(); - void cmd_st(); - void cmd_so(); - void cmd_sot(); - void cmd_show(); - void cmd_t(); - - 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); - void cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode); - void cmd_n_common(bool); - void cmd_s_common(bool); - void cmd_so_common(bool); - bool ParseVerbHex(const char *arg, uint32 *valp); - bool ParseAddr(const char *arg, uint32_t *addrp); - void SetNBreakpoint(); - - static const HelpMessages HelpListMain; - static const HelpMessages HelpListBreakpoints; - static const HelpMessages HelpDetails; - void ShowHelpList(const HelpMessages& msgs); - - // 個別ヘルプメッセージを出力用に置換 - std::string HelpConvert(const std::string& msg); - - // モニターを更新して表示 - void ShowMonitor(Monitor& monitor); - // テキストスクリーンを表示 - void ShowTextScreen(TextScreen& screen); - - DebuggerMD *md {}; // 機種依存部分 - - Console *cons {}; // 入出力 - const char *prompt {}; // プロンプト文字列 - std::string cmdbuf {}; // 現在のコマンドライン - std::string last_cmdbuf {}; // 直前のコマンドライン - std::vector args {}; - - uint32 pc {}; - std::vector ir {}; // この後実行する命令のバイナリ列 - std::array bpoint {}; - bool bc_enable {}; - uint32 bc_addr {}; - uint32 bi_inst {}; - int bi_inst_bytes {}; - int bi_need_bytes {}; - int bv_vector = -1; - saddr_t d_last_addr {}; - saddr_t m_last_addr {}; - bool n_enable {}; - uint32 n_breakaddr {}; - uint32 n_count {}; - bool s_enable {}; - uint32 s_count {}; - bool so_enable {}; - bool t_enable {}; - uint32 t_count {}; - - // 一度VMを実行して再びプロンプトに来たら true - bool is_continued {}; - - // プロンプトで表示するレジスタ群 - std::vector disp_regs {}; - - // ブレークポイント到達メッセージ - // (コンソールが獲得できるまで保留しておくため) - std::string bpointmsg {}; - - // ブレークポイントモニタ - DECLARE_MONITOR_CALLBACK(MonitorUpdateBpoint); - Monitor bpoint_monitor { this }; - - // メモリダンプモニタ - DECLARE_MONITOR_CALLBACK(MonitorUpdateMemdump); - - static std::vector cmdtable; + Normal = 0, + Stop, // STOP 命令など割り込み待ち状態 + Halt, // ホールト、リセットなど非動作状態 }; // デバッガの CPU 依存部分 class DebuggerMD { public: - DebuggerMD(Debugger *parent_, Debugger::Arch arch_) { - parent = parent_; - arch = arch_; - } + DebuggerMD(Debugger *parent_, CPUArch arch_); virtual ~DebuggerMD(); - // CPU のリクエストフラグに flag を立てる - virtual void ReqSet(uint32 flag) = 0; - // CPU のリクエストフラグから flag を落とす - virtual void ReqClr(uint32 flag) = 0; - + // CPU の実行状態を返す。 + virtual CPUState GetCPUState() const = 0; // 特権モードなら true を返す virtual bool IsSuper() const = 0; // MMU が有効なら true を返す @@ -320,9 +38,9 @@ class DebuggerMD // アドレス変換をする。 // MMUEnabled() が true であることは呼び出し側が確認すること。 - // lookup が true ならテーブルサーチまで行う。 - // 変換できなければ (uint64)-1 を返す。 - virtual uint64 TranslateAddr(saddr_t laddr, bool lookup) const = 0; + // 変換出来なければ BusAddr::BusErr を返す。 + // テーブルサーチを行ったら BusAddr::TableSearched を立てる。 + virtual busaddr TranslateAddr(busaddr laddr) const = 0; // 現在の命令先頭アドレスを返す virtual uint32 GetPC() const = 0; @@ -346,54 +64,52 @@ class DebuggerMD virtual void BackupRegs() = 0; // レジスタ表示系のコマンドを実行。処理すれば true を返す。 - virtual bool ShowRegister(Console *cons, - const std::vector& args) = 0; + 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; + virtual std::string Disassemble(DebuggerMemoryStream& mem) = 0; + + // ニーモニックに対応する機械語文字列を返す。(cmd_bi 用) + virtual std::string ParseInst(const std::string&) const = 0; + + // 機種名を取得する + const std::string& GetName() const { return name; } - // 例外のベクタ番号から名前を取得。 - virtual const char *GetExceptionName(int vector) const = 0; + // この CPU のバスを返す + IODevice *GetBus() const { return bus; } + // このバスの論理アドレス幅 (ビット数) を返す + int GetLASize() const { return lasize; } + // このバスの物理アドレス幅 (ビット数) を返す + int GetPASize() const { return pasize; } // 機種 - Debugger::Arch arch {}; + CPUArch arch {}; - // ベクタ番号の最大値 (+1) - int vector_max {}; // 最短の1命令のバイト数 uint inst_bytes {}; // 命令が固定長ならそのバイト数、可変長なら 0 uint inst_bytes_fixed {}; + // 例外ブレーク。 + // 機種固有ではないが main と xp でそれぞれに必要なので、ここに持っておく。 + int bv_vector {}; + protected: Debugger *parent {}; // 親クラス + + std::string name {}; // 機種名 + + IODevice *bus {}; // 対応する外部バス + int lasize {}; // バスの論理アドレス幅 + int pasize {}; // バスの物理アドレス幅 }; #define NORM "\x1b[0m"