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