|
|
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: interrupt = GetInterruptDevice();
349: pio1 = GetPIO1Device();
350:
1.1 root 351: return true;
352: }
353:
1.1.1.12 root 354: // リセット
355: void
356: PIO0Device::ResetHard(bool poweron)
357: {
358: auto dipswdev = GetDipswDevice();
359:
360: // XXX 本当は XP から割り込みが上がったタイミングとからしいけど、
361: // XP が出来るまでは当面リセットでラッチにしておく。
362: for (int i = 0; i < 8; i++) {
363: dipsw1[i] = dipswdev->Get(i);
364: dipsw2[i] = dipswdev->Get(i + 8);
365: }
366:
367: // XXX どうなる?
368: for (int i = 0; i < intreq.size(); i++) {
369: intreq[i] = false;
370: inten[i] = false;
371: }
372: }
1.1.1.7 root 373:
1.1.1.13 root 374: busdata
1.1.1.14 root 375: PIO0Device::ReadPort(uint32 offset)
1.1 root 376: {
1.1.1.14 root 377: busdata data;
1.1 root 378:
1.1.1.6 root 379: switch (offset) {
1.1 root 380: case 0:
381: // PortA
1.1.1.11 root 382: data = GetPA();
1.1.1.12 root 383:
384: // 割り込み要求(High)をクリア
385: intreq[INT_H] = false;
386: ChangeInterrupt();
387:
1.1.1.14 root 388: putlog(1, "DIP-SW1 -> $%02x", data.Data());
1.1.1.13 root 389: break;
1.1 root 390:
391: case 1:
392: // PortB
1.1.1.11 root 393: data = GetPB();
1.1.1.12 root 394:
395: // 割り込み要求(Low)をクリア
396: intreq[INT_L] = false;
397: ChangeInterrupt();
398:
1.1.1.14 root 399: putlog(1, "DIP-SW2 -> $%02x", data.Data());
1.1.1.13 root 400: break;
1.1 root 401:
402: case 2:
403: // PortC
404: data = GetPC();
1.1.1.14 root 405: putlog(1, "PortC -> $%02x", data.Data());
1.1.1.13 root 406: break;
1.1 root 407:
408: case 3:
409: data = ReadCtrl();
1.1.1.14 root 410: putlog(1, "Ctrl -> $%02x", data.Data());
1.1.1.13 root 411: break;
1.1 root 412:
413: default:
1.1.1.14 root 414: VMPANIC("corrupted offset=%u", offset);
1.1 root 415: }
1.1.1.13 root 416:
417: // XXX wait?
1.1.1.14 root 418: data |= BusData::Size1;
1.1.1.13 root 419: return data;
1.1 root 420: }
421:
1.1.1.13 root 422: busdata
1.1.1.14 root 423: PIO0Device::WritePort(uint32 offset, uint32 data)
1.1 root 424: {
1.1.1.6 root 425: switch (offset) {
1.1 root 426: case 0: // PIO0 PortA: DIPSW1 (入力のみ)
427: case 1: // PIO0 PortB: DIPSW2 (入力のみ)
1.1.1.13 root 428: break;
1.1 root 429:
430: case 2: // PIO0 PortC: ホスト割り込み制御
431: for (int i = 0; i < 8; i++) {
432: SetPC(i, data & 1);
433: data >>= 1;
434: }
1.1.1.13 root 435: break;
1.1 root 436:
437: case 3: // コントロール
438: WriteCtrl(data);
1.1.1.13 root 439: break;
1.1 root 440:
441: default:
1.1.1.14 root 442: VMPANIC("corrupted offset=%u", offset);
1.1 root 443: }
1.1.1.13 root 444:
445: // XXX wait?
1.1.1.14 root 446: busdata r = BusData::Size1;
447: return r;
1.1 root 448: }
449:
1.1.1.13 root 450: busdata
1.1.1.14 root 451: PIO0Device::PeekPort(uint32 offset)
1.1 root 452: {
1.1.1.6 root 453: switch (offset) {
1.1 root 454: case 0:
455: return GetPA();
456:
457: case 1:
458: return GetPB();
459:
460: case 2:
461: return GetPC();
462:
463: case 3:
464: return ReadCtrl();
465:
466: default:
1.1.1.12 root 467: return 0xff;
1.1 root 468: }
469: }
470:
1.1.1.12 root 471: // PIO0 が PIO0/PIO1 のモニタ両方を担当する。
1.1.1.3 root 472: void
1.1.1.8 root 473: PIO0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 474: {
475: int y;
476:
1.1.1.8 root 477: screen.Clear();
1.1.1.2 root 478:
1.1.1.12 root 479: // PIO0
480: screen.Puts(0, 0, "PIO0 (BaseAddr: $49000000)");
481: y = MonitorUpdateCommon(screen, 1);
482:
483: // PIO0 固有部
484: uint32 pa = GetPA();
485: uint32 pb = GetPB();
486: screen.Print(1, y, "PortA(DIP-SW1)=$%02x:", pa);
487: screen.Print(1, y + 1, "PortB(DIP-SW2)=$%02x:", pb);
488: for (int i = 0; i < 8; i++) {
489: // この図は bit7..0 をこの順で表示するので bitpos の向きは固定。
490: int bitpos = 7 - i;
491: // DIPSW の物理位置 #1 をバイトの下にするか上にするかが機種によって
492: // 違う。どうして…。
493: int label = (msb_first ? i : bitpos) + 1;
494:
495: bool d1 = (pa & (1U << bitpos));
496: bool d2 = (pb & (1U << bitpos));
1.1.1.14 root 497: screen.Print(21 + i * 7, y, TA::OnOff(d1), "DIP1-%u", label);
498: screen.Print(21 + i * 7, y + 1, TA::OnOff(d2), "DIP2-%u", label);
1.1.1.12 root 499: }
500: y += 2;
501:
502: uint32 pc = GetPC();
503: screen.Print(1, y, "PortC(XP etc.)=$%02x:", pc);
504: static const char * const pcstr[] = {
505: "XP RST", "PARITY", "------", "INT5EN",
506: "INT5RQ", "INT1EN", "------", "INT1RQ",
507: };
508: for (int i = 0; i < 8; i++) {
509: screen.Puts(21 + i * 7, y, TA::OnOff(pc & (1U << (7 - i))), pcstr[i]);
510: }
511: y++;
512:
513: // PIO1 移譲
514: y++;
515: pio1->MonitorUpdatePIO1(screen, y);
1.1.1.2 root 516: }
517:
1.1 root 518: // PortA (DIP-SW 1) 読み込み
519: uint32
520: PIO0Device::GetPA() const
521: {
522: uint32 data = 0;
523: for (int i = 0; i < 8; i++) {
524: data |= ((int)dipsw1[i]) << i;
525: }
1.1.1.9 root 526: if (msb_first) {
1.1.1.16! root 527: data = bitrev8(data);
1.1.1.9 root 528: }
1.1 root 529: return data & 0xff;
530: }
531:
532: // PortB (DIP-SW 2) 読み込み
533: uint32
534: PIO0Device::GetPB() const
535: {
536: uint32 data = 0;
537: for (int i = 0; i < 8; i++) {
538: data |= ((int)dipsw2[i]) << i;
539: }
1.1.1.9 root 540: if (msb_first) {
1.1.1.16! root 541: data = bitrev8(data);
1.1.1.9 root 542: }
1.1 root 543: return data & 0xff;
544: }
545:
546: // PortC 読み込み
547: uint32
548: PIO0Device::GetPC() const
549: {
550: uint32 data;
551:
552: data = 0x00 // XXX 空きビットは何が読めるか?
1.1.1.12 root 553: | (intreq[INT_L] ? 0x01 : 0)
554: | (inten[INT_L] ? 0x04 : 0)
555: | (intreq[INT_H] ? 0x08 : 0)
556: | (inten[INT_H] ? 0x10 : 0)
557: | (parity ? 0x40 : 0)
558: | (xp_reset ? 0x80 : 0);
1.1 root 559: return data;
560: }
561:
562: // PortC 書き込み
563: void
1.1.1.14 root 564: PIO0Device::SetPC(uint pc, uint val)
1.1 root 565: {
566: switch (pc) {
567: case 0:
1.1.1.12 root 568: // INT1 割り込み要求 (Read Only)
1.1 root 569: return;
570: case 1:
571: // Not Connected.
572: return;
573: case 2:
1.1.1.12 root 574: inten[INT_L] = val;
575: ChangeInterrupt();
1.1 root 576: return;
577: case 3:
1.1.1.12 root 578: // INT5 割り込み要求 (Read Only)
1.1 root 579: return;
580: case 4:
1.1.1.12 root 581: inten[INT_H] = val;
582: ChangeInterrupt();
1.1 root 583: return;
584: case 5:
585: // Not Connected.
586: return;
587: case 6:
588: // パリティ有効/無効
589: // 使わないので無視するが読み返しのために覚えておく
590: parity = val;
591: return;
592: case 7:
593: // XP リセット
594: if ((val ^ xp_reset)) {
595: xp_reset = val;
1.1.1.14 root 596: putlog(1, "XP Reset %u", xp_reset);
1.1.1.12 root 597: auto mpu64180 = GetMPU64180Device();
598: mpu64180->ChangeRESET(xp_reset);
1.1 root 599: }
600: return;
1.1.1.14 root 601: default:
602: VMPANIC("corrupted pc=%u", pc);
1.1 root 603: }
604: }
605:
1.1.1.12 root 606: // とりあえず、XP からここまではエッジトリガーで、
607: // ここから割り込みコントローラへはレベルトリガーとしておく。
608:
609: // XP からの割り込み (High)
610: void
611: PIO0Device::InterruptXPHigh()
612: {
613: intreq[INT_H] = true;
614: ChangeInterrupt();
615: }
616:
617:
618: // XP からの割り込み (Low)
619: void
620: PIO0Device::InterruptXPLow()
621: {
622: intreq[INT_L] = true;
623: ChangeInterrupt();
624: }
625:
626: // 割り込み状態を変更。
627: // intreq[], inten[] の変更で呼ぶこと。
628: void
629: PIO0Device::ChangeInterrupt()
630: {
631: bool val;
632:
633: val = (inten[INT_H] && intreq[INT_H]);
634: interrupt->ChangeINT(DEVICE_XPINT_HIGH, val);
635:
636: val = (inten[INT_L] && intreq[INT_L]);
637: interrupt->ChangeINT(DEVICE_XPINT_LOW, val);
638: }
639:
1.1 root 640:
641: //
642: // LUNA PIO1
643: //
644: // 仕様は 0x4d000000 から 4バイトだが、
1.1.1.12 root 645: // LUNA-I では 0x4c000000 から 0x4fffffff まで 4バイト単位でミラーが見える。
646: // LUNA-88K では 0x4c000000 から 0x4dffffff までが
647: // (こちらはロングワード配置なので) 16バイト単位のミラーに見える。
1.1 root 648:
649: // コンストラクタ
650: PIO1Device::PIO1Device()
1.1.1.12 root 651: : inherited(OBJ_PIO1)
1.1 root 652: {
653: }
654:
655: // デストラクタ
656: PIO1Device::~PIO1Device()
657: {
1.1.1.12 root 658: }
659:
660: // 初期化
661: bool
662: PIO1Device::Init()
663: {
664: lcd = GetLCDDevice();
665: mpu64180 = GetMPU64180Device();
666: powerdev = GetPowerDevice();
667:
668: return true;
1.1 root 669: }
670:
1.1.1.4 root 671: // リセット
672: void
1.1.1.10 root 673: PIO1Device::ResetHard(bool poweron)
1.1.1.4 root 674: {
1.1.1.10 root 675: inherited::ResetHard(poweron);
1.1.1.4 root 676:
1.1.1.14 root 677: // 電源ユニットは POWF* 信号が 'L' になると 1msec 後に電源オフになる。
678: // 正確には「1msec 以内に 'H' にすれば回避できる」なので、実際に電源が
679: // オフになるのはそれよりもっと十分長いとは思われる。
680: // 8255 リセット時、ポート C の各ピンは入力モードになっているので、
681: // ハイインピーダンス。たぶん電源的にも 'H' になってると想像する。
682: // なので電源オンで POWF* がハイインピーダンスなだけでは電源オフ
683: // タイマーは動作しないんじゃないかな。
684: power = true;
685: powerdev->SetSystemPowerOn(power);
1.1.1.4 root 686: }
687:
1.1.1.13 root 688: busdata
1.1.1.14 root 689: PIO1Device::ReadPort(uint32 offset)
1.1 root 690: {
1.1.1.14 root 691: busdata data;
1.1 root 692:
1.1.1.6 root 693: switch (offset) {
1.1 root 694: case 0:
695: // PIO1 PortA: LCD データ
1.1.1.13 root 696: data = lcd->Read();
697: break;
1.1 root 698:
699: case 1:
700: // PIO1 PortB: 無効
1.1.1.13 root 701: data = 0xff;
702: break;
1.1 root 703:
704: case 2:
705: // PortC
1.1.1.12 root 706: data = lcd->Get();
1.1 root 707: data |= xp_intreq ? 0 : 0x02;
708: // 残りのビットは %1 だろうか?
709: data |= 0x0d;
1.1.1.14 root 710: putlog(1, "PortC -> $%02x", data.Data());
1.1.1.13 root 711: break;
1.1 root 712:
713: case 3:
714: data = ReadCtrl();
1.1.1.14 root 715: putlog(1, "Ctrl -> $%02x", data.Data());
1.1.1.13 root 716: break;
1.1 root 717:
718: default:
1.1.1.14 root 719: VMPANIC("corrupted offset=%u", offset);
1.1 root 720: }
1.1.1.13 root 721:
722: // XXX wait?
1.1.1.14 root 723: data |= BusData::Size1;
1.1.1.13 root 724: return data;
1.1 root 725: }
726:
1.1.1.13 root 727: busdata
1.1.1.14 root 728: PIO1Device::WritePort(uint32 offset, uint32 data)
1.1 root 729: {
1.1.1.6 root 730: switch (offset) {
1.1 root 731: case 0: // PIO1 PortA: LCD データ
1.1.1.12 root 732: lcd->Write(data);
1.1.1.13 root 733: break;
1.1 root 734:
1.1.1.12 root 735: case 1: // PIO1 PortB: XP の INT0 をアサート
736: // データ不問でアサートする。
737: putlog(1, "Assert XP INT0");
738: mpu64180->AssertINT0();
1.1.1.13 root 739: break;
1.1 root 740:
741: case 2: // PIO1 PortC: LCD/パワーオフ制御
742: for (int i = 0; i < 8; i++) {
743: SetPC(i, data & 1);
744: data >>= 1;
745: }
1.1.1.13 root 746: break;
1.1 root 747:
748: case 3: // コントロール
749: WriteCtrl(data);
1.1.1.13 root 750: break;
1.1 root 751:
752: default:
1.1.1.14 root 753: VMPANIC("corrupted offset=%u", offset);
1.1 root 754: }
1.1.1.13 root 755:
756: // XXX wait?
1.1.1.14 root 757: busdata r = BusData::Size1;
758: return r;
1.1 root 759: }
760:
1.1.1.13 root 761: busdata
1.1.1.14 root 762: PIO1Device::PeekPort(uint32 offset)
1.1 root 763: {
1.1.1.6 root 764: switch (offset) {
1.1 root 765: case 0: // PIO1 PortA LCD データ
1.1.1.12 root 766: return lcd->Peek();
1.1 root 767:
768: case 1: // PIO1 PortB 無効
769: return 0xff;
770:
771: case 2: // PIO1 PortC
1.1.1.12 root 772: return GetPC();
1.1 root 773:
774: case 3:
775: return ReadCtrl();
776:
777: default:
1.1.1.12 root 778: return 0xff;
1.1 root 779: }
780: }
781:
1.1.1.12 root 782: // PIO0 の下請け。
783: void
784: PIO1Device::MonitorUpdatePIO1(TextScreen& screen, int y)
785: {
786: screen.Puts(0, y++, "PIO1 (BaseAddr: $4d000000)");
787:
788: // 共通部分
789: y = MonitorUpdateCommon(screen, y++);
790:
791: // PIO1 固有部
792: screen.Print(1, y++, "PortA(LCDDATA)=$%02x", lcd->Peek());
793: screen.Print(1, y++, "PortB(NotConn)=$%02x", 0xff);
794: uint32 pc = GetPC();
795: screen.Print(1, y, "PortC(LCD etc)=$%02x:", pc);
796: static const char * const pcstr[] = {
797: "LCD E", "LCD RS", "LCD RD", "!PWOFF",
798: "------", "------", "!XPINT", "------",
799: };
800: for (int i = 0; i < 8; i++) {
801: screen.Puts(21 + i * 7, y, TA::OnOff(pc & (1U << (7 - i))), pcstr[i]);
802: }
803: }
804:
805: uint32
806: PIO1Device::GetPC() const
807: {
808: uint32 data;
809:
810: data = lcd->Get();
811: data |= xp_intreq ? 0 : 0x02;
812: data |= power ? 0x10 : 0;
813: // 残りのビットは %1 だろうか?
814: data |= 0x0d;
815:
816: return data;
817: }
818:
1.1 root 819: void
1.1.1.14 root 820: PIO1Device::SetPC(uint pc, uint val)
1.1 root 821: {
822: switch (pc) {
823: case 0:
824: case 1:
825: case 2:
826: case 3:
827: // PortC の下半分は入力ポートとして使われることを想定して
828: // いるので、ここへの書き込みは起きないだろうし、無視する。
829: return;
830:
831: case 4:
1.1.1.14 root 832: // 8255 はモード変更 (WriteCtrl) をするとポート C を 'L' にするが、
833: // PC4 (POWF*) が 'L' だと電源オフ指示なので、1msec 以内に
834: // ソフトウェアでこれをキャンセルしないといけない。
835: // どうしてこうなった…。
1.1 root 836: power = val;
837: if (power) {
838: // 電源オフ取り消し
1.1.1.11 root 839: putlog(1, "Power-off canceled");
1.1.1.12 root 840: powerdev->SetSystemPowerOn(true);
1.1 root 841: } else {
842: // 1msec 後に電源オフ
1.1.1.11 root 843: putlog(1, "Power-off scheduled");
1.1.1.12 root 844: powerdev->SetSystemPowerOn(false);
1.1 root 845: }
846: return;
847: case 5:
1.1.1.12 root 848: lcd->SetRW(val);
1.1 root 849: return;
850: case 6:
1.1.1.12 root 851: lcd->SetRS(val);
1.1 root 852: return;
853: case 7:
1.1.1.12 root 854: lcd->SetE(val);
1.1 root 855: return;
856:
857: default:
1.1.1.14 root 858: VMPANIC("corrupted pc=%u", pc);
1.1 root 859: }
860: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.