/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19871 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


1 /*
2 * Copyright (C) 2003-2006 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.84 2006/01/17 05:55:53 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 relative_addr = r;
323 size_t i;
324
325 relative_addr /= d->addrdiv;
326
327 /* Different ways of accessing the registers: */
328 switch (d->access_style) {
329 case MC146818_ALGOR:
330 case MC146818_CATS:
331 case MC146818_PC_CMOS:
332 if ((relative_addr & 1) == 0x00) {
333 if (writeflag == MEM_WRITE) {
334 d->last_addr = data[0];
335 return 1;
336 } else {
337 data[0] = d->last_addr;
338 return 1;
339 }
340 } else
341 relative_addr = d->last_addr * 4;
342 break;
343 case MC146818_ARC_NEC:
344 if (relative_addr == 0x01) {
345 if (writeflag == MEM_WRITE) {
346 d->last_addr = data[0];
347 return 1;
348 } else {
349 data[0] = d->last_addr;
350 return 1;
351 }
352 } else if (relative_addr == 0x00)
353 relative_addr = d->last_addr * 4;
354 else {
355 fatal("[ mc146818: not accessed as an "
356 "MC146818_ARC_NEC device! ]\n");
357 }
358 break;
359 case MC146818_ARC_JAZZ:
360 /* See comment for dev_mc146818_jazz_access(). */
361 relative_addr = d->last_addr * 4;
362 break;
363 case MC146818_DEC:
364 case MC146818_SGI:
365 /*
366 * This device was originally written for DECstation
367 * emulation, so no changes are necessary for that access
368 * style.
369 *
370 * SGI access bytes 0x0..0xd at offsets 0x0yz..0xdyz, where yz
371 * should be ignored. It works _almost_ as DEC, if offsets are
372 * divided by 0x40.
373 */
374 break;
375 case MC146818_PMPPC:
376 relative_addr *= 4;
377 break;
378 default:
379 ;
380 }
381
382 #ifdef MC146818_DEBUG
383 if (writeflag == MEM_WRITE) {
384 fatal("[ mc146818: write to addr=0x%04x (len %i): ",
385 (int)relative_addr, (int)len);
386 for (i=0; i<len; i++)
387 fatal("0x%02x ", data[i]);
388 fatal("]\n");
389 }
390 #endif
391
392 /*
393 * Sprite seems to wants UF interrupt status, once every second, or
394 * it hangs forever during bootup. (These do not cause interrupts,
395 * but it is good enough... Sprite polls this, iirc.)
396 *
397 * Linux on at least sgimips and evbmips (Malta) wants the UIP bit
398 * in REGA to be updated once a second.
399 */
400 if (relative_addr == MC_REGA*4 || relative_addr == MC_REGC*4) {
401 timet = time(NULL);
402 tmp = gmtime(&timet);
403 d->reg[MC_REGC * 4] &= ~MC_REGC_UF;
404 if (tmp->tm_sec != d->previous_second) {
405 d->n_seconds_elapsed ++;
406 d->previous_second = tmp->tm_sec;
407 }
408 if (d->n_seconds_elapsed > d->uip_threshold) {
409 d->n_seconds_elapsed = 0;
410
411 d->reg[MC_REGA * 4] |= MC_REGA_UIP;
412
413 d->reg[MC_REGC * 4] |= MC_REGC_UF;
414 d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
415
416 /* For some reason, some Linux/DECstation KN04
417 kernels want the PF (periodic flag) bit set,
418 even though interrupts are not enabled? */
419 d->reg[MC_REGC * 4] |= MC_REGC_PF;
420 } else
421 d->reg[MC_REGA * 4] &= ~MC_REGA_UIP;
422 }
423
424 /* RTC data is in either BCD format or binary: */
425 if (d->use_bcd)
426 d->reg[MC_REGB * 4] &= ~(1 << 2);
427 else
428 d->reg[MC_REGB * 4] |= (1 << 2);
429
430 /* RTC date/time is always Valid: */
431 d->reg[MC_REGD * 4] |= MC_REGD_VRT;
432
433 if (writeflag == MEM_WRITE) {
434 /* WRITE: */
435 switch (relative_addr) {
436 case MC_REGA*4:
437 if ((data[0] & MC_REGA_DVMASK) == MC_BASE_32_KHz)
438 d->timebase_hz = 32000;
439 if ((data[0] & MC_REGA_DVMASK) == MC_BASE_1_MHz)
440 d->timebase_hz = 1000000;
441 if ((data[0] & MC_REGA_DVMASK) == MC_BASE_4_MHz)
442 d->timebase_hz = 4000000;
443 switch (data[0] & MC_REGA_RSMASK) {
444 case MC_RATE_NONE:
445 d->interrupt_hz = 0;
446 break;
447 case MC_RATE_1:
448 if (d->timebase_hz == 32000)
449 d->interrupt_hz = 256;
450 else
451 d->interrupt_hz = 32768;
452 break;
453 case MC_RATE_2:
454 if (d->timebase_hz == 32000)
455 d->interrupt_hz = 128;
456 else
457 d->interrupt_hz = 16384;
458 break;
459 case MC_RATE_8192_Hz: d->interrupt_hz = 8192; break;
460 case MC_RATE_4096_Hz: d->interrupt_hz = 4096; break;
461 case MC_RATE_2048_Hz: d->interrupt_hz = 2048; break;
462 case MC_RATE_1024_Hz: d->interrupt_hz = 1024; break;
463 case MC_RATE_512_Hz: d->interrupt_hz = 512; break;
464 case MC_RATE_256_Hz: d->interrupt_hz = 256; break;
465 case MC_RATE_128_Hz: d->interrupt_hz = 128; break;
466 case MC_RATE_64_Hz: d->interrupt_hz = 64; break;
467 case MC_RATE_32_Hz: d->interrupt_hz = 32; break;
468 case MC_RATE_16_Hz: d->interrupt_hz = 16; break;
469 case MC_RATE_8_Hz: d->interrupt_hz = 8; break;
470 case MC_RATE_4_Hz: d->interrupt_hz = 4; break;
471 case MC_RATE_2_Hz: d->interrupt_hz = 2; break;
472 default:/* debug("[ mc146818: unimplemented "
473 "MC_REGA RS: %i ]\n",
474 data[0] & MC_REGA_RSMASK); */
475 ;
476 }
477
478 recalc_interrupt_cycle(cpu, d);
479
480 d->cycles_left_until_interrupt =
481 d->interrupt_every_x_cycles;
482
483 d->reg[MC_REGA * 4] =
484 data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK);
485
486 debug("[ rtc set to interrupt every %i:th cycle ]\n",
487 d->interrupt_every_x_cycles);
488 break;
489 case MC_REGB*4:
490 if (((data[0] ^ d->reg[MC_REGB*4]) & MC_REGB_PIE))
491 d->cycles_left_until_interrupt =
492 d->interrupt_every_x_cycles;
493 d->reg[MC_REGB*4] = data[0];
494 if (!(data[0] & MC_REGB_PIE)) {
495 cpu_interrupt_ack(cpu, d->irq_nr);
496 /* d->cycles_left_until_interrupt =
497 d->interrupt_every_x_cycles; */
498 }
499 /* debug("[ mc146818: write to MC_REGB, data[0] "
500 "= 0x%02x ]\n", data[0]); */
501 break;
502 case MC_REGC*4:
503 d->reg[MC_REGC * 4] = data[0];
504 debug("[ mc146818: write to MC_REGC, data[0] = "
505 "0x%02x ]\n", data[0]);
506 break;
507 case 0x128:
508 d->reg[relative_addr] = data[0];
509 if (data[0] & 8) {
510 int j;
511
512 /* Used on SGI to power off the machine. */
513 fatal("[ md146818: power off ]\n");
514 for (j=0; j<cpu->machine->ncpus; j++)
515 cpu->machine->cpus[j]->running = 0;
516 cpu->machine->
517 exit_without_entering_debugger = 1;
518 }
519 break;
520 default:
521 d->reg[relative_addr] = data[0];
522
523 debug("[ mc146818: unimplemented write to "
524 "relative_addr = %08lx: ", (long)relative_addr);
525 for (i=0; i<len; i++)
526 debug("%02x ", data[i]);
527 debug("]\n");
528 }
529 } else {
530 /* READ: */
531 switch (relative_addr) {
532 case 0x01: /* Station's ethernet address (6 bytes) */
533 case 0x05: /* (on DECstation 3100) */
534 case 0x09:
535 case 0x0d:
536 case 0x11:
537 case 0x15:
538 break;
539 case 4 * MC_SEC:
540 if (d->ugly_netbsd_prep_hack_done < NETBSD_HACK_DONE) {
541 d->ugly_netbsd_prep_hack_done ++;
542 switch (d->ugly_netbsd_prep_hack_done) {
543 case NETBSD_HACK_FIRST_1:
544 d->ugly_netbsd_prep_hack_sec =
545 from_bcd(d->reg[relative_addr]);
546 break;
547 case NETBSD_HACK_FIRST_2:
548 d->reg[relative_addr] = to_bcd(
549 d->ugly_netbsd_prep_hack_sec);
550 break;
551 case NETBSD_HACK_SECOND_1:
552 case NETBSD_HACK_SECOND_2:
553 d->reg[relative_addr] = to_bcd((1 +
554 d->ugly_netbsd_prep_hack_sec) % 60);
555 break;
556 }
557 }
558 case 4 * MC_MIN:
559 case 4 * MC_HOUR:
560 case 4 * MC_DOW:
561 case 4 * MC_DOM:
562 case 4 * MC_MONTH:
563 case 4 * MC_YEAR:
564 case 4 * 63: /* 63 is used by Linux on DECstation */
565 case 4 * 72: /* 72 is Century, on SGI (DS1687) */
566 /*
567 * If the SET bit is set, then we don't automatically
568 * update the values. Otherwise, we update them by
569 * reading from the host's clock:
570 */
571 if (d->reg[MC_REGB * 4] & MC_REGB_SET)
572 break;
573
574 if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE)
575 mc146818_update_time(d);
576 break;
577 case 4 * MC_REGA:
578 break;
579 case 4 * MC_REGC: /* Interrupt ack. */
580 /* NOTE: Acking is done below, _after_ the
581 register has been read. */
582 break;
583 default:debug("[ mc146818: read from relative_addr = "
584 "%04x ]\n", (int)relative_addr);
585 }
586
587 data[0] = d->reg[relative_addr];
588
589 if (relative_addr == MC_REGC*4) {
590 cpu_interrupt_ack(cpu, d->irq_nr);
591 /* d->cycles_left_until_interrupt =
592 d->interrupt_every_x_cycles; */
593 d->reg[MC_REGC * 4] = 0x00;
594 }
595 }
596
597 #ifdef MC146818_DEBUG
598 if (writeflag == MEM_READ) {
599 fatal("[ mc146818: read from addr=0x%04x (len %i): ",
600 (int)relative_addr, (int)len);
601 for (i=0; i<len; i++)
602 fatal("0x%02x ", data[i]);
603 fatal("]\n");
604 }
605 #endif
606
607 return 1;
608 }
609
610
611 /*
612 * dev_mc146818_init():
613 *
614 * This needs to work for both DECstation emulation and other machine types,
615 * so it contains both rtc related stuff and the station's Ethernet address.
616 */
617 void dev_mc146818_init(struct machine *machine, struct memory *mem,
618 uint64_t baseaddr, int irq_nr, int access_style, int addrdiv)
619 {
620 unsigned char ether_address[6];
621 int i, dev_len;
622 struct mc_data *d;
623
624 d = malloc(sizeof(struct mc_data));
625 if (d == NULL) {
626 fprintf(stderr, "out of memory\n");
627 exit(1);
628 }
629
630 memset(d, 0, sizeof(struct mc_data));
631 d->irq_nr = irq_nr;
632 d->access_style = access_style;
633 d->addrdiv = addrdiv;
634
635 d->use_bcd = 0;
636 switch (access_style) {
637 case MC146818_SGI:
638 case MC146818_PC_CMOS:
639 case MC146818_PMPPC:
640 d->use_bcd = 1;
641 }
642
643 if (machine->machine_type != MACHINE_PREP) {
644 /* NetBSD/prep has a really ugly clock detection code;
645 no other machines/OSes don't need this. */
646 d->ugly_netbsd_prep_hack_done = NETBSD_HACK_DONE;
647 }
648
649 if (access_style == MC146818_DEC) {
650 /* Station Ethernet Address, on DECstation 3100: */
651 for (i=0; i<6; i++)
652 ether_address[i] = 0x10 * (i+1);
653
654 d->reg[0x01] = ether_address[0];
655 d->reg[0x05] = ether_address[1];
656 d->reg[0x09] = ether_address[2];
657 d->reg[0x0d] = ether_address[3];
658 d->reg[0x11] = ether_address[4];
659 d->reg[0x15] = ether_address[5];
660 /* TODO: 19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */
661 d->reg[0x29] = ether_address[5];
662 d->reg[0x2d] = ether_address[4];
663 d->reg[0x31] = ether_address[3];
664 d->reg[0x35] = ether_address[2];
665 d->reg[0x39] = ether_address[1];
666 d->reg[0x3d] = ether_address[1];
667 d->reg[0x41] = ether_address[0];
668 d->reg[0x45] = ether_address[1];
669 d->reg[0x49] = ether_address[2];
670 d->reg[0x4d] = ether_address[3];
671 d->reg[0x51] = ether_address[4];
672 d->reg[0x55] = ether_address[5];
673 /* TODO: 59, 5d = checksum bytes 1,2 resp. */
674 d->reg[0x61] = 0xff;
675 d->reg[0x65] = 0x00;
676 d->reg[0x69] = 0x55;
677 d->reg[0x6d] = 0xaa;
678 d->reg[0x71] = 0xff;
679 d->reg[0x75] = 0x00;
680 d->reg[0x79] = 0x55;
681 d->reg[0x7d] = 0xaa;
682
683 /* Battery valid, for DECstations */
684 d->reg[0xf8] = 1;
685 }
686
687 /*
688 * uip_threshold should ideally be 1, but when Linux polls the UIP bit
689 * it looses speed. This hack gives Linux the impression that the cpu
690 * is uip_threshold times faster than the slow clock it would
691 * otherwise detect.
692 *
693 * TODO: Find out if this messes up Sprite emulation; if so, then
694 * this hack has to be removed.
695 */
696 d->uip_threshold = 8;
697
698 if (access_style == MC146818_ARC_JAZZ)
699 memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,
700 1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL);
701
702 dev_len = DEV_MC146818_LENGTH;
703 switch (access_style) {
704 case MC146818_CATS:
705 case MC146818_PC_CMOS:
706 dev_len = 2;
707 break;
708 case MC146818_SGI:
709 dev_len = 0x400;
710 }
711
712 memory_device_register(mem, "mc146818", baseaddr,
713 dev_len * addrdiv, dev_mc146818_access,
714 d, DM_DEFAULT, NULL);
715
716 mc146818_update_time(d);
717
718 machine_add_tickfunction(machine, dev_mc146818_tick, d, TICK_SHIFT);
719 }
720

  ViewVC Help
Powered by ViewVC 1.1.26