File:  [Isaki's NoNo m68k/m88k emulator] / nono / m88xx0 / m88200.h
Revision 1.1.1.13 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:56 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
//

// MC88200(CMMU)

#pragma once

#include "device.h"
#include "bus.h"
#include "mainbus.h"
#include <array>

#define M88200_STAT

class MPU88xx0Device;
class MainbusDevice;

// SAPR, UAPR レジスタ
struct m88200APR
{
	bool enable;
	uint32 addr;
	// stat は ACC_STAT_MASK と同じ位置の WT,G,CI のみ使用。APR に WP はない。
	uint32 stat;
	const char *name;	// 自分の名前(ログ表示用)
};

// BATC
struct m88200BATC
{
	// LBA には S, V ビットを混ぜておく。比較を1回で済ませるため。
	// V ビットは invalid なら %1 にして一致しなくしておく。
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1  0
	// +-------------------------+-------------------------+-+-------+--+
	// |           LBA           |           0             |S|   0   |~V|
	// +-------------------------+-------------------------+-+-------+--+
	static const uint32 LBAMASK	= 0xfff80000;
	static const uint32 S		= 0x00000020;
	static const uint32 INVALID	= 0x00000001;
	uint32 lba;		// LBA,S,~V
	uint32 pba;		// PBA
	// stat は ACC_STAT_MASK と同じ WT,G,CI,WP のみ使用。
	// BWP (BATC Write Port) のビット位置とは違うので注意。
	uint32 stat;
	bool wp;		// WP (比較で使うのでこれだけ抜き出しておく)

	// このエントリが有効なら true を返す
	bool IsValid() const	{ return (lba & INVALID) == 0; }
	// S ビットが立っていれば true を返す
	bool IsS() const		{ return (lba & S); }
	// 論理アドレス(32ビット)を返す
	uint32 Laddr() const	{ return (lba & LBAMASK); }
};

// PATC
struct m88200PATC
{
	// LPA には S, V ビットを混ぜておく。比較を1回で済ませるため。
	// V ビットは invalid なら %1 にして一致しなくしておく。実際の
	// PATC エントリの有効/無効は 46ビットの PATC 構造の外で管理されている?
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1  0
	// +---------------------------------------+-----------+-+-------+--+
	// |                 LPA                   |     0     |S|   0   |~V|
	// +---------------------------------------+-----------+-+-------+--+
	static const uint32 LPAMASK	= 0xfffff000;
	static const uint32 S		= 0x00000020;
	static const uint32 INVALID	= 0x00000001;
	uint32 lpa;		// LPA,S,~V
	uint32 pfa;		// PFA
	uint32 stat;	// ACC_STAT_MASK と同じ WT,G,CI,WP のみ使用。
	bool m;			// Modified
	bool wp;		// Write Protect (比較で使うのでこれだけ抜き出しておく)

	// このエントリが有効なら true を返す
	bool IsValid() const	{ return (lpa & INVALID) == 0; }
	// S ビットが立っていれば true を返す
	bool IsS() const		{ return (lpa & S); }
	// 論理アドレス(32ビット)を返す
	uint32 Laddr() const	{ return (lpa & LPAMASK); }
};

// キャッシュの1セット
class m88200CacheSet
{
 public:
	enum Status {
		EU = 0,		// Exclusive Unmodified
		EM = 1,		// Exclusive Modified
		SU = 2,		// Shared Unmodified
		IV = 3,		// Invalid
	};

	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3  2 1  0
	// +---------------------------------------+---------------+----+-+--+
	// |                tag                    |      set      |word|0|~V|
	// +---------------------------------------+---------------+----+-+--+

	// タグはアドレスの上位 20ビット。
	// ただし無効なラインかどうかのチェックも一度で済ませるために
	// 無効(vv[]==IV)ならビット 0 を 1 にしておく。比較対象の paddr は
	// 下位12ビットを落としているため、これで絶対に一致しなくなる。
	static const uint32 TAG_INVALID = 0x00000001;
	uint32 tag[4] {};

	// LRU
	// CSSP の L ビットのロジックに従う。
	uint L {};

	// ステータス
	Status vv[4] {};

	// データ。word[] は以下の順
	//       Word
	//        +0   +1   +2   +3
	// line0 [ 0] [ 1] [ 2] [ 3]
	// line1 [ 4] [ 5] [ 6] [ 7]
	// :
	uint32 word[16] {};

	// 自身のセットインデックス
	uint32 setidx {};

	// 引数 L の状態から line を最新にしたらどうなるか、を返す。
	// 表示処理で一時変数に対して処理が必要なため static 分離してある。
	static uint TryUseLine(uint tmpL, int line);

	// 引数 L の状態から line を最古にしたらどうなるか、を返す。
	// 対称性のため static 分離してある。
	static uint TryUnuseLine(uint tmpL, int line);

	// 引数 L の状態で、最新の line を返す。
	// 表示処理で一時変数に対して処理が必要なため static 分離してある。
	static int TryGetOldestLine(uint tmpL);

	void Use(int line) {
		L = TryUseLine(L, line);
	}

	// 更新用に最も古いラインを選んで差し出す
	int SelectOldestLine() const;

	void Update(uint line, Status status);

	void Write(uint line, uint32 paddr, uint32 data, uint size);

	// キャッシュを検索して、ヒットした line を返す。
	int Lookup(uint32 tagaddr) const;
};

class m88200 : public Device
{
	using inherited = Device;
 public:
	m88200(MPU88xx0Device *parent_, uint id_);
	~m88200() override;

	bool Init() override;

	// リセット (ResetHard() ではない)
	void Reset();

 private:
	DECLARE_MONITOR_SCREEN(MonitorScreenReg);
	DECLARE_MONITOR_SCREEN(MonitorScreenATC);
	DECLARE_MONITOR_SCREEN(MonitorScreenCache);

	MPU88xx0Device *parent {};

	// モニター
	Monitor *reg_monitor {};
	Monitor *atc_monitor {};
	Monitor *cache_monitor {};

 public:
	//
	// レジスタ
	//

	// IDR (ID Register) +$000
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------+-----+---------+-------------------------------+
	// |      ID       | Type| Version |           reserved            |
	// +---------------+-----+---------+-------------------------------+
	//
	// ID はリセット時、下位7ビットはハードウェアで初期化、最上位ビットは
	// 0 で初期化。その後は全ビット変更可能。
	// Type は $5 = 88200、$6 = 88204。ここでは 88200 固定。
	uint32 id {};
	uint32 version {};

	// IDR レジスタの内容を返す
	uint32 GetIDR() const {
		return (id << 24) | (0x5 << 21) | (version << 16);
	}
	// Version フィールドを設定する
	void SetVersion(uint version_);

	// SCR (System Command Register) +$004
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------+-----------+
	// |                     reserved                      |CommandCode|
	// +---------------------------------------------------+-----------+
	uint32 command {};
	uint32 GetSCR() const;
	void SetSCR(uint32 val);
 private:
	static const char * const commandname[];
	static const uint32 GG_LINE	= 0;
	static const uint32 GG_PAGE	= 1;
	static const uint32 GG_SEG	= 2;
	static const uint32 GG_ALL	= 3;
	void FlushCacheCmd();
	void InvalidatePATCCmd();

 public:
	// SSR (System Status Register) +$008
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------------------+
	// |                               |C|B|       |W|S|G|C| |M|U|W|B|V|
	// |            reserved           |E|E|  res  |T|P| |I|r| | |P|H| |
	// +---------------------------------------------------------------+
	static const uint32 SSR_CE	= 0x00008000;	// Copyback Error
	static const uint32 SSR_BE	= 0x00004000;	// Bus Error
	static const uint32 SSR_WT	= 0x00000200;	// WriteThrough
	static const uint32 SSR_SP	= 0x00000100;	// Supervisor Privilege
	static const uint32 SSR_G	= 0x00000080;	// Global
	static const uint32 SSR_CI	= 0x00000040;	// Cache Inhibit
	static const uint32 SSR_M	= 0x00000010;	// Modified
	static const uint32 SSR_U	= 0x00000008;	// Used
	static const uint32 SSR_WP	= 0x00000004;	// Write Protection
	static const uint32 SSR_BH	= 0x00000002;	// BATC Hit
	static const uint32 SSR_V	= 0x00000001;	// Valid
	uint32 ssr {};
	uint32 GetSSR() const { return ssr; }
	void SetSSR(uint32 val) { ssr = val; }

	// SAR (System Address Register) +$00c
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------------------+
	// |                          Address                              |
	// +---------------------------------------------------------------+
	uint32 sar {};
	uint32 GetSAR() const { return sar; }
	void SetSAR(uint32 val) { sar = val; }

	// SCTR (System Control Register) +$104
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +-------------------------------+-+-+-+-------------------------+
	// |                               |P|S|P|                         |
	// |           reserved            |E|E|R|         reserved        |
	// +-------------------------------+-+-+-+-------------------------+
	static const uint32 SCTR_PE	= 0x00008000;	// Parity Enable
	static const uint32 SCTR_SE	= 0x00004000;	// Snoop Enable
	static const uint32 SCTR_PR	= 0x00002000;	// Priority Arbitration
	uint32 sctr {};
	uint32 GetSCTR() const { return sctr; }
	void SetSCTR(uint32 val);

	// SAPR (Supervisor Area Pointer Register) +$200
	// UAPR (User       Area Pointer Register) +$204
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------+---+-+-+-+-+---------+-+
	// | Supervisor Segment Table Base Address |   |W| |G|C|         |T|
	// | or    User Segment Table Base Address |0 0|T|0| |I|0 0 0 0 0|E|
	// +---------------------------------------+---+-+-+-+-+---------+-+
	static const uint32 APR_ADDR_MASK	= 0xfffff000;	// Base Address
	static const uint32 APR_WT			= 0x00000200;	// WriteThrough
	static const uint32 APR_G			= 0x00000080;	// Global
	static const uint32 APR_CI			= 0x00000040;	// Cache Inhibit
	static const uint32 APR_TE			= 0x00000001;	// Translation Enable
	m88200APR uapr {};
	m88200APR sapr {};
 private:
	uint32 GetAPR(const m88200APR&) const;
	void SetAPR(m88200APR&, uint32 data);
	// 現在の xAPR
	const m88200APR *acc_apr {};
 public:
	uint32 GetAPR(uint issuper) const;
	uint32 GetUAPR() const { return GetAPR(uapr); }
	uint32 GetSAPR() const { return GetAPR(sapr); }
	void SetUAPR(uint32 data) { SetAPR(uapr, data); }
	void SetSAPR(uint32 data) { SetAPR(sapr, data); }

	// PFSR (P Bus Fault Status Register) +$108
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +-------------------------+-----+-------------------------------+
	// |                         |Fault|                               |
	// |        reserved         | Code|            reserved           |
	// +-------------------------+-----+-------------------------------+
	static const uint32 FAULT_CODE_SUCCESS		= 0;	// Success (No fault)
	static const uint32 FAULT_CODE_BUSERR		= 3;	// Bus Error
	static const uint32 FAULT_CODE_SEGMENT		= 4;	// Segment Fault
	static const uint32 FAULT_CODE_PAGE			= 5;	// Page Fault
	static const uint32 FAULT_CODE_SUPERVISOR	= 6;	// Supervisor Violation
	static const uint32 FAULT_CODE_WRITE		= 7;	// Write Violation
	uint32 fault_code {};
	uint32 GetPFSR() const {
		return fault_code << 16;
	}
	void SetPFSR(uint32 data) {
		fault_code = (data >> 16) & 7;
	}

	// PFAR (P Bus Fault Address Register) +$10c
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------------------+
	// |                          Address                              |
	// +---------------------------------------------------------------+
	uint32 fault_addr {};
	uint32 GetPFAR() const { return fault_addr; }
	void SetPFAR(uint32 val) { fault_addr = val; }

	void SetFault(uint32 code_, uint32 addr_) {
		fault_code = code_;
		fault_addr = addr_;
	}

	// BWP0-7 (BATC Write Ports 0..7) +$400..+$41c
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------------------+
	// |                         |                         |S|W|G|C|W|V|
	// |  Logical Block Address  | Physical Block Address  | |T| |I|P| |
	// +---------------------------------------------------------------+
	static const uint32 BWP_LBA_MASK	= 0xfff80000;
	static const uint32 BWP_PBA_MASK	= 0x0007ffc0;
	static const uint32 BWP_FLAG_MASK	= 0x0000003f;
	static const uint32 BWP_S			= 0x00000020;	// Address Space
	static const uint32 BWP_WT			= 0x00000010;	// WriteThrough
	static const uint32 BWP_G			= 0x00000008;	// Global
	static const uint32 BWP_CI			= 0x00000004;	// Cache Inhibit
	static const uint32 BWP_WP			= 0x00000002;	// Write Protect
	static const uint32 BWP_V			= 0x00000001;	// Valid
	void SetBWP(uint n, uint32 val);
	void SetBATC(uint n, uint32 laddr, uint32 paddr, uint32 flags);

	// CDP0-3 (Cache Data Ports 0..3) +$800..+$80c
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------------------+
	// |                          Data Word                            |
	// +---------------------------------------------------------------+

	// CTP0-3 (Cache Tag Ports 0..3) +$840..+$84c
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------+-----------------------+
	// |            Physical Address           |       reserved        |
	// +---------------------------------------+-----------------------+

	// CSSP (Cache Set Status Port) +$880
	//    3                   2                   1
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------------------------------+
	// |   |L|L|L|L|L|L|D|D|D|D|VV3|VV2|VV1|VV0|                       |
	// |res|5|4|3|2|1|0|3|2|1|0|   |   |   |   |       reserved        |
	// +---------------------------------------------------------------+
	static const uint32 CSSP_L5		= 0x20000000;	// Line5
	static const uint32 CSSP_L4		= 0x10000000;	// Line4
	static const uint32 CSSP_L3		= 0x08000000;	// Line3
	static const uint32 CSSP_L2		= 0x04000000;	// Line2
	static const uint32 CSSP_L1		= 0x02000000;	// Line1
	static const uint32 CSSP_L0		= 0x01000000;	// Line0
	static const uint32 CSSP_D3		= 0x00800000;	// Line Disable
	static const uint32 CSSP_D2		= 0x00400000;	// Line Disable
	static const uint32 CSSP_D1		= 0x00200000;	// Line Disable
	static const uint32 CSSP_D0		= 0x00100000;	// Line Disable
	static const uint32 CSSP_VV3	= 0x000c0000;	// Line Valid
	static const uint32 CSSP_VV2	= 0x00030000;	// Line Valid
	static const uint32 CSSP_VV1	= 0x0000c000;	// Line Valid
	static const uint32 CSSP_VV0	= 0x00003000;	// Line Valid
	static const uint32 CSSP_VV3_OFFSET	= 18;
	static const uint32 CSSP_VV2_OFFSET	= 16;
	static const uint32 CSSP_VV1_OFFSET	= 14;
	static const uint32 CSSP_VV0_OFFSET	= 12;
	uint32 GetCSSP() const;
	void SetCSSP(uint32 val);

	//
	// 物理バスアクセス
	//
	busdata MBusRead(busaddr paddr);
	busdata MBusWrite(busaddr paddr, uint32 data);
	busdata MBusXmem(busaddr paddr, uint32 data);

	//
	// アクセス関数
	//
 private:
	template <uint size> busdata load(uint32 addr);
	template <uint size> busdata store(uint32 addr, uint32 data);
	template <uint size> busdata xmem(uint32 addr, uint32 data);
 public:
	busdata load_1(uint32 addr);
	busdata load_2(uint32 addr);
	busdata load_4(uint32 addr);
	busdata store_1(uint32 addr, uint32 data);
	busdata store_2(uint32 addr, uint32 data);
	busdata store_4(uint32 addr, uint32 data);
	busdata xmem_1(uint32 addr, uint32 data);
	busdata xmem_4(uint32 addr, uint32 data);

	//
	// 現在のアクセス中の状態。
	//
	// アドレス変換およびデータキャッシュルーチンではこれらの値を
	// グローバルに状態変数として使う。

	// ディスクリプタの下位にあるフラグは全部ビット位置が同じ。
	// Area descriptor (SAPR or UAPR)
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------+---+-+-+-+-+---------+-+
	// | Supervisor Segment Table Base Address |   |W| |G|C|         |T|
	// | or    User Segment Table Base Address |0 0|T|0| |I|0 0 0 0 0|E|
	// +---------------------------------------+---+-+-+-+-+---------+-+
	//
	// Segment Descriptor
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------+---+-+-+-+-+-----+-+-+-+
	// |    Page Table Base Address (PTBA)     |   |W|S|G|C|     |W| |V|
	// |                                       |0 0|T|P| |I|0 0 0|P|0| |
	// +---------------------------------------+---+-+-+-+-+-----+-+-+-+
	//
	// Page Descriptor
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------+---+-+-+-+-+-+-+-+-+-+-+
	// |       Page Frame Address (PFA)        |   |W|S|G|C| |M|U|W| |V|
	// |                                       |0 0|T|P| |I|0| | |P|0| |
	// +---------------------------------------+---+-+-+-+-+-+-+-+-+-+-+
	//
	// acc_stat も同じビット位置を使う。
	//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
	// +---------------------------------------+---+-+-+-+-+-----+-+---+
	// |                                       |   |W| |G|C|     |W|   |
	// |                                       |0 0|T|0| |I|  0  |P| 0 |
	// +---------------------------------------+---+-+-+-+-+-----+-+---+
	//
	static const uint32 DESC_WT		= 0x00000200;	// Write Through
	static const uint32 DESC_SP		= 0x00000100;	// Supervisor Protect
	static const uint32 DESC_G		= 0x00000080;	// Global
	static const uint32 DESC_CI		= 0x00000040;	// Cache Inhibit
	static const uint32 DESC_M		= 0x00000010;	// Modified
	static const uint32 DESC_U		= 0x00000008;	// Used
	static const uint32 DESC_WP		= 0x00000004;	// Write Protect
	static const uint32 DESC_V		= 0x00000001;	// Valid

 private:
	uint32 acc_laddr {};		// Logical Address
	uint32 acc_paddr {};		// Physical Address

 public:
	// acc_stat は 4 ビットのみ使用。
	// それ以外のビットは代入時にマスクすること。
	static const uint32 ACC_STAT_MASK = DESC_WT | DESC_G | DESC_CI | DESC_WP;
	uint32 acc_stat {};
	// Table Address.  とマニュアルには書いてあるけど、テーブル先頭と
	// 紛らわしいし 88200 のアドレス変換ツリーは2段固定で、今何段目か
	// しらんけど現在のテーブルアドレス…みたいなのを持つ必要はないので、
	// ここでは
	// sdaddr ... Segment Descriptor Address
	// pdaddr ... Page    Descriptor Address
	// の2つに明確に分けて管理することにする。
	uint32 acc_sdaddr {};
	busaddr acc_pdaddr {};
	bool acc_read {};			// True if read access
	bool acc_IsWrite() const { return !acc_read; }	// True if write access

	// S/U 信号線
	// 実際には P Bus の Address フェーズで毎回送られてくるが
	// そうそう変わらないので状態変化を通知してもらう方式。
	// acc_super は S か U のみ。
	busaddr acc_super {};
	void SetSuper(bool super);
	bool IsSuper() const { return acc_super.IsSuper(); }
	bool IsUser() const  { return !IsSuper(); }

	m88200PATC *acc_patc {};	// ヒットした PATC エントリ
	uint32 tmp_desc {};			// TEMP_DESCR

	//
	// アドレス変換
	//
	bool Translate();
	busaddr TranslatePeek(busaddr laddr) const;
 private:
	static std::string stat2str(uint32 stat);
	bool SelectAreaDesc();
	bool TableSearch();
	bool FetchSegmentDesc();
	bool FetchPageDesc();
	bool UpdatePageDesc();

	// BATC
	static const uint32 BATC_LBA_MASK	= BWP_LBA_MASK;
	static const uint32 BATC_S			= m88200BATC::S;
	static const uint32 BATC_INVALID	= m88200BATC::INVALID;
	void MakeBATCHash();
	std::array<m88200BATC, 10> batc {};
	// 検索用のハッシュ。値のビットN (0..9) が立っていれば batc[N] がこの
	// ハッシュに当たることを示している (この後完全一致で比較する必要はある)。
	// [0x00] => 0b00'0000'0000;
	std::array<uint16, 16> batc_hash_s {};
	std::array<uint16, 16> batc_hash_u {};
	// 現在の特権状態によって batc_hash_{s,u} のいずれかを指す。
	uint16 *batc_hash {};
	static int batc_hash_func(uint32 a) {
		return (a >> 19) & 0x0f;
	}

	// PATC
	static const uint32 PATC_S			= m88200PATC::S;
	static const uint32 PATC_INVALID	= m88200PATC::INVALID;
	void CreatePATCEntry();
	void InvalidatePATCHash(int);
	std::array<m88200PATC, 56> patc {};
	// 検索用のハッシュ。値のビット N (0..55) が立っていれば patc[N] がこの
	// ハッシュに当たることを示している (この後完全一致で比較する必要はある)。
	std::array<uint64, 256> patc_hash_s {};
	std::array<uint64, 256> patc_hash_u {};
	// 現在の特権状態によって patc_hash_{s,u} のいずれかを指す。
	uint64 *patc_hash {};
	static int patc_hash_func(uint32 a) {
		return (a >> 12) & 0xff;
	}
	// 空きエントリ。patc[N] が空いていればビット N を立てる。
	uint64 patc_free {};
	// 次回追加する位置。
	int patc_next {};

	// 統計
	uint64 translate_total {};
	std::array<uint64, 10> batc_hit {};
	uint64 patc_hit {};
	uint64 atc_miss {};
#if defined(M88200_STAT)
	// 開発用の統計
	uint64 stat_patc_create {};				// エントリ作成回数
	uint64 stat_patc_invcmd_all {};			// Invalidate ALL 発行回数
	uint64 stat_patc_invcmd_seg {};			// Invalidate Segment 発行回数
	uint64 stat_patc_invcmd_page {};		// Invalidate Page 発行回数
	uint64 stat_patc_invalidate {};			// 無効にした PATC の総数
	uint64 stat_patc_search {};				// ハッシュを引いた回数
	uint64 stat_patc_miss1 {};				// ハッシュだけでミスした回数
	uint64 stat_patc_miss2 {};				// ビットを調べてミスした回数
	std::array<int, 8> stat_batc_hash_s {};	// BATC.S の衝突状況
	std::array<int, 8> stat_batc_hash_u {};	// BATC.U の衝突状況
#endif

	//
	// 物理アドレスアクセス
	//
	busdata PhysRead(busaddr paddr, uint32 stat);
	busdata PhysWrite(busaddr paddr, uint32 data, uint32 stat);

	//
	// キャッシュ
	//
 private:
	std::array<m88200CacheSet,256> setarray {};
	// キャッシュラインにメモリから読み込む
	bool ReadLine(m88200CacheSet& set, uint line, uint32 tagaddr);
	// キャッシュラインをメモリに書き出す
	bool CopyBackLine(m88200CacheSet& set, uint line);

	// キャッシュに対して paddr の読み込みを行う
	busdata CacheRead(uint32 paddr);
	// キャッシュに対して paddr への書き込みを行う
	busdata CacheWrite(uint32 paddr, uint32 data, uint size);
	busdata CacheWriteHit(m88200CacheSet& set, uint line,
		uint32 paddr, uint32 data, uint size);
	busdata CacheXmem(uint32 paddr, uint32 data, uint size);

 public:
	// モニタスクリーン作成用
	void MonitorCacheSet(TextScreen&, int y, uint setidx);
	void MonitorCacheOverview(TextScreen&, int y, uint cursor, bool is_gui);
	void MonitorCacheOverview(TextScreen& s, int y, bool is_gui) {
		MonitorCacheOverview(s, y, -1, is_gui);
	}

	//
	// MBus
	//
 public:
	// MBus を所有している CMMU を返す。誰も持っていなければ NULL。
	// これは static 関数
	static m88200 *GetBusMaster() { return mbus_master; }

 private:
	static constexpr bool IM_0 = false;
	static constexpr bool IM_1 = true;
	void MBusAcquire();
	void MBusRelease() { }
	// 他 CMMU にスヌープさせる (バスマスタ側)
	void MBusMakeSnoop(uint32 addr, bool im);
	// バススヌープを行う (スレーブ側)
	void Snoop(uint32 addr, bool im);

	MainbusDevice *mainbus {};

	// MBus を所有してる CMMU を指す。NULL なら解放。
	// これは static 変数で全 m88200 で共有している
	static m88200 *mbus_master;

	// スヌープ相手の CMMU リスト
	std::vector<m88200*> other_cmmu {};
};

unix.superglobalmegacorp.com

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