--- nono/m88xx0/m88100.h 2026/04/29 17:04:34 1.1.1.2 +++ nono/m88xx0/m88100.h 2026/04/29 17:05:56 1.1.1.17 @@ -7,28 +7,25 @@ #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) // 命令後に割り込みチェック -// m88100 レジスタイメージを保持する構造体。 -// この構造体はコピーや比較をするので、ポインタとかは置かないこと。 -struct m88100reg +// 定数。 +struct M88100 { // PID(cr0) + // 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 | REV | VER |M| + // +---------------+---------------+---------------+-------------+-+ static const uint32 PID_REV_MASK = 0x0000ff00; // 0 = MC88100 static const uint32 PID_VER_MASK = 0x000000fe; static const uint32 PID_MASTER = 0x00000001; + // PSR(cr1) + // 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|B|S|C| |D|M|I|S| + // |U|O|E| | 0 |1|X|N|F| + // +-+-+-+-+-------+---------------+---------------+-------+-+-+-+-+ static const uint32 PSR_SUPER = 0x80000000; static const uint32 PSR_BO_LE = 0x40000000; // ByteOrder(Little) static const uint32 PSR_SER = 0x20000000; @@ -39,11 +36,20 @@ struct m88100reg static const uint32 PSR_SFRZ = 0x00000001; // Shadow Freeze // 例外処理で使用される S*IP + // 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*IP |V|E| + // +---------------+---------------+---------------+-----------+-+-+ static const uint32 SIP_MASK = 0xfffffffcU; static const uint32 SIP_V = 0x00000002; static const uint32 SIP_E = 0x00000001; // DMTn、データ例外 + // 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 + // +---------------+---------------+-+-+-+-+-------+-+-+-+-+-+-+-+-+ + // | |B|D|D|L| |S|E|E|E|E|W|V| + // | 0 |O|A|B|K| DREG | |3|2|1|0|R| | + // +---------------+---------------+-+-+-+-+-------+-+-+-+-+-+-+-+-+ static const uint32 DM_BO = 0x00008000; static const uint32 DM_DAS = 0x00004000; static const uint32 DM_DOUB1 = 0x00002000; @@ -70,26 +76,211 @@ 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 + + // 例外ベクタ。 + static const uint32 EXCVEC_RESET = 0; + static const uint32 EXCVEC_INTERRUPT = 1; + static const uint32 EXCVEC_INST = 2; + static const uint32 EXCVEC_DATA = 3; + static const uint32 EXCVEC_MISALIGNED = 4; + static const uint32 EXCVEC_UNIMPL_OP = 5; + static const uint32 EXCVEC_PRIV = 6; + static const uint32 EXCVEC_BOUNDS = 7; + static const uint32 EXCVEC_INT_DIV = 8; + static const uint32 EXCVEC_INT_OVF = 9; + static const uint32 EXCVEC_ERROR = 10; + static const uint32 EXCVEC_SFU1_PRECISE = 114; + static const uint32 EXCVEC_SFU1_IMPRECISE = 115; + static const uint32 EXCVEC_SFU2_PRECISE = 116; + static const uint32 EXCVEC_SFU3_PRECISE = 118; + static const uint32 EXCVEC_SFU4_PRECISE = 120; + static const uint32 EXCVEC_SFU5_PRECISE = 122; + static const uint32 EXCVEC_SFU6_PRECISE = 124; + static const uint32 EXCVEC_SFU7_PRECISE = 126; + + // 例外の優先順位 (LSB 側が優先度高)。一部カテゴリ分けも兼ねる。 + // + // 優先度 例外 + // 1 RESET + // 1 (ERROR) + // 2 INST + // 3 UNIMPL_OP + // 4 PRIV + // 5 INTERNAL … 内部発生例外のうちトラップ以外 + // 5 TRAP … 内部発生例外のうちトラップのみ + // -- (OUTER) …これ以降のどれかが立っているという代表ビット + // 6 INTERRUPT + // 7 SFU_IMPRECISE + // 8 DATA + // + // ERROR 例外は Table. 6-2 には載ってないけど、実質ダブルバスフォールト + // なので、リセットに準じる高さの気がする…。 + // TRAP は他の内部発生例外 (INTERNAL) とは区別が必要なので分けてある。 + // INTERNAL と TRAP はこの優先度だけでなくベクタ情報も必要。 + // INTERRUPT と DATA はどちらが起きても同時に処理するので、 + // どちらかを立てたまま OUTER ビットで処理させる。 + // SFU_IMPRECISE は未調査。 + static const uint32 EXCPRI_RESET = (1U << 0); + static const uint32 EXCPRI_ERROR = (1U << 1); + static const uint32 EXCPRI_INST = (1U << 2); + static const uint32 EXCPRI_UNIMPL_OP = (1U << 3); + static const uint32 EXCPRI_PRIV = (1U << 4); + static const uint32 EXCPRI_INTERNAL = (1U << 5); + static const uint32 EXCPRI_TRAP = (1U << 6); + static const uint32 EXCPRI_OUTER = (1U << 7); + static const uint32 EXCPRI_INTERRUPT = (1U << 8); + static const uint32 EXCPRI_SFU_IMPRECISE = (1U << 9); + static const uint32 EXCPRI_DATA = (1U << 10); + static const uint32 EXCPRI_OUTER_MASK = + EXCPRI_INTERRUPT | EXCPRI_SFU_IMPRECISE | EXCPRI_DATA; + + // 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 { uint32 cr[21] {}; struct { - uint32 pid; // cr0 + uint32 pid; // cr0 (ReadOnly) uint32 psr; // cr1 uint32 epsr; // cr2 uint32 ssbr; // cr3 - uint32 sxip; // cr4 + uint32 sxip; // cr4 (ReadOnly) uint32 snip; // cr5 uint32 sfip; // cr6 uint32 vbr; // cr7 @@ -122,148 +313,7 @@ struct m88100reg }; }; - // 直近のデータアクセスアドレス - uint32 lastaddr; - - // スーパーバイザ/ユーザモードなら true - bool IsSuper() const { return (psr & PSR_SUPER) != 0; } - bool IsUser() const { return (psr & PSR_SUPER) == 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 -{ - public: - m88kcpu(); - virtual ~m88kcpu(); - - public: - void Reset(uint32 reset_vector); - uint32 Run(uint64 request); - void Release(); - - uint64 total_cycle = 0; // 積算実行サイクル数 - - void Interrupt(); - - // PID.VERSION を設定する (初期化時に呼ぶ) - void SetVersion(uint32 version); - - public: - // [0] 命令バス - // [1] データバス - m88200 cmmu[2]; - - uint64 fetch() { - nip = fip; - opF = cmmu[0].load_32(fip); - fip += 4; - return opF; - } - - // op が>=0ならバスエラーは起きていない - // そのときに DELAYSLOT bit が 0 ならば通常 - // bit32 が 1 ならば遅延スロット命令 - // op が負数ならバスエラーが起きた - // そのときに DELAYSLOT bit が 1 ならば通常バスエラー - // bit32 が 0 ならば遅延スロットでのバスエラー - // バスエラーかどうかのチェックのほうが回数が多いため、 - // バスエラー優先にしたい。 - - - bool OpIsBusErr(uint64 op) const { - return (int64)op < 0; - } - bool OpIsDelay(uint64 op) const { - return (OpIsBusErr(op) ? ~op : op) & DELAYSLOT; - } - - // PSR を変更する。 - // CY ビットは特別にこの関数を経由しないで変更してよいことにする。 - void SetPSR(uint32 newpsr) - { - psr = newpsr; - // CMMU に S/U 信号を出す - cmmu[0].SetSuper(IsSuper()); - cmmu[1].SetSuper(IsSuper()); - } - - // クラス外部からの xip 取得 - uint32 Getxip() const { - return xip; - } - - enum ExceptionKind - { - NORMAL, - DATA, - ERROR, - INTR, - TRAP, - }; - - 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; - } - - // ブランチ処理用 - void EnterBranch(); - void DoBranch(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); - -#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); - } -}; - -// とりあえず -static inline uint32 -op32_to_12(uint32 op) -{ - uint32 op12 = ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f); - return op12; -}