Statistics
| Branch: | Revision:

root / hw / mc146818rtc.c @ b1503cda

History | View | Annotate | Download (17.5 kB)

1
/*
2
 * QEMU MC146818 RTC emulation
3
 *
4
 * Copyright (c) 2003-2004 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "hw.h"
25
#include "qemu-timer.h"
26
#include "sysemu.h"
27
#include "pc.h"
28
#include "isa.h"
29
#include "hpet_emul.h"
30

    
31
//#define DEBUG_CMOS
32

    
33
#define RTC_SECONDS             0
34
#define RTC_SECONDS_ALARM       1
35
#define RTC_MINUTES             2
36
#define RTC_MINUTES_ALARM       3
37
#define RTC_HOURS               4
38
#define RTC_HOURS_ALARM         5
39
#define RTC_ALARM_DONT_CARE    0xC0
40

    
41
#define RTC_DAY_OF_WEEK         6
42
#define RTC_DAY_OF_MONTH        7
43
#define RTC_MONTH               8
44
#define RTC_YEAR                9
45

    
46
#define RTC_REG_A               10
47
#define RTC_REG_B               11
48
#define RTC_REG_C               12
49
#define RTC_REG_D               13
50

    
51
#define REG_A_UIP 0x80
52

    
53
#define REG_B_SET 0x80
54
#define REG_B_PIE 0x40
55
#define REG_B_AIE 0x20
56
#define REG_B_UIE 0x10
57

    
58
struct RTCState {
59
    uint8_t cmos_data[128];
60
    uint8_t cmos_index;
61
    struct tm current_tm;
62
    qemu_irq irq;
63
    int it_shift;
64
    /* periodic timer */
65
    QEMUTimer *periodic_timer;
66
    int64_t next_periodic_time;
67
    /* second update */
68
    int64_t next_second_time;
69
    QEMUTimer *second_timer;
70
    QEMUTimer *second_timer2;
71
};
72

    
73
static void rtc_irq_raise(qemu_irq irq) {
74
    /* When HPET is operating in legacy mode, RTC interrupts are disabled
75
     * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
76
     * mode is established while interrupt is raised. We want it to
77
     * be lowered in any case
78
     */
79
#if defined TARGET_I386 || defined TARGET_X86_64
80
    if (!hpet_in_legacy_mode())
81
#endif
82
        qemu_irq_raise(irq);
83
}
84

    
85
static void rtc_set_time(RTCState *s);
86
static void rtc_copy_date(RTCState *s);
87

    
88
static void rtc_timer_update(RTCState *s, int64_t current_time)
89
{
90
    int period_code, period;
91
    int64_t cur_clock, next_irq_clock;
92

    
93
    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
94
#if defined TARGET_I386 || defined TARGET_X86_64
95
    /* disable periodic timer if hpet is in legacy mode, since interrupts are
96
     * disabled anyway.
97
     */
98
    if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
99
#else
100
    if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
101
#endif
102
        if (period_code <= 2)
103
            period_code += 7;
104
        /* period in 32 Khz cycles */
105
        period = 1 << (period_code - 1);
106
        /* compute 32 khz clock */
107
        cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
108
        next_irq_clock = (cur_clock & ~(period - 1)) + period;
109
        s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
110
        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
111
    } else {
112
        qemu_del_timer(s->periodic_timer);
113
    }
