--- nono/vm/mfp.h 2026/04/29 17:04:28 1.1 +++ nono/vm/mfp.h 2026/04/29 17:04:45 1.1.1.6 @@ -1,6 +1,7 @@ // // nono -// Copyright (C) 2017 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #pragma once @@ -60,36 +61,49 @@ struct MFP static const int GPIP_EXPON = 1; static const int GPIP_ALARM = 0; + static const uint INTR_RTC_ALARM = 0; + static const uint INTR_EXPON = 1; + static const uint INTR_POW_SW = 2; + static const uint INTR_FM_IRQ = 3; + static const uint INTR_TIMER_D = 4; + static const uint INTR_TIMER_C = 5; + static const uint INTR_VDISP = 6; + static const uint INTR_unused = 7; + static const uint INTR_TIMER_B = 8; + static const uint INTR_TXERR = 9; + static const uint INTR_TXEMPTY = 10; + static const uint INTR_RXERR = 11; + static const uint INTR_RXFULL = 12; + static const uint INTR_TIMER_A = 13; + static const uint INTR_CRTC_IRQ = 14; + static const uint INTR_HSYNC = 15; ir16 ier; 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 の値。 @@ -98,53 +112,138 @@ struct MFP // initial_tdr は 1..256 の値をとる。 uint initial_tdr[4]; - uint64 timer_start[4]; // タイマー開始時の仮想時刻 - uint8 scr; - uint8 ucr; // CLK WLI WLO STI STO PE E/O --- + + // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // UCR | CLK | WL | ST | PE | E/O | --- | + // | | | | +--------- %1で偶数パリティ + // | | | +--------------- %1でパリティエラー + // | | +------------------- スタート/ストップビット + // | +--- データ長 %00 同期 + // | %00:8bit, %01:7bit %01 非同期 1bit/1bit + // | %10:6bit, %11:5bit %10 非同期 1bit/1.5bit + // | %11 非同期 1bit/2bit + // | + // +------------------------------------- %1 送受信速度が入力の1/16 + static const uint32 UCR_CLK = 0x80; + static const uint32 UCR_WL = 0x60; + static const uint32 UCR_ST = 0x18; + static const uint32 UCR_PE = 0x04; + static const uint32 UCR_EO = 0x02; + uint8 ucr; + + // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // RSR | BF | OE | PE | FE | B | CIP | SS | RE | + // | | | | | | | +--- %1 RX Enable + // | | | | | | +--------- Sync Stop + // | | | | | +--------------- 非同期なら + // | | | | | %1 Detect Start Bit + // | | | | | %0 Detect Stop Bit + // | | | | +--------------------- %1 非同期ならBreak + // | | | +--------------------------- %1 Framing Error + // | | +--------------------------------- %1 Parity Error + // | +--------------------------------------- %1 Overflow Error + // +--------------------------------------------- %1 RX Buffer Full + static const uint32 RSR_BF = 0x80; + static const uint32 RSR_OE = 0x40; + static const uint32 RSR_PE = 0x20; + static const uint32 RSR_FE = 0x10; + static const uint32 RSR_B = 0x08; + static const uint32 RSR_CIP = 0x04; + static const uint32 RSR_SS = 0x02; + static const uint32 RSR_RE = 0x01; uint8 rsr; + + // | 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 + // +--------------------------------------------- %1 TX Buffer Empty + static const uint32 TSR_BE = 0x80; + static const uint32 TSR_UE = 0x40; + static const uint32 TSR_AT = 0x20; + static const uint32 TSR_END = 0x10; + static const uint32 TSR_B = 0x08; + static const uint32 TSR_H = 0x04; + static const uint32 TSR_L = 0x02; + static const uint32 TSR_TE = 0x01; uint8 tsr; - uint8 udr; + // 送受信レジスタ。 + // 受信データがなければ -1 にする + uint16 udr; }; class MFPDevice : public IODevice { - typedef IODevice inherited; + using inherited = IODevice; static const int baseaddr = 0xe88000; public: MFPDevice(); - virtual ~MFPDevice(); + virtual ~MFPDevice() override; - virtual void ResetSoft(); + void ResetHard() override; + void ResetSoft() override; + void MonitorUpdate(TextScreen&) override; - virtual uint64 Read8(uint32 addr); - virtual uint64 Read16(uint32 addr); - virtual uint64 Write8(uint32 addr, uint32 data); - virtual uint64 Write16(uint32 addr, uint32 data); - virtual uint64 Peek8(uint32 addr); - virtual bool MonitorUpdate(); + // 割り込みアクノリッジ + int InterruptAcknowledge(); // VDisp 入力 void SetVDisp(bool vdisp); + // KEY CTRL 状態を設定する + void SetKeyCtrl(bool ctrl); + + // RR 線の状態を返す + bool IsRR() const; + + // キーボードからデータを受信 + void Rx(uint32 data); + + protected: + // BusIO インタフェース + static const uint32 NPORT = 0x20; + uint64 Read(uint32 addr); + uint64 Write(uint32 addr, uint32 data); + uint64 Peek(uint32 addr); + private: - bool IsTimerIntrEnable(uint ch) const; + void Reset(); void SetTCR(int ch, uint32 data); - uint8 GetTDR(int ch); + uint8 GetTDR(int ch) const; void SetTDR(int ch, uint32 data); // GPIP の信号状態をセットする void SetGPIP(int num, bool val); - // タイマーイベントコールバック - void TimerCallback(int arg); + void SetUCR(uint32 data); + void SetRSR(uint32 data); + void SetUDR(uint32 data); + + // イベントコールバック + void TimerCallback(Event& ev); + void KeyCallback(Event& ev); + + // 必要なら割り込みを上げる + void SetInterrupt(uint ch); + + // 割り込み信号線の状態を変える + void ChangeInterrupt(); struct MFP mfp {}; Event event[4] {}; + Event key_event {}; + + // Receiver Ready 線の状態 + bool rr {}; + + // システムポート#4 の KEY CTRL 状態 + bool key_ctrl {}; static const char *intrname[]; static const char *gpipname[]; @@ -153,4 +252,4 @@ class MFPDevice static const int timer_vector[4]; }; -extern MFPDevice *gMFP; +extern std::unique_ptr gMFP;