File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / mpscc.h
Revision 1.1.1.9 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:59 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
//

//
// uPD7201(MPSC) と Z8530(SCC) の共通部分 (シリアルポート1個つき)
//

#pragma once

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

#if defined(MPSCC_SIO_LOG_HACK)
// SIO で SR0 のログ表示に細工をするため、
// SIO, MPSCC で putlog() マクロを再定義している。
#undef putlog
#define putlog(lv, fmt...)	do {	\
	if (__predict_false(loglevel >= (lv))) {	\
		putlogn(fmt);	\
		sr0_logphase = 0;	\
	}	\
} while (0)
#endif

class HostCOMDevice;
class InterruptDevice;

// 1チャンネル分の共通部分
class MPSCCChan final
{
 public:
	MPSCCChan();
	~MPSCCChan();

	void Init(int id_);

	// プロパティっぽいもの
	int id {};				// チャンネル番号 (0 or 1)
	char name {};			// チャンネル名 ('A' or 'B')
	const char *desc {};	// チャンネルの用途(モニタ表示用)
	uint32 ctrladdr {};		// 制御ポートのアドレス (モニタ表示用)
	uint32 dataaddr {};		// データポートのアドレス (モニタ表示用)

	// ここから内部構造

	// CR0/WR0 付近
	uint8 crc_cmd {};		// CRC
	uint8 cmd {};			// Command
	uint ptr {};			// Pointer (uPD7201 は 3bit、Z8530 は実質 4bit)

	// CR1/WR1 付近
	bool wait_enable {};	// b7
	bool wait_func {};		// b6; Z8530 Only
	bool wait_on_rx {};		// b5
	bool txint_enable {};	// b1
	bool esint_enable {};	// b0

	// Z8530 では割り込みモード3種類とパリティエラーを Sp.Rx に含むかどうかが
	// 独立して選択できるため、組み合わせは 3 * 2 (+ Disable 1通り) = 7通り。
	// uPD7201 ではこれに相当する設定は RXINT の 2bit しかなく、Disable を除く
	// 3通りはこのうち 3つがプリセットされたような感じ。
	// (もちろん歴史的経緯はこの逆だろうけど)
	//
	//         RXInt SP    割込モード	Parity Error を Sp.Rx に含むか
	// -----------------   ------------	------------------------------
	//          0  0  -  : Disable		-
	// uPD7201  0  1  -  : 1stChar		no
	// uPD7201  1  0  -  : AllChar		yes
	// uPD7201  1  1  -  : AllChar		no
	// Z8530    0  1  0  : 1stChar		no
	// Z8530    0  1  1  : 1stChar		yes
	// Z8530    1  0  0  : AllChar		no
	// Z8530    1  0  1  : AllChar		yes
	// Z8530    1  1  0  : SpOnly		no
	// Z8530    1  1  1  : SpOnly		yes
	static const uint RXINT_DISABLE	= 0x00;
	static const uint RXINT_1STCHAR	= 0x01;
	static const uint RXINT_ALLCHAR	= 0x02;
	static const uint RXINT_SPONLY	= 0x03;	// Z8530 Only
	uint rxint_mode {};
	bool sp_parity {};

	// SR0/RR0 付近
	bool break_detected {};
	bool tx_underrun {};
	bool nCTS {};
	bool nSYNC {};
	bool nDCD {};

	// これらのレジスタは uPD7201/Z8530 で共通

	// CR3/WR3 付近
	uint rxbits {};			// 受信データビット数 (レジスタ値ではない)
	uint8 cr3_sync {};		// SyncMode でだけ使う bit4-1 を保存
	bool auto_enable {};
	bool rx_enable {};

	// CR4/WR4 付近
	uint clkrate {};		// クロック倍率 (レジスタ値ではない)
	uint8 syncmode {};		// bit5,4 を保存
	uint8 stopbits {};		// STOPBITS_*
	bool parity_even {};
	int parity_enable {};	// パリティ有効 (追加するビット数 0 か 1 で保持)

	// CR5/WR5 付近
	bool nDTR {};			// ~DTR
	uint txbits {};			// 送信データビット数 (レジスタ値ではない)
	bool sendbreak {};
	bool tx_enable {};
	bool crc16 {};
	bool nRTS {};			// ~RTS
	bool txcrc_en {};