114
}
115

    
116
static void rtc_periodic_timer(void *opaque)
117
{
118
    RTCState *s = opaque;
119

    
120
    rtc_timer_update(s, s->next_periodic_time);
121
    s->cmos_data[RTC_REG_C] |= 0xc0;
122
    rtc_irq_raise(s->irq);
123
}
124

    
125
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
126
{
127
    RTCState *s = opaque;
128

    
129
    if ((addr & 1) == 0) {
130
        s->cmos_index = data & 0x7f;
131
    } else {
132
#ifdef DEBUG_CMOS
133
        printf("cmos: write index=0x%02x val=0x%02x\n",
134
               s->cmos_index, data);
135
#endif
136
        switch(s->cmos_index) {
137
        case RTC_SECONDS_ALARM:
138
        case RTC_MINUTES_ALARM:
139
        case RTC_HOURS_ALARM:
140
            /* XXX: not supported */
141
            s->cmos_data[s->cmos_index] = data;
142
            break;
143
        case RTC_SECONDS:
144
        case RTC_MINUTES:
145
        case RTC_HOURS:
146
        case RTC_DAY_OF_WEEK:
147
        case RTC_DAY_OF_MONTH:
148
        case RTC_MONTH:
149
        case RTC_YEAR:
150
            s->cmos_data[s->cmos_index] = data;
151
            /* if in set mode, do not update the time */
152
            if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
153
                rtc_set_time(s);
154
            }
155
            break;
156
        case RTC_REG_A:
157
            /* UIP bit is read only */
158
            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
159
                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
160
            rtc_timer_update(s, qemu_get_clock(vm_clock));
161
            break;
162
        case RTC_REG_B:
163
            if (data & REG_B_SET) {
164
                /* set mode: reset UIP mode */
165
                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
166
                data &= ~REG_B_UIE;
167
            } else {
168
                /* if disabling set mode, update the time */
169
                if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
170
                    rtc_set_time(s);
171
                }
172
            }
173
            s->cmos_data[RTC_REG_B] = data;
174
            rtc_timer_update(s, qemu_get_clock(vm_clock));
175
            break;
176
        case RTC_REG_C:
177
        case RTC_REG_D:
178
            /* cannot write to them */
179
            break;
180
        default:
181
            s->cmos_data[s->cmos_index] = data;
182
            break;
183
        }
184
    }
185
}
186

    
187
static inline int to_bcd(RTCState *s, int a)
188
{
189
    if (s->cmos_data[RTC_REG_B] & 0x04) {
190
        return a;
191
    } else {
192
        return ((a / 10) << 4) | (a % 10);
193
    }
194
}
195

    
196
static inline int from_bcd(RTCState *s, int a)
197
{
198
    if (s->cmos_data[RTC_REG_B] & 0x04) {
199
        return a;
200
    } else {
201
        return ((a >> 4) * 10) + (a & 0x0f);
202
    }
203
}
204

    
205
static void rtc_set_time(RTCState *s)
206
{
207
    struct tm *tm = &s->current_tm;
208

    
209
    tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
210
    tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
211
    tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
212
    if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
213
        (s->cmos_data[RTC_HOURS] & 0x80)) {
214
        tm->tm_hour += 12;
215
    }
216
    tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
217
    tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
218
    tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
219
    tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
