Annotation of nono/vm/goldfish_rtc.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.