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