220
}
221

    
222
static void rtc_copy_date(RTCState *s)
223
{
224
    const struct tm *tm = &s->current_tm;
225

    
226
    s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
227
    s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
228
    if (s->cmos_data[RTC_REG_B] & 0x02) {
229
        /* 24 hour format */
230
        s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
231
    } else {
232
        /* 12 hour format */
233
        s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
234
        if (tm->tm_hour >= 12)
235
            s->cmos_data[RTC_HOURS] |= 0x80;
236
    }
237
    s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
238
    s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
239
    s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
240
    s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
241
}
242

    
243
/* month is between 0 and 11. */
244
static int get_days_in_month(int month, int year)
245
{
246
    static const int days_tab[12] = {
247
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
248
    };
249
    int d;
250
    if ((unsigned )month >= 12)
251
        return 31;
252
    d = days_tab[month];
253
    if (month == 1) {
254
        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
255
            d++;
256
    }
257
    return d;
258
}
259

    
260
/* update 'tm' to the next second */
261
static void rtc_next_second(struct tm *tm)
262
{
263
    int days_in_month;
264

    
265
    tm->tm_sec++;
266
    if ((unsigned)tm->tm_sec >= 60) {
267
        tm->tm_sec = 0;
268
        tm->tm_min++;
269
        if ((unsigned)tm->tm_min >= 60) {
270
            tm->tm_min = 0;
271
            tm->tm_hour++;
272
            if ((unsigned)tm->tm_hour >= 24) {
273
                tm->tm_hour = 0;
274
                /* next day */
275
                tm->tm_wday++;
276
                if ((unsigned)tm->tm_wday >= 7)
277
                    tm->tm_wday = 0;
278
                days_in_month = get_days_in_month(tm->tm_mon,
279
                                                  tm->tm_year + 1900);
280
                tm->tm_mday++;
281
                if (tm->tm_mday < 1) {
282
                    tm->tm_mday = 1;
283
                } else if (tm->tm_mday > days_in_month) {
284
                    tm->tm_mday = 1;
285
                    tm->tm_mon++;
286
                    if (tm->tm_mon >= 12) {
287
                        tm->tm_mon = 0;
288
                        tm->tm_year++;
289
                    }
290
                }
291
            }
292
        }
293
    }
294
}
295

    
296

    
297
static void rtc_update_second(void *opaque)
298
{
299
    RTCState *s = opaque;
300
    int64_t delay;
301

    
302
    /* if the oscillator is not in normal operation, we do not update */
303
    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
304
        s->next_second_time += ticks_per_sec;
305
        qemu_mod_timer(s->second_timer, s->next_second_time);
306
    } else {
307
        rtc_next_second(&s->current_tm);
308

    
309
        if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
310
            /* update in progress bit */
311
            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
312
        }
313
        /* should be 244 us = 8 / 32768 seconds, but currently the
314
           timers do not have the necessary resolution. */
315
        delay = (ticks_per_sec * 1) / 100;
316
        if (delay < 1)
317
            delay = 1;
318
        qemu_mod_timer(s->second_timer2,
319
                       s->next_second_time + delay);
320
    }
321
}
322

    
323
static void rtc_update_second2(void *opaque)
324
{
325
    RTCState *s = opaque;
326

    
327
    if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
328
        rtc_copy_date(s);
329
    }
330

    
331
    /* check alarm */
332
    if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
333
        if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
334
             s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
335
            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
336
             s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
337
            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
338
             s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
339

    
340
            s->cmos_data[RTC_REG_C] |= 0xa0;
341
            rtc_irq_raise(s->irq);
342
        }
343
    }
344

    
345
    /* update ended interrupt */
346
    if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
347
        s->cmos_data[RTC_REG_C] |= 0x90;
348
        rtc_irq_raise(s->irq);
349
    }
350

    
351
    /* clear update in progress bit */
352
    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
353

    
354
    s->next_second_time += ticks_per_sec;
355
    qemu_mod_timer(s->second_timer, s->next_second_time);
