|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2022 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // NEWS の各種制御ポート(?) ! 9: // ! 10: ! 11: // NWS-1750 の $e100'0000..$e1ff'ffff ! 12: // ! 13: // +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F'0000 ! 14: // e100'0000 |TIC PE ! 15: // e110'0000 | I2D ! 16: // e120'0000 | ASD ! 17: // e130'0000 |L2E POW ! 18: // e140'0000 | ! 19: // e150'0000 | ! 20: // e160'0000 | ! 21: // e170'0000 | ! 22: // e180'0000 | ! 23: // e190'0000 |L2D ! 24: // e1a0'0000 |PD ! 25: // e1b0'0000 | ! 26: // e1c0'0000 |(*) ! 27: // e1d0'0000 | ! 28: // e1e0'0000 | ! 29: // e1f0'0000 | ! 30: // ! 31: // TIC: Timer Interrupt Control ! 32: // PE/PD: Parity Enable/Disable ! 33: // I2D: Lv2 Interrupt Disable ! 34: // ASD: AST Disable ! 35: // L2E/L2D: L2 Cache Enable/Disable ! 36: // POW: Power Control ! 37: // (*): IDROM, DIP-SW, Parity Vector, Interupt Status ! 38: // ! 39: // また、ここに書いてない $e000'0000 ブロックにあるデバイスも一部担当している。 ! 40: // newsio.cpp 冒頭のメモリマップも参照。 ! 41: ! 42: #include "newsctlr.h" ! 43: #include "dipsw.h" ! 44: #include "ethernet.h" ! 45: #include "interrupt.h" ! 46: #include "scheduler.h" ! 47: ! 48: // コンストラクタ ! 49: NewsCtlrDevice::NewsCtlrDevice() ! 50: : inherited(OBJ_NEWSCTLR) ! 51: { ! 52: // ROM のうち固定のもの ! 53: oidrom[0] = 0x0d; // ModelID = NWS-1750 ! 54: ! 55: timer_event.func = ToEventCallback(&NewsCtlrDevice::TimerCallback); ! 56: timer_event.time = 10_msec; ! 57: timer_event.Regist("SystemTimer"); ! 58: } ! 59: ! 60: // デストラクタ ! 61: NewsCtlrDevice::~NewsCtlrDevice() ! 62: { ! 63: } ! 64: ! 65: // 初期化 ! 66: bool ! 67: NewsCtlrDevice::Init() ! 68: { ! 69: if (inherited::Init() == false) { ! 70: return false; ! 71: } ! 72: ! 73: dipsw = GetDipswDevice(); ! 74: ! 75: // ステータス読み出しのためにキャストしたのを持っておく ! 76: interrupt = dynamic_cast<NewsInterrupt*>(GetInterruptDevice()); ! 77: assert(interrupt); ! 78: ! 79: // MAC アドレスを ROM にセット。 ! 80: macaddr_t macaddr; ! 81: if (EthernetDevice::GetConfigMacAddr(&macaddr, false) == false) { ! 82: // エラーメッセージは表示済み ! 83: return false; ! 84: } ! 85: putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str()); ! 86: memcpy(&oidrom[8], &macaddr, sizeof(macaddr)); ! 87: ! 88: return true; ! 89: } ! 90: ! 91: void ! 92: NewsCtlrDevice::ResetHard(bool poweron) ! 93: { ! 94: // たぶん止まるだろう。知らんけど。 ! 95: timer_intr = false; ! 96: timer_enable = false; ! 97: ! 98: // たぶん消すだろう。知らんけど。 ! 99: led = 0; ! 100: ! 101: // たぶん電源オンで即起動? 知らんけど。 ! 102: if (poweron) { ! 103: scheduler->StartEvent(timer_event); ! 104: } ! 105: } ! 106: ! 107: uint64 ! 108: NewsCtlrDevice::Read8(uint32 addr) ! 109: { ! 110: uint64 data = -1; ! 111: ! 112: addr |= 0xc0000000; ! 113: ! 114: if ((addr >> 16) == 0xe1c0) { ! 115: uint idx = (addr >> 8) & 3; ! 116: switch (idx) { ! 117: case 0: // e1c0'00xx ! 118: data = GetIDROM(addr); ! 119: putlog(2, "$%08x.B (IDROM) -> $%02x", addr, (uint32)data); ! 120: break; ! 121: case 2: // e1c0'02xx ! 122: // 割り込みステータス ! 123: data = interrupt->PeekStatus(); ! 124: putlog(1, "$%08x.B (IntStat) -> $%02x", addr, (uint32)data); ! 125: break; ! 126: default: // e1c0'01xx ! 127: // DIP-SW ! 128: data = GetDIPSW(); ! 129: putlog(1, "$%08x.B (DIPSW) -> $%02x", addr, (uint32)data); ! 130: break; ! 131: } ! 132: return data; ! 133: } ! 134: ! 135: VMPANIC("Read8($%08x)", addr); ! 136: return data; ! 137: } ! 138: ! 139: uint64 ! 140: NewsCtlrDevice::Write8(uint32 addr, uint32 data) ! 141: { ! 142: addr |= 0xc0000000; ! 143: ! 144: if (addr == 0xe0c8'0000) { ! 145: // PWS-1560 FDC? ! 146: putlog(0, "FDC <- $%02x (NOT IMPLEMENTED)", data); ! 147: return 0; ! 148: } ! 149: if (addr == 0xe0dc'0000) { ! 150: WriteLED(data); ! 151: return 0; ! 152: } ! 153: if (addr == 0xe100'0000) { ! 154: WriteTimer(data); ! 155: return 0; ! 156: } ! 157: if (addr == 0xe108'0000) { ! 158: // Parity enable? ! 159: putlog(0, "Parity enable? <- $%02x (NOT IMPLEMENTED)", data); ! 160: return 0; ! 161: } ! 162: if (addr == 0xe118'0000) { ! 163: // Level2 Interrupt ? ! 164: putlog(0, "Lv2 Interrupt disable? <- $%02x (NOT IMPLEMENTED)", data); ! 165: return 0; ! 166: } ! 167: if (addr == 0xe128'0000) { ! 168: putlog(0, "AST disable? <- $%02x (NOT IMPLEMENTED)", data); ! 169: return 0; ! 170: } ! 171: if (addr == 0xe130'0000) { ! 172: putlog(0, "L2 cache enable? <- $%02x (NOT IMPLEMENTED)", data); ! 173: return 0; ! 174: } ! 175: if (addr == 0xe138'0000) { ! 176: putlog(0, "Power Control <- $%02x (NOT IMPLEMENTED)", data); ! 177: return 0; ! 178: } ! 179: if (addr == 0xe190'0000) { ! 180: putlog(0, "L2 cache disable? <- $%02x (NOT IMPLEMENTED)", data); ! 181: return 0; ! 182: } ! 183: if (addr == 0xe1a0'0000) { ! 184: putlog(0, "Parity disable? <- $%02x (NOT IMPLEMENTED)", data); ! 185: return 0; ! 186: } ! 187: if (addr == 0xe1c0'0200) { ! 188: // XXX たぶん 0xe1c0'02ff まで全部同じかも ! 189: putlog(0, "Parity Vector? <- $%02x (NOT IMPLEMENTED)", data); ! 190: return 0; ! 191: } ! 192: ! 193: VMPANIC("Write8($%08x) <- $%02x", addr, data); ! 194: return (uint64)-1; ! 195: } ! 196: ! 197: uint64 ! 198: NewsCtlrDevice::Peek8(uint32 addr) ! 199: { ! 200: addr |= 0xc0000000; ! 201: ! 202: if ((addr >> 16) == 0xe1c0) { ! 203: uint idx = (addr >> 8) & 3; ! 204: switch (idx) { ! 205: case 0: // e1c0'00xx ! 206: return GetIDROM(addr); ! 207: case 2: // e1c0'02xx ! 208: return interrupt->PeekStatus(); ! 209: default: // e1c0'01xx ! 210: return GetDIPSW(); ! 211: } ! 212: } ! 213: ! 214: return (uint64)-1; ! 215: } ! 216: ! 217: // IDROM の値を返す。この関数は副作用を起こしてはいけない。 ! 218: uint8 ! 219: NewsCtlrDevice::GetIDROM(uint32 addr) const ! 220: { ! 221: uint32 data; ! 222: ! 223: // $e1c0'00xx はたぶん 256x4bit ROM。 ! 224: // ! 225: // 生データ oidrom[] はバイトで持っておき(つまり128バイト)、 ! 226: // アクセス時に分解する。 ! 227: // 実際に使われているのはこのうち先頭の 16バイト(32ニブル)分のようだ。 ! 228: ! 229: int n = (addr & 0xff) / 2; ! 230: if ((addr & 1) == 0) { ! 231: data = oidrom[n] >> 4; ! 232: } else { ! 233: data = oidrom[n]; ! 234: } ! 235: return data | 0xf0; ! 236: } ! 237: ! 238: // DIPSW の状態を読み出す。この関数は副作用を起こしてはいけない。 ! 239: // SW1 が LSB 側。 ! 240: // オン(true)なら %0、オフ(false)なら %1。 ! 241: uint8 ! 242: NewsCtlrDevice::GetDIPSW() const ! 243: { ! 244: uint8 data = 0; ! 245: ! 246: for (int i = 0; i < 8; i++) { ! 247: if (dipsw->Get(i) == false) { ! 248: data |= 1U << i; ! 249: } ! 250: } ! 251: return data; ! 252: } ! 253: ! 254: // LED 制御ポート書き込み ! 255: void ! 256: NewsCtlrDevice::WriteLED(uint32 data) ! 257: { ! 258: // bit0 が緑 LED、bit1 がオレンジ LED のオンオフらしい。 ! 259: led = data & 0x03; ! 260: putlog(1, "LED <- $%02x", led); ! 261: } ! 262: ! 263: // システムタイマー ! 264: void ! 265: NewsCtlrDevice::WriteTimer(uint32 data) ! 266: { ! 267: switch (data) { ! 268: case 0: ! 269: timer_enable = false; ! 270: timer_intr = false; ! 271: break; ! 272: case 1: ! 273: timer_enable = true; ! 274: break; ! 275: default: ! 276: VMPANIC("Unknown Timer Control $%02x", data); ! 277: break; ! 278: } ! 279: ChangeInterrupt(); ! 280: } ! 281: ! 282: // システムタイマーイベント ! 283: void ! 284: NewsCtlrDevice::TimerCallback(Event& ev) ! 285: { ! 286: timer_intr = true; ! 287: ChangeInterrupt(); ! 288: ! 289: // XXX clock-sync はまた後ほど ! 290: scheduler->RestartEvent(ev); ! 291: } ! 292: ! 293: // 割り込み信号線の状態を変える ! 294: void ! 295: NewsCtlrDevice::ChangeInterrupt() ! 296: { ! 297: interrupt->ChangeINT(this, (bool)(timer_enable && timer_intr)); ! 298: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.