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

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"
1.1.1.2 ! root       23: #include "mpu.h"
1.1       root       24: #include "textscreen.h"
                     25: 
                     26: //
                     27: // GFRTC
                     28: //
                     29: 
                     30: // コンストラクタ
                     31: GFRTCDevice::GFRTCDevice()
                     32:        : inherited()
                     33: {
                     34: }
                     35: 
                     36: // デストラクタ
                     37: GFRTCDevice::~GFRTCDevice()
                     38: {
                     39: }
                     40: 
                     41: // 初期化
                     42: bool
                     43: GFRTCDevice::Init()
                     44: {
                     45:        if (inherited::Init() == false) {
                     46:                return false;
                     47:        }
                     48: 
                     49:        return true;
                     50: }
                     51: 
                     52: // リセット
                     53: void
                     54: GFRTCDevice::ResetHard(bool poweron)
                     55: {
                     56:        time_nsec = 0;
                     57: }
                     58: 
                     59: busdata
1.1.1.2 ! root       60: GFRTCDevice::ReadPort(uint32 offset)
1.1       root       61: {
                     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:                        }
1.1.1.2 ! root       75: 
        !            76:                        if (loglevel >= 2) {
        !            77:                                struct tm tm, tr;
        !            78:                                time_t t = (time_t)(time_nsec / 1_sec);
        !            79:                                gmtime_r(&t, &tm);
        !            80:                                putlogn("TIME / 1e9:   %4u/%02u/%02u %02u:%02u:%02u",
        !            81:                                        tm.tm_year + 1900,
        !            82:                                        tm.tm_mon + 1,
        !            83:                                        tm.tm_mday,
        !            84:                                        tm.tm_hour,
        !            85:                                        tm.tm_min,
        !            86:                                        tm.tm_sec);
        !            87: 
        !            88:                                struct timeval tv;
        !            89:                                gettimeofday(&tv, NULL);
        !            90:                                gmtime_r(&tv.tv_sec, &tr);
        !            91:                                putlogn("gettimeofday: %4u/%02u/%02u %02u:%02u:%02u",
        !            92:                                        tr.tm_year + 1900,
        !            93:                                        tr.tm_mon + 1,
        !            94:                                        tr.tm_mday,
        !            95:                                        tr.tm_hour,
        !            96:                                        tr.tm_min,
        !            97:                                        tr.tm_sec);
        !            98:                        }
1.1       root       99:                }
                    100:                break;
                    101: 
                    102:         case GFRTC::TIME_HIGH:
                    103:                data = (uint32)(time_nsec >> 32);
                    104:                putlog(3, "TIME_HIGH -> $%08x", data.Data());
                    105:                break;
                    106: 
                    107:         case GFRTC::INTR_STATUS:
                    108:                putlog(2, "Read INTR_STATUS (No function)");
                    109:                data = 0;
                    110:                break;
                    111: 
                    112:         case GFRTC::ALARM_STATUS:
                    113:                putlog(2, "Read ALARM_STATUS (No function)");
                    114:                data = 0;
                    115:                break;
                    116: 
                    117:         default:
1.1.1.2 ! root      118:                putlog(1, "Read unknown $%08x", mpu->GetPaddr());
1.1       root      119:                data.SetBusErr();
                    120:                break;
                    121:        }
1.1.1.2 ! root      122: 
        !           123:        data |= BusData::Size4;
1.1       root      124:        return data;
                    125: }
                    126: 
                    127: busdata
