File:  [Isaki's NoNo m68k/m88k emulator] / nono / debugger / debugger_hd64180.cpp
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:58 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//

//
// デバッガ (HD64180 依存部分)
//

#include "debugger_hd64180.h"
#include "debugger_memory.h"
#include "xpbus.h"

// コンストラクタ
DebuggerMD_hd64180::DebuggerMD_hd64180(Debugger *parent_)
	: inherited(parent_, CPUArch::HD64180)
{
	// この時点で Get*Device() は使える
	cpu = GetMPU64180Device();
	bus = GetXPbusDevice();

	// 機種依存変数
	inst_bytes = 1;
	lasize = 16;
	pasize = 20;
	name = "xp";
}

// デストラクタ
DebuggerMD_hd64180::~DebuggerMD_hd64180()
{
}

// 動作状態を返す
CPUState
DebuggerMD_hd64180::GetCPUState() const
{
	// HD64180::OpMode を CPUState に変換
	auto opmode = cpu->GetOpMode();
	switch (opmode) {
	 case HD64180::OpMode::Normal:
		return CPUState::Normal;

	 case HD64180::OpMode::Reset:
	 case HD64180::OpMode::Halt:
	 case HD64180::OpMode::Sleep:
		return CPUState::Halt;

	 default:
		PANIC("corrupted opmode=%d", (int)opmode);
	}
}

// アドレス変換
busaddr
DebuggerMD_hd64180::TranslateAddr(busaddr laddr) const
{
	uint32 paddr = cpu->TranslatePeek(laddr.Addr());
	return busaddr(paddr);
}

// ステップアウトを設定する
void
DebuggerMD_hd64180::SetStepOut()
{
	so_sp = cpu->reg.sp;
}

bool
DebuggerMD_hd64180::IsStepOut() const
{
	return (cpu->reg.sp > so_sp);
}

// この命令がステップイン出来るなら true を返す
bool
DebuggerMD_hd64180::IsOpStepIn(DebuggerMemoryStream& mem)
{
	uint8 op = mem.Read(inst_bytes);

	if ( op == 0xcd				// CALL
	 || (op & 0xc7) == 0xc4		// CALL cc
	) {
		return true;
	}

	// LD*R, CP*R, IN*R, OT*R, OT*MR もステップイン扱いにしてみる。
	if (op == 0xed) {
		uint8 op2 = mem.Read(inst_bytes);
		if ((op2 & 0xd0) == 0x90) {
			return true;
		}
	}

	return false;
}

// name で示されるレジスタの値を返す。
// メモリダンプのような用途なので主にアドレスとして使うレジスタのみ。
uint64
DebuggerMD_hd64180::GetRegAddr(const char *name) const
{
	uint32 addr;

	if (strcmp(name, "pc") == 0) {
		addr = cpu->GetPPC();

	} else if (strcmp(name, "sp") == 0) {
		addr = cpu->reg.sp;

	} else if (strcmp(name, "bc") == 0) {
		addr = cpu->reg.GetBC();

	} else if (strcmp(name, "de") == 0) {
		addr = cpu->reg.GetDE();

	} else if (strcmp(name, "hl") == 0) {
		addr = cpu->reg.GetHL();

	} else if (strcmp(name, "ix") == 0) {
		addr = cpu->reg.ix;

	} else if (strcmp(name, "iy") == 0) {
		addr = cpu->reg.iy;

	} else {
		return (uint64)-1;
	}
	return addr;
}

void
DebuggerMD_hd64180::BackupRegs()
{
	prev = cpu->reg;
	prev_i = cpu->GetI();
}

// レジスタ表示系コマンド
bool
DebuggerMD_hd64180::ShowRegister(FILE *cons,
	const std::vector<std::string>& args)
{
	// 余分な引数は無視する?

	if (args[0] == "r") {
		ShowRegMain(cons);
		return true;
	}
	if (args[0] == "ro") {
		ShowRegOther(cons);
		return true;
	}

	// 該当なし
	return false;
}

bool
DebuggerMD_hd64180::ShowRegMain(FILE *cons)
{
	// AF:00 00 (------)  PC:0000   AF':00 00
	// BC:00 00           SP:0000   BC':00 00
	// DE:00 00  IX:0000   I:00     DE':00 00
	// HL:00 00  IY:0000   R:00     HL':00 00

	uint8 reg_i = cpu->GetI();
	uint8 reg_r = cpu->GetR();

	bool va = (cpu->reg.a != prev.a);
	bool vf = (cpu->reg.f.Get() != prev.f.Get());
	bool vb = (cpu->reg.b != prev.b);
	bool vc = (cpu->reg.c != prev.c);
	bool vd = (cpu->reg.d != prev.d);
	bool ve = (cpu->reg.e != prev.e);
	bool vh = (cpu->reg.h != prev.h);
	bool vl = (cpu->reg.l != prev.l);
	bool vix = (cpu->reg.ix != prev.ix);
	bool viy = (cpu->reg.iy != prev.iy);
	bool vsp = (cpu->reg.sp != prev.sp);

	bool vxa = (cpu->reg.ex.a != prev.ex.a);
	bool vxf = (cpu->reg.ex.f.Get() != prev.ex.f.Get());
	bool vxb = (cpu->reg.ex.b != prev.ex.b);
	bool vxc = (cpu->reg.ex.c != prev.ex.c);
	bool vxd = (cpu->reg.ex.d != prev.ex.d);
	bool vxe = (cpu->reg.ex.e != prev.ex.e);
	bool vxh = (cpu->reg.ex.h != prev.ex.h);
	bool vxl = (cpu->reg.ex.l != prev.ex.l);

	bool vi = (reg_i != prev_i);

	std::string fstr1 = FlagStr(cpu->reg.f);
	fprintf(cons, "AF:%s%02x%s %s%02x%s (%s)  PC:%04x   "
			"AF':%s%02x%s %s%02x%s\n",
		BOLDIF(va), cpu->reg.a, NORM,
		BOLDIF(vf), cpu->reg.f.Get(), NORM,
		fstr1.c_str(),
		cpu->reg.pc,
		BOLDIF(vxa), cpu->reg.ex.a, NORM,
		BOLDIF(vxf), cpu->reg.ex.f.Get(), NORM);
	fprintf(cons, "BC:%s%02x%s %s%02x%s           SP:%s%04x%s   "
			"BC':%s%02x%s %s%02x%s\n",
		BOLDIF(vb),  cpu->reg.b,	NORM,
		BOLDIF(vc),  cpu->reg.c,	NORM,
		BOLDIF(vsp), cpu->reg.sp,	NORM,
		BOLDIF(vxb), cpu->reg.ex.b,	NORM,
		BOLDIF(vxc), cpu->reg.ex.c,	NORM);
	fprintf(cons, "DE:%s%02x%s %s%02x%s  IX:%s%04x%s   I:%s%02x%s     "
			"DE':%s%02x%s %s%02x%s\n",
		BOLDIF(vd),    cpu->reg.d,		NORM,
		BOLDIF(ve),    cpu->reg.e,		NORM,
		BOLDIF(vix),   cpu->reg.ix,		NORM,
		BOLDIF(vi),    reg_i,			NORM,
		BOLDIF(vxe),   cpu->reg.ex.d,	NORM,
		BOLDIF(vxd),   cpu->reg.ex.e,	NORM);
	fprintf(cons, "HL:%s%02x%s %s%02x%s  IY:%s%04x%s   R:%02x     "
			"HL':%s%02x%s %s%02x%s\n",
		BOLDIF(vh),    cpu->reg.h,		NORM,
		BOLDIF(vl),    cpu->reg.l,		NORM,
		BOLDIF(viy),   cpu->reg.iy,		NORM,
		reg_r,
		BOLDIF(vxh),   cpu->reg.ex.h,	NORM,
		BOLDIF(vxl),   cpu->reg.ex.l,	NORM);

	return true;
}

std::string
DebuggerMD_hd64180::FlagStr(const hd64180flag& f)
{
	std::string buf;

	buf += f.IsS() ? 'S' : '-';
	buf += f.IsZ() ? 'Z' : '-';
	buf += f.IsH() ? 'H' : '-';
	buf += f.IsV() ? 'V' : (f.IsP() ? 'P' : '-');
	buf += f.IsN() ? 'N' : '-';
	buf += f.IsC() ? 'C' : '-';

	return buf;
}

bool
DebuggerMD_hd64180::ShowRegOther(FILE *cons)
{
	fprintf(cons, "IEF1: %s\n", cpu->GetIEF1() ? "Enable" : "Disable");
	fprintf(cons, "IEF2: %s\n", cpu->GetIEF2() ? "Enable" : "Disable");
	return true;
}

// レジスタ表示系コマンドのヘルプ
/*static*/ const HelpMessages
DebuggerMD_hd64180::HelpListReg = {
	{ "r",		"Show general registers" },
	{ "ro",		"Show some internal statuses" },
};

/*static*/ const HelpMessages
DebuggerMD_hd64180::HelpReg = {
	//-----
	{ "r", R"**(
	Command: r

	Shows general registers.
	)**" },

	//-----
	{ "ro", R"**(
	Command: ro

	Show some internal statuses.
	)**" },
};

const HelpMessages&
DebuggerMD_hd64180::GetHelpListReg() const
{
	return HelpListReg;
}

const HelpMessages&
DebuggerMD_hd64180::GetHelpReg() const
{
	return HelpReg;
}

std::string
DebuggerMD_hd64180::Disassemble(DebuggerMemoryStream& mem)
{
	hd64180disasm dis;
	if (dis.Exec(&mem) == false) {
		return "dis.Exec() failed.";
	}

	// dis.bin は uint8 列なのでそのままダンプ。
	std::string str;
	for (auto v : dis.bin) {
		str += string_format("%02x ", v);
	}
	// ダンプは最長5バイト分
	str += std::string((5 - dis.bin.size()) * 3, ' ');

	// ニーモニック
	str += dis.text;
	// (あれば) 条件判断
	str += CondStr(dis.bin);

	return str;
}

// ops が条件命令なら、成立可否などの文字列を返す。
const char *
DebuggerMD_hd64180::CondStr(const std::vector<uint8>& ops) const
{
	if (ops[0] == 0x10) {	// DJNZ
		if (cpu->reg.b == 0) {
			return " (will expire)";
		} else {
			return " (will take)";
		}
	}

	if ((ops[0] & 0xc7) == 0xc0		// RET f
	 || (ops[0] & 0xc7) == 0xc2		// JP f
	 || (ops[0] & 0xc7) == 0xc4)	// CALL f
	{
		if (cpu->reg.f.IsCond((ops[0] >> 3) & 7)) {
			return " (will take)";
		} else {
			return " (will not take)";
		}
	}

	// JR は f と同じ形式だが1ビット少ないだけ
	if ((ops[0] & 0xe7) == 0x20) {
		if (cpu->reg.f.IsCond((ops[0] >> 3) & 3)) {
			return " (will take)";
		} else {
			return " (will not take)";
		}
	}

	// 条件命令ではない
	return "";
}

// 命令ニーモニックに対するバイナリを文字列形式で返す。
// 対応しない場合は "" を返す。cmd_bi 用。
std::string
DebuggerMD_hd64180::ParseInst(const std::string& inst) const
{
	return "";
}

unix.superglobalmegacorp.com

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