1 |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
6 |
* |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* 3. The name of the author may not be used to endorse or promote products |
13 |
* derived from this software without specific prior written permission. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* |
28 |
* $Id: dev_mc146818.c,v 1.68 2005/02/07 05:51:54 debug Exp $ |
29 |
* |
30 |
* MC146818 real-time clock, used by many different machines types. |
31 |
* (DS1687 as used in some SGI machines is similar to MC146818.) |
32 |
* |
33 |
* This device contains Date/time, the machine's ethernet address (on |
34 |
* DECstation 3100), and can cause periodic (hardware) interrupts. |
35 |
* |
36 |
* NOTE: Many register offsets are multiplied by 4 in this code; this is |
37 |
* because I originally wrote it for DECstation 3100 emulation, where the |
38 |
* registered are spaced that way. |
39 |
*/ |
40 |
|
41 |
#include <stdio.h> |
42 |
#include <stdlib.h> |
43 |
#include <string.h> |
44 |
#include <time.h> |
45 |
|
46 |
#include "cpu.h" |
47 |
#include "devices.h" |
48 |
#include "machine.h" |
49 |
#include "memory.h" |
50 |
#include "misc.h" |
51 |
|
52 |
#include "mc146818reg.h" |
53 |
|
54 |
|
55 |
#define to_bcd(x) ( ((x)/10) * 16 + ((x)%10) ) |
56 |
|
57 |
/* #define MC146818_DEBUG */ |
58 |
|
59 |
#define TICK_STEPS_SHIFT 14 |
60 |
|
61 |
|
62 |
/* 256 on DECstation, SGI uses reg at 72*4 as the Century */ |
63 |
#define N_REGISTERS 1024 |
64 |
struct mc_data { |
65 |
int access_style; |
66 |
int last_addr; |
67 |
|
68 |
int register_choice; |
69 |
int reg[N_REGISTERS]; |
70 |
int addrdiv; |
71 |
|
72 |
int use_bcd; |
73 |
|
74 |
int timebase_hz; |
75 |
int interrupt_hz; |
76 |
int irq_nr; |
77 |
|
78 |
int previous_second; |
79 |
|
80 |
int interrupt_every_x_cycles; |
81 |
int cycles_left_until_interrupt; |
82 |
}; |
83 |
|
84 |
|
85 |
/* |
86 |
* recalc_interrupt_cycle(): |
87 |
* |
88 |
* If automatic_clock_adjustment is turned on, then emulated_hz is modified |
89 |
* dynamically. We have to recalculate how often interrupts are to be |
90 |
* triggered. |
91 |
*/ |
92 |
static void recalc_interrupt_cycle(struct cpu *cpu, struct mc_data *d) |
93 |
{ |
94 |
int64_t emulated_hz = cpu->machine->emulated_hz; |
95 |
#if 0 |
96 |
static int warning_printed = 0; |
97 |
|
98 |
/* |
99 |
* A hack to make Ultrix run, even on very fast host machines. |
100 |
* |
101 |
* (Ultrix was probably never meant to be run on machines with |
102 |
* faster CPUs than around 33 MHz or so.) |
103 |
*/ |
104 |
if (d->access_style == MC146818_DEC && emulated_hz > 30000000) { |
105 |
if (!warning_printed) { |
106 |
fatal("\n*********************************************" |
107 |
"**********************************\n\n Your hos" |
108 |
"t machine is too fast! The emulated CPU speed wil" |
109 |
"l be limited to\n 30 MHz, and clocks inside the" |
110 |
" emulated environment might go faster than\n in" |
111 |
" the real world. You have been warned.\n\n******" |
112 |
"*************************************************" |
113 |
"************************\n\n"); |
114 |
warning_printed = 1; |
115 |
} |
116 |
|
117 |
emulated_hz = 30000000; |
118 |
} |
119 |
#endif |
120 |
|
121 |
if (d->interrupt_hz > 0) |
122 |
d->interrupt_every_x_cycles = |
123 |
emulated_hz / d->interrupt_hz; |
124 |
else |
125 |
d->interrupt_every_x_cycles = 0; |
126 |
} |
127 |
|
128 |
|
129 |
/* |
130 |
* dev_mc146818_tick(): |
131 |
*/ |
132 |
void dev_mc146818_tick(struct cpu *cpu, void *extra) |
133 |
{ |
134 |
struct mc_data *d = extra; |
135 |
|
136 |
if (d == NULL) |
137 |
return; |
138 |
|
139 |
recalc_interrupt_cycle(cpu, d); |
140 |
|
141 |
if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && |
142 |
d->interrupt_every_x_cycles > 0) { |
143 |
d->cycles_left_until_interrupt -= |
144 |
(1 << TICK_STEPS_SHIFT); |
145 |
|
146 |
if (d->cycles_left_until_interrupt < 0 || |
147 |
d->cycles_left_until_interrupt >= |
148 |
d->interrupt_every_x_cycles) { |
149 |
/* debug("[ rtc interrupt (every %i cycles) ]\n", |
150 |
d->interrupt_every_x_cycles); */ |
151 |
cpu_interrupt(cpu, d->irq_nr); |
152 |
|
153 |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
154 |
|
155 |
/* Reset the cycle countdown: */ |
156 |
while (d->cycles_left_until_interrupt < 0) |
157 |
d->cycles_left_until_interrupt += |
158 |
d->interrupt_every_x_cycles; |
159 |
} |
160 |
} |
161 |
|
162 |
if (d->reg[MC_REGC * 4] & MC_REGC_UF || |
163 |
d->reg[MC_REGC * 4] & MC_REGC_AF || |
164 |
d->reg[MC_REGC * 4] & MC_REGC_PF) |
165 |
d->reg[MC_REGC * 4] |= MC_REGC_IRQF; |
166 |
} |
167 |
|
168 |
|
169 |
/* |
170 |
* dev_mc146818_jazz_access(): |
171 |
* |
172 |
* It seems like JAZZ machines accesses the mc146818 by writing one byte to |
173 |
* 0x90000070 and then reading or writing another byte at 0x......0004000. |
174 |
*/ |
175 |
int dev_mc146818_jazz_access(struct cpu *cpu, struct memory *mem, |
176 |
uint64_t relative_addr, unsigned char *data, size_t len, |
177 |
int writeflag, void *extra) |
178 |
{ |
179 |
struct mc_data *d = extra; |
180 |
|
181 |
#ifdef MC146818_DEBUG |
182 |
if (writeflag == MEM_WRITE) { |
183 |
int i; |
184 |
fatal("[ mc146818_jazz: write to addr=0x%04x: ", |
185 |
(int)relative_addr); |
186 |
for (i=0; i<len; i++) |
187 |
fatal("%02x ", data[i]); |
188 |
fatal("]\n"); |
189 |
} else |
190 |
fatal("[ mc146818_jazz: read from addr=0x%04x ]\n", |
191 |
(int)relative_addr); |
192 |
#endif |
193 |
|
194 |
if (writeflag == MEM_WRITE) { |
195 |
d->last_addr = data[0]; |
196 |
return 1; |
197 |
} else { |
198 |
data[0] = d->last_addr; |
199 |
return 1; |
200 |
} |
201 |
} |
202 |
|
203 |
|
204 |
/* |
205 |
* mc146818_update_time(): |
206 |
* |
207 |
* This function updates the MC146818 registers by reading |
208 |
* the host's clock. |
209 |
*/ |
210 |
static void mc146818_update_time(struct mc_data *d) |
211 |
{ |
212 |
struct tm *tmp; |
213 |
time_t timet; |
214 |
|
215 |
timet = time(NULL); |
216 |
tmp = gmtime(&timet); |
217 |
|
218 |
d->reg[4 * MC_SEC] = tmp->tm_sec; |
219 |
d->reg[4 * MC_MIN] = tmp->tm_min; |
220 |
d->reg[4 * MC_HOUR] = tmp->tm_hour; |
221 |
d->reg[4 * MC_DOW] = tmp->tm_wday + 1; |
222 |
d->reg[4 * MC_DOM] = tmp->tm_mday; |
223 |
d->reg[4 * MC_MONTH] = tmp->tm_mon + 1; |
224 |
d->reg[4 * MC_YEAR] = tmp->tm_year; |
225 |
|
226 |
switch (d->access_style) { |
227 |
case MC146818_ARC_NEC: |
228 |
d->reg[4 * MC_YEAR] += (0x18 - 104); |
229 |
break; |
230 |
case MC146818_SGI: |
231 |
/* |
232 |
* NetBSD/sgimips assumes data in BCD format. |
233 |
* Also, IRIX stores the year value in a weird |
234 |
* format, according to ../arch/sgimips/sgimips/clockvar.h |
235 |
* in NetBSD: |
236 |
* |
237 |
* "If year < 1985, store (year - 1970), else |
238 |
* (year - 1940). This matches IRIX semantics." |
239 |
* |
240 |
* Another rule: It seems that a real SGI IP32 box |
241 |
* uses the value 5 for the year 2005. |
242 |
*/ |
243 |
d->reg[4 * MC_YEAR] = |
244 |
d->reg[4 * MC_YEAR] >= 100 ? |
245 |
(d->reg[4 * MC_YEAR] - 100) : |
246 |
( |
247 |
d->reg[4 * MC_YEAR] < 85 ? |
248 |
(d->reg[4 * MC_YEAR] - 30 + 40) |
249 |
: (d->reg[4 * MC_YEAR] - 40) |
250 |
); |
251 |
|
252 |
/* Century: */ |
253 |
d->reg[72 * 4] = 19 + (tmp->tm_year / 100); |
254 |
|
255 |
break; |
256 |
case MC146818_DEC: |
257 |
/* |
258 |
* DECstations must have 72 or 73 in the |
259 |
* Year field, or Ultrix screems. (Weird.) |
260 |
*/ |
261 |
d->reg[4 * MC_YEAR] = 72; |
262 |
|
263 |
/* |
264 |
* Linux on DECstation stores the year in register 63, |
265 |
* but no other DECstation OS does? (Hm.) |
266 |
*/ |
267 |
d->reg[4 * 63] = tmp->tm_year - 100; |
268 |
break; |
269 |
} |
270 |
|
271 |
if (d->use_bcd) { |
272 |
d->reg[4 * MC_SEC] = to_bcd(d->reg[4 * MC_SEC]); |
273 |
d->reg[4 * MC_MIN] = to_bcd(d->reg[4 * MC_MIN]); |
274 |
d->reg[4 * MC_HOUR] = to_bcd(d->reg[4 * MC_HOUR]); |
275 |
d->reg[4 * MC_DOW] = to_bcd(d->reg[4 * MC_DOW]); |
276 |
d->reg[4 * MC_DOM] = to_bcd(d->reg[4 * MC_DOM]); |
277 |
d->reg[4 * MC_MONTH] = to_bcd(d->reg[4 * MC_MONTH]); |
278 |
d->reg[4 * MC_YEAR] = to_bcd(d->reg[4 * MC_YEAR]); |
279 |
|
280 |
/* Used by Linux on DECstation: (Hm) */ |
281 |
d->reg[4 * 63] = to_bcd(d->reg[4 * 63]); |
282 |
|
283 |
/* Used on SGI: */ |
284 |
d->reg[4 * 72] = to_bcd(d->reg[4 * 72]); |
285 |
} |
286 |
} |
287 |
|
288 |
|
289 |
/* |
290 |
* dev_mc146818_access(): |
291 |
* |
292 |
* TODO: This access function only handles 8-bit accesses! |
293 |
*/ |
294 |
int dev_mc146818_access(struct cpu *cpu, struct memory *mem, |
295 |
uint64_t r, unsigned char *data, size_t len, |
296 |
int writeflag, void *extra) |
297 |
{ |
298 |
struct tm *tmp; |
299 |
time_t timet; |
300 |
struct mc_data *d = extra; |
301 |
int i, relative_addr = r; |
302 |
|
303 |
relative_addr /= d->addrdiv; |
304 |
|
305 |
/* Different ways of accessing the registers: */ |
306 |
switch (d->access_style) { |
307 |
case MC146818_PC_CMOS: |
308 |
if (relative_addr == 0x70 || relative_addr == 0x00) { |
309 |
if (writeflag == MEM_WRITE) { |
310 |
d->last_addr = data[0]; |
311 |
return 1; |
312 |
} else { |
313 |
data[0] = d->last_addr; |
314 |
return 1; |
315 |
} |
316 |
} else if (relative_addr == 0x71 || relative_addr == 0x01) |
317 |
relative_addr = d->last_addr * 4; |
318 |
else { |
319 |
fatal("[ mc146818: not accessed as an " |
320 |
"MC146818_PC_CMOS device! ]\n"); |
321 |
} |
322 |
break; |
323 |
case MC146818_ARC_NEC: |
324 |
if (relative_addr == 0x01) { |
325 |
if (writeflag == MEM_WRITE) { |
326 |
d->last_addr = data[0]; |
327 |
return 1; |
328 |
} else { |
329 |
data[0] = d->last_addr; |
330 |
return 1; |
331 |
} |
332 |
} else if (relative_addr == 0x00) |
333 |
relative_addr = d->last_addr * 4; |
334 |
else { |
335 |
fatal("[ mc146818: not accessed as an " |
336 |
"MC146818_ARC_NEC device! ]\n"); |
337 |
} |
338 |
break; |
339 |
case MC146818_ARC_JAZZ: |
340 |
/* See comment for dev_mc146818_jazz_access(). */ |
341 |
relative_addr = d->last_addr * 4; |
342 |
break; |
343 |
case MC146818_DEC: |
344 |
case MC146818_SGI: |
345 |
/* |
346 |
* This device was originally written for DECstation |
347 |
* emulation, so no changes are necessary for that access |
348 |
* style. |
349 |
* |
350 |
* SGI access bytes 0x0..0xd at offsets 0x0yz..0xdyz, where yz |
351 |
* should be ignored. It works _almost_ as DEC, if offsets are |
352 |
* divided by 0x40. |
353 |
*/ |
354 |
default: |
355 |
; |
356 |
} |
357 |
|
358 |
#ifdef MC146818_DEBUG |
359 |
if (writeflag == MEM_WRITE) { |
360 |
fatal("[ mc146818: write to addr=0x%04x (len %i): ", |
361 |
(int)relative_addr, (int)len); |
362 |
for (i=0; i<len; i++) |
363 |
fatal("%02x ", data[i]); |
364 |
fatal("]\n"); |
365 |
} |
366 |
#endif |
367 |
|
368 |
/* |
369 |
* For some reason, Linux/sgimips relies on the UIP bit to go |
370 |
* on and off. Without this code, booting Linux takes forever: |
371 |
*/ |
372 |
d->reg[MC_REGA * 4] &= ~MC_REGA_UIP; |
373 |
#if 1 |
374 |
/* TODO: solve this more nicely */ |
375 |
if ((random() & 0xff) == 0) |
376 |
d->reg[MC_REGA * 4] ^= MC_REGA_UIP; |
377 |
#endif |
378 |
|
379 |
/* |
380 |
* Sprite seens to wants UF interrupt status, once every second, or |
381 |
* it hangs forever during bootup. (These do not cause interrupts, |
382 |
* but it is good enough... Sprite polls this, iirc.) |
383 |
*/ |
384 |
timet = time(NULL); |
385 |
tmp = gmtime(&timet); |
386 |
d->reg[MC_REGC * 4] &= ~MC_REGC_UF; |
387 |
if (tmp->tm_sec != d->previous_second) { |
388 |
d->reg[MC_REGC * 4] |= MC_REGC_UF; |
389 |
d->reg[MC_REGC * 4] |= MC_REGC_IRQF; |
390 |
d->previous_second = tmp->tm_sec; |
391 |
|
392 |
/* For some reason, some Linux/DECstation KN04 kernels want |
393 |
the PF (periodic flag) bit set, even though interrupts |
394 |
are not enabled? */ |
395 |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
396 |
} |
397 |
|
398 |
/* RTC data is in either BCD format or binary: */ |
399 |
if (d->use_bcd) { |
400 |
d->reg[MC_REGB * 4] &= ~(1 << 2); |
401 |
} else { |
402 |
d->reg[MC_REGB * 4] |= (1 << 2); |
403 |
} |
404 |
|
405 |
/* RTC date/time is always Valid: */ |
406 |
d->reg[MC_REGD * 4] |= MC_REGD_VRT; |
407 |
|
408 |
if (writeflag == MEM_WRITE) { |
409 |
/* WRITE: */ |
410 |
switch (relative_addr) { |
411 |
case MC_REGA*4: |
412 |
if ((data[0] & MC_REGA_DVMASK) == MC_BASE_32_KHz) |
413 |
d->timebase_hz = 32000; |
414 |
if ((data[0] & MC_REGA_DVMASK) == MC_BASE_1_MHz) |
415 |
d->timebase_hz = 1000000; |
416 |
if ((data[0] & MC_REGA_DVMASK) == MC_BASE_4_MHz) |
417 |
d->timebase_hz = 4000000; |
418 |
switch (data[0] & MC_REGA_RSMASK) { |
419 |
case MC_RATE_NONE: |
420 |
d->interrupt_hz = 0; |
421 |
break; |
422 |
case MC_RATE_1: |
423 |
if (d->timebase_hz == 32000) |
424 |
d->interrupt_hz = 256; |
425 |
else |
426 |
d->interrupt_hz = 32768; |
427 |
break; |
428 |
case MC_RATE_2: |
429 |
if (d->timebase_hz == 32000) |
430 |
d->interrupt_hz = 128; |
431 |
else |
432 |
d->interrupt_hz = 16384; |
433 |
break; |
434 |
case MC_RATE_8192_Hz: d->interrupt_hz = 8192; break; |
435 |
case MC_RATE_4096_Hz: d->interrupt_hz = 4096; break; |
436 |
case MC_RATE_2048_Hz: d->interrupt_hz = 2048; break; |
437 |
case MC_RATE_1024_Hz: d->interrupt_hz = 1024; break; |
438 |
case MC_RATE_512_Hz: d->interrupt_hz = 512; break; |
439 |
case MC_RATE_256_Hz: d->interrupt_hz = 256; break; |
440 |
case MC_RATE_128_Hz: d->interrupt_hz = 128; break; |
441 |
case MC_RATE_64_Hz: d->interrupt_hz = 64; break; |
442 |
case MC_RATE_32_Hz: d->interrupt_hz = 32; break; |
443 |
case MC_RATE_16_Hz: d->interrupt_hz = 16; break; |
444 |
case MC_RATE_8_Hz: d->interrupt_hz = 8; break; |
445 |
case MC_RATE_4_Hz: d->interrupt_hz = 4; break; |
446 |
case MC_RATE_2_Hz: d->interrupt_hz = 2; break; |
447 |
default: |
448 |
/* debug("[ mc146818: unimplemented " |
449 |
"MC_REGA RS: %i ]\n", |
450 |
data[0] & MC_REGA_RSMASK); */ |
451 |
; |
452 |
} |
453 |
|
454 |
recalc_interrupt_cycle(cpu, d); |
455 |
|
456 |
d->cycles_left_until_interrupt = |
457 |
d->interrupt_every_x_cycles; |
458 |
|
459 |
d->reg[MC_REGA * 4] = |
460 |
data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK); |
461 |
|
462 |
debug("[ rtc set to interrupt every %i:th cycle ]\n", |
463 |
d->interrupt_every_x_cycles); |
464 |
break; |
465 |
case MC_REGB*4: |
466 |
if (((data[0] ^ d->reg[MC_REGB*4]) & MC_REGB_PIE)) |
467 |
d->cycles_left_until_interrupt = |
468 |
d->interrupt_every_x_cycles; |
469 |
d->reg[MC_REGB*4] = data[0]; |
470 |
if (!(data[0] & MC_REGB_PIE)) { |
471 |
cpu_interrupt_ack(cpu, d->irq_nr); |
472 |
/* d->cycles_left_until_interrupt = |
473 |
d->interrupt_every_x_cycles; */ |
474 |
} |
475 |
/* debug("[ mc146818: write to MC_REGB, data[0] " |
476 |
"= 0x%02x ]\n", data[0]); */ |
477 |
break; |
478 |
case MC_REGC*4: |
479 |
d->reg[MC_REGC * 4] = data[0]; |
480 |
debug("[ mc146818: write to MC_REGC, data[0] = " |
481 |
"0x%02x ]\n", data[0]); |
482 |
break; |
483 |
case 0x128: |
484 |
d->reg[relative_addr] = data[0]; |
485 |
if (data[0] & 8) { |
486 |
/* Used on SGI to power off the machine. */ |
487 |
fatal("[ md146818: power off ]\n"); |
488 |
for (i=0; i<cpu->machine->ncpus; i++) |
489 |
cpu->machine->cpus[i]->running = 0; |
490 |
cpu->machine-> |
491 |
exit_without_entering_debugger = 1; |
492 |
} |
493 |
break; |
494 |
default: |
495 |
d->reg[relative_addr] = data[0]; |
496 |
|
497 |
debug("[ mc146818: unimplemented write to " |
498 |
"relative_addr = %08lx: ", (long)relative_addr); |
499 |
for (i=0; i<len; i++) |
500 |
debug("%02x ", data[i]); |
501 |
debug("]\n"); |
502 |
} |
503 |
} else { |
504 |
/* READ: */ |
505 |
switch (relative_addr) { |
506 |
case 0x01: /* Station's ethernet address (6 bytes) */ |
507 |
case 0x05: /* (on DECstation 3100) */ |
508 |
case 0x09: |
509 |
case 0x0d: |
510 |
case 0x11: |
511 |
case 0x15: |
512 |
break; |
513 |
case 4 * MC_SEC: |
514 |
case 4 * MC_MIN: |
515 |
case 4 * MC_HOUR: |
516 |
case 4 * MC_DOW: |
517 |
case 4 * MC_DOM: |
518 |
case 4 * MC_MONTH: |
519 |
case 4 * MC_YEAR: |
520 |
case 4 * 63: /* 63 is used by Linux on DECstation */ |
521 |
case 4 * 72: /* 72 is Century, on SGI (DS1687) */ |
522 |
/* |
523 |
* If the SET bit is set, then we don't automatically |
524 |
* update the values. Otherwise, we update them by |
525 |
* reading from the host's clock: |
526 |
*/ |
527 |
if (d->reg[MC_REGB * 4] & MC_REGB_SET) |
528 |
break; |
529 |
|
530 |
mc146818_update_time(d); |
531 |
break; |
532 |
case 4 * MC_REGC: /* Interrupt ack. */ |
533 |
/* NOTE: Acking is done below, _after_ the |
534 |
register has been read. */ |
535 |
break; |
536 |
default: |
537 |
debug("[ mc146818: read from relative_addr = " |
538 |
"%04x ]\n", (int)relative_addr); |
539 |
; |
540 |
} |
541 |
|
542 |
data[0] = d->reg[relative_addr]; |
543 |
|
544 |
if (relative_addr == MC_REGC*4) { |
545 |
cpu_interrupt_ack(cpu, d->irq_nr); |
546 |
/* d->cycles_left_until_interrupt = |
547 |
d->interrupt_every_x_cycles; */ |
548 |
d->reg[MC_REGC * 4] = 0x00; |
549 |
} |
550 |
} |
551 |
|
552 |
#ifdef MC146818_DEBUG |
553 |
if (writeflag == MEM_READ) { |
554 |
fatal("[ mc146818: read from addr=0x%04x (len %i): ", |
555 |
(int)relative_addr, (int)len); |
556 |
for (i=0; i<len; i++) |
557 |
fatal("%02x ", data[i]); |
558 |
fatal("]\n"); |
559 |
} |
560 |
#endif |
561 |
|
562 |
return 1; |
563 |
} |
564 |
|
565 |
|
566 |
/* |
567 |
* dev_mc146818_init(): |
568 |
* |
569 |
* This needs to work for both DECstation emulation and other machine types, |
570 |
* so it contains both rtc related stuff and the station's Ethernet address. |
571 |
*/ |
572 |
void dev_mc146818_init(struct machine *machine, struct memory *mem, |
573 |
uint64_t baseaddr, int irq_nr, int access_style, int addrdiv) |
574 |
{ |
575 |
unsigned char ether_address[6]; |
576 |
int i, dev_len; |
577 |
struct mc_data *d; |
578 |
|
579 |
d = malloc(sizeof(struct mc_data)); |
580 |
if (d == NULL) { |
581 |
fprintf(stderr, "out of memory\n"); |
582 |
exit(1); |
583 |
} |
584 |
|
585 |
memset(d, 0, sizeof(struct mc_data)); |
586 |
d->irq_nr = irq_nr; |
587 |
d->access_style = access_style; |
588 |
d->addrdiv = addrdiv; |
589 |
|
590 |
/* Station Ethernet Address, on DECstation 3100: */ |
591 |
for (i=0; i<6; i++) |
592 |
ether_address[i] = 0x10 * (i+1); |
593 |
|
594 |
d->reg[0x01] = ether_address[0]; |
595 |
d->reg[0x05] = ether_address[1]; |
596 |
d->reg[0x09] = ether_address[2]; |
597 |
d->reg[0x0d] = ether_address[3]; |
598 |
d->reg[0x11] = ether_address[4]; |
599 |
d->reg[0x15] = ether_address[5]; |
600 |
/* TODO: 19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */ |
601 |
d->reg[0x29] = ether_address[5]; |
602 |
d->reg[0x2d] = ether_address[4]; |
603 |
d->reg[0x31] = ether_address[3]; |
604 |
d->reg[0x35] = ether_address[2]; |
605 |
d->reg[0x39] = ether_address[1]; |
606 |
d->reg[0x3d] = ether_address[1]; |
607 |
d->reg[0x41] = ether_address[0]; |
608 |
d->reg[0x45] = ether_address[1]; |
609 |
d->reg[0x49] = ether_address[2]; |
610 |
d->reg[0x4d] = ether_address[3]; |
611 |
d->reg[0x51] = ether_address[4]; |
612 |
d->reg[0x55] = ether_address[5]; |
613 |
/* TODO: 59, 5d = checksum bytes 1,2 resp. */ |
614 |
d->reg[0x61] = 0xff; |
615 |
d->reg[0x65] = 0x00; |
616 |
d->reg[0x69] = 0x55; |
617 |
d->reg[0x6d] = 0xaa; |
618 |
d->reg[0x71] = 0xff; |
619 |
d->reg[0x75] = 0x00; |
620 |
d->reg[0x79] = 0x55; |
621 |
d->reg[0x7d] = 0xaa; |
622 |
|
623 |
/* Only SGI uses BCD format (?) */ |
624 |
d->use_bcd = 0; |
625 |
if (access_style == MC146818_SGI) |
626 |
d->use_bcd = 1; |
627 |
|
628 |
if (access_style == MC146818_DEC) { |
629 |
/* Battery valid, for DECstations */ |
630 |
d->reg[0xf8] = 1; |
631 |
} |
632 |
|
633 |
if (access_style == MC146818_ARC_JAZZ) |
634 |
memory_device_register(mem, "mc146818_jazz", 0x90000070ULL, |
635 |
1, dev_mc146818_jazz_access, d, MEM_DEFAULT, NULL); |
636 |
|
637 |
dev_len = DEV_MC146818_LENGTH; |
638 |
switch (access_style) { |
639 |
case MC146818_PC_CMOS: |
640 |
dev_len = 2; |
641 |
break; |
642 |
case MC146818_SGI: |
643 |
dev_len = 0x400; |
644 |
} |
645 |
|
646 |
memory_device_register(mem, "mc146818", baseaddr, |
647 |
dev_len * addrdiv, dev_mc146818_access, |
648 |
d, MEM_DEFAULT, NULL); |
649 |
|
650 |
mc146818_update_time(d); |
651 |
|
652 |
machine_add_tickfunction(machine, dev_mc146818_tick, |
653 |
d, TICK_STEPS_SHIFT); |
654 |
} |
655 |
|