1.1.1.2 ! root      128: GFRTCDevice::WritePort(uint32 offset, uint32 data)
1.1       root      129: {
                    130:        busdata r;
                    131: 
                    132:        switch (offset) {
                    133:         case GFRTC::TIME_LOW:
                    134:         {
                    135:                time_nsec |= data;
                    136: 
                    137:                if (__predict_false(loglevel >= 1)) {
                    138:                        if (loglevel >= 2) {
                    139:                                putlogn("TIME_LOW  <- $%08x", (uint32)time_nsec);
                    140:                        } else {
                    141:                                putlogn("TIME <- $%08x'%08x",
                    142:                                        (uint32)(time_nsec >> 32), (uint32)time_nsec);
                    143:                        }
                    144:                }
                    145: 
                    146:                time_t t = time_nsec / 1000'000'000U;
                    147:                struct tm tm;
                    148:                gmtime_r(&t, &tm);
                    149:                SetYear(tm.tm_year + 1900);
                    150:                SetMon(tm.tm_mon + 1);
                    151:                SetMday(tm.tm_mday);
                    152:                SetHour(tm.tm_hour);
                    153:                SetMin(tm.tm_min);
                    154:                SetSec(tm.tm_sec);
                    155:                break;
                    156:         }
                    157: 
                    158:         case GFRTC::TIME_HIGH:
                    159:                putlog(2, "TIME_HIGH <- $%08x", data);
                    160:                time_nsec = (uint64)data << 32;
                    161:                break;
                    162: 
                    163:         case GFRTC::ALARM_LOW:
                    164:                putlog(2, "ALARM_LOW  <- $%08x (No function)", data);
                    165:                break;
                    166: 
                    167:         case GFRTC::ALARM_HIGH:
                    168:                putlog(2, "ALARM_HIGH <- $%08x (No function)", data);
                    169:                break;
                    170: 
                    171:         case GFRTC::INTR_STATUS:
                    172:                putlog(2, "INTR_STATUS <- $%08x (No function)", data);
                    173:                break;
                    174: 
                    175:         case GFRTC::ALARM_CLEAR:
                    176:                putlog(2, "ALARM_CLEAR <- $%08x (No function)", data);
                    177:                break;
                    178: 
                    179:         case GFRTC::INTR_CLEAR:
                    180:                putlog(2, "INTR_CLEAR <- $%08x (No function)", data);
                    181:                break;
                    182: 
                    183:         default:
1.1.1.2 ! root      184:                putlog(1, "Write unknown $%08x <- $%08x", mpu->GetPaddr(), data);
1.1       root      185:                r.SetBusErr();
                    186:                break;
                    187:        }
1.1.1.2 ! root      188: 
        !           189:        r |= BusData::Size4;
1.1       root      190:        return r;
                    191: }
                    192: 
                    193: busdata
1.1.1.2 ! root      194: GFRTCDevice::PeekPort(uint32 offset)
1.1       root      195: {
                    196:        switch (offset) {
1.1.1.2 ! root      197:         case GFRTC::TIME_LOW:
1.1       root      198:         {
                    199:                uint64 now = MkTime() * 1000'000'000U;
1.1.1.2 ! root      200:                return now & 0xffffffffU;
1.1       root      201:         }
1.1.1.2 ! root      202:         case GFRTC::TIME_HIGH:
        !           203:         {
        !           204:                uint64 now = MkTime() * 1000'000'000U;
        !           205:                return now >> 32;
        !           206:         }
        !           207:         case GFRTC::INTR_STATUS:
        !           208:         case GFRTC::ALARM_STATUS:
1.1       root      209:                return 0;
                    210:         default:
1.1.1.2 ! root      211:                return BusData::BusErr;
1.1       root      212:        }
                    213: }
                    214: 
                    215: // モニタの下請け。(GFTimer から呼ばれる)
                    216: int
                    217: GFRTCDevice::MonitorUpdateRTC(TextScreen& screen, int y) const
                    218: {
                    219:        screen.Puts(0, y++, "<RTC>");
                    220:        screen.Print(0, y++, "%04u/%02u/%02u(%s) %02u:%02u:%02u",
                    221:                year, mon, day, wdays[GetWday()], hour, min, sec);
                    222:        screen.Puts(0, y++, "TimeZone: UTC");
                    223: 
                    224:        return y;
                    225: }
                    226: 
                    227: void
                    228: GFRTCDevice::Tick1Hz()
                    229: {
                    230:        CountUpSec();
                    231: }
                    232: 
                    233: // 内部時刻から time_t を作成する。
                    234: time_t
                    235: GFRTCDevice::MkTime() const
                    236: {
                    237:        struct tm tm;
                    238: 
                    239:        tm.tm_year = year - 1900;
                    240:        tm.tm_mon  = mon - 1;
                    241:        tm.tm_mday = day;
                    242:        tm.tm_hour = hour;
                    243:        tm.tm_min  = min;
                    244:        tm.tm_sec  = sec;
                    245: 
                    246:        return timegm(&tm);
                    247: }
                    248: 
                    249: uint
                    250: GFRTCDevice::GetWday() const
                    251: {
                    252:        // 曜日は保持していないので一旦日付を作ってから求める。
                    253:        struct tm tm;
                    254:        time_t t = MkTime();
                    255: 
                    256:        gmtime_r(&t, &tm);
                    257:        return tm.tm_wday;
                    258: }

unix.superglobalmegacorp.com

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