	uint8 cr6 {};
	uint8 cr7 {};
	uint8 sr1 {};

	// いずれもレジスタイメージとして保存
	uint8 old_cr3 {};
	uint8 old_cr4 {};
	uint8 old_cr5 {};

	// Z8530 専用のレジスタだけど継承とかは面倒なので結局ここに置く
	uint8 wr10 {};
	uint8 wr11 {};
	uint16 tc {};			// WR12, WR13
	uint8 wr14 {};
	uint8 wr15 {};
	uint8 rr10 {};

	// ここからその他の内部状態

	bool es_latched {};		// E/S ビットがラッチされているか

	// 受信バッファは短いので先頭からの FIFO とし、
	// 取り出したら前にずらす
	uint8 rxbuf[3] {};		// 受信バッファ(FIFO)
	int   rxlen {};			// 受信バッファの有効バイト数

	uint8 txbuf {};			// 送信バッファ
	int   txlen {};			// 送信バッファの有効バイト数
	uint8 tx_shiftreg {};	// 送信シフトレジスタ相当品

	// First Char 用のフラグで、この受信で割り込みを起こすなら true。
	// ALL なら常に true。FIRSTCHAR の時は最初が true で1文字目の受信
	// 割り込みを出したところで false にする。
	bool all_or_first {};

	// Tx 割り込み発火用のフラグ。
	// Tx 割り込みは
	// 1) Tx 割り込みが有効で
	// 2) 送信バッファに書き込まれるか Reset Tx INT/DMA Pending コマンドが
	//    発行されるかした後
	// 3) 送信バッファが空になった
	// 場合に発生する。チャンネルリセットとハードリセットで送信バッファが
	// 空になった場合には発生しない。
	// ので、ここの 2) を満たす場合 txint_ready = true とする。
	bool txint_ready {};

	// 割り込みペンディング (MPSCC::INTPEND_*)
	//
	// Z8530 の RR3A レジスタは個別の割り込みペンディング状態が読み出せる。
	// uPD7201 にも内部に同じだけの状態を持っているが個別に読み出す方法はなく
	// すべてを OR したペンディングの有無を SR0A b1 で読み出すことが出来る。
	uint intpend {};

	// ボーレート (表示用)
	// Z8530 なら tc から求められる
	double baudrate {};

	// 1フレームあたりの送受信のビット数 (表示用)
	uint txframebits {};
	uint rxframebits {};

	// LUNA の場合は TxC, RxC ピンに供給されているクロック。
	// X68030 の場合は Z8530 内部で生成されている基準クロック。
	// 誤差を減らすため 12 ビット分の時間 [tsec] としている。
	uint64 xc12_tsec {};

	// 実際の 12 ビットの通信にかかる時間。xc12_tsec に倍率をかけたもの。
	uint64 bit12_tsec {};
};

