--- nono/vm/mfp.h 2026/04/29 17:05:33 1.1.1.16 +++ nono/vm/mfp.h 2026/04/29 17:06:00 1.1.1.20 @@ -11,10 +11,10 @@ #pragma once #include "device.h" -#include "event.h" #include class InterruptDevice; +class Syncer; class X68030Keyboard; struct MFP @@ -91,9 +91,11 @@ struct MFP ir16 isr; ir16 imr; - // - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ // VR | V7 | V6 | V5 | V4 | S | --- | --- | --- | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // | | | | | // | | | | +------------ In-Service Register Enable // +-----+-----+-----+------------------ Vector Number uint8 vr_vec; // ベクタの上位4ビット @@ -101,26 +103,34 @@ struct MFP uint8 GetVR() const { return vr_vec | vr_s; } // タイマー - struct { - // TDR のカウンタをメインカウンタと呼び、このメインカウンタを - // 1減らすためのカウンタをプリスケーラカウンタと呼ぶ。 - // 実際のハードウェアは 4MHz のクロック入力ごとにプリスケーラカウンタを - // カウントしていき指定回数カウントすればメインカウンタを1減らすのだが、 - // この実装ではどちらのカウンタも持たず、タイマー終了時刻と現在時刻で - // 管理する。そのためメインカウンタの値はこの時間差から求める。 - - // tdr はカウンタの現在値 (1-256)。 - // カウンタが 1 から 0 になるタイミングで next_tdr を代入する。 + struct Timer { + // タイマー停止中は、カウンタの現在値 (1-256) を保持。 + // タイマー動作中は、現在カウントダウン中のカウントの初期値(1-256)。 + // TxDR レジスタ値際は、タイマー動作中/停止中どちらでも + // これではなく GetTDR() を使うこと。 uint32 tdr; - // next_tdr は次回の TxDR のリロード値 (1-256)。 + // 次回の TxDR のリロード値 (1-256)。 uint32 next_tdr; + // タイマーの開始時刻。 + uint64 start; + // tcr は書き込み値、現在のモードを保持する。 // TACR: --- --- --- RST AC3 AC2 AC1 AC0 // TBCR: --- --- --- RST BC3 BC2 BC1 BC0 // TCDCR: --- CC2 CC1 CC0 --- DC2 DC1 DC0 uint8 tcr; + + bool IsStopped() const noexcept { return (tcr == 0); } + bool IsDelay() const noexcept { return (0 < tcr && tcr < 8); } + bool IsEvent() const noexcept { return (tcr == 8); } + bool IsPulseWidth() const noexcept { return (tcr > 8); } + + // 現在時刻 now とメインカウンタ周期 period から + // 現在のメインカウンタの値を求める。 + // タイマー動作中のみ呼ぶこと。 + uint8 GetCounter(uint64 now, uint64 period) const; } timer[4]; // TCDCR の値 @@ -130,8 +140,11 @@ struct MFP uint8 scr; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ // UCR | CLK | WL | ST | PE | E/O | --- | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // | | | | | // | | | | +--------- %1で偶数パリティ // | | | +--------------- %1でパリティエラー // | | +------------------- スタート/ストップビット @@ -148,8 +161,11 @@ struct MFP static const uint32 UCR_EO = 0x02; uint8 ucr; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ // RSR | BF | OE | PE | FE | B | CIP | SS | RE | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // | | | | | | | | // | | | | | | | +--- %1 RX Enable // | | | | | | +--------- Sync Stop // | | | | | +--------------- 非同期なら @@ -170,8 +186,11 @@ struct MFP static const uint32 RSR_RE = 0x01; uint8 rsr; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ // TSR | BE | UE | AT | END | B | H | L | TE | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // | | | | // | | | +--- %1 TX Enable // | | +--------------------------- %1 TX Disabled // | +--------------------------------------- %1 Underrun Error @@ -237,10 +256,13 @@ class MFPDevice : public IODevice bool PokePort(uint32 offset, uint32 data); private: - void SetIER(uint8& ier, uint8& ipr, uint32 data); + void SetIER(uint16 data); void SetTCR(int ch, uint32 data); uint8 GetTDR(int ch) const; void SetTDR(int ch, uint32 data); + void RestartTimerEvent(int ch); + void StopTimerEvent(int ch); + bool IsTimerIntrEnable(int ch) const; // GPIP の信号状態をセットする void SetGPIP(int num, bool val); @@ -256,8 +278,8 @@ class MFPDevice : public IODevice bool IsRR() const; // イベントコールバック - void TimerCallback(Event& ev); - void KeyCallback(Event& ev); + void TimerCallback(Event *); + void KeyCallback(Event *); // 必要なら割り込みを上げる void SetInterrupt(uint ch); @@ -265,25 +287,36 @@ class MFPDevice : public IODevice // 割り込み信号線の状態を変える void ChangeInterrupt(); - DECLARE_MONITOR_CALLBACK(MonitorUpdate); + DECLARE_MONITOR_SCREEN(MonitorScreen); struct MFP mfp {}; - std::array event {}; - Event key_event { this }; + std::array event {}; + Event *key_event {}; + + // 各タイマーが刻んでいる時刻 (時間軸) + std::array stime {}; + + // 各タイマーの周期 + std::array rt_period {}; + + // タイマーを実時間に追従する場合は true。 + bool sync_rt {}; Monitor *monitor {}; InterruptDevice *interrupt {}; + Syncer *syncer {}; X68030Keyboard *keyboard {}; + static const busdata wait; static const char *intrname[]; static const char *gpipname[]; - static const uint prescale_ns[8]; + static const uint64 prescale_tsec[8]; static const char *prescale_str[8]; static const uint timer_vector[4]; static const char *regname[MFP::RegMax]; }; -static inline MFPDevice *GetMFPDevice() { +inline MFPDevice *GetMFPDevice() { return Object::GetObject(OBJ_MFP); }