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

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

unix.superglobalmegacorp.com

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