class MPSCC
{
 public:
	// レジスタ定義

	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +---------+--------------+--------------+
	// CR0  |   CRC   |   Command    |   Pointer    |
	// WR0  +---------+--------------+--------------+
	//
	static const uint8 CR0_CRC			= 0xc0;
	static const uint8 CR0_CMD			= 0x38;
	static const uint8 CR0_PTR			= 0x07;
	// Z8530 ではコマンド %000 と %001 がレジスタ切り替えなので、
	// CMD が 0x38、PTR が 0x0f とあえて被せてある。
	static const uint8 WR0_CRC			= CR0_CRC;
	static const uint8 WR0_CMD			= CR0_CMD;
	static const uint8 WR0_PTR			= 0x0f;

	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +----+----+----+---------+----+----+----+
	// CR1  | WE |  0 | WR |  RX Int | SAV| TE | ES |
	//      +----+----+----+---------+----+----+----+
	//        |         |       |      |    |    +---- E/S Int Enable
	//        |         |       |      |    +--------- TX INT/DMA Enable
	//        |         |       |      +-------------- Status Affects Vec.(Ch.B)
	//        |         |       +--------------------- RX Int Mode
	//        |         +----------------------------- Wait on RX(=%1),TX(=%0)
	//        +--------------------------------------- Wait Enable
	//
	static const uint8 CR1_WAIT_EN		= 0x80;	// Wait Enable
	static const uint8 CR1_WAIT_RX		= 0x20;	// Wait on RX
	static const uint8 CR1_RXINT		= 0x18;	// Rx Interrupt Mode
	static const uint8 CR1_RXINT_DISABLE	= 0x00;	// Disable
	static const uint8 CR1_RXINT_1STCHAR	= 0x08;	// 1st Char
	static const uint8 CR1_RXINT_ALLCHAR	= 0x10;	// All Chars
	static const uint8 CR1_RXINT_ALL_BUT_PE	= 0x18;	// All Chars exclude P.E.
	static const uint8 CR1_SAV			= 0x04;	// Status Affects Vector (Ch.B)
	static const uint8 CR1_TXINT_EN		= 0x02;	// Tx Int/DMA Enable
	static const uint8 CR1_ESINT_EN		= 0x01;	// E/S Interrupt Enable
	//
	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +----+----+----+---------+----+----+----+
	// WR1  | WE | WF | WR |  RX Int | SP | TE | ES |
	//      +----+----+----+---------+----+----+----+
	//             |                   +-------------- Sp includes Parity Err
	//             +---------------------------------- Wait Function
	//
	static const uint8 WR1_WAIT_EN		= CR1_WAIT_EN;
	static const uint8 WR1_WAIT_FUNC	= 0x40;	// Wait Function
	static const uint8 WR1_WAIT_RX		= CR1_WAIT_RX;
	static const uint8 WR1_RXINT		= CR1_RXINT;
	static const uint8 WR1_RXINT_DISABLE	= 0x00;	// Disable
	static const uint8 WR1_RXINT_1STCHAR	= 0x08;	// 1st Char or Sp.Cond.
	static const uint8 WR1_RXINT_ALLCHAR	= 0x10;	// All Chars or Sp.Cond.
	static const uint8 WR1_RXINT_SPONLY		= 0x18;	// Special Conditoin Only
	static const uint8 WR1_SP_INC_PE	= 0x04;	// Sp. Condition includes P.E.
	static const uint8 WR1_TXINT_EN		= CR1_TXINT_EN;
	static const uint8 WR1_ESINT_EN		= CR1_ESINT_EN;

	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +----+----+----+---------+----+---------+
	// CR2A | R/S|  0 | VM | IntMode | PS | Int/DMA |
	//      +----+----+----+---------+----+---------+
	//        |         |       |      |       +------ INT/DMA Mode
	//        |         |       |      +-------------- Priority Select
	//        |         |       +--------------------- Interrupt Mode -> VIS
	//        |         +----------------------------- Vector Mode
	//        +--------------------------------------- ~RTSB/~SYNCB Select
	//
	static const uint8 CR2_SYNCB		= 0x80;	// ~RTSB/~SYNCB Select
	static const uint8 CR2_VM			= 0x20;	// Vector Mode
	static const uint8 CR2_INT			= 0x18;	// Interrupt Mode -> VIS
	static const uint8 CR2_PRIOSEL		= 0x04;	// Priority Select
	static const uint8 CR2_INTDMA		= 0x03;	// Int/DMA Mode

	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +---------+----+-------------------+----+
	// CR3 | RX bits | AE |  (For sync mode)  | RE |
	// WR3 +---------+----+-------------------+----+
	//          |      |                        +---- RX Enable
	//          |      +----------------------------- Auto Enable
	//          +------------------------------------ RX bits
	//
	static const uint8 CR3_RXBITS		= 0xc0;	// Rx Bits
	static const uint8 CR3_AUTO_EN		= 0x40;	// Auto Enable
	static const uint8 CR3_SYNC_MASK	= 0x1e;
	static const uint8 CR3_RX_EN		= 0x01;	// Rx Enable
	// WR3
	static const uint8 WR3_RXBITS		= CR3_RXBITS;
	static const uint8 WR3_AUTO_EN		= CR3_AUTO_EN;
	static const uint8 WR3_RX_EN		= CR3_RX_EN;

