|
|
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);
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.