/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 18553 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26