	// 並び順が 5, 6, 7, 8 でないので注意
	static const uint8 RXBITS_5			= 0x00;
	static const uint8 RXBITS_7			= 0x40;
	static const uint8 RXBITS_6			= 0x80;
	static const uint8 RXBITS_8			= 0xc0;

	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +---------+---------+---------+----+----+
	// CR4 | ClkRate | SyncMode| StopBits| PEV| PEN|
	// WR4 +---------+---------+---------+----+----+
	//          |         |         |      |    +---- Parity Enable(%1)
	//          |         |         |      +--------- Parity Even(%1)
	//          |         |         +---------------- Stop Bits
	//          |         +-------------------------- Sync Mode
	//          +------------------------------------ Clock Rate
	//
	static const uint8 CR4_CLKRATE		= 0xc0;	// Clock Rate
	static const uint8 CR4_SYNCMODE		= 0x30;	// Sync Mode
	static const uint8 CR4_STOPBITS		= 0x0c;	// Stop Bits
	static const uint8 CR4_PARITY_EVEN	= 0x02;	// Parity Even
	static const uint8 CR4_PARITY_EN	= 0x01;	// Parity Enable
	// WR4
	static const uint8 WR4_CLKRATE		= CR4_CLKRATE;
	static const uint8 WR4_SYNCMODE		= CR4_SYNCMODE;
	static const uint8 WR4_STOPBITS		= CR4_STOPBITS;
	static const uint8 WR4_PARITY_EVEN	= CR4_PARITY_EVEN;
	static const uint8 WR4_PARITY_EN	= CR4_PARITY_EN;

	static const uint8 CLKRATE_1		= 0x00;
	static const uint8 CLKRATE_16		= 0x40;
	static const uint8 CLKRATE_32		= 0x80;
	static const uint8 CLKRATE_64		= 0xc0;

	static const uint8 STOPBITS_SYNC	= (0x00 >> 2);
	static const uint8 STOPBITS_1		= (0x04 >> 2);
	static const uint8 STOPBITS_1_5		= (0x08 >> 2);
	static const uint8 STOPBITS_2		= (0x0c >> 2);

	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +----+---------+----+----+----+----+----+
	// CR5 |~DTR| TX bits | SB | TE | CRC|~RTS| TCE|
	// WR5 +----+---------+----+----+----+----+----+
	//               |      |    |    |         +---- TX CRC Enable
	//               |      |    |    +-------------- CRC-16/CCITT
	//               |      |    +------------------- TX Enable
	//               |      +------------------------ Send Break
	//               +------------------------------- TX Bits
	static const uint8 CR5_nDTR			= 0x80;	// ~DTR
	static const uint8 CR5_TXBITS		= 0x60;	// Tx Bits
	static const uint8 CR5_SENDBREAK	= 0x10;	// Send Break
	static const uint8 CR5_TX_EN		= 0x08;	// Tx Enable
	static const uint8 CR5_CRC16		= 0x04;	// CRC-16/CCITT
	static const uint8 CR5_nRTS			= 0x02;	// ~RTS
	static const uint8 CR5_TXCRC_EN		= 0x01;	// Tx CRC Enable
	// WR5
	static const uint8 WR5_nDTR			= CR5_nDTR;
	static const uint8 WR5_TXBITS		= CR5_TXBITS;
	static const uint8 WR5_SENDBREAK	= CR5_SENDBREAK;
	static const uint8 WR5_TX_EN		= CR5_TX_EN;
	static const uint8 WR5_CRC16		= CR5_CRC16;
	static const uint8 WR5_nRTS			= CR5_nRTS;
	static const uint8 WR5_TXCRC_EN		= CR5_TXCRC_EN;