356
}
357

    
358
static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
359
{
360
    RTCState *s = opaque;
361
    int ret;
362
    if ((addr & 1) == 0) {
363
        return 0xff;
364
    } else {
365
        switch(s->cmos_index) {
366
        case RTC_SECONDS:
367
        case RTC_MINUTES:
368
        case RTC_HOURS:
369
        case RTC_DAY_OF_WEEK:
370
        case RTC_DAY_OF_MONTH:
371
        case RTC_MONTH:
372
        case RTC_YEAR:
373
            ret = s->cmos_data[s->cmos_index];
374
            break;
375
        case RTC_REG_A:
376
            ret = s->cmos_data[s->cmos_index];
377
            break;
378
        case RTC_REG_C:
379
            ret = s->cmos_data[s->cmos_index];
380
            qemu_irq_lower(s->irq);
381
            s->cmos_data[RTC_REG_C] = 0x00;
382
            break;
383
        default:
384
            ret = s->cmos_data[s->cmos_index];
385
            break;
386
        }
387
#ifdef DEBUG_CMOS
388
        printf("cmos: read index=0x%02x val=0x%02x\n",
389
               s->cmos_index, ret);
390
#endif
391
        return ret;
392
    }
393
}
394

    
395
void rtc_set_memory(RTCState *s, int addr, int val)
396
{
397
    if (addr >= 0 && addr <= 127)
398
        s->cmos_data[addr] = val;
399
}
400

    
401
void rtc_set_date(RTCState *s, const struct tm *tm)
402
{
403
    s->current_tm = *tm;
404
    rtc_copy_date(s);
405
}
406

    
407
/* PC cmos mappings */
408
#define REG_IBM_CENTURY_BYTE        0x32
409
#define REG_IBM_PS2_CENTURY_BYTE    0x37
410

    
411
static void rtc_set_date_from_host(RTCState *s)
412
{
413
    struct tm tm;
414
    int val;
415

    
416
    /* set the CMOS date */
417
    qemu_get_timedate(&tm, 0);
418
    rtc_set_date(s, &tm);
419

    
420
    val = to_bcd(s, (tm.tm_year / 100) + 19);
421
    rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
422
    rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
423
}
424

    
425
static void rtc_save(QEMUFile *f, void *opaque)
426
{
427
    RTCState *s = opaque;
428

    
429
    qemu_put_buffer(f, s->cmos_data, 128);
430
    qemu_put_8s(f, &s->cmos_index);
431

    
432
    qemu_put_be32(f, s->current_tm.tm_sec);
433
    qemu_put_be32(f, s->current_tm.tm_min);
434
    qemu_put_be32(f, s->current_tm.tm_hour);
435
    qemu_put_be32(f, s->current_tm.tm_wday);
436
    qemu_put_be32(f, s->current_tm.tm_mday);
437
    qemu_put_be32(f, s->current_tm.tm_mon);
438
    qemu_put_be32(f, s->current_tm.tm_year);
439

    
440
    qemu_put_timer(f, s->periodic_timer);
441
    qemu_put_be64(f, s->next_periodic_time);
442

    
443
    qemu_put_be64(f, s->next_second_time);
444
    qemu_put_timer(f, s->second_timer);
445
    qemu_put_timer(f, s->second_timer2);
446
}
447

    
448
static int rtc_load(QEMUFile *f, void *opaque, int version_id)
449
{
450
    RTCState *s = opaque;
451

    
452
    if (version_id != 1)
453
        return -EINVAL;
454

    
455
    qemu_get_buffer(f, s->cmos_data, 128);
456
    qemu_get_8s(f, &s->cmos_index);
457

    
458
    s->current_tm.tm_sec=qemu_get_be32(f);
459
    s->current_tm.tm_min=qemu_get_be32(f);
460
    s->current_tm.tm_hour=qemu_get_be32(f);
461
    s->current_tm.tm_wday=qemu_get_be32(f);
462
    s->current_tm.tm_mday=qemu_get_be32(f);
463
    s->current_tm.tm_mon=qemu_get_be32(f);
464
    s->current_tm.tm_year=qemu_get_be32(f);
465

    
466
    qemu_get_timer(f, s->periodic_timer);
467
    s->next_periodic_time=qemu_get_be64(f);
468

    
469
    s->next_second_time=qemu_get_be64(f);
470
    qemu_get_timer(f, s->second_timer);
471
    qemu_get_timer(f, s->second_timer2);
472
    return 0;
473
}
474

    
475
RTCState *rtc_init(int base, qemu_irq irq)
476
{
477
    RTCState *s;
478

    
479
    s = qemu_mallocz(sizeof(RTCState));
480
    if (!s)
481
        return NULL;
482

    
483
    s->irq = irq;
484
    s->cmos_data[RTC_REG_A] = 0x26;
485
    s->cmos_data[RTC_REG_B] = 0x02;
486
    s->cmos_data[RTC_REG_C] = 0x00;
487
    s->cmos_data[RTC_REG_D] = 0x80;
488

    
489
    rtc_set_date_from_host(s);
490

    
491
    s->periodic_timer = qemu_new_timer(vm_clock,
492
                                       rtc_periodic_timer, s);
493
    s->second_timer = qemu_new_timer(vm_clock,
494
                                     rtc_update_second, s);
495
    s->second_timer2 = qemu_new_timer(vm_clock,
496
                                      rtc_update_second2, s);
497

    
498
    s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
499
    qemu_mod_timer(s->second_timer2, s->next_second_time);
500

    
501
    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
502
    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
503

    
504
    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
505
    return s;
506
}
507

    
508
/* Memory mapped interface */
509
static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
510
{
511
    RTCState *s = opaque;
512

    
513
    return cmos_ioport_read(s, addr >> s->it_shift) & 0xFF;
514
}
515

    
516
static void cmos_mm_writeb (void *opaque,
517
                            target_phys_addr_t addr, uint32_t value)
