|
|
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.