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