symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/m48t59.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
       
     3  *
       
     4  * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
       
     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 "nvram.h"
       
    26 #include "isa.h"
       
    27 #include "qemu-timer.h"
       
    28 #include "sysemu.h"
       
    29 
       
    30 //#define DEBUG_NVRAM
       
    31 
       
    32 #if defined(DEBUG_NVRAM)
       
    33 #define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
       
    34 #else
       
    35 #define NVRAM_PRINTF(fmt, args...) do { } while (0)
       
    36 #endif
       
    37 
       
    38 /*
       
    39  * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
       
    40  * alarm and a watchdog timer and related control registers. In the
       
    41  * PPC platform there is also a nvram lock function.
       
    42  */
       
    43 struct m48t59_t {
       
    44     /* Model parameters */
       
    45     int type; // 2 = m48t02, 8 = m48t08, 59 = m48t59
       
    46     /* Hardware parameters */
       
    47     qemu_irq IRQ;
       
    48     int mem_index;
       
    49     uint32_t io_base;
       
    50     uint16_t size;
       
    51     /* RTC management */
       
    52     time_t   time_offset;
       
    53     time_t   stop_time;
       
    54     /* Alarm & watchdog */
       
    55     struct tm alarm;
       
    56     struct QEMUTimer *alrm_timer;
       
    57     struct QEMUTimer *wd_timer;
       
    58     /* NVRAM storage */
       
    59     uint8_t  lock;
       
    60     uint16_t addr;
       
    61     uint8_t *buffer;
       
    62 };
       
    63 
       
    64 /* Fake timer functions */
       
    65 /* Generic helpers for BCD */
       
    66 static inline uint8_t toBCD (uint8_t value)
       
    67 {
       
    68     return (((value / 10) % 10) << 4) | (value % 10);
       
    69 }
       
    70 
       
    71 static inline uint8_t fromBCD (uint8_t BCD)
       
    72 {
       
    73     return ((BCD >> 4) * 10) + (BCD & 0x0F);
       
    74 }
       
    75 
       
    76 /* Alarm management */
       
    77 static void alarm_cb (void *opaque)
       
    78 {
       
    79     struct tm tm;
       
    80     uint64_t next_time;
       
    81     m48t59_t *NVRAM = opaque;
       
    82 
       
    83     qemu_set_irq(NVRAM->IRQ, 1);
       
    84     if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
       
    85 	(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
       
    86 	(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
       
    87 	(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
       
    88         /* Repeat once a month */
       
    89         qemu_get_timedate(&tm, NVRAM->time_offset);
       
    90         tm.tm_mon++;
       
    91         if (tm.tm_mon == 13) {
       
    92             tm.tm_mon = 1;
       
    93             tm.tm_year++;
       
    94         }
       
    95         next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
       
    96     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
       
    97 	       (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
       
    98 	       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
       
    99 	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
       
   100         /* Repeat once a day */
       
   101         next_time = 24 * 60 * 60;
       
   102     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
       
   103 	       (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
       
   104 	       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
       
   105 	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
       
   106         /* Repeat once an hour */
       
   107         next_time = 60 * 60;
       
   108     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
       
   109 	       (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
       
   110 	       (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
       
   111 	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
       
   112         /* Repeat once a minute */
       
   113         next_time = 60;
       
   114     } else {
       
   115         /* Repeat once a second */
       
   116         next_time = 1;
       
   117     }
       
   118     qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock(vm_clock) +
       
   119                     next_time * 1000);
       
   120     qemu_set_irq(NVRAM->IRQ, 0);
       
   121 }
       
   122 
       
   123 static void set_alarm (m48t59_t *NVRAM)
       
   124 {
       
   125     int diff;
       
   126     if (NVRAM->alrm_timer != NULL) {
       
   127         qemu_del_timer(NVRAM->alrm_timer);
       
   128         diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
       
   129         if (diff > 0)
       
   130             qemu_mod_timer(NVRAM->alrm_timer, diff * 1000);
       
   131     }
       
   132 }
       
   133 
       
   134 /* RTC management helpers */
       
   135 static inline void get_time (m48t59_t *NVRAM, struct tm *tm)
       
   136 {
       
   137     qemu_get_timedate(tm, NVRAM->time_offset);
       
   138 }
       
   139 
       
   140 static void set_time (m48t59_t *NVRAM, struct tm *tm)
       
   141 {
       
   142     NVRAM->time_offset = qemu_timedate_diff(tm);
       
   143     set_alarm(NVRAM);
       
   144 }
       
   145 
       
   146 /* Watchdog management */
       
   147 static void watchdog_cb (void *opaque)
       
   148 {
       
   149     m48t59_t *NVRAM = opaque;
       
   150 
       
   151     NVRAM->buffer[0x1FF0] |= 0x80;
       
   152     if (NVRAM->buffer[0x1FF7] & 0x80) {
       
   153 	NVRAM->buffer[0x1FF7] = 0x00;
       
   154 	NVRAM->buffer[0x1FFC] &= ~0x40;
       
   155         /* May it be a hw CPU Reset instead ? */
       
   156         qemu_system_reset_request();
       
   157     } else {
       
   158 	qemu_set_irq(NVRAM->IRQ, 1);
       
   159 	qemu_set_irq(NVRAM->IRQ, 0);
       
   160     }
       
   161 }
       
   162 
       
   163 static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
       
   164 {
       
   165     uint64_t interval; /* in 1/16 seconds */
       
   166 
       
   167     NVRAM->buffer[0x1FF0] &= ~0x80;
       
   168     if (NVRAM->wd_timer != NULL) {
       
   169         qemu_del_timer(NVRAM->wd_timer);
       
   170         if (value != 0) {
       
   171             interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
       
   172             qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
       
   173                            ((interval * 1000) >> 4));
       
   174         }
       
   175     }
       
   176 }
       
   177 
       
   178 /* Direct access to NVRAM */
       
   179 void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
       
   180 {
       
   181     m48t59_t *NVRAM = opaque;
       
   182     struct tm tm;
       
   183     int tmp;
       
   184 
       
   185     if (addr > 0x1FF8 && addr < 0x2000)
       
   186 	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
       
   187 
       
   188     /* check for NVRAM access */
       
   189     if ((NVRAM->type == 2 && addr < 0x7f8) ||
       
   190         (NVRAM->type == 8 && addr < 0x1ff8) ||
       
   191         (NVRAM->type == 59 && addr < 0x1ff0))
       
   192         goto do_write;
       
   193 
       
   194     /* TOD access */
       
   195     switch (addr) {
       
   196     case 0x1FF0:
       
   197         /* flags register : read-only */
       
   198         break;
       
   199     case 0x1FF1:
       
   200         /* unused */
       
   201         break;
       
   202     case 0x1FF2:
       
   203         /* alarm seconds */
       
   204         tmp = fromBCD(val & 0x7F);
       
   205         if (tmp >= 0 && tmp <= 59) {
       
   206             NVRAM->alarm.tm_sec = tmp;
       
   207             NVRAM->buffer[0x1FF2] = val;
       
   208             set_alarm(NVRAM);
       
   209         }
       
   210         break;
       
   211     case 0x1FF3:
       
   212         /* alarm minutes */
       
   213         tmp = fromBCD(val & 0x7F);
       
   214         if (tmp >= 0 && tmp <= 59) {
       
   215             NVRAM->alarm.tm_min = tmp;
       
   216             NVRAM->buffer[0x1FF3] = val;
       
   217             set_alarm(NVRAM);
       
   218         }
       
   219         break;
       
   220     case 0x1FF4:
       
   221         /* alarm hours */
       
   222         tmp = fromBCD(val & 0x3F);
       
   223         if (tmp >= 0 && tmp <= 23) {
       
   224             NVRAM->alarm.tm_hour = tmp;
       
   225             NVRAM->buffer[0x1FF4] = val;
       
   226             set_alarm(NVRAM);
       
   227         }
       
   228         break;
       
   229     case 0x1FF5:
       
   230         /* alarm date */
       
   231         tmp = fromBCD(val & 0x1F);
       
   232         if (tmp != 0) {
       
   233             NVRAM->alarm.tm_mday = tmp;
       
   234             NVRAM->buffer[0x1FF5] = val;
       
   235             set_alarm(NVRAM);
       
   236         }
       
   237         break;
       
   238     case 0x1FF6:
       
   239         /* interrupts */
       
   240         NVRAM->buffer[0x1FF6] = val;
       
   241         break;
       
   242     case 0x1FF7:
       
   243         /* watchdog */
       
   244         NVRAM->buffer[0x1FF7] = val;
       
   245         set_up_watchdog(NVRAM, val);
       
   246         break;
       
   247     case 0x1FF8:
       
   248     case 0x07F8:
       
   249         /* control */
       
   250        NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
       
   251         break;
       
   252     case 0x1FF9:
       
   253     case 0x07F9:
       
   254         /* seconds (BCD) */
       
   255 	tmp = fromBCD(val & 0x7F);
       
   256 	if (tmp >= 0 && tmp <= 59) {
       
   257 	    get_time(NVRAM, &tm);
       
   258 	    tm.tm_sec = tmp;
       
   259 	    set_time(NVRAM, &tm);
       
   260 	}
       
   261         if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
       
   262 	    if (val & 0x80) {
       
   263 		NVRAM->stop_time = time(NULL);
       
   264 	    } else {
       
   265 		NVRAM->time_offset += NVRAM->stop_time - time(NULL);
       
   266 		NVRAM->stop_time = 0;
       
   267 	    }
       
   268 	}
       
   269         NVRAM->buffer[addr] = val & 0x80;
       
   270         break;
       
   271     case 0x1FFA:
       
   272     case 0x07FA:
       
   273         /* minutes (BCD) */
       
   274 	tmp = fromBCD(val & 0x7F);
       
   275 	if (tmp >= 0 && tmp <= 59) {
       
   276 	    get_time(NVRAM, &tm);
       
   277 	    tm.tm_min = tmp;
       
   278 	    set_time(NVRAM, &tm);
       
   279 	}
       
   280         break;
       
   281     case 0x1FFB:
       
   282     case 0x07FB:
       
   283         /* hours (BCD) */
       
   284 	tmp = fromBCD(val & 0x3F);
       
   285 	if (tmp >= 0 && tmp <= 23) {
       
   286 	    get_time(NVRAM, &tm);
       
   287 	    tm.tm_hour = tmp;
       
   288 	    set_time(NVRAM, &tm);
       
   289 	}
       
   290         break;
       
   291     case 0x1FFC:
       
   292     case 0x07FC:
       
   293         /* day of the week / century */
       
   294 	tmp = fromBCD(val & 0x07);
       
   295 	get_time(NVRAM, &tm);
       
   296 	tm.tm_wday = tmp;
       
   297 	set_time(NVRAM, &tm);
       
   298         NVRAM->buffer[addr] = val & 0x40;
       
   299         break;
       
   300     case 0x1FFD:
       
   301     case 0x07FD:
       
   302         /* date */
       
   303 	tmp = fromBCD(val & 0x1F);
       
   304 	if (tmp != 0) {
       
   305 	    get_time(NVRAM, &tm);
       
   306 	    tm.tm_mday = tmp;
       
   307 	    set_time(NVRAM, &tm);
       
   308 	}
       
   309         break;
       
   310     case 0x1FFE:
       
   311     case 0x07FE:
       
   312         /* month */
       
   313 	tmp = fromBCD(val & 0x1F);
       
   314 	if (tmp >= 1 && tmp <= 12) {
       
   315 	    get_time(NVRAM, &tm);
       
   316 	    tm.tm_mon = tmp - 1;
       
   317 	    set_time(NVRAM, &tm);
       
   318 	}
       
   319         break;
       
   320     case 0x1FFF:
       
   321     case 0x07FF:
       
   322         /* year */
       
   323 	tmp = fromBCD(val);
       
   324 	if (tmp >= 0 && tmp <= 99) {
       
   325 	    get_time(NVRAM, &tm);
       
   326             if (NVRAM->type == 8)
       
   327                 tm.tm_year = fromBCD(val) + 68; // Base year is 1968
       
   328             else
       
   329                 tm.tm_year = fromBCD(val);
       
   330 	    set_time(NVRAM, &tm);
       
   331 	}
       
   332         break;
       
   333     default:
       
   334         /* Check lock registers state */
       
   335         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
       
   336             break;
       
   337         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
       
   338             break;
       
   339     do_write:
       
   340         if (addr < NVRAM->size) {
       
   341             NVRAM->buffer[addr] = val & 0xFF;
       
   342 	}
       
   343         break;
       
   344     }
       
   345 }
       
   346 
       
   347 uint32_t m48t59_read (void *opaque, uint32_t addr)
       
   348 {
       
   349     m48t59_t *NVRAM = opaque;
       
   350     struct tm tm;
       
   351     uint32_t retval = 0xFF;
       
   352 
       
   353     /* check for NVRAM access */
       
   354     if ((NVRAM->type == 2 && addr < 0x078f) ||
       
   355         (NVRAM->type == 8 && addr < 0x1ff8) ||
       
   356         (NVRAM->type == 59 && addr < 0x1ff0))
       
   357         goto do_read;
       
   358 
       
   359     /* TOD access */
       
   360     switch (addr) {
       
   361     case 0x1FF0:
       
   362         /* flags register */
       
   363 	goto do_read;
       
   364     case 0x1FF1:
       
   365         /* unused */
       
   366 	retval = 0;
       
   367         break;
       
   368     case 0x1FF2:
       
   369         /* alarm seconds */
       
   370 	goto do_read;
       
   371     case 0x1FF3:
       
   372         /* alarm minutes */
       
   373 	goto do_read;
       
   374     case 0x1FF4:
       
   375         /* alarm hours */
       
   376 	goto do_read;
       
   377     case 0x1FF5:
       
   378         /* alarm date */
       
   379 	goto do_read;
       
   380     case 0x1FF6:
       
   381         /* interrupts */
       
   382 	goto do_read;
       
   383     case 0x1FF7:
       
   384 	/* A read resets the watchdog */
       
   385 	set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
       
   386 	goto do_read;
       
   387     case 0x1FF8:
       
   388     case 0x07F8:
       
   389         /* control */
       
   390 	goto do_read;
       
   391     case 0x1FF9:
       
   392     case 0x07F9:
       
   393         /* seconds (BCD) */
       
   394         get_time(NVRAM, &tm);
       
   395         retval = (NVRAM->buffer[addr] & 0x80) | toBCD(tm.tm_sec);
       
   396         break;
       
   397     case 0x1FFA:
       
   398     case 0x07FA:
       
   399         /* minutes (BCD) */
       
   400         get_time(NVRAM, &tm);
       
   401         retval = toBCD(tm.tm_min);
       
   402         break;
       
   403     case 0x1FFB:
       
   404     case 0x07FB:
       
   405         /* hours (BCD) */
       
   406         get_time(NVRAM, &tm);
       
   407         retval = toBCD(tm.tm_hour);
       
   408         break;
       
   409     case 0x1FFC:
       
   410     case 0x07FC:
       
   411         /* day of the week / century */
       
   412         get_time(NVRAM, &tm);
       
   413         retval = NVRAM->buffer[addr] | tm.tm_wday;
       
   414         break;
       
   415     case 0x1FFD:
       
   416     case 0x07FD:
       
   417         /* date */
       
   418         get_time(NVRAM, &tm);
       
   419         retval = toBCD(tm.tm_mday);
       
   420         break;
       
   421     case 0x1FFE:
       
   422     case 0x07FE:
       
   423         /* month */
       
   424         get_time(NVRAM, &tm);
       
   425         retval = toBCD(tm.tm_mon + 1);
       
   426         break;
       
   427     case 0x1FFF:
       
   428     case 0x07FF:
       
   429         /* year */
       
   430         get_time(NVRAM, &tm);
       
   431         if (NVRAM->type == 8)
       
   432             retval = toBCD(tm.tm_year - 68); // Base year is 1968
       
   433         else
       
   434             retval = toBCD(tm.tm_year);
       
   435         break;
       
   436     default:
       
   437         /* Check lock registers state */
       
   438         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
       
   439             break;
       
   440         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
       
   441             break;
       
   442     do_read:
       
   443         if (addr < NVRAM->size) {
       
   444             retval = NVRAM->buffer[addr];
       
   445 	}
       
   446         break;
       
   447     }
       
   448     if (addr > 0x1FF9 && addr < 0x2000)
       
   449        NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
       
   450 
       
   451     return retval;
       
   452 }
       
   453 
       
   454 void m48t59_set_addr (void *opaque, uint32_t addr)
       
   455 {
       
   456     m48t59_t *NVRAM = opaque;
       
   457 
       
   458     NVRAM->addr = addr;
       
   459 }
       
   460 
       
   461 void m48t59_toggle_lock (void *opaque, int lock)
       
   462 {
       
   463     m48t59_t *NVRAM = opaque;
       
   464 
       
   465     NVRAM->lock ^= 1 << lock;
       
   466 }
       
   467 
       
   468 /* IO access to NVRAM */
       
   469 static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
       
   470 {
       
   471     m48t59_t *NVRAM = opaque;
       
   472 
       
   473     addr -= NVRAM->io_base;
       
   474     NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
       
   475     switch (addr) {
       
   476     case 0:
       
   477         NVRAM->addr &= ~0x00FF;
       
   478         NVRAM->addr |= val;
       
   479         break;
       
   480     case 1:
       
   481         NVRAM->addr &= ~0xFF00;
       
   482         NVRAM->addr |= val << 8;
       
   483         break;
       
   484     case 3:
       
   485         m48t59_write(NVRAM, val, NVRAM->addr);
       
   486         NVRAM->addr = 0x0000;
       
   487         break;
       
   488     default:
       
   489         break;
       
   490     }
       
   491 }
       
   492 
       
   493 static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
       
   494 {
       
   495     m48t59_t *NVRAM = opaque;
       
   496     uint32_t retval;
       
   497 
       
   498     addr -= NVRAM->io_base;
       
   499     switch (addr) {
       
   500     case 3:
       
   501         retval = m48t59_read(NVRAM, NVRAM->addr);
       
   502         break;
       
   503     default:
       
   504         retval = -1;
       
   505         break;
       
   506     }
       
   507     NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
       
   508 
       
   509     return retval;
       
   510 }
       
   511 
       
   512 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
       
   513 {
       
   514     m48t59_t *NVRAM = opaque;
       
   515 
       
   516     m48t59_write(NVRAM, addr, value & 0xff);
       
   517 }
       
   518 
       
   519 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
       
   520 {
       
   521     m48t59_t *NVRAM = opaque;
       
   522 
       
   523     m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
       
   524     m48t59_write(NVRAM, addr + 1, value & 0xff);
       
   525 }
       
   526 
       
   527 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
       
   528 {
       
   529     m48t59_t *NVRAM = opaque;
       
   530 
       
   531     m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
       
   532     m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
       
   533     m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
       
   534     m48t59_write(NVRAM, addr + 3, value & 0xff);
       
   535 }
       
   536 
       
   537 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
       
   538 {
       
   539     m48t59_t *NVRAM = opaque;
       
   540     uint32_t retval;
       
   541 
       
   542     retval = m48t59_read(NVRAM, addr);
       
   543     return retval;
       
   544 }
       
   545 
       
   546 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
       
   547 {
       
   548     m48t59_t *NVRAM = opaque;
       
   549     uint32_t retval;
       
   550 
       
   551     retval = m48t59_read(NVRAM, addr) << 8;
       
   552     retval |= m48t59_read(NVRAM, addr + 1);
       
   553     return retval;
       
   554 }
       
   555 
       
   556 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
       
   557 {
       
   558     m48t59_t *NVRAM = opaque;
       
   559     uint32_t retval;
       
   560 
       
   561     retval = m48t59_read(NVRAM, addr) << 24;
       
   562     retval |= m48t59_read(NVRAM, addr + 1) << 16;
       
   563     retval |= m48t59_read(NVRAM, addr + 2) << 8;
       
   564     retval |= m48t59_read(NVRAM, addr + 3);
       
   565     return retval;
       
   566 }
       
   567 
       
   568 static CPUWriteMemoryFunc *nvram_write[] = {
       
   569     &nvram_writeb,
       
   570     &nvram_writew,
       
   571     &nvram_writel,
       
   572 };
       
   573 
       
   574 static CPUReadMemoryFunc *nvram_read[] = {
       
   575     &nvram_readb,
       
   576     &nvram_readw,
       
   577     &nvram_readl,
       
   578 };
       
   579 
       
   580 static void m48t59_save(QEMUFile *f, void *opaque)
       
   581 {
       
   582     m48t59_t *s = opaque;
       
   583 
       
   584     qemu_put_8s(f, &s->lock);
       
   585     qemu_put_be16s(f, &s->addr);
       
   586     qemu_put_buffer(f, s->buffer, s->size);
       
   587 }
       
   588 
       
   589 static int m48t59_load(QEMUFile *f, void *opaque, int version_id)
       
   590 {
       
   591     m48t59_t *s = opaque;
       
   592 
       
   593     if (version_id != 1)
       
   594         return -EINVAL;
       
   595 
       
   596     qemu_get_8s(f, &s->lock);
       
   597     qemu_get_be16s(f, &s->addr);
       
   598     qemu_get_buffer(f, s->buffer, s->size);
       
   599 
       
   600     return 0;
       
   601 }
       
   602 
       
   603 static void m48t59_reset(void *opaque)
       
   604 {
       
   605     m48t59_t *NVRAM = opaque;
       
   606 
       
   607     if (NVRAM->alrm_timer != NULL)
       
   608         qemu_del_timer(NVRAM->alrm_timer);
       
   609 
       
   610     if (NVRAM->wd_timer != NULL)
       
   611         qemu_del_timer(NVRAM->wd_timer);
       
   612 }
       
   613 
       
   614 /* Initialisation routine */
       
   615 m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base,
       
   616                        uint32_t io_base, uint16_t size,
       
   617                        int type)
       
   618 {
       
   619     m48t59_t *s;
       
   620     target_phys_addr_t save_base;
       
   621 
       
   622     s = qemu_mallocz(sizeof(m48t59_t));
       
   623     if (!s)
       
   624 	return NULL;
       
   625     s->buffer = qemu_mallocz(size);
       
   626     if (!s->buffer) {
       
   627         qemu_free(s);
       
   628         return NULL;
       
   629     }
       
   630     s->IRQ = IRQ;
       
   631     s->size = size;
       
   632     s->io_base = io_base;
       
   633     s->addr = 0;
       
   634     s->type = type;
       
   635     if (io_base != 0) {
       
   636         register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
       
   637         register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
       
   638     }
       
   639     if (mem_base != 0) {
       
   640         s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
       
   641         cpu_register_physical_memory(mem_base, size, s->mem_index);
       
   642     }
       
   643     if (type == 59) {
       
   644         s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
       
   645         s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
       
   646     }
       
   647     s->lock = 0;
       
   648     qemu_get_timedate(&s->alarm, 0);
       
   649 
       
   650     qemu_register_reset(m48t59_reset, s);
       
   651     save_base = mem_base ? mem_base : io_base;
       
   652     register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s);
       
   653 
       
   654     return s;
       
   655 }