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