Statistics
| Branch: | Revision:

root / hw / m48t08.c @ e68b9b2b

History | View | Annotate | Download (8.6 kB)

1 420557e8 bellard
/*
2 420557e8 bellard
 * QEMU M48T08 NVRAM emulation for Sparc platform
3 420557e8 bellard
 * 
4 420557e8 bellard
 * Copyright (c) 2003-2004 Jocelyn Mayer
5 420557e8 bellard
 * 
6 420557e8 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 420557e8 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 420557e8 bellard
 * in the Software without restriction, including without limitation the rights
9 420557e8 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 420557e8 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 420557e8 bellard
 * furnished to do so, subject to the following conditions:
12 420557e8 bellard
 *
13 420557e8 bellard
 * The above copyright notice and this permission notice shall be included in
14 420557e8 bellard
 * all copies or substantial portions of the Software.
15 420557e8 bellard
 *
16 420557e8 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 420557e8 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 420557e8 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 420557e8 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 420557e8 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 420557e8 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 420557e8 bellard
 * THE SOFTWARE.
23 420557e8 bellard
 */
24 420557e8 bellard
#include "vl.h"
25 420557e8 bellard
#include "m48t08.h"
26 420557e8 bellard
27 420557e8 bellard
//#define DEBUG_NVRAM
28 420557e8 bellard
29 420557e8 bellard
#if defined(DEBUG_NVRAM)
30 420557e8 bellard
#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
31 420557e8 bellard
#else
32 420557e8 bellard
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
33 420557e8 bellard
#endif
34 420557e8 bellard
35 e80cfcfc bellard
#define NVRAM_MAX_MEM 0x1ff0
36 e80cfcfc bellard
#define NVRAM_MAXADDR 0x1fff
37 420557e8 bellard
38 420557e8 bellard
struct m48t08_t {
39 420557e8 bellard
    /* RTC management */
40 420557e8 bellard
    time_t   time_offset;
41 420557e8 bellard
    time_t   stop_time;
42 420557e8 bellard
    /* NVRAM storage */
43 420557e8 bellard
    uint8_t *buffer;
44 420557e8 bellard
};
45 420557e8 bellard
46 420557e8 bellard
/* Fake timer functions */
47 420557e8 bellard
/* Generic helpers for BCD */
48 420557e8 bellard
static inline uint8_t toBCD (uint8_t value)
49 420557e8 bellard
{
50 420557e8 bellard
    return (((value / 10) % 10) << 4) | (value % 10);
51 420557e8 bellard
}
52 420557e8 bellard
53 420557e8 bellard
static inline uint8_t fromBCD (uint8_t BCD)
54 420557e8 bellard
{
55 420557e8 bellard
    return ((BCD >> 4) * 10) + (BCD & 0x0F);
56 420557e8 bellard
}
57 420557e8 bellard
58 420557e8 bellard
/* RTC management helpers */
59 420557e8 bellard
static void get_time (m48t08_t *NVRAM, struct tm *tm)
60 420557e8 bellard
{
61 420557e8 bellard
    time_t t;
62 420557e8 bellard
63 420557e8 bellard
    t = time(NULL) + NVRAM->time_offset;
64 420557e8 bellard
#ifdef _WIN32
65 420557e8 bellard
    memcpy(tm,localtime(&t),sizeof(*tm));
66 420557e8 bellard
#else
67 420557e8 bellard
    localtime_r (&t, tm) ;
68 420557e8 bellard
#endif
69 420557e8 bellard
}
70 420557e8 bellard
71 420557e8 bellard
static void set_time (m48t08_t *NVRAM, struct tm *tm)
72 420557e8 bellard
{
73 420557e8 bellard
    time_t now, new_time;
74 420557e8 bellard
    
75 420557e8 bellard
    new_time = mktime(tm);
76 420557e8 bellard
    now = time(NULL);
77 420557e8 bellard
    NVRAM->time_offset = new_time - now;
78 420557e8 bellard
}
79 420557e8 bellard
80 420557e8 bellard
/* Direct access to NVRAM */
81 e80cfcfc bellard
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
82 420557e8 bellard
{
83 420557e8 bellard
    struct tm tm;
84 420557e8 bellard
    int tmp;
85 420557e8 bellard
86 e80cfcfc bellard
    addr &= NVRAM_MAXADDR;
87 e80cfcfc bellard
    switch (addr) {
88 420557e8 bellard
    case 0x1FF8:
89 420557e8 bellard
        /* control */
90 420557e8 bellard
        NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
91 420557e8 bellard
        break;
92 420557e8 bellard
    case 0x1FF9:
93 420557e8 bellard
        /* seconds (BCD) */
94 420557e8 bellard
        tmp = fromBCD(val & 0x7F);
95 420557e8 bellard
        if (tmp >= 0 && tmp <= 59) {
96 420557e8 bellard
            get_time(NVRAM, &tm);
97 420557e8 bellard
            tm.tm_sec = tmp;
98 420557e8 bellard
            set_time(NVRAM, &tm);
99 420557e8 bellard
        }
100 420557e8 bellard
        if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
101 420557e8 bellard
            if (val & 0x80) {
102 420557e8 bellard
                NVRAM->stop_time = time(NULL);
103 420557e8 bellard
            } else {
104 420557e8 bellard
                NVRAM->time_offset += NVRAM->stop_time - time(NULL);
105 420557e8 bellard
                NVRAM->stop_time = 0;
106 420557e8 bellard
            }
107 420557e8 bellard
        }
108 420557e8 bellard
        NVRAM->buffer[0x1FF9] = val & 0x80;
109 420557e8 bellard
        break;
110 420557e8 bellard
    case 0x1FFA:
111 420557e8 bellard
        /* minutes (BCD) */
112 420557e8 bellard
        tmp = fromBCD(val & 0x7F);
113 420557e8 bellard
        if (tmp >= 0 && tmp <= 59) {
114 420557e8 bellard
            get_time(NVRAM, &tm);
115 420557e8 bellard
            tm.tm_min = tmp;
116 420557e8 bellard
            set_time(NVRAM, &tm);
117 420557e8 bellard
        }
118 420557e8 bellard
        break;
119 420557e8 bellard
    case 0x1FFB:
120 420557e8 bellard
        /* hours (BCD) */
121 420557e8 bellard
        tmp = fromBCD(val & 0x3F);
122 420557e8 bellard
        if (tmp >= 0 && tmp <= 23) {
123 420557e8 bellard
            get_time(NVRAM, &tm);
124 420557e8 bellard
            tm.tm_hour = tmp;
125 420557e8 bellard
            set_time(NVRAM, &tm);
126 420557e8 bellard
        }
127 420557e8 bellard
        break;
128 420557e8 bellard
    case 0x1FFC:
129 420557e8 bellard
        /* day of the week / century */
130 420557e8 bellard
        tmp = fromBCD(val & 0x07);
131 420557e8 bellard
        get_time(NVRAM, &tm);
132 420557e8 bellard
        tm.tm_wday = tmp;
133 420557e8 bellard
        set_time(NVRAM, &tm);
134 420557e8 bellard
        NVRAM->buffer[0x1FFC] = val & 0x40;
135 420557e8 bellard
        break;
136 420557e8 bellard
    case 0x1FFD:
137 420557e8 bellard
        /* date */
138 420557e8 bellard
        tmp = fromBCD(val & 0x1F);
139 420557e8 bellard
        if (tmp != 0) {
140 420557e8 bellard
            get_time(NVRAM, &tm);
141 420557e8 bellard
            tm.tm_mday = tmp;
142 420557e8 bellard
            set_time(NVRAM, &tm);
143 420557e8 bellard
        }
144 420557e8 bellard
        break;
145 420557e8 bellard
    case 0x1FFE:
146 420557e8 bellard
        /* month */
147 420557e8 bellard
        tmp = fromBCD(val & 0x1F);
148 420557e8 bellard
        if (tmp >= 1 && tmp <= 12) {
149 420557e8 bellard
            get_time(NVRAM, &tm);
150 420557e8 bellard
            tm.tm_mon = tmp - 1;
151 420557e8 bellard
            set_time(NVRAM, &tm);
152 420557e8 bellard
        }
153 420557e8 bellard
        break;
154 420557e8 bellard
    case 0x1FFF:
155 420557e8 bellard
        /* year */
156 420557e8 bellard
        tmp = fromBCD(val);
157 420557e8 bellard
        if (tmp >= 0 && tmp <= 99) {
158 420557e8 bellard
            get_time(NVRAM, &tm);
159 420557e8 bellard
            tm.tm_year = fromBCD(val);
160 420557e8 bellard
            set_time(NVRAM, &tm);
161 420557e8 bellard
        }
162 420557e8 bellard
        break;
163 420557e8 bellard
    default:
164 e80cfcfc bellard
        NVRAM->buffer[addr] = val & 0xFF;
165 420557e8 bellard
        break;
166 420557e8 bellard
    }
