|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2024 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // Goldfish (Qemu) RTC+Timer (の RTC のほう) ! 9: // ! 10: ! 11: // RTC デバイスのレジスタは次の通り。(QEMU 仕様) ! 12: // ! 13: // +$00.L TIME_LOW RW: ホスト時刻 [nsec] の下位 32 ビット ! 14: // +$04.L TIME_HIGH RW: ホスト時刻 [nsec] の上位 32 ビット ! 15: // ! 16: // TIME_LOW の動作は Timer デバイスと同じだが、こちらはホストの RTC 時刻 ! 17: // (実世界時間) を秒の粒度で返す。つまり time() * 1e9 だと仕様書にはある。 ! 18: // 書き込みも可能 (当然 VM の RTC を書き換える)。 ! 19: // アラームと割り込み機能は一切ないが、レジスタマップは Timer デバイスと ! 20: // 同じものを使うらしい。 ! 21: ! 22: #include "goldfish_rtc.h" ! 23: #include "textscreen.h" ! 24: ! 25: // ! 26: // GFRTC ! 27: // ! 28: ! 29: // コンストラクタ ! 30: GFRTCDevice::GFRTCDevice() ! 31: : inherited() ! 32: { ! 33: } ! 34: ! 35: // デストラクタ ! 36: GFRTCDevice::~GFRTCDevice() ! 37: { ! 38: } ! 39: ! 40: // 初期化 ! 41: bool ! 42: GFRTCDevice::Init() ! 43: { ! 44: if (inherited::Init() == false) { ! 45: return false; ! 46: } ! 47: ! 48: return true; ! 49: } ! 50: ! 51: // リセット ! 52: void ! 53: GFRTCDevice::ResetHard(bool poweron) ! 54: { ! 55: time_nsec = 0; ! 56: } ! 57: ! 58: busdata ! 59: GFRTCDevice::Read32(uint32 addr) ! 60: { ! 61: uint32 offset = addr & 0xfff; ! 62: busdata data; ! 63: ! 64: switch (offset) { ! 65: case GFRTC::TIME_LOW: ! 66: time_nsec = (uint64)MkTime() * 1000'000'000U; ! 67: data = (uint32)time_nsec; ! 68: if (__predict_false(loglevel >= 1)) { ! 69: if (loglevel >= 3) { ! 70: putlogn("TIME_LOW -> $%08x", data.Data()); ! 71: } else { ! 72: putlogn("TIME -> $%08x'%08x", ! 73: (uint32)(time_nsec >> 32), data.Data()); ! 74: } ! 75: } ! 76: break; ! 77: ! 78: case GFRTC::TIME_HIGH: ! 79: data = (uint32)(time_nsec >> 32); ! 80: putlog(3, "TIME_HIGH -> $%08x", data.Data()); ! 81: break; ! 82: ! 83: case GFRTC::INTR_STATUS: ! 84: putlog(2, "Read INTR_STATUS (No function)"); ! 85: data = 0; ! 86: break; ! 87: ! 88: case GFRTC::ALARM_STATUS: ! 89: putlog(2, "Read ALARM_STATUS (No function)"); ! 90: data = 0; ! 91: break; ! 92: ! 93: default: ! 94: putlog(1, "Read unknown $%08x", addr); ! 95: data.SetBusErr(); ! 96: break; ! 97: } ! 98: return data; ! 99: } ! 100: ! 101: busdata ! 102: GFRTCDevice::Write32(uint32 addr, uint32 data) ! 103: { ! 104: uint32 offset = addr & 0xfff; ! 105: busdata r; ! 106: ! 107: switch (offset) { ! 108: case GFRTC::TIME_LOW: ! 109: { ! 110: time_nsec |= data; ! 111: ! 112: if (__predict_false(loglevel >= 1)) { ! 113: if (loglevel >= 2) { ! 114: putlogn("TIME_LOW <- $%08x", (uint32)time_nsec); ! 115: } else { ! 116: putlogn("TIME <- $%08x'%08x", ! 117: (uint32)(time_nsec >> 32), (uint32)time_nsec); ! 118: } ! 119: } ! 120: ! 121: time_t t = time_nsec / 1000'000'000U; ! 122: struct tm tm; ! 123: gmtime_r(&t, &tm); ! 124: SetYear(tm.tm_year + 1900); ! 125: SetMon(tm.tm_mon + 1); ! 126: SetMday(tm.tm_mday); ! 127: SetHour(tm.tm_hour); ! 128: SetMin(tm.tm_min); ! 129: SetSec(tm.tm_sec); ! 130: break; ! 131: } ! 132: ! 133: case GFRTC::TIME_HIGH: ! 134: putlog(2, "TIME_HIGH <- $%08x", data); ! 135: time_nsec = (uint64)data << 32; ! 136: break; ! 137: ! 138: case GFRTC::ALARM_LOW: ! 139: putlog(2, "ALARM_LOW <- $%08x (No function)", data); ! 140: break; ! 141: ! 142: case GFRTC::ALARM_HIGH: ! 143: putlog(2, "ALARM_HIGH <- $%08x (No function)", data); ! 144: break; ! 145: ! 146: case GFRTC::INTR_STATUS: ! 147: putlog(2, "INTR_STATUS <- $%08x (No function)", data); ! 148: break; ! 149: ! 150: case GFRTC::ALARM_CLEAR: ! 151: putlog(2, "ALARM_CLEAR <- $%08x (No function)", data); ! 152: break; ! 153: ! 154: case GFRTC::INTR_CLEAR: ! 155: putlog(2, "INTR_CLEAR <- $%08x (No function)", data); ! 156: break; ! 157: ! 158: default: ! 159: putlog(1, "Write unknown $%08x <- $%08x", addr, data); ! 160: r.SetBusErr(); ! 161: break; ! 162: } ! 163: return r; ! 164: } ! 165: ! 166: busdata ! 167: GFRTCDevice::Peek8(uint32 addr) ! 168: { ! 169: uint32 offset = addr & 0xfff; ! 170: ! 171: switch (offset) { ! 172: case GFRTC::TIME_LOW + 0: ! 173: case GFRTC::TIME_LOW + 1: ! 174: case GFRTC::TIME_LOW + 2: ! 175: case GFRTC::TIME_LOW + 3: ! 176: case GFRTC::TIME_HIGH + 0: ! 177: case GFRTC::TIME_HIGH + 1: ! 178: case GFRTC::TIME_HIGH + 2: ! 179: case GFRTC::TIME_HIGH + 3: ! 180: { ! 181: uint64 now = MkTime() * 1000'000'000U; ! 182: ! 183: switch (offset) { ! 184: case GFRTC::TIME_LOW + 0: ! 185: return (now >> 24) & 0xff; ! 186: case GFRTC::TIME_LOW + 1: ! 187: return (now >> 16) & 0xff; ! 188: case GFRTC::TIME_LOW + 2: ! 189: return (now >> 8) & 0xff; ! 190: case GFRTC::TIME_LOW + 3: ! 191: return now & 0xff; ! 192: ! 193: case GFRTC::TIME_HIGH + 0: ! 194: return (now >> 56) & 0xff; ! 195: case GFRTC::TIME_HIGH + 1: ! 196: return (now >> 48) & 0xff; ! 197: case GFRTC::TIME_HIGH + 2: ! 198: return (now >> 40) & 0xff; ! 199: case GFRTC::TIME_HIGH + 3: ! 200: return (now >> 32) & 0xff; ! 201: default: ! 202: __unreachable(); ! 203: } ! 204: } ! 205: ! 206: case GFRTC::INTR_STATUS + 0: ! 207: case GFRTC::INTR_STATUS + 1: ! 208: case GFRTC::INTR_STATUS + 2: ! 209: case GFRTC::INTR_STATUS + 3: ! 210: return 0; ! 211: ! 212: case GFRTC::ALARM_STATUS + 0: ! 213: case GFRTC::ALARM_STATUS + 1: ! 214: case GFRTC::ALARM_STATUS + 2: ! 215: case GFRTC::ALARM_STATUS + 3: ! 216: return 0; ! 217: ! 218: default: ! 219: return busdata::BusErr; ! 220: } ! 221: } ! 222: ! 223: // モニタの下請け。(GFTimer から呼ばれる) ! 224: int ! 225: GFRTCDevice::MonitorUpdateRTC(TextScreen& screen, int y) const ! 226: { ! 227: screen.Puts(0, y++, "<RTC>"); ! 228: screen.Print(0, y++, "%04u/%02u/%02u(%s) %02u:%02u:%02u", ! 229: year, mon, day, wdays[GetWday()], hour, min, sec); ! 230: screen.Puts(0, y++, "TimeZone: UTC"); ! 231: ! 232: return y; ! 233: } ! 234: ! 235: void ! 236: GFRTCDevice::Tick1Hz() ! 237: { ! 238: CountUpSec(); ! 239: } ! 240: ! 241: // 内部時刻から time_t を作成する。 ! 242: time_t ! 243: GFRTCDevice::MkTime() const ! 244: { ! 245: struct tm tm; ! 246: ! 247: tm.tm_year = year - 1900; ! 248: tm.tm_mon = mon - 1; ! 249: tm.tm_mday = day; ! 250: tm.tm_hour = hour; ! 251: tm.tm_min = min; ! 252: tm.tm_sec = sec; ! 253: ! 254: return timegm(&tm); ! 255: } ! 256: ! 257: uint ! 258: GFRTCDevice::GetWday() const ! 259: { ! 260: // 曜日は保持していないので一旦日付を作ってから求める。 ! 261: struct tm tm; ! 262: time_t t = MkTime(); ! 263: ! 264: gmtime_r(&t, &tm); ! 265: return tm.tm_wday; ! 266: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.