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