--- nono/m88xx0/m88100.h 2026/04/29 17:05:05 1.1.1.11 +++ nono/m88xx0/m88100.h 2026/04/29 17:05:15 1.1.1.14 @@ -7,23 +7,11 @@ #pragma once #include "header.h" -#include "branchhistory.h" -#include "bus.h" -#include "m88200.h" -#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) // 命令後に割り込みチェック -#define CPU_REQ_RESET (0x00000040) // リセット例外 -// m88100 レジスタイメージを保持する構造体。 -// この構造体はコピーや比較をするので、ポインタとかは置かないこと。 -struct m88100reg +class MPU88xx0Device; + +// 定数。 +struct M88100 { // PID(cr0) static const uint32 PID_REV_MASK = 0x0000ff00; // 0 = MC88100 @@ -188,16 +176,49 @@ struct m88100reg static const uint32 FPCR_EFOVF = 0x00000002; // Enable Overflow static const uint32 FPCR_EFINX = 0x00000001; // Enable Inexact + // 例外 + static const uint32 EXCEP_RESET = 0; + static const uint32 EXCEP_INTERRUPT = 1; + static const uint32 EXCEP_INST = 2; + static const uint32 EXCEP_DATA = 3; + static const uint32 EXCEP_MISALIGNED = 4; + static const uint32 EXCEP_UNIMPL_OP = 5; + static const uint32 EXCEP_PRIV = 6; + static const uint32 EXCEP_BOUNDS = 7; + static const uint32 EXCEP_INT_DIV = 8; + static const uint32 EXCEP_INT_OVF = 9; + static const uint32 EXCEP_ERROR = 10; + + static const uint32 EXCEP_SFU1_PRECISE = 114; + static const uint32 EXCEP_SFU1_IMPRECISE= 115; + static const uint32 EXCEP_SFU2_PRECISE = 116; + static const uint32 EXCEP_SFU3_PRECISE = 118; + static const uint32 EXCEP_SFU4_PRECISE = 120; + static const uint32 EXCEP_SFU5_PRECISE = 122; + static const uint32 EXCEP_SFU6_PRECISE = 124; + static const uint32 EXCEP_SFU7_PRECISE = 126; + + // 32bit 命令コードからディスパッチ用の 12bit に変換。 + // ops と disasm で使うため。 + static uint32 op32_to_12(uint32 op) { + return ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f); + } +}; + +// m88100 レジスタイメージを保持する構造体。 +// この構造体はコピーや比較をするので、ポインタとかは置かないこと。 +struct m88100reg +{ // 頻繁にアクセスしそうな変数はオフセットの若いほうに持ってきておく。 // 実行中の命令 - uint64 opX = 0; + uint64 opX {}; // プリフェッチ命令 - uint64 opF = 0; + uint64 opF {}; - uint32 xip = 0; - uint32 nip = 0; - uint32 fip = 0; + uint32 xip {}; + uint32 nip {}; + uint32 fip {}; uint32 r[32] {}; union { @@ -240,249 +261,7 @@ struct m88100reg }; }; - // 直近のデータアクセスアドレス - uint32 lastaddr; - - // スーパーバイザ/ユーザモードなら true - 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 のうち最下位ビットのみ参照する (呼び出し側はマスクせず渡してよい) - 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(); - - void PowerOn(); - void RequestReset(); - - uint32 Run(uint32 delta); - void Release(); - - // 仮想時刻を返す - uint64 GetVTime() const { return total_vtime + Cycle2Vtime(used_cycle); } - - // 割り込み信号線が変化したことの通知を受ける。 - // level は 0 か 1。 - void Interrupt(int level); - - // PID.VERSION を設定する (初期化時に呼ぶ) - void SetVersion(uint32 version); - - // クラス外部からの xip 取得 - uint32 GetXIP() const { return xip; } - - // op が>=0ならバスエラーは起きていない - // そのときに DELAYSLOT bit が 0 ならば通常 - // bit32 が 1 ならば遅延スロット命令 - // op が負数ならバスエラーが起きた - // そのときに DELAYSLOT bit が 1 ならば通常バスエラー - // bit32 が 0 ならば遅延スロットでのバスエラー - // バスエラーかどうかのチェックのほうが回数が多いため、 - // バスエラー優先にしたい。 - - static bool OpIsBusErr(uint64 op) { - return (int64)op < 0; - } - - // op が DelaySlot 実行なら true を返す。デバッガで表示用に使う。 - static bool OpIsDelay(uint64 op) { - return (OpIsBusErr(op) ? ~op : op) & DELAYSLOT; - } - - // サイクルを加算 (m88200 から使う) - // 今は単純に加算しているだけでオーバーラップなどは考慮してない - void AddCycle(int32 wait) { used_cycle += wait; } - - // MPU クロックを設定 - void SetClockSpeed(uint32 clock_khz_); - - std::atomic atomic_reqflag {}; // リクエストフラグ - - // [0] 命令バス - // [1] データバス - m88200 cmmu[2] {}; - - // ブランチ履歴 (例外履歴を含む) - 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); - } - - // 例外名を返す - static const char *GetExceptionName(int vector); - - // 疑似 STOP 状態に入る機能を有効にする場合 true - bool pseudo_stop_enable {}; - - // DOS call エミュレーションコールバックを設定する - void SetFLineCallback(bool (*callback)(m88kcpu *, void *), void *arg); - - private: - void Reset(); - - 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()); - // 割り込み許可なら割り込みチェック - if (IsIntrEnable()) { - atomic_reqflag |= CPU_REQ_INTR; - } - } - - // 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); - 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(uint32 toaddr); - void ExitBranch(); - void ExitDelayBranch(); - uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ - - // ロードストア命令用の下処理 - 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" -OP_PROTO(illegal); -#undef OP_PROTO - - void op_unimpl() { - printf("unimplemented op XIP=%08x opX=%08x\n", xip, (uint32)opX); - } - void fpu_unimpl(); - - // 仮想時刻 [nsec] - uint64 total_vtime {}; - - // サイクル数を仮想時間 [nsec] に変換 - uint64 Cycle2Vtime(int32 cycle) const { - return (int64)cycle * c2v; - } - - // 仮想時間 [nsec] をサイクル数に変換 - uint32 Vtime2Cycle(uint32 vtime) const { - return ((uint64)vtime * v2c_factor) >> v2c_shift; - } - - // 今のところサイクルを正確に実装するのは無理なので - // 適当に全部積み上げてある。 - uint32 used_cycle {}; // 現在のターンでこれまでに消費したサイクル数 - uint32 goal_cycle {}; // 現在のターンで消費すべきサイクル数 - uint32 clock_khz {}; // MPU クロック [kHz] - uint32 c2v {}; // サイクル数を nsec に変換する際の係数 - uint64 v2c_factor {}; // nsec をサイクル数に変換する際の乗算係数 - uint32 v2c_shift {}; // nsec をサイクル数に変換する際のシフト係数 - - // ペンディング中の割り込みレベル - 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; - } - - // DOS call エミュレーション - bool (*fline_callback)(m88kcpu *, void *) = NULL; - void *fline_arg {}; - - // 例外名 - static const char * const exception_names[]; -};