/[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 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19059 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26