|
|
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:
7: #include "pio.h"
1.1.1.2 root 8: #include "config.h"
1.1 root 9: #include "lcd.h"
1.1.1.3 root 10: #include "mainapp.h"
1.1 root 11: #include "scheduler.h"
12:
13: // IODevice
14: // |
15: // v
16: // i8255Device (8255 としての共通部分)
17: // |
18: // +----------+----------+
19: // v v v
20: // PPIDevice PIO0Device PIO1Device
21: // (X68030) (LUNA) (LUNA)
22:
1.1.1.6 root 23: std::unique_ptr<PPIDevice> gPPI;
1.1 root 24: std::unique_ptr<PIO0Device> gPIO0;
25: std::unique_ptr<PIO1Device> gPIO1;
26:
27: //
28: // i8255
29: //
30:
31: // コンストラクタ
1.1.1.8 ! root 32: i8255Device::i8255Device(const std::string& objname_)
! 33: : inherited(objname_)
1.1 root 34: {
35: }
36:
37: // デストラクタ
38: i8255Device::~i8255Device()
39: {
40: }
41:
1.1.1.4 root 42: // リセット
43: void
44: i8255Device::ResetHard()
45: {
46: // clears the control register
47: // and place ports A, B, and C in input mode.
48: // The input latches in ports A, B, and C are not cleared.
49:
50: ctrl = 0b10011011;
51: }
52:
1.1 root 53: // コントロールポートへの書き込み。
54: void
55: i8255Device::WriteCtrl(uint32 data)
56: {
57: if ((data & 0x80)) {
58: // 最上位が立っていればモード設定
59: ctrl = data;
60: putlog(1,
61: "モード設定 groupA=%d groupB=%d portA=%s portB=%s portC=%s/%s",
62: GetGroupAMode(), GetGroupBMode(),
63: PortADir() == DIR_IN ? "IN" : "OUT",
64: PortBDir() == DIR_IN ? "IN" : "OUT",
65: PortCHDir() == DIR_IN ? "IN" : "OUT",
66: PortCLDir() == DIR_IN ? "IN" : "OUT");
67:
68: // モード設定すると PC はゼロクリアされる
69: for (int pc = 0; pc < 8; pc++) {
70: SetPC(pc, 0);
71: }
72: } else {
73: // portC 出力
74: //
75: // 0 x x x P P P V
76: // | | | +-- 書き込むビットデータ
77: // +--+--+----- 書き込むビット位置
78:
79: int pc = (data >> 1) & 7;
80: int val = data & 1;
81: SetPC(pc, val);
82: }
83: }
84:
85: void
86: i8255Device::SetPC(int pc, int data)
87: {
88: // 継承側で用意すること。ここには来ない
89: PANIC("not impl");
90: }
91:
92: //
93: // X68k PPI
94: //
95:
96: // コンストラクタ
97: PPIDevice::PPIDevice()
1.1.1.8 ! root 98: : inherited("PPI")
1.1 root 99: {
100: devaddr = baseaddr;
101: devlen = 0x2000;
102: }
103:
104: // デストラクタ
105: PPIDevice::~PPIDevice()
106: {
107: }
108:
109: uint64
1.1.1.6 root 110: PPIDevice::Read(uint32 offset)
1.1 root 111: {
1.1.1.4 root 112: gMPU->AddCycle(19); // InsideOut p.135
113:
1.1.1.6 root 114: switch (offset) {
1.1 root 115: case 0:
116: case 1:
117: return 0xff;
118: case 2:
1.1.1.6 root 119: putlog(0, "$e9a005 PortC 未実装読み込み");
1.1.1.5 root 120: return 0xff;
1.1 root 121: case 3:
1.1.1.6 root 122: PANIC("PPI $e9a007 未サポート読み込み");
1.1 root 123: break;
124: default:
125: __unreachable();
126: }
127: PANIC("not impl");
128: }
129:
130: uint64
1.1.1.6 root 131: PPIDevice::Write(uint32 offset, uint32 data)
1.1 root 132: {
1.1.1.4 root 133: gMPU->AddCycle(19); // InsideOut p.135
134:
1.1.1.6 root 135: switch (offset) {
1.1 root 136: case 0:
137: case 1:
138: break;
139: case 2:
1.1.1.6 root 140: putlog(0, "$e9a005 未実装書き込み $%02X (無視)", data);
1.1 root 141: break;
142: case 3:
143: if (data != 0x92) {
1.1.1.6 root 144: PANIC("PPI $e9a007 未実装書き込み $%02X", data);
1.1 root 145: } else {
1.1.1.6 root 146: putlog(0, "$e9a007 未実装書き込み $%02x (無視)", data);
1.1 root 147: }
148: break;
149: default:
150: __unreachable();
151: }
152: return 0;
153: }
154:
155: uint64
1.1.1.6 root 156: PPIDevice::Peek(uint32 offset)
1.1 root 157: {
158: // XXX
159: return 0xff;
160: }
161:
162: //
163: // LUNA PIO0
164: //
165: // 仕様は 0x49000000 から 4バイトだが、
166: // 0x48000000 から 0x4c000000 の手前まで 4バイト単位でミラーが見える。
167: //
168: // LUNA の DIP-SW は #1, #2 にそれぞれ8個、計16個ある。
169: // DIP-SW #1, #2 が設定ファイルの luna_dipsw_{1,2} に対応する。
170: // luna_dipsw_{1,2} はいずれも "0"/"1" を8つ並べた文字列であり、
171: // 先頭が本体表記でいう 1番、末尾側が本体表記でいう 8番に対応する。
172: // 変数は dipsw{1,2}[0..7] に対応。
173: // 設定ファイルと変数の値は %0 が down を表し、%1 が up を表す。
174: //
1.1.1.3 root 175: // LUNA-1:
1.1 root 176: // #1-1 up なら UNIX をロードして移行。down なら ROM モニタで起動。
177: // #1-2 up ならディスプレイコンソール。down ならシリアルコンソール。
178: // #1-3 up - color display, down - force to have monochrome display
179: // #1-4 up - no write verification,
180: // down - verification on every harddisk write operation
181: // #1-5 up - OS is UniOS-U (SystemV/COFF),
182: // down - OS is UniOS (4.3BSD/a.out OMAGIC)
183: // #1-6 down - force monochrome display?
184: // #1-7 up - boot from local device, down - boot from network
185: // #1-8 up - normal boot, down - start diagnostics と書いてあるが
186: // down にすると画面真っ暗で詳細不明。
187: //
188: // #2-x すべて up にすると /boot が自動的にカーネルを起動。一つでも down が
189: // あれば /boot がプロンプトで停止。これは ROM ではなく NetBSD のブート
190: // ローダの話。
191: // どこか由来のソースコードらしいがたぶんビット演算を間違えている。
1.1.1.3 root 192: //
193: // LUNA88K:
194: // #1-1 up なら ROM モニタで停止、down ならマルチユーザブート。
195: // OpenBSD カーネルも up なら UserKernelConfig で止まる模様?。
196: // #1-2 up なら外付けシリアルコンソール、down なら内蔵ビットマップ。
197: // #1-3..#1-8 は予約。
198: // #2-x はユーザ(?)
1.1 root 199:
200: // コンストラクタ
201: PIO0Device::PIO0Device()
1.1.1.8 ! root 202: : inherited("PIO0")
1.1 root 203: {
204: devaddr = 0x49000000;
205: devlen = 4;
1.1.1.2 root 206:
1.1.1.3 root 207: // 機種固有パラメータ
208:
209: // LUNA-1 と LUNA88K で使いやすいように初期値を変えておく。
210: switch (gMainApp.GetVMType()) {
211: case VMTYPE_LUNA1:
212: gConfig->SetDefault("luna-dipsw1", "11110111");
213: break;
214: case VMTYPE_LUNA88K:
1.1.1.4 root 215: gConfig->SetDefault("luna-dipsw1", "11111111");
1.1.1.3 root 216: break;
217: default:
218: __unreachable();
219: }
220: // DIP-SW#2 はユーザ定義(?)なので(今の所?)どちらも共通。
221: gConfig->SetDefault("luna-dipsw2", "11111111");
222:
1.1.1.8 ! root 223: monitor.func = (MonitorCallback_t)&PIO0Device::MonitorUpdate;
! 224: monitor.SetSize(22, 11);
! 225: monitor.Regist(ID_MONITOR_PIO0);
1.1 root 226: }
227:
228: // デストラクタ
229: PIO0Device::~PIO0Device()
230: {
231: }
232:
233: bool
234: PIO0Device::Init()
235: {
236: // XXX 本当はラッチのタイミングが違う気もするけど、とりあえずね
237:
1.1.1.2 root 238: const ConfigItem& item1 = gConfig->Find("luna-dipsw1");
1.1 root 239: const std::string& str1 = item1.AsString();
240: if (str1.size() != 8) {
241: item1.Err("must be 8 digits");
242: return false;
243: }
244:
1.1.1.2 root 245: const ConfigItem& item2 = gConfig->Find("luna-dipsw2");
1.1 root 246: const std::string& str2 = item2.AsString();
247: if (str2.size() != 8) {
248: item2.Err("must be 8 digits");
249: return false;
250: }
251: for (int i = 0; i < 8; i++) {
252: dipsw1[i] = (str1[i] != '0');
253: dipsw2[i] = (str2[i] != '0');
254: }
255: return true;
256: }
257:
1.1.1.7 root 258: // XXX PowerOn か ResetHard 未調査
259:
1.1 root 260: uint64
1.1.1.6 root 261: PIO0Device::Read(uint32 offset)
1.1 root 262: {
263: uint32 data;
264:
1.1.1.6 root 265: switch (offset) {
1.1 root 266: case 0:
267: // PortA
268: putlog(1, "DIP-SW 1 読み込み");
269: return GetPA();
270:
271: case 1:
272: // PortB
273: putlog(1, "DIP-SW 2 読み込み");
274: return GetPB();
275:
276: case 2:
277: // PortC
278: data = GetPC();
1.1.1.6 root 279: putlog(1, "PC 読み込み -> $%02x", data);
1.1 root 280: return data;
281:
282: case 3:
283: data = ReadCtrl();
284: putlog(1, "コントロール読み込み -> $%02x", data);
285: return data;
286:
287: default:
288: __unreachable();
289: }
290: }
291:
292: uint64
1.1.1.6 root 293: PIO0Device::Write(uint32 offset, uint32 data)
1.1 root 294: {
1.1.1.6 root 295: switch (offset) {
1.1 root 296: case 0: // PIO0 PortA: DIPSW1 (入力のみ)
297: case 1: // PIO0 PortB: DIPSW2 (入力のみ)
298: return 0;
299:
300: case 2: // PIO0 PortC: ホスト割り込み制御
301: for (int i = 0; i < 8; i++) {
302: SetPC(i, data & 1);
303: data >>= 1;
304: }
305: return 0;
306:
307: case 3: // コントロール
308: WriteCtrl(data);
309: return 0;
310:
311: default:
312: __unreachable();
313: }
314: }
315:
316: uint64
1.1.1.6 root 317: PIO0Device::Peek(uint32 offset)
1.1 root 318: {
1.1.1.6 root 319: switch (offset) {
1.1 root 320: case 0:
321: return GetPA();
322:
323: case 1:
324: return GetPB();
325:
326: case 2:
327: return GetPC();
328:
329: case 3:
330: return ReadCtrl();
331:
332: default:
333: __unreachable();
334: }
335: }
336:
1.1.1.3 root 337: void
1.1.1.8 ! root 338: PIO0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 339: {
340: int y;
341:
1.1.1.8 ! root 342: screen.Clear();
1.1.1.2 root 343:
344: y = 0;
1.1.1.8 ! root 345: screen.Print(0, y++, "PortA(DIPSW1):%c%c%c%c%c%c%c%c",
1.1.1.2 root 346: (dipsw1[0] ? '1' : '0'),
347: (dipsw1[1] ? '1' : '0'),
348: (dipsw1[2] ? '1' : '0'),
349: (dipsw1[3] ? '1' : '0'),
350: (dipsw1[4] ? '1' : '0'),
351: (dipsw1[5] ? '1' : '0'),
352: (dipsw1[6] ? '1' : '0'),
353: (dipsw1[7] ? '1' : '0'));
1.1.1.8 ! root 354: screen.Print(0, y++, "PortB(DIPSW2):%c%c%c%c%c%c%c%c",
1.1.1.2 root 355: (dipsw2[0] ? '1' : '0'),
356: (dipsw2[1] ? '1' : '0'),
357: (dipsw2[2] ? '1' : '0'),
358: (dipsw2[3] ? '1' : '0'),
359: (dipsw2[4] ? '1' : '0'),
360: (dipsw2[5] ? '1' : '0'),
361: (dipsw2[6] ? '1' : '0'),
362: (dipsw2[7] ? '1' : '0'));
1.1.1.8 ! root 363: screen.Puts(0, y++, "PortC");
! 364: screen.Puts(1, y++, TA::OnOff(xp_reset), "b7: XP Reset");
! 365: screen.Puts(1, y++, TA::OnOff(parity), "b6: Parity");
! 366: screen.Puts(1, y++, "b5: ---");
! 367: screen.Puts(1, y++, TA::OnOff(int5en), "b4: Int5 Enable");
! 368: screen.Puts(1, y++, TA::OnOff(int5rq), "b3: Int5 Request");
! 369: screen.Puts(1, y++, TA::OnOff(int1en), "b2: Int1 Enable");
! 370: screen.Puts(1, y++, "b1: ---");
! 371: screen.Puts(1, y++, TA::OnOff(int1rq), "b0: Intq Request");
1.1.1.2 root 372: }
373:
1.1 root 374: // PortA (DIP-SW 1) 読み込み
375: uint32
376: PIO0Device::GetPA() const
377: {
378: uint32 data = 0;
379: for (int i = 0; i < 8; i++) {
380: data |= ((int)dipsw1[i]) << i;
381: }
382: return data & 0xff;
383: }
384:
385: // PortB (DIP-SW 2) 読み込み
386: uint32
387: PIO0Device::GetPB() const
388: {
389: uint32 data = 0;
390: for (int i = 0; i < 8; i++) {
391: data |= ((int)dipsw2[i]) << i;
392: }
393: return data & 0xff;
394: }
395:
396: // PortC 読み込み
397: uint32
398: PIO0Device::GetPC() const
399: {
400: uint32 data;
401:
402: data = 0x00 // XXX 空きビットは何が読めるか?
403: | (int1rq ? 0x01 : 0)
404: | (int1en ? 0x04 : 0)
405: | (int5rq ? 0x08 : 0)
406: | (int5en ? 0x10 : 0)
407: | (parity ? 0x40 : 0)
408: | (xp_reset?0x80 : 0);
409: return data;
410: }
411:
412: // PortC 書き込み
413: void
414: PIO0Device::SetPC(int pc, int val)
415: {
416: switch (pc) {
417: case 0:
418: if ((val ^ int1rq)) {
419: int1rq = val;
420: putlog(0, "INT1割り込み要求 %d (未実装)", int1rq);
421: }
422: return;
423: case 1:
424: // Not Connected.
425: return;
426: case 2:
427: if ((val ^ int1en)) {
428: int1en = val;
429: putlog(0, "INT1割り込み許可 %d (未実装)", int1en);
430: }
431: return;
432: case 3:
433: if ((val ^ int5rq)) {
434: int5rq = val;
435: putlog(0, "INT5割り込み要求 %d (未実装)", int5rq);
436: }
437: return;
438: case 4:
439: if ((val ^ int5en)) {
440: int5en = val;
441: putlog(0, "INT5割り込み許可 %d (未実装)", int5en);
442: }
443: return;
444: case 5:
445: // Not Connected.
446: return;
447: case 6:
448: // パリティ有効/無効
449: // 使わないので無視するが読み返しのために覚えておく
450: parity = val;
451: return;
452: case 7:
453: // XP リセット
454: if ((val ^ xp_reset)) {
455: xp_reset = val;
456: putlog(0, "XPリセット %d (未実装)", xp_reset);
457: }
458: return;
459: }
460: PANIC("invalid pc=%d", pc);
461: }
462:
463:
464: //
465: // LUNA PIO1
466: //
467: // 仕様は 0x4d000000 から 4バイトだが、
468: // 0x4c000000 から 0x50000000 の手前まで 4バイト単位でミラーが見える。
469:
470: // コンストラクタ
471: PIO1Device::PIO1Device()
1.1.1.8 ! root 472: : inherited("PIO1")
1.1 root 473: {
474: devaddr = 0x4d000000;
475: devlen = 4;
476:
477: poffevent.func = (DeviceCallback_t)&PIO1Device::PowerOffCallback;
478: poffevent.SetName("PIO1 Power Off");
479: }
480:
481: // デストラクタ
482: PIO1Device::~PIO1Device()
483: {
484: }
485:
1.1.1.4 root 486: // リセット
487: void
488: PIO1Device::ResetHard()
489: {
490: inherited::ResetHard();
491:
492: poffevent.Stop();
493: }
494:
1.1 root 495: uint64
1.1.1.6 root 496: PIO1Device::Read(uint32 offset)
1.1 root 497: {
498: uint32 data;
499:
1.1.1.6 root 500: switch (offset) {
1.1 root 501: case 0:
502: // PIO1 PortA: LCD データ
503: return gLCD->Read();
504:
505: case 1:
506: // PIO1 PortB: 無効
507: return 0xff;
508:
509: case 2:
510: // PortC
511: data = gLCD->Get();
512: data |= xp_intreq ? 0 : 0x02;
513: // 残りのビットは %1 だろうか?
514: data |= 0x0d;
515: putlog(1, "PC 読み込み -> $%02x", data);
516: return data;
517:
518: case 3:
519: data = ReadCtrl();
520: putlog(1, "コントロール読み込み -> $%02x", data);
521: return data;
522:
523: default:
524: __unreachable();
525: }
526: }
527:
528: uint64
1.1.1.6 root 529: PIO1Device::Write(uint32 offset, uint32 data)
1.1 root 530: {
1.1.1.6 root 531: switch (offset) {
1.1 root 532: case 0: // PIO1 PortA: LCD データ
533: gLCD->Write(data);
534: return 0;
535:
536: case 1: // PIO1 PortB: ローカル割り込み
537: break;
538:
539: case 2: // PIO1 PortC: LCD/パワーオフ制御
540: for (int i = 0; i < 8; i++) {
541: SetPC(i, data & 1);
542: data >>= 1;
543: }
544: return 0;
545:
546: case 3: // コントロール
547: WriteCtrl(data);
548: return 0;
549:
550: default:
551: __unreachable();
552: }
1.1.1.6 root 553: PANIC("$%08X <- $%02X 未サポート書き込み", gMPU->GetPaddr(), data);
1.1 root 554: return 0;
555: }
556:
557: uint64
1.1.1.6 root 558: PIO1Device::Peek(uint32 offset)
1.1 root 559: {
560: uint32 data;
561:
1.1.1.6 root 562: switch (offset) {
1.1 root 563: case 0: // PIO1 PortA LCD データ
564: return gLCD->Peek();
565:
566: case 1: // PIO1 PortB 無効
567: return 0xff;
568:
569: case 2: // PIO1 PortC
570: data = gLCD->Get();
571: data |= xp_intreq ? 0 : 0x02;
572: // 残りのビットは %1 だろうか?
573: data |= 0x0d;
574: return data;
575:
576: case 3:
577: return ReadCtrl();
578:
579: default:
580: __unreachable();
581: }
582: }
583:
584: void
585: PIO1Device::SetPC(int pc, int val)
586: {
587: switch (pc) {
588: case 0:
589: case 1:
590: case 2:
591: case 3:
592: // PortC の下半分は入力ポートとして使われることを想定して
593: // いるので、ここへの書き込みは起きないだろうし、無視する。
594: return;
595:
596: case 4:
597: power = val;
598: if (power) {
599: // 電源オフ取り消し
600: putlog(1, "電源 OFF 取消");
601: poffevent.Stop();
602: } else {
603: // 1msec 後に電源オフ
604: putlog(1, "電源 OFF 指示");
605: poffevent.time = 1_msec;
606: poffevent.Start();
607: }
608: return;
609: case 5:
610: gLCD->SetRW(val);
611: return;
612: case 6:
613: gLCD->SetRS(val);
614: return;
615: case 7:
616: gLCD->SetE(val);
617: return;
618:
619: default:
620: break;
621: }
622: PANIC("PC%d 未実装", pc);
623: }
624:
625: // 電源 OFF イベントのコールバック
626: void
1.1.1.4 root 627: PIO1Device::PowerOffCallback(Event& ev)
1.1 root 628: {
629: putlog(0, "電源 OFF");
630: gScheduler->RequestPowerOff();
631: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.