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