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

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

unix.superglobalmegacorp.com

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