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