--- nono/m88xx0/m88100.h 2026/04/29 17:04:34 1.1.1.2 +++ nono/m88xx0/m88100.h 2026/04/29 17:05:07 1.1.1.12 @@ -10,16 +10,15 @@ #include "branchhistory.h" #include "bus.h" #include "m88200.h" +#include #include // 外部リクエストフラグ // XXX m680x0 側にもよく似たものがあってどうしたもんか -#define CPU_REQ_STOP (0x00000001) // ストップ状態 -#define CPU_REQ_TRACE (0x00000004) // デバッガ有効 -#define CPU_REQ_PROMPT (0x00000008) // デバッガプロンプト -#define CPU_REQ_RELEASE (0x00000010) // 命令後に CPU 実行中断 #define CPU_REQ_INTR (0x00000020) // 命令後に割り込みチェック +class MPU88xx0Device; + // m88100 レジスタイメージを保持する構造体。 // この構造体はコピーや比較をするので、ポインタとかは置かないこと。 struct m88100reg @@ -70,6 +69,123 @@ struct m88100reg static const uint32 DM_D1 = DM_SIZE_W | DM_DOUB1; static const uint32 DM_D2 = DM_SIZE_W; + // FPECR(fcr0) + // 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 + // +---------------+---------------+---------------+-+-+-+-+-+-+-+-+ + // | |I|U|P|O|D|U|O|I| + // | 0 |O|N|V|P|Z|F|V|N| + // +---------------+---------------+---------------+-+-+-+-+-+-+-+-+ + static const uint32 FPECR_MASK = 0x000000ff; // 有効ビットマスク + static const uint32 FPECR_FIOV = 0x00000080; // FP Integer Overflow + static const uint32 FPECR_FUNIMP= 0x00000040; // FP Unimplemented + static const uint32 FPECR_FPRV = 0x00000020; // FP Privilege Violation + static const uint32 FPECR_FROP = 0x00000010; // FP Reserved Operand + static const uint32 FPECR_FDVZ = 0x00000008; // FP Divice-by-Zero + static const uint32 FPECR_FUNF = 0x00000004; // FP Underflow + static const uint32 FPECR_FOVF = 0x00000002; // FP Overflow + static const uint32 FPECR_FINX = 0x00000001; // FP Inexact + + // FPHS1(fcr1) + // 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| Exponent | High order 20 bits of Mantissa | + // +-+---------------------+---------------------------------------+ + + // FPLS1(fcr2) + // 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 + // +---------------------------------------------------------------+ + // | Low order bits of Mantissa or Integer Operand | + // +---------------------------------------------------------------+ + + // FPHS2(fcr3) + // 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| Exponent | High order 20 bits of Mantissa | + // +-+---------------------+---------------------------------------+ + + // FPLS2(fcr4) + // 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 + // +---------------------------------------------------------------+ + // | Low order bits of Mantissa or Integer Operand | + // +---------------------------------------------------------------+ + + // FPPT(fcr5) + // 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 + // +---------------+---------------+---------+---+---+---+---------+ + // | 0 | OPCODE |T1 |T2 |TD | DestReg | + // +---------------+---------------+---------+---+---+---+---------+ + static const uint32 FPPT_MASK = 0x0000ffff; // 有効ビットマスク + static const uint32 FPPT_OPCODE = 0x0000f800; // Opcode + static const uint32 FPPT_T1 = 0x00000600; // Source1 Operand Size + static const uint32 FPPT_T2 = 0x00000180; // Source2 Operand Size + static const uint32 FPPT_TD = 0x00000060; // Destination Size + static const uint32 FPPT_DEST = 0x0000001f; // Destination Register No. + + // FPRH(fcr6) + // 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|RM |G|R|S|A| 0 | High Order Bits of Mantissa | + // +-----+-+-+-+-+-+-----+---------+-------------+-----------------+ + static const uint32 FPRH_MASK = 0xfe1fffff; // 有効ビットマスク + static const uint32 FPRH_SIGN = 0x80000000; // Result Sign + static const uint32 FPRH_RNDMODE= 0x60000000; // Rounding Mode for Res. + static const uint32 FPRH_GUARD = 0x10000000; // Guard Bit for Result + static const uint32 FPRH_ROUND = 0x08000000; // Round Bit for Result + static const uint32 FPRH_STICKY = 0x04000000; // Sticky Bit for Result + static const uint32 FPRH_ADDONE = 0x02000000; // Add One + static const uint32 FPRH_MANT = 0x001fffff; // Mantissa(High) + static const uint32 FPRH_1 = 0x00100000; // 隠し実数部の 1 + + // FPRL(fcr7) + // 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 + // +---------------------------------------------------------------+ + // | Low Order Bits of Mantissa | + // +---------------------------------------------------------------+ + + // FPIT(fcr8) + // 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 + // +-----------------------+-------+---------+-+-+-+-+-+-+---------+ + // | | | |D|E|E|E|E|E| | + // | RESEXP (12bits) | 0 | OPCODE |S|V|Z|U|O|N| DestReg | + // +-----------------------+-------+---------+-+-+-+-+-+-+---------+ + static const uint32 FPIT_MASK = 0xfff0ffff; // 有効ビットマスク + static const uint32 FPIT_RESEXP = 0xfff00000; // Result Exponent + static const uint32 FPIT_OPCODE = 0x0000f800; // Opcode + static const uint32 FPIT_DESTSIZ= 0x00000400; // Destination Size + static const uint32 FPIT_EFINV = 0x00000200; // Enable Invalid Op. + static const uint32 FPIT_EFDVZ = 0x00000100; // Enable Divide-by-Zero + static const uint32 FPIT_EFUNF = 0x00000080; // Enable Underflow + static const uint32 FPIT_EFOVF = 0x00000040; // Enable Overflow + static const uint32 FPIT_EFINX = 0x00000020; // Enable Inexact + static const uint32 FPIT_DEST = 0x0000001f; // Destination Register No. + + // FPSR(fcr62) + // 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 + // +---------------+---------------+---------------+-----+-+-+-+-+-+ + // | |A|A|A|A|A| + // | 0 |V|D|U|O|I| + // +---------------+---------------+---------------+-----+-+-+-+-+-+ + static const uint32 FPSR_MASK = 0x0000001f; // 有効ビットマスク + static const uint32 FPSR_AFINV = 0x00000010; // Acc. Invalid Op. Flag + static const uint32 FPSR_AFDVZ = 0x00000008; // Acc. Divide-by-Zero Flag + static const uint32 FPSR_AFUNF = 0x00000004; // Acc. Underflow Flag + static const uint32 FPSR_AFOVF = 0x00000002; // Acc. Overflow Flag + static const uint32 FPSR_AFINX = 0x00000001; // Acc. Inexact Flag + + // FPCR(fcr63) + // 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 + // +---------------+---------------+---+-----------+-----+-+-+-+-+-+ + // | | | |E|E|E|E|E| + // | 0 |RM | |V|D|U|O|I| + // +---------------+---------------+---+-----------+-----+-+-+-+-+-+ + static const uint32 FPCR_MASK = 0x0000c01f; // 有効ビットマスク + static const uint32 FPCR_RM = 0x0000c000; // Rounding Mask + static const uint32 FPCR_EFINV = 0x00000010; // Enable Invalid Operation + static const uint32 FPCR_EFDVZ = 0x00000008; // Enable Divide-by-Zero + static const uint32 FPCR_EFUNF = 0x00000004; // Enable Underflow + static const uint32 FPCR_EFOVF = 0x00000002; // Enable Overflow + static const uint32 FPCR_EFINX = 0x00000001; // Enable Inexact + // 頻繁にアクセスしそうな変数はオフセットの若いほうに持ってきておく。 // 実行中の命令 @@ -129,50 +245,69 @@ struct m88100reg bool IsSuper() const { return (psr & PSR_SUPER) != 0; } bool IsUser() const { return (psr & PSR_SUPER) == 0; } + // 割り込みが許可なら true + bool IsIntrEnable() const { return (psr & PSR_IND) == 0; } + + // SFU1(FPU)が有効なら true + bool IsFPUEnable() const { return (psr & PSR_SFD1) == 0; } + // MXM (Misaligned Access Enable) なら true bool IsMXM() const { return (psr & PSR_MXM) != 0; } // キャリーフラグが立っていれば 1 を返す uint32 GetCY() const { return (psr >> 28) & 1; } - // キャリーフラグをセットする。cy は最下位ビットのみ参照する + + // キャリーフラグをセットする。 + // cy のうち最下位ビットのみ参照する (呼び出し側はマスクせず渡してよい) void SetCY(uint cy) { psr &= ~PSR_C; psr |= ((cy & 1) << 28); } + static const uint32 fcr_mask[11]; static const char * const sipname[3]; static const char * const dmt_en_str[16]; }; class m88kcpu : public m88100reg { + static const uint64 DELAYSLOT = 1ULL << 62; + + enum ExceptionKind + { + NORMAL, + DATA, + ERROR, + INTR, + TRAP, + }; + public: - m88kcpu(); - virtual ~m88kcpu(); + static const uint32 CPU_STATE_NORMAL = 0; + static const uint32 CPU_STATE_STOP = 1; // 疑似 STOP 状態 public: - void Reset(uint32 reset_vector); - uint32 Run(uint64 request); - void Release(); + m88kcpu(MPU88xx0Device *dev_); + virtual ~m88kcpu(); - uint64 total_cycle = 0; // 積算実行サイクル数 + void PowerOn(); + uint64 Reset(); - void Interrupt(); + int Exec(); + int ExecPseudoStop(); + + // 割り込み信号線が変化したことの通知を受ける。 + // level は 0 か 1。 + void Interrupt(int level); // PID.VERSION を設定する (初期化時に呼ぶ) void SetVersion(uint32 version); - public: - // [0] 命令バス - // [1] データバス - m88200 cmmu[2]; + // クラス外部からの xip 取得 + uint32 GetXIP() const { return xip; } - uint64 fetch() { - nip = fip; - opF = cmmu[0].load_32(fip); - fip += 4; - return opF; - } + // クラス外部からの vbr 取得 + uint32 GetVBR() const { return vbr; } // op が>=0ならバスエラーは起きていない // そのときに DELAYSLOT bit が 0 ならば通常 @@ -183,64 +318,92 @@ class m88kcpu : public m88100reg // バスエラーかどうかのチェックのほうが回数が多いため、 // バスエラー優先にしたい。 - - bool OpIsBusErr(uint64 op) const { + static bool OpIsBusErr(uint64 op) { return (int64)op < 0; } - bool OpIsDelay(uint64 op) const { + + // op が DelaySlot 実行なら true を返す。デバッガで表示用に使う。 + static bool OpIsDelay(uint64 op) { return (OpIsBusErr(op) ? ~op : op) & DELAYSLOT; } - // PSR を変更する。 + // サイクルを加算 (m88200 から使う) + // 今は単純に加算しているだけでオーバーラップなどは考慮してない + void AddCycle(int32 wait) { used_cycle += wait; } + + std::atomic atomic_reqflag {}; // リクエストフラグ + + // CPU の状態 + uint32 cpu_state {}; + + // [0] 命令バス + // [1] データバス + std::array cmmu {}; + + // ブランチ履歴 (例外履歴を含む) + BranchHistory_m88xx0 brhist { BranchHistory::BrHist }; + // 例外履歴のみ + BranchHistory_m88xx0 exhist { BranchHistory::ExHistOnly }; + + // 32bit 命令コードからディスパッチ用の 12bit に変換。 + static uint32 op32_to_12(uint32 op) { + return ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f); + } + + // 疑似 STOP 状態に入る機能を有効にする場合 true + bool pseudo_stop_enable {}; + + // DOS call エミュレーションコールバックを設定する + void SetFLineCallback(bool (*callback)(m88kcpu *, void *), void *arg); + + private: + uint64 fetch() { + nip = fip; + opF = cmmu[0].load_32(fip); + fip += 4; + return opF; + } + + // PSR を newpsr に変更する。 // CY ビットは特別にこの関数を経由しないで変更してよいことにする。 void SetPSR(uint32 newpsr) { psr = newpsr; + SetPSR(); + } + // 更新された psr に基づいて、PSR 変更によって必要な処理をする。 + // CY ビットを変更した場合は呼ばなくてよいことにする。 + void SetPSR() + { // CMMU に S/U 信号を出す cmmu[0].SetSuper(IsSuper()); cmmu[1].SetSuper(IsSuper()); } - // クラス外部からの xip 取得 - uint32 Getxip() const { - return xip; - } - - enum ExceptionKind - { - NORMAL, - DATA, - ERROR, - INTR, - TRAP, - }; + // FPxS1, FPxS2 レジスタを設定 + void SetFPxS(uint32& h, uint32& l, double src, uint32 t); + void SetFPS1(double src, uint32 t1) { SetFPxS(fphs1, fpls1, src, t1); } + void SetFPS2(double src, uint32 t2) { SetFPxS(fphs2, fpls2, src, t2); } + void SetFPS1(uint32 src) { fpls1 = src; } + void SetFPS2(uint32 src) { fpls2 = src; } + // FP Result を FPIT, FPRH, FPRL レジスタに設定 + void SetFPRx(double src); void Exception(int vec); void ExceptionCore(int vec, ExceptionKind cause); - void ReadDataException(uint32 addr, uint32 flag); - void WriteDataException(uint32 addr, uint32 data, uint32 flag); - void XmemDataException(uint32 addr, uint32 data, uint32 flag); - - // ブランチ履歴 - BranchHistory brhist {}; - - // FPU - bool IsFPUEnable() { return !(psr & PSR_SFD1); } - void fpu_unimpl(); - - std::atomic atomic_reqflag {}; // リクエストフラグ - - private: - const uint64 DELAYSLOT = 1ULL << 62; - - // OpSetDelay を一つの op に対して複数回呼ばないでください - uint64 OpSetDelay(uint64 op) const { - return op ^ DELAYSLOT; - } + uint32 Calcdmt(uint32 flag); + void ReadDataException32(uint32 addr, uint32 flag); + void ReadDataException64(uint32 addr, uint32 flag); + void WriteDataException32(uint32 addr, uint32 flag); + void WriteDataException64(uint32 addr, uint32 flag); + void XmemDataException(uint32 addr, uint32 flag); + void FPPreciseException(uint32 cause, double s2); + void FPPreciseException(uint32 cause, double s1, double s2); + void FPPreciseException(uint32 cause); + void FPImpreciseException(uint32 cause); // ブランチ処理用 - void EnterBranch(); - void DoBranch(uint32 toaddr); + void EnterBranch(uint32 toaddr); void ExitBranch(); void ExitDelayBranch(); uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ @@ -249,6 +412,8 @@ class m88kcpu : public m88100reg bool ldst_usr(uint32& usr); uint32 ldst_scale(uint32 size); bool ldst_align(uint32 size, uint32& addr); + // 浮動小数点数命令用の処理 + void ops_int(int mode); #define OP_PROTO(name) void __CONCAT(op_,name)() #include "m88100ops.h" @@ -258,12 +423,46 @@ OP_PROTO(illegal); void op_unimpl() { printf("unimplemented op XIP=%08x opX=%08x\n", xip, (uint32)opX); } -}; + void fpu_unimpl(); -// とりあえず -static inline uint32 -op32_to_12(uint32 op) -{ - uint32 op12 = ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f); - return op12; -} + // 今のところサイクルを正確に実装するのは無理なので + // 適当に全部積み上げてある。 + + // 電源オンからの累積消費サイクル + uint64 used_cycle {}; + + // ペンディング中の割り込みレベル + int intr_pending {}; + + // float,double と整数値の相互変換 + static float u2f(uint32 u) { + float v; + memcpy(&v, &u, sizeof(v)); + return v; + } + static double u2d(uint64 u) { + double v; + memcpy(&v, &u, sizeof(v)); + return v; + } + static uint32 f2u(float v) { + uint32 u; + memcpy(&u, &v, sizeof(u)); + return u; + } + static uint64 d2u(double v) { + uint64 u; + memcpy(&u, &v, sizeof(u)); + return u; + } + + void ChangeState(uint32 new_state); + + int instruction_in_stop {}; + + MPU88xx0Device *dev {}; + + // DOS call エミュレーション + bool (*fline_callback)(m88kcpu *, void *) = NULL; + void *fline_arg {}; +};