--- nono/vm/mfp.h 2026/04/29 17:04:36 1.1.1.3 +++ nono/vm/mfp.h 2026/04/29 17:05:14 1.1.1.12 @@ -4,10 +4,16 @@ // Licensed under nono-license.txt // +// +// MFP (MC68901) +// + #pragma once #include "device.h" -#include "scheduler.h" +#include "event.h" +#include "monitor.h" +#include struct MFP { @@ -81,32 +87,29 @@ struct MFP ir16 ipr; ir16 isr; ir16 imr; - uint8 vr; // V7 V6 V5 V4 S --- --- --- + + // + // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // VR | V7 | V6 | V5 | V4 | S | --- | --- | --- | + // | | | | +------------ In-Service Register Enable + // +-----+-----+-----+------------------ Vector Number + uint8 vr_vec; // ベクタの上位4ビット + uint8 vr_s; // %1:ソフトウェアEOI(ISR有効)、%0:自動EOI(ISR無効) + uint8 GetVR() const { return vr_vec | vr_s; } // TDR のカウンタをメインカウンタと呼び、このメインカウンタを // 1減らすためのカウンタをプリスケーラカウンタと呼ぶ。 // 実際のハードウェアは 4MHz のクロック入力ごとにプリスケーラカウンタを // カウントしていき指定回数カウントすればメインカウンタを1減らすのだが、 - // この実装ではどちらのカウンタも持たず、タイマー開始時刻と現在時刻で - // 管理する。そのため、メインカウンタもプリスケーラカウンタも必要なら - // この時間差から求める。 - // - // X680x0 の MFP は 4MHz なので、1クロックは 0.25 usec。 - // TxCR = 1 の時プリスケール回数は 10 なので、入力クロック10回 - // (2.5usec) ごとにメインカウンタを 1 減らす。 - // TxDR = 5 から開始すれば 50 カウント (12.5 usec) 後にタイムアップする。 - // そのためタイマー開始時から現在 3 usec 経過していれば 3 / 0.25 = 12 で - // 総入力クロックは12回、メインカウンタは 1 減っており、プリスケール - // カウントは10回中残り 8回を指していることになる。 + // この実装ではどちらのカウンタも持たず、タイマー終了時刻と現在時刻で + // 管理する。そのためメインカウンタの値はこの時間差から求める。 + // tcr は書き込み値、現在のモードを保持する。 uint8 tcr[4]; // --- --- --- RST AC3 AC2 AC1 AC0 : TACR // --- --- --- RST BC3 BC2 BC1 BC0 : TBCR // --- CC2 CC1 CC0 --- DC2 DC1 DC0 : TCDCR - // tdr はカウンタの設定値。 - // タイマー停止中に TxDR に書き込まれると、initial_tdr に即反映される。 - // タイマー動作中に TxDR に書き込まれると、initial_tdr に反映されるのは - // 次のリロードタイミング。 + // tdr はカウンタの現在値。 uint8 tdr[4]; // initial_tdr はカウントダウン開始時点での TxDR の値。 @@ -115,8 +118,6 @@ struct MFP // initial_tdr は 1..256 の値をとる。 uint initial_tdr[4]; - uint64 timer_start[4]; // タイマー開始時の仮想時刻 - uint8 scr; // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | @@ -180,8 +181,7 @@ struct MFP uint16 udr; }; -class MFPDevice - : public IODevice +class MFPDevice : public IODevice { using inherited = IODevice; @@ -189,19 +189,30 @@ class MFPDevice public: MFPDevice(); - ~MFPDevice() override; + virtual ~MFPDevice() override; + + void ResetHard(bool poweron) override; + + // 割り込みアクノリッジ + int InterruptAcknowledge(); - void ResetSoft() override; - bool MonitorUpdate() override; + // HSync 入力 + void SetHSync(bool hsync); // VDisp 入力 void SetVDisp(bool vdisp); + // 電源ボタン状態入力 + void SetPowSW(bool powsw); + + // ALARM 信号入力 + void SetAlarmOut(bool alarm); + // KEY CTRL 状態を設定する void SetKeyCtrl(bool ctrl); - // RR 線の状態を返す - bool IsRR() const; + // キーボードからの送信が可能なら true を返す。 + bool RxIsReady() const; // キーボードからデータを受信 void Rx(uint32 data); @@ -209,12 +220,11 @@ class MFPDevice protected: // BusIO インタフェース static const uint32 NPORT = 0x20; - uint64 Read(uint32 addr); - uint64 Write(uint32 addr, uint32 data); - uint64 Peek(uint32 addr); + uint64 Read(uint32 offset); + uint64 Write(uint32 offset, uint32 data); + uint64 Peek(uint32 offset); private: - bool IsTimerIntrEnable(uint ch) const; void SetTCR(int ch, uint32 data); uint8 GetTDR(int ch) const; void SetTDR(int ch, uint32 data); @@ -226,19 +236,29 @@ class MFPDevice void SetRSR(uint32 data); void SetUDR(uint32 data); + // RSR::BF ビットの状態を変える + void SetBF(); + void ClearBF(); + // MFP の RR 線の状態を返す + bool IsRR() const; + // イベントコールバック - void TimerCallback(int arg); - void KeyCallback(int arg); + void TimerCallback(Event& ev); + void KeyCallback(Event& ev); - struct MFP mfp {}; - Event event[4] {}; - Event key_event {}; + // 必要なら割り込みを上げる + void SetInterrupt(uint ch); + + // 割り込み信号線の状態を変える + void ChangeInterrupt(); - // Receiver Ready 線の状態 - bool rr {}; + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + struct MFP mfp {}; + std::array event {}; + Event key_event { this }; - // システムポート#4 の KEY CTRL 状態 - bool key_ctrl {}; + Monitor monitor { this }; static const char *intrname[]; static const char *gpipname[]; @@ -247,4 +267,4 @@ class MFPDevice static const int timer_vector[4]; }; -extern std::unique_ptr gMFP; +extern MFPDevice *gMFP;