|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.10 root 7: //
8: // PIO/PPI (i8255)
9: //
10:
11: // IODevice
12: // |
13: // | +-------------+
14: // +--| i8255Device | (8255 としての共通部分)
15: // +-------------+
16: // |
17: // | +-----------+
18: // +--| PPIDevice | (X68030)
19: // | +-----------+
20: // |
21: // | +------------+
22: // +--| PIO0Device | (LUNA)
23: // | +------------+
24: // |
25: // | +------------+
26: // +--| PIO1Device | (LUNA)
27: // +------------+
28:
1.1 root 29: #include "pio.h"
1.1.1.9 root 30: #include "bitops.h"
1.1.1.12 root 31: #include "dipsw.h"
1.1.1.17! root 32: #include "event.h"
1.1.1.12 root 33: #include "interrupt.h"
1.1 root 34: #include "lcd.h"
1.1.1.3 root 35: #include "mainapp.h"
1.1.1.15 root 36: #include "monitor.h"
1.1.1.12 root 37: #include "mpu64180.h"
1.1.1.10 root 38: #include "power.h"
1.1 root 39: #include "scheduler.h"
40:
41: //
42: // i8255
43: //
44:
45: // コンストラクタ
1.1.1.14 root 46: i8255Device::i8255Device(uint objid_)
1.1.1.12 root 47: : inherited(objid_)
1.1 root 48: {
49: }
50:
51: // デストラクタ
52: i8255Device::~i8255Device()
53: {
54: }
55:
1.1.1.4 root 56: // リセット
57: void
1.1.1.10 root 58: i8255Device::ResetHard(bool poweron)
1.1.1.4 root 59: {
60: // clears the control register
61: // and place ports A, B, and C in input mode.
62: // The input latches in ports A, B, and C are not cleared.
63:
64: ctrl = 0b10011011;
65: }
66:
1.1 root 67: // コントロールポートへの書き込み。
68: void
69: i8255Device::WriteCtrl(uint32 data)
70: {
71: if ((data & 0x80)) {
72: // 最上位が立っていればモード設定
73: ctrl = data;
1.1.1.12 root 74: if (__predict_false(loglevel >= 1)) {
75: if (loglevel >= 2) {
1.1.1.14 root 76: putlogn("Ctrl <- $%02x: GrA/Bmode=%u/%u PA=%s PB=%s PC=%s:%s",
1.1.1.12 root 77: data,
78: GetGroupAMode(), GetGroupBMode(),
79: PortADir() == DIR_IN ? "IN" : "OUT",
80: PortBDir() == DIR_IN ? "IN" : "OUT",
81: PortCHDir() == DIR_IN ? "IN" : "OUT",
82: PortCLDir() == DIR_IN ? "IN" : "OUT");
83: } else {
84: putlogn("Ctrl <- $%02x: SetMode", data);
85: }
86: }
1.1 root 87:
88: // モード設定すると PC はゼロクリアされる
89: for (int pc = 0; pc < 8; pc++) {
90: SetPC(pc, 0);
91: }
92: } else {
93: // portC 出力
94: //
95: // 0 x x x P P P V
96: // | | | +-- 書き込むビットデータ
97: // +--+--+----- 書き込むビット位置
98:
1.1.1.14 root 99: uint pc = (data >> 1) & 7;
100: uint val = data & 1;
101: putlog(2, "Ctrl <- $%02x: SetPC%u=%u", data, pc, val);
1.1 root 102: SetPC(pc, val);
103: }
104: }
105:
1.1.1.14 root 106: bool
107: i8255Device::PokePort(uint32 offset, uint32 data)
108: {
109: return false;
110: }
111:
1.1.1.12 root 112: // 共通部分を表示。
113: // 戻り値は表示を終えた次の行。
114: int
115: i8255Device::MonitorUpdateCommon(TextScreen& screen, int y)
116: {
117: // Control = $xx
118: // GroupA (PortA,PortCH) Mode: 0(Basic I/O)
119: // GroupB (PortB,PortCL) Mode: 1(Strobed I/O)
120: // Port Direction: PA=OUT PB=IN PC(H)=OUT PC(L)=OUT
121:
122: screen.Print(1, y, "Control = $%02x:", ctrl);
123: static const char * const modestr[] = {
124: "Basic I/O",
125: "Strobed I/O",
126: "BiDirection",
127: "BiDirection",
128: };
129: const int x = 16;
1.1.1.14 root 130: screen.Print(x, y++, "GroupA (PortA,PortCH) Mode: %u(%s)",
1.1.1.12 root 131: GetGroupAMode(),
132: modestr[GetGroupAMode()]);
1.1.1.14 root 133: screen.Print(x, y++, "GroupB (PortB,PortCL) Mode: %u(%s)",
1.1.1.12 root 134: GetGroupBMode(),
135: modestr[GetGroupBMode()]);
136: static const char *inoutstr[] = {
137: "OUT",
138: "IN ",
139: };
140: screen.Print(x, y++, "Port Direction: PA=%s PB=%s PC(H)=%s PC(L)=%s",
141: inoutstr[PortADir()],
142: inoutstr[PortBDir()],
143: inoutstr[PortCHDir()],
144: inoutstr[PortCLDir()]);
145:
146: return y;
147: }
148:
1.1 root 149: //
150: // X68k PPI
151: //
152:
1.1.1.13 root 153: // InsideOut p.135
154: static const busdata ppi_wait = busdata::Wait(19 * 40_nsec);
155:
1.1 root 156: // コンストラクタ
157: PPIDevice::PPIDevice()
1.1.1.12 root 158: : inherited(OBJ_PPI)
1.1 root 159: {
160: }
161:
162: // デストラクタ
163: PPIDevice::~PPIDevice()
164: {
165: }
166:
1.1.1.13 root 167: busdata
1.1.1.14 root 168: PPIDevice::ReadPort(uint32 offset)
1.1 root 169: {
1.1.1.13 root 170: busdata data;
1.1.1.4 root 171:
1.1.1.6 root 172: switch (offset) {
1.1 root 173: case 0:
174: case 1:
1.1.1.13 root 175: data = 0xff;
176: break;
1.1 root 177: case 2:
1.1.1.11 root 178: putlog(0, "Read $e9a005 PortC (NOT IMPLEMENTED)");
1.1.1.13 root 179: data = 0xff;
180: break;
1.1 root 181: case 3:
1.1.1.11 root 182: putlog(0, "Read $e9a007 Ctrl (NOT IMPLEMENTED)");
1.1.1.13 root 183: data = 0xff;
184: break;
1.1 root 185: default:
1.1.1.14 root 186: VMPANIC("corrupted offset=%u", offset);
1.1 root 187: }
1.1.1.13 root 188:
189: data |= ppi_wait;
1.1.1.14 root 190: data |= BusData::Size1;
1.1.1.13 root 191: return data;
1.1 root 192: }
193:
1.1.1.13 root 194: busdata
1.1.1.14 root 195: PPIDevice::WritePort(uint32 offset, uint32 data)
1.1 root 196: {
1.1.1.6 root 197: switch (offset) {
1.1 root 198: case 0:
199: case 1:
200: break;
1.1.1.11 root 201: case 2: // PPI PortC
202: for (int i = 0; i < 8; i++) {
203: SetPC(i, data & 1);
204: data >>= 1;
205: }
1.1 root 206: break;
207: case 3:
1.1.1.11 root 208: WriteCtrl(data);
1.1 root 209: break;
210: default:
1.1.1.14 root 211: VMPANIC("corrupted offset=%u", offset);
1.1 root 212: }
1.1.1.14 root 213: busdata r = ppi_wait;
214: r |= BusData::Size1;
215: return r;
1.1 root 216: }
217:
1.1.1.13 root 218: busdata
1.1.1.14 root 219: PPIDevice::PeekPort(uint32 offset)
1.1 root 220: {
221: // XXX
222: return 0xff;
223: }
224:
1.1.1.10 root 225: // PortC 書き込み
226: void
1.1.1.14 root 227: PPIDevice::SetPC(uint pc, uint val)
1.1.1.10 root 228: {
1.1.1.11 root 229: switch (pc) {
230: case 0: // ADPCM PAN Left Off
231: pan_left = !val;
1.1.1.14 root 232: return;
1.1.1.11 root 233: case 1: // ADPCM PAN Right Off
234: pan_right = !val;
1.1.1.14 root 235: return;
1.1.1.11 root 236: case 2: // ADPCM サンプリングレート
237: adpcm_rate = (adpcm_rate & 2) | val;
1.1.1.14 root 238: return;
1.1.1.11 root 239: case 3: // ADPCM サンプリングレート
240: adpcm_rate = (val << 1) | (adpcm_rate & 1);
1.1.1.14 root 241: return;
1.1.1.11 root 242:
243: case 4: // ジョイスティック #1 コントロール
244: case 5: // ジョイスティック #2 コントロール
245: case 6: // ジョイスティック #1 ボタン A
246: case 7: // ジョイスティック #1 ボタン B
1.1.1.14 root 247: putlog(1, "SetPC(%u) <- %u (NOT IMPLEMENTED)", pc, val);
248: return;
1.1.1.11 root 249: default:
1.1.1.14 root 250: VMPANIC("corrupted pc=%u", pc);
1.1.1.11 root 251: }
1.1.1.10 root 252: }
253:
1.1 root 254: //
255: // LUNA PIO0
256: //
257: // 仕様は 0x49000000 から 4バイトだが、
1.1.1.12 root 258: // LUNA-I では 0x48000000 から 0x4bffffff まで 4バイト単位のミラーが見える。
259: // LUNA-88K では 0x48000000 から 0x49ffffff までが
260: // (こちらはロングワード配置なので) 16バイト単位のミラーに見える。
1.1.1.9 root 261: //
262: // PIO から読み出せる値のビットの並び順が機種によって異なる。
1.1.1.12 root 263: // LUNA-I では DIPSW 1番が LSB、8番が MSB の並び順、
264: // LUNA-88K では DIPSW 1番が MSB、8番が LSB の並び順。
1.1.1.9 root 265: // 値は、並び順に関わらずどちらも
266: // %0 が false = down = "0"、%1 が true = up = "1" である。
267: //
268: // #1 #2 #3 #4 #5 #6 #7 #8
269: // +-------------------------+
270: // | [] [] [] [] [] [] [] | 本体外観
271: // | [] |
272: // +-------------------------+
273: //
274: // luna-dipsw1 = "01111111" ← 設定ファイル
275: // |||||||| ↓ このクラスのメンバ変数
276: // |||||||+- dipsw1[7] = true;
277: // ||||||+-- dipsw1[6] = true;
278: // |||||+--- dipsw1[5] = true;
279: // ||||+---- dipsw1[4] = true;
280: // |||+----- dipsw1[3] = true;
281: // ||+------ dipsw1[2] = true;
282: // |+------- dipsw1[1] = true;
283: // +-------- dipsw1[0] = false;
284: //
285: // b7 b6 b5 b4 b3 b2 b1 b0
286: // +----+----+----+----+----+----+----+----+
1.1.1.12 root 287: // LUNA-I | #8 | #7 | #6 | #5 | #4 | #3 | #2 | #1 |
1.1.1.9 root 288: // PortA | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | %1=UP, %0=DOWN
289: // +----+----+----+----+----+----+----+----+
290: //
291: // b7 b6 b5 b4 b3 b2 b1 b0
292: // +----+----+----+----+----+----+----+----+
1.1.1.12 root 293: // LUNA-88K | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 |
1.1.1.9 root 294: // PortA | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | %1=UP, %0=DOWN
295: // +----+----+----+----+----+----+----+----+
1.1 root 296: //
1.1.1.12 root 297: // LUNA-I:
1.1 root 298: // #1-1 up なら UNIX をロードして移行。down なら ROM モニタで起動。
299: // #1-2 up ならディスプレイコンソール。down ならシリアルコンソール。
300: // #1-3 up - color display, down - force to have monochrome display
301: // #1-4 up - no write verification,
302: // down - verification on every harddisk write operation
303: // #1-5 up - OS is UniOS-U (SystemV/COFF),
304: // down - OS is UniOS (4.3BSD/a.out OMAGIC)
305: // #1-6 down - force monochrome display?
306: // #1-7 up - boot from local device, down - boot from network
307: // #1-8 up - normal boot, down - start diagnostics と書いてあるが
308: // down にすると画面真っ暗で詳細不明。
309: //
310: // #2-x すべて up にすると /boot が自動的にカーネルを起動。一つでも down が
311: // あれば /boot がプロンプトで停止。これは ROM ではなく NetBSD のブート
312: // ローダの話。
313: // どこか由来のソースコードらしいがたぶんビット演算を間違えている。
1.1.1.3 root 314: //
1.1.1.12 root 315: // LUNA-88K:
1.1.1.3 root 316: // #1-1 up なら ROM モニタで停止、down ならマルチユーザブート。
317: // OpenBSD カーネルも up なら UserKernelConfig で止まる模様?。
318: // #1-2 up なら外付けシリアルコンソール、down なら内蔵ビットマップ。
1.1.1.9 root 319: // #1-3..#1-7 は不明?
320: // #1-8 down なら自己診断後電源オフするようだ。
1.1.1.3 root 321: // #2-x はユーザ(?)
1.1 root 322:
323: // コンストラクタ
324: PIO0Device::PIO0Device()
1.1.1.12 root 325: : inherited(OBJ_PIO0)
1.1 root 326: {
1.1.1.12 root 327: // LUNA-I と LUNA-88K とでポートのビット並びが逆。どうして…
328: if (gMainApp.IsLUNA88K()) {
1.1.1.9 root 329: msb_first = true;
1.1.1.12 root 330: } else {
331: msb_first = false;
1.1.1.3 root 332: }
333:
1.1.1.12 root 334: // PIO0/PIO1
1.1.1.15 root 335: monitor = gMonitorManager->Regist(ID_MONITOR_PIO, this);
336: monitor->func = ToMonitorCallback(&PIO0Device::MonitorUpdate);
337: monitor->SetSize(76, 15);
1.1 root 338: }
339:
340: // デストラクタ
341: PIO0Device::~PIO0Device()
342: {
343: }
344:
1.1.1.12 root 345: // 初期化
1.1 root 346: bool
347: PIO0Device::Init()
348: {
1.1.1.12 root 349: interrupt = GetInterruptDevice();
350: pio1 = GetPIO1Device();
351:
1.1 root 352: return true;
353: }
354:
1.1.1.12 root 355: // リセット
356: void
357: PIO0Device::ResetHard(bool poweron)
358: {
359: auto dipswdev = GetDipswDevice();
360:
361: // XXX 本当は XP から割り込みが上がったタイミングとからしいけど、
362: // XP が出来るまでは当面リセットでラッチにしておく。
363: for (int i = 0; i < 8; i++) {
364: dipsw1[i] = dipswdev->Get(i);
365: dipsw2[i] = dipswdev->Get(i + 8);
366: }
367:
368: // XXX どうなる?
369: for (int i = 0; i < intreq.size(); i++) {
370: intreq[i] = false;
371: inten[i] = false;
372: }
373: }
1.1.1.7 root 374:
1.1.1.13 root 375: busdata
1.1.1.14 root 376: PIO0Device::ReadPort(uint32 offset)
1.1 root 377: {
1.1.1.14 root 378: busdata data;
1.1 root 379:
1.1.1.6 root 380: switch (offset) {
1.1 root 381: case 0:
382: // PortA
1.1.1.11 root 383: data = GetPA();
1.1.1.12 root 384:
385: // 割り込み要求(High)をクリア
386: intreq[INT_H] = false;
387: ChangeInterrupt();
388:
1.1.1.14 root 389: putlog(1, "DIP-SW1 -> $%02x", data.Data());
1.1.1.13 root 390: break;
1.1 root 391:
392: case 1:
393: // PortB
1.1.1.11 root 394: data = GetPB();
1.1.1.12 root 395:
396: // 割り込み要求(Low)をクリア
397: intreq[INT_L] = false;
398: ChangeInterrupt();
399:
1.1.1.14 root 400: putlog(1, "DIP-SW2 -> $%02x", data.Data());
1.1.1.13 root 401: break;
1.1 root 402:
403: case 2:
404: // PortC
405: data = GetPC();
1.1.1.14 root 406: putlog(1, "PortC -> $%02x", data.Data());
1.1.1.13 root 407: break;
1.1 root 408:
409: case 3:
410: data = ReadCtrl();
1.1.1.14 root 411: putlog(1, "Ctrl -> $%02x", data.Data());
1.1.1.13 root 412: break;
1.1 root 413:
414: default:
1.1.1.14 root 415: VMPANIC("corrupted offset=%u", offset);
1.1 root 416: }
1.1.1.13 root 417:
418: // XXX wait?
1.1.1.14 root 419: data |= BusData::Size1;
1.1.1.13 root 420: return data;
1.1 root 421: }
422:
1.1.1.13 root 423: busdata
1.1.1.14 root 424: PIO0Device::WritePort(uint32 offset, uint32 data)
1.1 root 425: {
1.1.1.6 root 426: switch (offset) {
1.1 root 427: case 0: // PIO0 PortA: DIPSW1 (入力のみ)
428: case 1: // PIO0 PortB: DIPSW2 (入力のみ)
1.1.1.13 root 429: break;
1.1 root 430:
431: case 2: // PIO0 PortC: ホスト割り込み制御
432: for (int i = 0; i < 8; i++) {
433: SetPC(i, data & 1);
434: data >>= 1;
435: }
1.1.1.13 root 436: break;
1.1 root 437:
438: case 3: // コントロール
439: WriteCtrl(data);
1.1.1.13 root 440: break;
1.1 root 441:
442: default:
1.1.1.14 root 443: VMPANIC("corrupted offset=%u", offset);
1.1 root 444: }
1.1.1.13 root 445:
446: // XXX wait?
1.1.1.14 root 447: busdata r = BusData::Size1;
448: return r;
1.1 root 449: }
450:
1.1.1.13 root 451: busdata
1.1.1.14 root 452: PIO0Device::PeekPort(uint32 offset)
1.1 root 453: {
1.1.1.6 root 454: switch (offset) {
1.1 root 455: case 0:
456: return GetPA();
457:
458: case 1:
459: return GetPB();
460:
461: case 2:
462: return GetPC();
463:
464: case 3:
465: return ReadCtrl();
466:
467: default:
1.1.1.12 root 468: return 0xff;
1.1 root 469: }
470: }
471:
1.1.1.12 root 472: // PIO0 が PIO0/PIO1 のモニタ両方を担当する。
1.1.1.3 root 473: void
1.1.1.8 root 474: PIO0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 475: {
476: int y;
477:
1.1.1.8 root 478: screen.Clear();
1.1.1.2 root 479:
1.1.1.12 root 480: // PIO0
481: screen.Puts(0, 0, "PIO0 (BaseAddr: $49000000)");
482: y = MonitorUpdateCommon(screen, 1);
483:
484: // PIO0 固有部
485: uint32 pa = GetPA();
486: uint32 pb = GetPB();
487: screen.Print(1, y, "PortA(DIP-SW1)=$%02x:", pa);
488: screen.Print(1, y + 1, "PortB(DIP-SW2)=$%02x:", pb);
489: for (int i = 0; i < 8; i++) {
490: // この図は bit7..0 をこの順で表示するので bitpos の向きは固定。
491: int bitpos = 7 - i;
492: // DIPSW の物理位置 #1 をバイトの下にするか上にするかが機種によって
493: // 違う。どうして…。
494: int label = (msb_first ? i : bitpos) + 1;
495:
496: bool d1 = (pa & (1U << bitpos));
497: bool d2 = (pb & (1U << bitpos));
1.1.1.14 root 498: screen.Print(21 + i * 7, y, TA::OnOff(d1), "DIP1-%u", label);
499: screen.Print(21 + i * 7, y + 1, TA::OnOff(d2), "DIP2-%u", label);
1.1.1.12 root 500: }
501: y += 2;
502:
503: uint32 pc = GetPC();
504: screen.Print(1, y, "PortC(XP etc.)=$%02x:", pc);
505: static const char * const pcstr[] = {
506: "XP RST", "PARITY", "------", "INT5EN",
507: "INT5RQ", "INT1EN", "------", "INT1RQ",
508: };
509: for (int i = 0; i < 8; i++) {
510: screen.Puts(21 + i * 7, y, TA::OnOff(pc & (1U << (7 - i))), pcstr[i]);
511: }
512: y++;
513:
514: // PIO1 移譲
515: y++;
516: pio1->MonitorUpdatePIO1(screen, y);
1.1.1.2 root 517: }
518:
1.1 root 519: // PortA (DIP-SW 1) 読み込み
520: uint32
521: PIO0Device::GetPA() const
522: {
523: uint32 data = 0;
524: for (int i = 0; i < 8; i++) {
525: data |= ((int)dipsw1[i]) << i;
526: }
1.1.1.9 root 527: if (msb_first) {
1.1.1.16 root 528: data = bitrev8(data);
1.1.1.9 root 529: }
1.1 root 530: return data & 0xff;
531: }
532:
533: // PortB (DIP-SW 2) 読み込み
534: uint32
535: PIO0Device::GetPB() const
536: {
537: uint32 data = 0;
538: for (int i = 0; i < 8; i++) {
539: data |= ((int)dipsw2[i]) << i;
540: }
1.1.1.9 root 541: if (msb_first) {
1.1.1.16 root 542: data = bitrev8(data);
1.1.1.9 root 543: }
1.1 root 544: return data & 0xff;
545: }
546:
547: // PortC 読み込み
548: uint32
549: PIO0Device::GetPC() const
550: {
551: uint32 data;
552:
553: data = 0x00 // XXX 空きビットは何が読めるか?
1.1.1.12 root 554: | (intreq[INT_L] ? 0x01 : 0)
555: | (inten[INT_L] ? 0x04 : 0)
556: | (intreq[INT_H] ? 0x08 : 0)
557: | (inten[INT_H] ? 0x10 : 0)
558: | (parity ? 0x40 : 0)
559: | (xp_reset ? 0x80 : 0);
1.1 root 560: return data;
561: }
562:
563: // PortC 書き込み
564: void
1.1.1.14 root 565: PIO0Device::SetPC(uint pc, uint val)
1.1 root 566: {
567: switch (pc) {
568: case 0:
1.1.1.12 root 569: // INT1 割り込み要求 (Read Only)
1.1 root 570: return;
571: case 1:
572: // Not Connected.
573: return;
574: case 2:
1.1.1.12 root 575: inten[INT_L] = val;
576: ChangeInterrupt();
1.1 root 577: return;
578: case 3:
1.1.1.12 root 579: // INT5 割り込み要求 (Read Only)
1.1 root 580: return;
581: case 4:
1.1.1.12 root 582: inten[INT_H] = val;
583: ChangeInterrupt();
1.1 root 584: return;
585: case 5:
586: // Not Connected.
587: return;
588: case 6:
589: // パリティ有効/無効
590: // 使わないので無視するが読み返しのために覚えておく
591: parity = val;
592: return;
593: case 7:
594: // XP リセット
595: if ((val ^ xp_reset)) {
596: xp_reset = val;
1.1.1.14 root 597: putlog(1, "XP Reset %u", xp_reset);
1.1.1.12 root 598: auto mpu64180 = GetMPU64180Device();
599: mpu64180->ChangeRESET(xp_reset);
1.1 root 600: }
601: return;
1.1.1.14 root 602: default:
603: VMPANIC("corrupted pc=%u", pc);
1.1 root 604: }
605: }
606:
1.1.1.12 root 607: // とりあえず、XP からここまではエッジトリガーで、
608: // ここから割り込みコントローラへはレベルトリガーとしておく。
609:
610: // XP からの割り込み (High)
611: void
612: PIO0Device::InterruptXPHigh()
613: {
614: intreq[INT_H] = true;
615: ChangeInterrupt();
616: }
617:
618:
619: // XP からの割り込み (Low)
620: void
621: PIO0Device::InterruptXPLow()
622: {
623: intreq[INT_L] = true;
624: ChangeInterrupt();
625: }
626:
627: // 割り込み状態を変更。
628: // intreq[], inten[] の変更で呼ぶこと。
629: void
630: PIO0Device::ChangeInterrupt()
631: {
632: bool val;
633:
634: val = (inten[INT_H] && intreq[INT_H]);
635: interrupt->ChangeINT(DEVICE_XPINT_HIGH, val);
636:
637: val = (inten[INT_L] && intreq[INT_L]);
638: interrupt->ChangeINT(DEVICE_XPINT_LOW, val);
639: }
640:
1.1 root 641:
642: //
643: // LUNA PIO1
644: //
645: // 仕様は 0x4d000000 から 4バイトだが、
1.1.1.12 root 646: // LUNA-I では 0x4c000000 から 0x4fffffff まで 4バイト単位でミラーが見える。
647: // LUNA-88K では 0x4c000000 から 0x4dffffff までが
648: // (こちらはロングワード配置なので) 16バイト単位のミラーに見える。
1.1 root 649:
650: // コンストラクタ
651: PIO1Device::PIO1Device()
1.1.1.12 root 652: : inherited(OBJ_PIO1)
1.1 root 653: {
654: }
655:
656: // デストラクタ
657: PIO1Device::~PIO1Device()
658: {
1.1.1.12 root 659: }
660:
661: // 初期化
662: bool
663: PIO1Device::Init()
664: {
665: lcd = GetLCDDevice();
666: mpu64180 = GetMPU64180Device();
667: powerdev = GetPowerDevice();
668:
669: return true;
1.1 root 670: }
671:
1.1.1.4 root 672: // リセット
673: void
1.1.1.10 root 674: PIO1Device::ResetHard(bool poweron)
1.1.1.4 root 675: {
1.1.1.10 root 676: inherited::ResetHard(poweron);
1.1.1.4 root 677:
1.1.1.14 root 678: // 電源ユニットは POWF* 信号が 'L' になると 1msec 後に電源オフになる。
679: // 正確には「1msec 以内に 'H' にすれば回避できる」なので、実際に電源が
680: // オフになるのはそれよりもっと十分長いとは思われる。
681: // 8255 リセット時、ポート C の各ピンは入力モードになっているので、
682: // ハイインピーダンス。たぶん電源的にも 'H' になってると想像する。
683: // なので電源オンで POWF* がハイインピーダンスなだけでは電源オフ
684: // タイマーは動作しないんじゃないかな。
685: power = true;
686: powerdev->SetSystemPowerOn(power);
1.1.1.4 root 687: }
688:
1.1.1.13 root 689: busdata
1.1.1.14 root 690: PIO1Device::ReadPort(uint32 offset)
1.1 root 691: {
1.1.1.14 root 692: busdata data;
1.1 root 693:
1.1.1.6 root 694: switch (offset) {
1.1 root 695: case 0:
696: // PIO1 PortA: LCD データ
1.1.1.13 root 697: data = lcd->Read();
698: break;
1.1 root 699:
700: case 1:
701: // PIO1 PortB: 無効
1.1.1.13 root 702: data = 0xff;
703: break;
1.1 root 704:
705: case 2:
706: // PortC
1.1.1.12 root 707: data = lcd->Get();
1.1 root 708: data |= xp_intreq ? 0 : 0x02;
709: // 残りのビットは %1 だろうか?
710: data |= 0x0d;
1.1.1.14 root 711: putlog(1, "PortC -> $%02x", data.Data());
1.1.1.13 root 712: break;
1.1 root 713:
714: case 3:
715: data = ReadCtrl();
1.1.1.14 root 716: putlog(1, "Ctrl -> $%02x", data.Data());
1.1.1.13 root 717: break;
1.1 root 718:
719: default:
1.1.1.14 root 720: VMPANIC("corrupted offset=%u", offset);
1.1 root 721: }
1.1.1.13 root 722:
723: // XXX wait?
1.1.1.14 root 724: data |= BusData::Size1;
1.1.1.13 root 725: return data;
1.1 root 726: }
727:
1.1.1.13 root 728: busdata
1.1.1.14 root 729: PIO1Device::WritePort(uint32 offset, uint32 data)
1.1 root 730: {
1.1.1.6 root 731: switch (offset) {
1.1 root 732: case 0: // PIO1 PortA: LCD データ
1.1.1.12 root 733: lcd->Write(data);
1.1.1.13 root 734: break;
1.1 root 735:
1.1.1.12 root 736: case 1: // PIO1 PortB: XP の INT0 をアサート
737: // データ不問でアサートする。
738: putlog(1, "Assert XP INT0");
739: mpu64180->AssertINT0();
1.1.1.13 root 740: break;
1.1 root 741:
742: case 2: // PIO1 PortC: LCD/パワーオフ制御
743: for (int i = 0; i < 8; i++) {
744: SetPC(i, data & 1);
745: data >>= 1;
746: }
1.1.1.13 root 747: break;
1.1 root 748:
749: case 3: // コントロール
750: WriteCtrl(data);
1.1.1.13 root 751: break;
1.1 root 752:
753: default:
1.1.1.14 root 754: VMPANIC("corrupted offset=%u", offset);
1.1 root 755: }
1.1.1.13 root 756:
757: // XXX wait?
1.1.1.14 root 758: busdata r = BusData::Size1;
759: return r;
1.1 root 760: }
761:
1.1.1.13 root 762: busdata
1.1.1.14 root 763: PIO1Device::PeekPort(uint32 offset)
1.1 root 764: {
1.1.1.6 root 765: switch (offset) {
1.1 root 766: case 0: // PIO1 PortA LCD データ
1.1.1.12 root 767: return lcd->Peek();
1.1 root 768:
769: case 1: // PIO1 PortB 無効
770: return 0xff;
771:
772: case 2: // PIO1 PortC
1.1.1.12 root 773: return GetPC();
1.1 root 774:
775: case 3:
776: return ReadCtrl();
777:
778: default:
1.1.1.12 root 779: return 0xff;
1.1 root 780: }
781: }
782:
1.1.1.12 root 783: // PIO0 の下請け。
784: void
785: PIO1Device::MonitorUpdatePIO1(TextScreen& screen, int y)
786: {
787: screen.Puts(0, y++, "PIO1 (BaseAddr: $4d000000)");
788:
789: // 共通部分
790: y = MonitorUpdateCommon(screen, y++);
791:
792: // PIO1 固有部
793: screen.Print(1, y++, "PortA(LCDDATA)=$%02x", lcd->Peek());
794: screen.Print(1, y++, "PortB(NotConn)=$%02x", 0xff);
795: uint32 pc = GetPC();
796: screen.Print(1, y, "PortC(LCD etc)=$%02x:", pc);
797: static const char * const pcstr[] = {
798: "LCD E", "LCD RS", "LCD RD", "!PWOFF",
799: "------", "------", "!XPINT", "------",
800: };
801: for (int i = 0; i < 8; i++) {
802: screen.Puts(21 + i * 7, y, TA::OnOff(pc & (1U << (7 - i))), pcstr[i]);
803: }
804: }
805:
806: uint32
807: PIO1Device::GetPC() const
808: {
809: uint32 data;
810:
811: data = lcd->Get();
812: data |= xp_intreq ? 0 : 0x02;
813: data |= power ? 0x10 : 0;
814: // 残りのビットは %1 だろうか?
815: data |= 0x0d;
816:
817: return data;
818: }
819:
1.1 root 820: void
1.1.1.14 root 821: PIO1Device::SetPC(uint pc, uint val)
1.1 root 822: {
823: switch (pc) {
824: case 0:
825: case 1:
826: case 2:
827: case 3:
828: // PortC の下半分は入力ポートとして使われることを想定して
829: // いるので、ここへの書き込みは起きないだろうし、無視する。
830: return;
831:
832: case 4:
1.1.1.14 root 833: // 8255 はモード変更 (WriteCtrl) をするとポート C を 'L' にするが、
834: // PC4 (POWF*) が 'L' だと電源オフ指示なので、1msec 以内に
835: // ソフトウェアでこれをキャンセルしないといけない。
836: // どうしてこうなった…。
1.1 root 837: power = val;
838: if (power) {
839: // 電源オフ取り消し
1.1.1.11 root 840: putlog(1, "Power-off canceled");
1.1.1.12 root 841: powerdev->SetSystemPowerOn(true);
1.1 root 842: } else {
843: // 1msec 後に電源オフ
1.1.1.11 root 844: putlog(1, "Power-off scheduled");
1.1.1.12 root 845: powerdev->SetSystemPowerOn(false);
1.1 root 846: }
847: return;
848: case 5:
1.1.1.12 root 849: lcd->SetRW(val);
1.1 root 850: return;
851: case 6:
1.1.1.12 root 852: lcd->SetRS(val);
1.1 root 853: return;
854: case 7:
1.1.1.12 root 855: lcd->SetE(val);
1.1 root 856: return;
857:
858: default:
1.1.1.14 root 859: VMPANIC("corrupted pc=%u", pc);
1.1 root 860: }
861: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.