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

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

//
// ブランチ履歴
//

#pragma once

#include "object.h"

class VectorTable;

// MPU に依存しないブランチ履歴。
//
// count = 0 なら書き込み前の無効エントリを示す。
// top がカーソルで、8ビットなので勝手に循環する。
// 直近と同じジャンプが連続する場合 count だけを増加させたいため、top は
// 次回の書き込み位置ではなく、直近の書き込み位置を指すことに注意。
//
// BranchHistory クラスはモニタを持つので Object からの継承になっているが
// 他の多くの Object 派生クラスと違ってグローバル参照は用意していない。
// というのもどの MPU のブランチ履歴かなので、MPU クラスから辿ることにする。

class BranchHistory : public Object
{
	using inherited = Object;

 protected:
	struct BranchEntry {
		uint32 count;	// 連続通過回数
		uint32 from;	// ジャンプ元アドレス(VA)
		uint32 to;		// ジャンプ先アドレス(VA)
		uint32 info;	// ジャンプ元命令や例外情報など (機種による)
	} __packed;

 public:
	// 表示系フラグ
	static const uint64 BottomToTop	= (1ULL << 63);	// 新しい方を下に

 public:
	explicit BranchHistory(uint objid_);
	~BranchHistory() override;

	// 初期化
	void Clear();

	// エントリを追加。
	// エントリを返す。
	const BranchEntry& AddEntry(uint32 from, uint32 to, uint32 info) {
		BranchEntry *e = &entry[top];

		if (e->from == from && e->to == to && e->info == info) {
			// 前回と同じなら通過回数++
			e->count++;
		} else {
			// そうでなければ、新規エントリ
			top++;
			e = &entry[top];
			e->count = 1;
			e->from  = from;
			e->to    = to;
			e->info  = info;
		}
		return *e;
	}

	// 使用中のエントリ数を取得する
	int GetUsed() const;

	// 16バイト単位のテーブルなので16バイト境界に整列がよかろう。
	alignas(16) BranchEntry entry[256] {};
	// 直近に使用した位置
	uint8 top {};

	// モニタ (デバッガから直接参照する)
	Monitor *monitor {};

 protected:
	virtual std::string FormatHeader() const;
	virtual std::string FormatEntry(const BranchEntry& e) = 0;

	DECLARE_MONITOR_SCREEN(MonitorScreen);

	// 例外履歴かどうか。ヘッダ行が違う。
	bool is_exhist {};

	// カウンタの表示開始座標 (HD64180 だけ違うため)
	int x_count {};

	VectorTable *vectortable {};
};

//
// m680x0 ブランチ履歴
// (MPU に依存しないとは一体…)
//
class BranchHistory_m680x0 : public BranchHistory
{
	using inherited = BranchHistory;

	// info の分岐種別
	static constexpr uint32 NORMAL		= 0x00000000;	// 通常分岐
	static constexpr uint32 VECTORJUMP	= 0x40000000;	// ベクタによる分岐
	static constexpr uint32 SERVICECALL_HUMAN	= 0x80000000; // IOCS/DOS call
	static constexpr uint32 SERVICECALL_NETBSD	= 0x80010000; // NetBSD syscall
	static constexpr uint32 EXCEPTION	= 0xc0000000;	// 例外発生

 public:
	explicit BranchHistory_m680x0(uint objid_);
	~BranchHistory_m680x0() override;

	static constexpr uint32 InfoNormal(uint16 inst) {
		return NORMAL | inst;
	}
	static constexpr uint32 InfoVectorJump() {
		return VECTORJUMP;
	}
	static constexpr uint32 InfoException(uint8 vector) {
		return EXCEPTION | vector;
	}
	static constexpr uint32 InfoIOCSCall(uint8 num) {
		return SERVICECALL_HUMAN | num;
	}
	static constexpr uint32 InfoDOSCall(uint16 ir) {
		return SERVICECALL_HUMAN | ir;
	}
	static constexpr uint32 InfoNetBSDSyscall(uint16 syscall) {
		return SERVICECALL_NETBSD | syscall;
	}

	std::string FormatEntry(const BranchEntry& e) override;
};

//
// m88xx0 ブランチ履歴
// (MPU に依存しないとは一体…)
//
class BranchHistory_m88xx0 : public BranchHistory
{
	using inherited = BranchHistory;
 public:
	explicit BranchHistory_m88xx0(uint objid_);
	~BranchHistory_m88xx0() override;

	std::string FormatEntry(const BranchEntry& e) override;
};

//
// HD64180 ブランチ履歴
//
class BranchHistory_hd64180 : public BranchHistory
{
	using inherited = BranchHistory;
 public:
	explicit BranchHistory_hd64180(uint objid_);
	~BranchHistory_hd64180() override;

	std::string FormatHeader() const override;
	std::string FormatEntry(const BranchEntry& e) override;

 private:
	static std::string fstr(int);
};

unix.superglobalmegacorp.com

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