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