--- nono/debugger/debugger_private.h 2026/04/29 17:04:30 1.1.1.1 +++ nono/debugger/debugger_private.h 2026/04/29 17:05:49 1.1.1.14 @@ -1,200 +1,36 @@ // // nono -// Copyright (C) 2020 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// デバッガ (内部用) // #pragma once -#include "header.h" +#include "debugger_defs.h" #include "bus.h" -#include "cvprompt.h" -#include "textscreen.h" - -// 諸情報付きのアドレス -struct saddr_t -{ - uint32 addr = 0; // アドレス(32bit) - // addr が論理アドレスなら true。 - // MMU の有効/無効状態はここにセットするのではなく、メモリアクセスに - // 際してアドレス変換を行う側がその時点で改めてチェックするので、 - // ここはどちらかというと物理アドレスなら false くらいの意味合い。 - bool logical = false; - - // addr が論理アドレスの場合に、テーブルサーチも行うなら true。 - // false なら TT、ATC のみ検索する。 - bool search = false; - - // addr がスーパバイザアクセスなら true。 - bool super = false; - - // addr がデータアクセスなら true。 - bool data = false; - - // コンストラクタ - saddr_t() {} - // コピーコンストラクタ - saddr_t(const saddr_t& lhs) { - addr = lhs.addr; - logical = lhs.logical; - search = lhs.search; - super = lhs.super; - data = lhs.super; - } - - bool IsLogical() const { return logical; } - bool IsSearch() const { return search; } - bool IsSuper() const { return super; } - bool IsData() const { return data; } - bool IsInst() const { return !data; } - - // (論理)アドレスと Super/User ビットを合わせた 33bit アドレスを返す - uint64 GetSaddr() const { - uint64 sa = addr; - if (IsSuper()) { - sa |= 0x100000000ULL; - } - return sa; - } -}; - -enum MemdumpMode { - Physical = 0, // 物理アドレス - Logical_atc, // 論理アドレス (ただし TT、ATC のみ検索) - Logical_search, // 論理アドレス (TT、ATC、テーブルサーチすべて行う) -}; +class IODevice; -class Console; -class DebuggerMD; -class Disasm; - -class Debugger +enum class CPUState { - friend class DebuggerMD_m680x0; - friend class DebuggerMD_m88xx0; - private: - // 型 - typedef void (Debugger::*cmdfunc_t)(); - typedef struct { - const char *name; - cmdfunc_t func; - } cmddef_t; - - // ブレークポイント - typedef struct { - bool enable; - bool ismemory; - uint32 addr; - uint32 count; - } breakpoint_t; - static const int MAX_BREAKPOINTS = 8; - - public: - Debugger(); - virtual ~Debugger() { } - - void Init(); - void ThreadRun(); - bool Check(); - - private: - bool MainLoop(); - cmddef_t *ParseCmd(); - // コマンド名は大文字小文字を区別する関係でスネークスタイル。 - void cmd_b(); - void cmd_b_list(); - void cmd_brhist(); - void cmd_bx(); - void cmd_c(); - void cmd_d(); - void cmd_dt(); - void cmd_D(); - void cmd_h(); - void cmd_L(); - void cmd_m(); - void cmd_mt(); - void cmd_M(); - void cmd_minus(); - void cmd_n(); - void cmd_q(); - void cmd_r(); - void cmd_ra(); - void cmd_rc(); - void cmd_rf(); - void cmd_rm(); - void cmd_ro(); - void cmd_s(); - void cmd_so(); - void cmd_show(); - void cmd_t(); - void cmd_unknown(); - - int AddBreakpoint(uint32 addr, bool ismemory); - void Continue(); - bool GetAddr(uint32& addr, uint32& lastaddr); - void cmd_d_common(MemdumpMode mode); - void cmd_m_common(MemdumpMode mode); - bool ParseAddr(const char *arg, uint32_t *addrp); - bool SetNBreakpoint(); - - void HelpMain(); - - void ShowMonitor(TextScreen& monitor); - // アドレスをダンプ表示用に整形して返す - bool FormatDumpAddr(saddr_t addr, std::string& addrstr); - - DebuggerMD *md = NULL; // 機種依存部分 - - Console *cons = NULL; // 入出力 - const char *prompt; // プロンプト文字列 - std::string cmdbuf {}; // 現在のコマンドライン - std::string last_cmdbuf {}; // 直前のコマンドライン - int ac = 0; - std::string strav[10] { {}, }; - const char *av[10] {}; - - uint32 pc = 0; - uint32 nextpc = 0; - std::vector ir {}; // この後実行する命令のバイナリ列 - breakpoint_t bpoint[MAX_BREAKPOINTS] {}; - bool bc_enable = false; - uint32 bc_addr = 0; - uint32 d_last_addr = 0; - uint32 m_last_addr = 0; - bool n_enable = false; - bool n_breakenable = false; - uint32 n_breakaddr = 0; - uint32 n_count = 0; - bool s_enable = false; - uint32 s_count = 0; - bool so_enable = false; - bool t_enable = false; - uint32 t_count = 0; - - // 一度VMを実行して再びプロンプトに来たら true - bool is_continued = false; - - static cmddef_t cmdtable[]; - static cmddef_t cmdtable_unknown; + Normal = 0, + Stop, // STOP 命令など割り込み待ち状態 + Halt, // ホールト、リセットなど非動作状態 }; // デバッガの CPU 依存部分 class DebuggerMD { public: - DebuggerMD(Debugger *arg) { - parent = arg; - - // 奇数にしておくことで初回に必ずアドレス変換を起こさせる。 - last_lpage.addr = 0xffffffff; - } - virtual ~DebuggerMD() { } - - // CPU のリクエストフラグに flag を立てる - virtual void ReqSet(uint32 flag) = 0; - // CPU のリクエストフラグから flag を落とす - virtual void ReqClr(uint32 flag) = 0; + DebuggerMD(Debugger *parent_, CPUArch arch_); + virtual ~DebuggerMD(); + // CPU の実行状態を返す。 + virtual CPUState GetCPUState() const = 0; // 特権モードなら true を返す virtual bool IsSuper() const = 0; // MMU が有効なら true を返す @@ -202,8 +38,9 @@ class DebuggerMD // アドレス変換をする。 // MMUEnabled() が true であることは呼び出し側が確認すること。 - // 変換できなければ (uint64)-1 を返す。 - virtual uint64 TranslateAddr(saddr_t laddr) = 0; + // 変換出来なければ BusAddr::BusErr を返す。 + // テーブルサーチを行ったら BusAddr::TableSearched を立てる。 + virtual busaddr TranslateAddr(busaddr laddr) const = 0; // 現在の命令先頭アドレスを返す virtual uint32 GetPC() const = 0; @@ -213,6 +50,9 @@ class DebuggerMD // ステップアウトなら true を返す virtual bool IsStepOut() const = 0; + // この命令がステップイン出来るなら true を返す (cmd_n 用) + virtual bool IsOpStepIn(DebuggerMemoryStream& mem) = 0; + // name で示されるのレジスタの値を返す。 // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて @@ -223,42 +63,53 @@ class DebuggerMD // 現在のレジスタセットを内部にバックアップする virtual void BackupRegs() = 0; - // レジスタの一覧を cons に出力 - virtual void ShowRegMain(Console *cons) = 0; - virtual void ShowRegCtrl(Console *cons) = 0; - virtual void ShowRegFPU(Console *cons) = 0; - virtual void ShowRegMMU(Console *cons) = 0; - virtual void ShowRegATC(Console *cons) = 0; - virtual void ShowRegOther(Console *cons) = 0; + // レジスタ表示系のコマンドを実行。処理すれば true を返す。 + virtual bool ShowRegister(FILE *, const std::vector& args) = 0; + // レジスタ表示系コマンドのヘルプ一覧を取得 + virtual const HelpMessages& GetHelpListReg() const = 0; + // レジスタ表示系コマンドのヘルプメッセージを取得 + virtual const HelpMessages& GetHelpReg() const = 0; // 直近の命令でアクセスした laddr が一致したら true を返す // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する virtual bool CheckLEA(uint32 laddr) = 0; - // 逆アセンブル。 - // laddr の位置の命令を一つ逆アセンブルする。 - // 成功すれば true を返し、失敗すれば(?) false を返す。 - // 成功した場合 mnemonic に逆アセンブルした文字列が、 - // bin にこの命令のバイナリ列が格納されている。 - // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。 - // bin はメモリイメージのバイト順で格納すること。 - virtual bool Disassemble(saddr_t laddr, - 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; + // mem.laddr の位置の命令を一つ逆アセンブルする。 + 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; } + + // この CPU のバスを返す + IODevice *GetBus() const { return bus; } + // このバスの論理アドレス幅 (ビット数) を返す + int GetLASize() const { return lasize; } + // このバスの物理アドレス幅 (ビット数) を返す + int GetPASize() const { return pasize; } + + // 機種 + CPUArch arch {}; + + // 最短の1命令のバイト数 + uint inst_bytes {}; + // 命令が固定長ならそのバイト数、可変長なら 0 + uint inst_bytes_fixed {}; + + // 例外ブレーク。 + // 機種固有ではないが main と xp でそれぞれに必要なので、ここに持っておく。 + int bv_vector {}; protected: - Debugger *parent; // 親クラス + Debugger *parent {}; // 親クラス + + std::string name {}; // 機種名 - // 前回アクセス時の論理ページ。.addr == 0xffffffff なら無効。 - saddr_t last_lpage; - uint32 last_ppage; + IODevice *bus {}; // 対応する外部バス + int lasize {}; // バスの論理アドレス幅 + int pasize {}; // バスの物理アドレス幅 }; #define NORM "\x1b[0m"