File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / mfp.h
Revision 1.1.1.20 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:00 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// MFP (MC68901)
//

#pragma once

#include "device.h"
#include <array>

class InterruptDevice;
class Syncer;
class X68030Keyboard;

struct MFP
{
	static const uint GPIP	= 0;	// $E88001
	static const uint AER	= 1;	// $E88003
	static const uint DDR	= 2;	// $E88005
	static const uint IERA	= 3;	// $E88007
	static const uint IERB	= 4;	// $E88009
	static const uint IPRA	= 5;	// $E8800B
	static const uint IPRB	= 6;	// $E8800D
	static const uint ISRA	= 7;	// $E8800F
	static const uint ISRB	= 8;	// $E88011
	static const uint IMRA	= 9;	// $E88013
	static const uint IMRB	= 10;	// $E88015
	static const uint VR	= 11;	// $E88017
	static const uint TACR	= 12;	// $E88019
	static const uint TBCR	= 13;	// $E8801B
	static const uint TCDCR	= 14;	// $E8801D
	static const uint TADR	= 15;	// $E8801F
	static const uint TBDR	= 16;	// $E88021
	static const uint TCDR	= 17;	// $E88023
	static const uint TDDR	= 18;	// $E88025
	static const uint SCR	= 19;	// $E88027
	static const uint UCR	= 20;	// $E88029
	static const uint RSR	= 21;	// $E8802B
	static const uint TSR	= 22;	// $E8802D
	static const uint UDR	= 23;	// $E8802F
	static const uint RegMax = 24;

	union ir16 {
		uint16 w;
		struct {
#if BYTE_ORDER == LITTLE_ENDIAN
			uint8 b, a;
#else
			uint8 a, b;
#endif
		};
	};

	// ハードウェア未実装ビットは書き込み時に '0' にする

	uint8 gpip;
	uint8 aer;
	uint8 ddr;
	static const uint GPIP_HSYNC = 7;
	static const uint GPIP_CIRQ  = 6;
										// 5 は常に '1'
	static const uint GPIP_VDISP = 4;
	static const uint GPIP_FMIRQ = 3;
	static const uint GPIP_POWSW = 2;
	static const uint GPIP_EXPON = 1;
	static const uint 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;

	//       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; }

	// タイマー
	struct Timer {
		// タイマー停止中は、カウンタの現在値 (1-256) を保持。
		// タイマー動作中は、現在カウントダウン中のカウントの初期値(1-256)。
		// TxDR レジスタ値際は、タイマー動作中/停止中どちらでも
		// これではなく GetTDR() を使うこと。
		uint32 tdr;

		// 次回の 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 の値
	uint8 GetTCDCR() const {
		return (timer[2].tcr << 4) | timer[3].tcr;
	}

	uint8 scr;

	//       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;

	// 送受信レジスタ。
	// 受信データがなければ -1 にする
	uint16 udr;
};

class MFPDevice : public IODevice
{
	using inherited = IODevice;

	static const uint32 baseaddr = 0xe88000;

 public:
	MFPDevice();
	~MFPDevice() override;

	bool Init() override;
	void ResetHard(bool poweron) override;

	// 割り込みアクノリッジ
	busdata InterruptAcknowledge();

	// 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);

	// キーボードからの送信が可能なら true を返す。
	bool RxIsReady() const;

	// キーボードからデータを受信
	void Rx(uint32 data);

 protected:
	// BusIO インタフェース
	static const uint32 NPORT = 0x20;
	busdata ReadPort(uint32 offset);
	busdata WritePort(uint32 offset, uint32 data);
	busdata PeekPort(uint32 offset);
	bool PokePort(uint32 offset, uint32 data);

 private:
	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);

	void SetUCR(uint32 data);
	void SetRSR(uint32 data);
	void SetUDR(uint32 data);

	// RSR::BF ビットの状態を変える
	void SetBF();
	void ClearBF();
	// MFP の RR 線の状態を返す
	bool IsRR() const;

	// イベントコールバック
	void TimerCallback(Event *);
	void KeyCallback(Event *);

	// 必要なら割り込みを上げる
	void SetInterrupt(uint ch);

	// 割り込み信号線の状態を変える
	void ChangeInterrupt();

	DECLARE_MONITOR_SCREEN(MonitorScreen);

	struct MFP mfp {};
	std::array<Event *, 4> event {};
	Event *key_event {};

	// 各タイマーが刻んでいる時刻 (時間軸)
	std::array<uint64, 4> stime {};

	// 各タイマーの周期
	std::array<uint64, 4> 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 uint64 prescale_tsec[8];
	static const char *prescale_str[8];
	static const uint timer_vector[4];
	static const char *regname[MFP::RegMax];
};

inline MFPDevice *GetMFPDevice() {
	return Object::GetObject<MFPDevice>(OBJ_MFP);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.