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