167 420557e8 bellard
}
168 420557e8 bellard
169 e80cfcfc bellard
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
170 420557e8 bellard
{
171 420557e8 bellard
    struct tm tm;
172 e80cfcfc bellard
    uint8_t retval = 0xFF;
173 420557e8 bellard
174 e80cfcfc bellard
    addr &= NVRAM_MAXADDR;
175 e80cfcfc bellard
    switch (addr) {
176 420557e8 bellard
    case 0x1FF8:
177 420557e8 bellard
        /* control */
178 420557e8 bellard
        goto do_read;
179 420557e8 bellard
    case 0x1FF9:
180 420557e8 bellard
        /* seconds (BCD) */
181 420557e8 bellard
        get_time(NVRAM, &tm);
182 420557e8 bellard
        retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
183 420557e8 bellard
        break;
184 420557e8 bellard
    case 0x1FFA:
185 420557e8 bellard
        /* minutes (BCD) */
186 420557e8 bellard
        get_time(NVRAM, &tm);
187 420557e8 bellard
        retval = toBCD(tm.tm_min);
188 420557e8 bellard
        break;
189 420557e8 bellard
    case 0x1FFB:
190 420557e8 bellard
        /* hours (BCD) */
191 420557e8 bellard
        get_time(NVRAM, &tm);
192 420557e8 bellard
        retval = toBCD(tm.tm_hour);
193 420557e8 bellard
        break;
194 420557e8 bellard
    case 0x1FFC:
195 420557e8 bellard
        /* day of the week / century */
196 420557e8 bellard
        get_time(NVRAM, &tm);
197 420557e8 bellard
        retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
198 420557e8 bellard
        break;
199 420557e8 bellard
    case 0x1FFD:
200 420557e8 bellard
        /* date */
201 420557e8 bellard
        get_time(NVRAM, &tm);
202 420557e8 bellard
        retval = toBCD(tm.tm_mday);
203 420557e8 bellard
        break;
204 420557e8 bellard
    case 0x1FFE:
205 420557e8 bellard
        /* month */
206 420557e8 bellard
        get_time(NVRAM, &tm);
207 420557e8 bellard
        retval = toBCD(tm.tm_mon + 1);
208 420557e8 bellard
        break;
209 420557e8 bellard
    case 0x1FFF:
210 420557e8 bellard
        /* year */
211 420557e8 bellard
        get_time(NVRAM, &tm);
212 420557e8 bellard
        retval = toBCD(tm.tm_year);
213 420557e8 bellard
        break;
214 420557e8 bellard
    default:
215 e80cfcfc bellard
    do_read:
216 e80cfcfc bellard
        retval = NVRAM->buffer[addr];
217 420557e8 bellard
        break;
218 420557e8 bellard
    }
219 420557e8 bellard
    return retval;
220 420557e8 bellard
}
221 420557e8 bellard
222 420557e8 bellard
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
223 420557e8 bellard
{
224 420557e8 bellard
    m48t08_t *NVRAM = opaque;
225 420557e8 bellard
    
226 e80cfcfc bellard
    m48t08_write(NVRAM, addr, value);
227 420557e8 bellard
}
228 420557e8 bellard
229 420557e8 bellard
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
230 420557e8 bellard
{
231 420557e8 bellard
    m48t08_t *NVRAM = opaque;
232 420557e8 bellard
    
233 e80cfcfc bellard
    m48t08_write(NVRAM, addr, value);
234 e80cfcfc bellard
    m48t08_write(NVRAM, addr + 1, value >> 8);
235 420557e8 bellard
}
236 420557e8 bellard
237 420557e8 bellard
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
238 420557e8 bellard
{
239 420557e8 bellard
    m48t08_t *NVRAM = opaque;
240 420557e8 bellard
    
241 e80cfcfc bellard
    m48t08_write(NVRAM, addr, value);
242 e80cfcfc bellard
    m48t08_write(NVRAM, addr + 1, value >> 8);
243 e80cfcfc bellard
    m48t08_write(NVRAM, addr + 2, value >> 16);
244 e80cfcfc bellard
    m48t08_write(NVRAM, addr + 3, value >> 24);
245 420557e8 bellard
}
246 420557e8 bellard
247 420557e8 bellard
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
248 420557e8 bellard
{
249 420557e8 bellard
    m48t08_t *NVRAM = opaque;
250 420557e8 bellard
    uint32_t retval = 0;
251 420557e8 bellard
    
252 e80cfcfc bellard
    retval = m48t08_read(NVRAM, addr);
253 420557e8 bellard
    return retval;
254 420557e8 bellard
}
255 420557e8 bellard
256 420557e8 bellard
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
257 420557e8 bellard
{
258 420557e8 bellard
    m48t08_t *NVRAM = opaque;
259 420557e8 bellard
    uint32_t retval = 0;
260 420557e8 bellard
    
261 e80cfcfc bellard
    retval = m48t08_read(NVRAM, addr) << 8;
262 e80cfcfc bellard
    retval |= m48t08_read(NVRAM, addr + 1);
263 420557e8 bellard
    return retval;
264 420557e8 bellard
}
265 420557e8 bellard
266 420557e8 bellard
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
267 420557e8 bellard
{
268 420557e8 bellard
    m48t08_t *NVRAM = opaque;
269 420557e8 bellard
    uint32_t retval = 0;
270 420557e8 bellard
    
271 e80cfcfc bellard
    retval = m48t08_read(NVRAM, addr) << 24;
272 e80cfcfc bellard
    retval |= m48t08_read(NVRAM, addr + 1) << 16;
273 e80cfcfc bellard
    retval |= m48t08_read(NVRAM, addr + 2) << 8;
274 e80cfcfc bellard
    retval |= m48t08_read(NVRAM, addr + 3);
275 420557e8 bellard
    return retval;
276 420557e8 bellard
}
277 420557e8 bellard
278 420557e8 bellard
static CPUWriteMemoryFunc *nvram_write[] = {
279 420557e8 bellard
    &nvram_writeb,
280 420557e8 bellard
    &nvram_writew,
281 420557e8 bellard
    &nvram_writel,
282 420557e8 bellard
};
283 420557e8 bellard
284 420557e8 bellard
static CPUReadMemoryFunc *nvram_read[] = {
285 420557e8 bellard
    &nvram_readb,
286 420557e8 bellard
    &nvram_readw,
287 420557e8 bellard
    &nvram_readl,
288 420557e8 bellard
};
289 420557e8 bellard
290 e80cfcfc bellard
static void nvram_save(QEMUFile *f, void *opaque)
291 e80cfcfc bellard
{
292 e80cfcfc bellard
    m48t08_t *s = opaque;
293 e80cfcfc bellard
    
294 e80cfcfc bellard
    qemu_put_be32s(f, (uint32_t *)&s->time_offset);
295 e80cfcfc bellard
    qemu_put_be32s(f, (uint32_t *)&s->stop_time);
296 e80cfcfc bellard
    qemu_put_buffer(f, s->buffer, 0x2000);
297 e80cfcfc bellard
}
298 e80cfcfc bellard
299 e80cfcfc bellard
static int nvram_load(QEMUFile *f, void *opaque, int version_id)
300 e80cfcfc bellard
{
301 e80cfcfc bellard
    m48t08_t *s = opaque;
302 e80cfcfc bellard
    
303 e80cfcfc bellard
    if (version_id != 1)
304 e80cfcfc bellard
        return -EINVAL;
305 e80cfcfc bellard
306 e80cfcfc bellard
    qemu_get_be32s(f, (uint32_t *)&s->time_offset);
307 e80cfcfc bellard
    qemu_get_be32s(f, (uint32_t *)&s->stop_time);
308 e80cfcfc bellard
    qemu_get_buffer(f, s->buffer, 0x2000);
309 e80cfcfc bellard
    return 0;
310 e80cfcfc bellard
}
311 e80cfcfc bellard
312 e80cfcfc bellard
static void m48t08_reset(void *opaque)
313 e80cfcfc bellard
{
314 e80cfcfc bellard
    m48t08_t *s = opaque;
315 e80cfcfc bellard
316 e80cfcfc bellard
    s->time_offset = 0;
317 e80cfcfc bellard
    s->stop_time = 0;
318 e80cfcfc bellard
}
319 e80cfcfc bellard
320 e80cfcfc bellard
321 420557e8 bellard
/* Initialisation routine */
322 e80cfcfc bellard
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
323 420557e8 bellard
{
324 420557e8 bellard
    m48t08_t *s;
325 e80cfcfc bellard
    int mem_index;
326 420557e8 bellard
327 420557e8 bellard
    s = qemu_mallocz(sizeof(m48t08_t));
328 420557e8 bellard
    if (!s)
329 420557e8 bellard
        return NULL;
330 420557e8 bellard
    s->buffer = qemu_mallocz(size);
331 420557e8 bellard
    if (!s->buffer) {
332 420557e8 bellard
        qemu_free(s);
333 420557e8 bellard
        return NULL;
334 420557e8 bellard
    }
335 420557e8 bellard
    if (mem_base != 0) {
336 e80cfcfc bellard
        mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
337 e80cfcfc bellard
        cpu_register_physical_memory(mem_base, 0x2000, mem_index);
338 420557e8 bellard
    }
339 420557e8 bellard
340 e80cfcfc bellard
    register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
341 e80cfcfc bellard
    qemu_register_reset(m48t08_reset, s);
342 420557e8 bellard
    return s;
343 420557e8 bellard
}
344 420557e8 bellard
345 420557e8 bellard
#if 0
346 420557e8 bellard
struct idprom
347 420557e8 bellard
{
348 420557e8 bellard
        unsigned char   id_format;      /* Format identifier (always 0x01) */
349 420557e8 bellard
        unsigned char   id_machtype;    /* Machine type */
350 420557e8 bellard
        unsigned char   id_ethaddr[6];  /* Hardware ethernet address */
351 420557e8 bellard
        long            id_date;        /* Date of manufacture */
352 420557e8 bellard
        unsigned int    id_sernum:24;   /* Unique serial number */
353 420557e8 bellard
        unsigned char   id_cksum;       /* Checksum - xor of the data bytes */
354 420557e8 bellard
        unsigned char   reserved[16];
355 420557e8 bellard
};
356 420557e8 bellard
#endif