518
{
519
    RTCState *s = opaque;
520

    
521
    cmos_ioport_write(s, addr >> s->it_shift, value & 0xFF);
522
}
523

    
524
static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
525
{
526
    RTCState *s = opaque;
527
    uint32_t val;
528

    
529
    val = cmos_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
530
#ifdef TARGET_WORDS_BIGENDIAN
531
    val = bswap16(val);
532
#endif
533
    return val;
534
}
535

    
536
static void cmos_mm_writew (void *opaque,
537
                            target_phys_addr_t addr, uint32_t value)
538
{
539
    RTCState *s = opaque;
540
#ifdef TARGET_WORDS_BIGENDIAN
541
    value = bswap16(value);
542
#endif
543
    cmos_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
544
}
545

    
546
static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
547
{
548
    RTCState *s = opaque;
549
    uint32_t val;
550

    
551
    val = cmos_ioport_read(s, addr >> s->it_shift);
552
#ifdef TARGET_WORDS_BIGENDIAN
553
    val = bswap32(val);
554
#endif
555
    return val;
556
}
557

    
558
static void cmos_mm_writel (void *opaque,
559
                            target_phys_addr_t addr, uint32_t value)
560
{
561
    RTCState *s = opaque;
562
#ifdef TARGET_WORDS_BIGENDIAN
563
    value = bswap32(value);
564
#endif
565
    cmos_ioport_write(s, addr >> s->it_shift, value);
566
}
567

    
568
static CPUReadMemoryFunc *rtc_mm_read[] = {
569
    &cmos_mm_readb,
570
    &cmos_mm_readw,
571
    &cmos_mm_readl,
572
};
573

    
574
static CPUWriteMemoryFunc *rtc_mm_write[] = {
575
    &cmos_mm_writeb,
576
    &cmos_mm_writew,
577
    &cmos_mm_writel,
578
};
579

    
580
RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
581
{
582
    RTCState *s;
583
    int io_memory;
584

    
585
    s = qemu_mallocz(sizeof(RTCState));
586
    if (!s)
587
        return NULL;
588

    
589
    s->irq = irq;
590
    s->cmos_data[RTC_REG_A] = 0x26;
591
    s->cmos_data[RTC_REG_B] = 0x02;
592
    s->cmos_data[RTC_REG_C] = 0x00;
593
    s->cmos_data[RTC_REG_D] = 0x80;
594

    
595
    rtc_set_date_from_host(s);
596

    
597
    s->periodic_timer = qemu_new_timer(vm_clock,
598
                                       rtc_periodic_timer, s);
599
    s->second_timer = qemu_new_timer(vm_clock,
600
                                     rtc_update_second, s);
601
    s->second_timer2 = qemu_new_timer(vm_clock,
602
                                      rtc_update_second2, s);
603

    
604
    s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
605
    qemu_mod_timer(s->second_timer2, s->next_second_time);
606

    
607
    io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
608
    cpu_register_physical_memory(base, 2 << it_shift, io_memory);
609

    
610
    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
611
    return s;
612
}