--- nono/m88xx0/m88100.h 2026/04/29 17:04:31 1.1 +++ nono/m88xx0/m88100.h 2026/04/29 17:04:54 1.1.1.9 @@ -1,50 +1,25 @@ // // nono -// Copyright (C) 2020 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #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) // 命令後に割り込みチェック - -class m88200 -{ - public: - m88200(); - virtual ~m88200(); - - public: - uint64 load_8(uint32 addr) { - return vm_phys_read_8(addr); - } - uint64 load_16(uint32 addr) { - return vm_phys_read_16(addr); - } - uint64 load_32(uint32 addr) { - return vm_phys_read_32(addr); - } - uint64 store_8(uint32 addr, uint32 data) { - return vm_phys_write_8(addr, data); - } - uint64 store_16(uint32 addr, uint32 data) { - return vm_phys_write_16(addr, data); - } - uint64 store_32(uint32 addr, uint32 data) { - return vm_phys_write_32(addr, data); - } - - uint32 idr = 0; - //: -}; +#define CPU_REQ_RESET (0x00000040) // リセット例外 // m88100 レジスタイメージを保持する構造体。 // この構造体はコピーや比較をするので、ポインタとかは置かないこと。 @@ -155,46 +130,64 @@ 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 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(); - public: - void Reset(uint32 reset_vector); - uint32 Run(uint64 request); + void PowerOn(); + void RequestReset(); + + uint32 Run(uint32 delta); void Release(); - uint64 total_cycle = 0; // 積算実行サイクル数 + // 仮想時刻を返す + uint64 GetVTime() const { return total_vtime + Cycle2Vtime(used_cycle); } - void Interrupt(); + // 割り込み信号線が変化したことの通知を受ける。 + // level は 0 か 1。 + void Interrupt(int level); - public: - // [0] 命令バス - // [1] データバス - m88200 cmmu[2]; + // PID.VERSION を設定する (初期化時に呼ぶ) + void SetVersion(uint32 version); - uint64 fetch() { - nip = fip; - opF = cmmu[0].load_32(fip); - fip += 4; - return opF; - } + // クラス外部からの xip 取得 + uint32 GetXIP() const { return xip; } // op が>=0ならバスエラーは起きていない // そのときに DELAYSLOT bit が 0 ならば通常 @@ -205,68 +198,130 @@ 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; } - // クラス外部からの xip 取得 - uint32 Getxip() const { - return xip; - } + // サイクルを加算 (m88200 から使う) + // 今は単純に加算しているだけでオーバーラップなどは考慮してない + void AddCycle(int32 wait) { used_cycle += wait; } - enum ExceptionKind - { - NORMAL, - ERROR, - INTR, - TRAP, - }; + // MPU クロックを設定 + void SetClockSpeed(uint32 clock_khz_); - void Exception(int vec); - void ExceptionCore(int vec, ExceptionKind cause); - void ReadDataException(uint32 addr, uint32 flag); - void WriteDataException(uint32 addr, uint32 data, uint32 flag); + std::atomic atomic_reqflag {}; // リクエストフラグ - // FPU - bool IsFPUEnable() { return !(psr & PSR_SFD1); } - void fpu_unimpl(); + // [0] 命令バス + // [1] データバス + m88200 cmmu[2] {}; - std::atomic atomic_reqflag {}; // リクエストフラグ + // ブランチ履歴 (例外履歴を含む) + 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 {}; private: - const uint64 DELAYSLOT = 1ULL << 62; + void Reset(); + + uint64 fetch() { + nip = fip; + opF = cmmu[0].load_32(fip); + fip += 4; + return opF; + } - // OpSetDelay を一つの op に対して複数回呼ばないでください - uint64 OpSetDelay(uint64 op) const { - return op ^ DELAYSLOT; + // 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; + } } + 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 FPException(int fpex); + // ブランチ処理用 - void EnterBranch(); + void EnterBranch(uint32 toaddr); void ExitBranch(); void ExitDelayBranch(); + uint32 nop_counter {}; // STOP 検出用の nop 命令カウンタ + // ロードストア命令用の下処理 - bool ldst_usr(uint32 size, uint32& usr); + 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); } -}; + void fpu_unimpl(); -// とりあえず -static inline uint32 -op32_to_12(uint32 op) -{ - uint32 op12 = ((op >> 20) & 0x0fc0) | ((op >> 10) & 0x003f); - return op12; -} + // 仮想時刻 [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 {}; + + // 例外名 + static const char * const exception_names[]; +};