⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m48t59.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms *  * Copyright (c) 2003-2005 Jocelyn Mayer *  * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "vl.h"#include "m48t59.h"//#define DEBUG_NVRAM#if defined(DEBUG_NVRAM)#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)#else#define NVRAM_PRINTF(fmt, args...) do { } while (0)#endif/* * The M48T08 and M48T59 chips are very similar. The newer '59 has * alarm and a watchdog timer and related control registers. In the * PPC platform there is also a nvram lock function. */struct m48t59_t {    /* Model parameters */    int type; // 8 = m48t08, 59 = m48t59    /* Hardware parameters */    int      IRQ;    int mem_index;    uint32_t mem_base;    uint32_t io_base;    uint16_t size;    /* RTC management */    time_t   time_offset;    time_t   stop_time;    /* Alarm & watchdog */    time_t   alarm;    struct QEMUTimer *alrm_timer;    struct QEMUTimer *wd_timer;    /* NVRAM storage */    uint8_t  lock;    uint16_t addr;    uint8_t *buffer;};/* Fake timer functions *//* Generic helpers for BCD */static inline uint8_t toBCD (uint8_t value){    return (((value / 10) % 10) << 4) | (value % 10);}static inline uint8_t fromBCD (uint8_t BCD){    return ((BCD >> 4) * 10) + (BCD & 0x0F);}/* RTC management helpers */static void get_time (m48t59_t *NVRAM, struct tm *tm){    time_t t;    t = time(NULL) + NVRAM->time_offset;#ifdef _WIN32    memcpy(tm,localtime(&t),sizeof(*tm));#else    localtime_r (&t, tm) ;#endif}static void set_time (m48t59_t *NVRAM, struct tm *tm){    time_t now, new_time;        new_time = mktime(tm);    now = time(NULL);    NVRAM->time_offset = new_time - now;}/* Alarm management */static void alarm_cb (void *opaque){    struct tm tm, tm_now;    uint64_t next_time;    m48t59_t *NVRAM = opaque;    pic_set_irq(NVRAM->IRQ, 1);    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && 	(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&	(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&	(NVRAM->buffer[0x1FF2] & 0x80) == 0) {	/* Repeat once a month */	get_time(NVRAM, &tm_now);	memcpy(&tm, &tm_now, sizeof(struct tm));	tm.tm_mon++;	if (tm.tm_mon == 13) {	    tm.tm_mon = 1;	    tm.tm_year++;	}	next_time = mktime(&tm);    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&	       (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&	       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {	/* Repeat once a day */	next_time = 24 * 60 * 60 + mktime(&tm_now);    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&	       (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&	       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {	/* Repeat once an hour */	next_time = 60 * 60 + mktime(&tm_now);    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&	       (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&	       (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&	       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {	/* Repeat once a minute */	next_time = 60 + mktime(&tm_now);    } else {	/* Repeat once a second */	next_time = 1 + mktime(&tm_now);    }    qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);    pic_set_irq(NVRAM->IRQ, 0);}static void get_alarm (m48t59_t *NVRAM, struct tm *tm){#ifdef _WIN32    memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));#else    localtime_r (&NVRAM->alarm, tm);#endif}static void set_alarm (m48t59_t *NVRAM, struct tm *tm){    NVRAM->alarm = mktime(tm);    if (NVRAM->alrm_timer != NULL) {        qemu_del_timer(NVRAM->alrm_timer);	NVRAM->alrm_timer = NULL;    }    if (NVRAM->alarm - time(NULL) > 0)	qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);}/* Watchdog management */static void watchdog_cb (void *opaque){    m48t59_t *NVRAM = opaque;    NVRAM->buffer[0x1FF0] |= 0x80;    if (NVRAM->buffer[0x1FF7] & 0x80) {	NVRAM->buffer[0x1FF7] = 0x00;	NVRAM->buffer[0x1FFC] &= ~0x40;        /* May it be a hw CPU Reset instead ? */        qemu_system_reset_request();    } else {	pic_set_irq(NVRAM->IRQ, 1);	pic_set_irq(NVRAM->IRQ, 0);    }}static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value){    uint64_t interval; /* in 1/16 seconds */    if (NVRAM->wd_timer != NULL) {        qemu_del_timer(NVRAM->wd_timer);	NVRAM->wd_timer = NULL;    }    NVRAM->buffer[0x1FF0] &= ~0x80;    if (value != 0) {	interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);	qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +		       ((interval * 1000) >> 4));    }}/* Direct access to NVRAM */void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val){    struct tm tm;    int tmp;    if (addr > 0x1FF8 && addr < 0x2000)	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);    if (NVRAM->type == 8 &&         (addr >= 0x1ff0 && addr <= 0x1ff7))        goto do_write;    switch (addr) {    case 0x1FF0:        /* flags register : read-only */        break;    case 0x1FF1:        /* unused */        break;    case 0x1FF2:        /* alarm seconds */        tmp = fromBCD(val & 0x7F);        if (tmp >= 0 && tmp <= 59) {            get_alarm(NVRAM, &tm);            tm.tm_sec = tmp;            NVRAM->buffer[0x1FF2] = val;            set_alarm(NVRAM, &tm);        }        break;    case 0x1FF3:        /* alarm minutes */        tmp = fromBCD(val & 0x7F);        if (tmp >= 0 && tmp <= 59) {            get_alarm(NVRAM, &tm);            tm.tm_min = tmp;            NVRAM->buffer[0x1FF3] = val;            set_alarm(NVRAM, &tm);        }        break;    case 0x1FF4:        /* alarm hours */        tmp = fromBCD(val & 0x3F);        if (tmp >= 0 && tmp <= 23) {            get_alarm(NVRAM, &tm);            tm.tm_hour = tmp;            NVRAM->buffer[0x1FF4] = val;            set_alarm(NVRAM, &tm);        }        break;    case 0x1FF5:        /* alarm date */        tmp = fromBCD(val & 0x1F);        if (tmp != 0) {            get_alarm(NVRAM, &tm);            tm.tm_mday = tmp;            NVRAM->buffer[0x1FF5] = val;            set_alarm(NVRAM, &tm);        }        break;    case 0x1FF6:        /* interrupts */        NVRAM->buffer[0x1FF6] = val;        break;    case 0x1FF7:        /* watchdog */        NVRAM->buffer[0x1FF7] = val;        set_up_watchdog(NVRAM, val);        break;    case 0x1FF8:        /* control */	NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;        break;    case 0x1FF9:        /* seconds (BCD) */	tmp = fromBCD(val & 0x7F);	if (tmp >= 0 && tmp <= 59) {	    get_time(NVRAM, &tm);	    tm.tm_sec = tmp;	    set_time(NVRAM, &tm);	}	if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {	    if (val & 0x80) {		NVRAM->stop_time = time(NULL);	    } else {		NVRAM->time_offset += NVRAM->stop_time - time(NULL);		NVRAM->stop_time = 0;	    }	}	NVRAM->buffer[0x1FF9] = val & 0x80;        break;    case 0x1FFA:        /* minutes (BCD) */	tmp = fromBCD(val & 0x7F);	if (tmp >= 0 && tmp <= 59) {	    get_time(NVRAM, &tm);	    tm.tm_min = tmp;	    set_time(NVRAM, &tm);	}        break;    case 0x1FFB:        /* hours (BCD) */	tmp = fromBCD(val & 0x3F);	if (tmp >= 0 && tmp <= 23) {	    get_time(NVRAM, &tm);	    tm.tm_hour = tmp;	    set_time(NVRAM, &tm);	}        break;    case 0x1FFC:        /* day of the week / century */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -