|
|
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; ! 365: poffevent.name = "Power Off"; ! 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.