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