|
|
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: #include "scc.h"
1.1.1.8 root 8: #include "bitops.h"
1.1.1.5 root 9: #include "interrupt.h"
1.1.1.8 root 10: #include "keyboard.h"
1.1.1.5 root 11: #include "mpu.h"
1.1 root 12:
13: // IODevice
14: // |
15: // v
16: // upd7201Device (uPD7201 と Z8530 の共通部分)
17: // |
18: // +---------+----------+
19: // v v
20: // SIODevice SCCDevice
21: // (LUNA, uPD7201) (X68030, Z8530)
22:
1.1.1.2 root 23: std::unique_ptr<SCCDevice> gSCC;
24:
1.1 root 25: SCCDevice::SCCDevice()
1.1.1.7 root 26: : inherited("SCC")
1.1 root 27: {
28: devaddr = baseaddr;
29: devlen = 0x2000;
1.1.1.2 root 30:
31: cr.chan[0].desc = "Serial Port";
32: cr.chan[1].desc = "Mouse";
1.1.1.7 root 33:
34: // X680x0 では SCC と呼ぶほうが通りがいい。
1.1.1.9 ! root 35: for (int ch = 0; ch < txevent.size(); ch++) {
! 36: txevent[ch].SetName(string_format("SCC Ch%s TX", cr.chan[ch].name));
! 37: }
1.1.1.7 root 38: monitor.Regist(ID_MONITOR_SCC);
1.1 root 39: }
40:
41: SCCDevice::~SCCDevice()
42: {
43: }
44:
45: // Z8530 は RD と WR を同時に Low にするとリセットがかかる。
46: // 回路図からは PEDEC から繋がってるという以上のことは分からないけど
47: // 普通に考えればハードリセットでリセットされるよな。
48:
49: uint64
1.1.1.6 root 50: SCCDevice::Read(uint32 offset)
1.1 root 51: {
1.1.1.4 root 52: gMPU->AddCycle(41); // InsideOut p.135
53:
1.1.1.6 root 54: switch (offset) {
1.1.1.3 root 55: case 0: // $E98001
1.1 root 56: return ReadCtrl(&cr.chan[1]);
57:
1.1.1.3 root 58: case 1: // $E98003
1.1.1.8 root 59: return ReadData(&cr.chan[1]);
1.1 root 60:
1.1.1.3 root 61: case 2: // $E98005
1.1 root 62: return ReadCtrl(&cr.chan[0]);
63:
1.1.1.3 root 64: case 3: // $E98007
1.1 root 65: putlog(0, "ChA データレジスタ読み込み (未実装)");
1.1.1.2 root 66: return ReadData(&cr.chan[0]);
1.1 root 67: }
1.1.1.3 root 68: __unreachable();
1.1 root 69: }
70:
71: uint64
1.1.1.6 root 72: SCCDevice::Write(uint32 offset, uint32 data)
1.1 root 73: {
1.1.1.4 root 74: gMPU->AddCycle(49); // InsideOut p.135
75:
1.1.1.6 root 76: switch (offset) {
1.1.1.3 root 77: case 0: // $E98001
1.1 root 78: WriteCtrl(&cr.chan[1], data);
79: return 0;
80:
1.1.1.3 root 81: case 1: // $E98003
1.1 root 82: WriteData(&cr.chan[1], data);
83: return 0;
84:
1.1.1.3 root 85: case 2: // $E98005
1.1 root 86: WriteCtrl(&cr.chan[0], data);
87: return 0;
88:
1.1.1.3 root 89: case 3: // $E98007
1.1 root 90: WriteData(&cr.chan[0], data);
91: return 0;
92: }
1.1.1.3 root 93: __unreachable();
1.1 root 94: }
95:
96: uint64
1.1.1.6 root 97: SCCDevice::Peek(uint32 offset)
1.1 root 98: {
1.1.1.6 root 99: switch (offset) {
1.1.1.3 root 100: case 0: // $E98001
1.1.1.2 root 101: return PeekCtrl(&cr.chan[1]);
102:
1.1.1.3 root 103: case 1: // $E98003
1.1.1.8 root 104: return PeekData(&cr.chan[1]);
1.1.1.2 root 105:
1.1.1.3 root 106: case 2: // $E98005
1.1.1.2 root 107: return PeekCtrl(&cr.chan[0]);
108:
1.1.1.3 root 109: case 3: // $E98007
1.1.1.2 root 110: return PeekData(&cr.chan[0]);
111: }
1.1.1.3 root 112: __unreachable();
1.1 root 113: }
114:
1.1.1.9 ! root 115: // CR(WR) レジスタ名を返す。Z8530 では WRn のほうが通りがいい。
! 116: const char *
! 117: SCCDevice::CRName(const SIO::channel *chan, int ptr_) const
! 118: {
! 119: assert(ptr_ < 16);
! 120: int idx = ptr_ * 2 + chan->id;
! 121: assert(idx < countof(wrnames));
! 122: return wrnames[idx];
! 123: }
! 124:
! 125: // SR(RR) レジスタ名を返す。Z8530 では RRn のほうが通りがいい。
! 126: const char *
! 127: SCCDevice::SRName(const SIO::channel *chan, int ptr_) const
! 128: {
! 129: assert(ptr_ < 16);
! 130: int idx = ptr_ * 2 + chan->id;
! 131: assert(idx < countof(rrnames));
! 132: return rrnames[idx];
! 133: }
! 134:
1.1 root 135: // Z8530 制御ポート読み込み
136: uint8
1.1.1.9 ! root 137: SCCDevice::ReadCtrl(SIO::channel *chan)
1.1 root 138: {
139: return inherited::ReadCtrl(chan);
140: }
141:
142: // Z8530 制御ポート書き込み
143: void
1.1.1.9 ! root 144: SCCDevice::WriteCtrl(SIO::channel *chan, uint32 data)
1.1 root 145: {
146: switch (chan->ptr) {
147: case 0: // WR0
1.1.1.9 ! root 148: WriteCR0(chan, data);
1.1 root 149: break;
150:
151: case 2: // WR2
152: // Z8530 の WR2 は A/B 共通でベクタ設定
153: putlog(2, "WR2 <- $%02x ベクタ設定", data);
154: cr.vector = data;
155: // アクセス後は WR0 へ戻す
156: chan->ptr = 0;
157: break;
158:
159: case 1: // WR1
160: case 3:
161: case 4:
162: case 5:
163: case 6:
164: case 7:
165: inherited::WriteCtrl(chan, data);
166: break;
167:
168: case 8: // WR8
169: WriteData(chan, data);
170: // アクセス後は WR0 へ戻す
171: chan->ptr = 0;
172: break;
173:
174: case 9: // WR9
1.1.1.9 ! root 175: putlog(2, "%s <- $%02x", WRName(chan), data);
1.1 root 176: switch ((data & 0xc0) >> 6) {
177: case 0: // No Reset
178: break;
179: case 1: // Channel Reset A
180: ResetChannel(&cr.chan[0]);
181: break;
182: case 2: // Channel Reset B
183: ResetChannel(&cr.chan[1]);
184: break;
185: case 3: // Force Hardware Reset
1.1.1.6 root 186: ResetHard();
1.1 root 187: break;
188: default:
189: __unreachable();
190: }
191: // アクセス後は WR0 へ戻す
192: chan->ptr = 0;
193: break;
194:
1.1.1.5 root 195: case 10: // WR10
1.1.1.9 ! root 196: putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1.1.5 root 197: chan->wr10 = data;
198: // アクセス後は WR0 へ戻す
199: chan->ptr = 0;
200: break;
201:
1.1 root 202: case 11: // WR11
1.1.1.9 ! root 203: putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1 root 204: chan->wr11 = data;
205: // アクセス後は WR0 へ戻す
206: chan->ptr = 0;
207: break;
208:
209: case 12: // WR12
210: chan->tc = (chan->tc & 0xff00) | data;
1.1.1.9 ! root 211: putlog(2, "%s TC(L)=%04x", WRName(chan), chan->tc);
! 212: SetTXC(chan);
1.1 root 213: // アクセス後は WR0 へ戻す
214: chan->ptr = 0;
215: break;
216:
217: case 13: // WR13
218: chan->tc = (chan->tc & 0x00ff) | (data << 8);
1.1.1.9 ! root 219: putlog(2, "%s TC(H)=%04x", WRName(chan), chan->tc);
! 220: SetTXC(chan);
1.1 root 221: // アクセス後は WR0 へ戻す
222: chan->ptr = 0;
223: break;
224:
225: case 14: // WR14
1.1.1.9 ! root 226: putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1 root 227: chan->wr14 = data;
228: // アクセス後は WR0 へ戻す
229: chan->ptr = 0;
230: break;
231:
232: case 15: // WR15
1.1.1.9 ! root 233: putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1 root 234: chan->wr15 = data;
235: // アクセス後は WR0 へ戻す
236: chan->ptr = 0;
237: break;
238:
239: default:
1.1.1.9 ! root 240: PANIC("未実装レジスタ書き込み %s <- $%02x", WRName(chan), data);
! 241: break;
! 242: }
! 243: }
! 244:
! 245: // 内部の送信データクロックの設定
! 246: void
! 247: SCCDevice::SetTXC(SIO::channel *chan)
! 248: {
! 249: // 5MHz = 200nsec
! 250: // 12bit = 2.4usec
! 251: txc12_ns = (2 * (chan->tc + 2)) * 2.4_usec;
! 252: }
! 253:
! 254: // CR0(WR0) 書き込み。
! 255: // uPD7201 の CR0 とは微妙に互換性がないので似てるけど違うので注意。
! 256: void
! 257: SCCDevice::WriteCR0(SIO::channel *chan, uint32 data)
! 258: {
! 259: uint cmd;
! 260:
! 261: // XXX b7,b6 (CRC Reset Command) は未対応。
! 262: // XXX コマンドが %001、%000 以外の時に PTR(レジスタセレクト) が同時に
! 263: // 指定されたらどうなるか。
! 264: chan->cr0 = data;
! 265:
! 266: if ((chan->cr0 & SIO::WR0_CRC)) {
! 267: putlog(0, "%s CRC リセット未実装", WRName(chan, 0));
! 268: }
! 269:
! 270: cmd = (chan->cr0 & SIO::WR0_CMD) >> 3;
! 271: switch (cmd) {
! 272: case 0:
! 273: case 1:
! 274: // コマンド 0、1 がレジスタ切り替え
! 275: chan->ptr = chan->cr0 & SIO::WR0_PTR;
! 276: putlog(3, "%s <- $%02x (ptr=%d)", WRName(chan, 0), data, chan->ptr);
! 277: break;
! 278: case 2: // Reset Ext/Status Interrupts
! 279: ResetESIntr(chan);
! 280: break;
! 281: case 3: // Send Abort
! 282: SendAbort(chan);
! 283: break;
! 284: case 4: // Enable Int on Next Rx Character
! 285: EnableIntrOnNextRx(chan);
! 286: break;
! 287: case 5: // Reset Tx Int Pending
! 288: ResetTxIntrPending(chan);
! 289: break;
! 290: case 6: // Error Reset
! 291: ErrorReset(chan);
1.1 root 292: break;
1.1.1.9 ! root 293: case 7: // Reset Highest IUS
! 294: ResetHighestIUS(chan);
! 295: break;
! 296: default:
! 297: __unreachable();
1.1 root 298: }
299: }
300:
1.1.1.8 root 301: void
1.1.1.9 ! root 302: SCCDevice::WriteCR5(SIO::channel *chan, uint32 data)
1.1.1.8 root 303: {
304: bool rts = bit_falling(chan->cr5, data, SIO::CR5_RTS);
305:
306: inherited::WriteCR5(chan, data);
307:
308: if (chan->id == 1 && rts) {
309: gKeyboard->MouseSendStart();
310: }
311: }
312:
1.1 root 313: // 割り込みを上げる
314: void
315: SCCDevice::Interrupt()
316: {
317: putlog(0, "割り込み(未実装)");
1.1.1.5 root 318: // gInterrupt->Raise(this);
319: }
320:
321: // 割り込みアクノリッジ
322: int
323: SCCDevice::InterruptAcknowledge()
324: {
325: return 0x50; /* XXX 実際は WR2 とか要因で変わる */
1.1 root 326: }
1.1.1.9 ! root 327:
! 328: void
! 329: SCCDevice::Tx(int ch, uint32 data)
! 330: {
! 331: // TODO: シリアル送信
! 332: // ChA はシリアルポート
! 333: // ChB はマウスだが TxD は接続されていない
! 334: }
! 335:
! 336: // ログ表示用のレジスタ名
! 337: /*static*/ const char * const
! 338: SCCDevice::wrnames[32] = {
! 339: "WR0A", "WR0B",
! 340: "WR1A", "WR1B",
! 341: "WR2A", "WR2B",
! 342: "WR3A", "WR3B",
! 343: "WR4A", "WR4B",
! 344: "WR5A", "WR5B",
! 345: "WR6A", "WR6B",
! 346: "WR7A", "WR7B",
! 347: "WR8A", "WR8B",
! 348: "WR9A", "WR9B",
! 349: "WR10A", "WR10B",
! 350: "WR11A", "WR11B",
! 351: "WR12A", "WR12B",
! 352: "WR13A", "WR13B",
! 353: "WR14A", "WR14B",
! 354: "WR15A", "WR15B",
! 355: };
! 356: /*static*/ const char * const
! 357: SCCDevice::rrnames[32] = {
! 358: "RR0A", "RR0B",
! 359: "RR1A", "RR1B",
! 360: "RR2A", "RR2B",
! 361: "RR3A", "RR3B",
! 362: "RR4A?", "RR4A?",
! 363: "RR5A?", "RR5A?",
! 364: "RR6A?", "RR6A?",
! 365: "RR7A?", "RR7A?",
! 366: "RR8A", "RR8B",
! 367: "RR9A?", "RR9A?",
! 368: "RR10A", "RR10B",
! 369: "RR11A?", "RR11A?",
! 370: "RR12A", "RR12B",
! 371: "RR13A", "RR13B",
! 372: "RR14A?", "RR14A?",
! 373: "RR15A", "RR15B",
! 374: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.