|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
9: #include "device.h"
1.1.1.10! root 10: #include "event.h"
1.1.1.7 root 11: #include "monitor.h"
1.1.1.10! root 12: #include <array>
1.1 root 13:
14: // uPD7201/Z8530 のレジスタ
15: //
16: // uPD7201 は、書き込みが CR (Command Register) 8本、
17: // 読み込みが SR (Status Register) 2本。
18: // Z8530 は、書き込みが WR (Write Register) 16本、
19: // 読み込みが RR (Read Register) 8本。
20: //
21: // Z8530 の WR0..WR7、RR0..RR2 は (名前が異なるが)
22: // uPD7201 の CR0..CR7、SR0..SR2 とわりとよく似ている (所々違う)。
23: //
24: // そのためデバイスは uPD7201Device クラスを基底に、SIODevice
25: // (ほぼ uPD7201Device) と SCCDevice (Z8530) とに派生している。
26: // レジスタ構造体は C++ の制約的に両方のセットを持ったものを一つ
27: // 用意するほうが楽なので、こうなっている。
28: struct SIO
29: {
1.1.1.8 root 30: // b7 b6 b5 b4 b3 b2 b1 b0
31: // +---------+--------------+--------------+
1.1 root 32: // CR0 | CRC | Command | Pointer |
1.1.1.8 root 33: // +---------+--------------+--------------+
1.1 root 34: static const int CR0_CRC = 0xc0;
35: static const int CR0_CMD = 0x38;
36: static const int CR0_PTR = 0x07;
37:
38: // Z8530 ではコマンド %000 と %001 がレジスタ切り替えなので、
39: // CMD が 0x38、PTR が 0x0f とあえて被せてある。
40: static const int WR0_CRC = CR0_CRC;
41: static const int WR0_CMD = CR0_CMD;
42: static const int WR0_PTR = 0x0f;
43:
1.1.1.8 root 44: // b7 b6 b5 b4 b3 b2 b1 b0
45: // +----+----+----+---------+----+----+----+
1.1 root 46: // CR1 | WE | -- | WR | RX Int | -- | TE | ES |
1.1.1.8 root 47: // +----+----+----+---------+----+----+----+
1.1 root 48: // | | | | +---- E/S Int Enable
49: // | | | +--------- TX INT/DMA Enable
50: // | | +--------------------- RX Int Mode
51: // | +----------------------------- Wait on RX(=%1),TX(=%0)
52: // +--------------------------------------- Wait Enable
53: static const int CR1_WAIT_EN = 0x80;
54: static const int CR1_WAIT_RX = 0x20;
55: static const int CR1_RXINT = 0x18;
56: static const int CR1_TXINT_EN = 0x02;
57: static const int CR1_ESINT_EN = 0x01;
58:
59: static const int WR1_WAIT_EN = CR1_WAIT_EN;
60: static const int WR1_WAIT_RX = CR1_WAIT_RX;
61: static const int WR1_RXINT = CR1_RXINT;
62: static const int WR1_TXINT_EN = CR1_TXINT_EN;
63: static const int WR1_ESINT_EN = CR1_ESINT_EN;
64:
65: // CR1_RXINT
66: static const int RXINT_DISABLE = 0x00; // disabled
67: static const int RXINT_FIRSTCHAR = 0x08; // First charactoer intr.
68: static const int RXINT_ALL_INC_SPECIAL = 0x10; // All char include special
69: static const int RXINT_ALL_EXC_SPECIAL = 0x18; // All char exclude special
70:
1.1.1.8 root 71: // b7 b6 b5 b4 b3 b2 b1 b0
72: // +---------+----+-------------------+----+
1.1 root 73: // CR3 | RX bits | AE | -- -- -- -- | RE |
1.1.1.8 root 74: // +---------+----+-------------------+----+
1.1 root 75: // | | +---- RX Enable
76: // | +----------------------------- Auto Enable
77: // +------------------------------------ RX bits
78: static const int CR3_RXBITS = 0xc0;
79: static const int CR3_AUTO_EN = 0x40;
80: static const int CR3_RX_EN = 0x01;
81:
82: static const int WR3_RXBITS = CR3_RXBITS;
83: static const int WR3_AUTO_EN = CR3_AUTO_EN;
84: static const int WR3_RX_EN = CR3_RX_EN;
85:
1.1.1.8 root 86: // b7 b6 b5 b4 b3 b2 b1 b0
87: // +---------+---------+---------+----+----+
1.1 root 88: // CR4 | ClkRate | SyncMode| StopBits| PV | PE |
1.1.1.8 root 89: // +---------+---------+---------+----+----+
1.1 root 90: // | | | | +---- Parity Enable(%1)
91: // | | | +--------- Parity Even(%1)
92: // | | +---------------- Stop Bits
93: // | +-------------------------- Sync Mode
94: // +------------------------------------ Clock Rate
1.1.1.6 root 95: //
1.1 root 96: static const int CR4_CLKRATE = 0xc0;
97: static const int CR4_SYNCMODE = 0x30;
98: static const int CR4_STOPBITS = 0x0c;
99: static const int CR4_PARITY_EVEN= 0x02;
100: static const int CR4_PARITY_EN = 0x01;
101:
102: static const int WR4_CLKRATE = CR4_CLKRATE;
103: static const int WR4_SYNCMODE = CR4_SYNCMODE;
104: static const int WR4_STOPBITS = CR4_STOPBITS;
105: static const int WR4_PARITY_EVEN= CR4_PARITY_EVEN;
106: static const int WR4_PARITY_EN = CR4_PARITY_EN;
107:
108: static const int SYNC_8BIT = 0x00;
109: static const int SYNC_16BIT = 0x10;
110: static const int SYNC_HDLC = 0x20;
111: static const int SYNC_EXT = 0x30;
112:
113: static const int SYNC_MODE = 0x00;
114: static const int STOP_BITS_1 = 0x04;
115: static const int STOP_BITS_1_5 = 0x08;
116: static const int STOP_BITS_2 = 0x0c;
117:
118: enum Mode {
119: SYNC = 0,
120: ASYNC = 1,
121: HDLC = 2,
122: };
123:
1.1.1.8 root 124: // b7 b6 b5 b4 b3 b2 b1 b0
125: // +----+---------+----+----+----+----+----+
1.1 root 126: // CR5 | DTR| TX bits | SB | TE | CRC| RTS| TC |
1.1.1.8 root 127: // +----+---------+----+----+----+----+----+
1.1 root 128: // | | | | | | +---- TX CRC Enable
129: // | | | | | +--------- ~RTS
130: // | | | | +-------------- CRC-16/CCITT
131: // | | | +------------------- TX Enable
132: // | | +------------------------ Send Break
133: // | +------------------------------- TX Bits
134: // +--------------------------------------- ~DTR
135: static const int CR5_DTR = 0x80;
136: static const int CR5_TXBITS = 0x60;
137: static const int CR5_SENDBREAK = 0x10;
138: static const int CR5_TX_EN = 0x08;
139: static const int CR5_CRC16 = 0x04;
140: static const int CR5_RTS = 0x02;
141: static const int CR5_TXCRC_EN = 0x01;
142:
143: static const int WR5_DTR = CR5_DTR;
144: static const int WR5_TXBITS = CR5_TXBITS;
145: static const int WR5_SENDBREAK = CR5_SENDBREAK;
146: static const int WR5_TX_EN = CR5_TX_EN;
147: static const int WR5_CRC16 = CR5_CRC16;
148: static const int WR5_RTS = CR5_RTS;
149: static const int WR5_TXCRC_EN = CR5_TXCRC_EN;
150:
1.1.1.8 root 151: // b7 b6 b5 b4 b3 b2 b1 b0
152: // +----+----+----+----+----+----+----+----+
1.1 root 153: // SR0 | BA | TU | CTS| SY | DCD| TE | IP | RA |
1.1.1.8 root 154: // +----+----+----+----+----+----+----+----+
1.1 root 155: static const int SR0_BREAK = 0x80; // Break/Abort
156: static const int SR0_TXUNDER = 0x40; // Tx Underrun
157: static const int SR0_CTS = 0x20; // CTS
158: static const int SR0_SYNC = 0x10; // SYNC
159: static const int SR0_DCD = 0x08; // DCD
160: static const int SR0_TXEMPTY = 0x04; // Tx Buffer Empty
161: static const int SR0_INTPEND = 0x02; // Interrupt Pending
162: static const int SR0_RXAVAIL = 0x01; // Rx Character Available
163:
164: static const int RR0_BREAK = SR0_BREAK;
165: static const int RR0_TXUNDER = SR0_TXUNDER;
166: static const int RR0_CTS = SR0_CTS;
167: static const int RR0_SYNC = SR0_SYNC;
168: static const int RR0_DCD = SR0_DCD;
169: static const int RR0_TXEMPTY = SR0_TXEMPTY;
170: static const int RR0_INTPEND = SR0_INTPEND;
171: static const int RR0_RXAVAIL = SR0_RXAVAIL;
172:
1.1.1.8 root 173: // b7 b6 b5 b4 b3 b2 b1 b0
174: // +----+----+----+----+--------------+----+
1.1 root 175: // SR1 | EF | CRC| RO | PE | ResidueCode | AS |
1.1.1.8 root 176: // +----+----+----+----+--------------+----+
1.1 root 177: static const int SR1_ENDOFFRAME = 0x80; // End of Frame
178: static const int SR1_CRCERROR = 0x40; // CRC/Framing Error
179: static const int SR1_RXOVERRUN = 0x20; // Rx Overrun
180: static const int SR1_PARITYERROR= 0x10; // Parity Error
181: static const int SR1_RESIDUEMASK= 0x0e; // Residue Code 2-0
182: static const int SR1_ALL_SENT = 0x01; // All Sent
183:
184: static const int RR1_ENDOFFRAME = SR1_ENDOFFRAME;
185: static const int RR1_CRCERROR = SR1_CRCERROR;
186: static const int RR1_RXOVERRUN = SR1_RXOVERRUN;
187: static const int RR1_PARITYERROR= SR1_PARITYERROR;
188: static const int RR1_RESIDUEMASK= SR1_RESIDUEMASK;
189: static const int RR1_ALL_SENT = SR1_ALL_SENT;
190:
1.1.1.5 root 191: // 割り込みベクタ ChB ChA
192: // Tx Buffer Empty %000 %100
193: // External/Status Change %001 %101
194: // Rx Character Available %010 %110
195: // Special Rx Condition %011 %111
196: // (この 3bit が V4-V2 か V2-V0 のところに出力される)
197: static const uint INTR_TX = (1U << 0);
198: static const uint INTR_ES = (1U << 1);
199: static const uint INTR_RX = (1U << 2);
200: static const uint INTR_SP = (1U << 3);
201:
202: // 割り込みあたりのロジック (uPD7201/7201A Figure 3-2 より INT 分のみ)
203: //
204: // Rx Disable (CR1:b1) *1 -----------------+ *1: Rx Enable (CR3:b0)
205: // | じゃなくて?
206: // +---+ |
207: // * RxCharAvailable ---->| | |
208: // | AND )--+ | +---+
209: // All/First RxChar --->| | | +---+ +->| |
210: // +---+ +->) | | AND )--+
211: // ) OR )-->| | |
212: // * Special Rx Condition ----------->) | +---+ | +-+
213: // +---+ +->) |
214: // ) | ---
215: // * External/Status -------------------------------------->) OR |o-> INT
216: // ) |
217: // +---+ +->) |
218: // * Tx Buffer Empty ---------------->| | +----+ | +-+
219: // | | | | |
220: // (Reset TxIntPend Cmd) --------->o| AND )-->| | |
221: // | | | | |
222: // Tx INT/DMA Enable (CR1:b1) ----->| | | AND )--+
223: // +---+ | |
224: // | |
225: // INT DMA Mode (CR2A b1-0) ----------------->| |
226: // +----+
227:
1.1 root 228: int cr2a; // CR2A
229: int vector;
230: struct channel {
231: // 二次変数など
232: int ptr; // CR0 で決まるレジスタ選択ポインタ
233: int id; // チャンネル番号。0 か 1
234: const char *name; // チャンネル名。"A" か "B"
235: const char *desc; // チャンネルの用途(モニタ表示用)
236: Mode mode; // CR4 で決まるモード
237:
238: // uPD7201 レジスタ
1.1.1.5 root 239: // CR0 の下位 3bit (PTR 部分) は読み出し時には使わないこと (代わりに
240: // ptr を使用する)。書き込み時は書き込んでよい(書き捨て)。
1.1 root 241: uint8 cr0;
242: uint8 cr1;
243: // CR2 は特殊なのでここにはない
244: uint8 cr3;
245: uint8 cr4;
246: uint8 cr5;
247: uint8 cr6; // CR6 (未実装)
248: uint8 cr7; // CR7 (未実装)
249:
250: uint8 sr0;
251: uint8 sr1;
252:
253: // ここから Z8530 拡張
1.1.1.5 root 254: uint8 wr10; // WR10
1.1 root 255: uint8 wr11; // WR11
256: uint16 tc; // WR12, WR13
257: uint8 wr14; // WR14
258: uint8 wr15; // WR15
259:
260: // ここからその他の内部状態
261: bool es_ratched; // E/S ビットがラッチされているか
262:
263: // 受信バッファは短いので先頭からの FIFO とし、
264: // 取り出したら前にずらす?
265: uint8 rxbuf[3]; // 受信バッファ(FIFO)
266: int rxlen; // 受信バッファの有効バイト数
1.1.1.5 root 267:
1.1.1.10! root 268: uint8 txbuf; // 送信バッファ
! 269: int txlen; // 送信バッファの有効バイト数
! 270: uint8 tx_shiftreg; // 送信シフトレジスタ相当品
! 271:
1.1.1.5 root 272: // First Char 用のフラグで、この受信で割り込みを起こすなら true。
273: // ALL なら常に true。FIRSTCHAR の時は最初が true で1文字目の受信
274: // 割り込みを出したところで false にする。
275: bool all_or_first;
276:
1.1.1.10! root 277: // 送信割り込み
! 278: bool txint;
1.1.1.5 root 279:
280: uint int_asserted; // 割り込み要因を保持
1.1 root 281: } chan[2];
282: };
283:
1.1.1.7 root 284: class uPD7201Device : public IODevice
1.1 root 285: {
1.1.1.3 root 286: using inherited = IODevice;
1.1 root 287: public:
1.1.1.7 root 288: uPD7201Device(const std::string& objname_);
1.1.1.5 root 289: virtual ~uPD7201Device() override;
1.1 root 290:
1.1.1.6 root 291: void ResetHard() override;
1.1 root 292:
293: // 受信
294: bool Rx(int ch, uint32 data);
295:
296: protected:
1.1.1.10! root 297: void ResetChannel(SIO::channel *chan);
! 298: virtual uint8 ReadCtrl(SIO::channel *chan);
! 299: uint8 ReadData(SIO::channel *chan);
! 300: virtual void WriteCtrl(SIO::channel *chan, uint32 data);
! 301: void WriteData(SIO::channel *chan, uint32 data);
! 302: uint8 PeekCtrl(const SIO::channel *chan) const;
! 303: uint8 PeekData(const SIO::channel *chan) const;
! 304:
! 305: virtual void WriteCR0(SIO::channel *chan, uint32 data);
! 306: void SendAbort(SIO::channel *chan);
! 307: void ResetESIntr(SIO::channel *chan);
! 308: void EnableIntrOnNextRx(SIO::channel *chan);
! 309: void ResetTxIntrPending(SIO::channel *chan);
! 310: void ErrorReset(SIO::channel *chan);
! 311: void ResetHighestIUS(SIO::channel *chan);
! 312: void WriteCR1(SIO::channel *chan, uint32 data);
! 313: void WriteCR2(SIO::channel *chan, uint32 data);
! 314: void WriteCR3(SIO::channel *chan, uint32 data);
! 315: void WriteCR4(SIO::channel *chan, uint32 data);
! 316: virtual void WriteCR5(SIO::channel *chan, uint32 data);
! 317: void WriteCR6(SIO::channel *chan, uint32 data);
! 318: void WriteCR7(SIO::channel *chan, uint32 data);
! 319:
! 320: void TrySend(SIO::channel *chan);
! 321: void TXCallback(Event& event);
! 322: virtual void Tx(int ch, uint32 data) = 0;
1.1 root 323:
1.1.1.10! root 324: void ChangeInterrupt();
1.1 root 325: // 割り込みを上げる (上位デバイスで用意する)
326: virtual void Interrupt() = 0;
327:
1.1.1.10! root 328: // 指定のレジスタ名を返す
! 329: virtual const char *CRName(const SIO::channel *chan, int n) const;
! 330: virtual const char *SRName(const SIO::channel *chan, int n) const;
! 331: // 現在のレジスタ名を返す
! 332: const char *CRName(const SIO::channel *chan) const {
! 333: return CRName(chan, chan->ptr);
! 334: }
! 335: const char *SRName(const SIO::channel *chan) const {
! 336: return SRName(chan, chan->ptr);
! 337: }
! 338:
1.1 root 339: struct SIO cr {};
340:
1.1.1.10! root 341: // TxC ピンに供給されているクロックで 12ビットの通信にかかる
! 342: // 時間を ns 単位で設定。12 ビットは誤差を減らすために選択。
! 343: uint64 txc12_ns {};
! 344:
! 345: // 送信用イベント
! 346: std::array<Event, 2> txevent {};
! 347:
1.1.1.7 root 348: Monitor monitor { this };
349:
1.1 root 350: static const int bits_per_char[4];
1.1.1.10! root 351: static const int clkrate[4];
1.1.1.5 root 352:
1.1.1.8 root 353: private:
1.1.1.10! root 354: void SetTXPeriod(SIO::channel *chan);
1.1.1.2 root 355:
1.1.1.7 root 356: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
1.1.1.4 root 357: void MonitorUpdateCh(TextScreen&, int ch, int xbase, int ybase);
358: void MonitorReg(TextScreen&,
359: int, int, uint32 reg, const char * const *names);
1.1.1.10! root 360:
! 361: static const char * const crnames[16];
! 362: static const char * const srnames[16];
1.1 root 363: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.