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