File:  [Isaki's NoNo m68k/m88k emulator] / nono / m680x0 / m680x0.h
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:57 2026 UTC (3 months 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 "bus.h"

// どこ?
__BEGIN_DECLS
#include "fpu_emulate.h"
__END_DECLS

// MPU 種別
enum class m680x0MPUType
{
	NONE = 0,
	M68030 = (1U << 1),
	M68040 = (1U << 2),
};

// FPU 種別
struct m680x0FPUType
{
	enum m680x0FPUType_ {
		M68030_NOFPU	= 0,			// 68030 without 6888x
		M68LC040		= (1U << 0),
		M68LC060		= (1U << 1),	// (reserved)
		M68040			= (1U << 2),
		M68060			= (1U << 3),	// (reserved)
		M68881			= (1U << 4),
		M68882			= (1U << 5),

		M68LC0x0		= (M68LC040 | M68LC060),
		M680x0			= (M68040 | M68060),
		M6888x			= (M68881 | M68882),
	} type {};

	// コンストラクタ
	m680x0FPUType() {
	}
	m680x0FPUType(m680x0FPUType_ type_)
		: type(type_)
	{
	}

	bool IsNoFPU() const noexcept	{ return (type == M68030_NOFPU); }
	bool Is4060LC() const noexcept	{ return (type & M68LC0x0) != 0; }
	bool Is40FPU() const noexcept	{ return (type & M68040) != 0; }
	bool Is4060FPU() const noexcept	{ return (type & M680x0) != 0; }
	bool Is6888x() const noexcept	{ return (type & M6888x) != 0; }
};
inline bool operator==(const m680x0FPUType& a, const m680x0FPUType& b) {
	return (a.type == b.type);
}
inline bool operator!=(const m680x0FPUType& a, const m680x0FPUType& b) {
	return !(a == b);
}

// 定数
struct M68K
{
	// SR(CCR)
	static const uint32 SR_T			= 0xc000;
	static const uint32 SR_S			= 0x2000;
	static const uint32 SR_M			= 0x1000;
	static const uint32 SR_IMASK		= 0x0700;
	static const uint32 CCR_X			= 0x0010;
	static const uint32 CCR_N			= 0x0008;
	static const uint32 CCR_Z			= 0x0004;
	static const uint32 CCR_V			= 0x0002;
	static const uint32 CCR_C			= 0x0001;

	// FC
	static const uint32 FC_DATA			= 1;
	static const uint32 FC_PROG			= 2;
	static const uint32 FC_USER			= 0;
	static const uint32 FC_SUPER		= 4;
	static const uint32 FC_UD			= (FC_USER  | FC_DATA);
	static const uint32 FC_UP			= (FC_USER  | FC_PROG);
	static const uint32 FC_SD			= (FC_SUPER | FC_DATA);
	static const uint32 FC_SP			= (FC_SUPER | FC_PROG);

	// FP
	static const uint32 FPCR_MASK		= 0x0000fff0;
	static const uint32 FPSR_MASK		= 0x0ffffff8;

	// 例外 (型は core.cpp の try-catch と揃えること)。
	// FPU_NOIMPL (浮動小数点未実装命令例外) はベクタ番号が 11 ($b) で
	// F ラインと同じだが処理が色々違うので帯域外のビットで判別する。
	static const uint EXCEP_RESET			= 0;
	static const uint EXCEP_BUSERR			= 2;
	static const uint EXCEP_ADDRERR			= 3;
	static const uint EXCEP_ILLEGAL			= 4;
	static const uint EXCEP_ZERODIV			= 5;
	static const uint EXCEP_CHK				= 6;
	static const uint EXCEP_TRAPV			= 7;
	static const uint EXCEP_PRIV			= 8;
	static const uint EXCEP_TRACE			= 9;
	static const uint EXCEP_ALINE			= 10;
	static const uint EXCEP_FLINE			= 11;
	static const uint EXCEP_FP_UNIMPL		= (11 | 0x100);
	static const uint EXCEP_COPRO			= 13;
	static const uint EXCEP_FORMAT			= 14;
	static const uint EXCEP_UNINIT_INTR		= 16;
	static const uint EXCEP_SPURIOUS		= 24;
	static const uint EXCEP_LEVEL_BASE		= 24;	// オートベクタ演算用
	static const uint EXCEP_LEVEL1			= 25;
	static const uint EXCEP_LEVEL7			= 31;
	static const uint EXCEP_TRAP0			= 32;
	static const uint EXCEP_TRAP15			= 47;
	static const uint EXCEP_FP_BSUN			= 48;
	static const uint EXCEP_FP_INEX			= 49;
	static const uint EXCEP_FP_ZERODIV		= 50;
	static const uint EXCEP_FP_UNFL			= 51;
	static const uint EXCEP_FP_OPERR		= 52;
	static const uint EXCEP_FP_OVFL			= 53;
	static const uint EXCEP_FP_SNAN			= 54;
	static const uint EXCEP_FP_UNSUPP		= 55;
	static const uint EXCEP_MMU_CONFIG		= 56;
};

// 定数
struct M68030
{
	// SSW
	static constexpr uint32 SSW_SIZE(uint32 x) { return ((x) & 0x03) << 4; }
	static const uint32 SSW_SIZE_LONG	= (0U << 4);
	static const uint32 SSW_SIZE_BYTE	= (1U << 4);
	static const uint32 SSW_SIZE_WORD	= (2U << 4);
	static const uint32 SSW_SIZE_3BYTES	= (3U << 4);
	static const uint32 SSW_SIZE_MASK	= (0x03U << 4);

	static const uint32 SSW_FC_MASK		= 0x0007;	// FC_*
	static const uint32 SSW_RW			= 0x0040;	// SSW_BUS_{R,W}
	static const uint32 SSW_RM			= 0x0080;
	static const uint32 SSW_DF			= 0x0100;	// Data Fault
	static const uint32 SSW_RB			= 0x1000;
	static const uint32 SSW_RC			= 0x2000;
	static const uint32 SSW_FB			= 0x4000;
	static const uint32 SSW_FC			= 0x8000;

	static const uint32 SSW_BUS_R		= 0x0040;
	static const uint32 SSW_BUS_W		= 0x0000;

	// CACR
	static const uint32 CACR_EI			= 0x0001;
	static const uint32 CACR_FI			= 0x0002;
	static const uint32 CACR_CEI		= 0x0004;
	static const uint32 CACR_CI			= 0x0008;
	static const uint32 CACR_IBE		= 0x0010;
	static const uint32 CACR_ED			= 0x0100;
	static const uint32 CACR_FD			= 0x0200;
	static const uint32 CACR_CED		= 0x0400;
	static const uint32 CACR_CD			= 0x0800;
	static const uint32 CACR_DBE		= 0x1000;
	static const uint32 CACR_WA			= 0x2000;
	static const uint32 CACR_MASK		= 0x3f1f;
};

// 定数
struct M68040
{
	// SSW
	static const uint32 SSW_TM_MASK		= 0x0007;
	static const uint32 SSW_TT_MASK		= 0x0018;
	static const uint32 SSW_SIZE_MASK	= 0x0060;	// (0x03U << 5)
	static const uint32 SSW_RW			= 0x0100;
	static const uint32 SSW_LK			= 0x0200;
	static const uint32 SSW_ATC			= 0x0400;
	static const uint32 SSW_MA			= 0x0800;
	static const uint32 SSW_CM			= 0x1000;
	static const uint32 SSW_CT			= 0x2000;
	static const uint32 SSW_CU			= 0x4000;
	static const uint32 SSW_CP			= 0x8000;

	static const uint32 SSW_SIZE_LONG	= (0x00U << 5);
	static const uint32 SSW_SIZE_BYTE	= (0x01U << 5);
	static const uint32 SSW_SIZE_WORD	= (0x02U << 5);
	static const uint32 SSW_SIZE_LINE	= (0x03U << 5);
	// バイトサイズから SSW_SIZE フィールドを作成する。1, 2, 4 バイトのみ。
	static constexpr uint32 SSW_SIZE(uint32 x) { return ((x) & 0x03) << 5; }

	// CACR
	static const uint32 CACR_MASK		= 0x80008000;
	static const uint32 CACR_DE			= 0x80000000;
	static const uint32 CACR_IE			= 0x00008000;
};

struct m680x0CCR
{
 protected:
	// X フラグは、X の X_BIT が立っていれば 1
	// N フラグは、N の N_BIT が立っていれば 1
	// Z フラグは、Z == 0 なら 1
	// V フラグは、V の V_BIT が立っていれば 1
	// C フラグは、C の C_BIT が立っていれば 1
	static const uint32 X_BIT = 0x00000001;
	static const uint32 N_BIT = 0x80000000;
	static const uint32 V_BIT = 0x80000000;
	static const uint32 C_BIT = 0x00000001;

	uint32 X;
	uint32 V;
	uint32 N;
	DEF_UNION64(, CZ, C, Z);

 public:
	// value をフラグにセットする
	void SetX(bool value) { X = (value) ? X_BIT : 0; }
	void SetN(bool value) { N = (value) ? N_BIT : 0; }
	void SetZ(bool value) { Z = (value) ? 0 : 1; }
	void SetV(bool value) { V = (value) ? V_BIT : 0; }
	void SetC(bool value) { C = (value) ? C_BIT : 0; }

	// フラグが立っていれば真を返す
	bool IsX() const { return ((X & X_BIT) != 0); }
	bool IsN() const { return ((N & N_BIT) != 0); }
	bool IsZ() const { return (Z == 0); }
	bool IsV() const { return ((V & V_BIT) != 0); }
	bool IsC() const { return ((C & C_BIT) != 0); }

	// CCR レジスタの内容を作って返す
	uint8 Get() const {
		return (IsX() ? M68K::CCR_X : 0)
		     | (IsN() ? M68K::CCR_N : 0)
		     | (IsZ() ? M68K::CCR_Z : 0)
		     | (IsV() ? M68K::CCR_V : 0)
		     | (IsC() ? M68K::CCR_C : 0);
	}

	// CCR レジスタに val をセットする
	void Set(uint8 val) {
		SetX((val) & M68K::CCR_X);
		SetN((val) & M68K::CCR_N);
		SetZ((val) & M68K::CCR_Z);
		SetV((val) & M68K::CCR_V);
		SetC((val) & M68K::CCR_C);
	}

	bool CondT()  const { return true; }
	bool CondF()  const { return false; }
	bool CondHI() const { return !IsC() && !IsZ(); }
	bool CondLS() const { return IsC() || IsZ(); }
	bool CondCC() const { return !IsC(); }
	bool CondCS() const { return IsC(); }
	bool CondNE() const { return !IsZ(); }
	bool CondEQ() const { return IsZ(); }
	bool CondVC() const { return !IsV(); }
	bool CondVS() const { return IsV(); }
	bool CondPL() const { return !IsN(); }
	bool CondMI() const { return IsN(); }
	bool CondGE() const { return (IsN() && IsV()) || (!IsN() && !IsV()); }
	bool CondLT() const { return (IsN() && !IsV()) || (!IsN() && IsV()); }
	bool CondGT() const {
		return (IsN() && IsV() && !IsZ()) || (!IsN() && !IsV() && !IsZ());
	}
	bool CondLE() const {
		return IsZ() || (IsN() && !IsV()) || (!IsN() && IsV());
	}

	// cond で示される条件が成立すれば true を返す。
	inline bool Cond(uint cond) const {
		switch (cond) {
		 case 0:	// T
			return CondT();
		 case 1:	// F
			return CondF();
		 case 2:
			return CondHI();
		 case 3:
			return CondLS();
		 case 4:
			return CondCC();
		 case 5:
			return CondCS();
		 case 6:
			return CondNE();
		 case 7:
			return CondEQ();
		 case 8:
			return CondVC();
		 case 9:
			return CondVS();
		 case 10:
			return CondPL();
		 case 11:
			return CondMI();
		 case 12:
			return CondGE();
		 case 13:
			return CondLT();
		 case 14:
			return CondGT();
		 case 15:
			return CondLE();
		}
		__unreachable();
	}
};

// レジスタイメージを保持する構造体。
// この構造体はコピーとか比較をするのでポインタとかは置かないこと。
struct m68kreg
{
	uint32 pc;
	union {
		uint32 R[16] {};
		struct {
			uint32 D[8];
			uint32 A[8];
		};
	};

	m680x0CCR ccr;
	bool s;				// SR の S ビット
	bool m;				// SR の M ビット
	int  intr_mask;		// SR の割り込みマスク (0-7)

	// 現在の SP は常に A[7]。A[7] が示しているときは対応する変数の
	// ほうは更新されないため無効 (図中 'x')。
	//
	// 						A[7]	usp		isp		msp
	//                  	----	---		---		---
	// ユーザ				USP		x		ISP		MSP
	// スーパーバイザ(I)	ISP		USP		x		MSP
	// スーパーバイザ(M)	MSP		USP		ISP		x
	uint32 usp;
	uint32 isp;
	uint32 msp;

	uint32 vbr;
	busaddr sfc;		// (R/W も含む)
	busaddr dfc;		// (R/W も含む)

	uint32 cacr;
	uint32 caar;

	// 68030 MMU
	union64 srp;
	union64 crp;
	uint32 tt[2];
	uint32 tc;
	uint16 mmusr;

	// 68040 MMU
	uint32 itt[2];
	uint32 dtt[2];
	uint32 srp40;
	uint32 urp40;
	uint16 tc40;
	uint32 mmusr40;

	struct fpframe fpframe;

	// SR レジスタ全体を返す
	uint16 GetSR() const {
		return (s ? M68K::SR_S : 0)
		     | (m ? M68K::SR_M : 0)
		     | (intr_mask << 8)
		     | ccr.Get();
	}
	// SFC, DFC レジスタの値を返す
	uint32 GetSFC() const { return sfc.GetFC(); }
	uint32 GetDFC() const { return dfc.GetFC(); }
};

// バス状態
struct m68kbus
{
	// 論理アドレス。(サイズ, R/W, FC2-0, Addr すべて使用)
	busaddr laddr;

	// データバス。
	// 今の所書き込みだけで使う。読み込みデータは戻り値のみ。
	uint32 data;

	// キャッシュ禁止。/CIIN
	bool ci;

	// ATC フォールト (68040 only)
	bool atcfault;

	// ATC フォールトが2ページ目で起きたら true (68040 only)
	bool atcfault2;

	// Supervisor アクセスなら true を返す
	bool IsSuper() const { return laddr.IsSuper(); }
};

// 仮
#define RegFP(n)	(reg.fpframe.fpf_regs[(n) * 3])
#define RegFPCR		(reg.fpframe.fpf_fpcr)
#define RegFPSR		(reg.fpframe.fpf_fpsr)
#define RegFPIAR	(reg.fpframe.fpf_fpiar)

unix.superglobalmegacorp.com

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