1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_mc146818.c,v 1.72 2005/08/02 07:56:37 debug Exp $ |
* $Id: dev_mc146818.c,v 1.91 2006/10/07 03:20:19 debug Exp $ |
29 |
* |
* |
30 |
* MC146818 real-time clock, used by many different machines types. |
* MC146818 real-time clock, used by many different machines types. |
31 |
* (DS1687 as used in some SGI machines is similar to MC146818.) |
* (DS1687 as used in some other machines is also similar to the MC146818.) |
32 |
* |
* |
33 |
* This device contains Date/time, the machine's ethernet address (on |
* This device contains Date/time, the machine's ethernet address (on |
34 |
* DECstation 3100), and can cause periodic (hardware) interrupts. |
* DECstation 3100), and can cause periodic (hardware) interrupts. |
48 |
#include "machine.h" |
#include "machine.h" |
49 |
#include "memory.h" |
#include "memory.h" |
50 |
#include "misc.h" |
#include "misc.h" |
51 |
|
#include "timer.h" |
52 |
|
|
53 |
#include "mc146818reg.h" |
#include "mc146818reg.h" |
54 |
|
|
55 |
|
|
56 |
#define to_bcd(x) ( ((x)/10) * 16 + ((x)%10) ) |
#define to_bcd(x) ( ((x)/10) * 16 + ((x)%10) ) |
57 |
|
#define from_bcd(x) ( ((x)>>4) * 10 + ((x)&15) ) |
58 |
|
|
59 |
/* #define MC146818_DEBUG */ |
/* #define MC146818_DEBUG */ |
60 |
|
|
64 |
/* 256 on DECstation, SGI uses reg at 72*4 as the Century */ |
/* 256 on DECstation, SGI uses reg at 72*4 as the Century */ |
65 |
#define N_REGISTERS 1024 |
#define N_REGISTERS 1024 |
66 |
struct mc_data { |
struct mc_data { |
67 |
int access_style; |
int access_style; |
68 |
int last_addr; |
int last_addr; |
69 |
|
|
70 |
int register_choice; |
int register_choice; |
71 |
int reg[N_REGISTERS]; |
int reg[N_REGISTERS]; |
72 |
int addrdiv; |
int addrdiv; |
73 |
|
|
74 |
|
int use_bcd; |
75 |
|
|
76 |
|
int timebase_hz; |
77 |
|
int interrupt_hz; |
78 |
|
int old_interrupt_hz; |
79 |
|
int irq_nr; |
80 |
|
struct timer *timer; |
81 |
|
volatile int pending_timer_interrupts; |
82 |
|
|
83 |
|
int previous_second; |
84 |
|
int n_seconds_elapsed; |
85 |
|
int uip_threshold; |
86 |
|
|
87 |
int use_bcd; |
int ugly_netbsd_prep_hack_done; |
88 |
|
int ugly_netbsd_prep_hack_sec; |
89 |
int timebase_hz; |
}; |
|
int interrupt_hz; |
|
|
int irq_nr; |
|
90 |
|
|
|
int previous_second; |
|
91 |
|
|
92 |
int interrupt_every_x_cycles; |
/* |
93 |
int cycles_left_until_interrupt; |
* Ugly hack to fool NetBSD/prep to accept the clock. (See mcclock_isa_match |
94 |
}; |
* in NetBSD's arch/prep/isa/mcclock_isa.c for details.) |
95 |
|
*/ |
96 |
|
#define NETBSD_HACK_INIT 0 |
97 |
|
#define NETBSD_HACK_FIRST_1 1 |
98 |
|
#define NETBSD_HACK_FIRST_2 2 |
99 |
|
#define NETBSD_HACK_SECOND_1 3 |
100 |
|
#define NETBSD_HACK_SECOND_2 4 |
101 |
|
#define NETBSD_HACK_DONE 5 |
102 |
|
|
103 |
|
|
104 |
/* |
/* |
105 |
* recalc_interrupt_cycle(): |
* timer_tick(): |
106 |
* |
* |
107 |
* If automatic_clock_adjustment is turned on, then emulated_hz is modified |
* Called d->interrupt_hz times per (real-world) second. |
|
* dynamically. We have to recalculate how often interrupts are to be |
|
|
* triggered. |
|
108 |
*/ |
*/ |
109 |
static void recalc_interrupt_cycle(struct cpu *cpu, struct mc_data *d) |
static void timer_tick(struct timer *timer, void *extra) |
110 |
{ |
{ |
111 |
int64_t emulated_hz = cpu->machine->emulated_hz; |
struct mc_data *d = (struct mc_data *) extra; |
112 |
#if 0 |
d->pending_timer_interrupts ++; |
|
static int warning_printed = 0; |
|
|
|
|
|
/* |
|
|
* A hack to make Ultrix run, even on very fast host machines. |
|
|
* |
|
|
* (Ultrix was probably never meant to be run on machines with |
|
|
* faster CPUs than around 33 MHz or so.) |
|
|
*/ |
|
|
if (d->access_style == MC146818_DEC && emulated_hz > 30000000) { |
|
|
if (!warning_printed) { |
|
|
fatal("\n*********************************************" |
|
|
"**********************************\n\n Your hos" |
|
|
"t machine is too fast! The emulated CPU speed wil" |
|
|
"l be limited to\n 30 MHz, and clocks inside the" |
|
|
" emulated environment might go faster than\n in" |
|
|
" the real world. You have been warned.\n\n******" |
|
|
"*************************************************" |
|
|
"************************\n\n"); |
|
|
warning_printed = 1; |
|
|
} |
|
|
|
|
|
emulated_hz = 30000000; |
|
|
} |
|
|
#endif |
|
|
|
|
|
if (d->interrupt_hz > 0) |
|
|
d->interrupt_every_x_cycles = |
|
|
emulated_hz / d->interrupt_hz; |
|
|
else |
|
|
d->interrupt_every_x_cycles = 0; |
|
113 |
} |
} |
114 |
|
|
115 |
|
|
116 |
/* |
DEVICE_TICK(mc146818) |
|
* dev_mc146818_tick(): |
|
|
*/ |
|
|
void dev_mc146818_tick(struct cpu *cpu, void *extra) |
|
117 |
{ |
{ |
118 |
struct mc_data *d = extra; |
struct mc_data *d = extra; |
119 |
|
int pti = d->pending_timer_interrupts; |
120 |
|
|
121 |
if (d == NULL) |
if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) { |
122 |
return; |
static int warned = 0; |
123 |
|
if (pti > 800 && !warned) { |
124 |
recalc_interrupt_cycle(cpu, d); |
warned = 1; |
125 |
|
fatal("[ WARNING: MC146818 interrupts lost, " |
126 |
|
"host too slow? ]\n"); |
127 |
|
} |
128 |
|
|
129 |
if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && |
#if 0 |
130 |
d->interrupt_every_x_cycles > 0) { |
/* For debugging, to see how much the interrupts are |
131 |
d->cycles_left_until_interrupt -= (1 << TICK_SHIFT); |
lagging behind the real clock: */ |
132 |
|
{ |
133 |
if (d->cycles_left_until_interrupt < 0 || |
static int x = 0; |
134 |
d->cycles_left_until_interrupt >= |
if (++x == 1) { |
135 |
d->interrupt_every_x_cycles) { |
x = 0; |
136 |
/* debug("[ rtc interrupt (every %i cycles) ]\n", |
printf("%i ", pti); |
137 |
d->interrupt_every_x_cycles); */ |
fflush(stdout); |
138 |
cpu_interrupt(cpu, d->irq_nr); |
} |
139 |
|
} |
140 |
|
#endif |
141 |
|
|
142 |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
cpu_interrupt(cpu, d->irq_nr); |
143 |
|
|
144 |
/* Reset the cycle countdown: */ |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
|
while (d->cycles_left_until_interrupt < 0) |
|
|
d->cycles_left_until_interrupt += |
|
|
d->interrupt_every_x_cycles; |
|
|
} |
|
145 |
} |
} |
146 |
|
|
147 |
if (d->reg[MC_REGC * 4] & MC_REGC_UF || |
if (d->reg[MC_REGC * 4] & MC_REGC_UF || |
208 |
d->reg[4 * MC_MONTH] = tmp->tm_mon + 1; |
d->reg[4 * MC_MONTH] = tmp->tm_mon + 1; |
209 |
d->reg[4 * MC_YEAR] = tmp->tm_year; |
d->reg[4 * MC_YEAR] = tmp->tm_year; |
210 |
|
|
211 |
|
/* |
212 |
|
* Special hacks for emulating the behaviour of various machines: |
213 |
|
*/ |
214 |
switch (d->access_style) { |
switch (d->access_style) { |
215 |
|
case MC146818_ALGOR: |
216 |
|
/* |
217 |
|
* NetBSD/evbmips sources indicate that the Algor year base |
218 |
|
* is 1920. This makes the time work with NetBSD in Malta |
219 |
|
* emulation. However, for Linux, commenting out this line |
220 |
|
* works better. (TODO: Find a way to make both work?) |
221 |
|
*/ |
222 |
|
d->reg[4 * MC_YEAR] += 80; |
223 |
|
break; |
224 |
case MC146818_ARC_NEC: |
case MC146818_ARC_NEC: |
225 |
d->reg[4 * MC_YEAR] += (0x18 - 104); |
d->reg[4 * MC_YEAR] += (0x18 - 104); |
226 |
break; |
break; |
227 |
|
case MC146818_CATS: |
228 |
|
d->reg[4 * MC_YEAR] %= 100; |
229 |
|
break; |
230 |
case MC146818_SGI: |
case MC146818_SGI: |
231 |
/* |
/* |
232 |
* NetBSD/sgimips assumes data in BCD format. |
* NetBSD/sgimips assumes data in BCD format. |
248 |
(d->reg[4 * MC_YEAR] - 30 + 40) |
(d->reg[4 * MC_YEAR] - 30 + 40) |
249 |
: (d->reg[4 * MC_YEAR] - 40) |
: (d->reg[4 * MC_YEAR] - 40) |
250 |
); |
); |
|
|
|
251 |
/* Century: */ |
/* Century: */ |
252 |
d->reg[72 * 4] = 19 + (tmp->tm_year / 100); |
d->reg[72 * 4] = 19 + (tmp->tm_year / 100); |
|
|
|
253 |
break; |
break; |
254 |
case MC146818_DEC: |
case MC146818_DEC: |
255 |
/* |
/* |
296 |
struct tm *tmp; |
struct tm *tmp; |
297 |
time_t timet; |
time_t timet; |
298 |
struct mc_data *d = extra; |
struct mc_data *d = extra; |
299 |
int i, relative_addr = r; |
int relative_addr = r; |
300 |
|
size_t i; |
301 |
|
|
302 |
relative_addr /= d->addrdiv; |
relative_addr /= d->addrdiv; |
303 |
|
|
304 |
/* Different ways of accessing the registers: */ |
/* Different ways of accessing the registers: */ |
305 |
switch (d->access_style) { |
switch (d->access_style) { |
306 |
|
case MC146818_ALGOR: |
307 |
|
case MC146818_CATS: |
308 |
case MC146818_PC_CMOS: |
case MC146818_PC_CMOS: |
309 |
if (relative_addr == 0x70 || relative_addr == 0x00) { |
if ((relative_addr & 1) == 0x00) { |
310 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
311 |
d->last_addr = data[0]; |
d->last_addr = data[0]; |
312 |
return 1; |
return 1; |
314 |
data[0] = d->last_addr; |
data[0] = d->last_addr; |
315 |
return 1; |
return 1; |
316 |
} |
} |
317 |
} else if (relative_addr == 0x71 || relative_addr == 0x01) |
} else |
318 |
relative_addr = d->last_addr * 4; |
relative_addr = d->last_addr * 4; |
|
else { |
|
|
fatal("[ mc146818: not accessed as an " |
|
|
"MC146818_PC_CMOS device! ]\n"); |
|
|
} |
|
319 |
break; |
break; |
320 |
case MC146818_ARC_NEC: |
case MC146818_ARC_NEC: |
321 |
if (relative_addr == 0x01) { |
if (relative_addr == 0x01) { |
348 |
* should be ignored. It works _almost_ as DEC, if offsets are |
* should be ignored. It works _almost_ as DEC, if offsets are |
349 |
* divided by 0x40. |
* divided by 0x40. |
350 |
*/ |
*/ |
351 |
|
break; |
352 |
|
case MC146818_PMPPC: |
353 |
|
relative_addr *= 4; |
354 |
|
break; |
355 |
default: |
default: |
356 |
; |
; |
357 |
} |
} |
361 |
fatal("[ mc146818: write to addr=0x%04x (len %i): ", |
fatal("[ mc146818: write to addr=0x%04x (len %i): ", |
362 |
(int)relative_addr, (int)len); |
(int)relative_addr, (int)len); |
363 |
for (i=0; i<len; i++) |
for (i=0; i<len; i++) |
364 |
fatal("%02x ", data[i]); |
fatal("0x%02x ", data[i]); |
365 |
fatal("]\n"); |
fatal("]\n"); |
366 |
} |
} |
367 |
#endif |
#endif |
374 |
* Linux on at least sgimips and evbmips (Malta) wants the UIP bit |
* Linux on at least sgimips and evbmips (Malta) wants the UIP bit |
375 |
* in REGA to be updated once a second. |
* in REGA to be updated once a second. |
376 |
*/ |
*/ |
377 |
timet = time(NULL); |
if (relative_addr == MC_REGA*4 || relative_addr == MC_REGC*4) { |
378 |
tmp = gmtime(&timet); |
timet = time(NULL); |
379 |
d->reg[MC_REGC * 4] &= ~MC_REGC_UF; |
tmp = gmtime(&timet); |
380 |
|
d->reg[MC_REGC * 4] &= ~MC_REGC_UF; |
381 |
|
if (tmp->tm_sec != d->previous_second) { |
382 |
|
d->n_seconds_elapsed ++; |
383 |
|
d->previous_second = tmp->tm_sec; |
384 |
|
} |
385 |
|
if (d->n_seconds_elapsed > d->uip_threshold) { |
386 |
|
d->n_seconds_elapsed = 0; |
387 |
|
|
388 |
if (tmp->tm_sec != d->previous_second) { |
d->reg[MC_REGA * 4] |= MC_REGA_UIP; |
|
d->reg[MC_REGA * 4] &= ~MC_REGA_UIP; |
|
389 |
|
|
390 |
d->reg[MC_REGC * 4] |= MC_REGC_UF; |
d->reg[MC_REGC * 4] |= MC_REGC_UF; |
391 |
d->reg[MC_REGC * 4] |= MC_REGC_IRQF; |
d->reg[MC_REGC * 4] |= MC_REGC_IRQF; |
|
d->previous_second = tmp->tm_sec; |
|
392 |
|
|
393 |
/* For some reason, some Linux/DECstation KN04 kernels want |
/* For some reason, some Linux/DECstation KN04 |
394 |
the PF (periodic flag) bit set, even though interrupts |
kernels want the PF (periodic flag) bit set, |
395 |
are not enabled? */ |
even though interrupts are not enabled? */ |
396 |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
397 |
} else |
} else |
398 |
d->reg[MC_REGA * 4] |= MC_REGA_UIP; |
d->reg[MC_REGA * 4] &= ~MC_REGA_UIP; |
399 |
|
} |
400 |
|
|
401 |
/* RTC data is in either BCD format or binary: */ |
/* RTC data is in either BCD format or binary: */ |
402 |
if (d->use_bcd) |
if (d->use_bcd) |
446 |
case MC_RATE_8_Hz: d->interrupt_hz = 8; break; |
case MC_RATE_8_Hz: d->interrupt_hz = 8; break; |
447 |
case MC_RATE_4_Hz: d->interrupt_hz = 4; break; |
case MC_RATE_4_Hz: d->interrupt_hz = 4; break; |
448 |
case MC_RATE_2_Hz: d->interrupt_hz = 2; break; |
case MC_RATE_2_Hz: d->interrupt_hz = 2; break; |
449 |
default: |
default:/* debug("[ mc146818: unimplemented " |
|
/* debug("[ mc146818: unimplemented " |
|
450 |
"MC_REGA RS: %i ]\n", |
"MC_REGA RS: %i ]\n", |
451 |
data[0] & MC_REGA_RSMASK); */ |
data[0] & MC_REGA_RSMASK); */ |
452 |
; |
; |
453 |
} |
} |
454 |
|
|
455 |
recalc_interrupt_cycle(cpu, d); |
if (d->interrupt_hz != d->old_interrupt_hz) { |
456 |
|
debug("[ rtc changed to interrupt at %i Hz ]\n", |
457 |
d->cycles_left_until_interrupt = |
d->interrupt_hz); |
458 |
d->interrupt_every_x_cycles; |
|
459 |
|
d->old_interrupt_hz = d->interrupt_hz; |
460 |
|
|
461 |
|
if (d->timer == NULL) |
462 |
|
d->timer = timer_add(d->interrupt_hz, |
463 |
|
timer_tick, d); |
464 |
|
else |
465 |
|
timer_update_frequency(d->timer, |
466 |
|
d->interrupt_hz); |
467 |
|
} |
468 |
|
|
469 |
d->reg[MC_REGA * 4] = |
d->reg[MC_REGA * 4] = |
470 |
data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK); |
data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK); |
|
|
|
|
debug("[ rtc set to interrupt every %i:th cycle ]\n", |
|
|
d->interrupt_every_x_cycles); |
|
471 |
break; |
break; |
472 |
case MC_REGB*4: |
case MC_REGB*4: |
|
if (((data[0] ^ d->reg[MC_REGB*4]) & MC_REGB_PIE)) |
|
|
d->cycles_left_until_interrupt = |
|
|
d->interrupt_every_x_cycles; |
|
473 |
d->reg[MC_REGB*4] = data[0]; |
d->reg[MC_REGB*4] = data[0]; |
474 |
if (!(data[0] & MC_REGB_PIE)) { |
if (!(data[0] & MC_REGB_PIE)) { |
475 |
cpu_interrupt_ack(cpu, d->irq_nr); |
cpu_interrupt_ack(cpu, d->irq_nr); |
|
/* d->cycles_left_until_interrupt = |
|
|
d->interrupt_every_x_cycles; */ |
|
476 |
} |
} |
477 |
|
|
478 |
/* debug("[ mc146818: write to MC_REGB, data[0] " |
/* debug("[ mc146818: write to MC_REGB, data[0] " |
479 |
"= 0x%02x ]\n", data[0]); */ |
"= 0x%02x ]\n", data[0]); */ |
480 |
break; |
break; |
486 |
case 0x128: |
case 0x128: |
487 |
d->reg[relative_addr] = data[0]; |
d->reg[relative_addr] = data[0]; |
488 |
if (data[0] & 8) { |
if (data[0] & 8) { |
489 |
|
int j; |
490 |
|
|
491 |
/* Used on SGI to power off the machine. */ |
/* Used on SGI to power off the machine. */ |
492 |
fatal("[ md146818: power off ]\n"); |
fatal("[ md146818: power off ]\n"); |
493 |
for (i=0; i<cpu->machine->ncpus; i++) |
for (j=0; j<cpu->machine->ncpus; j++) |
494 |
cpu->machine->cpus[i]->running = 0; |
cpu->machine->cpus[j]->running = 0; |
495 |
cpu->machine-> |
cpu->machine-> |
496 |
exit_without_entering_debugger = 1; |
exit_without_entering_debugger = 1; |
497 |
} |
} |
516 |
case 0x15: |
case 0x15: |
517 |
break; |
break; |
518 |
case 4 * MC_SEC: |
case 4 * MC_SEC: |
519 |
|
if (d->ugly_netbsd_prep_hack_done < NETBSD_HACK_DONE) { |
520 |
|
d->ugly_netbsd_prep_hack_done ++; |
521 |
|
switch (d->ugly_netbsd_prep_hack_done) { |
522 |
|
case NETBSD_HACK_FIRST_1: |
523 |
|
d->ugly_netbsd_prep_hack_sec = |
524 |
|
from_bcd(d->reg[relative_addr]); |
525 |
|
break; |
526 |
|
case NETBSD_HACK_FIRST_2: |
527 |
|
d->reg[relative_addr] = to_bcd( |
528 |
|
d->ugly_netbsd_prep_hack_sec); |
529 |
|
break; |
530 |
|
case NETBSD_HACK_SECOND_1: |
531 |
|
case NETBSD_HACK_SECOND_2: |
532 |
|
d->reg[relative_addr] = to_bcd((1 + |
533 |
|
d->ugly_netbsd_prep_hack_sec) % 60); |
534 |
|
break; |
535 |
|
} |
536 |
|
} |
537 |
case 4 * MC_MIN: |
case 4 * MC_MIN: |
538 |
case 4 * MC_HOUR: |
case 4 * MC_HOUR: |
539 |
case 4 * MC_DOW: |
case 4 * MC_DOW: |
550 |
if (d->reg[MC_REGB * 4] & MC_REGB_SET) |
if (d->reg[MC_REGB * 4] & MC_REGB_SET) |
551 |
break; |
break; |
552 |
|
|
553 |
mc146818_update_time(d); |
if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE) |
554 |
|
mc146818_update_time(d); |
555 |
|
break; |
556 |
|
case 4 * MC_REGA: |
557 |
break; |
break; |
558 |
case 4 * MC_REGC: /* Interrupt ack. */ |
case 4 * MC_REGC: /* Interrupt ack. */ |
559 |
/* NOTE: Acking is done below, _after_ the |
/* NOTE: Acking is done below, _after_ the |
560 |
register has been read. */ |
register has been read. */ |
561 |
break; |
break; |
562 |
default: |
default:debug("[ mc146818: read from relative_addr = " |
|
debug("[ mc146818: read from relative_addr = " |
|
563 |
"%04x ]\n", (int)relative_addr); |
"%04x ]\n", (int)relative_addr); |
|
; |
|
564 |
} |
} |
565 |
|
|
566 |
data[0] = d->reg[relative_addr]; |
data[0] = d->reg[relative_addr]; |
567 |
|
|
568 |
if (relative_addr == MC_REGC*4) { |
if (relative_addr == MC_REGC*4) { |
569 |
cpu_interrupt_ack(cpu, d->irq_nr); |
cpu_interrupt_ack(cpu, d->irq_nr); |
570 |
/* d->cycles_left_until_interrupt = |
|
571 |
d->interrupt_every_x_cycles; */ |
/* |
572 |
|
* Acknowledging an interrupt decreases the |
573 |
|
* number of pending "real world" timer ticks. |
574 |
|
*/ |
575 |
|
if (d->reg[MC_REGC * 4] & MC_REGC_PF) |
576 |
|
d->pending_timer_interrupts --; |
577 |
|
|
578 |
d->reg[MC_REGC * 4] = 0x00; |
d->reg[MC_REGC * 4] = 0x00; |
579 |
} |
} |
580 |
} |
} |
584 |
fatal("[ mc146818: read from addr=0x%04x (len %i): ", |
fatal("[ mc146818: read from addr=0x%04x (len %i): ", |
585 |
(int)relative_addr, (int)len); |
(int)relative_addr, (int)len); |
586 |
for (i=0; i<len; i++) |
for (i=0; i<len; i++) |
587 |
fatal("%02x ", data[i]); |
fatal("0x%02x ", data[i]); |
588 |
fatal("]\n"); |
fatal("]\n"); |
589 |
} |
} |
590 |
#endif |
#endif |
617 |
d->access_style = access_style; |
d->access_style = access_style; |
618 |
d->addrdiv = addrdiv; |
d->addrdiv = addrdiv; |
619 |
|
|
|
/* Only SGIs and PCs use BCD format (?) */ |
|
620 |
d->use_bcd = 0; |
d->use_bcd = 0; |
621 |
if (access_style == MC146818_SGI || access_style == MC146818_PC_CMOS) |
switch (access_style) { |
622 |
|
case MC146818_SGI: |
623 |
|
case MC146818_PC_CMOS: |
624 |
|
case MC146818_PMPPC: |
625 |
d->use_bcd = 1; |
d->use_bcd = 1; |
626 |
|
} |
627 |
|
|
628 |
|
if (machine->machine_type != MACHINE_PREP) { |
629 |
|
/* NetBSD/prep has a really ugly clock detection code; |
630 |
|
no other machines/OSes don't need this. */ |
631 |
|
d->ugly_netbsd_prep_hack_done = NETBSD_HACK_DONE; |
632 |
|
} |
633 |
|
|
634 |
if (access_style == MC146818_DEC) { |
if (access_style == MC146818_DEC) { |
635 |
/* Station Ethernet Address, on DECstation 3100: */ |
/* Station Ethernet Address, on DECstation 3100: */ |
669 |
d->reg[0xf8] = 1; |
d->reg[0xf8] = 1; |
670 |
} |
} |
671 |
|
|
672 |
|
/* |
673 |
|
* uip_threshold should ideally be 1, but when Linux polls the UIP bit |
674 |
|
* it looses speed. This hack gives Linux the impression that the cpu |
675 |
|
* is uip_threshold times faster than the slow clock it would |
676 |
|
* otherwise detect. |
677 |
|
* |
678 |
|
* TODO: Find out if this messes up Sprite emulation; if so, then |
679 |
|
* this hack has to be removed. |
680 |
|
*/ |
681 |
|
d->uip_threshold = 8; |
682 |
|
|
683 |
if (access_style == MC146818_ARC_JAZZ) |
if (access_style == MC146818_ARC_JAZZ) |
684 |
memory_device_register(mem, "mc146818_jazz", 0x90000070ULL, |
memory_device_register(mem, "mc146818_jazz", 0x90000070ULL, |
685 |
1, dev_mc146818_jazz_access, d, MEM_DEFAULT, NULL); |
1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL); |
686 |
|
|
687 |
dev_len = DEV_MC146818_LENGTH; |
dev_len = DEV_MC146818_LENGTH; |
688 |
switch (access_style) { |
switch (access_style) { |
689 |
|
case MC146818_CATS: |
690 |
case MC146818_PC_CMOS: |
case MC146818_PC_CMOS: |
691 |
dev_len = 2; |
dev_len = 2; |
692 |
break; |
break; |
696 |
|
|
697 |
memory_device_register(mem, "mc146818", baseaddr, |
memory_device_register(mem, "mc146818", baseaddr, |
698 |
dev_len * addrdiv, dev_mc146818_access, |
dev_len * addrdiv, dev_mc146818_access, |
699 |
d, MEM_DEFAULT, NULL); |
d, DM_DEFAULT, NULL); |
700 |
|
|
701 |
mc146818_update_time(d); |
mc146818_update_time(d); |
702 |
|
|
703 |
machine_add_tickfunction(machine, dev_mc146818_tick, d, TICK_SHIFT); |
machine_add_tickfunction(machine, dev_mc146818_tick, d, |
704 |
|
TICK_SHIFT, 0.0); |
705 |
} |
} |
706 |
|
|