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