	// 並び順が 5, 6, 7, 8 でないので注意
	static const uint8 TXBITS_5			= 0x00;
	static const uint8 TXBITS_7			= 0x20;
	static const uint8 TXBITS_6			= 0x40;
	static const uint8 TXBITS_8			= 0x60;

	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +---------+----+----+----+----+----+----+
	// WR9A |  Reset  |  0 |SHSL| MIE| DLC| NV | VIS|
	// WR9B +---------+----+----+----+----+----+----+
	//           |           |    |    |    |    +---- Vector Includes Status
	//           |           |    |    |    +--------- No Vector Mode
	//           |           |    |    +-------------- Disable Lower Chain
	//           |           |    +------------------- Master Interrupt Enable
	//           |           +------------------------ StatusHigh / StatusLow
	//           +------------------------------------ Reset Command
	// Reset Command は CR0 のコマンドも参照のこと。
	//
	static const uint8 WR9_RESET_CMD	= 0xc0;	// Reset Command
	static const uint8 WR9_SHSL			= 0x10;	// Status High / Status Low
	static const uint8 WR9_MIE			= 0x08;	// Master Interrupt Enable
	static const uint8 WR9_DLC			= 0x04;	// Disable Lower Chain
	static const uint8 WR9_NV			= 0x02;	// No Vector Mode
	static const uint8 WR9_VIS			= 0x01;	// Vector Includes Status

	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +----+----+----+----+----+----+----+----+
	// SR0 | B/A| T/E|~CTS|~S/H|~DCD| TE | IP | RA |
	//     +----+----+----+----+----+----+----+----+
	//       |    |         |         |    |    +---- Rx Char. Available
	//       |    |         |         |    +--------- Interrupt Pending
	//       |    |         |         +-------------- Tx Buffer Empty
	//       |    |         +------------------------ ~SYNC/Hunt
	//       |    +---------------------------------- Tx Underrun/EOM
	//       +--------------------------------------- Break/Abort
	//
	static const uint8 SR0_BREAK		= 0x80;	// Break/Abort
	static const uint8 SR0_TXUNDER		= 0x40;	// Tx Underrun/EOM
	static const uint8 SR0_nCTS			= 0x20;	// ~CTS
	static const uint8 SR0_nSYNC		= 0x10;	// ~SYNC/Hunt
	static const uint8 SR0_nDCD			= 0x08;	// ~DCD
	static const uint8 SR0_TXEMPTY		= 0x04;	// Tx Buffer Empty
	static const uint8 SR0_INTPEND		= 0x02;	// Interrupt Pending
	static const uint8 SR0_RXAVAIL		= 0x01;	// Rx Character Available
	//
	//     +----+----+----+----+----+----+----+----+
	// RR0 | B/A| T/E|~CTS|~S/H|~DCD| TE | ZC | RA |
	//     +----+----+----+----+----+----+----+----+
	//                                     +--------- Zero Count
	//
	static const uint8 RR0_BREAK		= SR0_BREAK;
	static const uint8 RR0_TXUNDER		= SR0_TXUNDER;
	static const uint8 RR0_nCTS			= SR0_nCTS;
	static const uint8 RR0_nSYNC		= SR0_nSYNC;
	static const uint8 RR0_nDCD			= SR0_nDCD;
	static const uint8 RR0_TXEMPTY		= SR0_TXEMPTY;
	static const uint8 RR0_ZEROCNT		= 0x02;	// Zero Count
	static const uint8 RR0_RXAVAIL		= SR0_RXAVAIL;

	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +----+----+----+----+--------------+----+
	// SR1 | EF | FRE| RO | PE | ResidueCode  | AS |
	// RR1 +----+----+----+----+--------------+----+
	//
	static const uint8 SR1_ENDOFFRAME	= 0x80;	// End of Frame
	static const uint8 SR1_FRAMEERROR	= 0x40;	// Framing/CRC Error
	static const uint8 SR1_RXOVERRUN	= 0x20;	// Rx Overrun
	static const uint8 SR1_PARITYERROR	= 0x10;	// Parity Error
	static const uint8 SR1_RESIDUEMASK	= 0x0e;	// Residue Code 2-0
	static const uint8 SR1_ALL_SENT		= 0x01;	// All Sent
	// RR1
	static const uint8 RR1_ENDOFFRAME	= SR1_ENDOFFRAME;
	static const uint8 RR1_FRAMEERROR	= SR1_FRAMEERROR;
	static const uint8 RR1_RXOVERRUN	= SR1_RXOVERRUN;
	static const uint8 RR1_PARITYERROR	= SR1_PARITYERROR;
	static const uint8 RR1_RESIDUEMASK	= SR1_RESIDUEMASK;
	static const uint8 RR1_ALL_SENT		= SR1_ALL_SENT;

	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +---------+----+----+----+----+----+----+
	// RR3A |    0    | RxA| TxA| ESA| RxB| TxB| ESB|
	//      +---------+----+----+----+----+----+----+
	static const uint8 RR3_RXA			= 0x20;	// Channel A Rx  Int. Pending
	static const uint8 RR3_TXA			= 0x10;	// Channel A Tx  Int. Pending
	static const uint8 RR3_ESA			= 0x08;	// Channel A E/S Int. Pending
	static const uint8 RR3_RXB			= 0x04;	// Channel B Rx  Int. Pending
	static const uint8 RR3_TXB			= 0x02;	// Channel B Tx  Int. Pending
	static const uint8 RR3_ESB			= 0x01;	// Channel B E/S Int. Pending

