--- nono/vm/upd7201.h 2026/04/29 17:04:36 1.1.1.3 +++ nono/vm/upd7201.h 2026/04/29 17:05:07 1.1.1.10 @@ -7,6 +7,9 @@ #pragma once #include "device.h" +#include "event.h" +#include "monitor.h" +#include // uPD7201/Z8530 のレジスタ // @@ -24,8 +27,10 @@ // 用意するほうが楽なので、こうなっている。 struct SIO { - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +---------+--------------+--------------+ // CR0 | CRC | Command | Pointer | + // +---------+--------------+--------------+ static const int CR0_CRC = 0xc0; static const int CR0_CMD = 0x38; static const int CR0_PTR = 0x07; @@ -36,8 +41,10 @@ struct SIO static const int WR0_CMD = CR0_CMD; static const int WR0_PTR = 0x0f; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +----+----+----+---------+----+----+----+ // CR1 | WE | -- | WR | RX Int | -- | TE | ES | + // +----+----+----+---------+----+----+----+ // | | | | +---- E/S Int Enable // | | | +--------- TX INT/DMA Enable // | | +--------------------- RX Int Mode @@ -61,8 +68,10 @@ struct SIO static const int RXINT_ALL_INC_SPECIAL = 0x10; // All char include special static const int RXINT_ALL_EXC_SPECIAL = 0x18; // All char exclude special - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +---------+----+-------------------+----+ // CR3 | RX bits | AE | -- -- -- -- | RE | + // +---------+----+-------------------+----+ // | | +---- RX Enable // | +----------------------------- Auto Enable // +------------------------------------ RX bits @@ -74,14 +83,16 @@ struct SIO static const int WR3_AUTO_EN = CR3_AUTO_EN; static const int WR3_RX_EN = CR3_RX_EN; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +---------+---------+---------+----+----+ // CR4 | ClkRate | SyncMode| StopBits| PV | PE | + // +---------+---------+---------+----+----+ // | | | | +---- Parity Enable(%1) // | | | +--------- Parity Even(%1) // | | +---------------- Stop Bits // | +-------------------------- Sync Mode // +------------------------------------ Clock Rate - // + // static const int CR4_CLKRATE = 0xc0; static const int CR4_SYNCMODE = 0x30; static const int CR4_STOPBITS = 0x0c; @@ -110,8 +121,10 @@ struct SIO HDLC = 2, }; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +----+---------+----+----+----+----+----+ // CR5 | DTR| TX bits | SB | TE | CRC| RTS| TC | + // +----+---------+----+----+----+----+----+ // | | | | | | +---- TX CRC Enable // | | | | | +--------- ~RTS // | | | | +-------------- CRC-16/CCITT @@ -135,8 +148,10 @@ struct SIO static const int WR5_RTS = CR5_RTS; static const int WR5_TXCRC_EN = CR5_TXCRC_EN; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +----+----+----+----+----+----+----+----+ // SR0 | BA | TU | CTS| SY | DCD| TE | IP | RA | + // +----+----+----+----+----+----+----+----+ static const int SR0_BREAK = 0x80; // Break/Abort static const int SR0_TXUNDER = 0x40; // Tx Underrun static const int SR0_CTS = 0x20; // CTS @@ -155,8 +170,10 @@ struct SIO static const int RR0_INTPEND = SR0_INTPEND; static const int RR0_RXAVAIL = SR0_RXAVAIL; - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | + // b7 b6 b5 b4 b3 b2 b1 b0 + // +----+----+----+----+--------------+----+ // SR1 | EF | CRC| RO | PE | ResidueCode | AS | + // +----+----+----+----+--------------+----+ static const int SR1_ENDOFFRAME = 0x80; // End of Frame static const int SR1_CRCERROR = 0x40; // CRC/Framing Error static const int SR1_RXOVERRUN = 0x20; // Rx Overrun @@ -171,6 +188,43 @@ struct SIO static const int RR1_RESIDUEMASK= SR1_RESIDUEMASK; static const int RR1_ALL_SENT = SR1_ALL_SENT; + // 割り込みベクタ ChB ChA + // Tx Buffer Empty %000 %100 + // External/Status Change %001 %101 + // Rx Character Available %010 %110 + // Special Rx Condition %011 %111 + // (この 3bit が V4-V2 か V2-V0 のところに出力される) + static const uint INTR_TX = (1U << 0); + static const uint INTR_ES = (1U << 1); + static const uint INTR_RX = (1U << 2); + static const uint INTR_SP = (1U << 3); + + // 割り込みあたりのロジック (uPD7201/7201A Figure 3-2 より INT 分のみ) + // + // Rx Disable (CR1:b1) *1 -----------------+ *1: Rx Enable (CR3:b0) + // | じゃなくて? + // +---+ | + // * RxCharAvailable ---->| | | + // | AND )--+ | +---+ + // All/First RxChar --->| | | +---+ +->| | + // +---+ +->) | | AND )--+ + // ) OR )-->| | | + // * Special Rx Condition ----------->) | +---+ | +-+ + // +---+ +->) | + // ) | --- + // * External/Status -------------------------------------->) OR |o-> INT + // ) | + // +---+ +->) | + // * Tx Buffer Empty ---------------->| | +----+ | +-+ + // | | | | | + // (Reset TxIntPend Cmd) --------->o| AND )-->| | | + // | | | | | + // Tx INT/DMA Enable (CR1:b1) ----->| | | AND )--+ + // +---+ | | + // | | + // INT DMA Mode (CR2A b1-0) ----------------->| | + // +----+ + int cr2a; // CR2A int vector; struct channel { @@ -182,6 +236,8 @@ struct SIO Mode mode; // CR4 で決まるモード // uPD7201 レジスタ + // CR0 の下位 3bit (PTR 部分) は読み出し時には使わないこと (代わりに + // ptr を使用する)。書き込み時は書き込んでよい(書き捨て)。 uint8 cr0; uint8 cr1; // CR2 は特殊なのでここにはない @@ -195,6 +251,7 @@ struct SIO uint8 sr1; // ここから Z8530 拡張 + uint8 wr10; // WR10 uint8 wr11; // WR11 uint16 tc; // WR12, WR13 uint8 wr14; // WR14 @@ -207,46 +264,100 @@ struct SIO // 取り出したら前にずらす? uint8 rxbuf[3]; // 受信バッファ(FIFO) int rxlen; // 受信バッファの有効バイト数 - bool rxrecved; // 1文字でも受信したら true (FirstCharIntr用) + + uint8 txbuf; // 送信バッファ + int txlen; // 送信バッファの有効バイト数 + uint8 tx_shiftreg; // 送信シフトレジスタ相当品 + + // First Char 用のフラグで、この受信で割り込みを起こすなら true。 + // ALL なら常に true。FIRSTCHAR の時は最初が true で1文字目の受信 + // 割り込みを出したところで false にする。 + bool all_or_first; + + // 送信割り込み + bool txint; + + uint int_asserted; // 割り込み要因を保持 } chan[2]; }; -class uPD7201Device - : public IODevice +class uPD7201Device : public IODevice { using inherited = IODevice; public: - uPD7201Device(); - ~uPD7201Device() override; + uPD7201Device(const std::string& objname_); + virtual ~uPD7201Device() override; - bool MonitorUpdate() override; + void ResetHard() override; // 受信 bool Rx(int ch, uint32 data); protected: - // チップリセット - void Reset(); - - void ResetChannel(struct SIO::channel *chan); - virtual uint8 ReadCtrl(struct SIO::channel *chan); - uint8 ReadData(struct SIO::channel *chan); - virtual void WriteCtrl(struct SIO::channel *chan, uint32 data); - void WriteData(struct SIO::channel *chan, uint32 data); - uint8 PeekCtrl(const struct SIO::channel *chan) const; - uint8 PeekData(const struct SIO::channel *chan) const; + void ResetChannel(SIO::channel *chan); + virtual uint8 ReadCtrl(SIO::channel *chan); + uint8 ReadData(SIO::channel *chan); + virtual void WriteCtrl(SIO::channel *chan, uint32 data); + void WriteData(SIO::channel *chan, uint32 data); + uint8 PeekCtrl(const SIO::channel *chan) const; + uint8 PeekData(const SIO::channel *chan) const; + + virtual void WriteCR0(SIO::channel *chan, uint32 data); + void SendAbort(SIO::channel *chan); + void ResetESIntr(SIO::channel *chan); + void EnableIntrOnNextRx(SIO::channel *chan); + void ResetTxIntrPending(SIO::channel *chan); + void ErrorReset(SIO::channel *chan); + void ResetHighestIUS(SIO::channel *chan); + void WriteCR1(SIO::channel *chan, uint32 data); + void WriteCR2(SIO::channel *chan, uint32 data); + void WriteCR3(SIO::channel *chan, uint32 data); + void WriteCR4(SIO::channel *chan, uint32 data); + virtual void WriteCR5(SIO::channel *chan, uint32 data); + void WriteCR6(SIO::channel *chan, uint32 data); + void WriteCR7(SIO::channel *chan, uint32 data); + + void TrySend(SIO::channel *chan); + void TXCallback(Event& event); + virtual void Tx(int ch, uint32 data) = 0; + void ChangeInterrupt(); // 割り込みを上げる (上位デバイスで用意する) virtual void Interrupt() = 0; + // 指定のレジスタ名を返す + virtual const char *CRName(const SIO::channel *chan, int n) const; + virtual const char *SRName(const SIO::channel *chan, int n) const; + // 現在のレジスタ名を返す + const char *CRName(const SIO::channel *chan) const { + return CRName(chan, chan->ptr); + } + const char *SRName(const SIO::channel *chan) const { + return SRName(chan, chan->ptr); + } + struct SIO cr {}; + // TxC ピンに供給されているクロックで 12ビットの通信にかかる + // 時間を ns 単位で設定。12 ビットは誤差を減らすために選択。 + uint64 txc12_ns {}; + + // 送信用イベント + std::array txevent {}; + + Monitor monitor { this }; + static const int bits_per_char[4]; + static const int clkrate[4]; private: - uint8 ReadSR0(const struct SIO::channel *chan) const; - uint8 ReadSR1(const struct SIO::channel *chan) const; + void SetTXPeriod(SIO::channel *chan); + + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + void MonitorUpdateCh(TextScreen&, int ch, int xbase, int ybase); + void MonitorReg(TextScreen&, + int, int, uint32 reg, const char * const *names); - void MonitorUpdateCh(int ch, int xbase, int ybase); - void MonitorReg(int, int, uint32 reg, const char * const *names); + static const char * const crnames[16]; + static const char * const srnames[16]; };