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