/[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 6 - (hide annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 17973 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26