 public:
	// 2チャンネル分
	std::array<MPSCCChan, 2> chan {};

	// CR2 付近
	uint8 intdma_mode {};
	static const uint8 INTDMA_INT_INT = 0;	// Both channel INT
	static const uint8 INTDMA_DMA_INT = 1;	// ChA DMA, ChB INT
	static const uint8 INTDMA_DMA_DMA = 2;	// Both channel DMA
	bool priority_select {};
	uint8 int_mode {};
	static const uint8 INTMODE_85_1	= 0;
	static const uint8 INTMODE_85_2	= 1;
	static const uint8 INTMODE_86	= 2;
	// 割り込み時にベクタを出力するなら true。
	// CR2A の VM は出力なら %1、WR9 の NV(Non Vector) は出力しない時 %1。
	bool vectored_mode {};
	bool syncb {};

	// WR9 付近
	uint8 wr9_cmd {};			// WR9 の b6,7
	bool sav_vis {};			// uPD7201 なら CR1 SAV、Z8530 なら WR9 VIS
	bool disable_lower_chain {};
	bool master_int_enable {};
	bool status_high_low {};

	// ベクタに割り込み要因(3bit) を入れるかどうかは、
	// CR1 なら Status Affects Vector、
	// WR9 なら Vector Includes Status が担当。
	// どこに (どの順で) 入れるかは CR2A INT Mode か WR9 bit4 で指定する。
	enum {
		VIS_FIXED = 0,
		VIS_432,	// uPD7201: SAV = %1 && CR2A INT Mode = %00 or %01
		VIS_210,	// uPD7201: SAV = %1 && CR2A INT Mode = %10
		VIS_321,	// Z8530:   VIS = %1 && WR9 SHSL = %0
		VIS_456,	// Z8530:   VIS = %1 && WR9 SHSL = %1 (456; 向きに注意)
	} vis {};

	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +---------------------------------------+
	// CR2B |               Vector                  |
	// WR2  +---------------------------------------+
	//
	//        b7   b6   b5   b4   b3   b2   b1   b0
	//      +---------------------------------------+
	// RR2A |        Vector (WR2 に書いた値)        |
	//      +---------------------------------------+
	//
	//      +---------------------------------------+
	// SR2B |   Vector (割り込み要因で変化した値)   |
	// RR2B +---------------------------------------+
	uint vector {};

	// 割り込み要因
	static const uint VS_TxB	= 0;
	static const uint VS_ESB	= 1;
	static const uint VS_RxB	= 2;
	static const uint VS_SPB	= 3;
	static const uint VS_TxA	= 4;
	static const uint VS_ESA	= 5;
	static const uint VS_RxA	= 6;
	static const uint VS_SPA	= 7;
	static const uint VS_none	= 8;	// 割り込みなし
};

class MPSCCDevice : public IODevice
{
	using inherited = IODevice;
 protected:
	// 割り込みペンディングビット。chan.intpend で使用する。
	static const uint INTPEND_TX		= 0x01;
	static const uint INTPEND_ES		= 0x02;
	static const uint INTPEND_RX		= 0x04;
	static const uint INTPEND_SP		= 0x08;

	// 今のところ SIO, SCC どちらもシリアルポートはチャンネル 0
	static const int COM_CH = 0;

