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