--- nono/m680x0/m68030.h 2026/04/29 17:05:08 1.1.1.11 +++ nono/m680x0/m68030.h 2026/04/29 17:05:15 1.1.1.12 @@ -6,102 +6,254 @@ #pragma once -// -// 外部公開用 -// - -#include "branchhistory.h" +#include "header.h" +// どこ? __BEGIN_DECLS #include "fpu_emulate.h" __END_DECLS -class m68kcpu; -class MPU680x0Device; +// 定数 +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; + + // SSW + static constexpr uint32 SSW_SIZE(uint32 x) { return ((x) & 0x03) << 4; } + static const uint32 SSW_SIZE_LONG = (0 << 4); + static const uint32 SSW_SIZE_BYTE = (1 << 4); + static const uint32 SSW_SIZE_WORD = (2 << 4); + static const uint32 SSW_SIZE_3BYTES = (3 << 4); + static const uint32 SSW_SIZE_MASK = (0x03 << 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; + + // 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); + + // 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; + + // FP + static const uint32 FPCR_MASK = 0x0000fff0; + static const uint32 FPSR_MASK = 0x0ffffff8; + + // 例外 + // (型は core.cpp の try-catch と揃えること) + static const int EXCEP_RESET = 0; + static const int EXCEP_BUSERR = 2; + static const int EXCEP_ADDRERR = 3; + static const int EXCEP_ILLEGAL = 4; + static const int EXCEP_ZERODIV = 5; + static const int EXCEP_CHK = 6; + static const int EXCEP_TRAPV = 7; + static const int EXCEP_PRIV = 8; + static const int EXCEP_TRACE = 9; + static const int EXCEP_ALINE = 10; + static const int EXCEP_FLINE = 11; + static const int EXCEP_COPRO = 13; + static const int EXCEP_FORMAT = 14; + static const int EXCEP_UNINIT_INTR = 16; + static const int EXCEP_SPURIOUS = 24; + static const int EXCEP_LEVEL_BASE = 24; // オートベクタ演算用 + static const int EXCEP_LEVEL1 = 25; + static const int EXCEP_LEVEL7 = 31; + static const int EXCEP_TRAP0 = 32; + static const int EXCEP_TRAP15 = 47; + static const int EXCEP_FPCP_BRANCH = 48; + static const int EXCEP_FPCP_INEXACT = 49; + static const int EXCEP_FPCP_ZERODIV = 50; + static const int EXCEP_FPCP_UNFL = 51; + static const int EXCEP_FPCP_OPERR = 52; + static const int EXCEP_FPCP_OVFL = 53; + static const int EXCEP_FPCP_SNAN = 54; + static const int EXCEP_MMU_CONFIG = 56; +}; + +struct m68030ccr +{ + 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; + union { + uint64 CZ; + struct { +#if BYTE_ORDER == LITTLE_ENDIAN + uint32 Z; + uint32 C; +#else + uint32 C; + uint32 Z; +#endif + } __packed; + }; -// 外部ループフラグ -// これらのフラグがいずれも立っていない間、CPU 実行は内側のディスパッチ -// ループを周り、どれかでも立てばディスパッチループを抜けてフラグを処理 -// してから再びディスパッチループに戻る。 -// それぞれ独立しているためビットを立てる際は代入ではなく OR すること。 -#define CPU_REQ_INTR (0x00000020) // 命令後に割り込みチェックが必要 - -#define M68K_SR_T (0xc000) -#define M68K_SR_S (0x2000) -#define M68K_SR_M (0x1000) -#define M68K_SR_IMASK (0x0700) -#define M68K_CCR_X (0x0010) -#define M68K_CCR_N (0x0008) -#define M68K_CCR_Z (0x0004) -#define M68K_CCR_V (0x0002) -#define M68K_CCR_C (0x0001) - -// SSW -#define SSW_SIZE(x) (((x) & 0x03) << 4) -#define SSW_SIZE_BYTE SSW_SIZE(1) -#define SSW_SIZE_WORD SSW_SIZE(2) -#define SSW_SIZE_3BYTES SSW_SIZE(3) -#define SSW_SIZE_LONG SSW_SIZE(0) -#define SSW_SIZE_MASK SSW_SIZE(0x03) - -#define SSW_FC_MASK (0x0007) // FC_* -#define SSW_RW (0x0040) // SSW_BUS_{R,W} -#define SSW_RM (0x0080) -#define SSW_DF (0x0100) // Data Fault -#define SSW_RB (0x1000) -#define SSW_RC (0x2000) -#define SSW_FB (0x4000) -#define SSW_FC (0x8000) - -#define SSW_BUS_R (0x0040) -#define SSW_BUS_W (0x0000) - -#define FC_DATA (1) -#define FC_PROG (2) -#define FC_USER (0) -#define FC_SUPER (4) -#define FC_UD (FC_USER | FC_DATA) -#define FC_UP (FC_USER | FC_PROG) -#define FC_SD (FC_SUPER | FC_DATA) -#define FC_SP (FC_SUPER | FC_PROG) - -#define M68K_CACR_EI (0x0001) -#define M68K_CACR_FI (0x0002) -#define M68K_CACR_CEI (0x0004) -#define M68K_CACR_CI (0x0008) -#define M68K_CACR_IBE (0x0010) -#define M68K_CACR_ED (0x0100) -#define M68K_CACR_FD (0x0200) -#define M68K_CACR_CED (0x0400) -#define M68K_CACR_CD (0x0800) -#define M68K_CACR_DBE (0x1000) -#define M68K_CACR_WA (0x2000) + 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); + } -#define M68K_FPCR_MASK (0x0000fff0) -#define M68K_FPSR_MASK (0x0ffffff8) + // 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); + } -#include "m68030ccr.h" -#include "m68030mmu.h" + 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(int 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 { - public: +struct m68kreg +{ uint32 pc; - uint32 da[16]; + union { + uint32 R[16] {}; + struct { + uint32 D[8]; + uint32 A[8]; + }; + }; m68030ccr ccr; bool s; // SR の S ビット bool m; // SR の M ビット int intr_mask; // SR の割り込みマスク (0-7) - // 現在の SP は常に da[15]。da[15] が示しているときは対応する変数の + // 現在の SP は常に A[7]。A[7] が示しているときは対応する変数の // ほうは更新されないため無効。 - // ユーザ状態なら da[15] が USP を示し usp は無効、 + // ユーザ状態なら A[7] が USP を示し usp は無効、 // isp, msp は ISP, MSP を示して有効。 - // スーパバイザ状態で SR_M なら da[15] が MSP を示し msp は無効、 + // スーパバイザ状態で SR_M なら A[7] が MSP を示し msp は無効、 // isp, usp は ISP, USP を示して有効。 - // スーパバイザ状態で !SR_M なら da[15] が ISP を示し isp は無効、 + // スーパバイザ状態で !SR_M なら A[7] が ISP を示し isp は無効、 // msp, usp は MSP, USP を示して有効。 uint32 usp; uint32 isp; @@ -122,15 +274,18 @@ struct m68kreg { struct fpframe fpframe; - public: - // SR の上位8ビット部分のみを返す - uint16 sr_h() { - return (s ? M68K_SR_S : 0) | (m ? M68K_SR_M : 0) | (intr_mask << 8); + // SR レジスタ全体を返す + uint16 GetSR() const { + return (s ? M68K::SR_S : 0) + | (m ? M68K::SR_M : 0) + | (intr_mask << 8) + | ccr.Get(); } }; // バス状態 -struct m68kbus { +struct m68kbus +{ // 論理アドレスと SSW。 // SSW はアクセス前に SSW_BUS_{R,W} と FC[012] をセットすること。 DEF_UNION64(, ssw_laddr, ssw, laddr); @@ -145,7 +300,7 @@ struct m68kbus { uint16 fc2; // バスが Write なら true を返す - bool IsWrite() const { return (ssw & SSW_BUS_R) == 0; } + bool IsWrite() const { return (ssw & M68K::SSW_BUS_R) == 0; } // このへんどうするか @@ -156,141 +311,14 @@ struct m68kbus { // FC を取得する。 // これは MMU ルーチンから呼ばれる。そのためこの時点ではすでに // FC0/1 と FC2 は ssw に合成済みなので、これでよい。 - uint GetFC() const { return ssw & SSW_FC_MASK; } -}; - -class m68kcpu final { - public: - m68kcpu() { } - ~m68kcpu() { } - - public: - m68kreg reg {}; - uint32 ppc {}; // 現在実行中の命令の先頭アドレス - uint16 ir {}; - uint16 ir2 {}; - - uint32 save_pd[8] {}; // -(An) を保存 - uint32 save_pi[8] {}; // (An)+ を保存 - uint8 flag_pd {}; // -(An) のどのレジスタを保存したか - uint8 flag_pi {}; // (An)+ のどのレジスタを保存したか - - // CPU の実行状態 - static const uint32 CPU_STATE_NORMAL = 0; - static const uint32 CPU_STATE_STOP = 1; - static const uint32 CPU_STATE_HALT = 2; - uint32 state {}; - - // MMU 状態 - bool mmu_enable {}; - // SRP - void SetSRP(uint32, uint32); - uint64 GetSRP() const { return reg.srp.q; } - uint32 GetSRPh() const { return reg.srp.h; } - uint32 GetSRPl() const { return reg.srp.l; } - // CRP - void SetCRP(uint32, uint32); - uint64 GetCRP() const { return reg.crp.q; } - uint32 GetCRPh() const { return reg.crp.h; } - uint32 GetCRPl() const { return reg.crp.l; } - // TT - void SetTT(int idx, uint32); - uint64 GetTT(int idx) const { return reg.tt[idx]; } - // TC - bool SetTC(uint32); - uint32 GetTC() const { return reg.tc; } - // MMUSR - void SetMMUSR(uint16); - uint16 GetMMUSR() const { return reg.mmusr; } - // MMU work - m68030TT mmu_tt[2] {}; - uint8 mmu_tt_quick[256] {}; - m68030TC mmu_tc {}; - m68030ATC atc {this}; - - private: - void mmu_enable_changed(); - - public: - int has_fpu {}; // 0:FPUなし、1:68881、2:68882(?) - bool fpu_dirty {}; - struct fpemu fe {}; - - // 現在の外部割り込みレベル - int intr_level {}; - - // 電源オンからの累積消費サイクル - uint64 used_cycle {}; - - int32 cycle_nocache {}; // ノーキャッシュケースの時の追加分 - - // ブランチ履歴 (例外履歴を含む) - BranchHistory_m680x0 brhist { BranchHistory::BrHist }; - // 例外履歴のみ - BranchHistory_m680x0 exhist { BranchHistory::ExHistOnly }; - - // バス - m68kbus bus {}; - - // A-Line, F-Line 命令エミュレーションのコールバックとユーザ引数。 - // ユーザ引数には関与しないので呼び出し側が自由に指定してよい。 - // コールバック側で処理完了したら true を返す。 - // デフォルトの処理(すなわちm68k例外)にする場合は false を返す。 - bool (*aline_callback)(m68kcpu *, void *) {}; - void *aline_arg {}; - bool (*fline_callback)(m68kcpu *, void *) {}; - void *fline_arg {}; - - // RESET 命令のコールバックとユーザ引数 - void (*resetop_callback)(void *) {}; - void *resetop_arg {}; - - // ダブルバスフォールトのコールバックとユーザ引数。 - void (*halt_callback)(void *) {}; - void *halt_arg {}; + uint GetFC() const { return ssw & M68K::SSW_FC_MASK; } - // VM 側デバイス - MPU680x0Device *dev {}; + // バスエラー時に SSW をセットする。 + void SET_SSW(bool use_mmu, uint size); }; -#define RegD(n) (cpu->reg.da[(n)]) -#define RegA(n) (cpu->reg.da[(n) + 8]) -#define RegR(n) (cpu->reg.da[(n)]) -#define RegPC (cpu->reg.pc) -#define RegPPC (cpu->ppc) -#define RegIR (cpu->ir) -#define RegIR2 (cpu->ir2) -#define RegSR (cpu->reg.sr_h() | cpu->reg.ccr.Get()) -#define RegVBR (cpu->reg.vbr) -#define RegUSP (cpu->reg.usp) -#define RegISP (cpu->reg.isp) -#define RegMSP (cpu->reg.msp) -#define RegSFC (cpu->reg.sfc) -#define RegDFC (cpu->reg.dfc) -#define RegCACR (cpu->reg.cacr) -#define RegCAAR (cpu->reg.caar) - -#define RegFP(n) (cpu->reg.fpframe.fpf_regs[n]) -#define RegFPCR (cpu->reg.fpframe.fpf_fpcr) -#define RegFPSR (cpu->reg.fpframe.fpf_fpsr) -#define RegFPIAR (cpu->reg.fpframe.fpf_fpiar) - -#define RegIRX ((RegIR >> 9) & 7) -#define RegIRY (RegIR & 7) -#define RegDX RegD(RegIRX) -#define RegAX RegA(RegIRX) -#define RegDY RegD(RegIRY) -#define RegAY RegA(RegIRY) - -// 外部公開ルーチン -extern m68kcpu *m68030_init(MPU680x0Device *dev_); -extern int m68030_exec(m68kcpu *cpu); -extern void m68030_power_on(m68kcpu *cpu); -extern bool m68030_interrupt(m68kcpu *cpu, int level); -extern bool m68030_check_interrupt(m68kcpu *cpu); -extern int m68030_exception_reset(m68kcpu *cpu); -extern int m68030_exception_interrupt(m68kcpu *cpu); - -// 外部で定義されるコールバック -extern void m68030_reset_inst(m68kcpu *cpu); -extern int m68030_interrupt_acknowledge(int level); +// 仮 +#define RegFP(n) (reg.fpframe.fpf_regs[n]) +#define RegFPCR (reg.fpframe.fpf_fpcr) +#define RegFPSR (reg.fpframe.fpf_fpsr) +#define RegFPIAR (reg.fpframe.fpf_fpiar)