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

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.5 ! root       24: #include "mainbus.h"
        !            25: #include "mytime.h"
1.1       root       26: #include "textscreen.h"
                     27: 
                     28: //
                     29: // GFRTC
                     30: //
                     31: 
                     32: // コンストラクタ
                     33: GFRTCDevice::GFRTCDevice()
                     34:        : inherited()
                     35: {
                     36: }
                     37: 
                     38: // デストラクタ
                     39: GFRTCDevice::~GFRTCDevice()
                     40: {
                     41: }
                     42: 
                     43: // リセット
                     44: void
                     45: GFRTCDevice::ResetHard(bool poweron)
                     46: {
1.1.1.5 ! root       47:        time_nsec.q = 0;
1.1       root       48: }
                     49: 
                     50: busdata
1.1.1.2   root       51: GFRTCDevice::ReadPort(uint32 offset)
1.1       root       52: {
                     53:        busdata data;
                     54: 
                     55:        switch (offset) {
                     56:         case GFRTC::TIME_LOW:
1.1.1.5 ! root       57:                time_nsec.q = sec_to_nsec(MkTime());
        !            58:                data = time_nsec.l;
1.1       root       59:                if (__predict_false(loglevel >= 1)) {
                     60:                        if (loglevel >= 3) {
                     61:                                putlogn("TIME_LOW  -> $%08x", data.Data());
                     62:                        } else {
1.1.1.5 ! root       63:                                putlogn("TIME -> $%08x'%08x", time_nsec.h, data.Data());
1.1       root       64:                        }
1.1.1.2   root       65: 
                     66:                        if (loglevel >= 2) {
                     67:                                struct tm tm, tr;
1.1.1.5 ! root       68:                                time_t t = (time_t)nsec_to_sec(time_nsec.q);
1.1.1.2   root       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: 
1.1.1.5 ! root       78:                                time_t u = (time_t)get_hosttime_sec();
        !            79:                                gmtime_r(&u, &tr);
        !            80:                                putlogn("system_clock: %4u/%02u/%02u %02u:%02u:%02u",
1.1.1.2   root       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:
1.1.1.5 ! root       92:                data = time_nsec.h;
1.1       root       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.5 ! root      107:                putlog(1, "Read unknown $%08x", GetMainbusDevice()->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:         {
1.1.1.5 ! root      124:                time_nsec.l = data;
1.1       root      125: 
                    126:                if (__predict_false(loglevel >= 1)) {
                    127:                        if (loglevel >= 2) {
1.1.1.5 ! root      128:                                putlogn("TIME_LOW  <- $%08x", time_nsec.l);
1.1       root      129:                        } else {
1.1.1.5 ! root      130:                                putlogn("TIME <- $%08x'%08x", time_nsec.h, time_nsec.l);
1.1       root      131:                        }
                    132:                }
                    133: 
1.1.1.5 ! root      134:                time_t t = nsec_to_sec(time_nsec.q);
1.1       root      135:                struct tm tm;
                    136:                gmtime_r(&t, &tm);
                    137:                SetYear(tm.tm_year + 1900);
                    138:                SetMon(tm.tm_mon + 1);
                    139:                SetMday(tm.tm_mday);
                    140:                SetHour(tm.tm_hour);
                    141:                SetMin(tm.tm_min);
                    142:                SetSec(tm.tm_sec);
                    143:                break;
                    144:         }
                    145: 
                    146:         case GFRTC::TIME_HIGH:
                    147:                putlog(2, "TIME_HIGH <- $%08x", data);
1.1.1.5 ! root      148:                time_nsec.h = data;
1.1       root      149:                break;
                    150: 
                    151:         case GFRTC::ALARM_LOW:
                    152:                putlog(2, "ALARM_LOW  <- $%08x (No function)", data);
                    153:                break;
                    154: 
                    155:         case GFRTC::ALARM_HIGH:
                    156:                putlog(2, "ALARM_HIGH <- $%08x (No function)", data);
                    157:                break;
                    158: 
                    159:         case GFRTC::INTR_STATUS:
                    160:                putlog(2, "INTR_STATUS <- $%08x (No function)", data);
                    161:                break;
                    162: 
                    163:         case GFRTC::ALARM_CLEAR:
                    164:                putlog(2, "ALARM_CLEAR <- $%08x (No function)", data);
                    165:                break;
                    166: 
                    167:         case GFRTC::INTR_CLEAR:
                    168:                putlog(2, "INTR_CLEAR <- $%08x (No function)", data);
                    169:                break;
                    170: 
                    171:         default:
1.1.1.5 ! root      172:                putlog(1, "Write unknown $%08x <- $%08x",
        !           173:                        GetMainbusDevice()->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:         {
1.1.1.5 ! root      188:                uint64 now = sec_to_nsec(MkTime());
1.1.1.2   root      189:                return now & 0xffffffffU;
1.1       root      190:         }
1.1.1.2   root      191:         case GFRTC::TIME_HIGH:
                    192:         {
1.1.1.5 ! root      193:                uint64 now = sec_to_nsec(MkTime());
1.1.1.2   root      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
1.1.1.5 ! root      206: GFRTCDevice::MonitorScreenRTC(TextScreen& screen, int y) const
1.1       root      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.