/[gxemul]/trunk/src/devices/dev_mc146818.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_mc146818.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19852 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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.80 2005/11/20 11:28:45 debug Exp $
29 *
30 * MC146818 real-time clock, used by many different machines types.
31 * (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
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 #define from_bcd(x) ( ((x)>>4) * 10 + ((x)&15) )
57
58 /* #define MC146818_DEBUG */
59
60 #define TICK_SHIFT 14
61
62
63 /* 256 on DECstation, SGI uses reg at 72*4 as the Century */
64 #define N_REGISTERS 1024
65 struct mc_data {
66 int access_style;
67 int last_addr;
68
69 int register_choice;
70 int reg[N_REGISTERS];
71 int addrdiv;
72
73 int use_bcd;
74
75 int timebase_hz;
76 int interrupt_hz;
77 int irq_nr;
78
79 int previous_second;
80 int n_seconds_elapsed;
81 int uip_threshold;
82
83 int interrupt_every_x_cycles;
84 int cycles_left_until_interrupt;
85
86 int ugly_netbsd_prep_hack_done;
87 int ugly_netbsd_prep_hack_sec;
88 };
89
90
91 /*
92 * Ugly hack to fool NetBSD/prep to accept the clock. (See mcclock_isa_match
93 * in NetBSD's arch/prep/isa/mcclock_isa.c for details.)
94 */
95 #define NETBSD_HACK_INIT 0
96 #define NETBSD_HACK_FIRST_1 1
97 #define NETBSD_HACK_FIRST_2 2
98 #define NETBSD_HACK_SECOND_1 3
99 #define NETBSD_HACK_SECOND_2 4
100 #define NETBSD_HACK_DONE 5
101
102
103 /*
104 * recalc_interrupt_cycle():
105 *
106 * If automatic_clock_adjustment is turned on, then emulated_hz is modified
107 * dynamically. We have to recalculate how often interrupts are to be
108 * triggered.
109 */
110 static void recalc_interrupt_cycle(struct cpu *cpu, struct mc_data *d)
111 {
112 int64_t emulated_hz = cpu->machine->emulated_hz;
113 #if 0
114 static int warning_printed = 0;
115
116 /*
117 * A hack to make Ultrix run, even on very fast host machines.
118 *
119 * (Ultrix was probably never meant to be run on machines with
120 * faster CPUs than around 33 MHz or so.)
121 */
122 if (d->access_style == MC146818_DEC && emulated_hz > 30000000) {
123 if (!warning_printed) {
124 fatal("\n*********************************************"
125 "**********************************\n\n Your hos"
126 "t machine is too fast! The emulated CPU speed wil"
127 "l be limited to\n 30 MHz, and clocks inside the"
128 " emulated environment might go faster than\n in"
129 " the real world. You have been warned.\n\n******"
130 "*************************************************"
131 "************************\n\n");
132 warning_printed = 1;
133 }
134
135 emulated_hz = 30000000;
136 }
137 #endif
138
139 if (d->interrupt_hz > 0)
140 d->interrupt_every_x_cycles =
141 emulated_hz / d->interrupt_hz;
142 else
143 d->interrupt_every_x_cycles = 0;
144 }
145
146
147 /*
148 * dev_mc146818_tick():
149 */
150 void dev_mc146818_tick(struct cpu *cpu, void *extra)
151 {
152 struct mc_data *d = extra;
153
154 recalc_interrupt_cycle(cpu, d);
155
156 if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) &&
157 d->interrupt_every_x_cycles > 0) {
158 d->cycles_left_until_interrupt -= (1 << TICK_SHIFT);
159
160 if (d->cycles_left_until_interrupt < 0 ||
161 d->cycles_left_until_interrupt >=
162 d->interrupt_every_x_cycles) {
163 /* debug("[ rtc interrupt (every %i cycles) ]\n",
164 d->interrupt_every_x_cycles); */
165 cpu_interrupt(cpu, d->irq_nr);
166
167 d->reg[MC_REGC * 4] |= MC_REGC_PF;
168
169 /* Reset the cycle countdown: */
170 while (d->cycles_left_until_interrupt < 0)
171 d->cycles_left_until_interrupt +=
172 d->interrupt_every_x_cycles;
173 }
174 }
175
176 if (d->reg[MC_REGC * 4] & MC_REGC_UF ||
177 d->reg[MC_REGC * 4] & MC_REGC_AF ||
178 d->reg[MC_REGC * 4] & MC_REGC_PF)
179 d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
180 }
181
182
183 /*
184 * dev_mc146818_jazz_access():
185 *
186 * It seems like JAZZ machines accesses the mc146818 by writing one byte to
187 * 0x90000070 and then reading or writing another byte at 0x......0004000.
188 */
189 int dev_mc146818_jazz_access(struct cpu *cpu, struct memory *mem,
190 uint64_t relative_addr, unsigned char *data, size_t len,
191 int writeflag, void *extra)
192 {
193 struct mc_data *d = extra;
194
195 #ifdef MC146818_DEBUG
196 if (writeflag == MEM_WRITE) {
197 int i;
198 fatal("[ mc146818_jazz: write to addr=0x%04x: ",
199 (int)relative_addr);
200 for (i=0; i<len; i++)
201 fatal("%02x ", data[i]);
202 fatal("]\n");
203 } else
204 fatal("[ mc146818_jazz: read from addr=0x%04x ]\n",
205 (int)relative_addr);
206 #endif
207
208 if (writeflag == MEM_WRITE) {
209 d->last_addr = data[0];
210 return 1;
211 } else {
212 data[0] = d->last_addr;
213 return 1;
214 }
215 }
216
217
218 /*
219 * mc146818_update_time():
220 *
221 * This function updates the MC146818 registers by reading
222 * the host's clock.
223 */
224 static void mc146818_update_time(struct mc_data *d)
225 {
226 struct tm *tmp;
227 time_t timet;
228
229 timet = time(NULL);
230 tmp = gmtime(&timet);
231
232 d->reg[4 * MC_SEC] = tmp->tm_sec;
233 d->reg[4 * MC_MIN] = tmp->tm_min;
234 d->reg[4 * MC_HOUR] = tmp->tm_hour;
235 d->reg[4 * MC_DOW] = tmp->tm_wday + 1;
236 d->reg[4 * MC_DOM] = tmp->tm_mday;
237 d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;
238 d->reg[4 * MC_YEAR] = tmp->tm_year;
239
240 /*
241 * Special hacks for emulating the behaviour of various machines:
242 */
243 switch (d->access_style) {
244 case MC146818_ALGOR:
245 d->reg[4 * MC_YEAR] += 80;
246 break;
247 case MC146818_ARC_NEC:
248 d->reg[4 * MC_YEAR] += (0x18 - 104);
249 break;
250 case MC146818_CATS:
251 d->reg[4 * MC_YEAR] %= 100;
252 break;
253 case MC146818_SGI:
254 /*
255 * NetBSD/sgimips assumes data in BCD format.
256 * Also, IRIX stores the year value in a weird
257 * format, according to ../arch/sgimips/sgimips/clockvar.h
258 * in NetBSD:
259 *
260 * "If year < 1985, store (year - 1970), else
261 * (year - 1940). This matches IRIX semantics."
262 *
263 * Another rule: It seems that a real SGI IP32 box
264 * uses the value 5 for the year 2005.
265 */
266 d->reg[4 * MC_YEAR] =
267 d->reg[4 * MC_YEAR] >= 100 ?
268 (d->reg[4 * MC_YEAR] - 100) :
269 (
270 d->reg[4 * MC_YEAR] < 85 ?
271 (d->reg[4 * MC_YEAR] - 30 + 40)
272 : (d->reg[4 * MC_YEAR] - 40)
273 );
274 /* Century: */
275 d->reg[72 * 4] = 19 + (tmp->tm_year / 100);
276 break;
277 case MC146818_DEC:
278 /*
279 * DECstations must have 72 or 73 in the
280 * Year field, or Ultrix screems. (Weird.)
281 */
282 d->reg[4 * MC_YEAR] = 72;
283
284 /*
285 * Linux on DECstation stores the year in register 63,
286 * but no other DECstation OS does? (Hm.)
287 */
288 d->reg[4 * 63] = tmp->tm_year - 100;
289 break;
290 }
291
292 if (d->use_bcd) {
293 d->reg[4 * MC_SEC] = to_bcd(d->reg[4 * MC_SEC]);
294 d->reg[4 * MC_MIN] = to_bcd(d->reg[4 * MC_MIN]);
295 d->reg[4 * MC_HOUR] = to_bcd(d->reg[4 * MC_HOUR]);
296 d->reg[4 * MC_DOW] = to_bcd(d->reg[4 * MC_DOW]);
297 d->reg[4 * MC_DOM] = to_bcd(d->reg[4 * MC_DOM]);
298 d->reg[4 * MC_MONTH] = to_bcd(d->reg[4 * MC_MONTH]);
299 d->reg[4 * MC_YEAR] = to_bcd(d->reg[4 * MC_YEAR]);
300
301 /* Used by Linux on DECstation: (Hm) */
302 d->reg[4 * 63] = to_bcd(d->reg[4 * 63]);
303
304 /* Used on SGI: */
305 d->reg[4 * 72] = to_bcd(d->reg[4 * 72]);
306 }
307 }
308
309
310 /*
311 * dev_mc146818_access():
312 *
313 * TODO: This access function only handles 8-bit accesses!
314 */
315 int dev_mc146818_access(struct cpu *cpu, struct memory *mem,
316 uint64_t r, unsigned char *data, size_t len,
317 int writeflag, void *extra)
318 {
319 struct tm *tmp;
320 time_t timet;
321 struct mc_data *d = extra;
322 int i, relative_addr = r;
323
324 relative_addr /= d->addrdiv;
325
326 /* Different ways of accessing the registers: */
327 switch (d->access_style) {
328 case MC146818_ALGOR:
329 case MC146818_CATS:
330 case MC146818_PC_CMOS:
331 if ((relative_addr & 1) == 0x00) {
332 if (writeflag == MEM_WRITE) {
333 d->last_addr = data[0];
334 return 1;
335 } else {
336 data[0] = d->last_addr;
337 return 1;
338 }
339 } else
340 relative_addr = d->last_addr * 4;
341 break;
342 case MC146818_ARC_NEC:
343 if (relative_addr == 0x01) {
344 if (writeflag == MEM_WRITE) {
345 d->last_addr = data[0];
346 return 1;
347 } else {
348 data[0] = d->last_addr;
349 return 1;
350 }
351 } else if (relative_addr == 0x00)
352 relative_addr = d->last_addr * 4;
353 else {
354 fatal("[ mc146818: not accessed as an "
355 "MC146818_ARC_NEC device! ]\n");
356 }
357 break;
358 case MC146818_ARC_JAZZ:
359 /* See comment for dev_mc146818_jazz_access(). */
360 relative_addr = d->last_addr * 4;
361 break;
362 case MC146818_DEC:
363 case MC146818_SGI:
364 /*
365 * This device was originally written for DECstation
366 * emulation, so no changes are necessary for that access
367 * style.
368 *
369 * SGI access bytes 0x0..0xd at offsets 0x0yz..0xdyz, where yz
370 * should be ignored. It works _almost_ as DEC, if offsets are
371 * divided by 0x40.
372 */
373 break;
374 case MC146818_PMPPC:
375 relative_addr *= 4;
376 break;
377 default:
378 ;
379 }
380
381 #ifdef MC146818_DEBUG
382 if (writeflag == MEM_WRITE) {
383 fatal("[ mc146818: write to addr=0x%04x (len %i): ",
384 (int)relative_addr, (int)len);
385 for (i=0; i<len; i++)
386 fatal("0x%02x ", data[i]);
387 fatal("]\n");
388 }
389 #endif
390
391 /*
392 * Sprite seems to wants UF interrupt status, once every second, or
393 * it hangs forever during bootup. (These do not cause interrupts,
394 * but it is good enough... Sprite polls this, iirc.)
395 *
396 * Linux on at least sgimips and evbmips (Malta) wants the UIP bit
397 * in REGA to be updated once a second.
398 */
399 if (relative_addr == MC_REGA*4 || relative_addr == MC_REGC*4) {
400 timet = time(NULL);
401 tmp = gmtime(&timet);
402 d->reg[MC_REGC * 4] &= ~MC_REGC_UF;
403 if (tmp->tm_sec != d->previous_second) {
404 d->n_seconds_elapsed ++;
405 d->previous_second = tmp->tm_sec;
406 }
407 if (d->n_seconds_elapsed > d->uip_threshold) {
408 d->n_seconds_elapsed = 0;
409
410 d->reg[MC_REGA * 4] |= MC_REGA_UIP;
411
412 d->reg[MC_REGC * 4] |= MC_REGC_UF;
413 d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
414
415 /* For some reason, some Linux/DECstation KN04
416 kernels want the PF (periodic flag) bit set,
417 even though interrupts are not enabled? */
418 d->reg[MC_REGC * 4] |= MC_REGC_PF;
419 } else
420 d->reg[MC_REGA * 4] &= ~MC_REGA_UIP;
421 }
422
423 /* RTC data is in either BCD format or binary: */
424 if (d->use_bcd)
425 d->reg[MC_REGB * 4] &= ~(1 << 2);
426 else
427 d->reg[MC_REGB * 4] |= (1 << 2);
428
429 /* RTC date/time is always Valid: */
430 d->reg[MC_REGD * 4] |= MC_REGD_VRT;
431
432 if (writeflag == MEM_WRITE) {
433 /* WRITE: */
434 switch (relative_addr) {
435 case MC_REGA*4:
436 if ((data[0] & MC_REGA_DVMASK) == MC_BASE_32_KHz)
437 d->timebase_hz = 32000;
438 if ((data[0] & MC_REGA_DVMASK) == MC_BASE_1_MHz)
439 d->timebase_hz = 1000000;
440 if ((data[0] & MC_REGA_DVMASK) == MC_BASE_4_MHz)
441 d->timebase_hz = 4000000;
442 switch (data[0] & MC_REGA_RSMASK) {
443 case MC_RATE_NONE:
444 d->interrupt_hz = 0;
445 break;
446 case MC_RATE_1:
447 if (d->timebase_hz == 32000)
448 d->interrupt_hz = 256;
449 else
450 d->interrupt_hz = 32768;
451 break;
452 case MC_RATE_2:
453 if (d->timebase_hz == 32000)
454 d->interrupt_hz = 128;
455 else
456 d->interrupt_hz = 16384;
457 break;
458 case MC_RATE_8192_Hz: d->interrupt_hz = 8192; break;
459 case MC_RATE_4096_Hz: d->interrupt_hz = 4096; break;
460 case MC_RATE_2048_Hz: d->interrupt_hz = 2048; break;
461 case MC_RATE_1024_Hz: d->interrupt_hz = 1024; break;
462 case MC_RATE_512_Hz: d->interrupt_hz = 512; break;
463 case MC_RATE_256_Hz: d->interrupt_hz = 256; break;
464 case MC_RATE_128_Hz: d->interrupt_hz = 128; break;
465 case MC_RATE_64_Hz: d->interrupt_hz = 64; break;
466 case MC_RATE_32_Hz: d->interrupt_hz = 32; break;
467 case MC_RATE_16_Hz: d->interrupt_hz = 16; break;
468 case MC_RATE_8_Hz: d->interrupt_hz = 8; break;
469 case MC_RATE_4_Hz: d->interrupt_hz = 4; break;
470 case MC_RATE_2_Hz: d->interrupt_hz = 2; break;
471 default:/* debug("[ mc146818: unimplemented "
472 "MC_REGA RS: %i ]\n",
473 data[0] & MC_REGA_RSMASK); */
474 ;
475 }
476
477 recalc_interrupt_cycle(cpu, d);
478
479 d->cycles_left_until_interrupt =
480 d->interrupt_every_x_cycles;
481
482 d->reg[MC_REGA * 4] =
483 data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK);
484
485 debug("[ rtc set to interrupt every %i:th cycle ]\n",
486 d->interrupt_every_x_cycles);
487 break;
488 case MC_REGB*4:
489 if (((data[0] ^ d->reg[MC_REGB*4]) & MC_REGB_PIE))
490 d->cycles_left_until_interrupt =
491 d->interrupt_every_x_cycles;
492 d->reg[MC_REGB*4] = data[0];
493 if (!(data[0] & MC_REGB_PIE)) {
494 cpu_interrupt_ack(cpu, d->irq_nr);
495 /* d->cycles_left_until_interrupt =
496 d->interrupt_every_x_cycles; */
497 }
498 /* debug("[ mc146818: write to MC_REGB, data[0] "
499 "= 0x%02x ]\n", data[0]); */
500 break;
501 case MC_REGC*4:
502 d->reg[MC_REGC * 4] = data[0];
503 debug("[ mc146818: write to MC_REGC, data[0] = "
504 "0x%02x ]\n", data[0]);
505 break;
506 case 0x128:
507 d->reg[relative_addr] = data[0];
508 if (data[0] & 8) {
509 /* Used on SGI to power off the machine. */
510 fatal("[ md146818: power off ]\n");
511 for (i=0; i<cpu->machine->ncpus; i++)
512 cpu->machine->cpus[i]->running = 0;
513 cpu->machine->
514 exit_without_entering_debugger = 1;
515 }
516 break;
517 default:
518 d->reg[relative_addr] = data[0];
519
520 debug("[ mc146818: unimplemented write to "
521 "relative_addr = %08lx: ", (long)relative_addr);
522 for (i=0; i<len; i++)
523 debug("%02x ", data[i]);
524 debug("]\n");
525 }
526 } else {
527 /* READ: */
528 switch (relative_addr) {
529 case 0x01: /* Station's ethernet address (6 bytes) */
530 case 0x05: /* (on DECstation 3100) */
531 case 0x09:
532 case 0x0d:
533 case 0x11:
534 case 0x15:
535 break;
536 case 4 * MC_SEC:
537 if (d->ugly_netbsd_prep_hack_done < NETBSD_HACK_DONE) {
538 d->ugly_netbsd_prep_hack_done ++;
539 switch (d->ugly_netbsd_prep_hack_done) {
540 case NETBSD_HACK_FIRST_1:
541 d->ugly_netbsd_prep_hack_sec =
542 from_bcd(d->reg[relative_addr]);
543 break;
544 case NETBSD_HACK_FIRST_2:
545 d->reg[relative_addr] = to_bcd(
546 d->ugly_netbsd_prep_hack_sec);
547 break;
548 case NETBSD_HACK_SECOND_1:
549 case NETBSD_HACK_SECOND_2:
550 d->reg[relative_addr] = to_bcd((1 +
551 d->ugly_netbsd_prep_hack_sec) % 60);
552 break;
553 }
554 }
555 case 4 * MC_MIN:
556 case 4 * MC_HOUR:
557 case 4 * MC_DOW:
558 case 4 * MC_DOM:
559 case 4 * MC_MONTH:
560 case 4 * MC_YEAR:
561 case 4 * 63: /* 63 is used by Linux on DECstation */
562 case 4 * 72: /* 72 is Century, on SGI (DS1687) */
563 /*
564 * If the SET bit is set, then we don't automatically
565 * update the values. Otherwise, we update them by
566 * reading from the host's clock:
567 */
568 if (d->reg[MC_REGB * 4] & MC_REGB_SET)
569 break;
570
571 if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE)
572 mc146818_update_time(d);
573 break;
574 case 4 * MC_REGA:
575 break;
576 case 4 * MC_REGC: /* Interrupt ack. */
577 /* NOTE: Acking is done below, _after_ the
578 register has been read. */
579 break;
580 default:debug("[ mc146818: read from relative_addr = "
581 "%04x ]\n", (int)relative_addr);
582 }
583
584 data[0] = d->reg[relative_addr];
585
586 if (relative_addr == MC_REGC*4) {
587 cpu_interrupt_ack(cpu, d->irq_nr);
588 /* d->cycles_left_until_interrupt =
589 d->interrupt_every_x_cycles; */
590 d->reg[MC_REGC * 4] = 0x00;
591 }
592 }
593
594 #ifdef MC146818_DEBUG
595 if (writeflag == MEM_READ) {
596 fatal("[ mc146818: read from addr=0x%04x (len %i): ",
597 (int)relative_addr, (int)len);
598 for (i=0; i<len; i++)
599 fatal("0x%02x ", data[i]);
600 fatal("]\n");
601 }
602 #endif
603
604 return 1;
605 }
606
607
608 /*
609 * dev_mc146818_init():
610 *
611 * This needs to work for both DECstation emulation and other machine types,
612 * so it contains both rtc related stuff and the station's Ethernet address.
613 */
614 void dev_mc146818_init(struct machine *machine, struct memory *mem,
615 uint64_t baseaddr, int irq_nr, int access_style, int addrdiv)
616 {
617 unsigned char ether_address[6];
618 int i, dev_len;
619 struct mc_data *d;
620
621 d = malloc(sizeof(struct mc_data));
622 if (d == NULL) {
623 fprintf(stderr, "out of memory\n");
624 exit(1);
625 }
626
627 memset(d, 0, sizeof(struct mc_data));
628 d->irq_nr = irq_nr;
629 d->access_style = access_style;
630 d->addrdiv = addrdiv;
631
632 d->use_bcd = 0;
633 switch (access_style) {
634 case MC146818_SGI:
635 case MC146818_PC_CMOS:
636 case MC146818_PMPPC:
637 d->use_bcd = 1;
638 }
639
640 if (machine->machine_type != MACHINE_PREP) {
641 /* NetBSD/prep has a really ugly clock detection code;
642 all other machines/OSes don't need this. */
643 d->ugly_netbsd_prep_hack_done = NETBSD_HACK_DONE;
644 }
645
646 if (access_style == MC146818_DEC) {
647 /* Station Ethernet Address, on DECstation 3100: */
648 for (i=0; i<6; i++)
649 ether_address[i] = 0x10 * (i+1);
650
651 d->reg[0x01] = ether_address[0];
652 d->reg[0x05] = ether_address[1];
653 d->reg[0x09] = ether_address[2];
654 d->reg[0x0d] = ether_address[3];
655 d->reg[0x11] = ether_address[4];
656 d->reg[0x15] = ether_address[5];
657 /* TODO: 19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */
658 d->reg[0x29] = ether_address[5];
659 d->reg[0x2d] = ether_address[4];
660 d->reg[0x31] = ether_address[3];
661 d->reg[0x35] = ether_address[2];
662 d->reg[0x39] = ether_address[1];
663 d->reg[0x3d] = ether_address[1];
664 d->reg[0x41] = ether_address[0];
665 d->reg[0x45] = ether_address[1];
666 d->reg[0x49] = ether_address[2];
667 d->reg[0x4d] = ether_address[3];
668 d->reg[0x51] = ether_address[4];
669 d->reg[0x55] = ether_address[5];
670 /* TODO: 59, 5d = checksum bytes 1,2 resp. */
671 d->reg[0x61] = 0xff;
672 d->reg[0x65] = 0x00;
673 d->reg[0x69] = 0x55;
674 d->reg[0x6d] = 0xaa;
675 d->reg[0x71] = 0xff;
676 d->reg[0x75] = 0x00;
677 d->reg[0x79] = 0x55;
678 d->reg[0x7d] = 0xaa;
679
680 /* Battery valid, for DECstations */
681 d->reg[0xf8] = 1;
682 }
683
684 /*
685 * uip_threshold should ideally be 1, but when Linux polls the UIP bit
686 * it looses speed. This hack gives Linux the impression that the cpu
687 * is uip_threshold times faster than the slow clock it would
688 * otherwise detect.
689 *
690 * TODO: Find out if this messes up Sprite emulation; if so, then
691 * this hack has to be removed.
692 */
693 d->uip_threshold = 5;
694
695 if (access_style == MC146818_ARC_JAZZ)
696 memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,
697 1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL);
698
699 dev_len = DEV_MC146818_LENGTH;
700 switch (access_style) {
701 case MC146818_CATS:
702 case MC146818_PC_CMOS:
703 dev_len = 2;
704 break;
705 case MC146818_SGI:
706 dev_len = 0x400;
707 }
708
709 memory_device_register(mem, "mc146818", baseaddr,
710 dev_len * addrdiv, dev_mc146818_access,
711 d, DM_DEFAULT, NULL);
712
713 mc146818_update_time(d);
714
715 machine_add_tickfunction(machine, dev_mc146818_tick, d, TICK_SHIFT);
716 }
717

  ViewVC Help
Powered by ViewVC 1.1.26