1 |
/* |
/* |
2 |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 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.91 2006/10/07 03:20:19 debug Exp $ |
* $Id: dev_mc146818.c,v 1.99 2007/06/15 19:57:33 debug Exp $ |
29 |
* |
* |
30 |
* MC146818 real-time clock, used by many different machines types. |
* COMMENT: MC146818 real-time clock |
31 |
|
* |
32 |
* (DS1687 as used in some other machines is also similar to the MC146818.) |
* (DS1687 as used in some other machines is also similar to the MC146818.) |
33 |
* |
* |
34 |
* This device contains Date/time, the machine's ethernet address (on |
* This device contains Date/time, the machine's ethernet address (on |
59 |
|
|
60 |
/* #define MC146818_DEBUG */ |
/* #define MC146818_DEBUG */ |
61 |
|
|
62 |
#define TICK_SHIFT 14 |
#define MC146818_TICK_SHIFT 14 |
63 |
|
|
64 |
|
|
65 |
/* 256 on DECstation, SGI uses reg at 72*4 as the Century */ |
/* 256 on DECstation, SGI uses reg at 72*4 as the Century */ |
77 |
int timebase_hz; |
int timebase_hz; |
78 |
int interrupt_hz; |
int interrupt_hz; |
79 |
int old_interrupt_hz; |
int old_interrupt_hz; |
80 |
int irq_nr; |
struct interrupt irq; |
81 |
struct timer *timer; |
struct timer *timer; |
82 |
volatile int pending_timer_interrupts; |
volatile int pending_timer_interrupts; |
83 |
|
|
120 |
int pti = d->pending_timer_interrupts; |
int pti = d->pending_timer_interrupts; |
121 |
|
|
122 |
if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) { |
if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) { |
|
static int warned = 0; |
|
|
if (pti > 800 && !warned) { |
|
|
warned = 1; |
|
|
fatal("[ WARNING: MC146818 interrupts lost, " |
|
|
"host too slow? ]\n"); |
|
|
} |
|
|
|
|
123 |
#if 0 |
#if 0 |
124 |
/* For debugging, to see how much the interrupts are |
/* For debugging, to see how much the interrupts are |
125 |
lagging behind the real clock: */ |
lagging behind the real clock: */ |
133 |
} |
} |
134 |
#endif |
#endif |
135 |
|
|
136 |
cpu_interrupt(cpu, d->irq_nr); |
INTERRUPT_ASSERT(d->irq); |
137 |
|
|
138 |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
d->reg[MC_REGC * 4] |= MC_REGC_PF; |
139 |
} |
} |
151 |
* It seems like JAZZ machines accesses the mc146818 by writing one byte to |
* It seems like JAZZ machines accesses the mc146818 by writing one byte to |
152 |
* 0x90000070 and then reading or writing another byte at 0x......0004000. |
* 0x90000070 and then reading or writing another byte at 0x......0004000. |
153 |
*/ |
*/ |
154 |
int dev_mc146818_jazz_access(struct cpu *cpu, struct memory *mem, |
DEVICE_ACCESS(mc146818_jazz) |
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
155 |
{ |
{ |
156 |
struct mc_data *d = extra; |
struct mc_data *d = extra; |
157 |
|
|
276 |
} |
} |
277 |
|
|
278 |
|
|
279 |
/* |
DEVICE_ACCESS(mc146818) |
|
* dev_mc146818_access(): |
|
|
* |
|
|
* TODO: This access function only handles 8-bit accesses! |
|
|
*/ |
|
|
int dev_mc146818_access(struct cpu *cpu, struct memory *mem, |
|
|
uint64_t r, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
280 |
{ |
{ |
281 |
|
struct mc_data *d = extra; |
282 |
struct tm *tmp; |
struct tm *tmp; |
283 |
time_t timet; |
time_t timet; |
|
struct mc_data *d = extra; |
|
|
int relative_addr = r; |
|
284 |
size_t i; |
size_t i; |
285 |
|
|
286 |
|
/* NOTE/TODO: This access function only handles 8-bit accesses! */ |
287 |
|
|
288 |
relative_addr /= d->addrdiv; |
relative_addr /= d->addrdiv; |
289 |
|
|
290 |
/* Different ways of accessing the registers: */ |
/* Different ways of accessing the registers: */ |
458 |
case MC_REGB*4: |
case MC_REGB*4: |
459 |
d->reg[MC_REGB*4] = data[0]; |
d->reg[MC_REGB*4] = data[0]; |
460 |
if (!(data[0] & MC_REGB_PIE)) { |
if (!(data[0] & MC_REGB_PIE)) { |
461 |
cpu_interrupt_ack(cpu, d->irq_nr); |
INTERRUPT_DEASSERT(d->irq); |
462 |
} |
} |
463 |
|
|
464 |
/* debug("[ mc146818: write to MC_REGB, data[0] " |
/* debug("[ mc146818: write to MC_REGB, data[0] " |
552 |
data[0] = d->reg[relative_addr]; |
data[0] = d->reg[relative_addr]; |
553 |
|
|
554 |
if (relative_addr == MC_REGC*4) { |
if (relative_addr == MC_REGC*4) { |
555 |
cpu_interrupt_ack(cpu, d->irq_nr); |
INTERRUPT_DEASSERT(d->irq); |
556 |
|
|
557 |
/* |
/* |
558 |
* Acknowledging an interrupt decreases the |
* Acknowledging an interrupt decreases the |
559 |
* number of pending "real world" timer ticks. |
* number of pending "real world" timer ticks. |
560 |
*/ |
*/ |
561 |
if (d->reg[MC_REGC * 4] & MC_REGC_PF) |
if (d->reg[MC_REGC * 4] & MC_REGC_PF && |
562 |
|
d->pending_timer_interrupts > 0) |
563 |
d->pending_timer_interrupts --; |
d->pending_timer_interrupts --; |
564 |
|
|
565 |
d->reg[MC_REGC * 4] = 0x00; |
d->reg[MC_REGC * 4] = 0x00; |
587 |
* so it contains both rtc related stuff and the station's Ethernet address. |
* so it contains both rtc related stuff and the station's Ethernet address. |
588 |
*/ |
*/ |
589 |
void dev_mc146818_init(struct machine *machine, struct memory *mem, |
void dev_mc146818_init(struct machine *machine, struct memory *mem, |
590 |
uint64_t baseaddr, int irq_nr, int access_style, int addrdiv) |
uint64_t baseaddr, char *irq_path, int access_style, int addrdiv) |
591 |
{ |
{ |
592 |
unsigned char ether_address[6]; |
unsigned char ether_address[6]; |
593 |
int i, dev_len; |
int i, dev_len; |
594 |
struct mc_data *d; |
struct mc_data *d; |
595 |
|
|
596 |
d = malloc(sizeof(struct mc_data)); |
CHECK_ALLOCATION(d = malloc(sizeof(struct mc_data))); |
|
if (d == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
|
|
|
597 |
memset(d, 0, sizeof(struct mc_data)); |
memset(d, 0, sizeof(struct mc_data)); |
598 |
d->irq_nr = irq_nr; |
|
599 |
d->access_style = access_style; |
d->access_style = access_style; |
600 |
d->addrdiv = addrdiv; |
d->addrdiv = addrdiv; |
601 |
|
|
602 |
|
INTERRUPT_CONNECT(irq_path, d->irq); |
603 |
|
|
604 |
d->use_bcd = 0; |
d->use_bcd = 0; |
605 |
switch (access_style) { |
switch (access_style) { |
606 |
case MC146818_SGI: |
case MC146818_SGI: |
616 |
} |
} |
617 |
|
|
618 |
if (access_style == MC146818_DEC) { |
if (access_style == MC146818_DEC) { |
619 |
/* Station Ethernet Address, on DECstation 3100: */ |
/* Station Ethernet Address, on DECstation 3100: */ |
620 |
for (i=0; i<6; i++) |
for (i=0; i<6; i++) |
621 |
ether_address[i] = 0x10 * (i+1); |
ether_address[i] = 0x10 * (i+1); |
622 |
|
|
623 |
d->reg[0x01] = ether_address[0]; |
d->reg[0x01] = ether_address[0]; |
624 |
d->reg[0x05] = ether_address[1]; |
d->reg[0x05] = ether_address[1]; |
685 |
mc146818_update_time(d); |
mc146818_update_time(d); |
686 |
|
|
687 |
machine_add_tickfunction(machine, dev_mc146818_tick, d, |
machine_add_tickfunction(machine, dev_mc146818_tick, d, |
688 |
TICK_SHIFT, 0.0); |
MC146818_TICK_SHIFT); |
689 |
} |
} |
690 |
|
|