Annotation of nono/vm/goldfish_rtc.cpp, revision 1.1.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.