|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.