/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 7 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 dpavlin 4 /*
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 dpavlin 20 * $Id: dev_mc146818.c,v 1.80 2005/11/20 11:28:45 debug Exp $
29 dpavlin 4 *
30     * MC146818 real-time clock, used by many different machines types.
31 dpavlin 16 * (DS1687 as used in some other machines is also similar to the MC146818.)
32 dpavlin 4 *
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 dpavlin 20 #define from_bcd(x) ( ((x)>>4) * 10 + ((x)&15) )
57 dpavlin 4
58     /* #define MC146818_DEBUG */
59    
60 dpavlin 12 #define TICK_SHIFT 14
61 dpavlin 4
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 dpavlin 20 int n_seconds_elapsed;
81     int uip_threshold;
82 dpavlin 4
83     int interrupt_every_x_cycles;
84     int cycles_left_until_interrupt;
85 dpavlin 20
86     int ugly_netbsd_prep_hack_done;
87     int ugly_netbsd_prep_hack_sec;
88 dpavlin 4 };
89    
90    
91     /*
92 dpavlin 20 * 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 dpavlin 4 * 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 dpavlin 12 d->cycles_left_until_interrupt -= (1 << TICK_SHIFT);
159 dpavlin 4
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 dpavlin 16 /*
241     * Special hacks for emulating the behaviour of various machines:
242     */
243 dpavlin 4 switch (d->access_style) {
244 dpavlin 20 case MC146818_ALGOR:
245     d->reg[4 * MC_YEAR] += 80;
246     break;
247 dpavlin 4 case MC146818_ARC_NEC:
248     d->reg[4 * MC_YEAR] += (0x18 - 104);
249     break;
250 dpavlin 16 case MC146818_CATS:
251     d->reg[4 * MC_YEAR] %= 100;
252     break;
253 dpavlin 4 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 dpavlin 20 case MC146818_ALGOR:
329 dpavlin 16 case MC146818_CATS:
330 dpavlin 4 case MC146818_PC_CMOS:
331 dpavlin 16 if ((relative_addr & 1) == 0x00) {
332 dpavlin 4 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 dpavlin 16 } else
340 dpavlin 4 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 dpavlin 20 break;
374     case MC146818_PMPPC:
375     relative_addr *= 4;
376     break;
377 dpavlin 4 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 dpavlin 20 fatal("0x%02x ", data[i]);
387 dpavlin 4 fatal("]\n");
388     }
389     #endif
390    
391     /*
392 dpavlin 12 * Sprite seems to wants UF interrupt status, once every second, or
393 dpavlin 4 * it hangs forever during bootup. (These do not cause interrupts,
394     * but it is good enough... Sprite polls this, iirc.)
395 dpavlin 12 *
396     * Linux on at least sgimips and evbmips (Malta) wants the UIP bit
397     * in REGA to be updated once a second.
398 dpavlin 4 */
399 dpavlin 20 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 dpavlin 12
410 dpavlin 20 d->reg[MC_REGA * 4] |= MC_REGA_UIP;
411 dpavlin 12
412 dpavlin 20 d->reg[MC_REGC * 4] |= MC_REGC_UF;
413     d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
414 dpavlin 4
415 dpavlin 20 /* 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 dpavlin 4
423     /* RTC data is in either BCD format or binary: */
424 dpavlin 12 if (d->use_bcd)
425 dpavlin 4 d->reg[MC_REGB * 4] &= ~(1 << 2);
426 dpavlin 12 else
427 dpavlin 4 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 dpavlin 20 default:/* debug("[ mc146818: unimplemented "
472 dpavlin 4 "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 dpavlin 20 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 dpavlin 4 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 dpavlin 20 if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE)
572     mc146818_update_time(d);
573 dpavlin 4 break;
574 dpavlin 20 case 4 * MC_REGA:
575     break;
576 dpavlin 4 case 4 * MC_REGC: /* Interrupt ack. */
577     /* NOTE: Acking is done below, _after_ the
578     register has been read. */
579     break;
580 dpavlin 20 default:debug("[ mc146818: read from relative_addr = "
581 dpavlin 4 "%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 dpavlin 20 fatal("0x%02x ", data[i]);
600 dpavlin 4 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 dpavlin 6 d->use_bcd = 0;
633 dpavlin 20 switch (access_style) {
634     case MC146818_SGI:
635     case MC146818_PC_CMOS:
636     case MC146818_PMPPC:
637 dpavlin 6 d->use_bcd = 1;
638 dpavlin 20 }
639 dpavlin 6
640 dpavlin 20 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 dpavlin 6 if (access_style == MC146818_DEC) {
647 dpavlin 4 /* Station Ethernet Address, on DECstation 3100: */
648     for (i=0; i<6; i++)
649     ether_address[i] = 0x10 * (i+1);
650    
651 dpavlin 6 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 dpavlin 4
680     /* Battery valid, for DECstations */
681     d->reg[0xf8] = 1;
682     }
683    
684 dpavlin 20 /*
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 dpavlin 4 if (access_style == MC146818_ARC_JAZZ)
696     memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,
697 dpavlin 20 1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL);
698 dpavlin 4
699     dev_len = DEV_MC146818_LENGTH;
700     switch (access_style) {
701 dpavlin 16 case MC146818_CATS:
702 dpavlin 4 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 dpavlin 20 d, DM_DEFAULT, NULL);
712 dpavlin 4
713     mc146818_update_time(d);
714    
715 dpavlin 12 machine_add_tickfunction(machine, dev_mc146818_tick, d, TICK_SHIFT);
716 dpavlin 4 }
717    

  ViewVC Help
Powered by ViewVC 1.1.26