 public:
	MPSCCDevice();
	~MPSCCDevice() override;

	bool Create() override;
	void SetLogLevel(int loglevel_) override;
	bool Init() override;

	// 1バイト受信 (送信側デバイスが呼ぶ)
	virtual bool Rx(int ch, uint32 data);

 protected:
	// 指定のレジスタ名を返す
	virtual const char *CRName(const MPSCCChan&, uint n) const = 0;
	virtual const char *SRName(const MPSCCChan&, uint n) const = 0;
	// 現在のレジスタ名を返す
	const char *CRName(const MPSCCChan& chan) const {
		return CRName(chan, chan.ptr);
	}
	const char *SRName(const MPSCCChan& chan) const {
		return SRName(chan, chan.ptr);
	}

	// チャンネルリセットの共通部
	void ResetChannelCommon(MPSCCChan&);

	// BusIO インタフェース
	static const uint32 NPORT = 4;
	bool PokePort(uint32 offset, uint32 data);

	// レジスタアクセス
	static uint8 GetCR0(const MPSCCChan&);
	static void SetCR3(MPSCCChan&, uint32 data);
	static uint8 GetCR3(const MPSCCChan&);
	static void SetCR4(MPSCCChan&, uint32 data);
	static uint8 GetCR4(const MPSCCChan&);
	static void SetCR5(MPSCCChan&, uint32 data);
	static uint8 GetCR5(const MPSCCChan&);
	uint8 GetSR2B() const;
	void WriteCR3(MPSCCChan&, uint32 data);
	void WriteCR4(MPSCCChan&, uint32 data);
	void WriteCR5(MPSCCChan&, uint32 data);
	void WriteCR6(MPSCCChan&, uint32 data);
	void WriteCR7(MPSCCChan&, uint32 data);

	uint8 ReadData(MPSCCChan&);
	void WriteData(MPSCCChan&, uint32 data);
	uint8 PeekData(const MPSCCChan&) const;

	void SendAbort(MPSCCChan&);
	void ResetESIntr(MPSCCChan&);
	void EnableIntrOnNextRx(MPSCCChan&);
	void ResetTxIntrPending(MPSCCChan&);
	void ErrorReset(MPSCCChan&);
	void ResetHighestIUS(MPSCCChan&);

	// 1バイト送信
	virtual void Tx(int ch, uint32 data) = 0;

	// シリアルから1バイト受信のメッセージとイベントコールバック
	void HostRxCallback(uint32);
	void RxMessage(MessageID, uint32);
	void RxCallback(Event *);

	// 送受信関連
	void TrySend(MPSCCChan&);
	void SetTxPeriod(MPSCCChan&);
	void SetRxPeriod(MPSCCChan&);
	void TxCallback(Event *);

	// 割り込み
	void ChangeInterrupt();
	// ペンディングのうち最も優先度の高い割り込み要因 (VS_*) を返す
	virtual uint GetHighestInt() const = 0;

	// "9600,N,8,1" みたいなのを返す
	std::string GetParamStr(const MPSCCChan& chan) const;

	void ChangeBaudrate(MPSCCChan&);
	static int GetClkRate(uint8);
	int AdditionalBits(MPSCCChan&, bool enable);
	int GetStopBits(MPSCCChan&, bool enable);

	// モニタの下請け
	int MonitorScreenCR345(TextScreen&, int x, int y, uint8, uint8, uint8);
	void MonitorScreenSR1(TextScreen&, int x, int y, uint8 sr1);
	void MonitorReg(TextScreen&, int x, int y,
		uint32 reg, const char * const *names);

	MPSCC mpscc {};

	// 送受信用イベント
	std::array<Event *, 2> txevent {};
	std::array<Event *, 2> rxevent {};

	// シリアルポート。
	// 本当は共通層でやることではないがどう考えても同じコードになるので。
	std::unique_ptr<HostCOMDevice> hostcom /*{}*/;

	// SR0 のログ対策 (sio.cpp::ReadCtrl 参照)
	int    sr0_logphase {};
	uint32 sr0_lastread {};

	InterruptDevice *interrupt {};

	// モニタ
	Monitor *monitor {};
};

unix.superglobalmegacorp.com

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